Platform: Code4rena
Start Date: 30/04/2024
Pot Size: $112,500 USDC
Total HM: 22
Participants: 122
Period: 8 days
Judge: alcueca
Total Solo HM: 1
Id: 372
League: ETH
Rank: 43/122
Findings: 3
Award: $18.61
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: guhu95
Also found by: 0rpse, 0x007, 0x73696d616f, 0xCiphky, 0xabhay, Audinarey, Bauchibred, Fassi_Security, GalloDaSballo, GoatedAudits, KupiaSec, LessDupes, MSaptarshi, OMEN, Ocean_Sky, RamenPeople, SBSecurity, Tendency, WildSniper, aslanbek, bill, blutorque, crypticdefense, cu5t0mpeo, d3e4, gjaldon, grearlake, gumgumzum, honey-k12, ilchovski, jokr, josephdara, kennedy1030, p0wd3r, peanuts, stonejiajia, t0x1c, tapir, underdog, zzykxx
0.4071 USDC - $0.41
https://github.com/code-423n4/2024-04-renzo/blob/519e518f2d8dec9acf6482b84a181e403070d22d/contracts/Rewards/RewardHandler.sol#L58-L70 https://github.com/code-423n4/2024-04-renzo/blob/519e518f2d8dec9acf6482b84a181e403070d22d/contracts/Deposits/DepositQueue.sol#L163-L183
Reward distribution from eigen layer can be exploited with front running
Protocol implement that all rewards from eigen layer send forward to deposit queue to fill the withdrawal buffer deficit and restake again at eigen layer .Cause of sending native eth in deposit queue , total TVL will be increased .But ezETH was not minted . ezETH value is calculated based on total TVL / total supply of ezETH.This means valuation of ezETH is increased due to reward distribution from eigen layer .However malicious user can see that reward distribution transaction in the mempool .So before reward transaction is executed , malicious user front run and deposit into restake manager to get back ezETH before it's price is increased.After reward distribution trasaction is executed , ezETH will be increased .Then malicious user burn the ezETH which become more valuable to get back ETH.
POC 1.Reward handler send reward to deposit queue 2.malicious user see that in mempool and mint ezETH with front running 3.ezETH value is increased due to rewards 4.then malicious user burn ezETH and take profits
Malicious profits from sandwiching the reward distribution is directly proportional to rewards send from reward handler .
manual view
make unprofitable for front runner with just minting and burning
MEV
#0 - c4-judge
2024-05-17T12:56:18Z
alcueca changed the severity to 3 (High Risk)
#1 - c4-judge
2024-05-17T12:56:34Z
alcueca marked the issue as duplicate of #326
#2 - c4-judge
2024-05-17T12:56:42Z
alcueca marked the issue as satisfactory
🌟 Selected for report: pauliax
Also found by: 0rpse, 0x73696d616f, 0xAadi, 0xCiphky, 0xPwned, 0xhacksmithh, 0xnev, 0xnightfall, 0xordersol, 14si2o_Flint, Aamir, Aymen0909, BiasedMerc, DanielArmstrong, Fassi_Security, FastChecker, GoatedAudits, Greed, KupiaSec, LessDupes, Maroutis, NentoR, OMEN, SBSecurity, Stefanov, TheFabled, adam-idarrha, ak1, aman, araj, aslanbek, b0g0, baz1ka, bigtone, blutorque, carlitox477, carrotsmuggler, crypticdefense, eeshenggoh, fyamf, gesha17, gjaldon, grearlake, guhu95, honey-k12, hunter_w3b, ilchovski, josephdara, kinda_very_good, lanrebayode77, m_Rassska, maxim371, mt030d, mussucal, oakcobalt, p0wd3r, peanuts, rbserver, shui, siguint, t0x1c, tapir, twcctop, ustazz, xg, zhaojohnson, zigtur, zzykxx
0.0026 USDC - $0.00
wrong calculation of total value lock will make the incorrect price of ezETH
if (!withdrawQueueTokenBalanceRecorded) { totalWithdrawalQueueValue += renzoOracle.lookupTokenValue( //*@audit-issue ----->>> it should be j index collateralTokens[i], collateralTokens[j].balanceOf(withdrawQueue) ); }
when calculating the TVL , value assets in withdrawal queue are also added to retrieve that TVL . However code implementation is incorrect . Protocol first loop the through total operator which use i as index . Within that loop , there is another loop for calculating each token values which use as j index .Withing calculating each collateral tokens , protocol intend to calculating total value from withdrawal queue .Cause in withdrawal queue , tokens are still over there until users come and get withdraw those tokens .While calculating that value , protocol use i
index of collateral tokens address with j
index of collateral token balance .So that means Only index 0 of collateral tokens array will be used with for all index of collateral tokens Balance array . The rest index of collateral tokens array are not calculated .This will cause the incorrect price and in the worst cause scenario , if wrong calculating tvl will cause ezETH below the 1 ether , protocol will not working anymore cause of ezETH price check in oracle.
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()); //*@audit ------>> price has to be above 1 ether if (_scaledPrice < 1 ether) revert InvalidOraclePrice(); return (_scaledPrice, timestamp); }
manual view
it should be only j
index
Context
#0 - c4-judge
2024-05-16T10:35:06Z
alcueca marked the issue as satisfactory
#1 - c4-judge
2024-05-16T10:38:47Z
alcueca changed the severity to 2 (Med Risk)
#2 - c4-judge
2024-05-16T10:39:08Z
alcueca changed the severity to 3 (High Risk)
#3 - c4-judge
2024-05-20T04:26:26Z
alcueca changed the severity to 2 (Med Risk)
#4 - c4-judge
2024-05-23T13:47:21Z
alcueca changed the severity to 3 (High Risk)
18.1958 USDC - $18.20
https://github.com/code-423n4/2024-04-renzo/blob/519e518f2d8dec9acf6482b84a181e403070d22d/contracts/RestakeManager.sol#L244-L263 https://github.com/code-423n4/2024-04-renzo/blob/519e518f2d8dec9acf6482b84a181e403070d22d/contracts/RestakeManager.sol#L160-L184
lose of funds for users who deposit into protocol and holding ezETH if protocol remove collateral tokens and operators while collateral tokens is staking at eigen layer and operators having staked values .
```function removeOperatorDelegator( IOperatorDelegator _operatorDelegatorToRemove ) external onlyRestakeManagerAdmin { // Remove it from the list uint256 odLength = operatorDelegators.length; //*@audit-issue -------->>> don't remove it when O.D have stake values for (uint256 i = 0; i < odLength; ) { if (address(operatorDelegators[i]) == address(_operatorDelegatorToRemove)) { // Clear the allocation operatorDelegatorAllocations[_operatorDelegatorToRemove] = 0; emit OperatorDelegatorAllocationUpdated(_operatorDelegatorToRemove, 0); // Remove from list operatorDelegators[i] = operatorDelegators[operatorDelegators.length - 1]; operatorDelegators.pop(); emit OperatorDelegatorRemoved(_operatorDelegatorToRemove); return; } unchecked { ++i; } } // If the item was not found, throw an error revert NotFound(); }``` function removeCollateralToken( IERC20 _collateralTokenToRemove ) external onlyRestakeManagerAdmin { // Remove it from the list //*@audit-issue --------->>> don't remove it if collateral tokens are in staked value uint256 tokenLength = collateralTokens.length; for (uint256 i = 0; i < tokenLength; ) { if (address(collateralTokens[i]) == address(_collateralTokenToRemove)) { //*@audit-info ------>>> check that after poping last index , previous last index went to where? collateralTokens[i] = collateralTokens[collateralTokens.length - 1]; collateralTokens.pop(); emit CollateralTokenRemoved(_collateralTokenToRemove); return; } unchecked { ++i; } } // If the item was not found, throw an error revert NotFound(); }
Both remove functions for collateral tokens and operators have no check for that collateral tokens which gonna removed has staked values by each operators at eigen layer and tokens in the withdrawal queue or NOT . IF removed collateral tokens have values at protocol, it gonna make negative impact at calculating TVL. When calculating TVL , each collateral tokens value is calculated with balance of each collateral tokens in protocol multiplied by it's price.
for (uint256 i = 0; i < odLength; ) { // Track the TVL for this OD uint256 operatorTVL = 0; // Track the individual token TVLs for this OD - native ETH will be last item in the array uint256[] memory operatorValues = new uint256[](collateralTokens.length + 1); operatorDelegatorTokenTVLs[i] = operatorValues; // Iterate through the tokens and get the value of each uint256 tokenLength = collateralTokens.length; //*@audit-info ------>>> collateral token is removed while being on staked at eigen layer //*@audit-info ------>>> while calculating total tvl , there will be missing value for staked collateral for (uint256 j = 0; j < tokenLength; ) { // Get the value of this token uint256 operatorBalance = operatorDelegators[i].getTokenBalanceFromStrategy( collateralTokens[j] ); // Set the value in the array for this OD operatorValues[j] = renzoOracle.lookupTokenValue( collateralTokens[j], operatorBalance ); // Add it to the total TVL for this OD operatorTVL += operatorValues[j]; // record token value of withdraw queue if (!withdrawQueueTokenBalanceRecorded) { totalWithdrawalQueueValue += renzoOracle.lookupTokenValue( //*@audit-issue ----->>> it should be j index collateralTokens[i], collateralTokens[j].balanceOf(withdrawQueue) ); } unchecked { ++j; } }
total value locked will be decreased due to remove collateral while having staked values . And there 's no burning the ezETH . This means value of ezETH is decreased . Due to ezETH value is decreased , user will lose funds while holding ezETH.Also Removing the operators while having stake values in the protocol will make above scenario. In the worst scenario , due to remove those collateral and operators , TVL is decreased and make the price of ezETH to below 1 ether .And then protocol will not work anymore due to check that price has to be above 1 ether in price oracle .
manual view
before removing the colalteral tokens and operators , pls check that they have stake values in protocol
Context
#0 - thebrittfactor
2024-05-21T14:03:10Z
For transparency, the judge has requested that issue #461Â be duplicated, as it contains two issues they deemed should be judged separately.
#1 - c4-judge
2024-05-23T10:08:42Z
alcueca marked the issue as duplicate of #5
#2 - c4-judge
2024-05-23T10:08:45Z
alcueca marked the issue as satisfactory