Liquid Staking

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

Incorrect Token Balance Withdrawal in removeSplitter Function

Summary

The removeSplitter function in the provided Solidity code attempts to withdraw the full token balance from a splitter contract, even after parts of the balance have been split and sent as rewards. This results in an incorrect balance being attempted for withdrawal.

Vulnerability Details

https://github.com/Cyfrin/2024-09-stakelink/blob/main/contracts/core/lstRewardsSplitter/LSTRewardsSplitterController.sol#L130-L153

  • Issue: The function does not account for the balance reduction after rewards are split and sent to receivers. It attempts to withdraw the previously cached balance, which may no longer be accurate, thereby leading to a failed token transfer

    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(); // rewards sent to reward receivers, depleting balance
    splitter.withdraw(balance, _account); // incorrect balance attempted for withdrawal
    }
    }

    }

Impact

High as splitter account can be deleted with remaining token balance

Tools Used

manual review

Recommendations

Adjust the function to accurately calculate the balance after rewards have been split and sent to receivers.

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();
uint256 balanceAfterSplit = IERC20(lst).balanceOf(address(splitter));
splitter.withdraw(balanceAfterSplit, _account);
}
}

}

Updates

Lead Judging Commences

inallhonesty Lead Judge about 1 year 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.