DeFiFoundrySolidity
16,653 OP
View results
Submission Details
Severity: medium
Invalid

Profit distribution is wrong when fee changes

Summary

The setPerformanceFee function in the TokenizedStrategy contract allows changing the performance fee without first claiming pending profits, which can unfairly impact profit distribution between users and the protocol. This is likely to happen whenever performance fee is changed impact yield earned for all users.

Vulnerability Details

In the TokenizedStrategy.sol contract, the setPerformanceFee function allows management to modify the performance fee percentage:

function setPerformanceFee(uint16 _performanceFee) external onlyManagement {
require(_performanceFee <= MAX_FEE, "MAX FEE");
_strategyStorage().performanceFee = _performanceFee;
emit UpdatePerformanceFee(_performanceFee);
}

The issue is that changing the performance fee rate affects pending profits that haven't yet been claimed. This means:

  1. If the fee is increased, users will receive less of the profits they were entitled to under the previous lower rate

  2. If the fee is decreased, the protocol will receive less than it should have for profits earned under the previous higher rate

The fees are calculated based on the current rate and the amount of profit that has been earned. This calculation is done in the report function as follows:

// Cache the performance fee.
uint16 fee = S.performanceFee;
uint256 totalFeeShares;
// If we are charging a performance fee
if (fee != 0) {
// Asses performance fees.
unchecked {
// Get in `asset` for the event.
totalFees = (profit * fee) / MAX_BPS;
// And in shares for the payment.
totalFeeShares = (sharesToLock * fee) / MAX_BPS;
}

And then the fees are minted to the performance fee recipient:

// Mint the difference to the strategy fee recipient.
unchecked {
_mint(
S,
S.performanceFeeRecipient,
totalFeeShares - protocolFeeShares
);
}
}

Scenario A:

  1. Alice deposits $10,000 worth of assets while performance fee is 2000bps (20%)

  2. The strategy earns $1000 in profit

  3. The strategy reports the profit and mints $200 to the performance fee recipient and $800 is minted to the protocol to linearly distribute to Alice over time.

Alice earns $800 in profit

Scenario B:

  1. Alice deposits $10,000 worth of assets while performance fee is 3000bps (30%)

  2. The strategy earns $1000 in profit

  3. The management changes the performance fee to 3000bps (30%)

  4. The strategy reports the profit and mints $300 to the performance fee recipient and $700 is minted to the protocol to linearly distribute to Alice over time.

Alice earns $700 in profit

So despite the strategy earning $1000 in profit in both scenarios, Alice loses $100 in profit due to the timing of the fee change. Because fees are not distributed prior to the setPerformanceFee function being called, the fees are not distributed at the correct rate. This creates an unfair situation where either users or the protocol can be disadvantaged by the timing of fee changes relative to when profits are realized. The root cause is that the function modifies the fee rate without first ensuring all pending profits are distributed based on the current rate.

Impact

  • Loss of yield for users if fees are increased before profits are claimed

  • Loss of protocol revenue if fees are decreased before profits are claimed

  • The impact scales with the size of pending profits and the magnitude of the fee change

Tools Used

Manual Review

Recommendations

Add a check to ensure pending profits are distributed based on the current fee rate before allowing fee changes. This can be done by implementing a check in the base strategy fallback function that calls the report function if the message signature points to setPerformanceFee. It is important to note that the management actor will need keeper privileges to call the report function.

This ensures all accrued profits are properly distributed at their original fee rate before any changes take effect.

Updates

Appeal created

inallhonesty Lead Judge 8 months ago
Submission Judgement Published
Invalidated
Reason: Out of scope

Support

FAQs

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