Liquid Staking

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

rewardThreshold can be bypassed in LSTRewardSplitter.sol

Summary

When rewards are positive in LSTRewardsSplitter.sol, it must be greater than the rewardThreshold() for it to be split amongst the fee recipients. uint256(newRewards) < controller.rewardThreshold().

This check can be bypassed by calling splitRewards(), because the check does not exist there.

Vulnerability Details

In LSTRewardsSplitter.sol, to split the rewards with the fee recipients, the function performUpkeep() will be called. If the rewards is positive, check that is is above controller.rewardThreshold() before calling _splitRewards().

There is another function splitRewards() that does the same thing but does not have the controller.rewardThreshold() check. Fee recipients who want their fees can simply call splitRewards() instead to bypass the threshold check.

function performUpkeep(bytes calldata) external {
int256 newRewards = int256(lst.balanceOf(address(this))) - int256(principalDeposits);
if (newRewards < 0) {
principalDeposits -= uint256(-1 * newRewards);
} else if (uint256(newRewards) < controller.rewardThreshold()) {
revert InsufficientRewards();
} else {
_splitRewards(uint256(newRewards));
}
}
/**
* @notice Splits new rewards between fee receivers
* @dev bypasses rewardThreshold
*/
function splitRewards() external {
int256 newRewards = int256(lst.balanceOf(address(this))) - int256(principalDeposits);
if (newRewards < 0) {
principalDeposits -= uint256(-1 * newRewards);
} else if (newRewards == 0) {
revert InsufficientRewards();
} else {
_splitRewards(uint256(newRewards));
}
}

Assume threshold is 1 ETH worth, and the rewards are at 0.5 ETH worth. Instead of waiting for the rewards to reach 1 ETH, fee recipients can call splitRewards() to get their rewards immediately.

Impact

Mechanism bypass.

Tools Used

Manual Review

Recommendations

It seems that both functions are called in the LSTRewardsSplitterController contract. Consider limiting splitRewards() call to onlyController.

Updates

Lead Judging Commences

inallhonesty Lead Judge 12 months ago
Submission Judgement Published
Invalidated
Reason: Design choice

Support

FAQs

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