Short Blush Guppy
Medium
There are multiple problems when validating the price feed data in OracleReader:getOraclePrice
The following checks are missing
- The code doesn't revert when
answer == 0
- the
GRACE_PERIOD
after a sequencer was down is not waited
Read more about the recommended ChainLink sequencer check here.
The following checks are missing in OracleReader:68
- The code doesn't revert when
answer == 0
- the
GRACE_PERIOD
after a sequencer was down is not waited
function getOraclePrice(address quote, address base) public view returns(uint256) {
bool isInverted = false;
address feed = OracleFeeds(oracleFeeds).priceFeeds(quote, base);
if (feed == address(0)) {
feed = OracleFeeds(oracleFeeds).priceFeeds(base, quote);
if (feed == address(0)) {
revert NoFeedFound();
}
// Invert the price
isInverted = true;
}
/// @audit-info: Add sequencer and grace period check here
//// @audit-info For more details visit : https://docs.chain.link/data-feeds/l2-sequencer-feeds
(,int256 answer,,uint256 updatedTimestamp,) = AggregatorV3Interface(feed).latestRoundData();
if (updatedTimestamp + OracleFeeds(oracleFeeds).feedHeartbeats(feed) < block.timestamp) {
revert StalePrice();
}
// @audit-info : Add a check to validate that answer is not zero
uint256 decimals = uint256(AggregatorV3Interface(feed).decimals());
return isInverted ? (10 ** decimals * 10 ** decimals) / uint256(answer) : uint256(answer);
}
Code can execute with prices that don’t reflect the current pricing resulting in a potential loss of funds for users or the protocol
- Add a check to see if the price return from chainlink price feeds in not zero.
function getOraclePrice(address quote, address base) public view returns(uint256) {
bool isInverted = false;
address feed = OracleFeeds(oracleFeeds).priceFeeds(quote, base);
if (feed == address(0)) {
feed = OracleFeeds(oracleFeeds).priceFeeds(base, quote);
if (feed == address(0)) {
revert NoFeedFound();
}
// Invert the price
isInverted = true;
}
(,int256 answer,,uint256 updatedTimestamp,) = AggregatorV3Interface(feed).latestRoundData();
+ if(answer <= 0){
+ revert InvalidPrice();
+ }
if (updatedTimestamp + OracleFeeds(oracleFeeds).feedHeartbeats(feed) < block.timestamp) {
revert StalePrice();
}
uint256 decimals = uint256(AggregatorV3Interface(feed).decimals());
return isInverted ? (10 ** decimals * 10 ** decimals) / uint256(answer) : uint256(answer);
}
- Use sequencer uptime check . For more information refer to ChainLink Docs