Liquid Staking

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

Users may be unable to unqueue tokens because of insufficient tokens in the contract

Summary

When depositing tokens, the function will first check that there is no deposit queue, then check the withdrawal queue, followed by staking pool and then either add to the deposit queue or refund the tokens back to the user.

When tokens are in the deposit queue, users can call unqueueTokens to unqueue their tokens and get back their native LINK tokens.

If there is no tokens in the contract because others have withdrawn their tokens, then users will not be able to unqueue their tokens.

Vulnerability Details

PriorityPool.sol leaves the queued tokens in the contract and changes the accountQueuedTokens[_account] state.

if (toDeposit != 0) {
if (_shouldQueue) {
_requireNotPaused();
if (accountIndexes[_account] == 0) {
accounts.push(_account);
accountIndexes[_account] = accounts.length - 1;
}
accountQueuedTokens[_account] += toDeposit;
totalQueued += toDeposit;

Users can call unqueueTokens() to unqueue their tokens:

function unqueueTokens(
uint256 _amountToUnqueue,
uint256 _amount,
uint256 _sharesAmount,
bytes32[] calldata _merkleProof
) external whenNotPaused {
if (_amountToUnqueue == 0) revert InvalidAmount();
if (_amountToUnqueue > totalQueued) revert InsufficientQueuedTokens();
address account = msg.sender;
// verify merkle proof only if sender is included in tree
if (accountIndexes[account] < merkleTreeSize) {
bytes32 node = keccak256(
bytes.concat(keccak256(abi.encode(account, _amount, _sharesAmount)))
);
if (!MerkleProofUpgradeable.verify(_merkleProof, merkleRoot, node))
revert InvalidProof();
}
if (_amountToUnqueue > getQueuedTokens(account, _amount)) revert InsufficientBalance();
accountQueuedTokens[account] -= _amountToUnqueue;
totalQueued -= _amountToUnqueue;
token.safeTransfer(account, _amountToUnqueue);
emit UnqueueTokens(account, _amountToUnqueue);
}

For example, Alice manages to stake 100 LINK for 100 staked LINK. Alice and Bob then queues 100 LINK each. Alice decides to unstake her 100 stakedLINK, and gets back 100 LINK in the deposit contract. Alice then calls unqueue to withdraw the other 100 LINK in the contract

When Bob calls unqueue now, he cannot receive his LINK back because there is no LINK left in the contract.

Impact

Users may not be able to get back tokens

Tools Used

Manual Reivew

Recommendations

When withdrawing, don't let the caller have the option to not unqueue their own tokens, if not they can take advantage of it by withdrawing other people's queued tokens and then unqueuing their tokens.

Updates

Lead Judging Commences

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

Support

FAQs

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