Chainlink recommends that all Optimistic L2 oracles check with the Sequencer Uptime Feed to ensure that the sequencer is live/not down before trusting the data returned by the oracle. This check is not implemented in RenzoOracleL2.sol:getMintRate() function where the data from the oracle is used.
RenzoOracleL2:getMintRate() is supposed to be used during ezETH minting process on L2s as seen in xRenzoDeposit.sol: _deposit(). This can cause stale data values to be used during a deposit() if the chainlink sequencer feed is inactive.
* @notice Pulls the price of ezETH
* @dev reverts if price is less than 1 Ether
*/
function getMintRate() public view returns (uint256, uint256) {
(, int256 price, , uint256 timestamp, ) = oracle.latestRoundData();
if (timestamp < block.timestamp - MAX_TIME_WINDOW) revert OraclePriceExpired();
// scale the price to have 18 decimals
uint256 _scaledPrice = (uint256(price)) * 10 ** (18 - oracle.decimals());
if (_scaledPrice < 1 ether) revert InvalidOraclePrice();
return (_scaledPrice, timestamp);
}
in the above snippet we can see that a call is made to the chainlink oracle on the L2 without a check to see if sequencer is active as recommended by chainlink. This can cause stale data which may look correct to be used in the function logic.
Lines of code
https://github.com/code-423n4/2024-04-renzo/blob/519e518f2d8dec9acf6482b84a181e403070d22d/contracts/Bridge/L2/Oracle/RenzoOracleL2.sol#L50-L58
Vulnerability details
Impact
Chainlink recommends that all Optimistic L2 oracles check with the Sequencer Uptime Feed to ensure that the sequencer is live/not down before trusting the data returned by the oracle. This check is not implemented in
RenzoOracleL2.sol:getMintRate()
function where the data from the oracle is used.RenzoOracleL2:getMintRate()
is supposed to be used during ezETH minting process on L2s as seen inxRenzoDeposit.sol: _deposit()
. This can cause stale data values to be used during a deposit() if the chainlink sequencer feed is inactive.More information on chainlink-L2 Sequencer feed here -> https://docs.chain.link/data-feeds/l2-sequencer-feeds#overview
Proof of Concept
https://github.com/code-423n4/2024-04-renzo/blob/519e518f2d8dec9acf6482b84a181e403070d22d/contracts/Bridge/L2/Oracle/RenzoOracleL2.sol#L50C1-L57C6
in the above snippet we can see that a call is made to the chainlink oracle on the L2 without a check to see if sequencer is active as recommended by chainlink. This can cause stale data which may look correct to be used in the function logic.
Tools Used
manual review
Recommended Mitigation Steps
check for if the sequencer is live/active before using the data. Here is an example as recommended by the chainlink docs -> https://docs.chain.link/data-feeds/l2-sequencer-feeds#example-code
Assessed type
Oracle