#41524 [SC-Critical] Incorrect Reward Calculation in accumulatedDeptRewardsYeet() Function Leads to Loss of User Funds During Vesting Period
Was this helpful?
Was this helpful?
Submitted on Mar 16th 2025 at 08:34:54 UTC by @InquisitorScythe for
Report ID: #41524
Report Type: Smart Contract
Report severity: Critical
Target: https://github.com/immunefi-team/audit-comp-yeet/blob/main/src/StakeV2.sol
Impacts:
Direct theft of any user funds, whether at-rest or in-motion, other than unclaimed yield
The accumulatedDeptRewardsYeet() function calculates rewards incorrectly by using a simple formula (stakingToken.balanceOf(address(this)) - totalSupply) that fails to account for tokens in vesting periods. This critical vulnerability allows the protocol to mistakenly identify users' vesting tokens as distributable rewards. When a manager calls executeRewardDistributionYeet(), these misidentified tokens can be permanently redirected to the vault, resulting in direct theft of users' funds that are in the unstaking process. If exploited in production, this could lead to substantial financial losses for users with active vestings, undermining protocol solvency and user trust.
The vulnerability stems from a fundamental accounting error in the accumulatedDeptRewardsYeet()
function, which calculates distributable rewards incorrectly:
This function assumes that any balance of stakingToken
held by the contract beyond the totalSupply
represents distributable rewards. However, this fails to account for tokens that are in the vesting process after users have called startUnstake()
.
When a user calls startUnstake()
, the following occurs:
Their balance in balanceOf
mapping is reduced
The contract's totalSupply
is reduced
A new Vesting
entry is created and tokens enter a vesting period (typically 10 days)
Critically, the tokens remain in the contract until the vesting period ends
The vulnerability exists because tokens in vesting are no longer counted in totalSupply
but still contribute to stakingToken.balanceOf(address(this))
. This discrepancy causes accumulatedDeptRewardsYeet()
to incorrectly include vesting tokens as distributable rewards.
The vulnerable flow is triggered when:
Users stake tokens, increasing totalSupply
Users call startUnstake()
, which decreases totalSupply
but keeps tokens in the contract
accumulatedDeptRewardsYeet()
incorrectly reports these vesting tokens as rewards
A manager calls executeRewardDistributionYeet()
, which:
The function incorrectly approves zapper to spend tokens that actually belong to users in vesting
The zapper converts these tokens to LP positions in the vault, permanently removing them from the contract
This vulnerability is particularly severe because:
It allows direct theft of user funds that are in vesting
It can be exploited by a malicious or misinformed manager
Users have no means to prevent their vesting funds from being taken
The larger the volume of unstaking, the larger the potential funds misdirected
The absence of proper accounting for vesting tokens represents a critical design flaw in the contract's reward calculation logic.
This vulnerability poses a severe risk to user assets and protocol integrity, with the following specific impacts:
Direct Loss of User Funds:
When a manager calls executeRewardDistributionYeet()
, tokens belonging to users in the vesting process can be permanently converted to vault shares
100% of vesting tokens could be misappropriated if distributed
Example: If users collectively have 1,000,000 tokens in vesting and a manager distributes all "rewards," users would lose their entire vesting amount
Protocol Insolvency:
As users complete their vesting period and attempt to claim tokens via the unstake()
function, the contract will lack sufficient tokens to fulfill these claims
The contract would eventually become insolvent, unable to honor user withdrawals
This creates a "bank run" scenario where users who unstake early receive their tokens, while later users receive nothing
The vulnerability represents a Critical severity issue as it leads to direct theft of user funds, creates systemic insolvency, and undermines the core economic guarantees of the protocol. The impact is immediate and requires no complex conditions to exploit - simply normal operation of the contract by managers who believe they are distributing legitimate rewards.
none
add following test in test/StakeV2.test.sol
run the test with forge test ./test/StakeV2.test.sol --match-test test_executeRewardDistributionYeet_vulnerability -vv
output: