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