From 94a6a8688cab2c1f0a3033f4dc4defaadd9f493e Mon Sep 17 00:00:00 2001 From: Gerardo Nardelli Date: Tue, 3 Nov 2020 12:22:15 -0300 Subject: [PATCH] Update liquidity swap adapter params to include min amount to receive --- contracts/adapters/BaseUniswapAdapter.sol | 22 +- .../adapters/UniswapLiquiditySwapAdapter.sol | 30 +-- test/uniswapAdapters.spec.ts | 254 +++++++++++------- 3 files changed, 188 insertions(+), 118 deletions(-) diff --git a/contracts/adapters/BaseUniswapAdapter.sol b/contracts/adapters/BaseUniswapAdapter.sol index 48fe5db9..1b11a8b7 100644 --- a/contracts/adapters/BaseUniswapAdapter.sol +++ b/contracts/adapters/BaseUniswapAdapter.sol @@ -40,10 +40,8 @@ contract BaseUniswapAdapter { bytes32 s; } - // Max slippage percent allow by param + // Max slippage percent allowed uint256 public constant MAX_SLIPPAGE_PERCENT = 3000; // 30% - // Min slippage percent allow by param - uint256 public constant MIN_SLIPPAGE_PERCENT = 10; // 0,1% ILendingPool public immutable POOL; IPriceOracleGetter public immutable ORACLE; @@ -100,18 +98,18 @@ contract BaseUniswapAdapter { } /** - * @dev Swaps an `amountToSwap` of an asset to another + * @dev Swaps an exact `amountToSwap` of an asset to another * @param assetToSwapFrom Origin asset * @param assetToSwapTo Destination asset * @param amountToSwap Exact amount of `assetToSwapFrom` to be swapped - * @param slippage the max slippage percentage allowed for the swap + * @param minAmountOut the min amount of `assetToSwapTo` to be received from the swap * @return the amount received from the swap */ function swapExactTokensForTokens( address assetToSwapFrom, address assetToSwapTo, uint256 amountToSwap, - uint256 slippage + uint256 minAmountOut ) internal returns (uint256) @@ -122,17 +120,19 @@ contract BaseUniswapAdapter { uint256 fromAssetPrice = _getPrice(assetToSwapFrom); uint256 toAssetPrice = _getPrice(assetToSwapTo); - uint256 amountOutMin = amountToSwap + uint256 expectedMinAmountOut = amountToSwap .mul(fromAssetPrice.mul(10**toAssetDecimals)) .div(toAssetPrice.mul(10**fromAssetDecimals)) - .percentMul(PercentageMath.PERCENTAGE_FACTOR.sub(slippage)); + .percentMul(PercentageMath.PERCENTAGE_FACTOR.sub(MAX_SLIPPAGE_PERCENT)); + + require(expectedMinAmountOut < minAmountOut, 'minAmountOut exceed max slippage'); IERC20(assetToSwapFrom).approve(address(UNISWAP_ROUTER), amountToSwap); address[] memory path = new address[](2); path[0] = assetToSwapFrom; path[1] = assetToSwapTo; - uint256[] memory amounts = UNISWAP_ROUTER.swapExactTokensForTokens(amountToSwap, amountOutMin, path, address(this), block.timestamp); + uint256[] memory amounts = UNISWAP_ROUTER.swapExactTokensForTokens(amountToSwap, minAmountOut, path, address(this), block.timestamp); emit Swapped(assetToSwapFrom, assetToSwapTo, amounts[0], amounts[1]); @@ -146,7 +146,7 @@ contract BaseUniswapAdapter { * @param assetToSwapTo Destination asset * @param maxAmountToSwap Max amount of `assetToSwapFrom` allowed to be swapped * @param amountToReceive Exact amount of `assetToSwapTo` to receive - * @return the amount received from the swap + * @return the amount swapped */ function swapTokensForExactTokens( address assetToSwapFrom, @@ -179,7 +179,7 @@ contract BaseUniswapAdapter { emit Swapped(assetToSwapFrom, assetToSwapTo, amounts[0], amounts[1]); - return amounts[1]; + return amounts[0]; } /** diff --git a/contracts/adapters/UniswapLiquiditySwapAdapter.sol b/contracts/adapters/UniswapLiquiditySwapAdapter.sol index 221baada..5291cb85 100644 --- a/contracts/adapters/UniswapLiquiditySwapAdapter.sol +++ b/contracts/adapters/UniswapLiquiditySwapAdapter.sol @@ -17,7 +17,7 @@ contract UniswapLiquiditySwapAdapter is BaseUniswapAdapter, IFlashLoanReceiver { struct SwapParams { address[] assetToSwapToList; - uint256 slippage; + uint256[] minAmountsToReceive; PermitParams permitParams; } @@ -40,7 +40,7 @@ contract UniswapLiquiditySwapAdapter is BaseUniswapAdapter, IFlashLoanReceiver { * @param initiator Address of the user * @param params Additional variadic field to include extra params. Expected parameters: * address[] assetToSwapToList List of the addresses of the reserve to be swapped to and deposited - * uint256 slippage The max slippage percentage allowed for the swap + * uint256[] minAmountsToReceive List of min amounts to be received from the swap * uint256[] deadline List of deadlines for the permit signature * uint8[] v List of v param for the permit signature * bytes32[] r List of r param for the permit signature @@ -58,12 +58,8 @@ contract UniswapLiquiditySwapAdapter is BaseUniswapAdapter, IFlashLoanReceiver { SwapParams memory decodedParams = _decodeParams(params); require( - decodedParams.slippage < MAX_SLIPPAGE_PERCENT && decodedParams.slippage >= MIN_SLIPPAGE_PERCENT, - 'SLIPPAGE_OUT_OF_RANGE' - ); - - require( - decodedParams.assetToSwapToList.length == assets.length + assets.length == decodedParams.assetToSwapToList.length + && assets.length == decodedParams.minAmountsToReceive.length && assets.length == decodedParams.permitParams.deadline.length && assets.length == decodedParams.permitParams.v.length && assets.length == decodedParams.permitParams.r.length @@ -76,7 +72,7 @@ contract UniswapLiquiditySwapAdapter is BaseUniswapAdapter, IFlashLoanReceiver { assets[i], decodedParams.assetToSwapToList[i], amounts[i], - decodedParams.slippage + decodedParams.minAmountsToReceive[i] ); // Deposit new reserve @@ -108,7 +104,8 @@ contract UniswapLiquiditySwapAdapter is BaseUniswapAdapter, IFlashLoanReceiver { * @param assetToSwapFromList List of addresses of the underlying asset to be swap from * @param assetToSwapToList List of addresses of the underlying asset to be swap to and deposited * @param amountToSwapList List of amounts to be swapped - * @param slippage The max slippage percentage allowed for the swap + * @param minAmountsToReceive List of min amounts to be received from the swap + * @param permitParams List of struct containing the permit signatures * uint256[] deadline List of deadlines for the permit signature * uint8[] v List of v param for the permit signature * bytes32[] r List of r param for the permit signature @@ -118,12 +115,13 @@ contract UniswapLiquiditySwapAdapter is BaseUniswapAdapter, IFlashLoanReceiver { address[] calldata assetToSwapFromList, address[] calldata assetToSwapToList, uint256[] calldata amountToSwapList, - uint256 slippage, + uint256[] calldata minAmountsToReceive, PermitSignature[] calldata permitParams ) external { require( assetToSwapFromList.length == assetToSwapToList.length && assetToSwapFromList.length == amountToSwapList.length + && assetToSwapFromList.length == minAmountsToReceive.length && assetToSwapFromList.length == permitParams.length, 'INCONSISTENT_PARAMS' ); @@ -140,7 +138,7 @@ contract UniswapLiquiditySwapAdapter is BaseUniswapAdapter, IFlashLoanReceiver { assetToSwapFromList[i], assetToSwapToList[i], amountToSwapList[i], - slippage + minAmountsToReceive[i] ); // Deposit new reserve @@ -153,7 +151,7 @@ contract UniswapLiquiditySwapAdapter is BaseUniswapAdapter, IFlashLoanReceiver { * @dev Decodes debt information encoded in flashloan params * @param params Additional variadic field to include extra params. Expected parameters: * address[] assetToSwapToList List of the addresses of the reserve to be swapped to and deposited - * uint256 slippage The max slippage percentage allowed for the swap + * uint256[] minAmountsToReceive List of min amounts to be received from the swap * uint256[] deadline List of deadlines for the permit signature * uint256[] deadline List of deadlines for the permit signature * uint8[] v List of v param for the permit signature @@ -164,13 +162,13 @@ contract UniswapLiquiditySwapAdapter is BaseUniswapAdapter, IFlashLoanReceiver { function _decodeParams(bytes memory params) internal returns (SwapParams memory) { ( address[] memory assetToSwapToList, - uint256 slippage, + uint256[] memory minAmountsToReceive, uint256[] memory deadline, uint8[] memory v, bytes32[] memory r, bytes32[] memory s - ) = abi.decode(params, (address[], uint256, uint256[], uint8[], bytes32[], bytes32[])); + ) = abi.decode(params, (address[], uint256[], uint256[], uint8[], bytes32[], bytes32[])); - return SwapParams(assetToSwapToList, slippage, PermitParams(deadline, v, r, s)); + return SwapParams(assetToSwapToList, minAmountsToReceive, PermitParams(deadline, v, r, s)); } } diff --git a/test/uniswapAdapters.spec.ts b/test/uniswapAdapters.spec.ts index 3d9e43aa..259a4ec3 100644 --- a/test/uniswapAdapters.spec.ts +++ b/test/uniswapAdapters.spec.ts @@ -126,12 +126,11 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => { // Subtract the FL fee from the amount to be swapped 0,09% const flashloanAmount = new BigNumber(liquidityToSwap.toString()).div(1.0009).toFixed(0); - // 0,5% slippage const params = ethers.utils.defaultAbiCoder.encode( - ['address[]', 'uint256', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'], + ['address[]', 'uint256[]', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'], [ [dai.address], - 50, + [expectedDaiAmount], [0], [0], ['0x0000000000000000000000000000000000000000000000000000000000000000'], @@ -224,10 +223,9 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => { const {v, r, s} = getSignatureFromTypedData(ownerPrivateKey, msgParams); - // 0,5% slippage const params = ethers.utils.defaultAbiCoder.encode( - ['address[]', 'uint256', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'], - [[dai.address], 50, [deadline], [v], [r], [s]] + ['address[]', 'uint256[]', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'], + [[dai.address], [expectedDaiAmount], [deadline], [v], [r], [s]] ); await expect( @@ -290,12 +288,11 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => { // Subtract the FL fee from the amount to be swapped 0,09% const flashloanAmount = new BigNumber(liquidityToSwap.toString()).div(1.0009).toFixed(0); - // 0,5% slippage const params = ethers.utils.defaultAbiCoder.encode( - ['address[]', 'uint256', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'], + ['address[]', 'uint256[]', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'], [ [dai.address, weth.address], - 50, + [expectedDaiAmount], [0], [0], ['0x0000000000000000000000000000000000000000000000000000000000000000'], @@ -318,10 +315,10 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => { ).to.be.revertedWith('INCONSISTENT_PARAMS'); const params2 = ethers.utils.defaultAbiCoder.encode( - ['address[]', 'uint256', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'], + ['address[]', 'uint256[]', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'], [ [dai.address, weth.address], - 50, + [expectedDaiAmount], [0, 0], [0], ['0x0000000000000000000000000000000000000000000000000000000000000000'], @@ -344,10 +341,10 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => { ).to.be.revertedWith('INCONSISTENT_PARAMS'); const params3 = ethers.utils.defaultAbiCoder.encode( - ['address[]', 'uint256', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'], + ['address[]', 'uint256[]', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'], [ [dai.address, weth.address], - 50, + [expectedDaiAmount], [0], [0, 0], ['0x0000000000000000000000000000000000000000000000000000000000000000'], @@ -370,10 +367,10 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => { ).to.be.revertedWith('INCONSISTENT_PARAMS'); const params4 = ethers.utils.defaultAbiCoder.encode( - ['address[]', 'uint256', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'], + ['address[]', 'uint256[]', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'], [ [dai.address, weth.address], - 50, + [expectedDaiAmount], [0], [0], [ @@ -399,10 +396,10 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => { ).to.be.revertedWith('INCONSISTENT_PARAMS'); const params5 = ethers.utils.defaultAbiCoder.encode( - ['address[]', 'uint256', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'], + ['address[]', 'uint256[]', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'], [ [dai.address, weth.address], - 50, + [expectedDaiAmount], [0], [0], ['0x0000000000000000000000000000000000000000000000000000000000000000'], @@ -426,6 +423,32 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => { 0 ) ).to.be.revertedWith('INCONSISTENT_PARAMS'); + + const params6 = ethers.utils.defaultAbiCoder.encode( + ['address[]', 'uint256[]', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'], + [ + [dai.address, weth.address], + [expectedDaiAmount, expectedDaiAmount], + [0], + [0], + ['0x0000000000000000000000000000000000000000000000000000000000000000'], + ['0x0000000000000000000000000000000000000000000000000000000000000000'], + ] + ); + + await expect( + pool + .connect(user) + .flashLoan( + uniswapLiquiditySwapAdapter.address, + [weth.address], + [flashloanAmount.toString()], + [0], + userAddress, + params6, + 0 + ) + ).to.be.revertedWith('INCONSISTENT_PARAMS'); }); it('should revert if caller not lending pool', async () => { @@ -450,12 +473,11 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => { // Subtract the FL fee from the amount to be swapped 0,09% const flashloanAmount = new BigNumber(liquidityToSwap.toString()).div(1.0009).toFixed(0); - // 0,5% slippage const params = ethers.utils.defaultAbiCoder.encode( - ['address[]', 'uint256', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'], + ['address[]', 'uint256[]', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'], [ [dai.address], - 50, + [expectedDaiAmount], [0], [0], ['0x0000000000000000000000000000000000000000000000000000000000000000'], @@ -531,12 +553,11 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => { // Subtract the FL fee from the amount to be swapped 0,09% const flashloanAmount = new BigNumber(amountUSDCtoSwap.toString()).div(1.0009).toFixed(0); - // 0,5% slippage const params = ethers.utils.defaultAbiCoder.encode( - ['address[]', 'uint256', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'], + ['address[]', 'uint256[]', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'], [ [dai.address], - 50, + [expectedDaiAmount], [0], [0], ['0x0000000000000000000000000000000000000000000000000000000000000000'], @@ -574,49 +595,34 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => { expect(aDaiBalance).to.be.eq(expectedDaiAmount); }); - it('should revert if slippage param is not inside limits', async () => { - const {users, pool, weth, oracle, dai, aWETH, uniswapLiquiditySwapAdapter} = testEnv; + it('should revert when min amount to receive exceeds the max slippage amount', async () => { + const {users, weth, oracle, dai, aWETH, pool, uniswapLiquiditySwapAdapter} = testEnv; const user = users[0].signer; const userAddress = users[0].address; const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); - await weth.connect(user).mint(amountWETHtoSwap); - await weth.connect(user).transfer(uniswapLiquiditySwapAdapter.address, amountWETHtoSwap); - const daiPrice = await oracle.getAssetPrice(dai.address); const expectedDaiAmount = await convertToCurrencyDecimals( dai.address, new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) ); - await mockUniswapRouter.connect(user).setAmountToReturn(expectedDaiAmount); + await mockUniswapRouter.setAmountToReturn(expectedDaiAmount); + const smallExpectedDaiAmount = expectedDaiAmount.div(2); // User will swap liquidity 10 aEth to aDai const liquidityToSwap = parseEther('10'); await aWETH.connect(user).approve(uniswapLiquiditySwapAdapter.address, liquidityToSwap); + // Subtract the FL fee from the amount to be swapped 0,09% const flashloanAmount = new BigNumber(liquidityToSwap.toString()).div(1.0009).toFixed(0); - // 30% slippage - const params1 = ethers.utils.defaultAbiCoder.encode( - ['address[]', 'uint256', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'], + const params = ethers.utils.defaultAbiCoder.encode( + ['address[]', 'uint256[]', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'], [ [dai.address], - 3000, - [0], - [0], - ['0x0000000000000000000000000000000000000000000000000000000000000000'], - ['0x0000000000000000000000000000000000000000000000000000000000000000'], - ] - ); - - // 0,05% slippage - const params2 = ethers.utils.defaultAbiCoder.encode( - ['address[]', 'uint256', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'], - [ - [dai.address], - 5, + [smallExpectedDaiAmount], [0], [0], ['0x0000000000000000000000000000000000000000000000000000000000000000'], @@ -633,23 +639,10 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => { [flashloanAmount.toString()], [0], userAddress, - params1, + params, 0 ) - ).to.be.revertedWith('SLIPPAGE_OUT_OF_RANGE'); - await expect( - pool - .connect(user) - .flashLoan( - uniswapLiquiditySwapAdapter.address, - [weth.address], - [flashloanAmount.toString()], - [0], - userAddress, - params2, - 0 - ) - ).to.be.revertedWith('SLIPPAGE_OUT_OF_RANGE'); + ).to.be.revertedWith('minAmountOut exceed max slippage'); }); }); @@ -690,16 +683,20 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => { const userAEthBalanceBefore = await aWETH.balanceOf(userAddress); await expect( - uniswapLiquiditySwapAdapter - .connect(user) - .swapAndDeposit([weth.address], [dai.address], [amountWETHtoSwap], 50, [ + uniswapLiquiditySwapAdapter.connect(user).swapAndDeposit( + [weth.address], + [dai.address], + [amountWETHtoSwap], + [expectedDaiAmount], + [ { deadline: 0, v: 0, r: '0x0000000000000000000000000000000000000000000000000000000000000000', s: '0x0000000000000000000000000000000000000000000000000000000000000000', }, - ]) + ] + ) ) .to.emit(uniswapLiquiditySwapAdapter, 'Swapped') .withArgs(weth.address, dai.address, amountWETHtoSwap.toString(), expectedDaiAmount); @@ -763,16 +760,20 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => { const {v, r, s} = getSignatureFromTypedData(ownerPrivateKey, msgParams); await expect( - uniswapLiquiditySwapAdapter - .connect(user) - .swapAndDeposit([weth.address], [dai.address], [amountWETHtoSwap], 50, [ + uniswapLiquiditySwapAdapter.connect(user).swapAndDeposit( + [weth.address], + [dai.address], + [amountWETHtoSwap], + [expectedDaiAmount], + [ { deadline, v, r, s, }, - ]) + ] + ) ) .to.emit(uniswapLiquiditySwapAdapter, 'Swapped') .withArgs(weth.address, dai.address, amountWETHtoSwap.toString(), expectedDaiAmount); @@ -795,35 +796,65 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => { }); it('should revert if inconsistent params', async () => { - const {users, weth, dai, uniswapLiquiditySwapAdapter} = testEnv; + const {users, weth, dai, uniswapLiquiditySwapAdapter, oracle} = testEnv; const user = users[0].signer; const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); + const daiPrice = await oracle.getAssetPrice(dai.address); + const expectedDaiAmount = await convertToCurrencyDecimals( + dai.address, + new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) + ); await expect( - uniswapLiquiditySwapAdapter - .connect(user) - .swapAndDeposit([weth.address, dai.address], [dai.address], [amountWETHtoSwap], 50, [ + uniswapLiquiditySwapAdapter.connect(user).swapAndDeposit( + [weth.address, dai.address], + [dai.address], + [amountWETHtoSwap], + [expectedDaiAmount], + [ { deadline: 0, v: 0, r: '0x0000000000000000000000000000000000000000000000000000000000000000', s: '0x0000000000000000000000000000000000000000000000000000000000000000', }, - ]) + ] + ) ).to.be.revertedWith('INCONSISTENT_PARAMS'); await expect( - uniswapLiquiditySwapAdapter - .connect(user) - .swapAndDeposit([weth.address], [dai.address, weth.address], [amountWETHtoSwap], 50, [ + uniswapLiquiditySwapAdapter.connect(user).swapAndDeposit( + [weth.address], + [dai.address, weth.address], + [amountWETHtoSwap], + [expectedDaiAmount], + [ { deadline: 0, v: 0, r: '0x0000000000000000000000000000000000000000000000000000000000000000', s: '0x0000000000000000000000000000000000000000000000000000000000000000', }, - ]) + ] + ) + ).to.be.revertedWith('INCONSISTENT_PARAMS'); + + await expect( + uniswapLiquiditySwapAdapter.connect(user).swapAndDeposit( + [weth.address], + [dai.address], + [amountWETHtoSwap, amountWETHtoSwap], + [expectedDaiAmount], + [ + { + deadline: 0, + v: 0, + r: '0x0000000000000000000000000000000000000000000000000000000000000000', + s: '0x0000000000000000000000000000000000000000000000000000000000000000', + }, + ] + ) ).to.be.revertedWith('INCONSISTENT_PARAMS'); await expect( @@ -832,25 +863,66 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => { .swapAndDeposit( [weth.address], [dai.address], - [amountWETHtoSwap, amountWETHtoSwap], - 50, - [ - { - deadline: 0, - v: 0, - r: '0x0000000000000000000000000000000000000000000000000000000000000000', - s: '0x0000000000000000000000000000000000000000000000000000000000000000', - }, - ] + [amountWETHtoSwap], + [expectedDaiAmount], + [] ) ).to.be.revertedWith('INCONSISTENT_PARAMS'); await expect( - uniswapLiquiditySwapAdapter - .connect(user) - .swapAndDeposit([weth.address], [dai.address], [amountWETHtoSwap], 50, []) + uniswapLiquiditySwapAdapter.connect(user).swapAndDeposit( + [weth.address], + [dai.address], + [amountWETHtoSwap], + [expectedDaiAmount, expectedDaiAmount], + [ + { + deadline: 0, + v: 0, + r: '0x0000000000000000000000000000000000000000000000000000000000000000', + s: '0x0000000000000000000000000000000000000000000000000000000000000000', + }, + ] + ) ).to.be.revertedWith('INCONSISTENT_PARAMS'); }); + + it('should revert when min amount to receive exceeds the max slippage amount', async () => { + const {users, weth, oracle, dai, aWETH, uniswapLiquiditySwapAdapter} = testEnv; + const user = users[0].signer; + + const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); + + const daiPrice = await oracle.getAssetPrice(dai.address); + const expectedDaiAmount = await convertToCurrencyDecimals( + dai.address, + new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) + ); + + await mockUniswapRouter.setAmountToReturn(expectedDaiAmount); + const smallExpectedDaiAmount = expectedDaiAmount.div(2); + + // User will swap liquidity 10 aEth to aDai + const liquidityToSwap = parseEther('10'); + await aWETH.connect(user).approve(uniswapLiquiditySwapAdapter.address, liquidityToSwap); + + await expect( + uniswapLiquiditySwapAdapter.connect(user).swapAndDeposit( + [weth.address], + [dai.address], + [amountWETHtoSwap], + [smallExpectedDaiAmount], + [ + { + deadline: 0, + v: 0, + r: '0x0000000000000000000000000000000000000000000000000000000000000000', + s: '0x0000000000000000000000000000000000000000000000000000000000000000', + }, + ] + ) + ).to.be.revertedWith('minAmountOut exceed max slippage'); + }); }); });