<!-- canonical: https://0xsimao.com/findings/yieldoor-deposit-hop-exact-output -->

# `Leverager::deposit`, does not support multi-hop swaps with `exactOutput`

Medium · Sherlock · CLMM · 24th February 2025

Finding M-10 of the Yieldoor competition.

- Protocol: https://audits.sherlock.xyz/contests/791
- Report: /reports/yieldoor
- Codebase: https://github.com/0xsimao/2025-02-yieldoor/tree/b5a0f779dce4236b02665606adb610099451a51a
- Source: https://github.com/sherlock-audit/2025-02-yieldoor-judging/issues/577

---

### Summary

When depositing into the leverager, if the borrowed token is not `token0` or `token1`, the function has to perform an `exactOutput` swap, to receive the borrowed `token0`/`token1`.

```solidity
function openLeveragedPosition(LeverageParams calldata lp) external nonReentrant returns (uint256 _id) {
        ...
        {
            // we first borrow the maximum amount the user is willing to borrow. Any unused within the swaps is later repaid.
            ILendingPool(lendingPool).borrow(lp.denomination, lp.maxBorrowAmount);

            IMainnetRouter.ExactOutputParams memory swapParams;

            if (a0 > lp.amount0In && up.token0 != lp.denomination) {
                swapParams = abi.decode(lp.swapParams1, (IMainnetRouter.ExactOutputParams));

                address tokenIn = _getTokenIn(swapParams.path);
                require(tokenIn == lp.denomination, "token should be denomination");

                IERC20(tokenIn).forceApprove(swapRouter, swapParams.amountInMaximum);

                swapParams.amountOut = a0 - lp.amount0In;
                IMainnetRouter(swapRouter).exactOutput(swapParams);
                IERC20(tokenIn).forceApprove(swapRouter, 0);
            }

            if (a1 > lp.amount1In && up.token1 != lp.denomination) {
                swapParams = abi.decode(lp.swapParams2, (IMainnetRouter.ExactOutputParams));
                address tokenIn = _getTokenIn(swapParams.path);
                require(tokenIn == lp.denomination, "token should be denomination 2 ");
                IERC20(tokenIn).forceApprove(swapRouter, swapParams.amountInMaximum);

                swapParams.amountOut = a1 - lp.amount1In;
                IMainnetRouter(swapRouter).exactOutput(swapParams);
                IERC20(tokenIn).forceApprove(swapRouter, 0);
            }
        }

        if (delta0 > 0) ILendingPool(lendingPool).pushFunds(up.token0, delta0);
        if (delta1 > 0) ILendingPool(lendingPool).pushFunds(up.token1, delta1);
        ...
    }
```


In order to validate that the `denomination` token  is the `tokenIn`, we call the internal `_getTokenIn`.

```solidity
    function _getTokenIn(bytes memory path) internal pure returns (address) {
        while (path.hasMultiplePools()) {
            path.skipToken();
        }

        (, address tokenIn,) = path.decodeFirstPool();
        return tokenIn;
    }
```

The function intends to skip, the pools until only the initial one is available, to get the tokenIn.

However, `path` is never changed which causes an infinite loop when the user is trying to do a multi-hop swaps.



### Root Cause

When, [skipping tokens](https://github.com/sherlock-audit/2025-02-yieldoor/blob/main/yieldoor/src/Leverager.sol#L568), path is never changed, causing an infinite loop, for users trying to do multihop swaps.

### Internal Pre-conditions

None

### External Pre-conditions

1. User tries to do a multi-hop swaps

### Attack Path

None

### Impact

The `Leverager::deposit` function fails to support multi-hop swaps as intended

### PoC

_No response_

### Mitigation

Consider overwriting the path when calling `skipToken`

```diff
 while (path.hasMultiplePools()) {
-          path.skipToken();
+         path  = path.skipToken();
        }
```

---

Related findings:

- [`DeliHookConstantProduct` swapping `exactOutput` and `_feeFromOutput` is incorrect](https://0xsimao.com/findings/bmx-hook-product-output-fee): BMX
- [ERC4626YieldBackend does not support vaults with deposit/withdrawal fees or slashing](https://0xsimao.com/findings/superfluid-erc4626-yield-withdrawal-slashing): Superfluid Yield Backends
