#42538 [SC-Insight] Incorrect value in events emitted in StakeV2
Submitted on Mar 24th 2025 at 15:07:29 UTC by @dobrevaleri for Audit Comp | Yeet
Report ID: #42538
Report Type: Smart Contract
Report severity: Insight
Target: https://github.com/immunefi-team/audit-comp-yeet/blob/main/src/StakeV2.sol
Impacts:
Contract fails to deliver promised returns, but doesn't lose value
Description
Brief
All StakeV2
claim functions emit misleading events when claiming rewards, as it only accounts for tokens received by the Zapper contract rather than the actual recipient.
Vulnerability Details
The issue occurs in All StakeV2
claim functions where the Claimed
event is emitted with the return value from the Zapper's withdrawal functions:
function claimRewardsInToken1(
uint256 amountToWithdraw,
IZapper.SingleTokenSwap calldata swapData,
IZapper.KodiakVaultUnstakingParams calldata unstakeParams,
IZapper.VaultRedeemParams calldata redeemParams
) external nonReentrant {
_updateRewards(msg.sender);
IZapper.VaultRedeemParams memory updatedRedeemParams = _verifyAndPrepareClaim(amountToWithdraw, redeemParams);
IERC20(redeemParams.vault).approve(address(zapper), amountToWithdraw);
uint256 receivedAmount = zapper.zapOutToToken1(msg.sender, swapData, unstakeParams, updatedRedeemParams);
emit Claimed(msg.sender, receivedAmount);
}
The problem is that the Zapper's _yeetOut()
function returns 0 as claimed value if the recipient in either KodiakVaultUnstakingParams
or VaultRedeemParams
is different from the Zapper's address, which doesn't correctly represent the actual claimed assets. Also because of this the zapOutToToken1()
will also return 0, which is used for emitting the Claimed
event:
function _yeetOut(
IZapper.VaultRedeemParams calldata redeemParams,
IZapper.KodiakVaultUnstakingParams calldata unstakeParams
) internal returns (IERC20 token0, IERC20 token1, uint256 token0Debt, uint256 token1Debt) {
uint256 islandTokensReceived = _withdrawFromVault(redeemParams);
if (redeemParams.receiver == address(this)) {
(token0, token1, token0Debt, token1Debt) =
_approveAndUnstakeFromKodiakVault(unstakeParams, islandTokensReceived);
if (unstakeParams.receiver != address(this)) {
return (IERC20(address(0)), IERC20(address(0)), 0, 0);
}
}
}
function zapOutToToken1(
address receiver,
SingleTokenSwap calldata swapData,
KodiakVaultUnstakingParams calldata unstakeParams,
VaultRedeemParams calldata redeemParams
) public nonReentrant onlyWhitelistedKodiakVaults(unstakeParams.kodiakVault) returns (uint256 totalToken1Out) {
(IERC20 token0, IERC20 token1, uint256 token0Debt, uint256 token1Debt) = _yeetOut(redeemParams, unstakeParams);
if (token0Debt == 0 && token1Debt == 0) {
@> return (0);
}
token0Debt -= swapData.inputAmount;
token1Debt += _verifyTokenAndSwap(swapData, address(token0), address(token1), address(this));
_sendERC20Token(token0, _msgSender(), token0Debt);
_sendERC20Token(token1, receiver, token1Debt);
return (token1Debt);
}
Impact
Events emit incorrect reward claim amounts
Off-chain systems tracking rewards through events will have incorrect data
Users may appear to have claimed 0 rewards when they actually received tokens
Proof of Concept
Proof of Concept
User has earned rewards in
StakeV2
User calls
claimRewardsInToken1()
and sets the recipient in eitherunstakeParams
orredeemParams
to their addressThe withdrawal executes successfully and user receives tokens
However, the
Claimed
event emits 0 as the claimed amount since the recipient wasn't the ZapperOff-chain systems tracking rewards see a claim for 0 tokens despite actual tokens being transferred
Was this helpful?