15,000 USDC
View results
Submission Details
Severity: medium
Valid

Oracle freshness threshold (TIMEOUT) can lead to stale data

Summary

DSCEngine use oracle lib with a constant heartbeat (TIMEOUT) for every price feed. This will

Vulnerability Details

On DSCEngine.sol, the constructor will add several token addresses and its corresponding chainlink priceFeed as supported collateral.

File: DSCEngine.sol
117: // For example ETH / USD, BTC / USD, MKR / USD, etc
118: for (uint256 i = 0; i < tokenAddresses.length; i++) {
119: s_priceFeeds[tokenAddresses[i]] = priceFeedAddresses[i];
120: s_collateralTokens.push(tokenAddresses[i]);
121: }

The comment says, it will support for example, ETH / USD, BTC / USD, MKR / USD pairs, and etc. Each of these pairs in Chainlink have its own heartbeat. For example ETH/USD is 3600 seconds (1 Hour), while BNB/USD, DOT/USD, ADA/USD are 86400 seconds (1 Day).

If we check OracleLib staleCheckLatestRoundData function:

File: OracleLib.sol
19: uint256 private constant TIMEOUT = 3 hours; // 3 * 60 * 60 = 10800 seconds
20:
21: function staleCheckLatestRoundData(AggregatorV3Interface priceFeed)
22: public
23: view
24: returns (uint80, int256, uint256, uint256, uint80)
25: {
26: (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) =
27: priceFeed.latestRoundData();
28:
29: uint256 secondsSince = block.timestamp - updatedAt;
30: if (secondsSince > TIMEOUT) revert OracleLib__StalePrice();
31:
32: return (roundId, answer, startedAt, updatedAt, answeredInRound);
33: }

There is problem with Line 30 validation is TIMEOUT is a constant set in the contract with the value of 36060 seconds, so it just restricts the data to not be outdated more than 3 hours. Usually Chainlink price feeds are updated much more frequently than that but there were some times that some price feeds took up a little bit more than 3 hours to update themselves with the most recent price.

The different pairs have diferrent heartbeats. Using the same TIMEOUT (ORACLE_FRESHNESS_THRESHOLD, heartbeat) for all the price feeds is not correct becuase the freshness validation would be useless for some pairs which can return stale data.

Impact

This can lead to potential price issues due to different pairs have different TIMEOUT (heartbeat)

Tools Used

Manual analysis

Recommendations

Do not hardcode the TIMEOUT (heartbeat) threshold and use the corresponding heartbeat ORACLE_FRESHNESS_THRESHOLD for each token

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.