Liquid Staking

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

The use of the `balance` in the `removeSplitter` function to withdraw from the contract is incorrect

Summary

In the process of removing an account's splitter, before the splitter is completely removed, the outdated balance value is incorrectly used to transfer the remaining tokens in the splitter contract to the account connected to the splitter, and this is a mistake.

Vulnerability Details

Lets check `removeSplitter` frunction :

https://github.com/Cyfrin/2024-09-stakelink/blob/ea5574ebce3a86d10adc2e1a5f6d5512750f7a72/contracts/core/lstRewardsSplitter/LSTRewardsSplitterController.sol#L134

function removeSplitter(address _account) external onlyOwner {
ILSTRewardsSplitter splitter = splitters[_account];
if (address(splitter) == address(0)) revert SplitterNotFound();
uint256 balance = IERC20(lst).balanceOf(address(splitter));
uint256 principalDeposits = splitter.principalDeposits();
if (balance != 0) {
if (balance != principalDeposits) splitter.splitRewards();
splitter.withdraw(balance, _account);
}
delete splitters[_account];
uint256 numAccounts = accounts.length;
for (uint256 i = 0; i < numAccounts; ++i) {
if (accounts[i] == _account) {
accounts[i] = accounts[numAccounts - 1];
accounts.pop();
break;
}
}
IERC677(lst).safeApprove(address(splitter), 0);
}

There are two important variables in this function:

  • balance : This amount represents the current balance of the Splitter, which includes both the initial deposits and additional rewards. Therefore, the balance may be greater than the principal deposits.

  • principalDeposits : It represents the user's initial deposits.

As you can see, in lines 5 and 6, we update the values of the two variables mentioned above. then In line 8, we run the process of distributing the rewards using the splitter.splitRewards() function.

At the end of the reward distribution process, the principalDeposits value in the splitter._splitRewards() function is updated and equals the amount of lst tokens remaining in the contract after the rewards have been distributed.

https://github.com/Cyfrin/2024-09-stakelink/blob/ea5574ebce3a86d10adc2e1a5f6d5512750f7a72/contracts/core/lstRewardsSplitter/LSTRewardsSplitter.sol#L185

However, again in line 9, the function uses the balance value to run the withdrawal process. The balance value in line 5 has been assigned and has not been updated after the reward distribution process. Using this incorrect value causes the contract to attempt to withdraw more lst tokens than what is available in the contract, resulting in a transaction failure due to insufficient balance.

Impact

Using this incorrect value causes the contract to attempt to withdraw more lst tokens than what is available in the contract, resulting in a transaction failure due to insufficient balance.

Tools Used

Manual review

Recommendations

At the end of the splitter._splitRewards() function, the available balance of the lst token for the contract is updated and assigned to the principalDeposits variable. contract should use updated principalDeposits variable to run withdraw process.

Updates

Lead Judging Commences

inallhonesty Lead Judge 8 months ago
Submission Judgement Published
Validated
Assigned finding tags:

In `removeSplitter` the `principalDeposits` should be used as an input for `withdraw` instead of balance after splitting the existing rewards.

Support

FAQs

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