#41524 [SC-Critical] Incorrect Reward Calculation in accumulatedDeptRewardsYeet() Function Leads to Loss of User Funds During Vesting Period
Submitted on Mar 16th 2025 at 08:34:54 UTC by @InquisitorScythe for Audit Comp | Yeet
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
Description
Brief/Intro
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.
Vulnerability Details
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 reducedThe contract's
totalSupply
is reducedA 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 decreasestotalSupply
but keeps tokens in the contractaccumulatedDeptRewardsYeet()
incorrectly reports these vesting tokens as rewardsA 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.
Impact Details
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 shares100% 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 claimsThe 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.
References
none
Proof of Concept
Proof of Concept
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:
Was this helpful?