sherlock-audit / 2024-03-arrakis-judging

2 stars 2 forks source link

Naresh - Chainlink's `latestRoundData` might return stale or incorrect results #36

Closed sherlock-admin2 closed 3 months ago

sherlock-admin2 commented 3 months ago

Naresh

medium

Chainlink's latestRoundData might return stale or incorrect results

Summary

Chainlink oracle data feed is not sufficiently validated and can return stale price.

Vulnerability Detail

Contract HOTOracle using latestRoundData, but there is no check if the return value indicates stale data.

   function _getOraclePriceUSD(
        AggregatorV3Interface feed,
        uint32 maxOracleUpdateDuration
    ) internal view returns (uint256 oraclePriceUSD) {
        (, int256 oraclePriceUSDInt, , uint256 updatedAt, ) = feed.latestRoundData();

        if (block.timestamp - updatedAt > maxOracleUpdateDuration) {
            revert HOTOracle___getOraclePriceUSD_stalePrice();
        }

        oraclePriceUSD = oraclePriceUSDInt.toUint256();
    }

Impact

This could lead to stale prices according to the Chainlink documentation: https://docs.chain.link/data-feeds/price-feeds/historical-data Related report: https://github.com/code-423n4/2021-05-fairside-findings/issues/70

Code Snippet

https://github.com/sherlock-audit/2024-03-arrakis/blob/64a7dc6ccb5de2824870474a9f35fd3386669e89/valantis-hot/src/HOTOracle.sol#L138-L148

Tool used

Manual Review

Recommendation

Add the below check for returned data

   function _getOraclePriceUSD(
        AggregatorV3Interface feed,
        uint32 maxOracleUpdateDuration
    ) internal view returns (uint256 oraclePriceUSD) {
-        (, int256 oraclePriceUSDInt, , uint256 updatedAt, ) = feed.latestRoundData();
+        (uint80 roundId, int256 oraclePriceUSDInt, uint256 timestamp , uint256 updatedAt, ) = feed.latestRoundData();

+         require(updatedAt >= roundID, "Stale price");
+         require(timestamp != 0,"Round not complete");
+         require(oraclePriceUSDInt > 0,"Chainlink price reporting 0");

        if (block.timestamp - updatedAt > maxOracleUpdateDuration) {
            revert HOTOracle___getOraclePriceUSD_stalePrice();
        }

        oraclePriceUSD = oraclePriceUSDInt.toUint256();
    }