The PriorityPool contract has a vulnerability where the performUpkeep function does not always update the contract state as expected. Due to how the _depositQueuedTokens function is implemented, there are cases where performUpkeep will revert without making any changes. This leads to a situation where checkUpkeep incorrectly returns true even after performUpkeep is called.
In the PriorityPool contract, there is an issue with how the performUpkeep function interacts with the checkUpkeep function. The performUpkeep function is expected to make state changes such that immediately calling checkUpkeep afterwards should return false. However, there are certain conditions where performUpkeep may not actually update the state as expected.
The root cause lies in the _depositQueuedTokens internal function which performUpkeep relies on: https://github.com/Cyfrin/2024-09-stakelink/blob/f5824f9ad67058b24a2c08494e51ddd7efdbb90b/contracts/core/priorityPool/PriorityPool.sol#L693-L729
If either the InsufficientDepositRoom or InsufficientQueuedTokens revert conditions are met, the function will exit without updating the totalQueued state variable or making any actual token deposits.
As a result, if performUpkeep is called when these conditions are true, it will not change the contract state in a way that guarantees checkUpkeep will return false immediately after. The checkUpkeep function may continue to return true unexpectedly.
Would need to ensure:
strategyDepositRoom is less than queueDepositMin so the first revert condition is hit OR
totalQueued + unusedDeposits is less than queueDepositMin so the second revert condition is hit
Under these conditions, performUpkeep will revert without making any state changes, so checkUpkeep will continue to return true erroneously.
If performUpkeep is called but does not perform any updates, it may waste gas fees for users. It could also stall expected token deposits from occurring if checkUpkeep continues to return true but performUpkeep keeps reverting.
Vs Code
Instead of immediately reverting, it could return a boolean indicating whether the deposit was successful or not. The performUpkeep function can then check this return value and only update the totalQueued state if the deposit actually occurred. All code paths need to result in checkUpkeep returning false if called again right after performUpkeep.
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.