Part 2

Zaros
PerpetualsDEXFoundrySolidity
70,000 USDC
View results
Submission Details
Severity: high
Invalid

Missing slippage handling when converting accumulated fees to Weth potentially results in fees loss

Summary

The convertAccumulatedFeesToWeth() function lacks a validation check for zero output tokens after performing swaps, unlike similar functions in the codebase. This oversight could lead to loss of accumulated fees if a swap results in zero WETH output due to extreme slippage or market manipulation.

Vulnerability Details

In convertMarketsCreditDepositsToUsdc(), there's an explicit check to ensure non-zero output from swaps:

// @audit-info Sanity check to ensure we didn't somehow give away the input tokens
>> if (usdcOut == 0) revert Errors.ZeroOutputTokens();

However, in convertAccumulatedFeesToWeth(), this check is missing:

if (swapPath.enabled) {
>> ctx.tokensSwapped = _performMultiDexSwap(swapPath, ctx.assetAmount);
} else if (path.length == 0) {
---SNIP---
// prepare the data for executing the swap
SwapExactInputSinglePayload memory swapCallData = SwapExactInputSinglePayload({
tokenIn: asset,
tokenOut: ctx.weth,
amountIn: ctx.assetAmount,
recipient: address(this)
});
// Swap collected collateral fee amount for WETH and store the obtained amount
>> ctx.tokensSwapped = dexSwapStrategy.executeSwapExactInputSingle(swapCallData);
} else {
---SNIP---
// prepare the data for executing the swap
SwapExactInputPayload memory swapCallData = SwapExactInputPayload({
path: path,
tokenIn: asset,
tokenOut: ctx.weth,
amountIn: ctx.assetAmount,
recipient: address(this)
});
// Swap collected collateral fee amount for WETH and store the obtained amount
>> ctx.tokensSwapped = dexSwapStrategy.executeSwapExactInput(swapCallData);
}
>> // @audit-info No zero output check here!
// @audit-info Simply Proceeds with distribution
ctx.receivedWethX18 = wethCollateral.convertTokenAmountToUd60x18(ctx.tokensSwapped);
>> _handleWethRewardDistribution(marketId, ctx.receivedWethX18);

Issue Scenario:

  1. A market accumulates significant fees in a collateral token

  2. A keeper calls convertAccumulatedFeesToWeth() to convert these fees to WETH

  3. Due to extreme slippage or market manipulation, the swap returns 0 WETH

  4. Without validation, the function proceeds to distribute 0 WETH

  5. The original fee tokens are lost without receiving any WETH in return.

This is because the subsequent internal function calls do not perform zero-amount checks and therefore do not revert/fail for such.
These include _handleWethRewardDistribution() which finally calls market.receiveWethReward() which adds the received weth rewards to the stored values of pending protocol weth rewards and vaults' total weth reward.

Impact

  • Loss of accumulated fees if swaps result in zero output

Tools Used

Manual Review

Recommendations

Add a zero output validation check after the swap execution:

// Swap collected collateral fee amount for WETH and store the obtained amount
ctx.tokensSwapped = dexSwapStrategy.executeSwapExactInput(swapCallData);
+ // @audit Ensure we received non-zero WETH from the swap
+ if (ctx.tokensSwapped == 0) revert Errors.ZeroOutputTokens();
// uint256 -> ud60x18
ctx.receivedWethX18 = wethCollateral.convertTokenAmountToUd60x18(ctx.tokensSwapped);
Updates

Lead Judging Commences

inallhonesty Lead Judge 7 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.