mirror of
				https://github.com/Instadapp/aave-protocol-v2.git
				synced 2024-07-29 21:47:30 +00:00 
			
		
		
		
	Merge branch 'feat/uniswap-adapter-flashloan' into '178-add-uniswap-adapters'
Add Uniswap adapter for liquidity swap and repay with collateral using flashloan See merge request aave-tech/protocol-v2!106
This commit is contained in:
		
						commit
						a32d1ce404
					
				
							
								
								
									
										367
									
								
								contracts/adapters/BaseUniswapAdapter.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										367
									
								
								contracts/adapters/BaseUniswapAdapter.sol
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,367 @@
 | 
			
		|||
// SPDX-License-Identifier: agpl-3.0
 | 
			
		||||
pragma solidity 0.6.12;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
import {PercentageMath} from '../protocol/libraries/math/PercentageMath.sol';
 | 
			
		||||
import {SafeMath} from '../dependencies/openzeppelin/contracts/SafeMath.sol';
 | 
			
		||||
import {IERC20} from '../dependencies/openzeppelin/contracts/IERC20.sol';
 | 
			
		||||
import {IERC20Detailed} from '../dependencies/openzeppelin/contracts/IERC20Detailed.sol';
 | 
			
		||||
import {SafeERC20} from '../dependencies/openzeppelin/contracts/SafeERC20.sol';
 | 
			
		||||
import {ILendingPoolAddressesProvider} from '../interfaces/ILendingPoolAddressesProvider.sol';
 | 
			
		||||
import {ILendingPool} from '../interfaces/ILendingPool.sol';
 | 
			
		||||
import {DataTypes} from '../protocol/libraries/types/DataTypes.sol';
 | 
			
		||||
import {IUniswapV2Router02} from '../interfaces/IUniswapV2Router02.sol';
 | 
			
		||||
import {IPriceOracleGetter} from '../interfaces/IPriceOracleGetter.sol';
 | 
			
		||||
import {IERC20WithPermit} from '../interfaces/IERC20WithPermit.sol';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @title BaseUniswapAdapter
 | 
			
		||||
 * @notice Implements the logic for performing assets swaps in Uniswap V2
 | 
			
		||||
 * @author Aave
 | 
			
		||||
 **/
 | 
			
		||||
