#42113 [SC-High] yeetOut function in Zapper.sol sends tokens back to StakeV2 contract instead of user
Was this helpful?
Was this helpful?
Submitted on Mar 20th 2025 at 21:49:47 UTC by @cryptostaker for
Report ID: #42113
Report Type: Smart Contract
Report severity: High
Target: https://github.com/immunefi-team/audit-comp-yeet/blob/main/src/contracts/Zapper.sol
Impacts:
Permanent freezing of funds
When a user wants to claim their staked rewards by calling claimRewardsInToken()
in StakeV2.sol, the function calls zapper.zapOut()
, which sends the excess Yeet & WBera tokens back to the StakeV2 contract instead of the user.
This is the flow of funds when claimRewardsInToken()
is called. Shares in the vault contract will be burned, and the user will receive the outputToken noted in the parameter.
Tokens from the Beradrome farm will be withdrawn back to the Vault.
The KDK LP tokens from the Vault will be swapped to WBera and Yeet.
WBera and Yeet will be swapped to the outputToken
In the event that there is excess tokens to be returned back when swapping WBera / Yeet to the outputToken (can be set from the parameters, or the swap leaves some WBera due to low liquidity etc), these excess tokens is sent back to the _msgSender()
which is the vault, instead of the user.
User may not get their excess tokens back, leading to stuck funds.
Ensure that the _msgSender()
is the direct caller (if someone interacts with the Zapper directly). If StakeV2 contract is calling, ensure that _msgSender()
is the receiver.
Function flow:
claimRewardsInToken() calls zapper.zapOut()
Zapper.zapOut()
calls yeetOut which withdraws from BeradromeFarm to get KDK LP tokens, and swaps these LP tokens to WBera and Yeet (token0 and token1, can be other tokens depending on the vault).
token0 and token1 is converted to outputToken through _verifyTokenAndSwap()
using the oogaBooga router:
The leftover tokens are sent back to the _msgSender()
, which in this case is the StakeV2 contract.
Scenario:
Let's say a user earns ~1e18 of rewards through his staked Yeet tokens. He wants to claim these rewards and calls claimRewardsInToken()
.
This 1e18 rewards gets him 1e18 KDK LP tokens, which is 1 WBera and 1 Yeet. Let's say the user doesn't want to swap all the token to outputToken and intends to get some WBera and Yeet back as well.
The user sets the parameter to ensure that he can get some WBera back, so swap0.inputAmount is ~0.5WBera.
Instead of getting 0.5WBera back, the 0.5WBera is left in the StakeV2.sol contract.