code-423n4 / 2024-04-renzo-findings

9 stars 7 forks source link

Malicious user can frontrun first depositor to block all protocol deposits leading to a protocol-wide DOS #63

Closed howlbot-integration[bot] closed 4 months ago

howlbot-integration[bot] commented 4 months ago

Lines of code

https://github.com/code-423n4/2024-04-renzo/blob/519e518f2d8dec9acf6482b84a181e403070d22d/contracts/RestakeManager.sol#L565-L569 https://github.com/code-423n4/2024-04-renzo/blob/519e518f2d8dec9acf6482b84a181e403070d22d/contracts/Oracle/RenzoOracle.sol#L123-L149

Vulnerability details

Impact

Malicious user can block the deposits of all collateralToken into the protocol so as

Proof of Concept

This attack is a combination because of the donation and first depositor Attack

For simplicity, I assume withdrawalBufferTarget = 11 ether (although not needed)


File: RestakeManager.sol
491:     function deposit(
492:         IERC20 _collateralToken,
493:         uint256 _amount,
494:         uint256 _referralId
495:     ) public nonReentrant notPaused {
496:         // Verify collateral token is in the list - call will revert if not found
497:         uint256 tokenIndex = getCollateralTokenIndex(_collateralToken);
498: 
499:         // Get the TVLs for each operator delegator and the total TVL
500:         (
501:             uint256[][] memory operatorDelegatorTokenTVLs,
502:             uint256[] memory operatorDelegatorTVLs,
504:             uint256 totalTVL
505:         ) = calculateTVLs();

538:         ...

564:         // Calculate how much ezETH to mint
565:  @>       uint256 ezETHToMint = renzoOracle.calculateMintAmount(
610:             totalTVL,
611:             collateralTokenValue,
612:             ezETH.totalSupply()
613:         );

File: RenzoOracle.sol
124:     function calculateMintAmount(
125:         uint256 _currentValueInProtocol,  // totalTVL
126:         uint256 _newValueAdded,
127:         uint256 _existingEzETHSupply
128:     ) external pure returns (uint256) {
129:         // For first mint, just return the new value added.
130:         // Checking both current value and existing supply to guard against gaming the initial mint
131:         if (_currentValueInProtocol == 0 || _existingEzETHSupply == 0) {
132:             return _newValueAdded; // value is priced in base units, so divide by scale factor
134:         }
135: 
136:         // Calculate the percentage of value after the deposit
137:         uint256 inflationPercentaage = (SCALE_FACTOR * _newValueAdded) / (_currentValueInProtocol + _newValueAdded);
138: 
139:         // Calculate the new supply ==>> targetv supply
140:         uint256 newEzETHSupply = (_existingEzETHSupply * SCALE_FACTOR) / (SCALE_FACTOR - inflationPercentaage);
141: 
142:         // Subtract the old supply from the new supply to get the amount to mint
143:         uint256 mintAmount = newEzETHSupply - _existingEzETHSupply;
144: 
145:         // Sanity check
146: @>      if (mintAmount == 0) revert InvalidTokenAmount();
147: 
148:         return mintAmount;
149:     }
            uint256 _currentValueInProtocol = totalTVL = 10000000000000000001 // (10ETH + 1 wei)
            uint256 _newValueAdded = 10000000000000000000 // 10 ether of Alice collateral token
            uint256 _existingEzETHSupply = 1 // current ezETH totalSupply

            // inflationPercentaage = (SCALE_FACTOR * _newValueAdded) / (_currentValueInProtocol + _newValueAdded);
            uint256 inflationPercentaage = (1e18 * 10000000000000000000) / (10000000000000000001 + 10000000000000000000)
                 = (1000000000000000000 * 10000000000000000000) / 20000000000000000001
                 = 499999999999999999

            // newEzETHSupply = (_existingEzETHSupply * SCALE_FACTOR) / (SCALE_FACTOR - inflationPercentaage);
            uint256 newEzETHSupply = ( 1 * 1000000000000000000) / (1e18 - 499999999999999999)
                 =  ( 1 * 1000000000000000000) / 500000000000000001
                 = 1
            // mintAmount = newEzETHSupply - _existingEzETHSupply;
            uint256 mintAmount = 1 - 1 = 0
- `mintAmount` for Alice evaluates to zero and the deposit function reverts
     if (mintAmount == 0) revert InvalidTokenAmount();

Tools Used

Manual review

Recommended Mitigation Steps

Consider making a sacrificial deposit of substantial amount at the point of deployment.

Assessed type

Other

c4-judge commented 4 months ago

alcueca marked the issue as unsatisfactory: Invalid