Renzo - btk'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: 85/122

Findings: 1

Award: $1.48

🌟 Selected for report: 0

🚀 Solo Findings: 0

Awards

1.479 USDC - $1.48

Labels

bug
2 (Med Risk)
satisfactory
sufficient quality report
:robot:_107_group
duplicate-484

External Links

Lines of code

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

Vulnerability details

Impact

Users will loss assets due to the absence of slippage control.

Proof of Concept

The WithdrawQueue lacks a mechanism for usersto express their minimum acceptable output.

It is reasonable that as the users deposit(sends input tokens) to the contract, he/she should receive the rightful amount of tokens on that moment. Also, when the users withdraw his/her tokens he/she should receive the rightful amount of usdc on that moment.

If the token amount to be received is less than what he/she expects, the transaction should revert. This deficiency exposes them to potential losses of their assets due to price fluctuations.

Here is the withdraw() function that contains 0 slippage protection:

    function withdraw(uint256 _amount, address _assetOut) external nonReentrant {
        // code

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

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

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

        // code

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

The WithdrawQueue uses lookupTokenAmountFromValue which uses chainlink.latestRoundData to retrieve the last price:

    function lookupTokenAmountFromValue(
        IERC20 _token,
        uint256 _value
    ) external view returns (uint256) {
        AggregatorV3Interface oracle = tokenOracleLookup[_token];
        if (address(oracle) == address(0x0)) revert OracleNotFound();

        (, int256 price, , uint256 timestamp, ) = oracle.latestRoundData();
        if (timestamp < block.timestamp - MAX_TIME_WINDOW) revert OraclePriceExpired();
        if (price <= 0) revert InvalidOraclePrice();

        // Price is times 10**18 ensure token amount is scaled
        return (_value * SCALE_FACTOR) / uint256(price);
    }

For instance, if an users attempts to withdraw his assets from the contract and their transaction is delayed due to low gas or network congestion, any price change would result in the trade occurring at a sub-optimal price, harming the investor.

Tools Used

Manual review

Allow users to specify a minOut & deadline inputs to protect against slippage.

Assessed type

Other

#0 - C4-Staff

2024-05-15T14:23:17Z

CloudEllie marked the issue as duplicate of #484

#1 - c4-judge

2024-05-17T13:44:10Z

alcueca marked the issue as duplicate of #345

#2 - c4-judge

2024-05-17T13:45:10Z

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