#41644 [SC-High] `_clearUserDebt` in zapOut function sends the remaining tokens to `msg.sender` instead of receiver.
Was this helpful?
Was this helpful?
Submitted on Mar 17th 2025 at 08:22:59 UTC by @OxAnmol for
Report ID: #41644
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
The Zapper:zapOut
function uses _clearUserDebt
to send remaining tokens that were not swapped back to the user. However, _msgSender()
is incorrectly used as the destination address, which sends funds to the StakerV2 contract instead of the actual user.
When users call claimRewardsInToken
, claimRewardInToken1
, or claimRewardInToken0 in the StakerV2
contract, they provide a SingleTokenSwap
struct as a parameter. This includes an amountIn
for the token the user wants to swap from.
The Zapper:zapOut
function performs several operations:
Redeems token1 and token0/YEET and WBERA from Kodiak
Swaps token1 and token0 to the desired output token based on the amountIn provided by the user
Sends the output amount to the user/receiver
Checks if there are any remaining token1 and token0 that were not used for swapping
In step 4, it uses _msgSender() (which is the StakerV2 contract) as the destination for unused tokens instead of the receiver
Users will lose all tokens that were not used for swapping. According to the impact scope, this constitutes "Permanent freezing of funds," which is a critical severity bug.
https://github.com/immunefi-team/audit-comp-yeet/blob/da15231cdefd8f385fcdb85c27258b5f0d0cc270/src/contracts/Zapper.sol#L352
A user calls StakerV2:claimRewardsInToken
to claim a reward in USDC. They want to swap 100 token0 and 100 token1 to USDC.
Zapper:zapOut
is called and calculates the amounts. Based on the user's stakes, they're eligible for 200 token0 and 200 token1.
_verifyTokenAndSwap
swaps 100 token0 and 100 token1 to USDC as specified by the user and sends that to the receiver/user.
Only 100 tokens of each type are utilized, and the remaining 100 of each should be returned to the receiver.
However, in _clearUserDebt, _msgSender() is used as the destination for remaining funds, which is actually the StakerV2 contract, not the user