Part 2

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

Missing slippage protection in the `FeeDistributionBranch::convertAccumulatedFeesToWeth` which leads to receiving less weth during conversion from collateral assests.

Summary

The FeeDistributionBranch::convertAccumulatedFeesToWeth contract is vulnerable to slippage exploitation during fee conversion due to the lack of minimum output checks in DEX swaps.

Vulnerability

The vulnerable function:

// 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
tx.tokensSwapped = dexSwapStrategy.executeSwapExactInputSingle(swapCallData);
// 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);

When converting fees to WETH, the contract uses either a custom swap path or a single swap via a DEX adapter. In both cases, the swap functions (executeSwapExactInputSingle or executeSwapExactInput) don't include parameters for minimum output. This means the swap could receive significantly less WETH than the current market rate if the price moves unfavorably between the time the transaction is submitted and when it's executed.

Impact

Protocol's collected fees, which should be distributed to stakeholders, are reduced because of these unfavorable swaps.

Tools used

Manual Review

Recommendation

struct ConvertAccumulatedFeesToWethContext {
UD60x18 assetAmountX18;
uint256 assetAmount;
+ uint256 assetAmountOutMin;
UD60x18 receivedWethX18;
address weth;
uint256 tokensSwapped;
UD60x18 feeRecipientsSharesX18;
UD60x18 receivedProtocolWethRewardX18;
UD60x18 receivedVaultsWethRewardX18;
}
// prepare the data for executing the swap
SwapExactInputSinglePayload memory swapCallData = SwapExactInputSinglePayload({
tokenIn: asset,
tokenOut: ctx.weth,
amountIn: ctx.assetAmount,
+ minAmountOut: minExpectedWeth // can be calculated off-chain or via oracle
recipient: address(this)
});

Update DexSwapStrategy to ensure adapters require amountOutMin and revert if not met:

Updates

Lead Judging Commences

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

Support

FAQs

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