mirror of
				https://github.com/Instadapp/aave-protocol-v2.git
				synced 2024-07-29 21:47:30 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			267 lines
		
	
	
		
			9.7 KiB
		
	
	
	
		
			Solidity
		
	
	
	
	
	
			
		
		
	
	
			267 lines
		
	
	
		
			9.7 KiB
		
	
	
	
		
			Solidity
		
	
	
	
	
	
| // SPDX-License-Identifier: agpl-3.0
 | |
| pragma solidity 0.6.12;
 | |
| pragma experimental ABIEncoderV2;
 | |
| 
 | |
| import {BaseUniswapAdapter} from './BaseUniswapAdapter.sol';
 | |
| import {ILendingPoolAddressesProvider} from '../interfaces/ILendingPoolAddressesProvider.sol';
 | |
| import {IUniswapV2Router02} from '../interfaces/IUniswapV2Router02.sol';
 | |
| import {IERC20} from '../dependencies/openzeppelin/contracts/IERC20.sol';
 | |
| import {DataTypes} from '../protocol/libraries/types/DataTypes.sol';
 | |
| 
 | |
| /**
 | |
|  * @title UniswapRepayAdapter
 | |
|  * @notice Uniswap V2 Adapter to perform a repay of a debt with collateral.
 | |
|  * @author Aave
 | |
|  **/
 | |
