Summary
Chainlink’s latestRoundData might return stale or incorrect results
Vulnerability Details
On OracleLib.sol is used latestRoundData
, but there is no check if the return value indicates stale data.
function staleCheckLatestRoundData(AggregatorV3Interface priceFeed)
public
view
returns (uint80, int256, uint256, uint256, uint80)
{
(uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) =
priceFeed.latestRoundData();
uint256 secondsSince = block.timestamp - updatedAt;
if (secondsSince > TIMEOUT) revert OracleLib__StalePrice();
return (roundId, answer, startedAt, updatedAt, answeredInRound);
}
Impact
This could lead to stale prices according to the Chainlink documentation:
https://docs.chain.link/data-feeds/historical-data
https://docs.chain.link/docs/faq/#how-can-i-check-if-the-answer-to-a-round-is-being-carried-over-from-a-previous-round
Tools Used
Manual review
Recommendations
Consider adding the missing checks for stale data.
For example:
(uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) =
priceFeed.latestRoundData();
uint256 secondsSince = block.timestamp - updatedAt;
if (secondsSince > TIMEOUT) revert OracleLib__StalePrice();
require(answer > 0, "Chainlink price <= 0"); <-- add this
require(answeredInRound >= roundID, "Stale price"); <-- add this
require(timestamp != 0, "Round not complete"); <-- add this