From 43d05c2bdf846fef7c8f4145988511a36fea3549 Mon Sep 17 00:00:00 2001 From: Gerardo Nardelli Date: Fri, 20 Nov 2020 15:53:50 -0300 Subject: [PATCH] Refactor repayAdapter to flash loan the debt asset instead of the collateral --- contracts/adapters/UniswapRepayAdapter.sol | 105 +++--- helpers/contracts-helpers.ts | 8 +- test/uniswapAdapters.spec.ts | 358 +++++---------------- 3 files changed, 114 insertions(+), 357 deletions(-) diff --git a/contracts/adapters/UniswapRepayAdapter.sol b/contracts/adapters/UniswapRepayAdapter.sol index 616a6ce1..c42df484 100644 --- a/contracts/adapters/UniswapRepayAdapter.sol +++ b/contracts/adapters/UniswapRepayAdapter.sol @@ -16,18 +16,10 @@ import {ReserveLogic} from '../libraries/logic/ReserveLogic.sol'; **/ contract UniswapRepayAdapter is BaseUniswapAdapter, IFlashLoanReceiver { - /* - * STANDARD: Use the provided amounts parameters - * ALL_DEBT: Repay the whole debt balance - * ALL_COLLATERAL: Use all the collateral balance to repay the max amount of debt - */ - enum RepayMode {STANDARD, ALL_DEBT, ALL_COLLATERAL} - struct RepayParams { - address assetToSwapTo; - uint256 repayAmount; + address collateralAsset; + uint256 collateralAmount; uint256 rateMode; - RepayMode repayMode; PermitSignature permitSignature; } @@ -40,17 +32,17 @@ contract UniswapRepayAdapter is BaseUniswapAdapter, IFlashLoanReceiver { {} /** - * @dev Swaps the received reserve amount into the asset specified in the params. The received funds from the swap are - * then used to repay a debt on the protocol on behalf of the user. - * The user should give this contract allowance to pull the ATokens in order to withdraw the underlying asset and - * repay the flash loan. + * @dev Uses the received funds from the flash loan to repay a debt on the protocol on behalf of the user. Then pulls + * the collateral from the user and swaps it to repay the flash loan. + * The user should give this contract allowance to pull the ATokens in order to withdraw the underlying asset, swap it + * and repay the flash loan. * @param assets Address to be swapped * @param amounts Amount of the reserve to be swapped * @param premiums Fee of the flash loan * @param initiator Address of the user * @param params Additional variadic field to include extra params. Expected parameters: - * address Address of the reserve to be swapped to and repay - * uint256 repayAmount Amount of debt to be repaid + * address collateralAsset Address of the reserve to be swapped + * uint256 collateralAmount Amount of reserve to be swapped * uint256 rateMode Rate modes of the debt to be repaid * RepayMode repayMode Enum indicating the repaid mode * uint256 permitAmount Amount for the permit signature @@ -71,13 +63,12 @@ contract UniswapRepayAdapter is BaseUniswapAdapter, IFlashLoanReceiver { RepayParams memory decodedParams = _decodeParams(params); _swapAndRepay( + decodedParams.collateralAsset, assets[0], - decodedParams.assetToSwapTo, amounts[0], - decodedParams.repayAmount, + decodedParams.collateralAmount, decodedParams.rateMode, initiator, - decodedParams.repayMode, premiums[0], decodedParams.permitSignature ); @@ -86,12 +77,12 @@ contract UniswapRepayAdapter is BaseUniswapAdapter, IFlashLoanReceiver { } /** - * @dev Perform the swap and the repay of the debt + * @dev Perform the repay of the debt, pulls the initiator collateral and swaps to repay the flash loan * * @param assetFrom Address of token to be swapped - * @param assetTo Address of token to be received - * @param amount Amount of the reserve to be swapped - * @param repayAmount Amount of the debt to be repaid + * @param assetTo Address of debt token to be received from the swap + * @param amount Amount of the debt to be repaid + * @param collateralAmount Amount of the reserve to be swapped * @param rateMode Rate mode of the debt to be repaid * @param initiator Address of the user * @param premium Fee of the flash loan @@ -101,61 +92,39 @@ contract UniswapRepayAdapter is BaseUniswapAdapter, IFlashLoanReceiver { address assetFrom, address assetTo, uint256 amount, - uint256 repayAmount, + uint256 collateralAmount, uint256 rateMode, address initiator, - RepayMode repayMode, uint256 premium, PermitSignature memory permitSignature ) internal { - uint256 debtRepayAmount; - uint256 amountSwapped; - - ReserveLogic.ReserveData memory reserveData = _getReserveData(assetFrom); - - if (repayMode == RepayMode.ALL_COLLATERAL) { - uint256 aTokenInitiatorBalance = IERC20(reserveData.aTokenAddress).balanceOf(initiator); - amountSwapped = aTokenInitiatorBalance.sub(premium); - - debtRepayAmount = _swapExactTokensForTokens(assetFrom, assetTo, amountSwapped, repayAmount); - } else { - if (repayMode == RepayMode.ALL_DEBT) { - ReserveLogic.ReserveData memory reserveDebtData = _getReserveData(assetTo); - - address debtToken = ReserveLogic.InterestRateMode(rateMode) == ReserveLogic.InterestRateMode.STABLE - ? reserveDebtData.stableDebtTokenAddress - : reserveDebtData.variableDebtTokenAddress; - - debtRepayAmount = IERC20(debtToken).balanceOf(initiator); - } else { - debtRepayAmount = repayAmount; - } - - amountSwapped = _swapTokensForExactTokens(assetFrom, assetTo, amount, debtRepayAmount); - } - // Repay debt - IERC20(assetTo).approve(address(POOL), debtRepayAmount); - POOL.repay(assetTo, debtRepayAmount, rateMode, initiator); - // In the case the repay amount provided exceeded the actual debt, send the leftovers to the user - _sendRepayLeftovers(assetTo, initiator); + IERC20(assetTo).approve(address(POOL), amount); + POOL.repay(assetTo, amount, rateMode, initiator); + uint256 debtRepayLeftovers = IERC20(assetTo).balanceOf(address(this)); uint256 flashLoanDebt = amount.add(premium); - uint256 amountToPull = amountSwapped.add(premium); + uint256 neededForFlashLoanDebt = flashLoanDebt.sub(debtRepayLeftovers); - _pullAToken(assetFrom, reserveData.aTokenAddress, initiator, amountToPull, permitSignature); + // Pull aTokens from user + ReserveLogic.ReserveData memory reserveData = _getReserveData(assetFrom); + _pullAToken(assetFrom, reserveData.aTokenAddress, initiator, collateralAmount, permitSignature); + + uint256 amountSwapped = _swapTokensForExactTokens(assetFrom, assetTo, collateralAmount, neededForFlashLoanDebt); + + // Send collateral leftovers from swap to the user + _sendLeftovers(assetFrom, initiator); // Repay flashloan - IERC20(assetFrom).approve(address(POOL), flashLoanDebt); + IERC20(assetTo).approve(address(POOL), flashLoanDebt); } /** * @dev Decodes debt information encoded in flashloan params * @param params Additional variadic field to include extra params. Expected parameters: - * address Address of the reserve to be swapped to and repay - * uint256 repayAmount Amount of debt to be repaid + * address collateralAsset Address of the reserve to be swapped + * uint256 collateralAmount Amount of reserve to be swapped * uint256 rateMode Rate modes of the debt to be repaid - * RepayMode repayMode Enum indicating the repaid mode * uint256 permitAmount Amount for the permit signature * uint256 deadline Deadline for the permit signature * uint8 v V param for the permit signature @@ -165,22 +134,20 @@ contract UniswapRepayAdapter is BaseUniswapAdapter, IFlashLoanReceiver { */ function _decodeParams(bytes memory params) internal pure returns (RepayParams memory) { ( - address assetToSwapTo, - uint256 repayAmount, + address collateralAsset, + uint256 collateralAmount, uint256 rateMode, - RepayMode repayMode, uint256 permitAmount, uint256 deadline, uint8 v, bytes32 r, bytes32 s - ) = abi.decode(params, (address, uint256, uint256, RepayMode, uint256, uint256, uint8, bytes32, bytes32)); + ) = abi.decode(params, (address, uint256, uint256, uint256, uint256, uint8, bytes32, bytes32)); return RepayParams( - assetToSwapTo, - repayAmount, + collateralAsset, + collateralAmount, rateMode, - repayMode, PermitSignature( permitAmount, deadline, @@ -196,7 +163,7 @@ contract UniswapRepayAdapter is BaseUniswapAdapter, IFlashLoanReceiver { * @param asset address of the asset * @param user address */ - function _sendRepayLeftovers(address asset, address user) internal { + function _sendLeftovers(address asset, address user) internal { uint256 assetLeftover = IERC20(asset).balanceOf(address(this)); if (assetLeftover > 0) { diff --git a/helpers/contracts-helpers.ts b/helpers/contracts-helpers.ts index a055fb32..832e8ae7 100644 --- a/helpers/contracts-helpers.ts +++ b/helpers/contracts-helpers.ts @@ -259,10 +259,9 @@ export const buildLiquiditySwapParams = ( }; export const buildRepayAdapterParams = ( - assetToSwapTo: tEthereumAddress, - repayAmount: BigNumberish, + collateralAsset: tEthereumAddress, + collateralAmount: BigNumberish, rateMode: BigNumberish, - repayMode: BigNumberish, permitAmount: BigNumberish, deadline: BigNumberish, v: BigNumberish, @@ -276,11 +275,10 @@ export const buildRepayAdapterParams = ( 'uint256', 'uint256', 'uint256', - 'uint256', 'uint8', 'bytes32', 'bytes32', ], - [assetToSwapTo, repayAmount, rateMode, repayMode, permitAmount, deadline, v, r, s] + [collateralAsset, collateralAmount, rateMode, permitAmount, deadline, v, r, s] ); }; diff --git a/test/uniswapAdapters.spec.ts b/test/uniswapAdapters.spec.ts index 2f0d35c4..b821f238 100644 --- a/test/uniswapAdapters.spec.ts +++ b/test/uniswapAdapters.spec.ts @@ -2085,19 +2085,19 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => { await aWETH.connect(user).approve(uniswapRepayAdapter.address, liquidityToSwap); const userAEthBalanceBefore = await aWETH.balanceOf(userAddress); - // Subtract the FL fee from the amount to be swapped 0,09% - const flashloanAmount = new BigNumber(liquidityToSwap.toString()).div(1.0009).toFixed(0); + await mockUniswapRouter.connect(user).setAmountToSwap(weth.address, liquidityToSwap); - await mockUniswapRouter.connect(user).setAmountToSwap(weth.address, flashloanAmount); + const flashLoanDebt = new BigNumber(expectedDaiAmount.toString()) + .multipliedBy(1.0009) + .toFixed(0); const params = buildRepayAdapterParams( - dai.address, - expectedDaiAmount, + weth.address, + liquidityToSwap, 1, 0, 0, 0, - 0, '0x0000000000000000000000000000000000000000000000000000000000000000', '0x0000000000000000000000000000000000000000000000000000000000000000' ); @@ -2107,8 +2107,8 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => { .connect(user) .flashLoan( uniswapRepayAdapter.address, - [weth.address], - [flashloanAmount.toString()], + [dai.address], + [expectedDaiAmount.toString()], [0], userAddress, params, @@ -2116,7 +2116,7 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => { ) ) .to.emit(uniswapRepayAdapter, 'Swapped') - .withArgs(weth.address, dai.address, flashloanAmount.toString(), expectedDaiAmount); + .withArgs(weth.address, dai.address, liquidityToSwap.toString(), flashLoanDebt); const adapterWethBalance = await weth.balanceOf(uniswapRepayAdapter.address); const adapterDaiBalance = await dai.balanceOf(uniswapRepayAdapter.address); @@ -2170,9 +2170,6 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => { const liquidityToSwap = amountWETHtoSwap; const userAEthBalanceBefore = await aWETH.balanceOf(userAddress); - // Subtract the FL fee from the amount to be swapped 0,09% - const flashloanAmount = new BigNumber(liquidityToSwap.toString()).div(1.0009).toFixed(0); - const chainId = DRE.network.config.chainId || BUIDLEREVM_CHAINID; const deadline = MAX_UINT_AMOUNT; const nonce = (await aWETH._nonces(userAddress)).toNumber(); @@ -2195,13 +2192,16 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => { const { v, r, s } = getSignatureFromTypedData(ownerPrivateKey, msgParams); - await mockUniswapRouter.connect(user).setAmountToSwap(weth.address, flashloanAmount); + await mockUniswapRouter.connect(user).setAmountToSwap(weth.address, liquidityToSwap); + + const flashLoanDebt = new BigNumber(expectedDaiAmount.toString()) + .multipliedBy(1.0009) + .toFixed(0); const params = buildRepayAdapterParams( - dai.address, - expectedDaiAmount, + weth.address, + liquidityToSwap, 1, - 0, liquidityToSwap, deadline, v, @@ -2214,8 +2214,8 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => { .connect(user) .flashLoan( uniswapRepayAdapter.address, - [weth.address], - [flashloanAmount.toString()], + [dai.address], + [expectedDaiAmount.toString()], [0], userAddress, params, @@ -2223,7 +2223,7 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => { ) ) .to.emit(uniswapRepayAdapter, 'Swapped') - .withArgs(weth.address, dai.address, flashloanAmount.toString(), expectedDaiAmount); + .withArgs(weth.address, dai.address, liquidityToSwap.toString(), flashLoanDebt); const adapterWethBalance = await weth.balanceOf(uniswapRepayAdapter.address); const adapterDaiBalance = await dai.balanceOf(uniswapRepayAdapter.address); @@ -2257,19 +2257,15 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => { const liquidityToSwap = amountWETHtoSwap; await aWETH.connect(user).approve(uniswapRepayAdapter.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); - - await mockUniswapRouter.connect(user).setAmountToSwap(weth.address, flashloanAmount); + await mockUniswapRouter.connect(user).setAmountToSwap(weth.address, liquidityToSwap); const params = buildRepayAdapterParams( - dai.address, - expectedDaiAmount, + weth.address, + liquidityToSwap, 1, 0, 0, 0, - 0, '0x0000000000000000000000000000000000000000000000000000000000000000', '0x0000000000000000000000000000000000000000000000000000000000000000' ); @@ -2278,8 +2274,8 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => { uniswapRepayAdapter .connect(user) .executeOperation( - [weth.address], - [flashloanAmount.toString()], + [dai.address], + [expectedDaiAmount.toString()], [0], userAddress, params @@ -2309,19 +2305,15 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => { const liquidityToSwap = amountWETHtoSwap; await aWETH.connect(user).approve(uniswapRepayAdapter.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); - - await mockUniswapRouter.connect(user).setAmountToSwap(weth.address, flashloanAmount); + await mockUniswapRouter.connect(user).setAmountToSwap(weth.address, liquidityToSwap); const params = buildRepayAdapterParams( - dai.address, - expectedDaiAmount, + weth.address, + liquidityToSwap, 1, 0, 0, 0, - 0, '0x0000000000000000000000000000000000000000000000000000000000000000', '0x0000000000000000000000000000000000000000000000000000000000000000' ); @@ -2331,8 +2323,8 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => { .connect(user) .flashLoan( uniswapRepayAdapter.address, - [weth.address], - [flashloanAmount.toString()], + [dai.address], + [expectedDaiAmount.toString()], [0], userAddress, params, @@ -2360,19 +2352,15 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => { const liquidityToSwap = amountWETHtoSwap; await aWETH.connect(user).approve(uniswapRepayAdapter.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); - - await mockUniswapRouter.connect(user).setAmountToSwap(weth.address, flashloanAmount); + await mockUniswapRouter.connect(user).setAmountToSwap(weth.address, liquidityToSwap); const params = buildRepayAdapterParams( - dai.address, - expectedDaiAmount, + weth.address, + liquidityToSwap, 1, 0, 0, 0, - 0, '0x0000000000000000000000000000000000000000000000000000000000000000', '0x0000000000000000000000000000000000000000000000000000000000000000' ); @@ -2382,8 +2370,8 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => { .connect(user) .flashLoan( uniswapRepayAdapter.address, - [weth.address], - [flashloanAmount.toString()], + [dai.address], + [expectedDaiAmount.toString()], [0], userAddress, params, @@ -2408,22 +2396,18 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => { // Open user Debt await pool.connect(user).borrow(dai.address, expectedDaiAmount, 1, 0, userAddress); - await aWETH.connect(user).approve(uniswapRepayAdapter.address, amountWETHtoSwap); - - // Subtract the FL fee from the amount to be swapped 0,09% const bigMaxAmountToSwap = amountWETHtoSwap.mul(2); - const flashloanAmount = new BigNumber(bigMaxAmountToSwap.toString()).div(1.0009).toFixed(0); + await aWETH.connect(user).approve(uniswapRepayAdapter.address, bigMaxAmountToSwap); - await mockUniswapRouter.connect(user).setAmountToSwap(weth.address, flashloanAmount); + await mockUniswapRouter.connect(user).setAmountToSwap(weth.address, bigMaxAmountToSwap); const params = buildRepayAdapterParams( - dai.address, - expectedDaiAmount, + weth.address, + bigMaxAmountToSwap, 1, 0, 0, 0, - 0, '0x0000000000000000000000000000000000000000000000000000000000000000', '0x0000000000000000000000000000000000000000000000000000000000000000' ); @@ -2433,8 +2417,8 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => { .connect(user) .flashLoan( uniswapRepayAdapter.address, - [weth.address], - [flashloanAmount.toString()], + [dai.address], + [expectedDaiAmount.toString()], [0], userAddress, params, @@ -2482,26 +2466,27 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => { const liquidityToSwap = amountWETHtoSwap; await aWETH.connect(user).approve(uniswapRepayAdapter.address, liquidityToSwap); const userAEthBalanceBefore = await aWETH.balanceOf(userAddress); + const userWethBalanceBefore = await weth.balanceOf(userAddress); - // Subtract the FL fee from the amount to be swapped 0,09% - const flashloanAmount = new BigNumber(liquidityToSwap.toString()).div(1.0009).toFixed(0); - - const actualWEthSwapped = new BigNumber(flashloanAmount.toString()) + const actualWEthSwapped = new BigNumber(liquidityToSwap.toString()) .multipliedBy(0.995) .toFixed(0); - const leftOverWeth = new BigNumber(flashloanAmount).minus(actualWEthSwapped); + const leftOverWeth = new BigNumber(liquidityToSwap.toString()).minus(actualWEthSwapped); await mockUniswapRouter.connect(user).setAmountToSwap(weth.address, actualWEthSwapped); + const flashLoanDebt = new BigNumber(expectedDaiAmount.toString()) + .multipliedBy(1.0009) + .toFixed(0); + const params = buildRepayAdapterParams( - dai.address, - expectedDaiAmount, + weth.address, + liquidityToSwap, 1, 0, 0, 0, - 0, '0x0000000000000000000000000000000000000000000000000000000000000000', '0x0000000000000000000000000000000000000000000000000000000000000000' ); @@ -2511,8 +2496,8 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => { .connect(user) .flashLoan( uniswapRepayAdapter.address, - [weth.address], - [flashloanAmount.toString()], + [dai.address], + [expectedDaiAmount.toString()], [0], userAddress, params, @@ -2520,13 +2505,14 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => { ) ) .to.emit(uniswapRepayAdapter, 'Swapped') - .withArgs(weth.address, dai.address, actualWEthSwapped.toString(), expectedDaiAmount); + .withArgs(weth.address, dai.address, actualWEthSwapped.toString(), flashLoanDebt); const adapterWethBalance = await weth.balanceOf(uniswapRepayAdapter.address); const adapterDaiBalance = await dai.balanceOf(uniswapRepayAdapter.address); const userDaiStableDebtAmount = await daiStableDebtContract.balanceOf(userAddress); const userAEthBalance = await aWETH.balanceOf(userAddress); const adapterAEthBalance = await aWETH.balanceOf(uniswapRepayAdapter.address); + const userWethBalance = await weth.balanceOf(userAddress); expect(adapterAEthBalance).to.be.eq(Zero); expect(adapterWethBalance).to.be.eq(Zero); @@ -2534,13 +2520,11 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => { expect(userDaiStableDebtAmountBefore).to.be.gte(expectedDaiAmount); expect(userDaiStableDebtAmount).to.be.lt(expectedDaiAmount); expect(userAEthBalance).to.be.lt(userAEthBalanceBefore); - expect(userAEthBalance).to.be.gt(userAEthBalanceBefore.sub(liquidityToSwap)); - expect(userAEthBalance).to.be.gte( - userAEthBalanceBefore.sub(liquidityToSwap).add(leftOverWeth.toString()) - ); + expect(userAEthBalance).to.be.eq(userAEthBalanceBefore.sub(liquidityToSwap)); + expect(userWethBalance).to.be.gte(userWethBalanceBefore.add(leftOverWeth.toString())); }); - it('should correctly swap tokens and repay the whole stable debt', async () => { + it('should correctly swap tokens and repay the whole stable debt with no leftovers', async () => { const { users, pool, @@ -2580,19 +2564,16 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => { await aWETH.connect(user).approve(uniswapRepayAdapter.address, liquidityToSwap); const userAEthBalanceBefore = await aWETH.balanceOf(userAddress); - // Subtract the FL fee from the amount to be swapped 0,09% - const flashloanAmount = new BigNumber(liquidityToSwap.toString()).div(1.0009).toFixed(0); + // Add a % to repay on top of the debt + const amountToRepay = new BigNumber(expectedDaiAmount.toString()) + .multipliedBy(1.1) + .toFixed(0); - await mockUniswapRouter.connect(user).setAmountToSwap(weth.address, flashloanAmount); - - // Passed amount to repay is smaller than debt, - // but repayAllDebt flag is enabled so the whole debt should be paid - const amountToRepay = expectedDaiAmount.div(2); + await mockUniswapRouter.connect(user).setAmountToSwap(weth.address, liquidityToSwap); const params = buildRepayAdapterParams( - dai.address, - amountToRepay, - 1, + weth.address, + liquidityToSwap, 1, 0, 0, @@ -2605,8 +2586,8 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => { .connect(user) .flashLoan( uniswapRepayAdapter.address, - [weth.address], - [flashloanAmount.toString()], + [dai.address], + [amountToRepay.toString()], [0], userAddress, params, @@ -2628,7 +2609,7 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => { expect(userAEthBalance).to.be.gte(userAEthBalanceBefore.sub(liquidityToSwap)); }); - it('should correctly swap tokens and repay the whole variable debt', async () => { + it('should correctly swap tokens and repay the whole variable debt with no leftovers', async () => { const { users, pool, @@ -2670,20 +2651,17 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => { await aWETH.connect(user).approve(uniswapRepayAdapter.address, liquidityToSwap); const userAEthBalanceBefore = await aWETH.balanceOf(userAddress); - // Subtract the FL fee from the amount to be swapped 0,09% - const flashloanAmount = new BigNumber(liquidityToSwap.toString()).div(1.0009).toFixed(0); + // Add a % to repay on top of the debt + const amountToRepay = new BigNumber(expectedDaiAmount.toString()) + .multipliedBy(1.1) + .toFixed(0); - await mockUniswapRouter.connect(user).setAmountToSwap(weth.address, flashloanAmount); - - // Passed amount to repay is smaller than debt, - // but repayAllDebt flag is enabled so the whole debt should be paid - const amountToRepay = expectedDaiAmount.div(2); + await mockUniswapRouter.connect(user).setAmountToSwap(weth.address, liquidityToSwap); const params = buildRepayAdapterParams( - dai.address, - amountToRepay, + weth.address, + liquidityToSwap, 2, - 1, 0, 0, 0, @@ -2695,8 +2673,8 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => { .connect(user) .flashLoan( uniswapRepayAdapter.address, - [weth.address], - [flashloanAmount.toString()], + [dai.address], + [amountToRepay.toString()], [0], userAddress, params, @@ -2717,192 +2695,6 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => { expect(userAEthBalance).to.be.lt(userAEthBalanceBefore); expect(userAEthBalance).to.be.gte(userAEthBalanceBefore.sub(liquidityToSwap)); }); - - it('should swap and repay debt using all the collateral for a bigger debt', async () => { - const { - users, - pool, - weth, - aWETH, - oracle, - dai, - uniswapRepayAdapter, - helpersContract, - } = testEnv; - const user = users[0].signer; - const userAddress = users[0].address; - - 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) - ); - - const userDebt = new BigNumber(expectedDaiAmount.toString()).multipliedBy(1.1).toFixed(0); - // Open user Debt - await pool.connect(user).borrow(dai.address, userDebt, 1, 0, userAddress); - - const daiStableDebtTokenAddress = ( - await helpersContract.getReserveTokensAddresses(dai.address) - ).stableDebtTokenAddress; - - const daiStableDebtContract = await getContract( - eContractid.StableDebtToken, - daiStableDebtTokenAddress - ); - - const userDaiStableDebtAmountBefore = await daiStableDebtContract.balanceOf(userAddress); - - const liquidityToSwap = amountWETHtoSwap; - await aWETH.connect(user).approve(uniswapRepayAdapter.address, liquidityToSwap); - const userAEthBalanceBefore = await aWETH.balanceOf(userAddress); - - // Subtract the FL fee from the amount to be swapped 0,09% - const flashloanAmount = new BigNumber(liquidityToSwap.toString()).div(1.0009).toFixed(0); - - const actualWEthSwapped = new BigNumber(flashloanAmount.toString()) - .multipliedBy(0.995) - .toFixed(0); - - // Remove other balance - await aWETH - .connect(user) - .transfer(users[1].address, userAEthBalanceBefore.sub(actualWEthSwapped)); - - await mockUniswapRouter.connect(user).setAmountToReturn(weth.address, expectedDaiAmount); - - const params = buildRepayAdapterParams( - dai.address, - expectedDaiAmount, - 1, - 2, - 0, - 0, - 0, - '0x0000000000000000000000000000000000000000000000000000000000000000', - '0x0000000000000000000000000000000000000000000000000000000000000000' - ); - - await pool - .connect(user) - .flashLoan( - uniswapRepayAdapter.address, - [weth.address], - [flashloanAmount.toString()], - [0], - userAddress, - params, - 0 - ); - - const adapterWethBalance = await weth.balanceOf(uniswapRepayAdapter.address); - const adapterDaiBalance = await dai.balanceOf(uniswapRepayAdapter.address); - const userDaiStableDebtAmount = await daiStableDebtContract.balanceOf(userAddress); - const userAEthBalance = await aWETH.balanceOf(userAddress); - const adapterAEthBalance = await aWETH.balanceOf(uniswapRepayAdapter.address); - - expect(adapterAEthBalance).to.be.eq(Zero); - expect(adapterWethBalance).to.be.eq(Zero); - expect(adapterDaiBalance).to.be.eq(Zero); - expect(userDaiStableDebtAmountBefore).to.be.gte(expectedDaiAmount); - expect(userDaiStableDebtAmount).to.be.lt(expectedDaiAmount); - expect(userAEthBalance).to.be.eq(Zero); - }); - - it('should swap and repay debt using all the collateral for a smaller debt', async () => { - const { - users, - pool, - weth, - aWETH, - oracle, - dai, - uniswapRepayAdapter, - helpersContract, - } = testEnv; - const user = users[0].signer; - const userAddress = users[0].address; - - 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) - ); - - const userDebt = new BigNumber(expectedDaiAmount.toString()).multipliedBy(0.9).toFixed(0); - // Open user Debt - await pool.connect(user).borrow(dai.address, userDebt, 1, 0, userAddress); - - const daiStableDebtTokenAddress = ( - await helpersContract.getReserveTokensAddresses(dai.address) - ).stableDebtTokenAddress; - - const daiStableDebtContract = await getContract( - eContractid.StableDebtToken, - daiStableDebtTokenAddress - ); - - const userDaiStableDebtAmountBefore = await daiStableDebtContract.balanceOf(userAddress); - - const liquidityToSwap = amountWETHtoSwap; - await aWETH.connect(user).approve(uniswapRepayAdapter.address, liquidityToSwap); - const userAEthBalanceBefore = await aWETH.balanceOf(userAddress); - - // Subtract the FL fee from the amount to be swapped 0,09% - const flashloanAmount = new BigNumber(liquidityToSwap.toString()).div(1.0009).toFixed(0); - - const actualWEthSwapped = new BigNumber(flashloanAmount.toString()) - .multipliedBy(0.995) - .toFixed(0); - - // Remove other balance - await aWETH - .connect(user) - .transfer(users[1].address, userAEthBalanceBefore.sub(actualWEthSwapped)); - - await mockUniswapRouter.connect(user).setAmountToReturn(weth.address, expectedDaiAmount); - - const params = buildRepayAdapterParams( - dai.address, - expectedDaiAmount, - 1, - 2, - 0, - 0, - 0, - '0x0000000000000000000000000000000000000000000000000000000000000000', - '0x0000000000000000000000000000000000000000000000000000000000000000' - ); - - await pool - .connect(user) - .flashLoan( - uniswapRepayAdapter.address, - [weth.address], - [flashloanAmount.toString()], - [0], - userAddress, - params, - 0 - ); - - const adapterWethBalance = await weth.balanceOf(uniswapRepayAdapter.address); - const adapterDaiBalance = await dai.balanceOf(uniswapRepayAdapter.address); - const userDaiStableDebtAmount = await daiStableDebtContract.balanceOf(userAddress); - const userAEthBalance = await aWETH.balanceOf(userAddress); - const adapterAEthBalance = await aWETH.balanceOf(uniswapRepayAdapter.address); - - expect(adapterAEthBalance).to.be.eq(Zero); - expect(adapterWethBalance).to.be.eq(Zero); - expect(adapterDaiBalance).to.be.eq(Zero); // Validate there are no leftovers - expect(userDaiStableDebtAmountBefore).to.be.gte(userDebt); - expect(userDaiStableDebtAmount).to.be.eq(Zero); - expect(userAEthBalance).to.be.eq(Zero); - }); }); }); });