| contract UniswapRepayAdapter is BaseUniswapAdapter {
 | |
|   struct RepayParams {
 | |
|     address collateralAsset;
 | |
|     uint256 collateralAmount;
 | |
|     uint256 rateMode;
 | |
|     PermitSignature permitSignature;
 | |
|     bool useEthPath;
 | |
|   }
 | |
| 
 | |
|   constructor(
 | |
|     ILendingPoolAddressesProvider addressesProvider,
 | |
|     IUniswapV2Router02 uniswapRouter,
 | |
|     address wethAddress
 | |
|   ) public BaseUniswapAdapter(addressesProvider, uniswapRouter, wethAddress) {}
 | |
| 
 | |
|   /**
 | |
|    * @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 the debt asset 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.
 | |
|    * Supports only one asset on the flash loan.
 | |
|    * @param assets Address of debt asset
 | |
|    * @param amounts Amount of the debt to be repaid
 | |
|    * @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 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
 | |
|    *   uint256 permitAmount Amount for the permit signature
 | |
|    *   uint256 deadline Deadline for the permit signature
 | |
|    *   uint8 v V param for the permit signature
 | |
|    *   bytes32 r R param for the permit signature
 | |
|    *   bytes32 s S param for the permit signature
 | |
|    */
 | |
|   function executeOperation(
 | |
|     address[] calldata assets,
 | |
|     uint256[] calldata amounts,
 | |
|     uint256[] calldata premiums,
 | |
|     address initiator,
 | |
|     bytes calldata params
 | |
|   ) external override returns (bool) {
 | |
|     require(msg.sender == address(LENDING_POOL), 'CALLER_MUST_BE_LENDING_POOL');
 | |
| 
 | |
|     RepayParams memory decodedParams = _decodeParams(params);
 | |
| 
 | |
|     _swapAndRepay(
 | |
|       decodedParams.collateralAsset,
 | |
|       assets[0],
 | |
|       amounts[0],
 | |
|       decodedParams.collateralAmount,
 | |
|       decodedParams.rateMode,
 | |
|       initiator,
 | |
|       premiums[0],
 | |
|       decodedParams.permitSignature,
 | |
|       decodedParams.useEthPath
 | |
|     );
 | |
| 
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * @dev Swaps the user collateral for the debt asset and then repay the debt on the protocol on behalf of the user
 | |
|    * without using flash loans. This method can be used when the temporary transfer of the collateral asset to this
 | |
|    * contract does not affect the user position.
 | |
|    * The user should give this contract allowance to pull the ATokens in order to withdraw the underlying asset
 | |
|    * @param collateralAsset Address of asset to be swapped
 | |
|    * @param debtAsset Address of debt asset
 | |
|    * @param collateralAmount Amount of the collateral to be swapped
 | |
|    * @param debtRepayAmount Amount of the debt to be repaid
 | |
|    * @param debtRateMode Rate mode of the debt to be repaid
 | |
|    * @param permitSignature struct containing the permit signature
 | |
|    * @param useEthPath struct containing the permit signature
 | |
| 
 | |
|    */
 | |
|   function swapAndRepay(
 | |
|     address collateralAsset,
 | |
|     address debtAsset,
 | |
|     uint256 collateralAmount,
 | |
|     uint256 debtRepayAmount,
 | |
|     uint256 debtRateMode,
 | |
|     PermitSignature calldata permitSignature,
 | |
|     bool useEthPath
 | |
|   ) external {
 | |
|     DataTypes.ReserveData memory collateralReserveData = _getReserveData(collateralAsset);
 | |
|     DataTypes.ReserveData memory debtReserveData = _getReserveData(debtAsset);
 | |
| 
 | |
|     address debtToken =
 | |
|       DataTypes.InterestRateMode(debtRateMode) == DataTypes.InterestRateMode.STABLE
 | |
|         ? debtReserveData.stableDebtTokenAddress
 | |
|         : debtReserveData.variableDebtTokenAddress;
 | |
| 
 | |
|     uint256 currentDebt = IERC20(debtToken).balanceOf(msg.sender);
 | |
|     uint256 amountToRepay = debtRepayAmount <= currentDebt ? debtRepayAmount : currentDebt;
 | |
| 
 | |
|     if (collateralAsset != debtAsset) {
 | |
|       uint256 maxCollateralToSwap = collateralAmount;
 | |
|       if (amountToRepay < debtRepayAmount) {
 | |
|         maxCollateralToSwap = maxCollateralToSwap.mul(amountToRepay).div(debtRepayAmount);
 | |
|       }
 | |
| 
 | |
|       // Get exact collateral needed for the swap to avoid leftovers
 | |
|       uint256[] memory amounts =
 | |
|         _getAmountsIn(collateralAsset, debtAsset, amountToRepay, useEthPath);
 | |
|       require(amounts[0] <= maxCollateralToSwap, 'slippage too high');
 | |
| 
 | |
|       // Pull aTokens from user
 | |
|       _pullAToken(
 | |
|         collateralAsset,
 | |
|         collateralReserveData.aTokenAddress,
 | |
|         msg.sender,
 | |
|         amounts[0],
 | |
|         permitSignature
 | |
|       );
 | |
| 
 | |
|       // Swap collateral for debt asset
 | |
|       _swapTokensForExactTokens(collateralAsset, debtAsset, amounts[0], amountToRepay, useEthPath);
 | |
|     } else {
 | |
|       // Pull aTokens from user
 | |
|       _pullAToken(
 | |
|         collateralAsset,
 | |
|         collateralReserveData.aTokenAddress,
 | |
|         msg.sender,
 | |
|         amountToRepay,
 | |
|         permitSignature
 | |
|       );
 | |
|     }
 | |
| 
 | |
|     // Repay debt. Approves 0 first to comply with tokens that implement the anti frontrunning approval fix
 | |
|     IERC20(debtAsset).safeApprove(address(LENDING_POOL), 0);
 | |
|     IERC20(debtAsset).safeApprove(address(LENDING_POOL), amountToRepay);
 | |
|     LENDING_POOL.repay(debtAsset, amountToRepay, debtRateMode, msg.sender);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * @dev Perform the repay of the debt, pulls the initiator collateral and swaps to repay the flash loan
 | |
|    *
 | |
|    * @param collateralAsset Address of token to be swapped
 | |
|    * @param debtAsset 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
 | |
|    * @param permitSignature struct containing the permit signature
 | |
|    */
 | |
|   function _swapAndRepay(
 | |
|     address collateralAsset,
 | |
|     address debtAsset,
 | |
|     uint256 amount,
 | |
|     uint256 collateralAmount,
 | |
|     uint256 rateMode,
 | |
|     address initiator,
 | |
|     uint256 premium,
 | |
|     PermitSignature memory permitSignature,
 | |
|     bool useEthPath
 | |
|   ) internal {
 | |
|     DataTypes.ReserveData memory collateralReserveData = _getReserveData(collateralAsset);
 | |
| 
 | |
|     // Repay debt. Approves for 0 first to comply with tokens that implement the anti frontrunning approval fix.
 | |
|     IERC20(debtAsset).safeApprove(address(LENDING_POOL), 0);
 | |
|     IERC20(debtAsset).safeApprove(address(LENDING_POOL), amount);
 | |
|     uint256 repaidAmount = IERC20(debtAsset).balanceOf(address(this));
 | |
|     LENDING_POOL.repay(debtAsset, amount, rateMode, initiator);
 | |
|     repaidAmount = repaidAmount.sub(IERC20(debtAsset).balanceOf(address(this)));
 | |
| 
 | |
|     if (collateralAsset != debtAsset) {
 | |
|       uint256 maxCollateralToSwap = collateralAmount;
 | |
|       if (repaidAmount < amount) {
 | |
|         maxCollateralToSwap = maxCollateralToSwap.mul(repaidAmount).div(amount);
 | |
|       }
 | |
| 
 | |
|       uint256 neededForFlashLoanDebt = repaidAmount.add(premium);
 | |
|       uint256[] memory amounts =
 | |
|         _getAmountsIn(collateralAsset, debtAsset, neededForFlashLoanDebt, useEthPath);
 | |
|       require(amounts[0] <= maxCollateralToSwap, 'slippage too high');
 | |
| 
 | |
|       // Pull aTokens from user
 | |
|       _pullAToken(
 | |
|         collateralAsset,
 | |
|         collateralReserveData.aTokenAddress,
 | |
|         initiator,
 | |
|         amounts[0],
 | |
|         permitSignature
 | |
|       );
 | |
| 
 | |
|       // Swap collateral asset to the debt asset
 | |
|       _swapTokensForExactTokens(
 | |
|         collateralAsset,
 | |
|         debtAsset,
 | |
|         amounts[0],
 | |
|         neededForFlashLoanDebt,
 | |
|         useEthPath
 | |
|       );
 | |
|     } else {
 | |
|       // Pull aTokens from user
 | |
|       _pullAToken(
 | |
|         collateralAsset,
 | |
|         collateralReserveData.aTokenAddress,
 | |
|         initiator,
 | |
|         repaidAmount.add(premium),
 | |
|         permitSignature
 | |
|       );
 | |
|     }
 | |
| 
 | |
|     // Repay flashloan. Approves for 0 first to comply with tokens that implement the anti frontrunning approval fix.
 | |
|     IERC20(debtAsset).safeApprove(address(LENDING_POOL), 0);
 | |
|     IERC20(debtAsset).safeApprove(address(LENDING_POOL), amount.add(premium));
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * @dev Decodes debt information encoded in the flash loan params
 | |
|    * @param params Additional variadic field to include extra params. Expected parameters:
 | |
|    *   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
 | |
|    *   uint256 permitAmount Amount for the permit signature
 | |
|    *   uint256 deadline Deadline for the permit signature
 | |
|    *   uint8 v V param for the permit signature
 | |
|    *   bytes32 r R param for the permit signature
 | |
|    *   bytes32 s S param for the permit signature
 | |
|    *   bool useEthPath use WETH path route
 | |
|    * @return RepayParams struct containing decoded params
 | |
|    */
 | |
|   function _decodeParams(bytes memory params) internal pure returns (RepayParams memory) {
 | |
|     (
 | |
|       address collateralAsset,
 | |
|       uint256 collateralAmount,
 | |
|       uint256 rateMode,
 | |
|       uint256 permitAmount,
 | |
|       uint256 deadline,
 | |
|       uint8 v,
 | |
|       bytes32 r,
 | |
|       bytes32 s,
 | |
|       bool useEthPath
 | |
|     ) =
 | |
|       abi.decode(
 | |
|         params,
 | |
|         (address, uint256, uint256, uint256, uint256, uint8, bytes32, bytes32, bool)
 | |
|       );
 | |
| 
 | |
|     return
 | |
|       RepayParams(
 | |
|         collateralAsset,
 | |
|         collateralAmount,
 | |
|         rateMode,
 | |
|         PermitSignature(permitAmount, deadline, v, r, s),
 | |
|         useEthPath
 | |
|       );
 | |
|   }
 | |
| }
 | 
