Liquid Staking

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

Users Unable to Claim Tokens if `accountClaimed` Exceeds Current Amount or `accountSharesClaimed` Exceeds `_sharesAmount`

Summary

A vulnerability exists in the PriorityPool::claimLSDTokens function where users cannot claim withdrawable liquid staking tokens if the accountClaimed[account] value exceeds the current _amount for a specific claim. This can lead to a Denial of Service (DoS) for users attempting to claim their tokens when their current amount is smaller than the previously claimed amount.

Vulnerability Detail

The PriorityPool::claimLSDTokens function calculates the amount to claim by subtracting the already claimed amount (accountClaimed[account]) from the total amount available (_amount). However, if the already claimed amount is greater than the current _amount, the subtraction results in an underflow (in Solidity 0.8 and later, this causes the transaction to revert). This blocks users from making further claims, effectively preventing them from withdrawing their liquid staking tokens.

The problematic section of the code is:

uint256 amountToClaim = _amount - accountClaimed[account];
uint256 sharesAmountToClaim = _sharesAmount - accountSharesClaimed[account];

IfaccountClaimed[account] is greater than _amount or accountSharesClaimed[account] is greate than _sharesAmount, the subtraction will revert, and the claim process will be halted.

Impact

This issue results in a Denial of Service (DoS) for users who cannot claim their tokens due to discrepancies between the current _amount and the previously claimed amount. In practice, this locks users out of their assets if historical claims exceed the currently claimable amount.

Code Snippet

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

function claimLSDTokens(
uint256 _amount,
uint256 _sharesAmount,
bytes32[] calldata _merkleProof
) external {
address account = msg.sender;
bytes32 node = keccak256(
bytes.concat(keccak256(abi.encode(account, _amount, _sharesAmount)))
);
if (!MerkleProofUpgradeable.verify(_merkleProof, merkleRoot, node)) revert InvalidProof();
@>> uint256 amountToClaim = _amount - accountClaimed[account];
@>> uint256 sharesAmountToClaim = _sharesAmount - accountSharesClaimed[account];
uint256 amountToClaimWithYield = stakingPool.getStakeByShares(sharesAmountToClaim);
if (amountToClaimWithYield == 0) revert NothingToClaim();
accountClaimed[account] = _amount;
accountSharesClaimed[account] = _sharesAmount;
IERC20Upgradeable(address(stakingPool)).safeTransfer(account, amountToClaimWithYield);
emit ClaimLSDTokens(account, amountToClaim, amountToClaimWithYield);
}

Tool Used

Manual Review

Recommendation

Really don't know the solution but through try/catch block we can avoide reverting.

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.