From d1f21118c19ed0c0d38141278bb7c7369026c3b6 Mon Sep 17 00:00:00 2001
From: andyk <kyzia.ru@gmail.com>
Date: Thu, 18 Jun 2020 17:36:37 +0300
Subject: [PATCH] initial refactoring of liquidation-atoken.spec

---
 helpers/types.ts                |   4 +
 test/__setup.spec.ts            |   2 +
 test/helpers/make-suite.ts      | 112 +++--
 test/liquidation-atoken.spec.ts | 846 +++++++++++++-------------------
 4 files changed, 419 insertions(+), 545 deletions(-)

diff --git a/helpers/types.ts b/helpers/types.ts
index e623a95a..14568310 100644
--- a/helpers/types.ts
+++ b/helpers/types.ts
@@ -58,6 +58,10 @@ export enum ProtocolErrors {
   INCONSISTENT_PROTOCOL_BALANCE = "The actual balance of the protocol is inconsistent",
   TOO_SMALL_FLASH_LOAN = "The requested amount is too small for a flashLoan.",
   NOT_ENOUGH_LIQUIDITY_TO_BORROW = "There is not enough liquidity available to borrow",
+  HF_IS_NOT_BELLOW_THRESHOLD = "Health factor is not below the threshold",
+  INVALID_HF = "Invalid health factor",
+  USER_DID_NOT_BORROW_SPECIFIED = "User did not borrow the specified currency",
+  INVALID_COLLATERAL_TO_LIQUIDATE = "Invalid collateral to liquidate",
 }
 
 export type tEthereumAddress = string;
diff --git a/test/__setup.spec.ts b/test/__setup.spec.ts
index ffefdbab..aedd6e97 100644
--- a/test/__setup.spec.ts
+++ b/test/__setup.spec.ts
@@ -63,6 +63,7 @@ import {MockAggregator} from "../types/MockAggregator";
 import {LendingRateOracle} from "../types/LendingRateOracle";
 import {LendingPoolCore} from "../types/LendingPoolCore";
 import {LendingPoolConfigurator} from "../types/LendingPoolConfigurator";
