Part 2

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

Slippage Higher than Expected in `CurveAdapter.executeSwapExactInput()` and `FeeDistributionBranch._performMultiDexSwap()` Multi-Hop Swaps

Summary

Multi-hop swaps in CurveAdapter.executeSwapExactInput() and FeeDistributionBranch._performMultiDexSwap() may result in higher than expected slippage because slippage is verified separately for each individual swap along the multi-hop path, rather than based on the total amount of tokens received at the end of all hops.

Vulnerability Details

When FeeDistribution.convertAccumulatedFeesToWeth() executes, the conversion of assets to WETH can occur through these methods:

  • UniswapV2 adapter: single or multi-hop swap

  • UniswapV3: single or multi-hop swap

  • Curve: single or multi-hop swap

  • Multiple DEXes: multi-hop swap across different exchanges

However, in two specific cases - Curve multi-hop swaps and multi-hop swaps across multiple DEXes - users may experience higher slippage than expected due to a flaw in the code logic. This occurs in both CurveAdapter.executeSwapExactInput() and FeeDistributionBranch._performMultiDexSwap(). Those functions when executing multi-hop swaps (for example, DAI -> USDC -> WETH) use the following loop:

  • Iterate all tokens in the provided path

    1. Fetch next token form the path

    2. Approve amount to the selected router

    3. Calculates expectedAmountOut based on oracle prices

    4. Calculates amountOutMinimum based on expectedAmountOut and slippageToleranceBps.

    5. Swap the tokens

As we can see, this behaves as expected for a single swap: the loss of tokens due to slippage is limited to (expectedAmountOut * slippageToleranceBps) / Constants.MIN_SLIPPAGE_BPS. However, in the case of multiple hops, minAmountOut is calculated separately at each step in the path. This means that while the slippage for each individual swap is constrained by the specified tolerance, the cumulative slippage across multiple hops will be greater.

As a result, although each swap in a multi-hop transaction adheres to the defined slippage limit, the final amountOut after all sequential swaps will experience a higher maximum slippage than the value set by slippageToleranceBps. The more hops involved in the swap, the greater the discrepancy between the actual slippage and the specified tolerance.

Consider the following example, to simplify consider that the exchange rate for all N tokens in a mult-hop scenario is 1:1 (this way we can focus only on slippage issues):

  • 1 Hop: amountOutMinimum will be (amountIn * (Constants.BPS_DENOMINATOR - slippageToleranceBps)) / Constants.BPS_DENOMINATOR

  • N Hops: amountOutMinimum will be approximately (ignoring precision issues) amountIn * ((Constants.BPS_DENOMINATOR - slippageToleranceBps) / Constants.BPS_DENOMINATOR)**N

Some examples for N up to 4, slippageToleranceBps set to 100 (1%) as used in Zaros test suite and AmountIn = 100000.

N minAmountOut Slippage
1 99000 1.00%
2 98010 1.99%
3 97029 2.97%
4 960581 3.94%

Over multiple hops, the actual slippage experienced by the swap can be significantly higher than the limit set by the slippageToleranceBps configuration. In contrast, other adapters, such as UniswapV2Adapter and UniswapV3Adapter, correctly enforce the slippageToleranceBps restriction, even in multi-hop swaps.

Impact

Multi-hop swaps executed via CurveAdapter.executeSwapExactInput() or FeeDistributionBranch._performMultiDexSwap() may experience slippage exceeding the defined slippageToleranceBps. As a result, in highly volatile market conditions, these swaps could incur greater than expected losses. This impacts fee conversion within FeeDistributionBranch.convertAccumulatedFeesToWeth(), which relies on these methods to convert received fees into WETH. Consequently, this may lead to a reduction in the total fees available for distribution to vaults.

Tools Used

Manual Review.

Recommended Mitigation

Consider adding a slippage check that compares the initial input token amount against the final output token amount received after completing all swaps in the transaction path.

Updates

Lead Judging Commences

inallhonesty Lead Judge 4 months ago
Submission Judgement Published
Validated
Assigned finding tags:

CurveAdapter cumulative slippage

Support

FAQs

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