Liquid Staking

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

Missing Reward Processing Before Fee Updates

Summary

During the audit of the StakingPool contract, a significant flaw was identified in the addFee and updateFee functions. These functions modify the fee structure applied to staking rewards, but they fail to process accrued rewards before updating the fee structure. This omission results in incorrect reward distribution, as old rewards might be calculated using the updated fee structure instead of the one that was in effect when the rewards were earned.

Vulnerability Details

  • Affected Functions:

    • addFee

    • updateFee

  • Description:
    Both addFee and updateFee functions modify the fee structure without first processing existing rewards under the current fee system. Failing to call _updateStrategyRewards before modifying the fee structure can lead to incorrect reward and fee calculations. This means rewards earned under the old fee system might be distributed based on the new fee rates, which could result in either overcharging or undercharging users and fee recipients.

    Specific lines that introduce the issue:

    In addFee:

    fees.push(Fee(_receiver, _feeBasisPoints)); // Fees modified before processing old rewards

    In updateFee:

    fees[_index].receiver = _receiver; // Fees updated before processing old rewards
    fees[_index].basisPoints = _feeBasisPoints;

    The problem arises because these modifications occur without first handling pending rewards through _updateStrategyRewards, leading to inconsistencies.

  • Missing Call to _updateStrategyRewards:
    The contract should process all outstanding rewards and fees under the current fee structure before updating to the new one. This ensures that any previously earned rewards are not inadvertently affected by the new fee rates.

Impact

Incorrect Reward and Fee Calculations:
The rewards accrued under the old fee system may be distributed incorrectly under the new fee structure. This can lead to:

  • Incorrect fees collected by fee recipients, which can either be too high or too low.

Tools Used

Recommendations

Call _updateStrategyRewards Before Modifying Fees:
To ensure that old rewards are processed under the correct fee structure, both addFee and updateFee should call _updateStrategyRewards before modifying the fees.

For addFee function:

function addFee(address _receiver, uint256 _feeBasisPoints) external onlyOwner {
// Process outstanding rewards before updating fees
uint256[] memory strategyIdxs = new uint256[]();
for (uint256 i = 0; i < strategies.length; ++i) {
strategyIdxs[i] = i;
}
_updateStrategyRewards(strategyIdxs, ""); // Process rewards under the old fee structure
// Now update the fee structure
fees.push(Fee(_receiver, _feeBasisPoints));
require(_totalFeesBasisPoints() <= 4000, "Total fees must be <= 40%");
}

For updateFee function:

function updateFee(
uint256 _index,
address _receiver,
uint256 _feeBasisPoints
) external onlyOwner {
// Process outstanding rewards before updating fees
uint256[] memory strategyIdxs = new uint256[]();
for (uint256 i = 0; i < strategies.length; ++i) {
strategyIdxs[i] = i;
}
_updateStrategyRewards(strategyIdxs, ""); // Process rewards under the old fee structure
// Now update the fee structure
require(_index < fees.length, "Fee does not exist");
if (_feeBasisPoints == 0) {
fees[_index] = fees[fees.length - 1];
fees.pop();
} else {
fees[_index].receiver = _receiver;
fees[_index].basisPoints = _feeBasisPoints;
}
require(_totalFeesBasisPoints() <= 4000, "Total fees must be <= 40%");
}
Updates

Lead Judging Commences

inallhonesty Lead Judge about 1 year ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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