contract BaseUniswapAdapter {
 | 
			
		||||
  using SafeMath for uint256;
 | 
			
		||||
  using PercentageMath for uint256;
 | 
			
		||||
  using SafeERC20 for IERC20;
 | 
			
		||||
 | 
			
		||||
  struct PermitSignature {
 | 
			
		||||
    uint256 amount;
 | 
			
		||||
    uint256 deadline;
 | 
			
		||||
    uint8 v;
 | 
			
		||||
    bytes32 r;
 | 
			
		||||
    bytes32 s;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  struct AmountCalc {
 | 
			
		||||
    uint256 calculatedAmount;
 | 
			
		||||
    uint256 relativePrice;
 | 
			
		||||
    uint256 amountInUsd;
 | 
			
		||||
    uint256 amountOutUsd;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Max slippage percent allowed
 | 
			
		||||
  uint256 public constant MAX_SLIPPAGE_PERCENT = 3000; // 30%
 | 
			
		||||
  // FLash Loan fee set in lending pool
 | 
			
		||||
  uint256 public constant FLASHLOAN_PREMIUM_TOTAL = 9;
 | 
			
		||||
  // USD oracle asset address
 | 
			
		||||
  address public constant USD_ADDRESS = 0x10F7Fc1F91Ba351f9C629c5947AD69bD03C05b96;
 | 
			
		||||
 | 
			
		||||
  ILendingPool public immutable POOL;
 | 
			
		||||
  IPriceOracleGetter public immutable ORACLE;
 | 
			
		||||
  IUniswapV2Router02 public immutable UNISWAP_ROUTER;
 | 
			
		||||
 | 
			
		||||
  event Swapped(address fromAsset, address toAsset, uint256 fromAmount, uint256 receivedAmount);
 | 
			
		||||
 | 
			
		||||
  constructor(ILendingPoolAddressesProvider addressesProvider, IUniswapV2Router02 uniswapRouter) public {
 | 
			
		||||
    POOL = ILendingPool(addressesProvider.getLendingPool());
 | 
			
		||||
    ORACLE = IPriceOracleGetter(addressesProvider.getPriceOracle());
 | 
			
		||||
    UNISWAP_ROUTER = uniswapRouter;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
 * @dev Given an input asset amount, returns the maximum output amount of the other asset and the prices
 | 
			
		||||
 * @param amountIn Amount of reserveIn
 | 
			
		||||
 * @param reserveIn Address of the asset to be swap from
 | 
			
		||||
 * @param reserveOut Address of the asset to be swap to
 | 
			
		||||
 * @return uint256 Amount out of the reserveOut
 | 
			
		||||
 * @return uint256 The price of out amount denominated in the reserveIn currency (18 decimals)
 | 
			
		||||
 * @return uint256 In amount of reserveIn value denominated in USD (8 decimals)
 | 
			
		||||
 * @return uint256 Out amount of reserveOut value denominated in USD (8 decimals)
 | 
			
		||||
 */
 | 
			
		||||
  function getAmountsOut(uint256 amountIn, address reserveIn, address reserveOut)
 | 
			
		||||
    external
 | 
			
		||||
    view
 | 
			
		||||
    returns (uint256, uint256, uint256, uint256)
 | 
			
		||||
  {
 | 
			
		||||
    AmountCalc memory results = _getAmountsOutData(reserveIn, reserveOut, amountIn);
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
      results.calculatedAmount,
 | 
			
		||||
      results.relativePrice,
 | 
			
		||||
      results.amountInUsd,
 | 
			
		||||
      results.amountOutUsd
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @dev Returns the minimum input asset amount required to buy the given output asset amount and the prices
 | 
			
		||||
   * @param amountOut Amount of reserveOut
 | 
			
		||||
   * @param reserveIn Address of the asset to be swap from
 | 
			
		||||
   * @param reserveOut Address of the asset to be swap to
 | 
			
		||||
   * @return uint256 Amount in of the reserveIn
 | 
			
		||||
   * @return uint256 The price of in amount denominated in the reserveOut currency (18 decimals)
 | 
			
		||||
   * @return uint256 In amount of reserveIn value denominated in USD (8 decimals)
 | 
			
		||||
   * @return uint256 Out amount of reserveOut value denominated in USD (8 decimals)
 | 
			
		||||
   */
 | 
			
		||||
  function getAmountsIn(uint256 amountOut, address reserveIn, address reserveOut)
 | 
			
		||||
    external
 | 
			
		||||
    view
 | 
			
		||||
    returns (uint256, uint256, uint256, uint256)
 | 
			
		||||
  {
 | 
			
		||||
    AmountCalc memory results = _getAmountsInData(reserveIn, reserveOut, amountOut);
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
      results.calculatedAmount,
 | 
			
		||||
      results.relativePrice,
 | 
			
		||||
      results.amountInUsd,
 | 
			
		||||
      results.amountOutUsd
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @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 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 minAmountOut
 | 
			
		||||
  )
 | 
			
		||||
    internal
 | 
			
		||||
    returns (uint256)
 | 
			
		||||
  {
 | 
			
		||||
    uint256 fromAssetDecimals = _getDecimals(assetToSwapFrom);
 | 
			
		||||
    uint256 toAssetDecimals = _getDecimals(assetToSwapTo);
 | 
			
		||||
 | 
			
		||||
    uint256 fromAssetPrice = _getPrice(assetToSwapFrom);
 | 
			
		||||
    uint256 toAssetPrice = _getPrice(assetToSwapTo);
 | 
			
		||||
 | 
			
		||||
    uint256 expectedMinAmountOut = amountToSwap
 | 
			
		||||
      .mul(fromAssetPrice.mul(10**toAssetDecimals))
 | 
			
		||||
      .div(toAssetPrice.mul(10**fromAssetDecimals))
 | 
			
		||||
      .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, minAmountOut, path, address(this), block.timestamp);
 | 
			
		||||
 | 
			
		||||
    emit Swapped(assetToSwapFrom, assetToSwapTo, amounts[0], amounts[1]);
 | 
			
		||||
 | 
			
		||||
    return amounts[1];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @dev Receive an exact amount `amountToReceive` of `assetToSwapTo` tokens for as few `assetToSwapFrom` tokens as
 | 
			
		||||
   * possible.
 | 
			
		||||
   * @param assetToSwapFrom Origin asset
 | 
			
		||||
   * @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 swapped
 | 
			
		||||
   */
 | 
			
		||||
  function _swapTokensForExactTokens(
 | 
			
		||||
    address assetToSwapFrom,
 | 
			
		||||
    address assetToSwapTo,
 | 
			
		||||
    uint256 maxAmountToSwap,
 | 
			
		||||
    uint256 amountToReceive
 | 
			
		||||
  )
 | 
			
		||||
    internal
 | 
			
		||||
    returns (uint256)
 | 
			
		||||
  {
 | 
			
		||||
    uint256 fromAssetDecimals = _getDecimals(assetToSwapFrom);
 | 
			
		||||
    uint256 toAssetDecimals = _getDecimals(assetToSwapTo);
 | 
			
		||||
 | 
			
		||||
    uint256 fromAssetPrice = _getPrice(assetToSwapFrom);
 | 
			
		||||
    uint256 toAssetPrice = _getPrice(assetToSwapTo);
 | 
			
		||||
 | 
			
		||||
    uint256 expectedMaxAmountToSwap = amountToReceive
 | 
			
		||||
      .mul(toAssetPrice.mul(10**fromAssetDecimals))
 | 
			
		||||
      .div(fromAssetPrice.mul(10**toAssetDecimals))
 | 
			
		||||
      .percentMul(PercentageMath.PERCENTAGE_FACTOR.add(MAX_SLIPPAGE_PERCENT));
 | 
			
		||||
 | 
			
		||||
    require(maxAmountToSwap < expectedMaxAmountToSwap, 'maxAmountToSwap exceed max slippage');
 | 
			
		||||
 | 
			
		||||
    IERC20(assetToSwapFrom).approve(address(UNISWAP_ROUTER), maxAmountToSwap);
 | 
			
		||||
 | 
			
		||||
    address[] memory path = new address[](2);
 | 
			
		||||
    path[0] = assetToSwapFrom;
 | 
			
		||||
    path[1] = assetToSwapTo;
 | 
			
		||||
    uint256[] memory amounts = UNISWAP_ROUTER.swapTokensForExactTokens(amountToReceive, maxAmountToSwap, path, address(this), block.timestamp);
 | 
			
		||||
 | 
			
		||||
    emit Swapped(assetToSwapFrom, assetToSwapTo, amounts[0], amounts[1]);
 | 
			
		||||
 | 
			
		||||
    return amounts[0];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @dev Get the price of the asset from the oracle denominated in eth
 | 
			
		||||
   * @param asset address
 | 
			
		||||
   * @return eth price for the asset
 | 
			
		||||
   */
 | 
			
		||||
  function _getPrice(address asset) internal view returns (uint256) {
 | 
			
		||||
    return ORACLE.getAssetPrice(asset);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @dev Get the decimals of an asset
 | 
			
		||||
   * @return number of decimals of the asset
 | 
			
		||||
   */
 | 
			
		||||
  function _getDecimals(address asset) internal view returns (uint256) {
 | 
			
		||||
    return IERC20Detailed(asset).decimals();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @dev Get the aToken associated to the asset
 | 
			
		||||
   * @return address of the aToken
 | 
			
		||||
   */
 | 
			
		||||
  function _getReserveData(address asset) internal view returns (DataTypes.ReserveData memory) {
 | 
			
		||||
    return POOL.getReserveData(asset);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @dev Pull the ATokens from the user
 | 
			
		||||
   * @param reserve address of the asset
 | 
			
		||||
   * @param reserveAToken address of the aToken of the reserve
 | 
			
		||||
   * @param user address
 | 
			
		||||
   * @param amount of tokens to be transferred to the contract
 | 
			
		||||
   * @param permitSignature struct containing the permit signature
 | 
			
		||||
   */
 | 
			
		||||
  function _pullAToken(
 | 
			
		||||
    address reserve,
 | 
			
		||||
    address reserveAToken,
 | 
			
		||||
    address user,
 | 
			
		||||
    uint256 amount,
 | 
			
		||||
    PermitSignature memory permitSignature
 | 
			
		||||
  ) internal {
 | 
			
		||||
    if (_usePermit(permitSignature)) {
 | 
			
		||||
      IERC20WithPermit(reserveAToken).permit(
 | 
			
		||||
        user,
 | 
			
		||||
        address(this),
 | 
			
		||||
        permitSignature.amount,
 | 
			
		||||
        permitSignature.deadline,
 | 
			
		||||
        permitSignature.v,
 | 
			
		||||
        permitSignature.r,
 | 
			
		||||
        permitSignature.s
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // transfer from user to adapter
 | 
			
		||||
    IERC20(reserveAToken).safeTransferFrom(user, address(this), amount);
 | 
			
		||||
 | 
			
		||||
    // withdraw reserve
 | 
			
		||||
    POOL.withdraw(reserve, amount, address(this));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @dev Tells if the permit method should be called by inspecting if there is a valid signature.
 | 
			
		||||
   * If signature params are set to 0, then permit won't be called.
 | 
			
		||||
   * @param signature struct containing the permit signature
 | 
			
		||||
   * @return whether or not permit should be called
 | 
			
		||||
   */
 | 
			
		||||
  function _usePermit(PermitSignature memory signature) internal pure returns (bool) {
 | 
			
		||||
    return !(uint256(signature.deadline) == uint256(signature.v) && uint256(signature.deadline) == 0);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @dev Calculates the value denominated in USD
 | 
			
		||||
   * @param reserve Address of the reserve
 | 
			
		||||
   * @param amount Amount of the reserve
 | 
			
		||||
   * @param decimals Decimals of the reserve
 | 
			
		||||
   * @return whether or not permit should be called
 | 
			
		||||
   */
 | 
			
		||||
  function _calcUsdValue(address reserve, uint256 amount, uint256 decimals) internal view returns (uint256) {
 | 
			
		||||
    uint256 ethUsdPrice = _getPrice(USD_ADDRESS);
 | 
			
		||||
    uint256 reservePrice = _getPrice(reserve);
 | 
			
		||||
 | 
			
		||||
    return amount
 | 
			
		||||
      .mul(reservePrice)
 | 
			
		||||
      .div(10**decimals)
 | 
			
		||||
      .mul(ethUsdPrice)
 | 
			
		||||
      .div(10**18);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @dev Given an input asset amount, returns the maximum output amount of the other asset
 | 
			
		||||
   * @param reserveIn Address of the asset to be swap from
 | 
			
		||||
   * @param reserveOut Address of the asset to be swap to
 | 
			
		||||
   * @param amountIn Amount of reserveIn
 | 
			
		||||
   * @return Struct containing the following information:
 | 
			
		||||
   *   uint256 Amount out of the reserveOut
 | 
			
		||||
   *   uint256 The price of out amount denominated in the reserveIn currency (18 decimals)
 | 
			
		||||
   *   uint256 In amount of reserveIn value denominated in USD (8 decimals)
 | 
			
		||||
   *   uint256 Out amount of reserveOut value denominated in USD (8 decimals)
 | 
			
		||||
   */
 | 
			
		||||
  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));
 | 
			
		||||
 | 
			
		||||
    address[] memory path = new address[](2);
 | 
			
		||||
    path[0] = reserveIn;
 | 
			
		||||
    path[1] = reserveOut;
 | 
			
		||||
 | 
			
		||||
    uint256[] memory amounts = UNISWAP_ROUTER.getAmountsOut(finalAmountIn, path);
 | 
			
		||||
 | 
			
		||||
    uint256 reserveInDecimals = _getDecimals(reserveIn);
 | 
			
		||||
    uint256 reserveOutDecimals = _getDecimals(reserveOut);
 | 
			
		||||
 | 
			
		||||
    uint256 outPerInPrice = finalAmountIn
 | 
			
		||||
      .mul(10**18)
 | 
			
		||||
      .mul(10**reserveOutDecimals)
 | 
			
		||||
      .div(amounts[1].mul(10**reserveInDecimals));
 | 
			
		||||
 | 
			
		||||
    return AmountCalc(
 | 
			
		||||
      amounts[1],
 | 
			
		||||
      outPerInPrice,
 | 
			
		||||
      _calcUsdValue(reserveIn, amountIn, reserveInDecimals),
 | 
			
		||||
      _calcUsdValue(reserveOut, amounts[1], reserveOutDecimals)
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @dev Returns the minimum 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 Struct containing the following information:
 | 
			
		||||
   *   uint256 Amount in of the reserveIn
 | 
			
		||||
   *   uint256 The price of in amount denominated in the reserveOut currency (18 decimals)
 | 
			
		||||
   *   uint256 In amount of reserveIn value denominated in USD (8 decimals)
 | 
			
		||||
   *   uint256 Out amount of reserveOut value denominated in USD (8 decimals)
 | 
			
		||||
   */
 | 
			
		||||
  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));
 | 
			
		||||
 | 
			
		||||
    uint256 reserveInDecimals = _getDecimals(reserveIn);
 | 
			
		||||
    uint256 reserveOutDecimals = _getDecimals(reserveOut);
 | 
			
		||||
 | 
			
		||||
    uint256 inPerOutPrice = amountOut
 | 
			
		||||
      .mul(10**18)
 | 
			
		||||
      .mul(10**reserveInDecimals)
 | 
			
		||||
      .div(finalAmountIn.mul(10**reserveOutDecimals));
 | 
			
		||||
 | 
			
		||||
    return AmountCalc(
 | 
			
		||||
      finalAmountIn,
 | 
			
		||||
      inPerOutPrice,
 | 
			
		||||
      _calcUsdValue(reserveIn, finalAmountIn, reserveInDecimals),
 | 
			
		||||
      _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);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										249
									
								
								contracts/adapters/UniswapLiquiditySwapAdapter.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										249
									
								
								contracts/adapters/UniswapLiquiditySwapAdapter.sol
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,249 @@
 | 
			
		|||
// 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 {IFlashLoanReceiver} from '../flashloan/interfaces/IFlashLoanReceiver.sol';
 | 
			
		||||
import {IERC20} from '../dependencies/openzeppelin/contracts/IERC20.sol';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @title UniswapLiquiditySwapAdapter
 | 
			
		||||
 * @notice Uniswap V2 Adapter to swap liquidity.
 | 
			
		||||
 * @author Aave
 | 
			
		||||
 **/
 | 
			
		||||
contract UniswapLiquiditySwapAdapter is BaseUniswapAdapter, IFlashLoanReceiver {
 | 
			
		||||
 | 
			
		||||
  struct PermitParams {
 | 
			
		||||
    uint256[] amount;
 | 
			
		||||
    uint256[] deadline;
 | 
			
		||||
    uint8[] v;
 | 
			
		||||
    bytes32[] r;
 | 
			
		||||
    bytes32[] s;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  struct SwapParams {
 | 
			
		||||
    address[] assetToSwapToList;
 | 
			
		||||
    uint256[] minAmountsToReceive;
 | 
			
		||||
    bool[] swapAllBalance;
 | 
			
		||||
    PermitParams permitParams;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  constructor(
 | 
			
		||||
    ILendingPoolAddressesProvider addressesProvider,
 | 
			
		||||
    IUniswapV2Router02 uniswapRouter
 | 
			
		||||
  )
 | 
			
		||||
    public
 | 
			
		||||
    BaseUniswapAdapter(addressesProvider, uniswapRouter)
 | 
			
		||||
  {}
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @dev Swaps the received reserve amount from the flash loan into the asset specified in the params.
 | 
			
		||||
   * The received funds from the swap are then deposited into 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.
 | 
			
		||||
   * @param assets Address of asset to be swapped
 | 
			
		||||
   * @param amounts Amount of the asset 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[] assetToSwapToList List of the addresses of the reserve to be swapped to and deposited
 | 
			
		||||
   *   uint256[] minAmountsToReceive List of min amounts to be received from the swap
 | 
			
		||||
   *   bool[] swapAllBalance Flag indicating if all the user balance should be swapped
 | 
			
		||||
   *   uint256[] permitAmount List of amounts for the permit signature
 | 
			
		||||
   *   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
 | 
			
		||||
   *   bytes32[] s List of 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(POOL), "CALLER_MUST_BE_LENDING_POOL");
 | 
			
		||||
 | 
			
		||||
    SwapParams memory decodedParams = _decodeParams(params);
 | 
			
		||||
 | 
			
		||||
    require(
 | 
			
		||||
      assets.length == decodedParams.assetToSwapToList.length
 | 
			
		||||
      && assets.length == decodedParams.minAmountsToReceive.length
 | 
			
		||||
      && assets.length == decodedParams.swapAllBalance.length
 | 
			
		||||
      && assets.length == decodedParams.permitParams.amount.length
 | 
			
		||||
      && assets.length == decodedParams.permitParams.deadline.length
 | 
			
		||||
      && assets.length == decodedParams.permitParams.v.length
 | 
			
		||||
      && assets.length == decodedParams.permitParams.r.length
 | 
			
		||||
      && assets.length == decodedParams.permitParams.s.length,
 | 
			
		||||
      'INCONSISTENT_PARAMS'
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    for (uint256 i = 0; i < assets.length; i++) {
 | 
			
		||||
      _swapLiquidity(
 | 
			
		||||
        assets[i],
 | 
			
		||||
        decodedParams.assetToSwapToList[i],
 | 
			
		||||
        amounts[i],
 | 
			
		||||
        premiums[i],
 | 
			
		||||
        initiator,
 | 
			
		||||
        decodedParams.minAmountsToReceive[i],
 | 
			
		||||
        decodedParams.swapAllBalance[i],
 | 
			
		||||
        PermitSignature(
 | 
			
		||||
          decodedParams.permitParams.amount[i],
 | 
			
		||||
          decodedParams.permitParams.deadline[i],
 | 
			
		||||
          decodedParams.permitParams.v[i],
 | 
			
		||||
          decodedParams.permitParams.r[i],
 | 
			
		||||
          decodedParams.permitParams.s[i]
 | 
			
		||||
        )
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @dev Swaps an amount of an asset to another and deposits the new asset amount on behalf of the user without using
 | 
			
		||||
   * a flash loan. 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 and
 | 
			
		||||
   * perform the swap.
 | 
			
		||||
   * @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. If the amount exceeds the balance, the total balance is used 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 permitAmount Amount for the permit signature
 | 
			
		||||
   *   uint256 deadline Deadline for the permit signature
 | 
			
		||||
   *   uint8 v param for the permit signature
 | 
			
		||||
   *   bytes32 r param for the permit signature
 | 
			
		||||
   *   bytes32 s param for the permit signature
 | 
			
		||||
   */
 | 
			
		||||
  function swapAndDeposit(
 | 
			
		||||
    address[] calldata assetToSwapFromList,
 | 
			
		||||
    address[] calldata assetToSwapToList,
 | 
			
		||||
    uint256[] calldata amountToSwapList,
 | 
			
		||||
    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'
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    for (uint256 i = 0; i < assetToSwapFromList.length; i++) {
 | 
			
		||||
      address aToken = _getReserveData(assetToSwapFromList[i]).aTokenAddress;
 | 
			
		||||
 | 
			
		||||
      uint256 aTokenInitiatorBalance = IERC20(aToken).balanceOf(msg.sender);
 | 
			
		||||
      uint256 amountToSwap = amountToSwapList[i] > aTokenInitiatorBalance ? aTokenInitiatorBalance : amountToSwapList[i];
 | 
			
		||||
 | 
			
		||||
      _pullAToken(
 | 
			
		||||
        assetToSwapFromList[i],
 | 
			
		||||
        aToken,
 | 
			
		||||
        msg.sender,
 | 
			
		||||
        amountToSwap,
 | 
			
		||||
        permitParams[i]
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      uint256 receivedAmount = _swapExactTokensForTokens(
 | 
			
		||||
        assetToSwapFromList[i],
 | 
			
		||||
        assetToSwapToList[i],
 | 
			
		||||
        amountToSwap,
 | 
			
		||||
        minAmountsToReceive[i]
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      // Deposit new reserve
 | 
			
		||||
      IERC20(assetToSwapToList[i]).approve(address(POOL), receivedAmount);
 | 
			
		||||
      POOL.deposit(assetToSwapToList[i], receivedAmount, msg.sender, 0);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @dev Swaps an `amountToSwap` of an asset to another and deposits the funds on behalf of the initiator.
 | 
			
		||||
   * @param assetFrom Address of the underlying asset to be swap from
 | 
			
		||||
   * @param assetTo Address of the underlying asset to be swap to and deposited
 | 
			
		||||
   * @param amount Amount from flash loan
 | 
			
		||||
   * @param premium Premium of the flash loan
 | 
			
		||||
   * @param minAmountToReceive Min amount to be received from the swap
 | 
			
		||||
   * @param swapAllBalance Flag indicating if all the user balance should be swapped
 | 
			
		||||
   * @param permitSignature List of struct containing the permit signature
 | 
			
		||||
   */
 | 
			
		||||
  function _swapLiquidity(
 | 
			
		||||
    address assetFrom,
 | 
			
		||||
    address assetTo,
 | 
			
		||||
    uint256 amount,
 | 
			
		||||
    uint256 premium,
 | 
			
		||||
    address initiator,
 | 
			
		||||
    uint256 minAmountToReceive,
 | 
			
		||||
    bool swapAllBalance,
 | 
			
		||||
    PermitSignature memory permitSignature
 | 
			
		||||
  ) internal {
 | 
			
		||||
    address aToken = _getReserveData(assetFrom).aTokenAddress;
 | 
			
		||||
 | 
			
		||||
    uint256 aTokenInitiatorBalance = IERC20(aToken).balanceOf(initiator);
 | 
			
		||||
    uint256 amountToSwap = swapAllBalance && aTokenInitiatorBalance.sub(premium) <= amount
 | 
			
		||||
      ? aTokenInitiatorBalance.sub(premium)
 | 
			
		||||
      : amount;
 | 
			
		||||
 | 
			
		||||
    uint256 receivedAmount = _swapExactTokensForTokens(
 | 
			
		||||
      assetFrom,
 | 
			
		||||
      assetTo,
 | 
			
		||||
      amountToSwap,
 | 
			
		||||
      minAmountToReceive
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // Deposit new reserve
 | 
			
		||||
    IERC20(assetTo).approve(address(POOL), receivedAmount);
 | 
			
		||||
    POOL.deposit(assetTo, receivedAmount, initiator, 0);
 | 
			
		||||
 | 
			
		||||
    uint256 flashLoanDebt = amount.add(premium);
 | 
			
		||||
    uint256 amountToPull = amountToSwap.add(premium);
 | 
			
		||||
 | 
			
		||||
    _pullAToken(assetFrom, aToken, initiator, amountToPull, permitSignature);
 | 
			
		||||
 | 
			
		||||
    // Repay flash loan
 | 
			
		||||
    IERC20(assetFrom).approve(address(POOL), flashLoanDebt);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @dev Decodes the information encoded in the flash loan 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[] minAmountsToReceive List of min amounts to be received from the swap
 | 
			
		||||
   *   bool[] swapAllBalance Flag indicating if all the user balance should be swapped
 | 
			
		||||
   *   uint256[] permitAmount List of amounts for the permit signature
 | 
			
		||||
   *   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
 | 
			
		||||
   *   bytes32[] s List of s param for the permit signature
 | 
			
		||||
   * @return SwapParams struct containing decoded params
 | 
			
		||||
   */
 | 
			
		||||
  function _decodeParams(bytes memory params) internal pure returns (SwapParams memory) {
 | 
			
		||||
    (
 | 
			
		||||
      address[] memory assetToSwapToList,
 | 
			
		||||
      uint256[] memory minAmountsToReceive,
 | 
			
		||||
      bool[] memory swapAllBalance,
 | 
			
		||||
      uint256[] memory permitAmount,
 | 
			
		||||
      uint256[] memory deadline,
 | 
			
		||||
      uint8[] memory v,
 | 
			
		||||
      bytes32[] memory r,
 | 
			
		||||
      bytes32[] memory s
 | 
			
		||||
    ) = abi.decode(params, (address[], uint256[], bool[], uint256[], uint256[], uint8[], bytes32[], bytes32[]));
 | 
			
		||||
 | 
			
		||||
    return SwapParams(
 | 
			
		||||
      assetToSwapToList,
 | 
			
		||||
      minAmountsToReceive,
 | 
			
		||||
      swapAllBalance,
 | 
			
		||||
      PermitParams(
 | 
			
		||||
        permitAmount,
 | 
			
		||||
        deadline,
 | 
			
		||||
        v,
 | 
			
		||||
        r,
 | 
			
		||||
        s
 | 
			
		||||
      )
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										239
									
								
								contracts/adapters/UniswapRepayAdapter.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										239
									
								
								contracts/adapters/UniswapRepayAdapter.sol
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,239 @@
 | 
			
		|||
// 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 {IFlashLoanReceiver} from '../flashloan/interfaces/IFlashLoanReceiver.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, IFlashLoanReceiver {
 | 
			
		||||
 | 
			
		||||
  struct RepayParams {
 | 
			
		||||
    address collateralAsset;
 | 
			
		||||
    uint256 collateralAmount;
 | 
			
		||||
    uint256 rateMode;
 | 
			
		||||
    PermitSignature permitSignature;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  constructor(
 | 
			
		||||
    ILendingPoolAddressesProvider addressesProvider,
 | 
			
		||||
    IUniswapV2Router02 uniswapRouter
 | 
			
		||||
  )
 | 
			
		||||
    public
 | 
			
		||||
    BaseUniswapAdapter(addressesProvider, uniswapRouter)
 | 
			
		||||
  {}
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @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(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
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
    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
 | 
			
		||||
   */
 | 
			
		||||
  function swapAndRepay(
 | 
			
		||||
    address collateralAsset,
 | 
			
		||||
    address debtAsset,
 | 
			
		||||
    uint256 collateralAmount,
 | 
			
		||||
    uint256 debtRepayAmount,
 | 
			
		||||
    uint256 debtRateMode,
 | 
			
		||||
    PermitSignature calldata permitSignature
 | 
			
		||||
  ) 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);
 | 
			
		||||
      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);
 | 
			
		||||
    } else {
 | 
			
		||||
      // Pull aTokens from user
 | 
			
		||||
      _pullAToken(collateralAsset, collateralReserveData.aTokenAddress, msg.sender, amountToRepay, permitSignature);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Repay debt
 | 
			
		||||
    IERC20(debtAsset).approve(address(POOL), amountToRepay);
 | 
			
		||||
    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
 | 
			
		||||
  ) internal {
 | 
			
		||||
    DataTypes.ReserveData memory collateralReserveData = _getReserveData(collateralAsset);
 | 
			
		||||
 | 
			
		||||
    // Repay debt
 | 
			
		||||
    IERC20(debtAsset).approve(address(POOL), amount);
 | 
			
		||||
    uint256 repaidAmount = IERC20(debtAsset).balanceOf(address(this));
 | 
			
		||||
    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);
 | 
			
		||||
      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);
 | 
			
		||||
    } else {
 | 
			
		||||
      // Pull aTokens from user
 | 
			
		||||
      _pullAToken(
 | 
			
		||||
        collateralAsset,
 | 
			
		||||
        collateralReserveData.aTokenAddress,
 | 
			
		||||
        initiator,
 | 
			
		||||
        repaidAmount.add(premium),
 | 
			
		||||
        permitSignature
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Repay flash loan
 | 
			
		||||
    IERC20(debtAsset).approve(address(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
 | 
			
		||||
   * @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
 | 
			
		||||
    ) = abi.decode(params, (address, uint256, uint256, uint256, uint256, uint8, bytes32, bytes32));
 | 
			
		||||
 | 
			
		||||
    return RepayParams(
 | 
			
		||||
      collateralAsset,
 | 
			
		||||
      collateralAmount,
 | 
			
		||||
      rateMode,
 | 
			
		||||
      PermitSignature(
 | 
			
		||||
        permitAmount,
 | 
			
		||||
        deadline,
 | 
			
		||||
        v,
 | 
			
		||||
        r,
 | 
			
		||||
        s
 | 
			
		||||
      )
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										16
									
								
								contracts/interfaces/IERC20WithPermit.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								contracts/interfaces/IERC20WithPermit.sol
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,16 @@
 | 
			
		|||
// SPDX-License-Identifier: agpl-3.0
 | 
			
		||||
pragma solidity 0.6.12;
 | 
			
		||||
 | 
			
		||||
import {IERC20} from '../dependencies/openzeppelin/contracts/IERC20.sol';
 | 
			
		||||
 | 
			
		||||
interface IERC20WithPermit is IERC20 {
 | 
			
		||||
  function permit(
 | 
			
		||||
    address owner,
 | 
			
		||||
    address spender,
 | 
			
		||||
    uint256 value,
 | 
			
		||||
    uint256 deadline,
 | 
			
		||||
    uint8 v,
 | 
			
		||||
    bytes32 r,
 | 
			
		||||
    bytes32 s
 | 
			
		||||
  ) external;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										24
									
								
								contracts/interfaces/IUniswapV2Router02.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								contracts/interfaces/IUniswapV2Router02.sol
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,24 @@
 | 
			
		|||
// SPDX-License-Identifier: agpl-3.0
 | 
			
		||||
pragma solidity 0.6.12;
 | 
			
		||||
 | 
			
		||||
interface IUniswapV2Router02 {
 | 
			
		||||
  function swapExactTokensForTokens(
 | 
			
		||||
    uint256 amountIn,
 | 
			
		||||
    uint256 amountOutMin,
 | 
			
		||||
    address[] calldata path,
 | 
			
		||||
    address to,
 | 
			
		||||
    uint256 deadline
 | 
			
		||||
  ) external returns (uint256[] memory amounts);
 | 
			
		||||
 | 
			
		||||
  function swapTokensForExactTokens(
 | 
			
		||||
    uint amountOut,
 | 
			
		||||
    uint amountInMax,
 | 
			
		||||
    address[] calldata path,
 | 
			
		||||
    address to,
 | 
			
		||||
    uint deadline
 | 
			
		||||
  ) external returns (uint256[] memory amounts);
 | 
			
		||||
 | 
			
		||||
  function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts);
 | 
			
		||||
 | 
			
		||||
  function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										82
									
								
								contracts/mocks/swap/MockUniswapV2Router02.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								contracts/mocks/swap/MockUniswapV2Router02.sol
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,82 @@
 | 
			
		|||
// SPDX-License-Identifier: agpl-3.0
 | 
			
		||||
pragma solidity 0.6.12;
 | 
			
		||||
 | 
			
		||||
import {IUniswapV2Router02} from "../../interfaces/IUniswapV2Router02.sol";
 | 
			
		||||
import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
 | 
			
		||||
import {MintableERC20} from '../tokens/MintableERC20.sol';
 | 
			
		||||
 | 
			
		||||
contract MockUniswapV2Router02 is IUniswapV2Router02 {
 | 
			
		||||
  mapping(address => uint256) internal _amountToReturn;
 | 
			
		||||
  mapping(address => uint256) internal _amountToSwap;
 | 
			
		||||
  mapping(address => mapping(address => mapping(uint256 => uint256))) internal _amountsIn;
 | 
			
		||||
  mapping(address => mapping(address => mapping(uint256 => uint256))) internal _amountsOut;
 | 
			
		||||
  uint256 internal defaultMockValue;
 | 
			
		||||
 | 
			
		||||
  function setAmountToReturn(address reserve, uint256 amount) public {
 | 
			
		||||
    _amountToReturn[reserve] = amount;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function setAmountToSwap(address reserve, uint256 amount) public {
 | 
			
		||||
    _amountToSwap[reserve] = amount;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function swapExactTokensForTokens(
 | 
			
		||||
    uint256 amountIn,
 | 
			
		||||
    uint256 /* amountOutMin */,
 | 
			
		||||
    address[] calldata path,
 | 
			
		||||
    address to,
 | 
			
		||||
    uint256 /* deadline */
 | 
			
		||||
  ) external override returns (uint256[] memory amounts) {
 | 
			
		||||
    IERC20(path[0]).transferFrom(msg.sender, address(this), amountIn);
 | 
			
		||||
 | 
			
		||||
    MintableERC20(path[1]).mint(_amountToReturn[path[0]]);
 | 
			
		||||
    IERC20(path[1]).transfer(to, _amountToReturn[path[0]]);
 | 
			
		||||
 | 
			
		||||
    amounts = new uint[](path.length);
 | 
			
		||||
    amounts[0] = amountIn;
 | 
			
		||||
    amounts[1] = _amountToReturn[path[0]];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function swapTokensForExactTokens(
 | 
			
		||||
    uint amountOut,
 | 
			
		||||
    uint /* amountInMax */,
 | 
			
		||||
    address[] calldata path,
 | 
			
		||||
    address to,
 | 
			
		||||
    uint /* deadline */
 | 
			
		||||
  ) external override returns (uint256[] memory amounts) {
 | 
			
		||||
    IERC20(path[0]).transferFrom(msg.sender, address(this), _amountToSwap[path[0]]);
 | 
			
		||||
 | 
			
		||||
    MintableERC20(path[1]).mint(amountOut);
 | 
			
		||||
    IERC20(path[1]).transfer(to, amountOut);
 | 
			
		||||
 | 
			
		||||
    amounts = new uint[](path.length);
 | 
			
		||||
    amounts[0] = _amountToSwap[path[0]];
 | 
			
		||||
    amounts[1] = amountOut;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function setAmountOut(uint amountIn, address reserveIn, address reserveOut, uint amountOut) public {
 | 
			
		||||
    _amountsOut[reserveIn][reserveOut][amountIn] = amountOut;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function setAmountIn(uint amountOut, address reserveIn, address reserveOut, uint amountIn) public {
 | 
			
		||||
    _amountsIn[reserveIn][reserveOut][amountOut] = amountIn;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function setDefaultMockValue(uint value) public {
 | 
			
		||||
    defaultMockValue = value;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function getAmountsOut(uint amountIn, address[] calldata path) external view override returns (uint[] memory) {
 | 
			
		||||
    uint256[] memory amounts = new uint256[](2);
 | 
			
		||||
    amounts[0] = amountIn;
 | 
			
		||||
    amounts[1] = _amountsOut[path[0]][path[1]][amountIn] > 0 ? _amountsOut[path[0]][path[1]][amountIn] : defaultMockValue;
 | 
			
		||||
    return amounts;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function getAmountsIn(uint amountOut, address[] calldata path) external view override returns (uint[] memory) {
 | 
			
		||||
    uint256[] memory amounts = new uint256[](2);
 | 
			
		||||
    amounts[0] = _amountsIn[path[0]][path[1]][amountOut] > 0 ? _amountsIn[path[0]][path[1]][amountOut] : defaultMockValue;
 | 
			
		||||
    amounts[1] = amountOut;
 | 
			
		||||
    return amounts;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -38,10 +38,13 @@ import {
 | 
			
		|||
  MockFlashLoanReceiverFactory,
 | 
			
		||||
  MockStableDebtTokenFactory,
 | 
			
		||||
  MockVariableDebtTokenFactory,
 | 
			
		||||
  MockUniswapV2Router02Factory,
 | 
			
		||||
  PriceOracleFactory,
 | 
			
		||||
  ReserveLogicFactory,
 | 
			
		||||
  SelfdestructTransferFactory,
 | 
			
		||||
  StableDebtTokenFactory,
 | 
			
		||||
  UniswapLiquiditySwapAdapterFactory,
 | 
			
		||||
  UniswapRepayAdapterFactory,
 | 
			
		||||
  VariableDebtTokenFactory,
 | 
			
		||||
  WalletBalanceProviderFactory,
 | 
			
		||||
  WETH9MockedFactory,
 | 
			
		||||
| 
						 | 
				
			
			@ -493,3 +496,33 @@ export const deploySelfdestructTransferMock = async (verify?: boolean) =>
 | 
			
		|||
    [],
 | 
			
		||||
    verify
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
export const deployMockUniswapRouter = async (verify?: boolean) =>
 | 
			
		||||
  withSaveAndVerify(
 | 
			
		||||
    await new MockUniswapV2Router02Factory(await getFirstSigner()).deploy(),
 | 
			
		||||
    eContractid.MockUniswapV2Router02,
 | 
			
		||||
    [],
 | 
			
		||||
    verify
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
export const deployUniswapLiquiditySwapAdapter = async (
 | 
			
		||||
  args: [tEthereumAddress, tEthereumAddress],
 | 
			
		||||
  verify?: boolean
 | 
			
		||||
) =>
 | 
			
		||||
  withSaveAndVerify(
 | 
			
		||||
    await new UniswapLiquiditySwapAdapterFactory(await getFirstSigner()).deploy(...args),
 | 
			
		||||
    eContractid.UniswapLiquiditySwapAdapter,
 | 
			
		||||
    args,
 | 
			
		||||
    verify
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
export const deployUniswapRepayAdapter = async (
 | 
			
		||||
  args: [tEthereumAddress, tEthereumAddress],
 | 
			
		||||
  verify?: boolean
 | 
			
		||||
) =>
 | 
			
		||||
  withSaveAndVerify(
 | 
			
		||||
    await new UniswapRepayAdapterFactory(await getFirstSigner()).deploy(...args),
 | 
			
		||||
    eContractid.UniswapRepayAdapter,
 | 
			
		||||
    args,
 | 
			
		||||
    verify
 | 
			
		||||
  );
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,11 +17,14 @@ import {
 | 
			
		|||
  MockFlashLoanReceiverFactory,
 | 
			
		||||
  MockStableDebtTokenFactory,
 | 
			
		||||
  MockVariableDebtTokenFactory,
 | 
			
		||||
  MockUniswapV2Router02Factory,
 | 
			
		||||
  PriceOracleFactory,
 | 
			
		||||
  ReserveLogicFactory,
 | 
			
		||||
  SelfdestructTransferFactory,
 | 
			
		||||
  StableAndVariableTokensHelperFactory,
 | 
			
		||||
  StableDebtTokenFactory,
 | 
			
		||||
  UniswapLiquiditySwapAdapterFactory,
 | 
			
		||||
  UniswapRepayAdapterFactory,
 | 
			
		||||
  VariableDebtTokenFactory,
 | 
			
		||||
  WalletBalanceProviderFactory,
 | 
			
		||||
  WETH9MockedFactory,
 | 
			
		||||
| 
						 | 
				
			
			@ -328,3 +331,26 @@ export const getAaveOracle = async (address?: tEthereumAddress) =>
 | 
			
		|||
    address || (await getDb().get(`${eContractid.AaveOracle}.${DRE.network.name}`).value()).address,
 | 
			
		||||
    await getFirstSigner()
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
export const getMockUniswapRouter = async (address?: tEthereumAddress) =>
 | 
			
		||||
  await MockUniswapV2Router02Factory.connect(
 | 
			
		||||
    address ||
 | 
			
		||||
      (await getDb().get(`${eContractid.MockUniswapV2Router02}.${DRE.network.name}`).value())
 | 
			
		||||
        .address,
 | 
			
		||||
    await getFirstSigner()
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
export const getUniswapLiquiditySwapAdapter = async (address?: tEthereumAddress) =>
 | 
			
		||||
  await UniswapLiquiditySwapAdapterFactory.connect(
 | 
			
		||||
    address ||
 | 
			
		||||
      (await getDb().get(`${eContractid.UniswapLiquiditySwapAdapter}.${DRE.network.name}`).value())
 | 
			
		||||
        .address,
 | 
			
		||||
    await getFirstSigner()
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
export const getUniswapRepayAdapter = async (address?: tEthereumAddress) =>
 | 
			
		||||
  await UniswapRepayAdapterFactory.connect(
 | 
			
		||||
    address ||
 | 
			
		||||
      (await getDb().get(`${eContractid.UniswapRepayAdapter}.${DRE.network.name}`).value()).address,
 | 
			
		||||
    await getFirstSigner()
 | 
			
		||||
  );
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,4 @@
 | 
			
		|||
import { Contract, Signer, utils, ethers } from 'ethers';
 | 
			
		||||
import { Contract, Signer, utils, ethers , BigNumberish} from 'ethers';
 | 
			
		||||
import { signTypedData_v4 } from 'eth-sig-util';
 | 
			
		||||
import { fromRpcSig, ECDSASignature } from 'ethereumjs-util';
 | 
			
		||||
import BigNumber from 'bignumber.js';
 | 
			
		||||
| 
						 | 
				
			
			@ -232,3 +232,53 @@ export const getSignatureFromTypedData = (
 | 
			
		|||
  });
 | 
			
		||||
  return fromRpcSig(signature);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const buildLiquiditySwapParams = (
 | 
			
		||||
  assetToSwapToList: tEthereumAddress[],
 | 
			
		||||
  minAmountsToReceive: BigNumberish[],
 | 
			
		||||
  swapAllBalances: BigNumberish[],
 | 
			
		||||
  permitAmounts: BigNumberish[],
 | 
			
		||||
  deadlines: BigNumberish[],
 | 
			
		||||
  v: BigNumberish[],
 | 
			
		||||
  r: (string | Buffer)[],
 | 
			
		||||
  s: (string | Buffer)[]
 | 
			
		||||
) => {
 | 
			
		||||
  return ethers.utils.defaultAbiCoder.encode(
 | 
			
		||||
    [
 | 
			
		||||
      'address[]',
 | 
			
		||||
      'uint256[]',
 | 
			
		||||
      'bool[]',
 | 
			
		||||
      'uint256[]',
 | 
			
		||||
      'uint256[]',
 | 
			
		||||
      'uint8[]',
 | 
			
		||||
      'bytes32[]',
 | 
			
		||||
      'bytes32[]',
 | 
			
		||||
    ],
 | 
			
		||||
    [assetToSwapToList, minAmountsToReceive, swapAllBalances, permitAmounts, deadlines, v, r, s]
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const buildRepayAdapterParams = (
 | 
			
		||||
  collateralAsset: tEthereumAddress,
 | 
			
		||||
  collateralAmount: BigNumberish,
 | 
			
		||||
  rateMode: BigNumberish,
 | 
			
		||||
  permitAmount: BigNumberish,
 | 
			
		||||
  deadline: BigNumberish,
 | 
			
		||||
  v: BigNumberish,
 | 
			
		||||
  r: string | Buffer,
 | 
			
		||||
  s: string | Buffer
 | 
			
		||||
) => {
 | 
			
		||||
  return ethers.utils.defaultAbiCoder.encode(
 | 
			
		||||
    [
 | 
			
		||||
      'address',
 | 
			
		||||
      'uint256',
 | 
			
		||||
      'uint256',
 | 
			
		||||
      'uint256',
 | 
			
		||||
      'uint256',
 | 
			
		||||
      'uint8',
 | 
			
		||||
      'bytes32',
 | 
			
		||||
      'bytes32',
 | 
			
		||||
    ],
 | 
			
		||||
    [collateralAsset, collateralAmount, rateMode, permitAmount, deadline, v, r, s]
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -67,6 +67,9 @@ export enum eContractid {
 | 
			
		|||
  LendingPoolImpl = 'LendingPoolImpl',
 | 
			
		||||
  LendingPoolConfiguratorImpl = 'LendingPoolConfiguratorImpl',
 | 
			
		||||
  LendingPoolCollateralManagerImpl = 'LendingPoolCollateralManagerImpl',
 | 
			
		||||
  MockUniswapV2Router02 = 'MockUniswapV2Router02',
 | 
			
		||||
  UniswapLiquiditySwapAdapter = 'UniswapLiquiditySwapAdapter',
 | 
			
		||||
  UniswapRepayAdapter = 'UniswapRepayAdapter',
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,6 +22,9 @@ import {
 | 
			
		|||
  deployATokensAndRatesHelper,
 | 
			
		||||
  deployWETHGateway,
 | 
			
		||||
  deployWETHMocked,
 | 
			
		||||
  deployMockUniswapRouter,
 | 
			
		||||
  deployUniswapLiquiditySwapAdapter,
 | 
			
		||||
  deployUniswapRepayAdapter,
 | 
			
		||||
} from '../helpers/contracts-deployments';
 | 
			
		||||
import { Signer } from 'ethers';
 | 
			
		||||
import { TokenContractId, eContractid, tEthereumAddress, AavePools } from '../helpers/types';
 | 
			
		||||
| 
						 | 
				
			
			@ -229,6 +232,24 @@ const buildTestEnv = async (deployer: Signer, secondaryWallet: Signer) => {
 | 
			
		|||
  const mockFlashLoanReceiver = await deployMockFlashLoanReceiver(addressesProvider.address);
 | 
			
		||||
  await insertContractAddressInDb(eContractid.MockFlashLoanReceiver, mockFlashLoanReceiver.address);
 | 
			
		||||
 | 
			
		||||
  const mockUniswapRouter = await deployMockUniswapRouter();
 | 
			
		||||
  await insertContractAddressInDb(eContractid.MockUniswapV2Router02, mockUniswapRouter.address);
 | 
			
		||||
 | 
			
		||||
  const UniswapLiquiditySwapAdapter = await deployUniswapLiquiditySwapAdapter([
 | 
			
		||||
    addressesProvider.address,
 | 
			
		||||
    mockUniswapRouter.address,
 | 
			
		||||
  ]);
 | 
			
		||||
  await insertContractAddressInDb(
 | 
			
		||||
    eContractid.UniswapLiquiditySwapAdapter,
 | 
			
		||||
    UniswapLiquiditySwapAdapter.address
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  const UniswapRepayAdapter = await deployUniswapRepayAdapter([
 | 
			
		||||
    addressesProvider.address,
 | 
			
		||||
    mockUniswapRouter.address,
 | 
			
		||||
  ]);
 | 
			
		||||
  await insertContractAddressInDb(eContractid.UniswapRepayAdapter, UniswapRepayAdapter.address);
 | 
			
		||||
 | 
			
		||||
  await deployWalletBalancerProvider();
 | 
			
		||||
 | 
			
		||||
  await deployWETHGateway([mockTokens.WETH.address, lendingPoolAddress]);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,6 +11,8 @@ import {
 | 
			
		|||
  getLendingPoolAddressesProviderRegistry,
 | 
			
		||||
  getWETHMocked,
 | 
			
		||||
  getWETHGateway,
 | 
			
		||||
  getUniswapLiquiditySwapAdapter,
 | 
			
		||||
  getUniswapRepayAdapter,
 | 
			
		||||
} from '../../helpers/contracts-getters';
 | 
			
		||||
import { tEthereumAddress } from '../../helpers/types';
 | 
			
		||||
import { LendingPool } from '../../types/LendingPool';
 | 
			
		||||
| 
						 | 
				
			
			@ -27,6 +29,8 @@ import { PriceOracle } from '../../types/PriceOracle';
 | 
			
		|||
import { LendingPoolAddressesProvider } from '../../types/LendingPoolAddressesProvider';
 | 
			
		||||
import { LendingPoolAddressesProviderRegistry } from '../../types/LendingPoolAddressesProviderRegistry';
 | 
			
		||||
import { getEthersSigners } from '../../helpers/contracts-helpers';
 | 
			
		||||
import { UniswapLiquiditySwapAdapter } from '../../types/UniswapLiquiditySwapAdapter';
 | 
			
		||||
import { UniswapRepayAdapter } from '../../types/UniswapRepayAdapter';
 | 
			
		||||
import { WETH9Mocked } from '../../types/WETH9Mocked';
 | 
			
		||||
import { WETHGateway } from '../../types/WETHGateway';
 | 
			
		||||
import { solidity } from 'ethereum-waffle';
 | 
			
		||||
| 
						 | 
				
			
			@ -53,6 +57,8 @@ export interface TestEnv {
 | 
			
		|||
  usdc: MintableERC20;
 | 
			
		||||
  aave: MintableERC20;
 | 
			
		||||
  addressesProvider: LendingPoolAddressesProvider;
 | 
			
		||||
  uniswapLiquiditySwapAdapter: UniswapLiquiditySwapAdapter;
 | 
			
		||||
  uniswapRepayAdapter: UniswapRepayAdapter;
 | 
			
		||||
  registry: LendingPoolAddressesProviderRegistry;
 | 
			
		||||
  wethGateway: WETHGateway;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -78,6 +84,8 @@ const testEnv: TestEnv = {
 | 
			
		|||
  usdc: {} as MintableERC20,
 | 
			
		||||
  aave: {} as MintableERC20,
 | 
			
		||||
  addressesProvider: {} as LendingPoolAddressesProvider,
 | 
			
		||||
  uniswapLiquiditySwapAdapter: {} as UniswapLiquiditySwapAdapter,
 | 
			
		||||
  uniswapRepayAdapter: {} as UniswapRepayAdapter,
 | 
			
		||||
  registry: {} as LendingPoolAddressesProviderRegistry,
 | 
			
		||||
  wethGateway: {} as WETHGateway,
 | 
			
		||||
} as TestEnv;
 | 
			
		||||
| 
						 | 
				
			
			@ -133,6 +141,9 @@ export async function initializeMakeSuite() {
 | 
			
		|||
  testEnv.aave = await getMintableERC20(aaveAddress);
 | 
			
		||||
  testEnv.weth = await getWETHMocked(wethAddress);
 | 
			
		||||
  testEnv.wethGateway = await getWETHGateway();
 | 
			
		||||
 | 
			
		||||
  testEnv.uniswapLiquiditySwapAdapter = await getUniswapLiquiditySwapAdapter();
 | 
			
		||||
  testEnv.uniswapRepayAdapter = await getUniswapRepayAdapter();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function makeSuite(name: string, tests: (testEnv: TestEnv) => void) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										3334
									
								
								test/uniswapAdapters.spec.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3334
									
								
								test/uniswapAdapters.spec.ts
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
		Loading…
	
		Reference in New Issue
	
	Block a user