#42469 [SC-Critical] Incorrect computation of excess rewards leads to permanent freezing of user funds
Was this helpful?
Was this helpful?
Submitted on Mar 24th 2025 at 07:07:53 UTC by @Oxgee001 for
Report ID: #42469
Report Type: Smart Contract
Report severity: Critical
Target: https://github.com/immunefi-team/audit-comp-yeet/blob/main/src/StakeV2.sol
Impacts:
Permanent freezing of funds
The StakeV2 contract contains a critical accounting error in its unstaking mechanism where tokens under vesting are incorrectly counted as excess rewards. This allows these vesting tokens to be distributed as rewards through executeRewardDistributionYeet
, permanently freezing user funds that are supposed to be released after the vesting period.
The vulnerability stems from an accounting mismatch between the contract's totalSupply
and actual token balance handling during the unstaking process. When users call startUnstake()
, the function reduces totalSupply
immediately but keeps the actual tokens in the contract until the vesting period ends:
However, the accumulatedDeptRewardsYeet()
function calculates excess rewards incorrectly:
This calculation incorrectly considers vesting tokens as excess rewards since they're included in the contract's balance but excluded from totalSupply
. These "excess" tokens can then be distributed through executeRewardDistributionYeet
for reward distribution:
These tokens are permanently converted to LP positions and vault shares through the zapper, with no mechanism to convert them back for unstaking. Once distributed as rewards, the tokens become inaccessible to the original vesting users who are waiting for their vesting period to end.
All users with active vesting entries will permanently lose access to their tokens if executeRewardDistributionYeet is called during their vesting period. The tokens are irreversibly converted to LP positions and vault shares, making them permanently frozen and inaccessible to the original vesting users. This could affect the entire contract balance if multiple users are in the vesting state when rewards are distributed, leading to a complete freeze of vested funds with no possibility of recovery.
https://github.com/immunefi-team/audit-comp-yeet/blob/da15231cdefd8f385fcdb85c27258b5f0d0cc270/src/StakeV2.sol#L255 https://github.com/immunefi-team/audit-comp-yeet/blob/da15231cdefd8f385fcdb85c27258b5f0d0cc270/src/StakeV2.sol#L148 https://github.com/immunefi-team/audit-comp-yeet/blob/da15231cdefd8f385fcdb85c27258b5f0d0cc270/src/StakeV2.sol#L153
Consider this scenario:
Alice stakes 1000 tokens
Alice calls startUnstake(1000)
, which:
Reduces totalSupply by 1000
Creates a vesting entry for 1000 tokens
The 1000 tokens remain in the contract
accumulatedDeptRewardsYeet()
now returns 1000 (contract balance 1000 - totalSupply 0)
Manager calls executeRewardDistributionYeet
, which:
Sees 1000 tokens as "excess rewards"
Converts these 1000 tokens to LP positions and vault shares
After vesting period ends, Alice tries to unstake but fails because:
Her 1000 tokens were already converted and distributed
The contract has 0 tokens to fulfill her withdrawal