Platform: Code4rena
Start Date: 24/07/2023
Pot Size: $100,000 USDC
Total HM: 18
Participants: 73
Period: 7 days
Judge: alcueca
Total Solo HM: 8
Id: 267
League: ETH
Rank: 35/73
Findings: 1
Award: $104.41
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: 0xkazim
Also found by: Auditwolf, BRONZEDISC, Hama, MohammedRizwan, R-Nemes, dacian, kodyvim, markus_ether, nadin, niki, okolicodes
104.4113 USDC - $104.41
It is important to note that the Chainlink Price Oracle data feed aggregator incorporates two variables, namely minAnswer and maxAnswer values. These variables serve as bounds that prevent the aggregator from updating the latestAnswer value if it falls outside the agreed range of acceptable values.
However, it is crucial to understand that the contract application is still capable of reading the most recent answer from the Chainlink Price Oracle, regardless of whether it falls within the accepted range or not. This implies that the contract's borrowing functionality may utilize asset prices that fall outside the expected range, potentially leading to inaccurate calculations and incorrect borrowing decisions.
The impact of this situation can be significant. Borrowers relying on asset prices that deviate from the acceptable range may face increased risks and potential financial losses. It is crucial to carefully evaluate the implications of using data that falls outside the predefined bounds and consider implementing additional checks or alternative data sources to ensure the accuracy and reliability of asset pricing information.
chainlink docs The data feed aggregator includes both minAnswer and maxAnswer values. These variables prevent the aggregator from updating the latestAnswer outside the agreed range of acceptable values, but they do not stop your application from reading the most recent answer.
core/Oracles/ChainlinkOracle.sol#L97C1-L113C6
function getChainlinkPrice( AggregatorV3Interface feed ) internal view returns (uint256) { (, int256 answer, , uint256 updatedAt, ) = AggregatorV3Interface(feed) .latestRoundData(); require(answer > 0, "Chainlink price cannot be lower than 0"); require(updatedAt != 0, "Round is in incompleted state"); // Chainlink USD-denominated feeds store answers at 8 decimals uint256 decimalDelta = uint256(18).sub(feed.decimals()); // Ensure that we don't multiply the result by 0 if (decimalDelta > 0) { return uint256(answer).mul(10 ** decimalDelta); } else { return uint256(answer); } }
Manual review
getChainlinkPrice
function should check the returned price is within some specied bounds and revert if the price is outside those values.
function getChainlinkPrice( AggregatorV3Interface feed ) internal view returns (uint256) { (, int256 answer, , uint256 updatedAt, ) = AggregatorV3Interface(feed) .latestRoundData(); require(answer > 0, "Chainlink price cannot be lower than 0"); require(updatedAt != 0, "Round is in incompleted state"); --->if (price >= maxPrice or price <= minPrice) revert(); // Chainlink USD-denominated feeds store answers at 8 decimals uint256 decimalDelta = uint256(18).sub(feed.decimals()); // Ensure that we don't multiply the result by 0 if (decimalDelta > 0) { return uint256(answer).mul(10 ** decimalDelta); } else { return uint256(answer); } }
Invalid Validation
#0 - 0xSorryNotSorry
2023-08-02T15:19:08Z
The implementation does not set a min/max value by design. Also Chainlink does not return min/max price as per the AggregatorV3 docs HERE contrary to the reported.
Further proof required as per the context.
#1 - c4-pre-sort
2023-08-02T15:19:12Z
0xSorryNotSorry marked the issue as low quality report
#2 - c4-judge
2023-08-13T21:40:02Z
alcueca marked the issue as duplicate of #340
#3 - c4-judge
2023-08-13T21:40:05Z
alcueca marked the issue as satisfactory