From 50e5ea907b9d3977b399ef78ef6ef06011ff1ca2 Mon Sep 17 00:00:00 2001 From: Gerardo Nardelli Date: Tue, 24 Nov 2020 12:11:13 -0300 Subject: [PATCH] Add first draft of swapAndRepay without using flash loans --- contracts/adapters/BaseUniswapAdapter.sol | 29 ++++++++++++------ contracts/adapters/UniswapRepayAdapter.sol | 34 ++++++++++++++++++++++ 2 files changed, 54 insertions(+), 9 deletions(-) diff --git a/contracts/adapters/BaseUniswapAdapter.sol b/contracts/adapters/BaseUniswapAdapter.sol index 7a727b7d..0e4ca193 100644 --- a/contracts/adapters/BaseUniswapAdapter.sol +++ b/contracts/adapters/BaseUniswapAdapter.sol @@ -73,7 +73,7 @@ contract BaseUniswapAdapter { view returns (uint256, uint256, uint256, uint256) { - AmountCalc memory results = _getAmountsOut(reserveIn, reserveOut, amountIn); + AmountCalc memory results = _getAmountsOutData(reserveIn, reserveOut, amountIn); return ( results.calculatedAmount, @@ -98,7 +98,7 @@ contract BaseUniswapAdapter { view returns (uint256, uint256, uint256, uint256) { - AmountCalc memory results = _getAmountsIn(reserveIn, reserveOut, amountOut); + AmountCalc memory results = _getAmountsInData(reserveIn, reserveOut, amountOut); return ( results.calculatedAmount, @@ -291,7 +291,7 @@ contract BaseUniswapAdapter { * uint256 In amount of reserveIn value denominated in USD (8 decimals) * uint256 Out amount of reserveOut value denominated in USD (8 decimals) */ - function _getAmountsOut(address reserveIn, address reserveOut, uint256 amountIn) internal view returns (AmountCalc memory) { + function _getAmountsOutData(address reserveIn, address reserveOut, uint256 amountIn) internal view returns (AmountCalc memory) { // Subtract flash loan fee uint256 finalAmountIn = amountIn.sub(amountIn.mul(FLASHLOAN_PREMIUM_TOTAL).div(10000)); @@ -328,12 +328,8 @@ contract BaseUniswapAdapter { * uint256 In amount of reserveIn value denominated in USD (8 decimals) * uint256 Out amount of reserveOut value denominated in USD (8 decimals) */ - function _getAmountsIn(address reserveIn, address reserveOut, uint256 amountOut) internal view returns (AmountCalc memory) { - address[] memory path = new address[](2); - path[0] = reserveIn; - path[1] = reserveOut; - - uint256[] memory amounts = UNISWAP_ROUTER.getAmountsIn(amountOut, path); + function _getAmountsInData(address reserveIn, address reserveOut, uint256 amountOut) internal view returns (AmountCalc memory) { + uint256[] memory amounts = _getAmountsIn(reserveIn, reserveOut, amountOut); // Add flash loan fee uint256 finalAmountIn = amounts[0].add(amounts[0].mul(FLASHLOAN_PREMIUM_TOTAL).div(10000)); @@ -353,4 +349,19 @@ contract BaseUniswapAdapter { _calcUsdValue(reserveOut, amountOut, reserveOutDecimals) ); } + + /** + * @dev Calculates the input asset amount required to buy the given output asset amount + * @param reserveIn Address of the asset to be swap from + * @param reserveOut Address of the asset to be swap to + * @param amountOut Amount of reserveOut + * @return uint256[] amounts Array containing the amountIn and amountOut for a swap + */ + function _getAmountsIn(address reserveIn, address reserveOut, uint256 amountOut) internal view returns (uint256[] memory) { + address[] memory path = new address[](2); + path[0] = reserveIn; + path[1] = reserveOut; + + return UNISWAP_ROUTER.getAmountsIn(amountOut, path); + } } diff --git a/contracts/adapters/UniswapRepayAdapter.sol b/contracts/adapters/UniswapRepayAdapter.sol index c42df484..9c741745 100644 --- a/contracts/adapters/UniswapRepayAdapter.sol +++ b/contracts/adapters/UniswapRepayAdapter.sol @@ -76,6 +76,40 @@ contract UniswapRepayAdapter is BaseUniswapAdapter, IFlashLoanReceiver { return true; } + function swapAndRepay( + address collateralAsset, + address debtAsset, + uint256 collateralAmount, + uint256 debtRepayAmount, + uint256 debtRateMode, + PermitSignature calldata permitSignature + ) external { + ReserveLogic.ReserveData memory reserveData = _getReserveData(collateralAsset); + + if (collateralAsset != debtAsset) { + // Get exact collateral needed for the swap to avoid leftovers + uint256[] memory amounts = _getAmountsIn(collateralAsset, debtAsset, debtRepayAmount); + require(amounts[0] <= collateralAmount, 'slippage too high'); + + // Pull aTokens from user + _pullAToken(collateralAsset, reserveData.aTokenAddress, msg.sender, amounts[0], permitSignature); + + // Swap collateral for debt asset + _swapTokensForExactTokens(collateralAsset, debtAsset, amounts[0], debtRepayAmount); + } else { + // Pull aTokens from user + _pullAToken(collateralAsset, reserveData.aTokenAddress, msg.sender, debtRepayAmount, permitSignature); + } + + // Repay debt + IERC20(debtAsset).approve(address(POOL), debtRepayAmount); + POOL.repay(debtAsset, debtRepayAmount, debtRateMode, msg.sender); + + // In the case the repay amount provided exceeded the actual debt, send the leftovers to the user + _sendLeftovers(debtAsset, msg.sender); + } + + /** * @dev Perform the repay of the debt, pulls the initiator collateral and swaps to repay the flash loan *