+import { initializeMakeSuite } from './helpers/make-suite';
 
 const deployAllMockTokens = async (deployer: Signer) => {
   const tokens: {[symbol: string]: MockContract | MintableErc20} = {};
@@ -642,6 +643,7 @@ before(async () => {
   const [deployer, secondaryWallet] = await getEthersSigners();
   console.log("-> Deploying test environment...");
   await buildTestEnv(deployer, secondaryWallet);
+  await initializeMakeSuite();
   console.log("\n***************");
   console.log("Setup and snapshot finished");
   console.log("***************\n");
diff --git a/test/helpers/make-suite.ts b/test/helpers/make-suite.ts
index 89a9e8f8..e70cb56c 100644
--- a/test/helpers/make-suite.ts
+++ b/test/helpers/make-suite.ts
@@ -1,5 +1,4 @@
 import {evmRevert, evmSnapshot, BRE} from "../../helpers/misc-utils";
-import {TEST_SNAPSHOT_ID} from "../../helpers/constants";
 import {Signer} from "ethers";
 import {
   getEthersSigners,
@@ -9,8 +8,8 @@ import {
   getAaveProtocolTestHelpers,
   getAToken,
   getMintableErc20,
-  getLendingPoolConfiguratorProxy,
-} from "../../helpers/contracts-helpers";
+  getLendingPoolConfiguratorProxy, getPriceOracle,
+} from '../../helpers/contracts-helpers';
 import {tEthereumAddress} from "../../helpers/types";
 import {LendingPool} from "../../types/LendingPool";
 import {LendingPoolCore} from "../../types/LendingPoolCore";
@@ -23,6 +22,7 @@ import {LendingPoolConfigurator} from "../../types/LendingPoolConfigurator";
 import chai from "chai";
 // @ts-ignore
 import bignumberChai from "chai-bignumber";
+import { PriceOracle } from '../../types/PriceOracle';
 chai.use(bignumberChai());
 
 export interface SignerWithAddress {
@@ -36,9 +36,11 @@ export interface TestEnv {
   core: LendingPoolCore;
   configurator: LendingPoolConfigurator;
   addressesProvider: LendingPoolAddressesProvider;
+  oracle: PriceOracle;
   helpersContract: AaveProtocolTestHelpers;
   dai: MintableErc20;
   aDai: AToken;
+  usdc: MintableErc20;
 }
 
 let buidlerevmSnapshotId: string = "0x1";
@@ -48,59 +50,65 @@ const setBuidlerevmSnapshotId = (id: string) => {
   }
 };
 
+const testEnv: TestEnv = {
+  deployer: {} as SignerWithAddress,
+  users: [] as SignerWithAddress[],
+  pool: {} as LendingPool,
+  core: {} as LendingPoolCore,
+  configurator: {} as LendingPoolConfigurator,
+  addressesProvider: {} as LendingPoolAddressesProvider,
+  helpersContract: {} as AaveProtocolTestHelpers,
+  oracle: {} as PriceOracle,
+  dai: {} as MintableErc20,
+  aDai: {} as AToken,
+  usdc: {} as MintableErc20,
+} as TestEnv;
+
+export async function initializeMakeSuite() {
+  const [_deployer, ...restSigners] = await getEthersSigners();
+  const deployer: SignerWithAddress = {
+    address: await _deployer.getAddress(),
+    signer: _deployer,
+  };
+
+  for (const signer of restSigners) {
+    testEnv.users.push({
+      signer,
+      address: await signer.getAddress(),
+    });
+  }
+  testEnv.deployer = deployer;
+  testEnv.pool = await getLendingPool();
+  testEnv.core = await getLendingPoolCore();
+  testEnv.configurator = await getLendingPoolConfiguratorProxy();
+  testEnv.oracle = await getPriceOracle();
+  testEnv.addressesProvider = await getLendingPoolAddressesProvider();
+  testEnv.helpersContract = await getAaveProtocolTestHelpers();
+  const aDaiAddress = (await testEnv.helpersContract.getAllATokens()).find(
+    (aToken) => aToken.symbol === "aDAI"
+  )?.tokenAddress;
+
+  const reservesTokens = await testEnv.helpersContract.getAllReservesTokens();
+  const daiAddress = reservesTokens.find(token => token.symbol === "DAI")?.tokenAddress;
+  const usdcAddress = reservesTokens.find(token => token.symbol === "USDC")?.tokenAddress;
+  if (!aDaiAddress) {
+    console.log(`atoken-modifiers.spec: aDAI not correctly initialized`);
+    process.exit(1);
+  }
+  if (!daiAddress || !usdcAddress) {
+    console.log(`atoken-modifiers.spec: USDC or DAI not correctly initialized`);
+    process.exit(1);
+  }
+
+  testEnv.aDai = await getAToken(aDaiAddress);
+  testEnv.dai = await getMintableErc20(daiAddress);
+  testEnv.usdc = await getMintableErc20(usdcAddress);
+}
+
 export function makeSuite(name: string, tests: (testEnv: TestEnv) => void) {
   describe(name, () => {
-    const testEnv: TestEnv = {
-      deployer: {} as SignerWithAddress,
-      users: [] as SignerWithAddress[],
-      pool: {} as LendingPool,
-      core: {} as LendingPoolCore,
-      configurator: {} as LendingPoolConfigurator,
-      addressesProvider: {} as LendingPoolAddressesProvider,
-      helpersContract: {} as AaveProtocolTestHelpers,
-      dai: {} as MintableErc20,
-      aDai: {} as AToken,
-    } as TestEnv;
     before(async () => {
-      console.time("makeSuite");
       setBuidlerevmSnapshotId(await evmSnapshot());
-      const [_deployer, ...restSigners] = await getEthersSigners();
-      const deployer: SignerWithAddress = {
-        address: await _deployer.getAddress(),
-        signer: _deployer,
-      };
-
-      for (const signer of restSigners) {
-        testEnv.users.push({
-          signer,
-          address: await signer.getAddress(),
-        });
-      }
-      testEnv.deployer = deployer;
-      testEnv.pool = await getLendingPool();
-      testEnv.core = await getLendingPoolCore();
-      testEnv.configurator = await getLendingPoolConfiguratorProxy();
-      testEnv.addressesProvider = await getLendingPoolAddressesProvider();
-      testEnv.helpersContract = await getAaveProtocolTestHelpers();
-      const aDaiAddress = (await testEnv.helpersContract.getAllATokens()).find(
-        (aToken) => aToken.symbol === "aDAI"
-      )?.tokenAddress;
-
-      const daiAddress = (
-        await await testEnv.helpersContract.getAllReservesTokens()
-      ).find((token) => token.symbol === "DAI")?.tokenAddress;
-      if (!aDaiAddress) {
-        console.log(`atoken-modifiers.spec: aDAI not correctly initialized`);
-        process.exit(1);
-      }
-      if (!daiAddress) {
-        console.log(`atoken-modifiers.spec: DAI not correctly initialized`);
-        process.exit(1);
-      }
-
-      testEnv.aDai = await getAToken(aDaiAddress);
-      testEnv.dai = await getMintableErc20(daiAddress);
-      console.timeEnd("makeSuite");
     });
     tests(testEnv);
     after(async () => {
diff --git a/test/liquidation-atoken.spec.ts b/test/liquidation-atoken.spec.ts
index fd0c03a7..62b610fe 100644
--- a/test/liquidation-atoken.spec.ts
+++ b/test/liquidation-atoken.spec.ts
@@ -1,493 +1,353 @@
-// import {
-//   LendingPoolInstance,
-//   LendingPoolCoreInstance,
-//   IPriceOracleInstance,
-//   ATokenInstance,
-//   LendingPoolAddressesProviderInstance,
-//   MintableERC20Instance,
-// } from '../utils/typechain-types/truffle-contracts';
-// import {
-//   ContractId,
-//   IReserveParams,
-//   iATokenBase,
-//   iAavePoolAssets,
-//   iAssetsWithoutETH,
-//   ITestEnvWithoutInstances,
-//   RateMode,
-// } from '../utils/types';
-// import BigNumber from 'bignumber.js';
-// import {
-//   APPROVAL_AMOUNT_LENDING_POOL_CORE,
-//   oneEther,
-//   ETHEREUM_ADDRESS,
-// } from '../utils/constants';
-// import {testEnvProviderWithoutInstances} from '../utils/truffle/dlp-tests-env';
-// import {convertToCurrencyDecimals} from '../utils/misc-utils';
-// import {getTruffleContractInstance} from '../utils/truffle/truffle-core-utils';
-
-// const expectRevert = require('@openzeppelin/test-helpers').expectRevert;
-
-// const {expect} = require('chai');
-
-// const almostEqual: any = function(this: any, expected: any, actual: any): any {
-//   this.assert(
-//     expected.plus(new BigNumber(1)).eq(actual) ||
-//       expected.plus(new BigNumber(2)).eq(actual) ||
-//       actual.plus(new BigNumber(1)).eq(expected) ||
-//       actual.plus(new BigNumber(2)).eq(expected) ||
-//       expected.eq(actual),
-//     'expected #{act} to be almost equal #{exp}',
-//     'expected #{act} to be different from #{exp}',
-//     expected.toString(),
-//     actual.toString()
-//   );
-// };
-
-// require('chai').use(function(chai: any, utils: any) {
-//   chai.Assertion.overwriteMethod('almostEqual', function(original: any) {
-//     return function(this: any, value: any) {
-//       if (utils.flag(this, 'bignumber')) {
-//         var expected = new BigNumber(value);
-//         var actual = new BigNumber(this._obj);
-//         almostEqual.apply(this, [expected, actual]);
-//       } else {
-//         original.apply(this, arguments);
-//       }
-//     };
-//   });
-// });
-
-// contract('LendingPool liquidation - liquidator receiving aToken', async ([deployer, ...users]) => {
-//   let _testEnvProvider: ITestEnvWithoutInstances;
-//   let _lendingPoolInstance: LendingPoolInstance;
-//   let _lendingPoolCoreInstance: LendingPoolCoreInstance;
-//   let _lendingPoolAddressesProviderInstance: LendingPoolAddressesProviderInstance;
-//   let _priceOracleInstance: IPriceOracleInstance;
-//   let _aTokenInstances: iATokenBase<ATokenInstance>;
-//   let _tokenInstances: iAssetsWithoutETH<MintableERC20Instance>;
-
-//   let _daiAddress: string;
-
-//   let _reservesParams: iAavePoolAssets<IReserveParams>;
-
-//   let _depositorAddress: string;
-//   let _borrowerAddress: string;
-
-//   let _web3: Web3;
-
-//   let _initialDepositorETHBalance: string;
-
-//   before('Initializing LendingPool test variables', async () => {
-//     console.time('setup-test');
-//     _testEnvProvider = await testEnvProviderWithoutInstances(artifacts, [deployer, ...users]);
-
-//     const {
-//       getWeb3,
-//       getAllAssetsInstances,
-//       getFirstBorrowerAddressOnTests,
-//       getFirstDepositorAddressOnTests,
-//       getAavePoolReservesParams,
-//       getLendingPoolInstance,
-//       getLendingPoolCoreInstance,
-//       getPriceOracleInstance,
-//       getATokenInstances,
-//       getLendingPoolAddressesProviderInstance,
-//     } = _testEnvProvider;
-
-//     const instances = await Promise.all([
-//       getLendingPoolInstance(),
-//       getLendingPoolCoreInstance(),
-//       getPriceOracleInstance(),
-//       getATokenInstances(),
-//       getLendingPoolAddressesProviderInstance(),
-//       getAllAssetsInstances(),
-//     ]);
-
-//     _reservesParams = await getAavePoolReservesParams();
-//     _lendingPoolInstance = instances[0];
-//     _lendingPoolCoreInstance = instances[1];
-//     _priceOracleInstance = instances[2];
-//     _aTokenInstances = instances[3];
-//     _lendingPoolAddressesProviderInstance = instances[4];
-//     _tokenInstances = instances[5];
-//     _daiAddress = _tokenInstances.DAI.address;
-//     _depositorAddress = await getFirstDepositorAddressOnTests();
-//     _borrowerAddress = await getFirstBorrowerAddressOnTests();
-
-//     _web3 = await getWeb3();
-//     _initialDepositorETHBalance = await _web3.eth.getBalance(_depositorAddress);
-//     console.timeEnd('setup-test');
-//   });
-
-//   it('LIQUIDATION - Deposits ETH, borrows DAI/Check liquidation fails because health factor is above 1', async () => {
-//     const {DAI: daiInstance} = _tokenInstances;
-
-//     const aEthInstance: ATokenInstance = await getTruffleContractInstance(
-//       artifacts,
-//       ContractId.AToken,
-//       await _lendingPoolCoreInstance.getReserveATokenAddress(ETHEREUM_ADDRESS)
-//     );
-
-//     //mints DAI to depositor
-//     await daiInstance.mint(await convertToCurrencyDecimals(daiInstance.address, '1000'), {
-//       from: _depositorAddress,
-//     });
-
-//     //approve protocol to access depositor wallet
-//     await daiInstance.approve(_lendingPoolCoreInstance.address, APPROVAL_AMOUNT_LENDING_POOL_CORE, {
-//       from: _depositorAddress,
-//     });
-
-//     //user 1 deposits 1000 DAI
-//     const amountDAItoDeposit = await convertToCurrencyDecimals(_daiAddress, '1000');
-
-//     await _lendingPoolInstance.deposit(_daiAddress, amountDAItoDeposit, '0', {
-//       from: _depositorAddress,
-//     });
-
-//     //user 2 deposits 1 ETH
-//     const amountETHtoDeposit = await convertToCurrencyDecimals(ETHEREUM_ADDRESS, '1');
-
-//     await _lendingPoolInstance.deposit(ETHEREUM_ADDRESS, amountETHtoDeposit, '0', {
-//       from: _borrowerAddress,
-//       value: amountETHtoDeposit,
-//     });
-
-//     //user 2 borrows
-
-//     const userGlobalData: any = await _lendingPoolInstance.getUserAccountData(_borrowerAddress);
-//     const daiPrice = await _priceOracleInstance.getAssetPrice(_daiAddress);
-
-//     const amountDAIToBorrow = await convertToCurrencyDecimals(
-//       _daiAddress,
-//       new BigNumber(userGlobalData.availableBorrowsETH)
-//         .div(daiPrice)
-//         .multipliedBy(0.95)
-//         .toFixed(0)
-//     );
-
-//     await _lendingPoolInstance.borrow(_daiAddress, amountDAIToBorrow, RateMode.Stable, '0', {
-//       from: _borrowerAddress,
-//     });
-
-//     const userGlobalDataAfter: any = await _lendingPoolInstance.getUserAccountData(
-//       _borrowerAddress
-//     );
-
-//     expect(userGlobalDataAfter.currentLiquidationThreshold).to.be.bignumber.equal(
-//       '80',
-//       'Invalid liquidation threshold'
-//     );
-
-//     //user 2 tries to borrow
-//     await expectRevert(
-//       _lendingPoolInstance.liquidationCall(
-//         ETHEREUM_ADDRESS,
-//         _daiAddress,
-//         _borrowerAddress,
-//         amountDAIToBorrow,
-//         true
-//       ),
-//       'Health factor is not below the threshold'
-//     );
-//   });
-
-//   it('LIQUIDATION - Drop the health factor below 1', async () => {
-//     const daiPrice = await _priceOracleInstance.getAssetPrice(_daiAddress);
-
-//     //halving the price of ETH - means doubling the DAIETH exchange rate
-
-//     await _priceOracleInstance.setAssetPrice(
-//       _daiAddress,
-//       new BigNumber(daiPrice).multipliedBy(1.15).toFixed(0)
-//     );
-
-//     const userGlobalData: any = await _lendingPoolInstance.getUserAccountData(_borrowerAddress);
-
-//     expect(userGlobalData.healthFactor).to.be.bignumber.lt(
-//       oneEther.toFixed(0),
-//       'Invalid health factor'
-//     );
-//   });
-
-//   it('LIQUIDATION - Tries to liquidate a different currency than the loan principal', async () => {
-//     //user 2 tries to borrow
-//     await expectRevert(
-//       _lendingPoolInstance.liquidationCall(
-//         ETHEREUM_ADDRESS,
-//         ETHEREUM_ADDRESS,
-//         _borrowerAddress,
-//         oneEther,
-//         true
-//       ),
-//       'User did not borrow the specified currency'
-//     );
-//   });
-
-//   it('LIQUIDATION - Tries to liquidate a different collateral than the borrower collateral', async () => {
-//     //user 2 tries to borrow
-//     await expectRevert(
-//       _lendingPoolInstance.liquidationCall(
-//         _daiAddress,
-//         _daiAddress,
-//         _borrowerAddress,
-//         oneEther,
-//         true
-//       ),
-//       'Invalid collateral to liquidate'
-//     );
-//   });
-
-//   it('LIQUIDATION - Liquidates the borrow', async () => {
-//     const {DAI: daiInstance} = _tokenInstances;
-
-//     //mints dai to the caller
-
-//     await daiInstance.mint(await convertToCurrencyDecimals(daiInstance.address, '1000'));
-
-//     //approve protocol to access depositor wallet
-//     await daiInstance.approve(_lendingPoolCoreInstance.address, APPROVAL_AMOUNT_LENDING_POOL_CORE);
-
-//     const userReserveDataBefore: any = await _lendingPoolInstance.getUserReserveData(
-//       _daiAddress,
-//       _borrowerAddress
-//     );
-
-//     const daiReserveDataBefore: any = await _lendingPoolInstance.getReserveData(_daiAddress);
-//     const ethReserveDataBefore: any = await _lendingPoolInstance.getReserveData(ETHEREUM_ADDRESS);
-
-//     const amountToLiquidate = new BigNumber(userReserveDataBefore.currentBorrowBalance)
-//       .div(2)
-//       .toFixed(0);
-
-//     await _lendingPoolInstance.liquidationCall(
-//       ETHEREUM_ADDRESS,
-//       _daiAddress,
-//       _borrowerAddress,
-//       amountToLiquidate,
-//       true
-//     );
-
-//     const userReserveDataAfter: any = await _lendingPoolInstance.getUserReserveData(
-//       _daiAddress,
-//       _borrowerAddress
-//     );
-
-//     const userGlobalDataAfter: any = await _lendingPoolInstance.getUserAccountData(
-//       _borrowerAddress
-//     );
-
-//     const daiReserveDataAfter: any = await _lendingPoolInstance.getReserveData(_daiAddress);
-//     const ethReserveDataAfter: any = await _lendingPoolInstance.getReserveData(ETHEREUM_ADDRESS);
-
-//     const feeAddress = await _lendingPoolAddressesProviderInstance.getTokenDistributor();
-
-//     const feeAddressBalance = await web3.eth.getBalance(feeAddress);
-
-//     const collateralPrice = await _priceOracleInstance.getAssetPrice(ETHEREUM_ADDRESS);
-//     const principalPrice = await _priceOracleInstance.getAssetPrice(_daiAddress);
-
-//     const collateralDecimals = await _lendingPoolCoreInstance.getReserveDecimals(ETHEREUM_ADDRESS);
-//     const principalDecimals = await _lendingPoolCoreInstance.getReserveDecimals(_daiAddress);
-
-//     const expectedCollateralLiquidated = new BigNumber(principalPrice)
-//       .times(new BigNumber(amountToLiquidate).times(105))
-//       .times(new BigNumber(10).pow(collateralDecimals))
-//       .div(new BigNumber(collateralPrice).times(new BigNumber(10).pow(principalDecimals)))
-//       .decimalPlaces(0, BigNumber.ROUND_DOWN);
-
-//     const expectedFeeLiquidated = new BigNumber(principalPrice)
-//       .times(new BigNumber(userReserveDataBefore.originationFee).times(105))
-//       .times(new BigNumber(10).pow(collateralDecimals))
-//       .div(new BigNumber(collateralPrice).times(new BigNumber(10).pow(principalDecimals)))
-//       .div(100)
-//       .decimalPlaces(0, BigNumber.ROUND_DOWN);
-
-//     expect(userGlobalDataAfter.healthFactor).to.be.bignumber.gt(
-//       oneEther.toFixed(0),
-//       'Invalid health factor'
-//     );
-
-//     expect(userReserveDataAfter.originationFee).to.be.bignumber.eq(
-//       '0',
-//       'Origination fee should be repaid'
-//     );
-
-//     expect(feeAddressBalance).to.be.bignumber.gt('0');
-
-//     expect(userReserveDataAfter.principalBorrowBalance).to.be.bignumber.almostEqual(
-//       new BigNumber(userReserveDataBefore.currentBorrowBalance).minus(amountToLiquidate).toFixed(0),
-//       'Invalid user borrow balance after liquidation'
-//     );
-
-//     expect(daiReserveDataAfter.availableLiquidity).to.be.bignumber.almostEqual(
-//       new BigNumber(daiReserveDataBefore.availableLiquidity).plus(amountToLiquidate).toFixed(0),
-//       'Invalid principal available liquidity'
-//     );
-
-//     expect(ethReserveDataAfter.availableLiquidity).to.be.bignumber.almostEqual(
-//       new BigNumber(ethReserveDataBefore.availableLiquidity)
-//         .minus(expectedFeeLiquidated)
-//         .toFixed(0),
-//       'Invalid collateral available liquidity'
-//     );
-//   });
-
-//   it('User 3 deposits 1000 USDC, user 4 1 ETH, user 4 borrows - drops HF, liquidates the borrow', async () => {
-//     const {USDC: usdcInstance} = _tokenInstances;
-
-//     //mints USDC to depositor
-//     await usdcInstance.mint(await convertToCurrencyDecimals(usdcInstance.address, '1000'), {
-//       from: users[3],
-//     });
-
-//     //approve protocol to access depositor wallet
-//     await usdcInstance.approve(
-//       _lendingPoolCoreInstance.address,
-//       APPROVAL_AMOUNT_LENDING_POOL_CORE,
-//       {
-//         from: users[3],
-//       }
-//     );
-
-//     //user 3 deposits 1000 USDC
-//     const amountUSDCtoDeposit = await convertToCurrencyDecimals(usdcInstance.address, '1000');
-
-//     await _lendingPoolInstance.deposit(usdcInstance.address, amountUSDCtoDeposit, '0', {
-//       from: users[3],
-//     });
-
-//     //user 4 deposits 1 ETH
-//     const amountETHtoDeposit = await convertToCurrencyDecimals(ETHEREUM_ADDRESS, '1');
-
-//     await _lendingPoolInstance.deposit(ETHEREUM_ADDRESS, amountETHtoDeposit, '0', {
-//       from: users[4],
-//       value: amountETHtoDeposit,
-//     });
-
-//     //user 4 borrows
-//     const userGlobalData: any = await _lendingPoolInstance.getUserAccountData(users[4]);
-
-//     const usdcPrice = await _priceOracleInstance.getAssetPrice(usdcInstance.address);
-
-//     const amountUSDCToBorrow = await convertToCurrencyDecimals(
-//       usdcInstance.address,
-//       new BigNumber(userGlobalData.availableBorrowsETH)
-//         .div(usdcPrice)
-//         .multipliedBy(0.95)
-//         .toFixed(0)
-//     );
-
-//     await _lendingPoolInstance.borrow(
-//       usdcInstance.address,
-//       amountUSDCToBorrow,
-//       RateMode.Stable,
-//       '0',
-//       {
-//         from: users[4],
-//       }
-//     );
-
-//     //drops HF below 1
-
-//     await _priceOracleInstance.setAssetPrice(
-//       usdcInstance.address,
-//       new BigNumber(usdcPrice).multipliedBy(1.2).toFixed(0)
-//     );
-
-//     //mints dai to the liquidator
-
-//     await usdcInstance.mint(await convertToCurrencyDecimals(usdcInstance.address, '1000'));
-
-//     //approve protocol to access depositor wallet
-//     await usdcInstance.approve(_lendingPoolCoreInstance.address, APPROVAL_AMOUNT_LENDING_POOL_CORE);
-
-//     const userReserveDataBefore: any = await _lendingPoolInstance.getUserReserveData(
-//       usdcInstance.address,
-//       users[4]
-//     );
-
-//     const usdcReserveDataBefore: any = await _lendingPoolInstance.getReserveData(
-//       usdcInstance.address
-//     );
-//     const ethReserveDataBefore: any = await _lendingPoolInstance.getReserveData(ETHEREUM_ADDRESS);
-
-//     const amountToLiquidate = new BigNumber(userReserveDataBefore.currentBorrowBalance)
-//       .div(2)
-//       .toFixed(0);
-
-//     await _lendingPoolInstance.liquidationCall(
-//       ETHEREUM_ADDRESS,
-//       usdcInstance.address,
-//       users[4],
-//       amountToLiquidate,
-//       true
-//     );
-
-//     const userReserveDataAfter: any = await _lendingPoolInstance.getUserReserveData(
-//       usdcInstance.address,
-//       users[4]
-//     );
-
-//     const userGlobalDataAfter: any = await _lendingPoolInstance.getUserAccountData(users[4]);
-
-//     const usdcReserveDataAfter: any = await _lendingPoolInstance.getReserveData(
-//       usdcInstance.address
-//     );
-//     const ethReserveDataAfter: any = await _lendingPoolInstance.getReserveData(ETHEREUM_ADDRESS);
-
-//     const feeAddress = await _lendingPoolAddressesProviderInstance.getTokenDistributor();
-
-//     const feeAddressBalance = await web3.eth.getBalance(feeAddress);
-
-//     const collateralPrice = await _priceOracleInstance.getAssetPrice(ETHEREUM_ADDRESS);
-//     const principalPrice = await _priceOracleInstance.getAssetPrice(usdcInstance.address);
-
-//     const collateralDecimals = await _lendingPoolCoreInstance.getReserveDecimals(ETHEREUM_ADDRESS);
-//     const principalDecimals = await _lendingPoolCoreInstance.getReserveDecimals(
-//       usdcInstance.address
-//     );
-
-//     const expectedCollateralLiquidated = new BigNumber(principalPrice)
-//       .times(new BigNumber(amountToLiquidate).times(105))
-//       .times(new BigNumber(10).pow(collateralDecimals))
-//       .div(new BigNumber(collateralPrice).times(new BigNumber(10).pow(principalDecimals)))
-//       .decimalPlaces(0, BigNumber.ROUND_DOWN);
-
-//     const expectedFeeLiquidated = new BigNumber(principalPrice)
-//       .times(new BigNumber(userReserveDataBefore.originationFee).times(105))
-//       .times(new BigNumber(10).pow(collateralDecimals))
-//       .div(new BigNumber(collateralPrice).times(new BigNumber(10).pow(principalDecimals)))
-//       .div(100)
-//       .decimalPlaces(0, BigNumber.ROUND_DOWN);
-
-//     expect(userGlobalDataAfter.healthFactor).to.be.bignumber.gt(
-//       oneEther.toFixed(0),
-//       'Invalid health factor'
-//     );
-
-//     expect(userReserveDataAfter.originationFee).to.be.bignumber.eq(
-//       '0',
-//       'Origination fee should be repaid'
-//     );
-
-//     expect(feeAddressBalance).to.be.bignumber.gt('0');
-
-//     expect(userReserveDataAfter.principalBorrowBalance).to.be.bignumber.almostEqual(
-//       new BigNumber(userReserveDataBefore.currentBorrowBalance).minus(amountToLiquidate).toFixed(0),
-//       'Invalid user borrow balance after liquidation'
-//     );
-
-//     expect(usdcReserveDataAfter.availableLiquidity).to.be.bignumber.almostEqual(
-//       new BigNumber(usdcReserveDataBefore.availableLiquidity).plus(amountToLiquidate).toFixed(0),
-//       'Invalid principal available liquidity'
-//     );
-
-//     expect(ethReserveDataAfter.availableLiquidity).to.be.bignumber.almostEqual(
-//       new BigNumber(ethReserveDataBefore.availableLiquidity)
-//         .minus(expectedFeeLiquidated)
-//         .toFixed(0),
-//       'Invalid collateral available liquidity'
-//     );
-//   });
-// });
+import BigNumber from 'bignumber.js';
+
+import {BRE} from '../helpers/misc-utils';
+import {APPROVAL_AMOUNT_LENDING_POOL_CORE, MOCK_ETH_ADDRESS, oneEther} from '../helpers/constants';
+import {convertToCurrencyDecimals} from '../helpers/contracts-helpers';
+import {makeSuite} from './helpers/make-suite';
+import {ProtocolErrors, RateMode} from '../helpers/types';
+
+const {expect} = require('chai');
+
+makeSuite('LendingPool liquidation - liquidator receiving aToken', (testEnv) => {
+  const {
+    HF_IS_NOT_BELLOW_THRESHOLD,
+    INVALID_HF,
+    USER_DID_NOT_BORROW_SPECIFIED,
+    INVALID_COLLATERAL_TO_LIQUIDATE,
+  } = ProtocolErrors;
+
+  it('LIQUIDATION - Deposits ETH, borrows DAI/Check liquidation fails because health factor is above 1', async () => {
+    const {dai, users, core, pool, oracle} = testEnv;
+    const depositor = users[0];
+    const borrower = users[1];
+
+    //mints DAI to depositor
+    await dai.connect(depositor.signer).mint(await convertToCurrencyDecimals(dai.address, '1000'));
+
+    //approve protocol to access depositor wallet
+    await dai.connect(depositor.signer).approve(core.address, APPROVAL_AMOUNT_LENDING_POOL_CORE);
+
+    //user 1 deposits 1000 DAI
+    const amountDAItoDeposit = await convertToCurrencyDecimals(dai.address, '1000');
+    await pool.connect(depositor.signer).deposit(dai.address, amountDAItoDeposit, '0');
+
+    //user 2 deposits 1 ETH
+    const amountETHtoDeposit = await convertToCurrencyDecimals(MOCK_ETH_ADDRESS, '1');
+    await pool
+      .connect(borrower.signer)
+      .deposit(MOCK_ETH_ADDRESS, amountETHtoDeposit, '0', {value: amountETHtoDeposit});
+
+    await pool.connect(borrower.signer).deposit(MOCK_ETH_ADDRESS, amountETHtoDeposit, '0', {
+      value: amountETHtoDeposit,
+    });
+
+    //user 2 borrows
+
+    const userGlobalData = await pool.getUserAccountData(borrower.address);
+    const daiPrice = await oracle.getAssetPrice(dai.address);
+
+    const amountDAIToBorrow = await convertToCurrencyDecimals(
+      dai.address,
+      new BigNumber(userGlobalData.availableBorrowsETH.toString())
+        .div(daiPrice.toString())
+        .multipliedBy(0.95)
+        .toFixed(0)
+    );
+
+    await pool
+      .connect(borrower.signer)
+      .borrow(dai.address, amountDAIToBorrow, RateMode.Variable, '0');
+
+    const userGlobalDataAfter = await pool.getUserAccountData(borrower.address);
+    console.log('userGlobalDataAfter.healthFactor', userGlobalDataAfter.healthFactor.toString());
+
+    expect(userGlobalDataAfter.currentLiquidationThreshold).to.be.bignumber.equal(
+      '80',
+      'Invalid liquidation threshold'
+    );
+
+    //someone tries to liquidate user 2
+    await expect(
+      pool.liquidationCall(MOCK_ETH_ADDRESS, dai.address, borrower.address, 1, true)
+    ).to.be.revertedWith(HF_IS_NOT_BELLOW_THRESHOLD);
+  });
+
+  it('LIQUIDATION - Drop the health factor below 1', async () => {
+    const {dai, users, pool, oracle} = testEnv;
+    const borrower = users[1];
+
+    const daiPrice = await oracle.getAssetPrice(dai.address);
+
+    //halving the price of ETH - means doubling the DAIETH exchange rate
+    console.log('DAI price before', daiPrice.toString());
+
+    await oracle.setAssetPrice(
+      dai.address,
+      new BigNumber(daiPrice.toString()).multipliedBy(1.15).toFixed(0)
+    );
+    console.log('DAI price after', (await oracle.getAssetPrice(dai.address)).toString());
+
+    const userGlobalData = await pool.getUserAccountData(borrower.address);
+
+    expect(userGlobalData.healthFactor).to.be.bignumber.lt(oneEther.toFixed(0), INVALID_HF);
+  });
+
+  it('LIQUIDATION - Tries to liquidate a different currency than the loan principal', async () => {
+    const {pool, users} = testEnv;
+    const borrower = users[1];
+    //user 2 tries to borrow
+    await expect(
+      pool.liquidationCall(
+        MOCK_ETH_ADDRESS,
+        MOCK_ETH_ADDRESS,
+        borrower.address,
+        oneEther.toString(),
+        true
+      )
+    ).revertedWith(USER_DID_NOT_BORROW_SPECIFIED);
+  });
+
+  it(
+    'LIQUIDATION - Tries to liquidate a different ' + 'collateral than the borrower collateral',
+    async () => {
+      const {pool, dai, users} = testEnv;
+      const borrower = users[1];
+
+      await expect(
+        pool.liquidationCall(dai.address, dai.address, borrower.address, oneEther.toString(), true)
+      ).revertedWith(INVALID_COLLATERAL_TO_LIQUIDATE);
+    }
+  );
+
+  it('LIQUIDATION - Liquidates the borrow', async () => {
+    const {pool, dai, core, users, addressesProvider, oracle} = testEnv;
+    const borrower = users[1];
+
+    //mints dai to the caller
+
+    await dai.mint(await convertToCurrencyDecimals(dai.address, '1000'));
+
+    //approve protocol to access depositor wallet
+    await dai.approve(core.address, APPROVAL_AMOUNT_LENDING_POOL_CORE);
+
+    const userReserveDataBefore = await pool.getUserReserveData(dai.address, borrower.address);
+
+    const daiReserveDataBefore = await pool.getReserveData(dai.address);
+    const ethReserveDataBefore = await pool.getReserveData(MOCK_ETH_ADDRESS);
+
+    const amountToLiquidate = new BigNumber(userReserveDataBefore.currentBorrowBalance.toString())
+      .div(2)
+      .toFixed(0);
+
+    await pool.liquidationCall(
+      MOCK_ETH_ADDRESS,
+      dai.address,
+      borrower.address,
+      amountToLiquidate,
+      true
+    );
+
+    const userReserveDataAfter = await pool.getUserReserveData(dai.address, borrower.address);
+
+    const userGlobalDataAfter = await pool.getUserAccountData(borrower.address);
+
+    const daiReserveDataAfter = await pool.getReserveData(dai.address);
+    const ethReserveDataAfter = await pool.getReserveData(MOCK_ETH_ADDRESS);
+
+    const feeAddress = await addressesProvider.getTokenDistributor();
+
+    const feeAddressBalance = await BRE.ethers.provider.getBalance(feeAddress);
+
+    const collateralPrice = (await oracle.getAssetPrice(MOCK_ETH_ADDRESS)).toString();
+    const principalPrice = (await oracle.getAssetPrice(dai.address)).toString();
+
+    const collateralDecimals = (await core.getReserveDecimals(MOCK_ETH_ADDRESS)).toString();
+    const principalDecimals = (await core.getReserveDecimals(dai.address)).toString();
+
+    const expectedCollateralLiquidated = new BigNumber(principalPrice)
+      .times(new BigNumber(amountToLiquidate).times(105))
+      .times(new BigNumber(10).pow(collateralDecimals))
+      .div(new BigNumber(collateralPrice).times(new BigNumber(10).pow(principalDecimals)))
+      .decimalPlaces(0, BigNumber.ROUND_DOWN);
+
+    const expectedFeeLiquidated = new BigNumber(principalPrice)
+      .times(new BigNumber(userReserveDataBefore.originationFee.toString()).times(105))
+      .times(new BigNumber(10).pow(collateralDecimals))
+      .div(new BigNumber(collateralPrice).times(new BigNumber(10).pow(principalDecimals)))
+      .div(100)
+      .decimalPlaces(0, BigNumber.ROUND_DOWN);
+
+    expect(userGlobalDataAfter.healthFactor).to.be.bignumber.gt(
+      oneEther.toFixed(0),
+      'Invalid health factor'
+    );
+
+    expect(userReserveDataAfter.originationFee).to.be.bignumber.eq(
+      '0',
+      'Origination fee should be repaid'
+    );
+
+    expect(feeAddressBalance).to.be.bignumber.gt('0');
+
+    expect(userReserveDataAfter.principalBorrowBalance).to.be.bignumber.almostEqual(
+      new BigNumber(userReserveDataBefore.currentBorrowBalance.toString())
+        .minus(amountToLiquidate)
+        .toFixed(0),
+      'Invalid user borrow balance after liquidation'
+    );
+
+    expect(daiReserveDataAfter.availableLiquidity).to.be.bignumber.almostEqual(
+      new BigNumber(daiReserveDataBefore.availableLiquidity.toString())
+        .plus(amountToLiquidate)
+        .toFixed(0),
+      'Invalid principal available liquidity'
+    );
+
+    expect(ethReserveDataAfter.availableLiquidity).to.be.bignumber.almostEqual(
+      new BigNumber(ethReserveDataBefore.availableLiquidity.toString())
+        .minus(expectedFeeLiquidated)
+        .toFixed(0),
+      'Invalid collateral available liquidity'
+    );
+  });
+
+  it(
+    'User 3 deposits 1000 USDC, user 4 1 ETH,' +
+      ' user 4 borrows - drops HF, liquidates the borrow',
+    async () => {
+      const {users, core, pool, usdc, oracle, addressesProvider} = testEnv;
+      const depositor = users[3];
+      const borrower = users[4];
+      //mints USDC to depositor
+      await usdc
+        .connect(depositor.signer)
+        .mint(await convertToCurrencyDecimals(usdc.address, '1000'));
+
+      //approve protocol to access depositor wallet
+      await usdc.connect(depositor.signer).approve(core.address, APPROVAL_AMOUNT_LENDING_POOL_CORE);
+
+      //user 3 deposits 1000 USDC
+      const amountUSDCtoDeposit = await convertToCurrencyDecimals(usdc.address, '1000');
+
+      await pool.connect(depositor.signer).deposit(usdc.address, amountUSDCtoDeposit, '0');
+
+      //user 4 deposits 1 ETH
+      const amountETHtoDeposit = await convertToCurrencyDecimals(MOCK_ETH_ADDRESS, '1');
+
+      await pool.connect(borrower.signer).deposit(MOCK_ETH_ADDRESS, amountETHtoDeposit, '0', {
+        value: amountETHtoDeposit,
+      });
+
+      //user 4 borrows
+      const userGlobalData = await pool.getUserAccountData(borrower.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(borrower.signer)
+        .borrow(usdc.address, amountUSDCToBorrow, RateMode.Stable, '0');
+
+      //drops HF below 1
+
+      await oracle.setAssetPrice(
+        usdc.address,
+        new BigNumber(usdcPrice.toString()).multipliedBy(1.2).toFixed(0)
+      );
+
+      //mints dai to the liquidator
+
+      await usdc.mint(await convertToCurrencyDecimals(usdc.address, '1000'));
+
+      //approve protocol to access depositor wallet
+      await usdc.approve(core.address, APPROVAL_AMOUNT_LENDING_POOL_CORE);
+
+      const userReserveDataBefore = await pool.getUserReserveData(usdc.address, borrower.address);
+
+      const usdcReserveDataBefore = await pool.getReserveData(usdc.address);
+      const ethReserveDataBefore = await pool.getReserveData(MOCK_ETH_ADDRESS);
+
+      const amountToLiquidate = new BigNumber(userReserveDataBefore.currentBorrowBalance.toString())
+        .div(2)
+        .toFixed(0);
+
+      await pool.liquidationCall(
+        MOCK_ETH_ADDRESS,
+        usdc.address,
+        borrower.address,
+        amountToLiquidate,
+        true
+      );
+
+      const userReserveDataAfter = await pool.getUserReserveData(usdc.address, borrower.address);
+
+      const userGlobalDataAfter = await pool.getUserAccountData(borrower.address);
+
+      const usdcReserveDataAfter = await pool.getReserveData(usdc.address);
+      const ethReserveDataAfter = await pool.getReserveData(MOCK_ETH_ADDRESS);
+
+      const feeAddress = await addressesProvider.getTokenDistributor();
+
+      const feeAddressBalance = await BRE.ethers.provider.getBalance(feeAddress);
+
+      const collateralPrice = (await oracle.getAssetPrice(MOCK_ETH_ADDRESS)).toString();
+      const principalPrice = (await oracle.getAssetPrice(usdc.address)).toString();
+
+      const collateralDecimals = (await core.getReserveDecimals(MOCK_ETH_ADDRESS)).toString();
+      const principalDecimals = (await core.getReserveDecimals(usdc.address)).toString();
+
+      const expectedCollateralLiquidated = new BigNumber(principalPrice)
+        .times(new BigNumber(amountToLiquidate).times(105))
+        .times(new BigNumber(10).pow(collateralDecimals))
+        .div(new BigNumber(collateralPrice).times(new BigNumber(10).pow(principalDecimals)))
+        .decimalPlaces(0, BigNumber.ROUND_DOWN);
+
+      const expectedFeeLiquidated = new BigNumber(principalPrice)
+        .times(new BigNumber(userReserveDataBefore.originationFee.toString()).times(105))
+        .times(new BigNumber(10).pow(collateralDecimals))
+        .div(new BigNumber(collateralPrice).times(new BigNumber(10).pow(principalDecimals)))
+        .div(100)
+        .decimalPlaces(0, BigNumber.ROUND_DOWN);
+
+      expect(userGlobalDataAfter.healthFactor).to.be.bignumber.gt(
+        oneEther.toFixed(0),
+        'Invalid health factor'
+      );
+
+      expect(userReserveDataAfter.originationFee).to.be.bignumber.eq(
+        '0',
+        'Origination fee should be repaid'
+      );
+
+      expect(feeAddressBalance).to.be.bignumber.gt('0');
+
+      expect(userReserveDataAfter.principalBorrowBalance).to.be.bignumber.almostEqual(
+        new BigNumber(userReserveDataBefore.currentBorrowBalance.toString())
+          .minus(amountToLiquidate)
+          .toFixed(0),
+        'Invalid user borrow balance after liquidation'
+      );
+
+      expect(usdcReserveDataAfter.availableLiquidity).to.be.bignumber.almostEqual(
+        new BigNumber(usdcReserveDataBefore.availableLiquidity.toString())
+          .plus(amountToLiquidate)
+          .toFixed(0),
+        'Invalid principal available liquidity'
+      );
+
+      expect(ethReserveDataAfter.availableLiquidity).to.be.bignumber.almostEqual(
+        new BigNumber(ethReserveDataBefore.availableLiquidity.toString())
+          .minus(expectedFeeLiquidated)
+          .toFixed(0),
+        'Invalid collateral available liquidity'
+      );
+    }
+  );
+});