The withdraw() has an unbounded loop with external calls. If the gas costs of functions change between when deposits are made and when rewards are withdrawn, or if the gas cost of the deposit (safetransferFrom()) is less than the gas cost of the withdrawal (safetransfer()), then the withdraw() function may revert due to exceeding the block size gas limit.
1) The withdraw() function processes a list of withdrawal requests, transferring Liquid Staking Tokens (LSTs) from the contract to the user based on the withdrawal IDs and corresponding batch IDs provided by the caller.
Parameters
_withdrawalIds (uint256[]): List of IDs representing the queued withdrawals that the caller wishes to process.
_batchIds (uint256[]): List of batch IDs corresponding to the withdrawal IDs. Used to verify and compute withdrawal amounts.
External Call
token.safeTransfer(owner, amountToWithdraw): This function transfers the total amount of LSTs calculated from the withdrawal requests to the caller
2) The withdraw function contains a loop that iterates over the entire length of the _withdrawalIds array, making it unbounded. Since there is no limit on the number of withdrawal IDs a user can submit, if the array is too large, the loop may consume too much gas, potentially causing the transaction to revert if it exceeds the block gas limit.
The cost of executing the safeTransfer() in the withdrawal process may be higher than the gas cost of deposits (safeTransferFrom()), especially if rewards have accumulated or multiple withdrawals are being processed. If the gas cost increases between the time of deposit and the time of withdrawal (e.g., due to changes in the EVM gas schedule or network congestion), this could cause the withdrawal function to revert.
If the transaction reverts due to gas issues, all LST** in the affected withdrawals would remain locked in the contract** until a successful withdrawal can be processed.
This could create a scenario where users are unable to withdraw their tokens, particularly if they attempt to process large batches of withdrawals in a single transaction.
manual
Allow the specification of an offset and length to the withdraw() function, so that withdrawals can be broken up into smaller batches if required.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.