mirror of
				https://github.com/Instadapp/aave-protocol-v2.git
				synced 2024-07-29 21:47:30 +00:00 
			
		
		
		
	Remove swapLiquidity/repayWithCollateral
This commit is contained in:
		
							parent
							
								
									7ddf18b823
								
							
						
					
					
						commit
						b7efa920ca
					
				| 
						 | 
				
			
			@ -259,27 +259,6 @@ interface ILendingPool {
 | 
			
		|||
    bool receiveAToken
 | 
			
		||||
  ) external;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @dev flashes the underlying collateral on an user to swap for the owed asset and repay
 | 
			
		||||
   * - Both the owner of the position and other liquidators can execute it
 | 
			
		||||
   * - The owner can repay with his collateral at any point, no matter the health factor
 | 
			
		||||
   * - Other liquidators can only use this function below 1 HF. To liquidate 50% of the debt > HF 0.98 or the whole below
 | 
			
		||||
   * @param collateral The address of the collateral asset
 | 
			
		||||
   * @param principal The address of the owed asset
 | 
			
		||||
   * @param user Address of the borrower
 | 
			
		||||
   * @param principalAmount Amount of the debt to repay. type(uint256).max to repay the maximum possible
 | 
			
		||||
   * @param receiver Address of the contract receiving the collateral to swap
 | 
			
		||||
   * @param params Variadic bytes param to pass with extra information to the receiver
 | 
			
		||||
   **/
 | 
			
		||||
  function repayWithCollateral(
 | 
			
		||||
    address collateral,
 | 
			
		||||
    address principal,
 | 
			
		||||
    address user,
 | 
			
		||||
    uint256 principalAmount,
 | 
			
		||||
    address receiver,
 | 
			
		||||
    bytes calldata params
 | 
			
		||||
  ) external;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @dev allows smartcontracts to access the liquidity of the pool within one transaction,
 | 
			
		||||
   * as long as the amount taken plus a fee is returned. NOTE There are security concerns for developers of flashloan receiver contracts
 | 
			
		||||
