Using the decimals()
selector for verifying a Chainlink oracle can not be exclusive to price feed contracts
https://github.com/Cyfrin/2024-05-beanstalk-the-finale/blob/main/protocol/contracts/libraries/Silo/LibWhitelist.sol#L453
When a token is whitelisted to the Silo, a function staticall is executed to proof that the oracle implementation is compatible with the type of oracle the contract expects. To do that there are 3 types of oracle:
We can see that the different types of oracles are Chainlink price feed, Uniswap pool and a custom oracle implementation.
In the case of Uniswap pool it calls the function token0()
which is actually a pretty specific function to a Uniswap pool. However for the chainlink price feed it calls the function decimals()
. The problem with this function is that is a pretty common function that a lot of contracts can implement, for example ERC20s. For this reason, if for example an address of an ERC20 is passed as the oracle implementation when whitelisting a token, the call success. However, when Beanstalk will try to fetch a price, the transaction will revert.
The optimal function to ensure that a contract is a chainlink oracle would be the latestRoundData()
function because it is still a view function which can be accessed with a staticall and it is exclusive for chainlink price feeds.
Medium, a mistake can be made easily when whitelisting a token and passing an address of an ERC20 as an oracle implementation and it will not revert
Manual review
Use instead the latestRoundData()
function selector to verify chainlink price feeds.
Invalid as per docs https://docs.codehawks.com/hawks-auditors/how-to-determine-a-finding-validity
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.