Summary
Checking minWithdrawalAmount
in withdrawPool:queueWithdrawal() causes DoS
Vulnerability Details
function queueWithdrawal(address _account, uint256 _amount) external onlyPriorityPool {
@> if (_amount < minWithdrawalAmount) revert AmountTooSmall();
...
}
queueWithdrawal()
will revert under the condition that _amount
is less than minWithdrawalAmount
, which is 10 ether(from test file). This could always happens, because when user pass the _amountToWithdraw
in priorityPool:withdraw(), it is modified/re-calculated
by this protocol and finally send to the queueWithdrawal().
function withdraw(
uint256 _amountToWithdraw,
uint256 _amount,
uint256 _sharesAmount,
bytes32[] calldata _merkleProof,
bool _shouldUnqueue,
bool _shouldQueueWithdrawal
) external {
if (_amountToWithdraw == 0) revert InvalidAmount();
@> uint256 toWithdraw = _amountToWithdraw;
address account = msg.sender;
...
if (amountToUnqueue != 0) {
accountQueuedTokens[account] -= amountToUnqueue;
totalQueued -= amountToUnqueue;
@> toWithdraw -= amountToUnqueue;
emit UnqueueTokens(account, amountToUnqueue);
}
}
if (toWithdraw != 0) {
IERC20Upgradeable(address(stakingPool)).safeTransferFrom(account, address(this), toWithdraw);
@> toWithdraw = _withdraw(account, toWithdraw, _shouldQueueWithdrawal);
}
token.safeTransfer(account, _amountToWithdraw - toWithdraw);
}
function _withdraw(address _account, uint256 _amount, bool _shouldQueueWithdrawal) internal returns (uint256) {
if (poolStatus == PoolStatus.CLOSED) revert WithdrawalsDisabled();
uint256 toWithdraw = _amount;
if (totalQueued != 0) {
uint256 toWithdrawFromQueue = toWithdraw <= totalQueued ? toWithdraw : totalQueued;
totalQueued -= toWithdrawFromQueue;
depositsSinceLastUpdate += toWithdrawFromQueue;
sharesSinceLastUpdate += stakingPool.getSharesByStake(toWithdrawFromQueue);
@> toWithdraw -= toWithdrawFromQueue;
}
if (toWithdraw != 0) {
if (!_shouldQueueWithdrawal) revert InsufficientLiquidity();
@> withdrawalPool.queueWithdrawal(_account, toWithdraw);
}
...
}
The _amount could be any small value than minWithdrawalAmount. The users passes right value in priorityPool:withdraw(), but could revert, and they don't know why.
Impact
Users withdraw will be reverted even though passing the correct/right amount in priorityPool:withdraw()
Tools Used
Manual Review
Recommendations
Instead of reverting the queueWithdrawal(), just return
function queueWithdrawal(address _account, uint256 _amount) external onlyPriorityPool {
- if (_amount < minWithdrawalAmount) revert AmountTooSmall();
+ if (_amount < minWithdrawalAmount) return;
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);
}