Liquid Staking

Stakelink
DeFiHardhatOracle
50,000 USDC
View results
Submission Details
Severity: medium
Invalid

Queued tokens can become inaccessible when contract is paused

Summary

The PriorityPool contract allows users to withdraw liquid staking tokens (LSTs) without unqueuing their queued tokens. This flexibility, combined with the contract's ability to be paused, can lead to a scenario where users' queued tokens become temporarily inaccessible if the contract is paused after an LST-only withdrawal.

Vulnerability Details

https://github.com/Cyfrin/2024-09-stakelink/blob/f5824f9ad67058b24a2c08494e51ddd7efdbb90b/contracts/core/priorityPool/PriorityPool.sol#L271-L308

  1. The withdraw function allows users to choose whether to unqueue tokens during withdrawal:

function withdraw(
uint256 _amountToWithdraw,
uint256 _amount,
uint256 _sharesAmount,
bytes32[] calldata _merkleProof,
bool _shouldUnqueue,
bool _shouldQueueWithdrawal
) external {
// ...
if (_shouldUnqueue == true) {
_requireNotPaused();
// Unqueuing logic
}
// ...
}
  1. The contract can be paused, preventing unqueuing operations:

function unqueueTokens(
uint256 _amountToUnqueue,
uint256 _amount,
uint256 _sharesAmount,
bytes32[] calldata _merkleProof
) external whenNotPaused {
// ...
}

This combination can lead to the following scenario:

  1. A user with both queued tokens and LSTs withdraws only LSTs by setting _shouldUnqueue = false.

  2. The contract is paused before the user can unqueue their tokens in a separate transaction.

  3. The user's queued tokens become inaccessible until the contract is unpaused.

Impact

Users may experience a temporary DOS for their queued tokens if the contract is paused after they've withdrawn LSTs but before they've had a chance to unqueue their tokens. This could potentially lock significant value for an undetermined period, depending on how long the contract remains paused.

Tools Used

Manual

Recommendations

Consider implementing one or more of the following solutions:

  1. Allow unqueuing even when the contract is paused:
    Modify the unqueueTokens function to remove the whenNotPaused modifier, ensuring users can always access their queued tokens.

  2. Implement a time-lock on the pause functionality:
    Add a delay between initiating a pause and its activation, giving users a window to unqueue their tokens before the pause takes effect.

  3. Create a separate unqueue function for paused states:
    Implement an emergency unqueue function that remains operational during paused states, allowing users to retrieve their queued tokens even when normal operations are suspended.

  4. Automatic unqueuing during LST withdrawals:
    Modify the withdraw function to always attempt unqueuing of tokens before processing LST withdrawals, ensuring users can't inadvertently leave tokens queued before a potential pause.

Updates

Lead Judging Commences

inallhonesty Lead Judge 9 months ago
Submission Judgement Published
Invalidated
Reason: Design choice

Support

FAQs

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