sherlock-audit / 2024-08-saffron-finance-judging

9 stars 5 forks source link

SyncCode2017 - Users funds will be stuck if many users request for withdrawal from the fixed side when the vault has started due to two unbounded array lengths in `LidoVault::finalizeVaultOngoingFixedWithdrawals`. #147

Open sherlock-admin2 opened 2 months ago

sherlock-admin2 commented 2 months ago

SyncCode2017

High

Users funds will be stuck if many users request for withdrawal from the fixed side when the vault has started due to two unbounded array lengths in LidoVault::finalizeVaultOngoingFixedWithdrawals.

Summary

When a user calls LidoVault::finalizeVaultOngoingFixedWithdrawals to request for withdrawal from the fixed side when the vault has started, each of the 2 arrays in line 599 and line 1174 will be looped through. With sufficient number of withdrawals pending, the gas needed to complete this transaction will be greater than the block gas limit (30 million gas) and every transaction calling this function will fail.

https://github.com/sherlock-audit/2024-08-saffron-finance/blob/main/lido-fiv/contracts/LidoVault.sol#L599

https://github.com/sherlock-audit/2024-08-saffron-finance/blob/main/lido-fiv/contracts/LidoVault.sol#L1174

Funds of these users will be stuck.

Root Cause

Two unbounded arrays will be looped through when LidoVault::finalizeVaultOngoingFixedWithdrawals is called by a user. The unbounded arrays are in line 599 and line 1174 as shown in the summary section.

Internal pre-conditions

No response

External pre-conditions

No response

Attack Path

No response

Impact

Funds of users requesting for withdrawals from an ongoing vault will be stuck due to unusually high gas (higher than block gas limit) required to complete the transaction. Especially when this contract is running on Ethereum mainnet where gas fees are very high.

PoC

30 million gas is the maximum gas limit per block in the Ethereum blockchain according to ethereum.org. Please click the link below. https://ethereum.org/en/developers/docs/gas/#block-size:~:text=fee%20and%20tip.-,Block%20size,-Each%20block%20has

As the number of users and withdrawal requests on the fixed side grows so also the array lengths in line 599 and line 1174 grow and gas needed to complete the withdrawal transaction. https://github.com/sherlock-audit/2024-08-saffron-finance/blob/main/lido-fiv/contracts/LidoVault.sol#L599

https://github.com/sherlock-audit/2024-08-saffron-finance/blob/main/lido-fiv/contracts/LidoVault.sol#L1174

When a user calls LidoVault::finalizeVaultOngoingFixedWithdrawals to request for withdrawal, each of the 2 arrays will be looped through. With sufficient number of withdrawals pending, the gas needed to complete this transaction will be greater than the block gas limit (30 million gas) and every transaction calling this function will fail.

Mitigation

The contract follows the steps below for a withdrawal from ongoing fixed-side vault to be finalised;

  1. user calls LidoVault::withdraw to place request for withdrawal. The user request is not sent to Lido immediately, it is queued up along with other requests;
  2. all the queued up requests are sent when a user calls LidoVault::finalizeVaultOngoingFixedWithdrawals. Each request is sent individually in a loop. So a long loop of requests is expected to be processed in this one transaction.

This logic is erroneous. Besides funds being stuck due to unusually high gas, a user is made to pay gas fees for other users requests to be sent to Lido. This logic must reviewed and revised.