Liquid Staking

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

`_depositLiquidity` uses inaccurate value for deposits

Summary

This function should deposit only staked tokens into strategies,but it deposits the entire contract token balance.

Vulnerability Details

The _depositLiquidity function aims to deploy users staked tokens into strategies. It does this by looping through the strategies and depositing the amount which is called toDeposit

The issue lies in how toDeposit is evaluated: https://github.com/Cyfrin/2024-09-stakelink/blob/f5824f9ad67058b24a2c08494e51ddd7efdbb90b/contracts/core/StakingPool.sol#L478

It uses the total balance of token available in the stakingPool contract. This is not accurate as this will also consider tokens that were sent via donations.

The ` donateTokens function is a function users call to send tokens to the stakingPool without minting LSTs. As a way to donate to the protocol.

Impact

Donated tokens inflate the balance reported by toDeposit, making it appear that there are more idle, deployable assets than there really are. This could lead to over-deployment of tokens into strategies, causing the pool to run out of liquidity when it's needed for withdrawals or other operations.

If all the tokens, including donated ones, are deployed into yield strategies, the pool might lack the liquidity needed to fulfill withdrawal requests.

If donated tokens are included in strategies, they will earn yield, but because no LSTs are minted for them, the protocol won’t properly track who should be entitled to the rewards generated by these tokens.

There will be yield generated that isn’t attributed to any user, which can lead to accounting errors or even unfair allocation of rewards. This introduces complications in distributing earned rewards properly to regular depositors.

Tools Used

Manual Review

Recommendations

Introduce a variable that tracks donated tokens. And then subtract this value when querying toDeposit :

function donateTokens(uint256 _amount) external {
token.safeTransferFrom(msg.sender, address(this), _amount);
totalStaked += _amount;
+ totalDonated += _amount;
emit DonateTokens(msg.sender, _amount);
}
function _depositLiquidity(bytes[] calldata _data) private {
+ uint256 toDeposit = token.balanceOf(address(this)) - totalDonated;
if (toDeposit > 0) {
for (uint256 i = 0; i < strategies.length; i++) {
IStrategy strategy = IStrategy(strategies[i]);
uint256 strategyCanDeposit = strategy.canDeposit();
if (strategyCanDeposit >= toDeposit) {
strategy.deposit(toDeposit, _data[i]);
break;
} else if (strategyCanDeposit > 0) {
strategy.deposit(strategyCanDeposit, _data[i]);
toDeposit -= strategyCanDeposit;
}
}
}
}
Updates

Lead Judging Commences

inallhonesty Lead Judge about 1 year ago
Submission Judgement Published
Invalidated
Reason: Design choice

Support

FAQs

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