#41875 [SC-High] Permanent Lock of User Funds in StakeV2 Due to Incorrect token Debt Handling
Submitted on Mar 19th 2025 at 03:17:58 UTC by @Bluedragon for Audit Comp | Yeet
Report ID: #41875
Report Type: Smart Contract
Report severity: High
Target: https://github.com/immunefi-team/audit-comp-yeet/blob/main/src/StakeV2.sol
Impacts:
Permanent freezing of funds
Description
Summary:
When users claim rewards in native tokens using the claimRewardsInNative function in the StakeV2 contract, any remaining token debt (e.g., token0Debt or token1Debt) from the Zapper contract is sent back to the StakeV2 contract instead of the user. This occurs because the msg.sender in the context of Zapper contract is StakeV2, not the actual user. As a result, users lose access to their funds, and the tokens are permanently locked in the StakeV2 contract.
Vulnerability Details:
The issue arises in the claimRewardsInNative function of the StakeV2 contract. When a user claims rewards, the zapOutNative function in the Zapper contract is called. If there is any remaining token debt (e.g., token0Debt or token1Debt), the Zapper contract uses the _clearUserDebt function to send these tokens back to the msg.sender. However, since the msg.sender in this context is the StakeV2 contract, the tokens are sent to StakeV2 instead of the user. This results in the loss of user funds, as the tokens are permanently locked in the StakeV2 contract.
List Of Affected Functions:
StakeV2::claimRewardsInNativeStakeV2::claimRewardsInToken0StakeV2::claimRewardsInToken1StakeV2::claimRewardsInToken
Impact:
Loss of User Funds: Users lose access to their tokens (e.g.,
token0ortoken1) when claiming rewards in other tokens with custom swap data. These tokens are permanently locked in theStakeV2contract.Permanent Lock of Tokens: Tokens sent to the
StakeV2contract cannot be recovered, as there is no mechanism to withdraw them.
Reference Code Snippet:
[StakeV2::claimRewardsInNative] (https://github.com/immunefi-team/audit-comp-yeet/blob/da15231cdefd8f385fcdb85c27258b5f0d0cc270/src/StakeV2.sol#L327)
[Zapper::zapOut] (https://github.com/immunefi-team/audit-comp-yeet/blob/da15231cdefd8f385fcdb85c27258b5f0d0cc270/src/contracts/Zapper.sol#L352)
[Zapper::_swapBera] (https://github.com/immunefi-team/audit-comp-yeet/blob/da15231cdefd8f385fcdb85c27258b5f0d0cc270/src/contracts/Zapper.sol#L622)
Proof of Concept
Proof of Concept:
Scenario:
User
bluedragonhas 600e18 rewards in theStakeV2contract.bluedragonwants to withdraw these rewards in native BERA and uses theclaimRewardsInNativefunction.As custom swap data can be used for claiming rewards,
bluedragonprovides custom swap data to convert 300e18 of the rewards to BERA and the remaining 300e18 totoken0(e.g., USDbr). [Assuming 1 BERA = 6 USDbr.]The
claimRewardsInNativefunction calls thezapOutNativefunction in the Zapper contract.The Zapper contract swaps 300e18 of the rewards to BERA and 300e18 to
token0(USDbr).After the swap, the Zapper contract has 50e18 WBERA (converted to BERA) and 300e18 USDbr.
The Zapper contract sends 50e18 BERA to
bluedragon.The remaining 300e18 USDbr is sent to the
StakeV2contract via the_clearUserDebtfunction, as themsg.senderisStakeV2.
Issue:
The 300e18 USDbr send to the
StakeV2contract is permanently locked, andbluedragonloses access to these funds.
Was this helpful?