Liquid Staking

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

Double Counting of `strategyFeeAmounts` Leads to Excess Minting of LST and Incorrect Fee Distribution

Summary

In the StakingPool::_updateStrategyRewards function, rewards and fees are distributed based on balance changes in strategies since the last update. However, due to double counting of strategyFeeAmounts, excess Liquid Staking Tokens (LST) are minted and distributed to fee receivers. This results in an inaccurate reward distribution and an inflationary supply of LST, which could harm the overall integrity of the protocol.

Vulnerability Details

The StakingPool::_updateStrategyRewards function calls strategy.updateDeposits to calculate the fees on newly earned rewards. The function returns the following:

/*
* @return depositChange change in deposits since last update
* @return receivers list of fee receivers
* @return amounts list of fee amounts
*/
function updateDeposits(
bytes calldata _data
)
external
override
onlyStakingPool
returns (int256 depositChange, address[] memory receivers, uint256[] memory amounts)
{

The amounts are fractions of the depositChange and represent the fee amounts for each strategy.

In StakingPool::_updateStrategyRewards, the rewards to be distributed are first added to a variable totalFeeAmounts before converting to shares. However, the function double counts a portion of the depositChange in two separate loops:

  1. First, when summing strategyFeeAmounts[j] from the amounts returned by strategy.updateDeposits.

  2. Second, when iterating through fees.length to sum feeAmounts[feeAmounts.length - 1][i], which are a portion of totalRewards (equivalent to depositChange).

This leads to the double counting of fees, as illustrated in the code:

for (uint256 i = 0; i < fees.length; i++) {
receivers[receivers.length - 1][i] = fees[i].receiver;
feeAmounts[feeAmounts.length - 1][i] = (uint256(totalRewards) * fees[i].basisPoints) / 10000;
// @audit double counting: `totalFeeAmounts` already accounted for some of `totalRewards`
// in the earlier line as `strategyFeeAmounts` are portions of `depositChange` (`totalReward`) for each strategy.
totalFeeAmounts += feeAmounts[feeAmounts.length - 1][i];
}

The issue arises because strategyFeeAmounts are already fractions of depositChange (i.e., totalRewards), and adding them again recounts tokens that have already been included, inflating the total fees.

Impact

This double counting leads to an excess minting of LST, which is then distributed to fee receivers. The inflation of LST supply due to incorrect reward calculations could result in an imbalance in the protocol’s tokenomics, unfairly distributing rewards and impacting the system’s stability.

Tools Used

Manual

Recommendations

Refactor the _updateStrategyRewards function to ensure that strategyFeeAmounts are only counted once. This can be achieved by adjusting the fee calculation logic to avoid adding portions of depositChange more than once. Ensure the correct amount of LST is minted to maintain the protocol’s token supply integrity.

Updates

Lead Judging Commences

inallhonesty Lead Judge 10 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Appeal created

krisrenzo Submitter
10 months ago
krisrenzo Submitter
10 months ago
krisrenzo Submitter
10 months ago
krisrenzo Submitter
10 months ago
krisrenzo Submitter
10 months ago
krisrenzo Submitter
10 months ago
inallhonesty Lead Judge
10 months ago
inallhonesty Lead Judge 10 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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