Skip to content

Latest commit

 

History

History
97 lines (64 loc) · 3.01 KB

File metadata and controls

97 lines (64 loc) · 3.01 KB

Short Blush Guppy

Medium

Insufficient validation of Chainlink data feeds in getOraclePrice

Summary

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.

Root Cause

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);
  }

Impact

Code can execute with prices that don’t reflect the current pricing resulting in a potential loss of funds for users or the protocol

Mitigation

  • 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