| 
						 | 
				
			
			@ -299,22 +278,6 @@ interface ILendingPool {
 | 
			
		|||
    uint16 referralCode
 | 
			
		||||
  ) external;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @dev Allows an user to release one of his assets deposited in the protocol, even if it is used as collateral, to swap for another.
 | 
			
		||||
   * - It's not possible to release one asset to swap for the same
 | 
			
		||||
   * @param receiverAddress The address of the contract receiving the funds. The receiver should implement the ISwapAdapter interface
 | 
			
		||||
   * @param fromAsset Asset to swap from
 | 
			
		||||
   * @param toAsset Asset to swap to
 | 
			
		||||
   * @param params a bytes array to be sent (if needed) to the receiver contract with extra data
 | 
			
		||||
   **/
 | 
			
		||||
  function swapLiquidity(
 | 
			
		||||
    address receiverAddress,
 | 
			
		||||
    address fromAsset,
 | 
			
		||||
    address toAsset,
 | 
			
		||||
    uint256 amountToSwap,
 | 
			
		||||
    bytes calldata params
 | 
			
		||||
  ) external;
 | 
			
		||||
 | 
			
		||||
  function getUserAccountData(address user)
 | 
			
		||||
    external
 | 
			
		||||
    view
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -482,55 +482,6 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
 | 
			
		|||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @dev flashes the underlying collateral on an user to swap for the owed asset and repay
 | 
			
		||||
   * - Both the owner of the position and other liquidators can execute it
 | 
			
		||||
   * - The owner can repay with his collateral at any point, no matter the health factor
 | 
			
		||||
   * - Other liquidators can only use this function below 1 HF. To liquidate 50% of the debt > HF 0.98 or the whole below
 | 
			
		||||
   * @param collateral The address of the collateral asset
 | 
			
		||||
   * @param principal The address of the owed asset
 | 
			
		||||
   * @param user Address of the borrower
 | 
			
		||||
   * @param principalAmount Amount of the debt to repay. type(uint256).max to repay the maximum possible
 | 
			
		||||
   * @param receiver Address of the contract receiving the collateral to swap
 | 
			
		||||
   * @param params Variadic bytes param to pass with extra information to the receiver
 | 
			
		||||
   **/
 | 
			
		||||
  function repayWithCollateral(
 | 
			
		||||
    address collateral,
 | 
			
		||||
    address principal,
 | 
			
		||||
    address user,
 | 
			
		||||
    uint256 principalAmount,
 | 
			
		||||
    address receiver,
 | 
			
		||||
    bytes calldata params
 | 
			
		||||
  ) external override {
 | 
			
		||||
    _whenNotPaused();
 | 
			
		||||
    require(!_flashLiquidationLocked, Errors.REENTRANCY_NOT_ALLOWED);
 | 
			
		||||
    _flashLiquidationLocked = true;
 | 
			
		||||
 | 
			
		||||
    address collateralManager = _addressesProvider.getLendingPoolCollateralManager();
 | 
			
		||||
 | 
			
		||||
    //solium-disable-next-line
 | 
			
		||||
    (bool success, bytes memory result) = collateralManager.delegatecall(
 | 
			
		||||
      abi.encodeWithSignature(
 | 
			
		||||
        'repayWithCollateral(address,address,address,uint256,address,bytes)',
 | 
			
		||||
        collateral,
 | 
			
		||||
        principal,
 | 
			
		||||
        user,
 | 
			
		||||
        principalAmount,
 | 
			
		||||
        receiver,
 | 
			
		||||
        params
 | 
			
		||||
      )
 | 
			
		||||
    );
 | 
			
		||||
    require(success, Errors.FAILED_REPAY_WITH_COLLATERAL);
 | 
			
		||||
 | 
			
		||||
    (uint256 returnCode, string memory returnMessage) = abi.decode(result, (uint256, string));
 | 
			
		||||
 | 
			
		||||
    if (returnCode != 0) {
 | 
			
		||||
      revert(string(abi.encodePacked(returnMessage)));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _flashLiquidationLocked = false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  struct FlashLoanLocalVars {
 | 
			
		||||
    uint256 premium;
 | 
			
		||||
    uint256 amountPlusPremium;
 | 
			
		||||
| 
						 | 
				
			
			@ -609,44 +560,6 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
 | 
			
		|||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @dev Allows an user to release one of his assets deposited in the protocol, even if it is used as collateral, to swap for another.
 | 
			
		||||
   * - It's not possible to release one asset to swap for the same
 | 
			
		||||
   * @param receiverAddress The address of the contract receiving the funds. The receiver should implement the ISwapAdapter interface
 | 
			
		||||
   * @param fromAsset Asset to swap from
 | 
			
		||||
   * @param toAsset Asset to swap to
 | 
			
		||||
   * @param params a bytes array to be sent (if needed) to the receiver contract with extra data
 | 
			
		||||
   **/
 | 
			
		||||
  function swapLiquidity(
 | 
			
		||||
    address receiverAddress,
 | 
			
		||||
    address fromAsset,
 | 
			
		||||
    address toAsset,
 | 
			
		||||
    uint256 amountToSwap,
 | 
			
		||||
    bytes calldata params
 | 
			
		||||
  ) external override {
 | 
			
		||||
    _whenNotPaused();
 | 
			
		||||
    address collateralManager = _addressesProvider.getLendingPoolCollateralManager();
 | 
			
		||||
 | 
			
		||||
    //solium-disable-next-line
 | 
			
		||||
    (bool success, bytes memory result) = collateralManager.delegatecall(
 | 
			
		||||
      abi.encodeWithSignature(
 | 
			
		||||
        'swapLiquidity(address,address,address,uint256,bytes)',
 | 
			
		||||
        receiverAddress,
 | 
			
		||||
        fromAsset,
 | 
			
		||||
        toAsset,
 | 
			
		||||
        amountToSwap,
 | 
			
		||||
        params
 | 
			
		||||
      )
 | 
			
		||||
    );
 | 
			
		||||
    require(success, Errors.FAILED_COLLATERAL_SWAP);
 | 
			
		||||
 | 
			
		||||
    (uint256 returnCode, string memory returnMessage) = abi.decode(result, (uint256, string));
 | 
			
		||||
 | 
			
		||||
    if (returnCode != 0) {
 | 
			
		||||
      revert(string(abi.encodePacked(returnMessage)));
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @dev returns the state and configuration of the reserve
 | 
			
		||||
   * @param asset the address of the reserve
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -58,24 +58,6 @@ contract LendingPoolCollateralManager is VersionedInitializable, LendingPoolStor
 | 
			
		|||
    bool receiveAToken
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
    @dev emitted when a borrower/liquidator repays with the borrower's collateral
 | 
			
		||||
    @param collateral the address of the collateral being swapped to repay
 | 
			
		||||
    @param principal the address of the reserve of the debt
 | 
			
		||||
    @param user the borrower's address
 | 
			
		||||
    @param liquidator the address of the liquidator, same as the one of the borrower on self-repayment
 | 
			
		||||
    @param principalAmount the amount of the debt finally covered
 | 
			
		||||
    @param swappedCollateralAmount the amount of collateral finally swapped
 | 
			
		||||
  */
 | 
			
		||||
  event RepaidWithCollateral(
 | 
			
		||||
    address indexed collateral,
 | 
			
		||||
    address indexed principal,
 | 
			
		||||
    address indexed user,
 | 
			
		||||
    address liquidator,
 | 
			
		||||
    uint256 principalAmount,
 | 
			
		||||
    uint256 swappedCollateralAmount
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  struct LiquidationCallLocalVars {
 | 
			
		||||
    uint256 userCollateralBalance;
 | 
			
		||||
    uint256 userStableDebt;
 | 
			
		||||
| 
						 | 
				
			
			@ -96,16 +78,6 @@ contract LendingPoolCollateralManager is VersionedInitializable, LendingPoolStor
 | 
			
		|||
    string errorMsg;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  struct SwapLiquidityLocalVars {
 | 
			
		||||
    uint256 healthFactor;
 | 
			
		||||
    uint256 amountToReceive;
 | 
			
		||||
    uint256 userBalanceBefore;
 | 
			
		||||
    IAToken fromReserveAToken;
 | 
			
		||||
    IAToken toReserveAToken;
 | 
			
		||||
    uint256 errorCode;
 | 
			
		||||
    string errorMsg;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  struct AvailableCollateralToLiquidateLocalVars {
 | 
			
		||||
    uint256 userCompoundedBorrowBalance;
 | 
			
		||||
    uint256 liquidationBonus;
 | 
			
		||||
| 
						 | 
				
			
			@ -189,7 +161,7 @@ contract LendingPoolCollateralManager is VersionedInitializable, LendingPoolStor
 | 
			
		|||
    (
 | 
			
		||||
      vars.maxCollateralToLiquidate,
 | 
			
		||||
      vars.principalAmountNeeded
 | 
			
		||||
    ) = calculateAvailableCollateralToLiquidate(
 | 
			
		||||
    ) = _calculateAvailableCollateralToLiquidate(
 | 
			
		||||
      collateralReserve,
 | 
			
		||||
      principalReserve,
 | 
			
		||||
      collateral,
 | 
			
		||||
| 
						 | 
				
			
			@ -295,259 +267,6 @@ contract LendingPoolCollateralManager is VersionedInitializable, LendingPoolStor
 | 
			
		|||
    return (uint256(Errors.CollateralManagerErrors.NO_ERROR), Errors.NO_ERRORS);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @dev flashes the underlying collateral on an user to swap for the owed asset and repay
 | 
			
		||||
   * - Both the owner of the position and other liquidators can execute it.
 | 
			
		||||
   * - The owner can repay with his collateral at any point, no matter the health factor.
 | 
			
		||||
   * - Other liquidators can only use this function below 1 HF. To liquidate 50% of the debt > HF 0.98 or the whole below.
 | 
			
		||||
   * @param collateral The address of the collateral asset.
 | 
			
		||||
   * @param principal The address of the owed asset.
 | 
			
		||||
   * @param user Address of the borrower.
 | 
			
		||||
   * @param principalAmount Amount of the debt to repay.
 | 
			
		||||
   * @param receiver Address of the contract receiving the collateral to swap.
 | 
			
		||||
   * @param params Variadic bytes param to pass with extra information to the receiver
 | 
			
		||||
   **/
 | 
			
		||||
  function repayWithCollateral(
 | 
			
		||||
    address collateral,
 | 
			
		||||
    address principal,
 | 
			
		||||
    address user,
 | 
			
		||||
    uint256 principalAmount,
 | 
			
		||||
    address receiver,
 | 
			
		||||
    bytes calldata params
 | 
			
		||||
  ) external returns (uint256, string memory) {
 | 
			
		||||
    ReserveLogic.ReserveData storage collateralReserve = _reserves[collateral];
 | 
			
		||||
    ReserveLogic.ReserveData storage debtReserve = _reserves[principal];
 | 
			
		||||
    UserConfiguration.Map storage userConfig = _usersConfig[user];
 | 
			
		||||
 | 
			
		||||
    LiquidationCallLocalVars memory vars;
 | 
			
		||||
 | 
			
		||||
    (, , , , vars.healthFactor) = GenericLogic.calculateUserAccountData(
 | 
			
		||||
      user,
 | 
			
		||||
      _reserves,
 | 
			
		||||
      _usersConfig[user],
 | 
			
		||||
      _reservesList,
 | 
			
		||||
      _reservesCount,
 | 
			
		||||
      _addressesProvider.getPriceOracle()
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    (vars.userStableDebt, vars.userVariableDebt) = Helpers.getUserCurrentDebt(user, debtReserve);
 | 
			
		||||
 | 
			
		||||
    (vars.errorCode, vars.errorMsg) = ValidationLogic.validateRepayWithCollateral(
 | 
			
		||||
      collateralReserve,
 | 
			
		||||
      debtReserve,
 | 
			
		||||
      userConfig,
 | 
			
		||||
      user,
 | 
			
		||||
      vars.healthFactor,
 | 
			
		||||
      vars.userStableDebt,
 | 
			
		||||
      vars.userVariableDebt
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    if (Errors.CollateralManagerErrors(vars.errorCode) != Errors.CollateralManagerErrors.NO_ERROR) {
 | 
			
		||||
      return (vars.errorCode, vars.errorMsg);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vars.maxPrincipalAmountToLiquidate = vars.userStableDebt.add(vars.userVariableDebt);
 | 
			
		||||
 | 
			
		||||
    vars.actualAmountToLiquidate = principalAmount > vars.maxPrincipalAmountToLiquidate
 | 
			
		||||
      ? vars.maxPrincipalAmountToLiquidate
 | 
			
		||||
      : principalAmount;
 | 
			
		||||
 | 
			
		||||
    vars.collateralAtoken = IAToken(collateralReserve.aTokenAddress);
 | 
			
		||||
    vars.userCollateralBalance = vars.collateralAtoken.balanceOf(user);
 | 
			
		||||
 | 
			
		||||
    (
 | 
			
		||||
      vars.maxCollateralToLiquidate,
 | 
			
		||||
      vars.principalAmountNeeded
 | 
			
		||||
    ) = calculateAvailableCollateralToLiquidate(
 | 
			
		||||
      collateralReserve,
 | 
			
		||||
      debtReserve,
 | 
			
		||||
      collateral,
 | 
			
		||||
      principal,
 | 
			
		||||
      vars.actualAmountToLiquidate,
 | 
			
		||||
      vars.userCollateralBalance
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    //if principalAmountNeeded < vars.ActualAmountToLiquidate, there isn't enough
 | 
			
		||||
    //of collateral to cover the actual amount that is being liquidated, hence we liquidate
 | 
			
		||||
    //a smaller amount
 | 
			
		||||
    if (vars.principalAmountNeeded < vars.actualAmountToLiquidate) {
 | 
			
		||||
      vars.actualAmountToLiquidate = vars.principalAmountNeeded;
 | 
			
		||||
    }
 | 
			
		||||
    //updating collateral reserve indexes
 | 
			
		||||
    collateralReserve.updateState();
 | 
			
		||||
 | 
			
		||||
    //updating collateral reserve interest rates
 | 
			
		||||
    collateralReserve.updateInterestRates(
 | 
			
		||||
      collateral,
 | 
			
		||||
      address(vars.collateralAtoken),
 | 
			
		||||
      0,
 | 
			
		||||
      vars.maxCollateralToLiquidate
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    vars.collateralAtoken.burn(
 | 
			
		||||
      user,
 | 
			
		||||
      receiver,
 | 
			
		||||
      vars.maxCollateralToLiquidate,
 | 
			
		||||
      collateralReserve.liquidityIndex
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    if (vars.userCollateralBalance == vars.maxCollateralToLiquidate) {
 | 
			
		||||
      _usersConfig[user].setUsingAsCollateral(collateralReserve.id, false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vars.principalAToken = debtReserve.aTokenAddress;
 | 
			
		||||
 | 
			
		||||
    // Notifies the receiver to proceed, sending as param the underlying already transferred
 | 
			
		||||
    ISwapAdapter(receiver).executeOperation(
 | 
			
		||||
      collateral,
 | 
			
		||||
      principal,
 | 
			
		||||
      vars.maxCollateralToLiquidate,
 | 
			
		||||
      address(this),
 | 
			
		||||
      params
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    //updating debt reserve
 | 
			
		||||
    debtReserve.updateState();
 | 
			
		||||
    debtReserve.updateInterestRates(
 | 
			
		||||
      principal,
 | 
			
		||||
      vars.principalAToken,
 | 
			
		||||
      vars.actualAmountToLiquidate,
 | 
			
		||||
      0
 | 
			
		||||
    );
 | 
			
		||||
    IERC20(principal).safeTransferFrom(
 | 
			
		||||
      receiver,
 | 
			
		||||
      vars.principalAToken,
 | 
			
		||||
      vars.actualAmountToLiquidate
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    if (vars.userVariableDebt >= vars.actualAmountToLiquidate) {
 | 
			
		||||
      IVariableDebtToken(debtReserve.variableDebtTokenAddress).burn(
 | 
			
		||||
        user,
 | 
			
		||||
        vars.actualAmountToLiquidate,
 | 
			
		||||
        debtReserve.variableBorrowIndex
 | 
			
		||||
      );
 | 
			
		||||
    } else {
 | 
			
		||||
      IVariableDebtToken(debtReserve.variableDebtTokenAddress).burn(
 | 
			
		||||
        user,
 | 
			
		||||
        vars.userVariableDebt,
 | 
			
		||||
        debtReserve.variableBorrowIndex
 | 
			
		||||
      );
 | 
			
		||||
      IStableDebtToken(debtReserve.stableDebtTokenAddress).burn(
 | 
			
		||||
        user,
 | 
			
		||||
        vars.actualAmountToLiquidate.sub(vars.userVariableDebt)
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    emit RepaidWithCollateral(
 | 
			
		||||
      collateral,
 | 
			
		||||
      principal,
 | 
			
		||||
      user,
 | 
			
		||||
      msg.sender,
 | 
			
		||||
      vars.actualAmountToLiquidate,
 | 
			
		||||
      vars.maxCollateralToLiquidate
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    return (uint256(Errors.CollateralManagerErrors.NO_ERROR), Errors.NO_ERRORS);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @dev Allows an user to release one of his assets deposited in the protocol, even if it is used as collateral, to swap for another.
 | 
			
		||||
   * - It's not possible to release one asset to swap for the same
 | 
			
		||||
   * @param receiverAddress The address of the contract receiving the funds. The receiver should implement the ISwapAdapter interface
 | 
			
		||||
   * @param fromAsset Asset to swap from
 | 
			
		||||
   * @param toAsset Asset to swap to
 | 
			
		||||
   * @param params a bytes array to be sent (if needed) to the receiver contract with extra data
 | 
			
		||||
   **/
 | 
			
		||||
  function swapLiquidity(
 | 
			
		||||
    address receiverAddress,
 | 
			
		||||
    address fromAsset,
 | 
			
		||||
    address toAsset,
 | 
			
		||||
    uint256 amountToSwap,
 | 
			
		||||
    bytes calldata params
 | 
			
		||||
  ) external returns (uint256, string memory) {
 | 
			
		||||
    ReserveLogic.ReserveData storage fromReserve = _reserves[fromAsset];
 | 
			
		||||
    ReserveLogic.ReserveData storage toReserve = _reserves[toAsset];
 | 
			
		||||
 | 
			
		||||
    SwapLiquidityLocalVars memory vars;
 | 
			
		||||
 | 
			
		||||
    (vars.errorCode, vars.errorMsg) = ValidationLogic.validateSwapLiquidity(
 | 
			
		||||
      fromReserve,
 | 
			
		||||
      toReserve,
 | 
			
		||||
      fromAsset,
 | 
			
		||||
      toAsset
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    if (Errors.CollateralManagerErrors(vars.errorCode) != Errors.CollateralManagerErrors.NO_ERROR) {
 | 
			
		||||
      return (vars.errorCode, vars.errorMsg);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vars.fromReserveAToken = IAToken(fromReserve.aTokenAddress);
 | 
			
		||||
    vars.toReserveAToken = IAToken(toReserve.aTokenAddress);
 | 
			
		||||
 | 
			
		||||
    fromReserve.updateState();
 | 
			
		||||
    toReserve.updateState();
 | 
			
		||||
 | 
			
		||||
    if (vars.fromReserveAToken.balanceOf(msg.sender) == amountToSwap) {
 | 
			
		||||
      _usersConfig[msg.sender].setUsingAsCollateral(fromReserve.id, false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fromReserve.updateInterestRates(fromAsset, address(vars.fromReserveAToken), 0, amountToSwap);
 | 
			
		||||
 | 
			
		||||
    vars.fromReserveAToken.burn(
 | 
			
		||||
      msg.sender,
 | 
			
		||||
      receiverAddress,
 | 
			
		||||
      amountToSwap,
 | 
			
		||||
      fromReserve.liquidityIndex
 | 
			
		||||
    );
 | 
			
		||||
    // Notifies the receiver to proceed, sending as param the underlying already transferred
 | 
			
		||||
    ISwapAdapter(receiverAddress).executeOperation(
 | 
			
		||||
      fromAsset,
 | 
			
		||||
      toAsset,
 | 
			
		||||
      amountToSwap,
 | 
			
		||||
      address(this),
 | 
			
		||||
      params
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    vars.amountToReceive = IERC20(toAsset).balanceOf(receiverAddress);
 | 
			
		||||
    if (vars.amountToReceive != 0) {
 | 
			
		||||
      IERC20(toAsset).safeTransferFrom(
 | 
			
		||||
        receiverAddress,
 | 
			
		||||
        address(vars.toReserveAToken),
 | 
			
		||||
        vars.amountToReceive
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      if (vars.toReserveAToken.balanceOf(msg.sender) == 0) {
 | 
			
		||||
        _usersConfig[msg.sender].setUsingAsCollateral(toReserve.id, true);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      vars.toReserveAToken.mint(msg.sender, vars.amountToReceive, toReserve.liquidityIndex);
 | 
			
		||||
      toReserve.updateInterestRates(
 | 
			
		||||
        toAsset,
 | 
			
		||||
        address(vars.toReserveAToken),
 | 
			
		||||
        vars.amountToReceive,
 | 
			
		||||
        0
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    (, , , , vars.healthFactor) = GenericLogic.calculateUserAccountData(
 | 
			
		||||
      msg.sender,
 | 
			
		||||
      _reserves,
 | 
			
		||||
      _usersConfig[msg.sender],
 | 
			
		||||
      _reservesList,
 | 
			
		||||
      _reservesCount,
 | 
			
		||||
      _addressesProvider.getPriceOracle()
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    if (vars.healthFactor < GenericLogic.HEALTH_FACTOR_LIQUIDATION_THRESHOLD) {
 | 
			
		||||
      return (
 | 
			
		||||
        uint256(Errors.CollateralManagerErrors.HEALTH_FACTOR_LOWER_THAN_LIQUIDATION_THRESHOLD),
 | 
			
		||||
        Errors.HEALTH_FACTOR_LOWER_THAN_LIQUIDATION_THRESHOLD
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return (uint256(Errors.CollateralManagerErrors.NO_ERROR), Errors.NO_ERRORS);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @dev calculates how much of a specific collateral can be liquidated, given
 | 
			
		||||
   * a certain amount of principal currency. This function needs to be called after
 | 
			
		||||
| 
						 | 
				
			
			@ -559,7 +278,7 @@ contract LendingPoolCollateralManager is VersionedInitializable, LendingPoolStor
 | 
			
		|||
   * @return collateralAmount the maximum amount that is possible to liquidated given all the liquidation constraints (user balance, close factor)
 | 
			
		||||
   * @return principalAmountNeeded the purchase amount
 | 
			
		||||
   **/
 | 
			
		||||
  function calculateAvailableCollateralToLiquidate(
 | 
			
		||||
  function _calculateAvailableCollateralToLiquidate(
 | 
			
		||||
    ReserveLogic.ReserveData storage collateralReserve,
 | 
			
		||||
    ReserveLogic.ReserveData storage principalReserve,
 | 
			
		||||
    address collateralAddress,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -384,95 +384,4 @@ library ValidationLogic {
 | 
			
		|||
 | 
			
		||||
    return (uint256(Errors.CollateralManagerErrors.NO_ERROR), Errors.NO_ERRORS);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @dev Validates the repayWithCollateral() action
 | 
			
		||||
   * @param collateralReserve The reserve data of the collateral
 | 
			
		||||
   * @param principalReserve The reserve data of the principal
 | 
			
		||||
   * @param userConfig The user configuration
 | 
			
		||||
   * @param user The address of the user
 | 
			
		||||
   * @param userHealthFactor The user's health factor
 | 
			
		||||
   * @param userStableDebt Total stable debt balance of the user
 | 
			
		||||
   * @param userVariableDebt Total variable debt balance of the user
 | 
			
		||||
   **/
 | 
			
		||||
  function validateRepayWithCollateral(
 | 
			
		||||
    ReserveLogic.ReserveData storage collateralReserve,
 | 
			
		||||
    ReserveLogic.ReserveData storage principalReserve,
 | 
			
		||||
    UserConfiguration.Map storage userConfig,
 | 
			
		||||
    address user,
 | 
			
		||||
    uint256 userHealthFactor,
 | 
			
		||||
    uint256 userStableDebt,
 | 
			
		||||
    uint256 userVariableDebt
 | 
			
		||||
  ) internal view returns (uint256, string memory) {
 | 
			
		||||
    if (
 | 
			
		||||
      !collateralReserve.configuration.getActive() || !principalReserve.configuration.getActive()
 | 
			
		||||
    ) {
 | 
			
		||||
      return (uint256(Errors.CollateralManagerErrors.NO_ACTIVE_RESERVE), Errors.NO_ACTIVE_RESERVE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (
 | 
			
		||||
      msg.sender != user && userHealthFactor >= GenericLogic.HEALTH_FACTOR_LIQUIDATION_THRESHOLD
 | 
			
		||||
    ) {
 | 
			
		||||
      return (
 | 
			
		||||
        uint256(Errors.CollateralManagerErrors.HEALTH_FACTOR_ABOVE_THRESHOLD),
 | 
			
		||||
        Errors.HEALTH_FACTOR_NOT_BELOW_THRESHOLD
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (msg.sender != user) {
 | 
			
		||||
      bool isCollateralEnabled = collateralReserve.configuration.getLiquidationThreshold() > 0 &&
 | 
			
		||||
        userConfig.isUsingAsCollateral(collateralReserve.id);
 | 
			
		||||
 | 
			
		||||
      //if collateral isn't enabled as collateral by user, it cannot be liquidated
 | 
			
		||||
      if (!isCollateralEnabled) {
 | 
			
		||||
        return (
 | 
			
		||||
          uint256(Errors.CollateralManagerErrors.COLLATERAL_CANNOT_BE_LIQUIDATED),
 | 
			
		||||
          Errors.COLLATERAL_CANNOT_BE_LIQUIDATED
 | 
			
		||||
        );
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (userStableDebt == 0 && userVariableDebt == 0) {
 | 
			
		||||
      return (
 | 
			
		||||
        uint256(Errors.CollateralManagerErrors.CURRRENCY_NOT_BORROWED),
 | 
			
		||||
        Errors.SPECIFIED_CURRENCY_NOT_BORROWED_BY_USER
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return (uint256(Errors.CollateralManagerErrors.NO_ERROR), Errors.NO_ERRORS);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @dev Validates the swapLiquidity() action
 | 
			
		||||
   * @param fromReserve The reserve data of the asset to swap from
 | 
			
		||||
   * @param toReserve The reserve data of the asset to swap to
 | 
			
		||||
   * @param fromAsset Address of the asset to swap from
 | 
			
		||||
   * @param toAsset Address of the asset to swap to
 | 
			
		||||
   **/
 | 
			
		||||
  function validateSwapLiquidity(
 | 
			
		||||
    ReserveLogic.ReserveData storage fromReserve,
 | 
			
		||||
    ReserveLogic.ReserveData storage toReserve,
 | 
			
		||||
    address fromAsset,
 | 
			
		||||
    address toAsset
 | 
			
		||||
  ) internal view returns (uint256, string memory) {
 | 
			
		||||
    if (fromAsset == toAsset) {
 | 
			
		||||
      return (
 | 
			
		||||
        uint256(Errors.CollateralManagerErrors.INVALID_EQUAL_ASSETS_TO_SWAP),
 | 
			
		||||
        Errors.INVALID_EQUAL_ASSETS_TO_SWAP
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    (bool isToActive, bool isToFreezed, , ) = toReserve.configuration.getFlags();
 | 
			
		||||
    if (!fromReserve.configuration.getActive() || !isToActive) {
 | 
			
		||||
      return (uint256(Errors.CollateralManagerErrors.NO_ACTIVE_RESERVE), Errors.NO_ACTIVE_RESERVE);
 | 
			
		||||
    }
 | 
			
		||||
    if (isToFreezed) {
 | 
			
		||||
      return (
 | 
			
		||||
        uint256(Errors.CollateralManagerErrors.NO_UNFREEZED_RESERVE),
 | 
			
		||||
        Errors.NO_UNFREEZED_RESERVE
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return (uint256(Errors.CollateralManagerErrors.NO_ERROR), Errors.NO_ERRORS);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,59 +0,0 @@
 | 
			
		|||
// SPDX-License-Identifier: agpl-3.0
 | 
			
		||||
pragma solidity ^0.6.8;
 | 
			
		||||
 | 
			
		||||
import {MintableERC20} from '../tokens/MintableERC20.sol';
 | 
			
		||||
import {ILendingPoolAddressesProvider} from '../../interfaces/ILendingPoolAddressesProvider.sol';
 | 
			
		||||
import {ISwapAdapter} from '../../interfaces/ISwapAdapter.sol';
 | 
			
		||||
import {ILendingPool} from '../../interfaces/ILendingPool.sol';
 | 
			
		||||
import {IERC20} from '../../dependencies/openzeppelin/contracts/IERC20.sol';
 | 
			
		||||
 | 
			
		||||
contract MockSwapAdapter is ISwapAdapter {
 | 
			
		||||
  uint256 internal _amountToReturn;
 | 
			
		||||
  bool internal _tryReentrancy;
 | 
			
		||||
  ILendingPoolAddressesProvider public addressesProvider;
 | 
			
		||||
 | 
			
		||||
  event Swapped(address fromAsset, address toAsset, uint256 fromAmount, uint256 receivedAmount);
 | 
			
		||||
 | 
			
		||||
  constructor(ILendingPoolAddressesProvider provider) public {
 | 
			
		||||
    addressesProvider = provider;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function setAmountToReturn(uint256 amount) public {
 | 
			
		||||
    _amountToReturn = amount;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function setTryReentrancy(bool tryReentrancy) public {
 | 
			
		||||
    _tryReentrancy = tryReentrancy;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function executeOperation(
 | 
			
		||||
    address assetToSwapFrom,
 | 
			
		||||
    address assetToSwapTo,
 | 
			
		||||
    uint256 amountToSwap,
 | 
			
		||||
    address fundsDestination,
 | 
			
		||||
    bytes calldata params
 | 
			
		||||
  ) external override {
 | 
			
		||||
    params;
 | 
			
		||||
    IERC20(assetToSwapFrom).transfer(address(1), amountToSwap); // We don't want to keep funds here
 | 
			
		||||
    MintableERC20(assetToSwapTo).mint(_amountToReturn);
 | 
			
		||||
    IERC20(assetToSwapTo).approve(fundsDestination, _amountToReturn);
 | 
			
		||||
 | 
			
		||||
    if (_tryReentrancy) {
 | 
			
		||||
      ILendingPool(fundsDestination).repayWithCollateral(
 | 
			
		||||
        assetToSwapFrom,
 | 
			
		||||
        assetToSwapTo,
 | 
			
		||||
        address(1), // Doesn't matter, we just want to test the reentrancy
 | 
			
		||||
        1 ether, // Same
 | 
			
		||||
        address(1), // Same
 | 
			
		||||
        '0x'
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    emit Swapped(assetToSwapFrom, assetToSwapTo, amountToSwap, _amountToReturn);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function burnAsset(IERC20 asset, uint256 amount) public {
 | 
			
		||||
    uint256 amountToBurn = (amount == type(uint256).max) ? asset.balanceOf(address(this)) : amount;
 | 
			
		||||
    asset.transfer(address(0), amountToBurn);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -5,7 +5,7 @@
 | 
			
		|||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "localhost": {
 | 
			
		||||
      "address": "0x58F132FBB86E21545A4Bace3C19f1C05d86d7A22",
 | 
			
		||||
      "address": "0xDFbeeed692AA81E7f86E72F7ACbEA2A1C4d63544",
 | 
			
		||||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "coverage": {
 | 
			
		||||
| 
						 | 
				
			
			@ -19,7 +19,7 @@
 | 
			
		|||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "localhost": {
 | 
			
		||||
      "address": "0xa4bcDF64Cdd5451b6ac3743B414124A6299B65FF",
 | 
			
		||||
      "address": "0x5191aA68c7dB195181Dd2441dBE23A48EA24b040",
 | 
			
		||||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "coverage": {
 | 
			
		||||
| 
						 | 
				
			
			@ -37,7 +37,7 @@
 | 
			
		|||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "localhost": {
 | 
			
		||||
      "address": "0x5A0773Ff307Bf7C71a832dBB5312237fD3437f9F",
 | 
			
		||||
      "address": "0xa89E20284Bd638F31b0011D0fC754Fc9d2fa73e3",
 | 
			
		||||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "coverage": {
 | 
			
		||||
| 
						 | 
				
			
			@ -73,7 +73,7 @@
 | 
			
		|||
      "address": "0x6642B57e4265BAD868C17Fc1d1F4F88DBBA04Aa8"
 | 
			
		||||
    },
 | 
			
		||||
    "localhost": {
 | 
			
		||||
      "address": "0x65e0Cd5B8904A02f2e00BC6f58bf881998D54BDe"
 | 
			
		||||
      "address": "0x9Ec55627757348b322c8dD0865D704649bFa0c7b"
 | 
			
		||||
    },
 | 
			
		||||
    "kovan": {
 | 
			
		||||
      "address": "0x1339f3c1FfF00D0FD8946187fdC61F0ef0fFe786"
 | 
			
		||||
| 
						 | 
				
			
			@ -89,7 +89,7 @@
 | 
			
		|||
      "address": "0xD9273d497eDBC967F39d419461CfcF382a0A822e"
 | 
			
		||||
    },
 | 
			
		||||
    "localhost": {
 | 
			
		||||
      "address": "0x5d12dDe3286D94E0d85F9D3B01B7099cfA0aBCf1"
 | 
			
		||||
      "address": "0x3EE716e38f21e5FC16BFDB773db24D63C637A5d8"
 | 
			
		||||
    },
 | 
			
		||||
    "kovan": {
 | 
			
		||||
      "address": "0xB43CCfF1148bb5ab2104E2ee68A7c30cDEBb9A9C"
 | 
			
		||||
| 
						 | 
				
			
			@ -101,7 +101,7 @@
 | 
			
		|||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "localhost": {
 | 
			
		||||
      "address": "0x1750499D05Ed1674d822430FB960d5F6731fDf64",
 | 
			
		||||
      "address": "0x5889354f21A1C8D8D2f82669d778f6Dab778B519",
 | 
			
		||||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "coverage": {
 | 
			
		||||
| 
						 | 
				
			
			@ -115,7 +115,7 @@
 | 
			
		|||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "localhost": {
 | 
			
		||||
      "address": "0xEC1C93A9f6a9e18E97784c76aC52053587FcDB89",
 | 
			
		||||
      "address": "0xC452C5244F701108B4e8E8BCe693160046b30332",
 | 
			
		||||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "coverage": {
 | 
			
		||||
| 
						 | 
				
			
			@ -129,7 +129,7 @@
 | 
			
		|||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "localhost": {
 | 
			
		||||
      "address": "0x7B6C3e5486D9e6959441ab554A889099eed76290",
 | 
			
		||||
      "address": "0x0B63c002cb44B2e5e580C3B3560a27F4101D95c0",
 | 
			
		||||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "coverage": {
 | 
			
		||||
| 
						 | 
				
			
			@ -147,7 +147,7 @@
 | 
			
		|||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "localhost": {
 | 
			
		||||
      "address": "0xD83D2773a7873ae2b5f8Fb92097e20a8C64F691E",
 | 
			
		||||
      "address": "0xCeB290A2C6614BF23B2faa0f0B8067F29C48DB0F",
 | 
			
		||||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "coverage": {
 | 
			
		||||
| 
						 | 
				
			
			@ -165,7 +165,7 @@
 | 
			
		|||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "localhost": {
 | 
			
		||||
      "address": "0x626FdE749F9d499d3777320CAf29484B624ab84a",
 | 
			
		||||
      "address": "0x7C95b1ad025F0C9aB14192f87bF2aD53889bE4F7",
 | 
			
		||||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "coverage": {
 | 
			
		||||
| 
						 | 
				
			
			@ -227,7 +227,7 @@
 | 
			
		|||
      "address": "0xBEF0d4b9c089a5883741fC14cbA352055f35DDA2"
 | 
			
		||||
    },
 | 
			
		||||
    "localhost": {
 | 
			
		||||
      "address": "0x2B681757d757fbB80cc51c6094cEF5eE75bF55aA"
 | 
			
		||||
      "address": "0x9c91aEaD98b1354C7B0EAfb8ff539d0796c79894"
 | 
			
		||||
    },
 | 
			
		||||
    "coverage": {
 | 
			
		||||
      "address": "0x2B681757d757fbB80cc51c6094cEF5eE75bF55aA"
 | 
			
		||||
| 
						 | 
				
			
			@ -235,11 +235,11 @@
 | 
			
		|||
  },
 | 
			
		||||
  "WalletBalanceProvider": {
 | 
			
		||||
    "buidlerevm": {
 | 
			
		||||
      "address": "0xC6bA6049F86d528698B5924B8fC2FE7289D38578",
 | 
			
		||||
      "address": "0x2cfcA5785261fbC88EFFDd46fCFc04c22525F9e4",
 | 
			
		||||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "localhost": {
 | 
			
		||||
      "address": "0xDf73fC454FA018051D4a1509e63D11530A59DE10",
 | 
			
		||||
      "address": "0x145b7B6368Df63e7F3497b0A948B30fC1A4d5E55",
 | 
			
		||||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "coverage": {
 | 
			
		||||
| 
						 | 
				
			
			@ -253,7 +253,7 @@
 | 
			
		|||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "localhost": {
 | 
			
		||||
      "address": "0x7c2C195CD6D34B8F845992d380aADB2730bB9C6F",
 | 
			
		||||
      "address": "0x010e948B9B7D30771E23346C0B17a4D5Ff04e300",
 | 
			
		||||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "coverage": {
 | 
			
		||||
| 
						 | 
				
			
			@ -267,7 +267,7 @@
 | 
			
		|||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "localhost": {
 | 
			
		||||
      "address": "0x8858eeB3DfffA017D4BCE9801D340D36Cf895CCf",
 | 
			
		||||
      "address": "0x79094eDB848047e87a4B8a64ab5Ee2f527791bC0",
 | 
			
		||||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "coverage": {
 | 
			
		||||
| 
						 | 
				
			
			@ -281,7 +281,7 @@
 | 
			
		|||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "localhost": {
 | 
			
		||||
      "address": "0x0078371BDeDE8aAc7DeBfFf451B74c5EDB385Af7",
 | 
			
		||||
      "address": "0xEE0A69d0Bb1312685870Dd7E20AcAD66b6f6264F",
 | 
			
		||||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "coverage": {
 | 
			
		||||
| 
						 | 
				
			
			@ -295,7 +295,7 @@
 | 
			
		|||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "localhost": {
 | 
			
		||||
      "address": "0xf4e77E5Da47AC3125140c470c71cBca77B5c638c",
 | 
			
		||||
      "address": "0x631B367fBE1dbB934bC039aAA0C9eC2EE5943fd5",
 | 
			
		||||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "coverage": {
 | 
			
		||||
| 
						 | 
				
			
			@ -309,7 +309,7 @@
 | 
			
		|||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "localhost": {
 | 
			
		||||
      "address": "0x3619DbE27d7c1e7E91aA738697Ae7Bc5FC3eACA5",
 | 
			
		||||
      "address": "0xf55Af78B3f3059fACF166Aa338FFe059A14e75F6",
 | 
			
		||||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "coverage": {
 | 
			
		||||
| 
						 | 
				
			
			@ -323,7 +323,7 @@
 | 
			
		|||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "localhost": {
 | 
			
		||||
      "address": "0x038B86d9d8FAFdd0a02ebd1A476432877b0107C8",
 | 
			
		||||
      "address": "0xD5A0587aAEB195028909E98930B391dFB3f9F589",
 | 
			
		||||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "coverage": {
 | 
			
		||||
| 
						 | 
				
			
			@ -337,7 +337,7 @@
 | 
			
		|||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "localhost": {
 | 
			
		||||
      "address": "0x1A1FEe7EeD918BD762173e4dc5EfDB8a78C924A8",
 | 
			
		||||
      "address": "0xaD3AdbC18E4AD090034A6C74Eda61f4310dce313",
 | 
			
		||||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "coverage": {
 | 
			
		||||
| 
						 | 
				
			
			@ -351,7 +351,7 @@
 | 
			
		|||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "localhost": {
 | 
			
		||||
      "address": "0x500D1d6A4c7D8Ae28240b47c8FCde034D827fD5e",
 | 
			
		||||
      "address": "0x25a88BbA9c8D2a46e3Ff4bFe98712DF7A1044fB6",
 | 
			
		||||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "coverage": {
 | 
			
		||||
| 
						 | 
				
			
			@ -365,7 +365,7 @@
 | 
			
		|||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "localhost": {
 | 
			
		||||
      "address": "0xc4905364b78a742ccce7B890A89514061E47068D",
 | 
			
		||||
      "address": "0x16d1802cd7cfcb67955BBBa26bAae1cE559B5F5B",
 | 
			
		||||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "coverage": {
 | 
			
		||||
| 
						 | 
				
			
			@ -379,7 +379,7 @@
 | 
			
		|||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "localhost": {
 | 
			
		||||
      "address": "0xD6C850aeBFDC46D7F4c207e445cC0d6B0919BDBe",
 | 
			
		||||
      "address": "0xE58d8c88f5A670f16BE8F7864707170F43e943A6",
 | 
			
		||||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "coverage": {
 | 
			
		||||
| 
						 | 
				
			
			@ -393,7 +393,7 @@
 | 
			
		|||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "localhost": {
 | 
			
		||||
      "address": "0x8B5B7a6055E54a36fF574bbE40cf2eA68d5554b3",
 | 
			
		||||
      "address": "0xfdAF4f6e47e854c05bE158993d32872e784F0502",
 | 
			
		||||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "coverage": {
 | 
			
		||||
| 
						 | 
				
			
			@ -407,7 +407,7 @@
 | 
			
		|||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "localhost": {
 | 
			
		||||
      "address": "0xEcc0a6dbC0bb4D51E4F84A315a9e5B0438cAD4f0",
 | 
			
		||||
      "address": "0x92edC13A10036A3C50396f2B63148a3e9a8D589e",
 | 
			
		||||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "coverage": {
 | 
			
		||||
| 
						 | 
				
			
			@ -421,7 +421,7 @@
 | 
			
		|||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "localhost": {
 | 
			
		||||
      "address": "0x20Ce94F404343aD2752A2D01b43fa407db9E0D00",
 | 
			
		||||
      "address": "0xE5C277cDb7E10372918Ac54Ce54022910A24FE88",
 | 
			
		||||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "coverage": {
 | 
			
		||||
| 
						 | 
				
			
			@ -435,7 +435,7 @@
 | 
			
		|||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "localhost": {
 | 
			
		||||
      "address": "0x1d80315fac6aBd3EfeEbE97dEc44461ba7556160",
 | 
			
		||||
      "address": "0xF5742a599a0F4520089cbf2EBBa66Bb4F471B85F",
 | 
			
		||||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "coverage": {
 | 
			
		||||
| 
						 | 
				
			
			@ -449,7 +449,7 @@
 | 
			
		|||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "localhost": {
 | 
			
		||||
      "address": "0x2D8553F9ddA85A9B3259F6Bf26911364B85556F5",
 | 
			
		||||
      "address": "0x380EF388e13D8cAdeACef6eF682C7B7D85865076",
 | 
			
		||||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "coverage": {
 | 
			
		||||
| 
						 | 
				
			
			@ -463,7 +463,7 @@
 | 
			
		|||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "localhost": {
 | 
			
		||||
      "address": "0x52d3b94181f8654db2530b0fEe1B19173f519C52",
 | 
			
		||||
      "address": "0xC89577DED8441e52C17C13D527b85b225C5c8311",
 | 
			
		||||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "coverage": {
 | 
			
		||||
| 
						 | 
				
			
			@ -477,7 +477,7 @@
 | 
			
		|||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "localhost": {
 | 
			
		||||
      "address": "0xd15468525c35BDBC1eD8F2e09A00F8a173437f2f",
 | 
			
		||||
      "address": "0xD4b06774A717Ff5A7c20c8712e31c6BbfFcb1F01",
 | 
			
		||||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "coverage": {
 | 
			
		||||
| 
						 | 
				
			
			@ -491,7 +491,7 @@
 | 
			
		|||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "localhost": {
 | 
			
		||||
      "address": "0x7e35Eaf7e8FBd7887ad538D4A38Df5BbD073814a",
 | 
			
		||||
      "address": "0xbe66dC9DFEe580ED968403e35dF7b5159f873df8",
 | 
			
		||||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "coverage": {
 | 
			
		||||
| 
						 | 
				
			
			@ -505,7 +505,7 @@
 | 
			
		|||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "localhost": {
 | 
			
		||||
      "address": "0x5bcb88A0d20426e451332eE6C4324b0e663c50E0",
 | 
			
		||||
      "address": "0x93AfC6Df4bB8F62F2493B19e577f8382c0BA9EBC",
 | 
			
		||||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "coverage": {
 | 
			
		||||
| 
						 | 
				
			
			@ -519,7 +519,7 @@
 | 
			
		|||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "localhost": {
 | 
			
		||||
      "address": "0x3521eF8AaB0323004A6dD8b03CE890F4Ea3A13f5",
 | 
			
		||||
      "address": "0x75Ded61646B5945BdDd0CD9a9Db7c8288DA6F810",
 | 
			
		||||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "coverage": {
 | 
			
		||||
| 
						 | 
				
			
			@ -533,7 +533,7 @@
 | 
			
		|||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "localhost": {
 | 
			
		||||
      "address": "0x53369fd4680FfE3DfF39Fc6DDa9CfbfD43daeA2E",
 | 
			
		||||
      "address": "0xdE7c40e675bF1aA45c18cCbaEb9662B16b0Ddf7E",
 | 
			
		||||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "coverage": {
 | 
			
		||||
| 
						 | 
				
			
			@ -547,7 +547,7 @@
 | 
			
		|||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "localhost": {
 | 
			
		||||
      "address": "0xB00cC45B4a7d3e1FEE684cFc4417998A1c183e6d",
 | 
			
		||||
      "address": "0xEcb928A3c079a1696Aa5244779eEc3dE1717fACd",
 | 
			
		||||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "coverage": {
 | 
			
		||||
| 
						 | 
				
			
			@ -561,7 +561,7 @@
 | 
			
		|||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "localhost": {
 | 
			
		||||
      "address": "0x58F132FBB86E21545A4Bace3C19f1C05d86d7A22",
 | 
			
		||||
      "address": "0xDFbeeed692AA81E7f86E72F7ACbEA2A1C4d63544",
 | 
			
		||||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "coverage": {
 | 
			
		||||
| 
						 | 
				
			
			@ -574,7 +574,7 @@
 | 
			
		|||
      "address": "0xe7536f450378748E1BD4645D3c77ec38e0F3ba28"
 | 
			
		||||
    },
 | 
			
		||||
    "localhost": {
 | 
			
		||||
      "address": "0x2cfcA5785261fbC88EFFDd46fCFc04c22525F9e4"
 | 
			
		||||
      "address": "0x987223924D2DD6c6efB601756850f3886ECbceF6"
 | 
			
		||||
    },
 | 
			
		||||
    "coverage": {
 | 
			
		||||
      "address": "0x2cfcA5785261fbC88EFFDd46fCFc04c22525F9e4"
 | 
			
		||||
| 
						 | 
				
			
			@ -590,7 +590,7 @@
 | 
			
		|||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "localhost": {
 | 
			
		||||
      "address": "0xB660Fdd109a95718cB9d20E3A89EE6cE342aDcB6",
 | 
			
		||||
      "address": "0xaca5aCeB6f44845d07Fd339a51F0bd52Bb3D8D1A",
 | 
			
		||||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "coverage": {
 | 
			
		||||
| 
						 | 
				
			
			@ -608,7 +608,7 @@
 | 
			
		|||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "localhost": {
 | 
			
		||||
      "address": "0x830bceA96E56DBC1F8578f75fBaC0AF16B32A07d",
 | 
			
		||||
      "address": "0x9bD0Bec44106D8Ea8fFb6296d7A84742a290E064",
 | 
			
		||||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "coverage": {
 | 
			
		||||
| 
						 | 
				
			
			@ -622,7 +622,7 @@
 | 
			
		|||
  },
 | 
			
		||||
  "AToken": {
 | 
			
		||||
    "localhost": {
 | 
			
		||||
      "address": "0xA0AB1cB92A4AF81f84dCd258155B5c25D247b54E",
 | 
			
		||||
      "address": "0x00f126cCA2266bFb634Ed6DB17c4C74fb8cA5177",
 | 
			
		||||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "buidlerevm": {
 | 
			
		||||
| 
						 | 
				
			
			@ -640,11 +640,11 @@
 | 
			
		|||
  },
 | 
			
		||||
  "MockAToken": {
 | 
			
		||||
    "buidlerevm": {
 | 
			
		||||
      "address": "0x3b050AFb4ac4ACE646b31fF3639C1CD43aC31460",
 | 
			
		||||
      "address": "0x392E5355a0e88Bd394F717227c752670fb3a8020",
 | 
			
		||||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "localhost": {
 | 
			
		||||
      "address": "0xa89E20284Bd638F31b0011D0fC754Fc9d2fa73e3",
 | 
			
		||||
      "address": "0xbF538F34cb100bAeEE55aa1F036D33F03b03d900",
 | 
			
		||||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "coverage": {
 | 
			
		||||
| 
						 | 
				
			
			@ -658,7 +658,7 @@
 | 
			
		|||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "localhost": {
 | 
			
		||||
      "address": "0xf784709d2317D872237C4bC22f867d1BAe2913AB",
 | 
			
		||||
      "address": "0xff1B1B810F5DCe853a9b1819DE220D532D1CFeF2",
 | 
			
		||||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "coverage": {
 | 
			
		||||
| 
						 | 
				
			
			@ -668,11 +668,11 @@
 | 
			
		|||
  },
 | 
			
		||||
  "MockStableDebtToken": {
 | 
			
		||||
    "buidlerevm": {
 | 
			
		||||
      "address": "0xEBAB67ee3ef604D5c250A53b4b8fcbBC6ec3007C",
 | 
			
		||||
      "address": "0x3b050AFb4ac4ACE646b31fF3639C1CD43aC31460",
 | 
			
		||||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "localhost": {
 | 
			
		||||
      "address": "0xaA935993065F2dDB1d13623B1941C7AEE3A60F23",
 | 
			
		||||
      "address": "0x7436d6adaA697413F00cb63E1A2A854bF2Aec5A1",
 | 
			
		||||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "coverage": {
 | 
			
		||||
| 
						 | 
				
			
			@ -682,11 +682,11 @@
 | 
			
		|||
  },
 | 
			
		||||
  "MockVariableDebtToken": {
 | 
			
		||||
    "buidlerevm": {
 | 
			
		||||
      "address": "0xBE36BE5680244Ae1A6F983E4A6f6E1c142cdAbe3",
 | 
			
		||||
      "address": "0xEBAB67ee3ef604D5c250A53b4b8fcbBC6ec3007C",
 | 
			
		||||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "localhost": {
 | 
			
		||||
      "address": "0x35A2624888e207e4B3434E9a9E250bF6Ee68FeA3",
 | 
			
		||||
      "address": "0x2A7BE996B8801ED21f2f45148791D402811A2106",
 | 
			
		||||
      "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
 | 
			
		||||
    },
 | 
			
		||||
    "coverage": {
 | 
			
		||||
| 
						 | 
				
			
			@ -702,7 +702,7 @@
 | 
			
		|||
      "address": "0xBEF0d4b9c089a5883741fC14cbA352055f35DDA2"
 | 
			
		||||
    },
 | 
			
		||||
    "localhost": {
 | 
			
		||||
      "address": "0xBEF0d4b9c089a5883741fC14cbA352055f35DDA2"
 | 
			
		||||
      "address": "0x48FAde2E719B770E1783d03466dAEe98b5183538"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  "MockFlashRepayAdapter": {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,258 +0,0 @@
 | 
			
		|||
import {makeSuite, TestEnv} from './helpers/make-suite';
 | 
			
		||||
import {MockSwapAdapter} from '../types/MockSwapAdapter';
 | 
			
		||||
import {getMockSwapAdapter} from '../helpers/contracts-helpers';
 | 
			
		||||
import {ProtocolErrors} from '../helpers/types';
 | 
			
		||||
import {ethers} from 'ethers';
 | 
			
		||||
import {APPROVAL_AMOUNT_LENDING_POOL} from '../helpers/constants';
 | 
			
		||||
import {getContractsData, getTxCostAndTimestamp} from './helpers/actions';
 | 
			
		||||
import {calcExpectedATokenBalance} from './helpers/utils/calculations';
 | 
			
		||||
import {waitForTx} from '../helpers/misc-utils';
 | 
			
		||||
import {advanceBlock, timeLatest} from '../helpers/misc-utils';
 | 
			
		||||
 | 
			
		||||
const {expect} = require('chai');
 | 
			
		||||
 | 
			
		||||
makeSuite('LendingPool SwapDeposit function', (testEnv: TestEnv) => {
 | 
			
		||||
  let _mockSwapAdapter = {} as MockSwapAdapter;
 | 
			
		||||
  const {
 | 
			
		||||
    HEALTH_FACTOR_LOWER_THAN_LIQUIDATION_THRESHOLD,
 | 
			
		||||
    NO_UNFREEZED_RESERVE,
 | 
			
		||||
    NO_ACTIVE_RESERVE,
 | 
			
		||||
    INVALID_EQUAL_ASSETS_TO_SWAP,
 | 
			
		||||
  } = ProtocolErrors;
 | 
			
		||||
 | 
			
		||||
  before(async () => {
 | 
			
		||||
    _mockSwapAdapter = await getMockSwapAdapter();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('Should not allow to swap if from equal to', async () => {
 | 
			
		||||
    const {pool, weth} = testEnv;
 | 
			
		||||
 | 
			
		||||
    await expect(
 | 
			
		||||
      pool.swapLiquidity(
 | 
			
		||||
        _mockSwapAdapter.address,
 | 
			
		||||
        weth.address,
 | 
			
		||||
        weth.address,
 | 
			
		||||
        '1'.toString(),
 | 
			
		||||
        '0x10'
 | 
			
		||||
      )
 | 
			
		||||
    ).to.be.revertedWith(INVALID_EQUAL_ASSETS_TO_SWAP);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('Should not allow to swap if from or to reserves are not active', async () => {
 | 
			
		||||
    const {pool, weth, dai, configurator} = testEnv;
 | 
			
		||||
 | 
			
		||||
    await configurator.deactivateReserve(weth.address);
 | 
			
		||||
 | 
			
		||||
    await expect(
 | 
			
		||||
      pool.swapLiquidity(
 | 
			
		||||
        _mockSwapAdapter.address,
 | 
			
		||||
        weth.address,
 | 
			
		||||
        dai.address,
 | 
			
		||||
        '1'.toString(),
 | 
			
		||||
        '0x10'
 | 
			
		||||
      )
 | 
			
		||||
    ).to.be.revertedWith(NO_ACTIVE_RESERVE);
 | 
			
		||||
    await configurator.activateReserve(weth.address);
 | 
			
		||||
 | 
			
		||||
    await configurator.deactivateReserve(dai.address);
 | 
			
		||||
 | 
			
		||||
    await expect(
 | 
			
		||||
      pool.swapLiquidity(
 | 
			
		||||
        _mockSwapAdapter.address,
 | 
			
		||||
        weth.address,
 | 
			
		||||
        dai.address,
 | 
			
		||||
        '1'.toString(),
 | 
			
		||||
        '0x10'
 | 
			
		||||
      )
 | 
			
		||||
    ).to.be.revertedWith(NO_ACTIVE_RESERVE);
 | 
			
		||||
 | 
			
		||||
    //cleanup state
 | 
			
		||||
    await configurator.activateReserve(dai.address);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('Deposits WETH into the reserve', async () => {
 | 
			
		||||
    const {pool, weth, users} = testEnv;
 | 
			
		||||
    const amountToDeposit = ethers.utils.parseEther('1');
 | 
			
		||||
 | 
			
		||||
    for (const signer of [weth.signer, users[2].signer]) {
 | 
			
		||||
      const connectedWETH = weth.connect(signer);
 | 
			
		||||
      await connectedWETH.mint(amountToDeposit);
 | 
			
		||||
      await connectedWETH.approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL);
 | 
			
		||||
      await pool
 | 
			
		||||
        .connect(signer)
 | 
			
		||||
        .deposit(weth.address, amountToDeposit, await signer.getAddress(), '0');
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('User tries to swap more then he can, revert expected', async () => {
 | 
			
		||||
    const {pool, weth, dai} = testEnv;
 | 
			
		||||
    await expect(
 | 
			
		||||
      pool.swapLiquidity(
 | 
			
		||||
        _mockSwapAdapter.address,
 | 
			
		||||
        weth.address,
 | 
			
		||||
        dai.address,
 | 
			
		||||
        ethers.utils.parseEther('1.1'),
 | 
			
		||||
        '0x10'
 | 
			
		||||
      )
 | 
			
		||||
    ).to.be.revertedWith('55');
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('User tries to swap more then available on the reserve', async () => {
 | 
			
		||||
    const {pool, weth, dai, users, aEth, deployer} = testEnv;
 | 
			
		||||
 | 
			
		||||
    await pool.borrow(weth.address, ethers.utils.parseEther('0.1'), 1, 0, deployer.address);
 | 
			
		||||
    await pool.connect(users[2].signer).withdraw(weth.address, ethers.utils.parseEther('1'));
 | 
			
		||||
 | 
			
		||||
    await expect(
 | 
			
		||||
      pool.swapLiquidity(
 | 
			
		||||
        _mockSwapAdapter.address,
 | 
			
		||||
        weth.address,
 | 
			
		||||
        dai.address,
 | 
			
		||||
        ethers.utils.parseEther('1'),
 | 
			
		||||
        '0x10'
 | 
			
		||||
      )
 | 
			
		||||
    ).to.be.revertedWith('55');
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('User tries to swap correct amount', async () => {
 | 
			
		||||
    const {pool, weth, dai, aEth, aDai, helpersContract} = testEnv;
 | 
			
		||||
    const userAddress = await pool.signer.getAddress();
 | 
			
		||||
    const amountToSwap = ethers.utils.parseEther('0.25');
 | 
			
		||||
 | 
			
		||||
    const amountToReturn = ethers.utils.parseEther('0.5');
 | 
			
		||||
    await _mockSwapAdapter.setAmountToReturn(amountToReturn);
 | 
			
		||||
 | 
			
		||||
    const {
 | 
			
		||||
      reserveData: wethReserveDataBefore,
 | 
			
		||||
      userData: wethUserDataBefore,
 | 
			
		||||
    } = await getContractsData(weth.address, userAddress, testEnv);
 | 
			
		||||
 | 
			
		||||
    const {reserveData: daiReserveDataBefore, userData: daiUserDataBefore} = await getContractsData(
 | 
			
		||||
      dai.address,
 | 
			
		||||
      userAddress,
 | 
			
		||||
      testEnv
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const reserveBalanceWETHBefore = await weth.balanceOf(aEth.address);
 | 
			
		||||
    const reserveBalanceDAIBefore = await dai.balanceOf(aDai.address);
 | 
			
		||||
 | 
			
		||||
    const txReceipt = await waitForTx(
 | 
			
		||||
      await pool.swapLiquidity(
 | 
			
		||||
        _mockSwapAdapter.address,
 | 
			
		||||
        weth.address,
 | 
			
		||||
        dai.address,
 | 
			
		||||
        amountToSwap,
 | 
			
		||||
        '0x10'
 | 
			
		||||
      )
 | 
			
		||||
    );
 | 
			
		||||
    const {txTimestamp} = await getTxCostAndTimestamp(txReceipt);
 | 
			
		||||
    const userATokenBalanceWETHAfter = await aEth.balanceOf(userAddress);
 | 
			
		||||
    const userATokenBalanceDAIAfter = await aDai.balanceOf(userAddress);
 | 
			
		||||
 | 
			
		||||
    const reserveBalanceWETHAfter = await weth.balanceOf(aEth.address);
 | 
			
		||||
    const reserveBalanceDAIAfter = await dai.balanceOf(aDai.address);
 | 
			
		||||
 | 
			
		||||
    expect(userATokenBalanceWETHAfter.toString()).to.be.equal(
 | 
			
		||||
      calcExpectedATokenBalance(wethReserveDataBefore, wethUserDataBefore, txTimestamp)
 | 
			
		||||
        .minus(amountToSwap.toString())
 | 
			
		||||
        .toString(),
 | 
			
		||||
      'was burned incorrect amount of user funds'
 | 
			
		||||
    );
 | 
			
		||||
    expect(userATokenBalanceDAIAfter.toString()).to.be.equal(
 | 
			
		||||
      calcExpectedATokenBalance(daiReserveDataBefore, daiUserDataBefore, txTimestamp)
 | 
			
		||||
        .plus(amountToReturn.toString())
 | 
			
		||||
        .toString(),
 | 
			
		||||
      'was minted incorrect amount of user funds'
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    expect(reserveBalanceWETHAfter.toString()).to.be.equal(
 | 
			
		||||
      reserveBalanceWETHBefore.sub(amountToSwap).toString(),
 | 
			
		||||
      'was sent incorrect amount if reserve funds'
 | 
			
		||||
    );
 | 
			
		||||
    expect(reserveBalanceDAIAfter.toString()).to.be.equal(
 | 
			
		||||
      reserveBalanceDAIBefore.add(amountToReturn).toString(),
 | 
			
		||||
      'was received incorrect amount if reserve funds'
 | 
			
		||||
    );
 | 
			
		||||
    expect(
 | 
			
		||||
      (await helpersContract.getUserReserveData(dai.address, userAddress)).usageAsCollateralEnabled
 | 
			
		||||
    ).to.be.equal(true, 'usage as collateral was not enabled on destination reserve for the user');
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('User tries to drop HF below one', async () => {
 | 
			
		||||
    const {pool, weth, dai, deployer} = testEnv;
 | 
			
		||||
    const amountToSwap = ethers.utils.parseEther('0.3');
 | 
			
		||||
 | 
			
		||||
    const amountToReturn = ethers.utils.parseEther('0.5');
 | 
			
		||||
    await _mockSwapAdapter.setAmountToReturn(amountToReturn);
 | 
			
		||||
 | 
			
		||||
    await pool.borrow(weth.address, ethers.utils.parseEther('0.3'), 1, 0, deployer.address);
 | 
			
		||||
 | 
			
		||||
    await expect(
 | 
			
		||||
      pool.swapLiquidity(_mockSwapAdapter.address, weth.address, dai.address, amountToSwap, '0x10')
 | 
			
		||||
    ).to.be.revertedWith(HEALTH_FACTOR_LOWER_THAN_LIQUIDATION_THRESHOLD);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('Should set usage as collateral to false if no leftovers after swap', async () => {
 | 
			
		||||
    const {pool, weth, dai, users} = testEnv;
 | 
			
		||||
    const userAddress = await pool.signer.getAddress();
 | 
			
		||||
 | 
			
		||||
    // add more liquidity to allow user 0 to swap everything he has
 | 
			
		||||
    await weth.connect(users[2].signer).mint(ethers.utils.parseEther('1'));
 | 
			
		||||
    await pool
 | 
			
		||||
      .connect(users[2].signer)
 | 
			
		||||
      .deposit(weth.address, ethers.utils.parseEther('1'), users[2].address, '0');
 | 
			
		||||
 | 
			
		||||
    // cleanup borrowings, to be abe to swap whole weth
 | 
			
		||||
    const amountToRepay = ethers.utils.parseEther('0.5');
 | 
			
		||||
    await weth.mint(amountToRepay);
 | 
			
		||||
    await pool.repay(weth.address, amountToRepay, '1', userAddress);
 | 
			
		||||
    const txTimestamp = (await timeLatest()).plus(100);
 | 
			
		||||
 | 
			
		||||
    const {
 | 
			
		||||
      reserveData: wethReserveDataBefore,
 | 
			
		||||
      userData: wethUserDataBefore,
 | 
			
		||||
    } = await getContractsData(weth.address, userAddress, testEnv);
 | 
			
		||||
    const amountToSwap = calcExpectedATokenBalance(
 | 
			
		||||
      wethReserveDataBefore,
 | 
			
		||||
      wethUserDataBefore,
 | 
			
		||||
      txTimestamp.plus('1')
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    await advanceBlock(txTimestamp.toNumber());
 | 
			
		||||
 | 
			
		||||
    await pool.swapLiquidity(
 | 
			
		||||
      _mockSwapAdapter.address,
 | 
			
		||||
      weth.address,
 | 
			
		||||
      dai.address,
 | 
			
		||||
      amountToSwap.toString(),
 | 
			
		||||
      '0x10'
 | 
			
		||||
    );
 | 
			
		||||
    const {userData: wethUserDataAfter} = await getContractsData(
 | 
			
		||||
      weth.address,
 | 
			
		||||
      userAddress,
 | 
			
		||||
      testEnv
 | 
			
		||||
    );
 | 
			
		||||
    expect(wethUserDataAfter.usageAsCollateralEnabled).to.be.equal(
 | 
			
		||||
      false,
 | 
			
		||||
      'usageAsCollateralEnabled are not set to false'
 | 
			
		||||
    );
 | 
			
		||||
  });
 | 
			
		||||
  it('Should not allow to swap if to reserve are freezed', async () => {
 | 
			
		||||
    const {pool, weth, dai, configurator} = testEnv;
 | 
			
		||||
 | 
			
		||||
    await configurator.freezeReserve(dai.address);
 | 
			
		||||
 | 
			
		||||
    await expect(
 | 
			
		||||
      pool.swapLiquidity(
 | 
			
		||||
        _mockSwapAdapter.address,
 | 
			
		||||
        weth.address,
 | 
			
		||||
        dai.address,
 | 
			
		||||
        '1'.toString(),
 | 
			
		||||
        '0x10'
 | 
			
		||||
      )
 | 
			
		||||
    ).to.be.revertedWith(NO_UNFREEZED_RESERVE);
 | 
			
		||||
 | 
			
		||||
    //cleanup state
 | 
			
		||||
    await configurator.unfreezeReserve(dai.address);
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			@ -1,932 +0,0 @@
 | 
			
		|||
import {TestEnv, makeSuite} from './helpers/make-suite';
 | 
			
		||||
import {APPROVAL_AMOUNT_LENDING_POOL, oneEther} from '../helpers/constants';
 | 
			
		||||
import {ethers} from 'ethers';
 | 
			
		||||
import BigNumber from 'bignumber.js';
 | 
			
		||||
import {
 | 
			
		||||
  calcExpectedVariableDebtTokenBalance,
 | 
			
		||||
  calcExpectedStableDebtTokenBalance,
 | 
			
		||||
} from './helpers/utils/calculations';
 | 
			
		||||
import {getContractsData} from './helpers/actions';
 | 
			
		||||
import {timeLatest, BRE, increaseTime, waitForTx} from '../helpers/misc-utils';
 | 
			
		||||
import {ProtocolErrors} from '../helpers/types';
 | 
			
		||||
import {convertToCurrencyDecimals} from '../helpers/contracts-helpers';
 | 
			
		||||
import {expectRepayWithCollateralEvent} from './repay-with-collateral.spec';
 | 
			
		||||
 | 
			
		||||
const {expect} = require('chai');
 | 
			
		||||
const {parseUnits, parseEther} = ethers.utils;
 | 
			
		||||
 | 
			
		||||
makeSuite('LendingPool. repayWithCollateral() with liquidator', (testEnv: TestEnv) => {
 | 
			
		||||
  const {INVALID_HF, COLLATERAL_CANNOT_BE_LIQUIDATED, IS_PAUSED} = ProtocolErrors;
 | 
			
		||||
 | 
			
		||||
  it('User 1 provides some liquidity for others to borrow', async () => {
 | 
			
		||||
    const {pool, weth, dai, usdc, deployer} = testEnv;
 | 
			
		||||
 | 
			
		||||
    await weth.mint(parseEther('200'));
 | 
			
		||||
    await weth.approve(pool.address, parseEther('200'));
 | 
			
		||||
    await pool.deposit(weth.address, parseEther('200'), deployer.address, 0);
 | 
			
		||||
    await dai.mint(parseEther('20000'));
 | 
			
		||||
    await dai.approve(pool.address, parseEther('20000'));
 | 
			
		||||
    await pool.deposit(dai.address, parseEther('20000'), deployer.address, 0);
 | 
			
		||||
    await usdc.mint(parseEther('20000'));
 | 
			
		||||
    await usdc.approve(pool.address, parseEther('20000'));
 | 
			
		||||
    await pool.deposit(usdc.address, parseEther('20000'), deployer.address, 0);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('User 5 liquidate User 3 collateral, all his variable debt and part of the stable', async () => {
 | 
			
		||||
    const {pool, weth, usdc, users, mockSwapAdapter, oracle, helpersContract} = testEnv;
 | 
			
		||||
    const user = users[2];
 | 
			
		||||
    const liquidator = users[4];
 | 
			
		||||
    const amountToDeposit = parseEther('20');
 | 
			
		||||
    const amountToBorrow = parseUnits('40', 6);
 | 
			
		||||
 | 
			
		||||
    await weth.connect(user.signer).mint(amountToDeposit);
 | 
			
		||||
 | 
			
		||||
    await weth.connect(user.signer).approve(pool.address, amountToDeposit);
 | 
			
		||||
    await pool.connect(user.signer).deposit(weth.address, amountToDeposit, user.address, '0');
 | 
			
		||||
 | 
			
		||||
    const usdcPrice = await oracle.getAssetPrice(usdc.address);
 | 
			
		||||
 | 
			
		||||
    await pool.connect(user.signer).borrow(usdc.address, amountToBorrow, 2, 0, user.address);
 | 
			
		||||
 | 
			
		||||
    await pool.connect(user.signer).borrow(usdc.address, amountToBorrow, 1, 0, user.address);
 | 
			
		||||
 | 
			
		||||
    const {userData: wethUserDataBefore} = await getContractsData(
 | 
			
		||||
      weth.address,
 | 
			
		||||
      user.address,
 | 
			
		||||
      testEnv
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const {
 | 
			
		||||
      reserveData: usdcReserveDataBefore,
 | 
			
		||||
      userData: usdcUserDataBefore,
 | 
			
		||||
    } = await getContractsData(usdc.address, user.address, testEnv);
 | 
			
		||||
 | 
			
		||||
    // Set HF below 1
 | 
			
		||||
    await oracle.setAssetPrice(
 | 
			
		||||
      usdc.address,
 | 
			
		||||
      new BigNumber(usdcPrice.toString()).multipliedBy(60).toFixed(0)
 | 
			
		||||
    );
 | 
			
		||||
    const userGlobalDataPrior = await pool.getUserAccountData(user.address);
 | 
			
		||||
    expect(userGlobalDataPrior.healthFactor.toString()).to.be.bignumber.lt(oneEther, INVALID_HF);
 | 
			
		||||
 | 
			
		||||
    const amountToRepay = parseUnits('80', 6);
 | 
			
		||||
 | 
			
		||||
    await mockSwapAdapter.setAmountToReturn(amountToRepay);
 | 
			
		||||
    const txReceipt = await waitForTx(
 | 
			
		||||
      await pool
 | 
			
		||||
        .connect(liquidator.signer)
 | 
			
		||||
        .repayWithCollateral(
 | 
			
		||||
          weth.address,
 | 
			
		||||
          usdc.address,
 | 
			
		||||
          user.address,
 | 
			
		||||
          amountToRepay,
 | 
			
		||||
          mockSwapAdapter.address,
 | 
			
		||||
          '0x'
 | 
			
		||||
        )
 | 
			
		||||
    );
 | 
			
		||||
    const repayWithCollateralTimestamp = await timeLatest();
 | 
			
		||||
 | 
			
		||||
    const {userData: wethUserDataAfter} = await getContractsData(
 | 
			
		||||
      weth.address,
 | 
			
		||||
      user.address,
 | 
			
		||||
      testEnv
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const {userData: usdcUserDataAfter} = await getContractsData(
 | 
			
		||||
      usdc.address,
 | 
			
		||||
      user.address,
 | 
			
		||||
      testEnv
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const collateralPrice = await oracle.getAssetPrice(weth.address);
 | 
			
		||||
    const principalPrice = await oracle.getAssetPrice(usdc.address);
 | 
			
		||||
 | 
			
		||||
    const collateralDecimals = (
 | 
			
		||||
      await helpersContract.getReserveConfigurationData(weth.address)
 | 
			
		||||
    ).decimals.toString();
 | 
			
		||||
    const principalDecimals = (
 | 
			
		||||
      await helpersContract.getReserveConfigurationData(usdc.address)
 | 
			
		||||
    ).decimals.toString();
 | 
			
		||||
 | 
			
		||||
    const expectedCollateralLiquidated = new BigNumber(principalPrice.toString())
 | 
			
		||||
      .times(new BigNumber(amountToRepay.toString()).times(105))
 | 
			
		||||
      .times(new BigNumber(10).pow(collateralDecimals))
 | 
			
		||||
      .div(
 | 
			
		||||
        new BigNumber(collateralPrice.toString()).times(new BigNumber(10).pow(principalDecimals))
 | 
			
		||||
      )
 | 
			
		||||
      .div(100)
 | 
			
		||||
      .decimalPlaces(0, BigNumber.ROUND_DOWN);
 | 
			
		||||
 | 
			
		||||
    const expectedVariableDebtIncrease = calcExpectedVariableDebtTokenBalance(
 | 
			
		||||
      usdcReserveDataBefore,
 | 
			
		||||
      usdcUserDataBefore,
 | 
			
		||||
      new BigNumber(repayWithCollateralTimestamp)
 | 
			
		||||
    ).minus(usdcUserDataBefore.currentVariableDebt);
 | 
			
		||||
 | 
			
		||||
    const expectedStableDebtIncrease = calcExpectedStableDebtTokenBalance(
 | 
			
		||||
      usdcUserDataBefore.principalStableDebt,
 | 
			
		||||
      usdcUserDataBefore.stableBorrowRate,
 | 
			
		||||
      usdcUserDataBefore.stableRateLastUpdated,
 | 
			
		||||
      new BigNumber(repayWithCollateralTimestamp)
 | 
			
		||||
    ).minus(usdcUserDataBefore.currentStableDebt);
 | 
			
		||||
 | 
			
		||||
    expect(usdcUserDataAfter.currentVariableDebt).to.be.bignumber.equal(
 | 
			
		||||
      new BigNumber(usdcUserDataBefore.currentVariableDebt)
 | 
			
		||||
        .minus(amountToRepay.toString())
 | 
			
		||||
        .plus(expectedVariableDebtIncrease)
 | 
			
		||||
        .gte(0)
 | 
			
		||||
        ? new BigNumber(usdcUserDataBefore.currentVariableDebt)
 | 
			
		||||
            .minus(amountToRepay.toString())
 | 
			
		||||
            .plus(expectedVariableDebtIncrease)
 | 
			
		||||
            .toString()
 | 
			
		||||
        : '0',
 | 
			
		||||
      'INVALID_VARIABLE_DEBT_POSITION'
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const stableDebtRepaid = new BigNumber(usdcUserDataBefore.currentVariableDebt)
 | 
			
		||||
      .minus(amountToRepay.toString())
 | 
			
		||||
      .plus(expectedVariableDebtIncrease)
 | 
			
		||||
      .abs();
 | 
			
		||||
 | 
			
		||||
    expect(usdcUserDataAfter.currentStableDebt).to.be.bignumber.equal(
 | 
			
		||||
      new BigNumber(usdcUserDataBefore.currentStableDebt)
 | 
			
		||||
        .minus(stableDebtRepaid)
 | 
			
		||||
        .plus(expectedStableDebtIncrease)
 | 
			
		||||
        .gte(0)
 | 
			
		||||
        ? new BigNumber(usdcUserDataBefore.currentStableDebt)
 | 
			
		||||
            .minus(stableDebtRepaid)
 | 
			
		||||
            .plus(expectedStableDebtIncrease)
 | 
			
		||||
            .toString()
 | 
			
		||||
        : '0',
 | 
			
		||||
      'INVALID_STABLE_DEBT_POSITION'
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    expect(wethUserDataAfter.currentATokenBalance).to.be.bignumber.equal(
 | 
			
		||||
      new BigNumber(wethUserDataBefore.currentATokenBalance).minus(
 | 
			
		||||
        expectedCollateralLiquidated.toString()
 | 
			
		||||
      ),
 | 
			
		||||
      'INVALID_COLLATERAL_POSITION'
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const eventsEmitted = txReceipt.events || [];
 | 
			
		||||
 | 
			
		||||
    expectRepayWithCollateralEvent(
 | 
			
		||||
      eventsEmitted,
 | 
			
		||||
      pool.address,
 | 
			
		||||
      weth.address,
 | 
			
		||||
      usdc.address,
 | 
			
		||||
      user.address
 | 
			
		||||
    );
 | 
			
		||||
    // Resets USDC Price
 | 
			
		||||
    await oracle.setAssetPrice(usdc.address, usdcPrice);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('User 3 deposits WETH and borrows USDC at Variable', async () => {
 | 
			
		||||
    const {pool, weth, usdc, users, oracle} = testEnv;
 | 
			
		||||
    const user = users[2];
 | 
			
		||||
    const amountToDeposit = parseEther('10');
 | 
			
		||||
 | 
			
		||||
    await weth.connect(user.signer).mint(amountToDeposit);
 | 
			
		||||
 | 
			
		||||
    await weth.connect(user.signer).approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL);
 | 
			
		||||
 | 
			
		||||
    await pool.connect(user.signer).deposit(weth.address, amountToDeposit, user.address, '0');
 | 
			
		||||
 | 
			
		||||
    const userGlobalData = await pool.getUserAccountData(user.address);
 | 
			
		||||
 | 
			
		||||
    const usdcPrice = await oracle.getAssetPrice(usdc.address);
 | 
			
		||||
 | 
			
		||||
    const amountUSDCToBorrow = await convertToCurrencyDecimals(
 | 
			
		||||
      usdc.address,
 | 
			
		||||
      new BigNumber(userGlobalData.availableBorrowsETH.toString())
 | 
			
		||||
        .div(usdcPrice.toString())
 | 
			
		||||
        .multipliedBy(0.95)
 | 
			
		||||
        .toFixed(0)
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    await pool.connect(user.signer).borrow(usdc.address, amountUSDCToBorrow, 2, 0, user.address);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('User 5 liquidates half the USDC loan of User 3 by swapping his WETH collateral', async () => {
 | 
			
		||||
    const {pool, weth, usdc, users, mockSwapAdapter, oracle, helpersContract} = testEnv;
 | 
			
		||||
    const user = users[2];
 | 
			
		||||
    const liquidator = users[4];
 | 
			
		||||
    // Sets USDC Price higher to decrease health factor below 1
 | 
			
		||||
    const usdcPrice = await oracle.getAssetPrice(usdc.address);
 | 
			
		||||
 | 
			
		||||
    await oracle.setAssetPrice(
 | 
			
		||||
      usdc.address,
 | 
			
		||||
      new BigNumber(usdcPrice.toString()).multipliedBy(1.15).toFixed(0)
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const userGlobalData = await pool.getUserAccountData(user.address);
 | 
			
		||||
 | 
			
		||||
    expect(userGlobalData.healthFactor.toString()).to.be.bignumber.lt(oneEther, INVALID_HF);
 | 
			
		||||
 | 
			
		||||
    const {userData: wethUserDataBefore} = await getContractsData(
 | 
			
		||||
      weth.address,
 | 
			
		||||
      user.address,
 | 
			
		||||
      testEnv
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const {
 | 
			
		||||
      reserveData: usdcReserveDataBefore,
 | 
			
		||||
      userData: usdcUserDataBefore,
 | 
			
		||||
    } = await getContractsData(usdc.address, user.address, testEnv);
 | 
			
		||||
 | 
			
		||||
    const amountToRepay = usdcReserveDataBefore.totalVariableDebt.dividedBy(2).toFixed(0);
 | 
			
		||||
 | 
			
		||||
    await mockSwapAdapter.setAmountToReturn(amountToRepay);
 | 
			
		||||
    await waitForTx(
 | 
			
		||||
      await pool
 | 
			
		||||
        .connect(liquidator.signer)
 | 
			
		||||
        .repayWithCollateral(
 | 
			
		||||
          weth.address,
 | 
			
		||||
          usdc.address,
 | 
			
		||||
          user.address,
 | 
			
		||||
          amountToRepay,
 | 
			
		||||
          mockSwapAdapter.address,
 | 
			
		||||
          '0x'
 | 
			
		||||
        )
 | 
			
		||||
    );
 | 
			
		||||
    const repayWithCollateralTimestamp = await timeLatest();
 | 
			
		||||
 | 
			
		||||
    const {userData: wethUserDataAfter} = await getContractsData(
 | 
			
		||||
      weth.address,
 | 
			
		||||
      user.address,
 | 
			
		||||
      testEnv
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const {userData: usdcUserDataAfter} = await getContractsData(
 | 
			
		||||
      usdc.address,
 | 
			
		||||
      user.address,
 | 
			
		||||
      testEnv
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const collateralPrice = await oracle.getAssetPrice(weth.address);
 | 
			
		||||
    const principalPrice = await oracle.getAssetPrice(usdc.address);
 | 
			
		||||
 | 
			
		||||
    const collateralDecimals = (
 | 
			
		||||
      await helpersContract.getReserveConfigurationData(weth.address)
 | 
			
		||||
    ).decimals.toString();
 | 
			
		||||
    const principalDecimals = (
 | 
			
		||||
      await helpersContract.getReserveConfigurationData(usdc.address)
 | 
			
		||||
    ).decimals.toString();
 | 
			
		||||
 | 
			
		||||
    const expectedCollateralLiquidated = new BigNumber(principalPrice.toString())
 | 
			
		||||
      .times(new BigNumber(amountToRepay.toString()).times(105))
 | 
			
		||||
      .times(new BigNumber(10).pow(collateralDecimals))
 | 
			
		||||
      .div(
 | 
			
		||||
        new BigNumber(collateralPrice.toString()).times(new BigNumber(10).pow(principalDecimals))
 | 
			
		||||
      )
 | 
			
		||||
      .div(100)
 | 
			
		||||
      .decimalPlaces(0, BigNumber.ROUND_DOWN);
 | 
			
		||||
 | 
			
		||||
    const expectedVariableDebtIncrease = calcExpectedVariableDebtTokenBalance(
 | 
			
		||||
      usdcReserveDataBefore,
 | 
			
		||||
      usdcUserDataBefore,
 | 
			
		||||
      new BigNumber(repayWithCollateralTimestamp)
 | 
			
		||||
    ).minus(usdcUserDataBefore.currentVariableDebt);
 | 
			
		||||
 | 
			
		||||
    expect(usdcUserDataAfter.currentVariableDebt).to.be.bignumber.almostEqual(
 | 
			
		||||
      new BigNumber(usdcUserDataBefore.currentVariableDebt)
 | 
			
		||||
        .minus(amountToRepay.toString())
 | 
			
		||||
        .plus(expectedVariableDebtIncrease)
 | 
			
		||||
        .toString(),
 | 
			
		||||
      'INVALID_DEBT_POSITION'
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    expect(wethUserDataAfter.currentATokenBalance).to.be.bignumber.almostEqual(
 | 
			
		||||
      new BigNumber(wethUserDataBefore.currentATokenBalance).minus(
 | 
			
		||||
        expectedCollateralLiquidated.toString()
 | 
			
		||||
      ),
 | 
			
		||||
      'INVALID_COLLATERAL_POSITION'
 | 
			
		||||
    );
 | 
			
		||||
    expect(wethUserDataAfter.usageAsCollateralEnabled).to.be.true;
 | 
			
		||||
 | 
			
		||||
    // Resets USDC Price
 | 
			
		||||
    await oracle.setAssetPrice(usdc.address, usdcPrice);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('Revert expected. User 5 tries to liquidate an User 3 collateral a currency he havent borrow', async () => {
 | 
			
		||||
    const {pool, weth, dai, users, oracle, mockSwapAdapter, usdc} = testEnv;
 | 
			
		||||
    const user = users[2];
 | 
			
		||||
    const liquidator = users[4];
 | 
			
		||||
 | 
			
		||||
    const amountToRepay = parseUnits('10', 6);
 | 
			
		||||
 | 
			
		||||
    // Sets USDC Price higher to decrease health factor below 1
 | 
			
		||||
    const usdcPrice = await oracle.getAssetPrice(usdc.address);
 | 
			
		||||
 | 
			
		||||
    await oracle.setAssetPrice(
 | 
			
		||||
      usdc.address,
 | 
			
		||||
      new BigNumber(usdcPrice.toString()).multipliedBy(6.4).toFixed(0)
 | 
			
		||||
    );
 | 
			
		||||
    const userGlobalData = await pool.getUserAccountData(user.address);
 | 
			
		||||
 | 
			
		||||
    expect(userGlobalData.healthFactor.toString()).to.be.bignumber.lt(oneEther, INVALID_HF);
 | 
			
		||||
 | 
			
		||||
    await expect(
 | 
			
		||||
      pool
 | 
			
		||||
        .connect(liquidator.signer)
 | 
			
		||||
        .repayWithCollateral(
 | 
			
		||||
          weth.address,
 | 
			
		||||
          dai.address,
 | 
			
		||||
          user.address,
 | 
			
		||||
          amountToRepay,
 | 
			
		||||
          mockSwapAdapter.address,
 | 
			
		||||
          '0x'
 | 
			
		||||
        )
 | 
			
		||||
    ).to.be.revertedWith('40');
 | 
			
		||||
 | 
			
		||||
    await oracle.setAssetPrice(usdc.address, usdcPrice);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('User 5 liquidates all the USDC loan of User 3 by swapping his WETH collateral', async () => {
 | 
			
		||||
    const {pool, weth, usdc, users, mockSwapAdapter, oracle, helpersContract} = testEnv;
 | 
			
		||||
    const user = users[2];
 | 
			
		||||
    const liquidator = users[4];
 | 
			
		||||
    // Sets USDC Price higher to decrease health factor below 1
 | 
			
		||||
    const usdcPrice = await oracle.getAssetPrice(usdc.address);
 | 
			
		||||
 | 
			
		||||
    await oracle.setAssetPrice(
 | 
			
		||||
      usdc.address,
 | 
			
		||||
      new BigNumber(usdcPrice.toString()).multipliedBy(1.35).toFixed(0)
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const userGlobalData = await pool.getUserAccountData(user.address);
 | 
			
		||||
 | 
			
		||||
    expect(userGlobalData.healthFactor.toString()).to.be.bignumber.lt(oneEther, INVALID_HF);
 | 
			
		||||
 | 
			
		||||
    const {userData: wethUserDataBefore} = await getContractsData(
 | 
			
		||||
      weth.address,
 | 
			
		||||
      user.address,
 | 
			
		||||
      testEnv
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const {
 | 
			
		||||
      reserveData: usdcReserveDataBefore,
 | 
			
		||||
      userData: usdcUserDataBefore,
 | 
			
		||||
    } = await getContractsData(usdc.address, user.address, testEnv);
 | 
			
		||||
 | 
			
		||||
    const amountToRepay = usdcReserveDataBefore.totalVariableDebt.toFixed(0);
 | 
			
		||||
 | 
			
		||||
    await mockSwapAdapter.setAmountToReturn(amountToRepay);
 | 
			
		||||
    await waitForTx(
 | 
			
		||||
      await pool
 | 
			
		||||
        .connect(liquidator.signer)
 | 
			
		||||
        .repayWithCollateral(
 | 
			
		||||
          weth.address,
 | 
			
		||||
          usdc.address,
 | 
			
		||||
          user.address,
 | 
			
		||||
          amountToRepay,
 | 
			
		||||
          mockSwapAdapter.address,
 | 
			
		||||
          '0x'
 | 
			
		||||
        )
 | 
			
		||||
    );
 | 
			
		||||
    const repayWithCollateralTimestamp = await timeLatest();
 | 
			
		||||
 | 
			
		||||
    const {userData: wethUserDataAfter} = await getContractsData(
 | 
			
		||||
      weth.address,
 | 
			
		||||
      user.address,
 | 
			
		||||
      testEnv
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const {userData: usdcUserDataAfter} = await getContractsData(
 | 
			
		||||
      usdc.address,
 | 
			
		||||
      user.address,
 | 
			
		||||
      testEnv
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const collateralPrice = await oracle.getAssetPrice(weth.address);
 | 
			
		||||
    const principalPrice = await oracle.getAssetPrice(usdc.address);
 | 
			
		||||
 | 
			
		||||
    const collateralDecimals = (
 | 
			
		||||
      await helpersContract.getReserveConfigurationData(weth.address)
 | 
			
		||||
    ).decimals.toString();
 | 
			
		||||
    const principalDecimals = (
 | 
			
		||||
      await helpersContract.getReserveConfigurationData(usdc.address)
 | 
			
		||||
    ).decimals.toString();
 | 
			
		||||
 | 
			
		||||
    const expectedCollateralLiquidated = new BigNumber(principalPrice.toString())
 | 
			
		||||
      .times(new BigNumber(amountToRepay.toString()).times(105))
 | 
			
		||||
      .times(new BigNumber(10).pow(collateralDecimals))
 | 
			
		||||
      .div(
 | 
			
		||||
        new BigNumber(collateralPrice.toString()).times(new BigNumber(10).pow(principalDecimals))
 | 
			
		||||
      )
 | 
			
		||||
      .div(100)
 | 
			
		||||
      .decimalPlaces(0, BigNumber.ROUND_DOWN);
 | 
			
		||||
 | 
			
		||||
    const expectedVariableDebtIncrease = calcExpectedVariableDebtTokenBalance(
 | 
			
		||||
      usdcReserveDataBefore,
 | 
			
		||||
      usdcUserDataBefore,
 | 
			
		||||
      new BigNumber(repayWithCollateralTimestamp)
 | 
			
		||||
    ).minus(usdcUserDataBefore.currentVariableDebt);
 | 
			
		||||
 | 
			
		||||
    expect(usdcUserDataAfter.currentVariableDebt).to.be.bignumber.almostEqual(
 | 
			
		||||
      new BigNumber(usdcUserDataBefore.currentVariableDebt)
 | 
			
		||||
        .minus(amountToRepay.toString())
 | 
			
		||||
        .plus(expectedVariableDebtIncrease)
 | 
			
		||||
        .toString(),
 | 
			
		||||
      'INVALID_DEBT_POSITION'
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    expect(wethUserDataAfter.currentATokenBalance).to.be.bignumber.equal(
 | 
			
		||||
      new BigNumber(wethUserDataBefore.currentATokenBalance).minus(
 | 
			
		||||
        expectedCollateralLiquidated.toString()
 | 
			
		||||
      ),
 | 
			
		||||
      'INVALID_COLLATERAL_POSITION'
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // Resets USDC Price
 | 
			
		||||
    await oracle.setAssetPrice(usdc.address, usdcPrice);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('User 2 deposit WETH and borrows DAI at Variable', async () => {
 | 
			
		||||
    const {pool, weth, dai, users, oracle} = testEnv;
 | 
			
		||||
    const user = users[1];
 | 
			
		||||
    const amountToDeposit = ethers.utils.parseEther('2');
 | 
			
		||||
 | 
			
		||||
    await weth.connect(user.signer).mint(amountToDeposit);
 | 
			
		||||
 | 
			
		||||
    await weth.connect(user.signer).approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL);
 | 
			
		||||
 | 
			
		||||
    await pool.connect(user.signer).deposit(weth.address, amountToDeposit, user.address, '0');
 | 
			
		||||
 | 
			
		||||
    const userGlobalData = await pool.getUserAccountData(user.address);
 | 
			
		||||
 | 
			
		||||
    const daiPrice = await oracle.getAssetPrice(dai.address);
 | 
			
		||||
 | 
			
		||||
    const amountDAIToBorrow = await convertToCurrencyDecimals(
 | 
			
		||||
      dai.address,
 | 
			
		||||
      new BigNumber(userGlobalData.availableBorrowsETH.toString())
 | 
			
		||||
        .div(daiPrice.toString())
 | 
			
		||||
        .multipliedBy(0.9)
 | 
			
		||||
        .toFixed(0)
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    await pool.connect(user.signer).borrow(dai.address, amountDAIToBorrow, 2, 0, user.address);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('It is not possible to do reentrancy on repayWithCollateral()', async () => {
 | 
			
		||||
    const {pool, weth, dai, users, mockSwapAdapter, oracle} = testEnv;
 | 
			
		||||
    const user = users[1];
 | 
			
		||||
    const liquidator = users[4];
 | 
			
		||||
 | 
			
		||||
    // Sets DAI Price higher to decrease health factor below 1
 | 
			
		||||
    const daiPrice = await oracle.getAssetPrice(dai.address);
 | 
			
		||||
 | 
			
		||||
    await oracle.setAssetPrice(
 | 
			
		||||
      dai.address,
 | 
			
		||||
      new BigNumber(daiPrice.toString()).multipliedBy(1.4).toFixed(0)
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const {reserveData: daiReserveDataBefore} = await getContractsData(
 | 
			
		||||
      dai.address,
 | 
			
		||||
      user.address,
 | 
			
		||||
      testEnv
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const amountToRepay = daiReserveDataBefore.totalVariableDebt.toString();
 | 
			
		||||
 | 
			
		||||
    await waitForTx(await mockSwapAdapter.setTryReentrancy(true));
 | 
			
		||||
 | 
			
		||||
    await mockSwapAdapter.setAmountToReturn(amountToRepay);
 | 
			
		||||
    await expect(
 | 
			
		||||
      pool
 | 
			
		||||
        .connect(liquidator.signer)
 | 
			
		||||
        .repayWithCollateral(
 | 
			
		||||
          weth.address,
 | 
			
		||||
          dai.address,
 | 
			
		||||
          user.address,
 | 
			
		||||
          amountToRepay,
 | 
			
		||||
          mockSwapAdapter.address,
 | 
			
		||||
          '0x'
 | 
			
		||||
        )
 | 
			
		||||
    ).to.be.revertedWith('53');
 | 
			
		||||
 | 
			
		||||
    // Resets DAI Price
 | 
			
		||||
    await oracle.setAssetPrice(dai.address, daiPrice);
 | 
			
		||||
    // Resets mock
 | 
			
		||||
    await waitForTx(await mockSwapAdapter.setTryReentrancy(false));
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('User 5 tries to liquidate  User 2 DAI Variable loan using his WETH collateral, with good HF', async () => {
 | 
			
		||||
    const {pool, weth, dai, users, mockSwapAdapter} = testEnv;
 | 
			
		||||
    const user = users[1];
 | 
			
		||||
    const liquidator = users[4];
 | 
			
		||||
 | 
			
		||||
    const {reserveData: daiReserveDataBefore} = await getContractsData(
 | 
			
		||||
      dai.address,
 | 
			
		||||
      user.address,
 | 
			
		||||
      testEnv
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // First half
 | 
			
		||||
    const amountToRepay = daiReserveDataBefore.totalVariableDebt.dividedBy(2).toString();
 | 
			
		||||
 | 
			
		||||
    await mockSwapAdapter.setAmountToReturn(amountToRepay);
 | 
			
		||||
    await expect(
 | 
			
		||||
      pool
 | 
			
		||||
        .connect(liquidator.signer)
 | 
			
		||||
        .repayWithCollateral(
 | 
			
		||||
          weth.address,
 | 
			
		||||
          dai.address,
 | 
			
		||||
          user.address,
 | 
			
		||||
          amountToRepay,
 | 
			
		||||
          mockSwapAdapter.address,
 | 
			
		||||
          '0x'
 | 
			
		||||
        )
 | 
			
		||||
    ).to.be.revertedWith('38');
 | 
			
		||||
  });
 | 
			
		||||
  it('User 5 liquidates User 2 DAI Variable loan using his WETH collateral, half the amount', async () => {
 | 
			
		||||
    const {pool, weth, dai, users, mockSwapAdapter, oracle, helpersContract} = testEnv;
 | 
			
		||||
    const user = users[1];
 | 
			
		||||
    const liquidator = users[4];
 | 
			
		||||
 | 
			
		||||
    // Sets DAI Price higher to decrease health factor below 1
 | 
			
		||||
    const daiPrice = await oracle.getAssetPrice(dai.address);
 | 
			
		||||
 | 
			
		||||
    await oracle.setAssetPrice(
 | 
			
		||||
      dai.address,
 | 
			
		||||
      new BigNumber(daiPrice.toString()).multipliedBy(1.4).toFixed(0)
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const userGlobalData = await pool.getUserAccountData(user.address);
 | 
			
		||||
 | 
			
		||||
    expect(userGlobalData.healthFactor.toString()).to.be.bignumber.lt(oneEther, INVALID_HF);
 | 
			
		||||
 | 
			
		||||
    const {userData: wethUserDataBefore} = await getContractsData(
 | 
			
		||||
      weth.address,
 | 
			
		||||
      user.address,
 | 
			
		||||
      testEnv
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const {reserveData: daiReserveDataBefore, userData: daiUserDataBefore} = await getContractsData(
 | 
			
		||||
      dai.address,
 | 
			
		||||
      user.address,
 | 
			
		||||
      testEnv
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // First half
 | 
			
		||||
    const amountToRepay = daiReserveDataBefore.totalVariableDebt
 | 
			
		||||
      .multipliedBy(0.6)
 | 
			
		||||
      .toFixed(0)
 | 
			
		||||
      .toString();
 | 
			
		||||
 | 
			
		||||
    await mockSwapAdapter.setAmountToReturn(amountToRepay);
 | 
			
		||||
    await waitForTx(
 | 
			
		||||
      await pool
 | 
			
		||||
        .connect(liquidator.signer)
 | 
			
		||||
        .repayWithCollateral(
 | 
			
		||||
          weth.address,
 | 
			
		||||
          dai.address,
 | 
			
		||||
          user.address,
 | 
			
		||||
          amountToRepay,
 | 
			
		||||
          mockSwapAdapter.address,
 | 
			
		||||
          '0x'
 | 
			
		||||
        )
 | 
			
		||||
    );
 | 
			
		||||
    const repayWithCollateralTimestamp = await timeLatest();
 | 
			
		||||
 | 
			
		||||
    const {userData: wethUserDataAfter} = await getContractsData(
 | 
			
		||||
      weth.address,
 | 
			
		||||
      user.address,
 | 
			
		||||
      testEnv
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const {userData: daiUserDataAfter} = await getContractsData(dai.address, user.address, testEnv);
 | 
			
		||||
 | 
			
		||||
    const collateralPrice = await oracle.getAssetPrice(weth.address);
 | 
			
		||||
    const principalPrice = await oracle.getAssetPrice(dai.address);
 | 
			
		||||
 | 
			
		||||
    const collateralDecimals = (
 | 
			
		||||
      await helpersContract.getReserveConfigurationData(weth.address)
 | 
			
		||||
    ).decimals.toString();
 | 
			
		||||
    const principalDecimals = (
 | 
			
		||||
      await helpersContract.getReserveConfigurationData(dai.address)
 | 
			
		||||
    ).decimals.toString();
 | 
			
		||||
 | 
			
		||||
    const expectedCollateralLiquidated = new BigNumber(principalPrice.toString())
 | 
			
		||||
      .times(new BigNumber(amountToRepay.toString()).times(105))
 | 
			
		||||
      .times(new BigNumber(10).pow(collateralDecimals))
 | 
			
		||||
      .div(
 | 
			
		||||
        new BigNumber(collateralPrice.toString()).times(new BigNumber(10).pow(principalDecimals))
 | 
			
		||||
      )
 | 
			
		||||
      .div(100)
 | 
			
		||||
      .decimalPlaces(0, BigNumber.ROUND_DOWN);
 | 
			
		||||
 | 
			
		||||
    const expectedVariableDebtIncrease = calcExpectedVariableDebtTokenBalance(
 | 
			
		||||
      daiReserveDataBefore,
 | 
			
		||||
      daiUserDataBefore,
 | 
			
		||||
      new BigNumber(repayWithCollateralTimestamp)
 | 
			
		||||
    ).minus(daiUserDataBefore.currentVariableDebt);
 | 
			
		||||
 | 
			
		||||
    expect(daiUserDataAfter.currentVariableDebt).to.be.bignumber.almostEqual(
 | 
			
		||||
      new BigNumber(daiUserDataBefore.currentVariableDebt)
 | 
			
		||||
        .minus(amountToRepay.toString())
 | 
			
		||||
        .plus(expectedVariableDebtIncrease)
 | 
			
		||||
        .toString()
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    expect(wethUserDataAfter.currentATokenBalance).to.be.bignumber.equal(
 | 
			
		||||
      new BigNumber(wethUserDataBefore.currentATokenBalance).minus(
 | 
			
		||||
        expectedCollateralLiquidated.toString()
 | 
			
		||||
      )
 | 
			
		||||
    );
 | 
			
		||||
    expect(wethUserDataAfter.usageAsCollateralEnabled).to.be.true;
 | 
			
		||||
 | 
			
		||||
    // Resets DAI price
 | 
			
		||||
    await oracle.setAssetPrice(dai.address, daiPrice);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('User 2 tries to repay remaining DAI Variable loan using his WETH collateral', async () => {
 | 
			
		||||
    const {pool, weth, dai, users, mockSwapAdapter, oracle, helpersContract} = testEnv;
 | 
			
		||||
    const user = users[1];
 | 
			
		||||
 | 
			
		||||
    const {userData: wethUserDataBefore} = await getContractsData(
 | 
			
		||||
      weth.address,
 | 
			
		||||
      user.address,
 | 
			
		||||
      testEnv
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const {reserveData: daiReserveDataBefore, userData: daiUserDataBefore} = await getContractsData(
 | 
			
		||||
      dai.address,
 | 
			
		||||
      user.address,
 | 
			
		||||
      testEnv
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    await increaseTime(1000);
 | 
			
		||||
    // Repay the remaining DAI
 | 
			
		||||
    const amountToRepay = daiReserveDataBefore.totalVariableDebt.toString();
 | 
			
		||||
 | 
			
		||||
    await mockSwapAdapter.setAmountToReturn(amountToRepay);
 | 
			
		||||
    const receipt = await waitForTx(
 | 
			
		||||
      await pool
 | 
			
		||||
        .connect(user.signer)
 | 
			
		||||
        .repayWithCollateral(
 | 
			
		||||
          weth.address,
 | 
			
		||||
          dai.address,
 | 
			
		||||
          user.address,
 | 
			
		||||
          amountToRepay,
 | 
			
		||||
          mockSwapAdapter.address,
 | 
			
		||||
          '0x'
 | 
			
		||||
        )
 | 
			
		||||
    );
 | 
			
		||||
    const repayWithCollateralTimestamp = (await BRE.ethers.provider.getBlock(receipt.blockNumber))
 | 
			
		||||
      .timestamp;
 | 
			
		||||
 | 
			
		||||
    const {userData: wethUserDataAfter} = await getContractsData(
 | 
			
		||||
      weth.address,
 | 
			
		||||
      user.address,
 | 
			
		||||
      testEnv
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const {userData: daiUserDataAfter} = await getContractsData(dai.address, user.address, testEnv);
 | 
			
		||||
 | 
			
		||||
    const collateralPrice = await oracle.getAssetPrice(weth.address);
 | 
			
		||||
    const principalPrice = await oracle.getAssetPrice(dai.address);
 | 
			
		||||
 | 
			
		||||
    const collateralDecimals = (
 | 
			
		||||
      await helpersContract.getReserveConfigurationData(weth.address)
 | 
			
		||||
    ).decimals.toString();
 | 
			
		||||
    const principalDecimals = (
 | 
			
		||||
      await helpersContract.getReserveConfigurationData(dai.address)
 | 
			
		||||
    ).decimals.toString();
 | 
			
		||||
 | 
			
		||||
    const expectedCollateralLiquidated = new BigNumber(principalPrice.toString())
 | 
			
		||||
      .times(new BigNumber(amountToRepay.toString()).times(105))
 | 
			
		||||
      .times(new BigNumber(10).pow(collateralDecimals))
 | 
			
		||||
      .div(
 | 
			
		||||
        new BigNumber(collateralPrice.toString()).times(new BigNumber(10).pow(principalDecimals))
 | 
			
		||||
      )
 | 
			
		||||
      .div(100)
 | 
			
		||||
      .decimalPlaces(0, BigNumber.ROUND_DOWN);
 | 
			
		||||
 | 
			
		||||
    const expectedVariableDebtIncrease = calcExpectedVariableDebtTokenBalance(
 | 
			
		||||
      daiReserveDataBefore,
 | 
			
		||||
      daiUserDataBefore,
 | 
			
		||||
      new BigNumber(repayWithCollateralTimestamp)
 | 
			
		||||
    ).minus(daiUserDataBefore.currentVariableDebt);
 | 
			
		||||
 | 
			
		||||
    expect(daiUserDataAfter.currentVariableDebt).to.be.bignumber.almostEqual(
 | 
			
		||||
      new BigNumber(daiUserDataBefore.currentVariableDebt)
 | 
			
		||||
        .minus(amountToRepay.toString())
 | 
			
		||||
        .plus(expectedVariableDebtIncrease)
 | 
			
		||||
        .toString()
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    expect(
 | 
			
		||||
      new BigNumber(wethUserDataBefore.currentATokenBalance).minus(
 | 
			
		||||
        expectedCollateralLiquidated.toString()
 | 
			
		||||
      )
 | 
			
		||||
    ).to.be.bignumber.equal(wethUserDataAfter.currentATokenBalance);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('Liquidator tries to repay 4 user a bigger amount that what can be swapped of a particular collateral, repaying only the maximum allowed by that collateral', async () => {
 | 
			
		||||
    const {pool, weth, dai, usdc, users, mockSwapAdapter, oracle, helpersContract} = testEnv;
 | 
			
		||||
    const user = users[3];
 | 
			
		||||
    const liquidator = users[5];
 | 
			
		||||
 | 
			
		||||
    const amountToDepositWeth = parseEther('0.1');
 | 
			
		||||
    const amountToDepositDAI = parseEther('500');
 | 
			
		||||
    const amountToBorrowVariable = parseUnits('80', '6');
 | 
			
		||||
 | 
			
		||||
    await weth.connect(user.signer).mint(amountToDepositWeth);
 | 
			
		||||
    await dai.connect(user.signer).mint(amountToDepositDAI);
 | 
			
		||||
    await weth.connect(user.signer).approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL);
 | 
			
		||||
    await dai.connect(user.signer).approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL);
 | 
			
		||||
 | 
			
		||||
    await pool.connect(user.signer).deposit(weth.address, amountToDepositWeth, user.address, '0');
 | 
			
		||||
    await pool.connect(user.signer).deposit(dai.address, amountToDepositDAI, user.address, '0');
 | 
			
		||||
 | 
			
		||||
    await pool
 | 
			
		||||
      .connect(user.signer)
 | 
			
		||||
      .borrow(usdc.address, amountToBorrowVariable, 2, 0, user.address);
 | 
			
		||||
 | 
			
		||||
    const amountToRepay = amountToBorrowVariable;
 | 
			
		||||
 | 
			
		||||
    const {userData: wethUserDataBefore} = await getContractsData(
 | 
			
		||||
      weth.address,
 | 
			
		||||
      user.address,
 | 
			
		||||
      testEnv
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const {
 | 
			
		||||
      reserveData: usdcReserveDataBefore,
 | 
			
		||||
      userData: usdcUserDataBefore,
 | 
			
		||||
    } = await getContractsData(usdc.address, user.address, testEnv);
 | 
			
		||||
 | 
			
		||||
    // Set HF below 1
 | 
			
		||||
    const daiPrice = await oracle.getAssetPrice(dai.address);
 | 
			
		||||
    await oracle.setAssetPrice(
 | 
			
		||||
      dai.address,
 | 
			
		||||
      new BigNumber(daiPrice.toString()).multipliedBy(0.1).toFixed(0)
 | 
			
		||||
    );
 | 
			
		||||
    const userGlobalDataPrior = await pool.getUserAccountData(user.address);
 | 
			
		||||
    expect(userGlobalDataPrior.healthFactor.toString()).to.be.bignumber.lt(oneEther, INVALID_HF);
 | 
			
		||||
 | 
			
		||||
    // Execute liquidation
 | 
			
		||||
    await mockSwapAdapter.setAmountToReturn(amountToRepay);
 | 
			
		||||
    await waitForTx(
 | 
			
		||||
      await pool
 | 
			
		||||
        .connect(liquidator.signer)
 | 
			
		||||
        .repayWithCollateral(
 | 
			
		||||
          weth.address,
 | 
			
		||||
          usdc.address,
 | 
			
		||||
          user.address,
 | 
			
		||||
          amountToRepay,
 | 
			
		||||
          mockSwapAdapter.address,
 | 
			
		||||
          '0x'
 | 
			
		||||
        )
 | 
			
		||||
    );
 | 
			
		||||
    const repayWithCollateralTimestamp = await timeLatest();
 | 
			
		||||
 | 
			
		||||
    const {userData: wethUserDataAfter} = await getContractsData(
 | 
			
		||||
      weth.address,
 | 
			
		||||
      user.address,
 | 
			
		||||
      testEnv
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const {userData: usdcUserDataAfter} = await getContractsData(
 | 
			
		||||
      usdc.address,
 | 
			
		||||
      user.address,
 | 
			
		||||
      testEnv
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const collateralPrice = await oracle.getAssetPrice(weth.address);
 | 
			
		||||
    const principalPrice = await oracle.getAssetPrice(usdc.address);
 | 
			
		||||
 | 
			
		||||
    const collateralConfig = await helpersContract.getReserveConfigurationData(weth.address);
 | 
			
		||||
 | 
			
		||||
    const collateralDecimals = collateralConfig.decimals.toString();
 | 
			
		||||
    const principalDecimals = (
 | 
			
		||||
      await helpersContract.getReserveConfigurationData(usdc.address)
 | 
			
		||||
    ).decimals.toString();
 | 
			
		||||
    const collateralLiquidationBonus = collateralConfig.liquidationBonus.toString();
 | 
			
		||||
 | 
			
		||||
    const expectedDebtCovered = new BigNumber(collateralPrice.toString())
 | 
			
		||||
      .times(new BigNumber(wethUserDataBefore.currentATokenBalance.toString()))
 | 
			
		||||
      .times(new BigNumber(10).pow(principalDecimals))
 | 
			
		||||
      .div(
 | 
			
		||||
        new BigNumber(principalPrice.toString()).times(new BigNumber(10).pow(collateralDecimals))
 | 
			
		||||
      )
 | 
			
		||||
      .div(new BigNumber(collateralLiquidationBonus).div(10000).toString())
 | 
			
		||||
      .decimalPlaces(0, BigNumber.ROUND_DOWN);
 | 
			
		||||
 | 
			
		||||
    const expectedVariableDebtIncrease = calcExpectedVariableDebtTokenBalance(
 | 
			
		||||
      usdcReserveDataBefore,
 | 
			
		||||
      usdcUserDataBefore,
 | 
			
		||||
      new BigNumber(repayWithCollateralTimestamp)
 | 
			
		||||
    ).minus(usdcUserDataBefore.currentVariableDebt);
 | 
			
		||||
 | 
			
		||||
    expect(usdcUserDataAfter.currentVariableDebt).to.be.bignumber.almostEqual(
 | 
			
		||||
      new BigNumber(usdcUserDataBefore.currentVariableDebt)
 | 
			
		||||
        .minus(expectedDebtCovered.toString())
 | 
			
		||||
        .plus(expectedVariableDebtIncrease),
 | 
			
		||||
      'INVALID_VARIABLE_DEBT_POSITION'
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    expect(wethUserDataAfter.usageAsCollateralEnabled).to.be.false;
 | 
			
		||||
 | 
			
		||||
    expect(wethUserDataAfter.currentATokenBalance).to.be.bignumber.equal(0);
 | 
			
		||||
 | 
			
		||||
    // Resets DAI Price
 | 
			
		||||
    await oracle.setAssetPrice(dai.address, daiPrice);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('User 4 deposits WETH, LEND and DAI, then borrows USDC at Variable, then disables WETH as collateral', async () => {
 | 
			
		||||
    const {pool, weth, dai, usdc, users} = testEnv;
 | 
			
		||||
    const user = users[4];
 | 
			
		||||
    const amountWETHToDeposit = parseEther('10');
 | 
			
		||||
    const amountDAIToDeposit = parseEther('100');
 | 
			
		||||
 | 
			
		||||
    const amountToBorrow = parseUnits('75', 6);
 | 
			
		||||
 | 
			
		||||
    await weth.connect(user.signer).mint(amountWETHToDeposit);
 | 
			
		||||
    await weth.connect(user.signer).approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL);
 | 
			
		||||
    await pool.connect(user.signer).deposit(weth.address, amountWETHToDeposit, user.address, '0');
 | 
			
		||||
 | 
			
		||||
    await dai.connect(user.signer).mint(amountDAIToDeposit);
 | 
			
		||||
    await dai.connect(user.signer).approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL);
 | 
			
		||||
    await pool.connect(user.signer).deposit(dai.address, amountDAIToDeposit, user.address, '0');
 | 
			
		||||
 | 
			
		||||
    await pool.connect(user.signer).borrow(usdc.address, amountToBorrow, 2, 0, user.address);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('Liquidator tries to liquidate User 5 USDC loan by swapping his WETH collateral, should revert due WETH collateral disabled', async () => {
 | 
			
		||||
    const {pool, weth, dai, usdc, users, mockSwapAdapter, oracle} = testEnv;
 | 
			
		||||
    const user = users[4];
 | 
			
		||||
    const liquidator = users[5];
 | 
			
		||||
 | 
			
		||||
    const amountToRepay = parseUnits('65', 6);
 | 
			
		||||
 | 
			
		||||
    // User 5 Disable WETH as collateral
 | 
			
		||||
    await pool.connect(user.signer).setUserUseReserveAsCollateral(weth.address, false);
 | 
			
		||||
 | 
			
		||||
    const {userData: wethUserDataBefore} = await getContractsData(
 | 
			
		||||
      weth.address,
 | 
			
		||||
      user.address,
 | 
			
		||||
      testEnv
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const {
 | 
			
		||||
      reserveData: usdcReserveDataBefore,
 | 
			
		||||
      userData: usdcUserDataBefore,
 | 
			
		||||
    } = await getContractsData(usdc.address, user.address, testEnv);
 | 
			
		||||
 | 
			
		||||
    expect(wethUserDataBefore.usageAsCollateralEnabled).to.be.false;
 | 
			
		||||
 | 
			
		||||
    //drop the price to set the HF below 1
 | 
			
		||||
    const daiPrice = await oracle.getAssetPrice(dai.address);
 | 
			
		||||
 | 
			
		||||
    await oracle.setAssetPrice(
 | 
			
		||||
      dai.address,
 | 
			
		||||
      new BigNumber(daiPrice.toString()).multipliedBy(0.9).toFixed(0)
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // Liquidator should NOT be able to liquidate himself with WETH, even if is disabled
 | 
			
		||||
    await mockSwapAdapter.setAmountToReturn(amountToRepay);
 | 
			
		||||
    await expect(
 | 
			
		||||
      pool
 | 
			
		||||
        .connect(liquidator.signer)
 | 
			
		||||
        .repayWithCollateral(
 | 
			
		||||
          weth.address,
 | 
			
		||||
          usdc.address,
 | 
			
		||||
          user.address,
 | 
			
		||||
          amountToRepay,
 | 
			
		||||
          mockSwapAdapter.address,
 | 
			
		||||
          '0x'
 | 
			
		||||
        )
 | 
			
		||||
    ).to.be.revertedWith(COLLATERAL_CANNOT_BE_LIQUIDATED);
 | 
			
		||||
 | 
			
		||||
    const repayWithCollateralTimestamp = await timeLatest();
 | 
			
		||||
 | 
			
		||||
    const {userData: wethUserDataAfter} = await getContractsData(
 | 
			
		||||
      weth.address,
 | 
			
		||||
      user.address,
 | 
			
		||||
      testEnv
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const {userData: usdcUserDataAfter} = await getContractsData(
 | 
			
		||||
      usdc.address,
 | 
			
		||||
      user.address,
 | 
			
		||||
      testEnv
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const expectedVariableDebtIncrease = calcExpectedVariableDebtTokenBalance(
 | 
			
		||||
      usdcReserveDataBefore,
 | 
			
		||||
      usdcUserDataBefore,
 | 
			
		||||
      new BigNumber(repayWithCollateralTimestamp)
 | 
			
		||||
    ).minus(usdcUserDataBefore.currentVariableDebt);
 | 
			
		||||
 | 
			
		||||
    expect(usdcUserDataAfter.currentVariableDebt).to.be.bignumber.almostEqual(
 | 
			
		||||
      new BigNumber(usdcUserDataBefore.currentVariableDebt)
 | 
			
		||||
        .plus(expectedVariableDebtIncrease)
 | 
			
		||||
        .toString(),
 | 
			
		||||
      'INVALID_DEBT_POSITION'
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    expect(wethUserDataAfter.usageAsCollateralEnabled).to.be.false;
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			@ -155,22 +155,6 @@ makeSuite('Pausable Pool', (testEnv: TestEnv) => {
 | 
			
		|||
    await configurator.setPoolPause(false);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('Swap liquidity', async () => {
 | 
			
		||||
    const {pool, dai, weth, users, configurator} = testEnv;
 | 
			
		||||
 | 
			
		||||
    const user = users[1];
 | 
			
		||||
    // Pause the pool
 | 
			
		||||
    await configurator.setPoolPause(true);
 | 
			
		||||
 | 
			
		||||
    // Try to execute liquidation
 | 
			
		||||
    await expect(
 | 
			
		||||
      pool.connect(user.signer).swapLiquidity(user.address, dai.address, weth.address, '1', '0x')
 | 
			
		||||
    ).revertedWith(IS_PAUSED);
 | 
			
		||||
 | 
			
		||||
    // Unpause the pool
 | 
			
		||||
    await configurator.setPoolPause(false);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('Repay', async () => {
 | 
			
		||||
    const {pool, dai, users, configurator} = testEnv;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -187,32 +171,6 @@ makeSuite('Pausable Pool', (testEnv: TestEnv) => {
 | 
			
		|||
    await configurator.setPoolPause(false);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('Repay with collateral', async () => {
 | 
			
		||||
    const {pool, weth, dai, usdc, users, mockSwapAdapter, oracle, configurator} = testEnv;
 | 
			
		||||
    const user = users[6];
 | 
			
		||||
    const liquidator = users[5];
 | 
			
		||||
 | 
			
		||||
    // Pause the pool
 | 
			
		||||
    await configurator.setPoolPause(true);
 | 
			
		||||
 | 
			
		||||
    // Try to execute liquidation
 | 
			
		||||
    await expect(
 | 
			
		||||
      pool
 | 
			
		||||
        .connect(liquidator.signer)
 | 
			
		||||
        .repayWithCollateral(
 | 
			
		||||
          weth.address,
 | 
			
		||||
          usdc.address,
 | 
			
		||||
          user.address,
 | 
			
		||||
          '1',
 | 
			
		||||
          mockSwapAdapter.address,
 | 
			
		||||
          '0x'
 | 
			
		||||
        )
 | 
			
		||||
    ).revertedWith(IS_PAUSED);
 | 
			
		||||
 | 
			
		||||
    // Unpause the pool
 | 
			
		||||
    await configurator.setPoolPause(false);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('Flash loan', async () => {
 | 
			
		||||
    const {dai, pool, weth, users, configurator} = testEnv;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,682 +0,0 @@
 | 
			
		|||
import {TestEnv, makeSuite} from './helpers/make-suite';
 | 
			
		||||
import {APPROVAL_AMOUNT_LENDING_POOL} from '../helpers/constants';
 | 
			
		||||
import {ethers} from 'ethers';
 | 
			
		||||
import BigNumber from 'bignumber.js';
 | 
			
		||||
import {
 | 
			
		||||
  calcExpectedVariableDebtTokenBalance,
 | 
			
		||||
  calcExpectedStableDebtTokenBalance,
 | 
			
		||||
} from './helpers/utils/calculations';
 | 
			
		||||
import {getContractsData} from './helpers/actions';
 | 
			
		||||
import {timeLatest, waitForTx} from '../helpers/misc-utils';
 | 
			
		||||
import {ProtocolErrors, tEthereumAddress} from '../helpers/types';
 | 
			
		||||
 | 
			
		||||
const {expect} = require('chai');
 | 
			
		||||
const {parseUnits, parseEther} = ethers.utils;
 | 
			
		||||
 | 
			
		||||
export const expectRepayWithCollateralEvent = (
 | 
			
		||||
  events: ethers.Event[],
 | 
			
		||||
  pool: tEthereumAddress,
 | 
			
		||||
  collateral: tEthereumAddress,
 | 
			
		||||
  borrowing: tEthereumAddress,
 | 
			
		||||
  user: tEthereumAddress
 | 
			
		||||
) => {
 | 
			
		||||
  if (!events || events.length < 16) {
 | 
			
		||||
    expect(false, 'INVALID_EVENTS_LENGTH_ON_REPAY_COLLATERAL');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const repayWithCollateralEvent = events[15];
 | 
			
		||||
 | 
			
		||||
  expect(repayWithCollateralEvent.address).to.be.equal(pool);
 | 
			
		||||
  expect(`0x${repayWithCollateralEvent.topics[1].slice(26)}`.toLowerCase()).to.be.equal(
 | 
			
		||||
    collateral.toLowerCase()
 | 
			
		||||
  );
 | 
			
		||||
  expect(`0x${repayWithCollateralEvent.topics[2].slice(26)}`).to.be.equal(borrowing.toLowerCase());
 | 
			
		||||
  expect(`0x${repayWithCollateralEvent.topics[3].slice(26)}`.toLowerCase()).to.be.equal(
 | 
			
		||||
    user.toLowerCase()
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
makeSuite('LendingPool. repayWithCollateral()', (testEnv: TestEnv) => {
 | 
			
		||||
  const {IS_PAUSED} = ProtocolErrors;
 | 
			
		||||
  it("It's not possible to repayWithCollateral() on a non-active collateral or a non active principal", async () => {
 | 
			
		||||
    const {configurator, weth, pool, users, dai, mockSwapAdapter} = testEnv;
 | 
			
		||||
    const user = users[1];
 | 
			
		||||
    await configurator.deactivateReserve(weth.address);
 | 
			
		||||
 | 
			
		||||
    await expect(
 | 
			
		||||
      pool
 | 
			
		||||
        .connect(user.signer)
 | 
			
		||||
        .repayWithCollateral(
 | 
			
		||||
          weth.address,
 | 
			
		||||
          dai.address,
 | 
			
		||||
          user.address,
 | 
			
		||||
          parseEther('100'),
 | 
			
		||||
          mockSwapAdapter.address,
 | 
			
		||||
          '0x'
 | 
			
		||||
        )
 | 
			
		||||
    ).to.be.revertedWith('2');
 | 
			
		||||
 | 
			
		||||
    await configurator.activateReserve(weth.address);
 | 
			
		||||
 | 
			
		||||
    await configurator.deactivateReserve(dai.address);
 | 
			
		||||
 | 
			
		||||
    await expect(
 | 
			
		||||
      pool
 | 
			
		||||
        .connect(user.signer)
 | 
			
		||||
        .repayWithCollateral(
 | 
			
		||||
          weth.address,
 | 
			
		||||
          dai.address,
 | 
			
		||||
          user.address,
 | 
			
		||||
          parseEther('100'),
 | 
			
		||||
          mockSwapAdapter.address,
 | 
			
		||||
          '0x'
 | 
			
		||||
        )
 | 
			
		||||
    ).to.be.revertedWith('2');
 | 
			
		||||
 | 
			
		||||
    await configurator.activateReserve(dai.address);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('User 1 provides some liquidity for others to borrow', async () => {
 | 
			
		||||
    const {pool, weth, dai, usdc, deployer} = testEnv;
 | 
			
		||||
 | 
			
		||||
    await weth.mint(parseEther('200'));
 | 
			
		||||
    await weth.approve(pool.address, parseEther('200'));
 | 
			
		||||
    await pool.deposit(weth.address, parseEther('200'), deployer.address, 0);
 | 
			
		||||
    await dai.mint(parseEther('20000'));
 | 
			
		||||
    await dai.approve(pool.address, parseEther('20000'));
 | 
			
		||||
    await pool.deposit(dai.address, parseEther('20000'), deployer.address, 0);
 | 
			
		||||
    await usdc.mint(parseEther('20000'));
 | 
			
		||||
    await usdc.approve(pool.address, parseEther('20000'));
 | 
			
		||||
    await pool.deposit(usdc.address, parseEther('20000'), deployer.address, 0);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('User 2 deposit WETH and borrows DAI at Variable', async () => {
 | 
			
		||||
    const {pool, weth, dai, users} = testEnv;
 | 
			
		||||
    const user = users[1];
 | 
			
		||||
    const amountToDeposit = ethers.utils.parseEther('1');
 | 
			
		||||
    const amountToBorrow = ethers.utils.parseEther('20');
 | 
			
		||||
 | 
			
		||||
    await weth.connect(user.signer).mint(amountToDeposit);
 | 
			
		||||
 | 
			
		||||
    await weth.connect(user.signer).approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL);
 | 
			
		||||
 | 
			
		||||
    await pool.connect(user.signer).deposit(weth.address, amountToDeposit, user.address, '0');
 | 
			
		||||
 | 
			
		||||
    await pool.connect(user.signer).borrow(dai.address, amountToBorrow, 2, 0, user.address);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('It is not possible to do reentrancy on repayWithCollateral()', async () => {
 | 
			
		||||
    const {pool, weth, dai, users, mockSwapAdapter, oracle} = testEnv;
 | 
			
		||||
    const user = users[1];
 | 
			
		||||
 | 
			
		||||
    const amountToRepay = parseEther('10');
 | 
			
		||||
 | 
			
		||||
    await waitForTx(await mockSwapAdapter.setTryReentrancy(true));
 | 
			
		||||
 | 
			
		||||
    await mockSwapAdapter.setAmountToReturn(amountToRepay);
 | 
			
		||||
    await expect(
 | 
			
		||||
      pool
 | 
			
		||||
        .connect(user.signer)
 | 
			
		||||
        .repayWithCollateral(
 | 
			
		||||
          weth.address,
 | 
			
		||||
          dai.address,
 | 
			
		||||
          user.address,
 | 
			
		||||
          amountToRepay,
 | 
			
		||||
          mockSwapAdapter.address,
 | 
			
		||||
          '0x'
 | 
			
		||||
        )
 | 
			
		||||
    ).to.be.revertedWith('53');
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('User 2 tries to repay his DAI Variable loan using his WETH collateral. First half the amount, after that, the rest', async () => {
 | 
			
		||||
    const {pool, weth, dai, users, mockSwapAdapter, oracle, helpersContract} = testEnv;
 | 
			
		||||
    const user = users[1];
 | 
			
		||||
 | 
			
		||||
    const amountToRepay = parseEther('10');
 | 
			
		||||
 | 
			
		||||
    await waitForTx(await mockSwapAdapter.setTryReentrancy(false));
 | 
			
		||||
 | 
			
		||||
    const {userData: wethUserDataBefore} = await getContractsData(
 | 
			
		||||
      weth.address,
 | 
			
		||||
      user.address,
 | 
			
		||||
      testEnv
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const {reserveData: daiReserveDataBefore, userData: daiUserDataBefore} = await getContractsData(
 | 
			
		||||
      dai.address,
 | 
			
		||||
      user.address,
 | 
			
		||||
      testEnv
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    await mockSwapAdapter.setAmountToReturn(amountToRepay);
 | 
			
		||||
    await waitForTx(
 | 
			
		||||
      await pool
 | 
			
		||||
        .connect(user.signer)
 | 
			
		||||
        .repayWithCollateral(
 | 
			
		||||
          weth.address,
 | 
			
		||||
          dai.address,
 | 
			
		||||
          user.address,
 | 
			
		||||
          amountToRepay,
 | 
			
		||||
          mockSwapAdapter.address,
 | 
			
		||||
          '0x'
 | 
			
		||||
        )
 | 
			
		||||
    );
 | 
			
		||||
    const repayWithCollateralTimestamp = await timeLatest();
 | 
			
		||||
 | 
			
		||||
    const {userData: wethUserDataAfter} = await getContractsData(
 | 
			
		||||
      weth.address,
 | 
			
		||||
      user.address,
 | 
			
		||||
      testEnv
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const {userData: daiUserDataAfter} = await getContractsData(dai.address, user.address, testEnv);
 | 
			
		||||
 | 
			
		||||
    const collateralPrice = await oracle.getAssetPrice(weth.address);
 | 
			
		||||
    const principalPrice = await oracle.getAssetPrice(dai.address);
 | 
			
		||||
 | 
			
		||||
    const collateralDecimals = (
 | 
			
		||||
      await helpersContract.getReserveConfigurationData(weth.address)
 | 
			
		||||
    ).decimals.toString();
 | 
			
		||||
    const principalDecimals = (
 | 
			
		||||
      await helpersContract.getReserveConfigurationData(dai.address)
 | 
			
		||||
    ).decimals.toString();
 | 
			
		||||
 | 
			
		||||
    const expectedCollateralLiquidated = new BigNumber(principalPrice.toString())
 | 
			
		||||
      .times(new BigNumber(amountToRepay.toString()).times(105))
 | 
			
		||||
      .times(new BigNumber(10).pow(collateralDecimals))
 | 
			
		||||
      .div(
 | 
			
		||||
        new BigNumber(collateralPrice.toString()).times(new BigNumber(10).pow(principalDecimals))
 | 
			
		||||
      )
 | 
			
		||||
      .div(100)
 | 
			
		||||
      .decimalPlaces(0, BigNumber.ROUND_DOWN);
 | 
			
		||||
 | 
			
		||||
    const expectedVariableDebtIncrease = calcExpectedVariableDebtTokenBalance(
 | 
			
		||||
      daiReserveDataBefore,
 | 
			
		||||
      daiUserDataBefore,
 | 
			
		||||
      new BigNumber(repayWithCollateralTimestamp)
 | 
			
		||||
    ).minus(daiUserDataBefore.currentVariableDebt);
 | 
			
		||||
 | 
			
		||||
    expect(daiUserDataAfter.currentVariableDebt).to.be.bignumber.almostEqual(
 | 
			
		||||
      new BigNumber(daiUserDataBefore.currentVariableDebt)
 | 
			
		||||
        .minus(amountToRepay.toString())
 | 
			
		||||
        .plus(expectedVariableDebtIncrease)
 | 
			
		||||
        .toString()
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    expect(wethUserDataAfter.currentATokenBalance).to.be.bignumber.equal(
 | 
			
		||||
      new BigNumber(wethUserDataBefore.currentATokenBalance).minus(
 | 
			
		||||
        expectedCollateralLiquidated.toString()
 | 
			
		||||
      )
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    expect(wethUserDataAfter.usageAsCollateralEnabled).to.be.true;
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('User 3 deposits WETH and borrows USDC at Variable', async () => {
 | 
			
		||||
    const {pool, weth, usdc, users} = testEnv;
 | 
			
		||||
    const user = users[2];
 | 
			
		||||
    const amountToDeposit = parseEther('10');
 | 
			
		||||
    const amountToBorrow = parseUnits('40', 6);
 | 
			
		||||
 | 
			
		||||
    await weth.connect(user.signer).mint(amountToDeposit);
 | 
			
		||||
 | 
			
		||||
    await weth.connect(user.signer).approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL);
 | 
			
		||||
 | 
			
		||||
    await pool.connect(user.signer).deposit(weth.address, amountToDeposit, user.address, '0');
 | 
			
		||||
 | 
			
		||||
    await pool.connect(user.signer).borrow(usdc.address, amountToBorrow, 2, 0, user.address);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('User 3 repays completely his USDC loan by swapping his WETH collateral', async () => {
 | 
			
		||||
    const {pool, weth, usdc, users, mockSwapAdapter, oracle, helpersContract} = testEnv;
 | 
			
		||||
    const user = users[2];
 | 
			
		||||
 | 
			
		||||
    const amountToRepay = parseUnits('10', 6);
 | 
			
		||||
 | 
			
		||||
    const {userData: wethUserDataBefore} = await getContractsData(
 | 
			
		||||
      weth.address,
 | 
			
		||||
      user.address,
 | 
			
		||||
      testEnv
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const {
 | 
			
		||||
      reserveData: usdcReserveDataBefore,
 | 
			
		||||
      userData: usdcUserDataBefore,
 | 
			
		||||
    } = await getContractsData(usdc.address, user.address, testEnv);
 | 
			
		||||
 | 
			
		||||
    await mockSwapAdapter.setAmountToReturn(amountToRepay);
 | 
			
		||||
    await waitForTx(
 | 
			
		||||
      await pool
 | 
			
		||||
        .connect(user.signer)
 | 
			
		||||
        .repayWithCollateral(
 | 
			
		||||
          weth.address,
 | 
			
		||||
          usdc.address,
 | 
			
		||||
          user.address,
 | 
			
		||||
          amountToRepay,
 | 
			
		||||
          mockSwapAdapter.address,
 | 
			
		||||
          '0x'
 | 
			
		||||
        )
 | 
			
		||||
    );
 | 
			
		||||
    const repayWithCollateralTimestamp = await timeLatest();
 | 
			
		||||
 | 
			
		||||
    const {userData: wethUserDataAfter} = await getContractsData(
 | 
			
		||||
      weth.address,
 | 
			
		||||
      user.address,
 | 
			
		||||
      testEnv
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const {userData: usdcUserDataAfter} = await getContractsData(
 | 
			
		||||
      usdc.address,
 | 
			
		||||
      user.address,
 | 
			
		||||
      testEnv
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const collateralPrice = await oracle.getAssetPrice(weth.address);
 | 
			
		||||
    const principalPrice = await oracle.getAssetPrice(usdc.address);
 | 
			
		||||
 | 
			
		||||
    const collateralDecimals = (
 | 
			
		||||
      await helpersContract.getReserveConfigurationData(weth.address)
 | 
			
		||||
    ).decimals.toString();
 | 
			
		||||
    const principalDecimals = (
 | 
			
		||||
      await helpersContract.getReserveConfigurationData(usdc.address)
 | 
			
		||||
    ).decimals.toString();
 | 
			
		||||
 | 
			
		||||
    const expectedCollateralLiquidated = new BigNumber(principalPrice.toString())
 | 
			
		||||
      .times(new BigNumber(amountToRepay.toString()).times(105))
 | 
			
		||||
      .times(new BigNumber(10).pow(collateralDecimals))
 | 
			
		||||
      .div(
 | 
			
		||||
        new BigNumber(collateralPrice.toString()).times(new BigNumber(10).pow(principalDecimals))
 | 
			
		||||
      )
 | 
			
		||||
      .div(100)
 | 
			
		||||
      .decimalPlaces(0, BigNumber.ROUND_DOWN);
 | 
			
		||||
 | 
			
		||||
    const expectedVariableDebtIncrease = calcExpectedVariableDebtTokenBalance(
 | 
			
		||||
      usdcReserveDataBefore,
 | 
			
		||||
      usdcUserDataBefore,
 | 
			
		||||
      new BigNumber(repayWithCollateralTimestamp)
 | 
			
		||||
    ).minus(usdcUserDataBefore.currentVariableDebt);
 | 
			
		||||
 | 
			
		||||
    expect(usdcUserDataAfter.currentVariableDebt).to.be.bignumber.almostEqual(
 | 
			
		||||
      new BigNumber(usdcUserDataBefore.currentVariableDebt)
 | 
			
		||||
        .minus(amountToRepay.toString())
 | 
			
		||||
        .plus(expectedVariableDebtIncrease)
 | 
			
		||||
        .toString(),
 | 
			
		||||
      'INVALID_DEBT_POSITION'
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    expect(wethUserDataAfter.currentATokenBalance).to.be.bignumber.equal(
 | 
			
		||||
      new BigNumber(wethUserDataBefore.currentATokenBalance).minus(
 | 
			
		||||
        expectedCollateralLiquidated.toString()
 | 
			
		||||
      ),
 | 
			
		||||
      'INVALID_COLLATERAL_POSITION'
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    expect(wethUserDataAfter.usageAsCollateralEnabled).to.be.true;
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('Revert expected. User 3 tries to repay with his collateral a currency he havent borrow', async () => {
 | 
			
		||||
    const {pool, weth, dai, users, mockSwapAdapter} = testEnv;
 | 
			
		||||
    const user = users[2];
 | 
			
		||||
 | 
			
		||||
    const amountToRepay = parseUnits('10', 6);
 | 
			
		||||
 | 
			
		||||
    await expect(
 | 
			
		||||
      pool
 | 
			
		||||
        .connect(user.signer)
 | 
			
		||||
        .repayWithCollateral(
 | 
			
		||||
          weth.address,
 | 
			
		||||
          dai.address,
 | 
			
		||||
          user.address,
 | 
			
		||||
          amountToRepay,
 | 
			
		||||
          mockSwapAdapter.address,
 | 
			
		||||
          '0x'
 | 
			
		||||
        )
 | 
			
		||||
    ).to.be.revertedWith('40');
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('User 3 tries to repay with his collateral all his variable debt and part of the stable', async () => {
 | 
			
		||||
    const {pool, weth, usdc, users, mockSwapAdapter, oracle, helpersContract} = testEnv;
 | 
			
		||||
    const user = users[2];
 | 
			
		||||
 | 
			
		||||
    const amountToDeposit = parseEther('20');
 | 
			
		||||
    const amountToBorrowStable = parseUnits('40', 6);
 | 
			
		||||
    const amountToBorrowVariable = parseUnits('40', 6);
 | 
			
		||||
 | 
			
		||||
    await weth.connect(user.signer).mint(amountToDeposit);
 | 
			
		||||
 | 
			
		||||
    await pool.connect(user.signer).deposit(weth.address, amountToDeposit, user.address, '0');
 | 
			
		||||
 | 
			
		||||
    await pool
 | 
			
		||||
      .connect(user.signer)
 | 
			
		||||
      .borrow(usdc.address, amountToBorrowVariable, 2, 0, user.address);
 | 
			
		||||
 | 
			
		||||
    await pool.connect(user.signer).borrow(usdc.address, amountToBorrowStable, 1, 0, user.address);
 | 
			
		||||
 | 
			
		||||
    const amountToRepay = parseUnits('80', 6);
 | 
			
		||||
 | 
			
		||||
    const {userData: wethUserDataBefore} = await getContractsData(
 | 
			
		||||
      weth.address,
 | 
			
		||||
      user.address,
 | 
			
		||||
      testEnv
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const {
 | 
			
		||||
      reserveData: usdcReserveDataBefore,
 | 
			
		||||
      userData: usdcUserDataBefore,
 | 
			
		||||
    } = await getContractsData(usdc.address, user.address, testEnv);
 | 
			
		||||
 | 
			
		||||
    await mockSwapAdapter.setAmountToReturn(amountToRepay);
 | 
			
		||||
    const txReceipt = await waitForTx(
 | 
			
		||||
      await pool
 | 
			
		||||
        .connect(user.signer)
 | 
			
		||||
        .repayWithCollateral(
 | 
			
		||||
          weth.address,
 | 
			
		||||
          usdc.address,
 | 
			
		||||
          user.address,
 | 
			
		||||
          amountToRepay,
 | 
			
		||||
          mockSwapAdapter.address,
 | 
			
		||||
          '0x'
 | 
			
		||||
        )
 | 
			
		||||
    );
 | 
			
		||||
    const repayWithCollateralTimestamp = await timeLatest();
 | 
			
		||||
 | 
			
		||||
    const {userData: wethUserDataAfter} = await getContractsData(
 | 
			
		||||
      weth.address,
 | 
			
		||||
      user.address,
 | 
			
		||||
      testEnv
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const {userData: usdcUserDataAfter} = await getContractsData(
 | 
			
		||||
      usdc.address,
 | 
			
		||||
      user.address,
 | 
			
		||||
      testEnv
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const collateralPrice = await oracle.getAssetPrice(weth.address);
 | 
			
		||||
    const principalPrice = await oracle.getAssetPrice(usdc.address);
 | 
			
		||||
 | 
			
		||||
    const collateralDecimals = (
 | 
			
		||||
      await helpersContract.getReserveConfigurationData(weth.address)
 | 
			
		||||
    ).decimals.toString();
 | 
			
		||||
    const principalDecimals = (
 | 
			
		||||
      await helpersContract.getReserveConfigurationData(usdc.address)
 | 
			
		||||
    ).decimals.toString();
 | 
			
		||||
 | 
			
		||||
    const expectedCollateralLiquidated = new BigNumber(principalPrice.toString())
 | 
			
		||||
      .times(new BigNumber(amountToRepay.toString()).times(105))
 | 
			
		||||
      .times(new BigNumber(10).pow(collateralDecimals))
 | 
			
		||||
      .div(
 | 
			
		||||
        new BigNumber(collateralPrice.toString()).times(new BigNumber(10).pow(principalDecimals))
 | 
			
		||||
      )
 | 
			
		||||
      .div(100)
 | 
			
		||||
      .decimalPlaces(0, BigNumber.ROUND_DOWN);
 | 
			
		||||
 | 
			
		||||
    const expectedVariableDebtIncrease = calcExpectedVariableDebtTokenBalance(
 | 
			
		||||
      usdcReserveDataBefore,
 | 
			
		||||
      usdcUserDataBefore,
 | 
			
		||||
      new BigNumber(repayWithCollateralTimestamp)
 | 
			
		||||
    ).minus(usdcUserDataBefore.currentVariableDebt);
 | 
			
		||||
 | 
			
		||||
    const expectedStableDebtIncrease = calcExpectedStableDebtTokenBalance(
 | 
			
		||||
      usdcUserDataBefore.principalStableDebt,
 | 
			
		||||
      usdcUserDataBefore.stableBorrowRate,
 | 
			
		||||
      usdcUserDataBefore.stableRateLastUpdated,
 | 
			
		||||
      new BigNumber(repayWithCollateralTimestamp)
 | 
			
		||||
    ).minus(usdcUserDataBefore.currentStableDebt);
 | 
			
		||||
 | 
			
		||||
    expect(usdcUserDataAfter.currentVariableDebt).to.be.bignumber.equal(
 | 
			
		||||
      new BigNumber(usdcUserDataBefore.currentVariableDebt)
 | 
			
		||||
        .minus(amountToRepay.toString())
 | 
			
		||||
        .plus(expectedVariableDebtIncrease)
 | 
			
		||||
        .gte(0)
 | 
			
		||||
        ? new BigNumber(usdcUserDataBefore.currentVariableDebt)
 | 
			
		||||
            .minus(amountToRepay.toString())
 | 
			
		||||
            .plus(expectedVariableDebtIncrease)
 | 
			
		||||
            .toString()
 | 
			
		||||
        : '0',
 | 
			
		||||
      'INVALID_VARIABLE_DEBT_POSITION'
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const stableDebtRepaid = new BigNumber(usdcUserDataBefore.currentVariableDebt)
 | 
			
		||||
      .minus(amountToRepay.toString())
 | 
			
		||||
      .plus(expectedVariableDebtIncrease)
 | 
			
		||||
      .abs();
 | 
			
		||||
 | 
			
		||||
    expect(usdcUserDataAfter.currentStableDebt).to.be.bignumber.equal(
 | 
			
		||||
      new BigNumber(usdcUserDataBefore.currentStableDebt)
 | 
			
		||||
        .minus(stableDebtRepaid)
 | 
			
		||||
        .plus(expectedStableDebtIncrease)
 | 
			
		||||
        .gte(0)
 | 
			
		||||
        ? new BigNumber(usdcUserDataBefore.currentStableDebt)
 | 
			
		||||
            .minus(stableDebtRepaid)
 | 
			
		||||
            .plus(expectedStableDebtIncrease)
 | 
			
		||||
            .toString()
 | 
			
		||||
        : '0',
 | 
			
		||||
      'INVALID_STABLE_DEBT_POSITION'
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    expect(wethUserDataAfter.currentATokenBalance).to.be.bignumber.equal(
 | 
			
		||||
      new BigNumber(wethUserDataBefore.currentATokenBalance).minus(
 | 
			
		||||
        expectedCollateralLiquidated.toString()
 | 
			
		||||
      ),
 | 
			
		||||
      'INVALID_COLLATERAL_POSITION'
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const eventsEmitted = txReceipt.events || [];
 | 
			
		||||
 | 
			
		||||
    expectRepayWithCollateralEvent(
 | 
			
		||||
      eventsEmitted,
 | 
			
		||||
      pool.address,
 | 
			
		||||
      weth.address,
 | 
			
		||||
      usdc.address,
 | 
			
		||||
      user.address
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    expect(wethUserDataAfter.usageAsCollateralEnabled).to.be.true;
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('User 4 tries to repay a bigger amount that what can be swapped of a particular collateral, repaying only the maximum allowed by that collateral', async () => {
 | 
			
		||||
    const {pool, weth, dai, users, mockSwapAdapter, oracle, helpersContract} = testEnv;
 | 
			
		||||
    const user = users[3];
 | 
			
		||||
 | 
			
		||||
    const amountToDepositWeth = parseEther('0.1');
 | 
			
		||||
    const amountToDepositDAI = parseEther('500');
 | 
			
		||||
    const amountToBorrowVariable = parseEther('80');
 | 
			
		||||
 | 
			
		||||
    await weth.connect(user.signer).mint(amountToDepositWeth);
 | 
			
		||||
    await dai.connect(user.signer).mint(amountToDepositDAI);
 | 
			
		||||
    await weth.connect(user.signer).approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL);
 | 
			
		||||
    await dai.connect(user.signer).approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL);
 | 
			
		||||
 | 
			
		||||
    await pool.connect(user.signer).deposit(weth.address, amountToDepositWeth, user.address, '0');
 | 
			
		||||
    await pool.connect(user.signer).deposit(dai.address, amountToDepositDAI, user.address, '0');
 | 
			
		||||
 | 
			
		||||
    await pool.connect(user.signer).borrow(dai.address, amountToBorrowVariable, 2, 0, user.address);
 | 
			
		||||
 | 
			
		||||
    const amountToRepay = parseEther('80');
 | 
			
		||||
 | 
			
		||||
    const {userData: wethUserDataBefore} = await getContractsData(
 | 
			
		||||
      weth.address,
 | 
			
		||||
      user.address,
 | 
			
		||||
      testEnv
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const {reserveData: daiReserveDataBefore, userData: daiUserDataBefore} = await getContractsData(
 | 
			
		||||
      dai.address,
 | 
			
		||||
      user.address,
 | 
			
		||||
      testEnv
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    await mockSwapAdapter.setAmountToReturn(amountToRepay);
 | 
			
		||||
    await waitForTx(
 | 
			
		||||
      await pool
 | 
			
		||||
        .connect(user.signer)
 | 
			
		||||
        .repayWithCollateral(
 | 
			
		||||
          weth.address,
 | 
			
		||||
          dai.address,
 | 
			
		||||
          user.address,
 | 
			
		||||
          amountToRepay,
 | 
			
		||||
          mockSwapAdapter.address,
 | 
			
		||||
          '0x'
 | 
			
		||||
        )
 | 
			
		||||
    );
 | 
			
		||||
    const repayWithCollateralTimestamp = await timeLatest();
 | 
			
		||||
 | 
			
		||||
    const {userData: wethUserDataAfter} = await getContractsData(
 | 
			
		||||
      weth.address,
 | 
			
		||||
      user.address,
 | 
			
		||||
      testEnv
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const {userData: daiUserDataAfter} = await getContractsData(dai.address, user.address, testEnv);
 | 
			
		||||
 | 
			
		||||
    const collateralPrice = await oracle.getAssetPrice(weth.address);
 | 
			
		||||
    const principalPrice = await oracle.getAssetPrice(dai.address);
 | 
			
		||||
 | 
			
		||||
    const collateralConfig = await helpersContract.getReserveConfigurationData(weth.address);
 | 
			
		||||
 | 
			
		||||
    const collateralDecimals = collateralConfig.decimals.toString();
 | 
			
		||||
    const collateralLiquidationBonus = collateralConfig.liquidationBonus.toString();
 | 
			
		||||
 | 
			
		||||
    const principalDecimals = (
 | 
			
		||||
      await helpersContract.getReserveConfigurationData(dai.address)
 | 
			
		||||
    ).decimals.toString();
 | 
			
		||||
 | 
			
		||||
    const expectedDebtCovered = new BigNumber(collateralPrice.toString())
 | 
			
		||||
      .times(new BigNumber(wethUserDataBefore.currentATokenBalance.toString()))
 | 
			
		||||
      .times(new BigNumber(10).pow(principalDecimals))
 | 
			
		||||
      .div(
 | 
			
		||||
        new BigNumber(principalPrice.toString()).times(new BigNumber(10).pow(collateralDecimals))
 | 
			
		||||
      )
 | 
			
		||||
      .div(new BigNumber(collateralLiquidationBonus).div(10000).toString())
 | 
			
		||||
      .decimalPlaces(0, BigNumber.ROUND_DOWN);
 | 
			
		||||
 | 
			
		||||
    const expectedVariableDebtIncrease = calcExpectedVariableDebtTokenBalance(
 | 
			
		||||
      daiReserveDataBefore,
 | 
			
		||||
      daiUserDataBefore,
 | 
			
		||||
      new BigNumber(repayWithCollateralTimestamp)
 | 
			
		||||
    ).minus(daiUserDataBefore.currentVariableDebt);
 | 
			
		||||
 | 
			
		||||
    expect(daiUserDataAfter.currentVariableDebt).to.be.bignumber.almostEqual(
 | 
			
		||||
      new BigNumber(daiUserDataBefore.currentVariableDebt)
 | 
			
		||||
        .minus(expectedDebtCovered.toString())
 | 
			
		||||
        .plus(expectedVariableDebtIncrease),
 | 
			
		||||
      'INVALID_VARIABLE_DEBT_POSITION'
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    expect(wethUserDataAfter.currentATokenBalance).to.be.bignumber.almostEqual(0);
 | 
			
		||||
 | 
			
		||||
    expect(wethUserDataAfter.usageAsCollateralEnabled).to.be.false;
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('User 5 deposits WETH and DAI, then borrows USDC at Variable, then disables WETH as collateral', async () => {
 | 
			
		||||
    const {pool, weth, dai, usdc, users} = testEnv;
 | 
			
		||||
    const user = users[4];
 | 
			
		||||
    const amountWETHToDeposit = parseEther('10');
 | 
			
		||||
    const amountDAIToDeposit = parseEther('120');
 | 
			
		||||
    const amountToBorrow = parseUnits('65', 6);
 | 
			
		||||
 | 
			
		||||
    await weth.connect(user.signer).mint(amountWETHToDeposit);
 | 
			
		||||
    await weth.connect(user.signer).approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL);
 | 
			
		||||
    await pool.connect(user.signer).deposit(weth.address, amountWETHToDeposit, user.address, '0');
 | 
			
		||||
 | 
			
		||||
    await dai.connect(user.signer).mint(amountDAIToDeposit);
 | 
			
		||||
    await dai.connect(user.signer).approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL);
 | 
			
		||||
    await pool.connect(user.signer).deposit(dai.address, amountDAIToDeposit, user.address, '0');
 | 
			
		||||
 | 
			
		||||
    await pool.connect(user.signer).borrow(usdc.address, amountToBorrow, 2, 0, user.address);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('User 5 tries to repay his USDC loan by swapping his WETH collateral, should not revert even with WETH collateral disabled', async () => {
 | 
			
		||||
    const {pool, weth, usdc, users, mockSwapAdapter, oracle, helpersContract} = testEnv;
 | 
			
		||||
    const user = users[4];
 | 
			
		||||
 | 
			
		||||
    const amountToRepay = parseUnits('65', 6);
 | 
			
		||||
 | 
			
		||||
    // Disable WETH as collateral
 | 
			
		||||
    await pool.connect(user.signer).setUserUseReserveAsCollateral(weth.address, false);
 | 
			
		||||
 | 
			
		||||
    const {userData: wethUserDataBefore} = await getContractsData(
 | 
			
		||||
      weth.address,
 | 
			
		||||
      user.address,
 | 
			
		||||
      testEnv
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const {
 | 
			
		||||
      reserveData: usdcReserveDataBefore,
 | 
			
		||||
      userData: usdcUserDataBefore,
 | 
			
		||||
    } = await getContractsData(usdc.address, user.address, testEnv);
 | 
			
		||||
 | 
			
		||||
    expect(wethUserDataBefore.usageAsCollateralEnabled).to.be.false;
 | 
			
		||||
 | 
			
		||||
    // User 5 should be able to liquidate himself with WETH, even if is disabled
 | 
			
		||||
    await mockSwapAdapter.setAmountToReturn(amountToRepay);
 | 
			
		||||
    expect(
 | 
			
		||||
      await pool
 | 
			
		||||
        .connect(user.signer)
 | 
			
		||||
        .repayWithCollateral(
 | 
			
		||||
          weth.address,
 | 
			
		||||
          usdc.address,
 | 
			
		||||
          user.address,
 | 
			
		||||
          amountToRepay,
 | 
			
		||||
          mockSwapAdapter.address,
 | 
			
		||||
          '0x'
 | 
			
		||||
        )
 | 
			
		||||
    );
 | 
			
		||||
    const repayWithCollateralTimestamp = await timeLatest();
 | 
			
		||||
 | 
			
		||||
    const {userData: wethUserDataAfter} = await getContractsData(
 | 
			
		||||
      weth.address,
 | 
			
		||||
      user.address,
 | 
			
		||||
      testEnv
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const {userData: usdcUserDataAfter} = await getContractsData(
 | 
			
		||||
      usdc.address,
 | 
			
		||||
      user.address,
 | 
			
		||||
      testEnv
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const collateralPrice = await oracle.getAssetPrice(weth.address);
 | 
			
		||||
    const principalPrice = await oracle.getAssetPrice(usdc.address);
 | 
			
		||||
 | 
			
		||||
    const collateralDecimals = (
 | 
			
		||||
      await helpersContract.getReserveConfigurationData(weth.address)
 | 
			
		||||
    ).decimals.toString();
 | 
			
		||||
    const principalDecimals = (
 | 
			
		||||
      await helpersContract.getReserveConfigurationData(usdc.address)
 | 
			
		||||
    ).decimals.toString();
 | 
			
		||||
 | 
			
		||||
    const expectedCollateralLiquidated = new BigNumber(principalPrice.toString())
 | 
			
		||||
      .times(new BigNumber(amountToRepay.toString()).times(105))
 | 
			
		||||
      .times(new BigNumber(10).pow(collateralDecimals))
 | 
			
		||||
      .div(
 | 
			
		||||
        new BigNumber(collateralPrice.toString()).times(new BigNumber(10).pow(principalDecimals))
 | 
			
		||||
      )
 | 
			
		||||
      .div(100)
 | 
			
		||||
      .decimalPlaces(0, BigNumber.ROUND_DOWN);
 | 
			
		||||
 | 
			
		||||
    const expectedVariableDebtIncrease = calcExpectedVariableDebtTokenBalance(
 | 
			
		||||
      usdcReserveDataBefore,
 | 
			
		||||
      usdcUserDataBefore,
 | 
			
		||||
      new BigNumber(repayWithCollateralTimestamp)
 | 
			
		||||
    ).minus(usdcUserDataBefore.currentVariableDebt);
 | 
			
		||||
 | 
			
		||||
    expect(usdcUserDataAfter.currentVariableDebt).to.be.bignumber.almostEqual(
 | 
			
		||||
      new BigNumber(usdcUserDataBefore.currentVariableDebt)
 | 
			
		||||
        .minus(amountToRepay.toString())
 | 
			
		||||
        .plus(expectedVariableDebtIncrease)
 | 
			
		||||
        .toString(),
 | 
			
		||||
      'INVALID_DEBT_POSITION'
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    expect(wethUserDataAfter.currentATokenBalance).to.be.bignumber.equal(
 | 
			
		||||
      new BigNumber(wethUserDataBefore.currentATokenBalance).minus(
 | 
			
		||||
        expectedCollateralLiquidated.toString()
 | 
			
		||||
      ),
 | 
			
		||||
      'INVALID_COLLATERAL_POSITION'
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    expect(wethUserDataAfter.usageAsCollateralEnabled).to.be.false;
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user