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

Hardcoded TIMEOUT is not able act as a safeguard for all oracles

Hardcoded TIMEOUT is not able act as a safeguard for all oracles

Summary

Wrong oracle price can be reported for an extended period of time because the TIMEOUT safeguard is not able to handle all oracles’ heartbeat.

Vulnerability Detail

Different oracles have different heartbeat. For instance, the WBTC-USD oracle has a heartbeat of 5 minutes and the AMPL-USD oracle has a heartbeat of 2 days. A TIMEOUT value of 3 hours should only be applicable to oracles with a heartbeat of 3 hours. There should never be an instance when it is okay to use a stale price.

For example, if we were to use WBTC as a collateral to mint DSC and the WBTC-USD oracle has a 5 minute heartbeat. The TIMEOUT should be 5 minutes and not 3 hours because it is entirely possible that within these 3 hours, the price of WBTC may have crashed and the oracle is down but when OracleLib queries the price, it will treat it as a valid price. This will allow users to mint more DSC than expected because the WBTC collateral is worth more.

Impact

User’s may be able to mint more DSC than expected because the collateral is reporting an outdated price that is higher than the true price.

User’s may not be able to mint without compromising their health factor because the collateral is reporting an outdated price that is lower than the true price.

Tool used

Manual Review

Recommendation

// DSCEngine.sol
// 1. Add a new mapping
mapping(address user => mapping(address token => uint256 amount)) private s_timeouts;
// 2. Modify the constructor to also take in a uint256[] array for timeouts
constructor(address[] memory tokenAddresses, address[] memory priceFeedAddresses, uint256[] memory timeouts, address dscAddress) {
// USD Price Feeds
if (tokenAddresses.length != priceFeedAddresses.length) {
revert DSCEngine__TokenAddressesAndPriceFeedAddressesMustBeSameLength();
}
if (tokenAddresses.length != timeouts.length) {
revert DSCEngine__TokenAddressesAndTimeoutsMustBeSameLength();
}
// For example ETH / USD, BTC / USD, MKR / USD, etc
for (uint256 i = 0; i < tokenAddresses.length; i++) {
s_priceFeeds[tokenAddresses[i]] = priceFeedAddresses[i];
s_collateralTokens.push(tokenAddresses[i]);
s_timeouts[tokenAddress[i]] = timeouts[i]
}
i_dsc = DecentralizedStableCoin(dscAddress);
}
// 3. Modify OracleLib.staleCheckLatestRoundData() to accept a uint256 timeout parameter and use that to check TIMEOUT.

Support

FAQs

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