Closed sherlock-admin closed 1 year ago
w42d3n
medium
Chainlink's latestRoundData() is used but there is no check if the return value indicates stale data. This could lead to stale prices according to the Chainlink documentation:
https://docs.chain.link/docs/historical-price-data/#historical-rounds
The functions
StableOracleDAI.getpriceUSD() StableOracleWBTC.getpriceUSD() StableOracleWETH.getpriceUSD()
uses Chainlink's latestRoundData() to get the latest price. However, there is no check if the return value indicates stale data.
These contracts could return stale price data for the underlying asset.
https://github.com/sherlock-audit/2023-05-USSD/blob/main/ussd-contracts/contracts/oracles/StableOracleDAI.sol#L33-L53
function getPriceUSD() external view override returns (uint256) { address[] memory pools = new address[](1); pools[0] = 0x60594a405d53811d3BC4766596EFD80fd545A270; uint256 DAIWethPrice = DAIEthOracle.quoteSpecificPoolsWithTimePeriod( 1000000000000000000, // 1 Eth 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2, // WETH (base token) 0x6B175474E89094C44Da98b954EedeAC495271d0F, // DAI (quote token) pools, // DAI/WETH pool uni v3 600 // period ); uint256 wethPriceUSD = ethOracle.getPriceUSD(); // chainlink price data is 8 decimals for WETH/USD, so multiply by 10 decimals to get 18 decimal fractional //(uint80 roundID, int256 price, uint256 startedAt, uint256 timeStamp, uint80 answeredInRound) = priceFeedDAIETH.latestRoundData(); (, int256 price, , , ) = priceFeedDAIETH.latestRoundData(); return (wethPriceUSD * 1e18) / ((DAIWethPrice + uint256(price) * 1e10) / 2); }
https://github.com/sherlock-audit/2023-05-USSD/blob/main/ussd-contracts/contracts/oracles/StableOracleWBTC.sol#LL21C1-L26C6
function getPriceUSD() external view override returns (uint256) { //(uint80 roundID, int256 price, uint256 startedAt, uint256 timeStamp, uint80 answeredInRound) = priceFeed.latestRoundData(); (, int256 price, , , ) = priceFeed.latestRoundData(); // chainlink price data is 8 decimals for WETH/USD return uint256(price) * 1e10; }
https://github.com/sherlock-audit/2023-05-USSD/blob/main/ussd-contracts/contracts/oracles/StableOracleWETH.sol#LL21C1-L26C6
Manual Review
Consider adding checks for stale data. e.g
(uint80 roundID, int256 price, uint256 startedAt, uint256 timeStamp, uint80 answeredInRound) = priceFeed.latestRoundData(); (+) require(answeredInRound >= roundId, "Price stale");
Duplicate of #31
w42d3n
medium
Chainlink's latestRoundData might return stale price
Summary
Chainlink's latestRoundData() is used but there is no check if the return value indicates stale data. This could lead to stale prices according to the Chainlink documentation:
https://docs.chain.link/docs/historical-price-data/#historical-rounds
Vulnerability Detail
The functions
StableOracleDAI.getpriceUSD() StableOracleWBTC.getpriceUSD() StableOracleWETH.getpriceUSD()
uses Chainlink's latestRoundData() to get the latest price. However, there is no check if the return value indicates stale data.
Impact
These contracts could return stale price data for the underlying asset.
Code Snippet
https://github.com/sherlock-audit/2023-05-USSD/blob/main/ussd-contracts/contracts/oracles/StableOracleDAI.sol#L33-L53
https://github.com/sherlock-audit/2023-05-USSD/blob/main/ussd-contracts/contracts/oracles/StableOracleWBTC.sol#LL21C1-L26C6
https://github.com/sherlock-audit/2023-05-USSD/blob/main/ussd-contracts/contracts/oracles/StableOracleWETH.sol#LL21C1-L26C6
Tool used
Manual Review
Recommendation
Consider adding checks for stale data. e.g
Duplicate of #31