Liquid Staking

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

Donation Attack

Summary

A donation attack of the LINK token to the StakingPool can DoS deposits if endingBalance is always higher than unusedDepositLimit

Vulnerability Details

Let's have a look at the deposit function of the StakingPool:

function deposit(
address _account,
uint256 _amount,
bytes[] calldata _data
) external onlyPriorityPool {
require(strategies.length > 0, "Must be > 0 strategies to stake");
uint256 startingBalance = token.balanceOf(address(this));
if (_amount > 0) {
token.safeTransferFrom(msg.sender, address(this), _amount);
_depositLiquidity(_data);
_mint(_account, _amount);
totalStaked += _amount;
} else {
_depositLiquidity(_data);
}
uint256 endingBalance = token.balanceOf(address(this));
if (endingBalance > startingBalance && endingBalance > unusedDepositLimit)
revert InvalidDeposit();
}

We will be looking at this piece of code particularly:

if (endingBalance > startingBalance && endingBalance > unusedDepositLimit)
revert InvalidDeposit();

The idea is to limit how much unused balance there is in the StakingPool. However, this can easily be used to DoS and grief a user (or multiple users) by a malicious actor.

Let's have the following scenario:

  1. The contract’s starting balance is 0 tokens.

  2. The unusedDepositLimit is 100 tokens.

  3. A malicious user donates 30 tokens directly to the contract (outside the deposit function).

  4. The contract’s starting balance is 30 tokens (from the external donation).

  5. User calls deposit(100):

  6. startingBalance = 30 tokens (from the donation).

  7. The contract now has 30 + 100 = 130 tokens.

  8. Call to _depositLiquidity:
    Assume the strategies can only accept 20 tokens.
    20 tokens are deposited into strategies.
    110 tokens remain in the contract (leftover tokens).

  9. After the deposit and liquidity operations, the endingBalance is 110 tokens (remaining in the contract).

  10. Is endingBalance > startingBalance?
    Yes. Ending balance = 110 tokens, and starting balance = 30 tokens. The condition 110 > 30 is true.

  11. Is endingBalance > unusedDepositLimit?
    Yes. The ending balance is 110 tokens, and the unusedDepositLimit is 100 tokens. The condition 110 > 100 is true.

  12. Since both conditions are met, the function will revert with the error InvalidDeposit.

What is more, the malicious actor can donate the tokens only when they see the user calling deposit and front-run their transaction to DoS it.

Impact

The impact of such a vulnerability is griefing other users and DoS-ing deposits that should not be reverted.

Tools Used

Manual Review

Recommendations

Implement a system that has an internal system of counting tokens and remove usage of balanceOf to ensure that no malicious actor can DoS depositing.

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.