Liquid Staking

Stakelink
DeFiHardhatOracle
50,000 USDC
View results
Submission Details
Severity: low
Valid

Due To The `minWithdrawalAmount` check Users Who Want To Withdraw Wont Be Able To Queue Their Token Withdrawals On Some Amounts

Summary

On some certain amount when users want to withdraw their tokens in the prioriyPool and queue them in the withdrawalPool wouldn't be able to due to the queued tokens in the priotityPool being used to satisfy majority of the withdrawal and the rest passed into the queueWithdrawal function where the minWithdrawalAmount in the function hits even though there is enough liquidity to satisfy majority of the withdrawal.

The user then has to either deposit more tokens, wait for more tokens to be queued into the priorityPool, if other users empty the queued tokens, the new queued tokens would also first be used to satisfy the queued withdrawals if any before the users remaining withdrawal can be processed.

Vulnerability Details

In the priorityPool when users want to withdraw their tokens either through the onTransferReceived or withdraw function.
The inner _withdraw function is called which in turn checks if there are any queued tokens in the priority pool
and performs an exchange of the tokens to first satisfy as much of the withdrawal it can,
then forwards the rest of the tokens that it cannot satisfy to the withdrawal pool to queue.

This is the functionality here in the _withdraw in the PriorityPool

uint256 toWithdraw = _amount;
// checks if the queued tokens can satisy as much as the withdrawal possible
if (totalQueued != 0) {
uint256 toWithdrawFromQueue = toWithdraw <= totalQueued ? toWithdraw : totalQueued;
totalQueued -= toWithdrawFromQueue;
depositsSinceLastUpdate += toWithdrawFromQueue;
sharesSinceLastUpdate += stakingPool.getSharesByStake(toWithdrawFromQueue);
toWithdraw -= toWithdrawFromQueue;
}
// what couldnt be satisfied would be forwarded to the withdrawal pool to be queued
if (toWithdraw != 0) {
if (!_shouldQueueWithdrawal) revert InsufficientLiquidity();
withdrawalPool.queueWithdrawal(_account, toWithdraw);
}

If you notice the toWithdraw takes in the users amount of LST tokens to withdraw and then uses the totalQueued to satisfy some of the withdrawal amount.
So once some of the tokens can be satisfied from the totalQueued the toWithdraw is reduced by the toWithdrawFromQueue and is passed on to the withdrawalPool to be queued via the queueWithdrawal function.

function queueWithdrawal(
address _account,
uint256 _amount
) external onlyPriorityPool {
// Where the issue occurs :-> The amount passed here would most likely be trimmed down by the tokens in the priority pool
if (_amount < minWithdrawalAmount) revert AmountTooSmall();
lst.safeTransferFrom(msg.sender, address(this), _amount);
uint256 sharesAmount = _getSharesByStake(_amount);
queuedWithdrawals.push(Withdrawal(uint128(sharesAmount), 0));
totalQueuedShareWithdrawals += sharesAmount;
uint256 withdrawalId = queuedWithdrawals.length - 1;
queuedWithdrawalsByAccount[_account].push(withdrawalId);
withdrawalOwners[withdrawalId] = _account;
emit QueueWithdrawal(_account, _amount);
}

Inside the queueWithdrawal function is where the issue arises, the reduced toWithdraw amount is passed into the function and is immediately chcecked with the minWithdrawalAmount.

Impact

If a situation occurs where most of the users withdrawal from the priorityPool is satisfied by the queued tokens before being sent to the queueWithdrawal function, the _amount passed would most likely be less than the minWithdawal amount and would lead to the entire withdrawal being reverted denying the user from queueing their tokens for withdrawal or claiming any part of their withdrawable amount.

Recommendations

If a user chooses to queue their withdrawal when there is insufficient liquidity in the priorityPool's queued tokens, after subtracting what you can take from the pool, if the withdrawal amount thats left is less than the minWithdrawalAmount then queue the whole withdrawal amount instead.

Updates

Lead Judging Commences

inallhonesty Lead Judge 10 months ago
Submission Judgement Published
Validated
Assigned finding tags:

A withdrawal of totalQueued + x with x < minWithdrawal amount will revert

Appeal created

j1v9 Submitter
10 months ago
inallhonesty Lead Judge
10 months ago
j1v9 Submitter
10 months ago
inallhonesty Lead Judge
10 months ago
inallhonesty Lead Judge 10 months ago
Submission Judgement Published
Validated
Assigned finding tags:

A withdrawal of totalQueued + x with x < minWithdrawal amount will revert

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.