#42123 [SC-Critical] Insufficient Token Reservation in `startUnstake` Leads to Permanent Freezing of Vested Funds
Submitted on Mar 20th 2025 at 23:24:15 UTC by @Ekko for Audit Comp | Yeet
Report ID: #42123
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
Description
Brief/Intro
In StakeV2.sol, the startUnstake
function reduces totalSupply
immediately, but the stakingToken balance
isn’t decreased until unstake
is called later. This creates a temporary "excess" in accumulatedDeptRewardsYeet (stakingToken.balanceOf(this) - totalSupply)
, which can be distributed as rewards via executeRewardDistributionYeet
. If these tokens are distributed before the vesting period ends, the contract lacks sufficient stakingToken to fulfill vesting withdrawals, permanently freezing user funds in production.
Vulnerability Details
startUnstake
reducestotalSupply
but leaves staking token contract balance -stakingToken.balanceOf(this)
unchanged
accumulatedDeptRewardsYeet
calculates excess tokens as
This "excess" includes tokens still needed for vesting, which are not reserved.
executeRewardDistributionYeet
uses this excess to transfer stakingToken to the zapper for reward distribution:
These tokens are permanently converted to LP positions and vault shares, with no mechanism to convert them back for unstaking:
When users try to unstake after vesting, the transaction reverts because the contract has insufficient balance:
Impact Details
If executeRewardDistributionYeet distributes tokens committed to vesting entries as rewards, the contract’s stakingToken balance may become insufficient to fulfill withdrawals during unstake. This causes the vested tokens to be permanently frozen, as there’s no mechanism to recover the funds or cancel vesting entries.
References
https://github.com/immunefi-team/audit-comp-yeet/blob/da15231cdefd8f385fcdb85c27258b5f0d0cc270/src/StakeV2.sol#L149
Proof of Concept
Proof of Concept
copy this to StakeV2.test.sol
Was this helpful?