Renzo - OMEN's results

A protocol that abstracts all staking complexity from the end-user and enables easy collaboration with EigenLayer node operators and a Validated Services (AVSs).

General Information

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

Renzo

Findings Distribution

Researcher Performance

Rank: 43/122

Findings: 3

Award: $18.61

🌟 Selected for report: 0

🚀 Solo Findings: 0

Awards

0.4071 USDC - $0.41

Labels

bug
3 (High Risk)
satisfactory
sufficient quality report
upgraded by judge
:robot:_71_group
duplicate-326

External Links

Lines of code

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

Vulnerability details

Impact

Reward distribution from eigen layer can be exploited with front running

Proof of Concept

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 .

Tools Used

manual view

make unprofitable for front runner with just minting and burning

Assessed type

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

Lines of code

https://github.com/code-423n4/2024-04-renzo/blob/519e518f2d8dec9acf6482b84a181e403070d22d/contracts/RestakeManager.sol#L317-L319

Vulnerability details

Impact

wrong calculation of total value lock will make the incorrect price of ezETH

Proof of Concept

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); }

Tools Used

manual view

it should be only j index

Assessed type

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)

Findings Information

Awards

18.1958 USDC - $18.20

Labels

bug
2 (Med Risk)
satisfactory
sponsor acknowledged
duplicate-103

External Links

Lines of code

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

Vulnerability details

Impact

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 .

Proof of Concept

```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 .

Tools Used

manual view

before removing the colalteral tokens and operators , pls check that they have stake values in protocol

Assessed type

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

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter