Liquid Staking

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

Token Queuing and Merkle Tree Size Discrepancy in PriorityPool Contract

Summary

A critical vulnerability has been identified in the PriorityPool contract related to the queuing of tokens in the _deposit function and subsequent inability to withdraw those tokens using the unqueueTokens function. Specifically, when tokens are queued, the merkleTreeSize is not updated, leading to a scenario where the accountIndexes of the user exceeds the merkleTreeSize. This discrepancy causes the user to be unable to withdraw their queued tokens. This behavior contradicts the system’s documentation, which explicitly states: "Yes, you can withdraw your LINK from the Priority Pool at any time"​.

Vulnerability Details

_deposit function:

  • When a user deposits tokens with _shouldQueue == true, the tokens are added to the queue for future staking. The user’s accountIndexes[_account] is updated, and the user is added to the accounts array if they are not already present:

if (_shouldQueue) {
_requireNotPaused();
if (accountIndexes[_account] == 0) {
accounts.push(_account);
accountIndexes[_account] = accounts.length - 1;
}
accountQueuedTokens[_account] += toDeposit;
totalQueued += toDeposit;
}
  • However, the merkleTreeSize, which represents the number of unique addresses in the latest Merkle tree, is not updated when new users are added to the queue. As a result, the accountIndexes[_account] of new users may exceed the merkleTreeSize, which is problematic in subsequent withdrawal attempts.

unqueueTokens function:

  • In the unqueueTokens function, the contract checks whether the user’s accountIndexes[_account] is less than the merkleTreeSize before allowing the user to unqueue their tokens:

if (accountIndexes[account] < merkleTreeSize) {
bytes32 node = keccak256(
bytes.concat(keccak256(abi.encode(account, _amount, _sharesAmount)))
);
if (!MerkleProofUpgradeable.verify(_merkleProof, merkleRoot, node))
revert InvalidProof();
}
  • If the accountIndexes[_account] is greater than or equal to the merkleTreeSize, the transaction is reverted, preventing the user from withdrawing their tokens from the queue.

This discrepancy between the user’s accountIndexes and the merkleTreeSize leads to a scenario where users who have queued their tokens are unable to withdraw them, violating the expected functionality outlined in the system documentation.

Impact

Users who have queued tokens for staking cannot withdraw their tokens if their accountIndexes is greater than or equal to merkleTreeSize. This creates a situation where legitimate users are unjustly prevented from accessing their own funds. The inability for users to access their queued funds could result in significant economic losses, especially in scenarios where users need to reclaim their assets promptly.

Tools Used

Manually

Recommendations

The merkleTreeSize should be updated whenever a new user is added to the queue in the _deposit function. This can be done by incrementing the merkleTreeSize when the user’s accountIndexes is set:

if (_shouldQueue) {
_requireNotPaused();
if (accountIndexes[_account] == 0) {
accounts.push(_account);
accountIndexes[_account] = accounts.length - 1;
merkleTreeSize++; // Update merkleTreeSize when a new account is added
}
accountQueuedTokens[_account] += toDeposit;
totalQueued += toDeposit;
}
Updates

Lead Judging Commences

inallhonesty Lead Judge
about 1 year ago
inallhonesty Lead Judge about 1 year ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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