The PriorityPool contract has a bug in the _deposit() function that causes incorrect queueing behavior when shouldQueue is true and totalQueued is zero. The issue arises because the logic prioritizes depositing tokens into the withdrawal pool and staking pool, neglecting to queue the remaining tokens as expected. This bug affects users by not properly accounting for their tokens in the queue, leading to discrepancies in the expected behavior of the contract.
When the shouldQueue parameter is set to true and totalQueued is zero. The issue occurs because the logic prioritizes depositing tokens into the withdrawal pool and staking pool, even if shouldQueue is true, resulting in the remaining tokens not being queued as expected. PriorityPool.sol# https://github.com/Cyfrin/2024-09-stakelink/blob/f5824f9ad67058b24a2c08494e51ddd7efdbb90b/contracts/core/priorityPool/PriorityPool.sol#L607-L644
The fact that the queueing logic is inside the
if (totalQueued == 0)block. WhentotalQueuedis zero, the code prioritizes depositing tokens into the withdrawal pool and staking pool, even if_shouldQueueis set totrue. As a result, the remaining tokens (toDeposit) are not queued correctly when_shouldQueueistrueandtotalQueuedis zero.
When a user calls the deposit() function with shouldQueue set to true, it internally calls the _deposit() function.
Inside _deposit(), there is a check for if (totalQueued == 0). If totalQueued is indeed 0, the function proceeds to attempt depositing tokens into the withdrawal pool and staking pool.
If there is room for deposits in either the withdrawal pool or staking pool, the tokens are deposited accordingly, reducing the remaining amount to be queued.
After the deposits, if there are any remaining tokens, they are not queued even though shouldQueue is true. This is because the queuing logic is inside the if (totalQueued == 0) block, and it is not executed when totalQueued is 0.
This bug affects users because when they call deposit() with shouldQueue set to true, expecting the remaining tokens to be queued, the tokens may not be queued if totalQueued is 0 and there is room for deposits in the withdrawal pool or staking pool. As a result, users' tokens may not be properly accounted for in the queue, leading to discrepancies in the expected behavior of the contract.
Examining the this trace, we can see the following sequence of calls:
PriorityPool.deposit(1, true, []) is called with amount = 1, shouldQueue = true, and empty data.
Inside deposit(), it calls the internal function _deposit() with the same parameters.
In _deposit(), it checks the poolStatus and totalQueued.
Since totalQueued is 0, it attempts to deposit into the withdrawal pool and staking pool.
The remaining amount (1) is not queued even though shouldQueue is true.
To reproduce the issue, call
deposit()withshouldQueue = truewhentotalQueuedis 0 and there is room for deposits in the withdrawal pool or staking pool.
Users' tokens may not be properly accounted for in the queue when they call the deposit() function with shouldQueue set to true and totalQueued is zero. This can lead to discrepancies in the expected behavior of the contract, causing confusion and loss of funds for users who expect their tokens to be queued correctly.
Vs Code
The queueing logic should be moved outside the if (totalQueued == 0) block to ensure that the remaining tokens are always queued when _shouldQueue is true, regardless of the value of totalQueued.
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.