xanoutas/solidity-security-findings huggingface dataset:
Vulnerable to inflation attacks when making deposits
Audit: 2024-04-renzo-findings
Severity: HIGH

# Lines of code

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


# Vulnerability details

## Impact

Deposits are vulnerable to inflation attacks, resulting in user losses.

## Proof of Concept

The formula for calculating the shares received by a user upon deposit is: `totalSupply(share) / (1 - (deltaAsset/(totalAsset+deltaAsset))) - totalSupply(share)`. 

However, in reality, this formula is equivalent to: `deltaAsset * SupplyShare / totalAsset`.

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

Therefore, if a user donates to Withdraw, causing the totalAsset price to rise, this will result in the next user receiving significantly fewer shares than expected upon deposit, leading to losses.

Proof of Concept (PoC):

1. User B wants to deposit 100,000 tokens.
2. User A discovers B's transaction to deposit 100,000 tokens in the mempool and deposits 1 token first, obtaining 1 share.
3. User A then donates 49,999 tokens to the WithdrawQueue contract.
4. The share calculation for User B's deposit of 100,000 tokens is: 1 / (1 - (100,000 / (50,000 + 100,000))) - 1 => 2.999999 - 1 = 1.
5. User A withdraws 75,000 tokens.



## Tools Used

Manual Review

## Recommended Mitigation Steps

Add minShare parameter.


## Assessed type

Math
When withdrawing ezETH for LST collateral, some collateral will be stuck if the LST is rebasing
Audit: 2024-04-renzo-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-04-renzo/blob/519e518f2d8dec9acf6482b84a181e403070d22d/contracts/Withdraw/WithdrawQueue.sol#L206-L262


# Vulnerability details

## Impact

Stuck funds in the WithdrawQueue contract. Users will get lesser amount back than intended. It will also affect the TVL calculation.

## Proof of Concept

When withdrawing collateral, users must deposit their ezETH in exchange for the collateral they want, eg stETH. The function checks that they have enough collateral in the contract to exchange for the ezETH, and add to the withdrawRequest of the user.

The function transfers ezETH into the WithdrawQueue contract.

```
    function withdraw(uint256 _amount, address _assetOut) external nonReentrant {
        // check for 0 values
        if (_amount == 0 || _assetOut == address(0)) revert InvalidZeroInput();

        // check if provided assetOut is supported
        if (withdrawalBufferTarget[_assetOut] == 0) revert UnsupportedWithdrawAsset();

        // transfer ezETH tokens to this address
        IERC20(address(ezETH)).safeTransferFrom(msg.sender, address(this), _amount);

```

The function calculates the TVL and calculates the redeem amount in ETH.

```

        // calculate totalTVL
        (, , uint256 totalTVL) = restakeManager.calculateTVLs();

        // Calculate amount to Redeem in ETH
        uint256 amountToRedeem = renzoOracle.calculateRedeemAmount(
            _amount,
            ezETH.totalSupply(),
            totalTVL
        );
```

The function then converts the ETH amount to the collateral amount

```
        // update amount in claim asset, if claim asset is not ETH
        if (_assetOut != IS_NATIVE) {
            // Get ERC20 asset equivalent amount
            amountToRedeem = renzoOracle.lookupTokenAmountFromValue(
                IERC20(_assetOut),
                amountToRedeem
            );
        }

        // revert if amount to redeem is greater than withdrawBufferTarget
        if (amountToRedeem > getAvailableToWithdraw(_assetOut)) revert NotEnoughWithdrawBuffer();

```
The function lastly adds to the withdrawRequests.
```
        // increment the withdrawRequestNonce
        withdrawRequestNonce++;

        // add withdraw request for msg.sender
        withdrawRequests[msg.sender].push(
            WithdrawRequest(
                _assetOut,
                withdrawRequestNonce,
                amountToRedeem,
                _amount,
                block.timestamp
            )
        );

        // add redeem amount to claimReserve of claim asset
        claimReserve[_assetOut] += amountToRedeem;

        emit WithdrawRequestCreated(
            withdrawRequestNonce,
            msg.sender,
            _assetOut,
            amountToRedeem,
            _amount,
            withdrawRequests[msg.sender].length - 1
        );
    }
```

The user then waits for 7 days before they can claim their collateral amount.

