Light ModeLight
Light ModeDark

One Bug Per Day

One H/M every day from top Wardens

Checkmark

Join over 1120 wardens!

Checkmark

Receive the email at any hour!

Ad

YieldEthStakingLido lacks a limit on the max stake amount, which may result in the unstake exceeding MAX_STETH_WITHDRAWAL_AMOUNT, resulting in the token not being retrieved.

mediumCode4rena

Lines of code

https://github.com/code-423n4/2024-07-benddao/blob/117ef61967d4b318fc65170061c9577e674fffa1/src/yield/lido/YieldEthStakingLido.sol#L81

Vulnerability details

Vulnerability details

in YieldEthStakingLido

The main processes are as follows:

  1. stake() -> stEth balnace increase
  2. unstake () -> unstETH.requestWithdrawals(allShares)
  3. repay() -> unstETH.claimWithdrawal()

The issue is the second step, unstETH is with a maximum withdrawal limit: MAX_STETH_WITHDRAWAL_AMOUNT

solidity
contract YieldEthStakingLido is YieldStakingBase { ... function protocolRequestWithdrawal(YieldStakeData storage sd) internal virtual override { IYieldAccount yieldAccount = IYieldAccount(yieldAccounts[msg.sender]); uint256[] memory requestAmounts = new uint256[](1); requestAmounts[0] = sd.withdrawAmount; bytes memory result = yieldAccount.execute( address(unstETH), @> abi.encodeWithSelector(IUnstETH.requestWithdrawals.selector, requestAmounts, address(yieldAccount)) ); uint256[] memory withdrawReqIds = abi.decode(result, (uint256[])); require(withdrawReqIds.length > 0 && withdrawReqIds[0] > 0, Errors.YIELD_ETH_WITHDRAW_FAILED); sd.withdrawReqId = withdrawReqIds[0]; }

https://docs.lido.fi/contracts/withdrawal-queue-erc721/#requestwithdrawals

each amount in _amounts must be greater than or equal to MIN_STETH_WITHDRAWAL_AMOUNT and lower than or equal to MAX_STETH_WITHDRAWAL_AMOUNT

current configuration: https://github.com/lidofinance/lido-dao/blob/master/contracts/0.8.9/WithdrawalQueue.sol#L57

solidity
/// @notice maximum amount of stETH that is possible to withdraw by a single request /// Prevents accumulating too much funds per single request fulfillment in the future. /// @dev To withdraw larger amounts, it's recommended to split it to several requests uint256 public constant MAX_STETH_WITHDRAWAL_AMOUNT = 1000 * 1e18;

lido suggests that if it exceeds this value, it needs to be taken in batches, but YieldEthStakingLido.sol can only be taken at once!

So if the stake amount exceeds this value, it will not be possible to unstake() and the token will be locked in the contract

Assumption. leverageFactor = 50000 , eth price = $2500.

Then as long as the value of the nft is greater than: 1000 * $2500 / 5 = $500,000 it will be possible to stake() more than MAX_STETH_WITHDRAWAL_AMOUNT. After that, when the user performs an unstake() it will fail, causing the token to be locked.

Impact

Excessive amount of stake will result in failure to unstake().

Recommended Mitigation

YieldStakingBase add method checkStakeAmount Each sub contract override implements its own maximum amount limit, YieldEthStakingLido suggests a maximum of MAX_STETH_WITHDRAWAL_AMOUNT / 2.

Assessed type

Context