The library LibUsdOracle
relies on the Chainlink price feed registry with hardcoded address, but this address is specific to the Ethereum mainnet. However, the protocol is intended to be deployed on other EVM-equivalent Layer 2 chains, which don't support this registry address. Also, the protocol uses a WETH
address that is for Ethereum mainnet. The functionality of the protocol that relies on this address will be broken on the other chains.
The chainlinkRegistry
is used in the LibUsdOracle::getTokenPriceFromExternal
function to obtain the address of the Chainlink price feed aggregator for a specific token pair (e.g., token/USD), if the target address in the oracleImpl
is not set. This is achieved through the getFeed
function, which takes the base token address and the quote token address (USD) as parameters.
The problem is that the Chainlink registry address is harcoded in the contract:
This hardcoded address is the address of the chainlinkRegistry
on the Ethereum mainnet. In the README
is written that the protocol will be deployed also on EVM-equivalent L2 chains. But deploying the protocol on other chains without modifying this address will result in failed oracle lookups and incorrect price feeds. Additionally, according to the chainlink documentation the chainlinkRegistry
for now is available only on Ethereum mainnet.
Also, the protocol uses the WETH
address, that is hardcoded in some contracts (LibWeth.sol
and C.sol
(out of scope, but the impact is in the scope))
Link: https://github.com/Cyfrin/2024-05-beanstalk-the-finale/blob/4e0ad0b964f74a1b4880114f4dd5b339bc69cd3e/protocol/contracts/libraries/Token/LibWeth.sol#L16
In LibWeth.sol
library:
The problem is that the WETH
token has different addresses on the different chains. The hardcoded address is the WETH
address on the Ethereum mainnet. But if the protocol is deployed on the other EVM-equivalent L2 chain the address will be different. For example, in Arbitrum the address of the WETH
token is: 0x82af49447d8a07e3bd95bd0d56f35241523fbab1
.
There is also one more important hardcoded variable that wouldn't be correct when the protocol is deployed on L2 chain that is the CHAIN_ID
in the C.sol
contract. The CHAIN_ID
is retrived by the function C.hetChainId
in LibTractor
, LibSiloPermit
and LibTokenPermit
contracts in order to build the domain separator. The hardcoded CHAIN_ID
constant specified in C.sol
is not recommended also due to possibility of replaying of all signed permits from Ethereum mainnet on the forked chain, but this is a known issue from the Cyfrin audit.
The LibUsdOracle::getTokenPriceFromExternal
is called in the OracleFacet::getTokenPriceFromExternal
to retrive the token price. If the Chainlink registry is not available on the deployed chain the protocol will be unable to retrive the price feed.
If the LibWeth
is deployed on the EVM-equivalent L2 chains the library will be useless, because its functionality relies on the hardcoded WETH
address that is not correct for the other chain different from Ethereum mainnet.
The CHAIN_ID
in the C.sol
is defined as 1
and this is correct for the Ethereum mainnet, but for example the Arbitrium's chainId is different (42161). The transaction will be considered invalid by the network, and nodes will reject it. This is because the chainId
is used to prevent replay attacks, ensuring that the transaction is meant for the specific blockchain.
Manual Review
Don't rely on the Chainlink registry on chain different from Ethereum mainnet and check all hardcoded addresses and varibales if they are correct for the choosen L2 chain before deploying on it. Also, you can add functionality the owner to modify these addresses.
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.