The issue is that some LST are rebasing, meaning the
Withdrawal amount calculation timing causes yield leakage and asset imbalance
Audit: 2024-04-renzo-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-04-renzo/blob/main/contracts/Withdraw/WithdrawQueue.sol#L217-L233
https://github.com/code-423n4/2024-04-renzo/blob/main/contracts/Withdraw/WithdrawQueue.sol#L305-L308


# Vulnerability details


## Cause

The `WithdrawQueue` contract calculates the withdrawal redemption amount [at the time of the withdrawal request](https://github.com/code-423n4/2024-04-renzo/blob/main/contracts/Withdraw/WithdrawQueue.sol#L217-L233) but [pays out the amount at the time of the claim](https://github.com/code-423n4/2024-04-renzo/blob/main/contracts/Withdraw/WithdrawQueue.sol#L305-L308). 
- For ETH and **rebasing** LSTs like **stETH**, this means that the withdrawal asset **does not earn yield** during the delay (as the ETH value of an amount is constant). 
- However, for **accruing** LSTs like **wBETH**, the withdrawal will continue earning yield during the delay period (because its price increases with the yield).

## Impact

For accruing LSTs, this means that yield that can be accrued for ezETH holders, is instead accrued to withdrawals, and lost to the protocol.

This will also create an imbalance in deposit and withdrawal flows because users will prefer to redeem in accruing tokens to avoid losing 7 days of yield.

This, in turn, will skew the asset composition, causing the protocol to accumulate rebasing LSTs over time [to reach their TVL cap](https://github.com/code-423n4/2024-04-renzo/blob/main/contracts/RestakeManager.sol#L529-L530) and revert on subsequent deposits. This will result in an ongoing DoS of deposits for these assets.

While it's possible to keep increasing TVL caps for rebasing LSTs, it is unlikely to be a long term solution, because would not be responsible risk management and would reduce asset diversification.

## Proof of Concept

1. Users will deposit all supported LSTs.
2. Users will withdraw predominantly accruing LSTs due to the yield accrued during withdrawal delay.
3. The accruing LSTs' yield will be lost to ezETH holders.
4. The rebasing LSTs will keep accumulating over time in the protocol due to imbalanced flows, hitting TVL caps required for risk management and diversification.
5. Users will not be able to deposit rebasing LSTs when their TVL cap is reached and not increased.

## Tools Used

Manual Review

## Recommended Mitigation Steps

Calculate the redemption from **ezETH to ETH** value at the withdrawal **request time**, but calculate the final **LST amount** at **claim time** for all assets. This will keep the ETH value of a withdrawal fixed for the duration of the delay and **divert the yield earned to the ezETH holders**. 

Alternatively, allow the admin to rebalance the asset mixture by swapping assets withdrawn from Eigenlayer before transferring them to the `WithdrawQueue`.

```diff
    function withdraw(uint256 _amount, address _assetOut) external nonReentrant {
	    ...
	    
        // Calculate amount to Redeem in ETH
        uint256 amountToRedeem = renzoOracle.ca
Incorrect Minting Calculation in Deposit Functions Due to Stale Total Value Locked (TVL)
Audit: 2024-04-renzo-findings
Severity: HIGH

# Lines of code

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


# Vulnerability details

## Impact
The current implementation of the [`deposit`](https://github.com/code-423n4/2024-04-renzo/blob/519e518f2d8dec9acf6482b84a181e403070d22d/contracts/RestakeManager.sol#L491-L576) and [`depositETH`](https://github.com/code-423n4/2024-04-renzo/blob/519e518f2d8dec9acf6482b84a181e403070d22d/contracts/RestakeManager.sol#L592-L616) functions in the `RestakeManager.sol` makes use of a stale `totalTVL` value when calculating the amount of `ezETH` to mint for a depositor. This stale value does not include the value of the assets being deposited in the current transaction. As a result, the amount of `ezETH` minted for the depositor may be less than what they are rightfully entitled to based on their contribution to the total pool. This can lead to discrepancies in token distribution, affecting the fairness and accuracy of the protocol's token economics.


As per the [README](https://github.com/code-423n4/2024-04-renzo/blob/main/README.md#main-invariants), 
> ezETH should be minted or redeemed based on current supply and TVL.

Hence, I marked this as High severity



## Proof of Concept

### Current Implementation in `RestakeManager.sol`
Here is the relevant part of the `deposit` function:

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

```solidity
// Get the value of the collateral token being deposited
uint256 collateralTokenValue = renzoOracle.lookupTokenValue(_collateralToken, _amount);
```
https://github.com/code-423n4/2024-04-renzo/blob/519e518f2d8dec9acf6482b84a181e403070d22d/contracts/RestakeManager.sol#L652

```solidity
// Get the TVLs for each operator delegator and the total TVL
(uint256[][] memory operatorDelegatorTokenTVLs, uint256[] memory operatorDelegatorTVLs, uint256 totalTVL) = calculateTVLs();
```


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

```solidity
// Calculate how much ezETH to mint
uint256 ezETHToMint = renzoOracle.calculateMintAmount(
    totalTVL,
    collateralTokenValue,
    ezETH.totalSupply()
);
```

### `calculateMintAmount` Function in `RenzoOracle.sol`
https://github.com/code-423n4/2024-04-renzo/blob/519e518f2d8dec9acf6482b84a181e403070d22d/contracts/Oracle/RenzoOracle.sol#L123-L149

```solidity
function calculateMintAmount(
    uint256 _currentValueInProtocol,
    uint256 _newValueAdded,
    uint256 _existingE
Miscalculation of TVL in RestakeManager.sol Leads to Discrepancies
Audit: 2024-04-renzo-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-04-renzo/blob/main/contracts/RestakeManager.sol#L316-L321


# Vulnerability details

## Impact
The bug causes the Total Value Locked (TVL) to be calculated incorrectly. This means that important financial calculations across the protocol are wrong. Incorrect TVL affects reward distribution, minting ezETH, wrong calculations of rate of ezETH etc.

## Proof of Concept
[Code](https://github.com/code-423n4/2024-04-renzo/blob/main/contracts/RestakeManager.sol#L316-L321)

## Tools Used
Manual Review

## Recommended Mitigation Steps
```diff
if (!withdrawQueueTokenBalanceRecorded) {
       totalWithdrawalQueueValue += renzoOracle.lookupTokenValue(
-       collateralTokens[i],
+       collateralTokens[j],
       collateralTokens[j].balanceOf(withdrawQueue)
    );
}
```


## Assessed type

Other
Incorrect loop ordering allows minting ezETH at inflated rate
Audit: 2024-04-renzo-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-04-renzo/blob/main/contracts/RestakeManager.sol#L289
https://github.com/code-423n4/2024-04-renzo/blob/main/contracts/RestakeManager.sol#L299
https://github.com/code-423n4/2024-04-renzo/blob/main/contracts/RestakeManager.sol#L316-L321


# Vulnerability details

The [`RestakeManager.calculateTVLs()`](https://github.com/code-423n4/2024-04-renzo/blob/519e518f2d8dec9acf6482b84a181e403070d22d/contracts/RestakeManager.sol#L274) function serves to calculate the protocol's TVL, which is used together with the total ezETH supply to determine the mint and redeem rates. This function iterates through all `OperatorDelegator` contracts and sums up the value of their staked collateral tokens and ETH, and adds the balance of collateral tokens held in the `WithdrawQueue` contract.

This is implemented as an outer loop that iterates over the operator delegators, and an inner loop that iterates over the collateral tokens for each operator delegator.

However, there is an issue with how the TVL locked in the withdrawal queues is accounted for. The TVL in the queue is only counted if there is at least one operator delegator. If there are no operator delegators, either when the protocol is freshly deployed or if they are later removed e.g. in order to migrate to new ones, the queues will not be accounted for in the TVL calculation, leading to an incorrect value being reported.

This incorrect TVL value is then used in the [`depositETH()`](https://github.com/code-423n4/2024-04-renzo/blob/main/contracts/RestakeManager.sol#L592) function to calculate the amount of ezETH to mint for a given ETH deposit. If the TVL is underreported due to the issue described above, users will be able to mint ezETH at an artificially inflated rate.

## Impact
If the protocol has no operator delegators, either when it is freshly deployed or if they are later removed, users will be able to mint ezETH at an artificially inflated rate when calling `depositETH()`. This is because the TVL used in the calculation will be underreported, not accounting for the value locked in the withdrawal queue.

## Proof of Concept
Consider the following scenario:

1. The protocol is freshly deployed, and no operator delegators have been added yet.
2. All user deposits go to the withdrawal queue, so it holds a significant amount of value in various collateral tokens.
3. User calls `depositETH()` with an ETH amount, which calls  `calculateTVLs()`.
4. `calculateTVLs()` only reports the ETH value in the deposit and withdraw queues.
8. User receives more ezETH than they should, based on the actual total value locked in the protocol.

The same scenario could occur if the protocol previously had operator delegators, but they were later removed, leaving the queues holding value that is not accounted for in the TVL calculation.

## Tools Used
Manual review

## Recommended Mitigation Steps
To fix this issue, the order of the loops should be swapped. The outer loop should
ezETH bridged price will be incorrect due to issue in totalTVL accounting
Audit: 2024-04-renzo-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-04-renzo/blob/main/contracts/RateProvider/BalancerRateProvider.sol#L29-L40
https://github.com/code-423n4/2024-04-renzo/blob/main/contracts/Delegation/OperatorDelegator.sol#L329
https://github.com/code-423n4/2024-04-renzo/blob/main/contracts/RestakeManager.sol#L317-L319


# Vulnerability details

## Impact

L1 contract sends an undervalued ezETH price to L2.

This can allow users to mint more ezETH on L2 than expected for the same amount of ETH.


## Proof of Concept

### Root cause

The [`xRenzoBridge.sendPrice` function retrieves the ezETH price](https://github.com/code-423n4/2024-04-renzo/blob/main/contracts/Bridge/L1/xRenzoBridge.sol#L215) to send it to the L2 contracts.
ezETH price is calculated in the `BalancerRateProvider.getRate` function based on [the totalTVL](https://github.com/code-423n4/2024-04-renzo/blob/main/contracts/RateProvider/BalancerRateProvider.sol#L31) in protocol and the ezETH total supply.

```solidity
    /// @dev Returns the current rate of ezETH in ETH
    function getRate() external view returns (uint256) {
        // Get the total TVL priced in ETH from restakeManager
        (, , uint256 totalTVL) = restakeManager.calculateTVLs();

        // Get the total supply of the ezETH token
        uint256 totalSupply = ezETHToken.totalSupply();

        // Sanity check
        if (totalSupply == 0 || totalTVL == 0) revert InvalidZeroInput();

        // Return the rate
        return (10 ** 18 * totalTVL) / totalSupply;
    }
```

However, the `totalTVL` calculated in `RestakeManager.calculateTVLs()` has two issues that will reduce the amount of total TVL:
- issue 01: `WithdrawalQueue`'s value is incorrectly accounted in totalTVL due to [a confusion in variable names](https://github.com/code-423n4/2024-04-renzo/blob/main/contracts/RestakeManager.sol#L317-L319)
- issue 02: All the `OperatorDelegator` contracts do not account withdraw queued shares in totalTVL due to [an incorrect condition](https://github.com/code-423n4/2024-04-renzo/blob/main/contracts/Delegation/OperatorDelegator.sol#L329)

Combined, these two issues can decrease the `totalTVL` value [returned by `RestakeManager.calculateTVLs()`](https://github.com/code-423n4/2024-04-renzo/blob/main/contracts/RestakeManager.sol#L274-L358).
As this `totalTVL` will be incorrect, the `getRate()` function will return an incorrect price and this price will be bridged to L2.

Then, an undervalued price can be used by users to mint more ezETH tokens on the L2 than on the L1 for a same amount of ETH, bridge back these funds to L1 and exchange them back to ETH on L1.
This will drain value from the protocol.

## Tools Used
Manual review

## Recommended Mitigation Steps

Consider fixing the two issues explained in the root cause section.

### Fix issue 01

Consider fixing the index used for the `collateralTokens` in [the `calculateTVLs` function](https://github.com/code-423n4/2024-04-renzo/blob/main/contracts/RestakeManager.sol#L316-
Exploiting Slashing Events to Front-Run Withdrawals and Inflate Shares Owed
Audit: 2024-04-renzo-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-04-renzo/blob/1c7cc4e632564349b204b4b5e5f494c9b0bc631d/contracts/Withdraw/WithdrawQueue.sol#L206
https://github.com/code-423n4/2024-04-renzo/blob/1c7cc4e632564349b204b4b5e5f494c9b0bc631d/contracts/Withdraw/WithdrawQueue.sol#L279


# Vulnerability details

## Impact
Stakers can exploit this timing gap to withdraw their staked tokens without incurring the losses that would normally result from [penalties](https://eth2book.info/capella/part2/incentives/penalties/) or [slashing events](https://eth2book.info/capella/part2/incentives/slashing/).

## Proof of Concept
A validator experiences penalties or is slashed, reducing their balance.

Before the TVL is updated via [EigenPod::verifyBalanceUpdates()](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v0.2.1-goerli-m2/src/contracts/pods/EigenPod.sol#L185) or [EigenPod::verifyAndProcessWithdrawals()](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v0.2.1-goerli-m2/src/contracts/pods/EigenPod.sol#L232), a staker requests a withdraw all their `LRTTokens` using [withdraw](https://github.com/code-423n4/2024-04-renzo/blob/1c7cc4e632564349b204b4b5e5f494c9b0bc631d/contracts/Withdraw/WithdrawQueue.sol#L206).

The staker then triggers the update of the TVL by calling one of the aforementioned functions.
When [withdraw](https://github.com/code-423n4/2024-04-renzo/blob/1c7cc4e632564349b204b4b5e5f494c9b0bc631d/contracts/Withdraw/WithdrawQueue.sol#L206) is executed, the withdrawal is processed without accounting for the recent penalties or slashing, as the TVL drop is instantaneous upon the update.

for example:

Initial state:
2 validators 32 ETH each
10 users with equal LRT, 6.4 each.

1. Validator 1 is slashed for 16 ETH
2. User 1 front-runs `verifyBalanceUpdates()` with a call to tWithdrawal() and has sharesOwed = 6.4 since TVL is still 64 ETH.
3. `verifyBalanceUpdates()` is now called to update EigenLayer balance.
4. User 2 calls `withdraw()` and has sharesOwed = 4.8 since TVL has decreased to 48.

User 1 has stolen 1.4 ETH from the rest.

## Tools Used
Manual Review

## Recommended Mitigation Steps
Locking Period: Implement a locking period after a slashing event is detected, during which no withdrawals can be processed. This allows the system to update the TVL accordingly.


## Assessed type

Context
Stakers can frontrun validators penalties and slashing events with a withdrawal request in order to avoid the loss, this is possible if the deposit pool has enough liquidity available.
Audit: 2024-04-renzo-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-04-renzo/blob/519e518f2d8dec9acf6482b84a181e403070d22d/contracts/EigenLayer/interfaces/IEigenPod.sol#L217-L224


# Vulnerability details

## Impact
Detailed description of the impact of this finding.

## Proof of Concept
Validators can lose part of their deposit via penalties or slashing events:

In case of penalties Eigenlayer can be notified of the balance drop via the permissionless function `EigenPod::verifyBalanceUpdates()`.
In case of slashing the validator is forced to exit and Eigenlayer can be notified via the permissionless function `EigenPod::verifyAndProcessWithdrawals()` because the slashing event is effectively a full withdrawal.
As soon as either `EigenPod::verifyBalanceUpdates()` or `EigenPod::verifyAndProcessWithdrawals()` is called the TVL drops instantly. This is because both of the functions update the variable `podOwnerShares[podOwner]`:
this is the same attack vector mentioned in [this report](https://solodit.xyz/issues/m-7-stakers-can-avoid-validator-penalties-sherlock-rio-network-git) 

## Tools Used
manual review
## Recommended Mitigation Steps
when penalties or slashing events happened during the epoch being settled, distribute the correct amount of penalties to all the `LRTTokens` withdrawn in the current epoch, including the ones that requested the withdrawal before the drop.


## Assessed type

MEV
Users can front-run eigenlayer updates to avoid penalties
Audit: 2024-04-renzo-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-04-renzo/blob/519e518f2d8dec9acf6482b84a181e403070d22d/contracts/Withdraw/WithdrawQueue.sol#L206


# Vulnerability details

Validator balances are updated when [verifyBalanceUpdates()](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v0.2.1-goerli-m2/src/contracts/pods/EigenPod.sol#L185) is called on an EigenPod if a validator is penalized or [verifyAndProcessWithdrawals()](https://github.com/Layr-Labs/eigenlayer-contracts/blob/v0.2.1-goerli-m2/src/contracts/pods/EigenPod.sol#L232) is called if a validator is slashed, which means these actions are known before they take effect in the EigenLayer system. The issue is that users can front-run these calls to initiate a [withdraw](https://github.com/code-423n4/2024-04-renzo/blob/519e518f2d8dec9acf6482b84a181e403070d22d/contracts/Withdraw/WithdrawQueue.sol#L206) and get more out of the system before the total TVL calculations take place with updates as withdraw request will be cached with the stale TVL calculations.
## Impact
Users front-running slashing and penalty updates will be stealing from other users.

## Tools Used
Manual review
## Recommended Mitigation Steps
Ensure that the correct amount of penalties is distributed evenly among stakers.


## Assessed type

Other