The bug allows totalQueuedShareWithdrawals
to become inconsistent with the real queued amount if a deposit only partially covers the next withdrawal. This violates the totalQueuedSharesConsistency
invariant.
Sequence of calls leading to the violation:
initialize
is called to set up the contract state
queueWithdrawal
is called to queue a withdrawal of 100 LST tokens
deposit
is called to deposit 50 tokens, which partially finalizes the queued withdrawal
At this point, totalQueuedShares
is inconsistent with the actual total queued withdrawals
The problem occurs because totalQueuedShareWithdrawals
is decremented by sharesToWithdraw
before the loop that processes the queued withdrawals. If a deposit only partially covers the next queued withdrawal, totalQueuedShareWithdrawals
will be decremented by the full sharesToWithdraw
amount, even though only a portion of the withdrawal was processed. The _finalizeWithdrawals
internal function in WithdrawalPool.sol
: https://github.com/Cyfrin/2024-09-stakelink/blob/f5824f9ad67058b24a2c08494e51ddd7efdbb90b/contracts/core/priorityPool/WithdrawalPool.sol#L422-L428
Assume the contract has the following state:
totalQueuedShareWithdrawals
is 1000
There is a queued withdrawal of 800 shares
A deposit of 500 tokens is made, triggering _finalizeWithdrawals(500)
.
sharesToWithdraw
is calculated as 500.
totalQueuedShareWithdrawals
is decremented by 500, becoming 500.
The loop processes the queued withdrawal of 800 shares.
The withdrawal is partially finalized, with 500 shares processed and 300 shares remaining.
After the function execution, totalQueuedShareWithdrawals
remains at 500, even though there are still 300 shares queued for withdrawal.
If totalQueuedShareWithdrawals
is lower than the actual total of unprocessed withdrawals, it may incorrectly indicate that there are fewer queued withdrawals than there actually are.
Manual Review
By decrementing totalQueuedShareWithdrawals
inline as withdrawals are processed, it ensures that totalQueuedShareWithdrawals
always reflects the actual total of unprocessed queued withdrawals.
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.