mirror of
				https://github.com/Instadapp/aave-protocol-v2.git
				synced 2024-07-29 21:47:30 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			493 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			493 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| import BigNumber from 'bignumber.js';
 | |
| 
 | |
| import { DRE, increaseTime } from '../../helpers/misc-utils';
 | |
| import { APPROVAL_AMOUNT_LENDING_POOL, oneEther } from '../../helpers/constants';
 | |
| import { convertToCurrencyDecimals } from '../../helpers/contracts-helpers';
 | |
| import { makeSuite } from './helpers/make-suite';
 | |
| import { ProtocolErrors, RateMode } from '../../helpers/types';
 | |
| import { calcExpectedStableDebtTokenBalance } from './helpers/utils/calculations';
 | |
| import { getUserData } from './helpers/utils/helpers';
 | |
| import { CommonsConfig } from '../../markets/aave/commons';
 | |
| 
 | |
| import { parseEther } from 'ethers/lib/utils';
 | |
| 
 | |
| const chai = require('chai');
 | |
| 
 | |
| const { expect } = chai;
 | |
| 
 | |
| makeSuite('LendingPool liquidation - liquidator receiving the underlying asset', (testEnv) => {
 | |
|   const { INVALID_HF } = ProtocolErrors;
 | |
| 
 | |
|   before('Before LendingPool liquidation: set config', () => {
 | |
|     BigNumber.config({ DECIMAL_PLACES: 0, ROUNDING_MODE: BigNumber.ROUND_DOWN });
 | |
|   });
 | |
| 
 | |
|   after('After LendingPool liquidation: reset config', () => {
 | |
|     BigNumber.config({ DECIMAL_PLACES: 20, ROUNDING_MODE: BigNumber.ROUND_HALF_UP });
 | |
|   });
 | |
| 
 | |
|   it("It's not possible to liquidate on a non-active collateral or a non active principal", async () => {
 | |
|     const { configurator, weth, pool, users, dai } = testEnv;
 | |
|     const user = users[1];
 | |
|     await configurator.deactivateReserve(weth.address);
 | |
| 
 | |
|     await expect(
 | |
|       pool.liquidationCall(weth.address, dai.address, user.address, parseEther('1000'), false)
 | |
|     ).to.be.revertedWith('2');
 | |
| 
 | |
|     await configurator.activateReserve(weth.address);
 | |
| 
 | |
|     await configurator.deactivateReserve(dai.address);
 | |
| 
 | |
|     await expect(
 | |
|       pool.liquidationCall(weth.address, dai.address, user.address, parseEther('1000'), false)
 | |
|     ).to.be.revertedWith('2');
 | |
| 
 | |
|     await configurator.activateReserve(dai.address);
 | |
|   });
 | |
| 
 | |
|   it('Deposits WETH, borrows DAI', async () => {
 | |
|     const { dai, weth, users, 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(pool.address, APPROVAL_AMOUNT_LENDING_POOL);
 | |
| 
 | |
|     //user 1 deposits 1000 DAI
 | |
|     const amountDAItoDeposit = await convertToCurrencyDecimals(dai.address, '1000');
 | |
| 
 | |
|     await pool
 | |
|       .connect(depositor.signer)
 | |
|       .deposit(dai.address, amountDAItoDeposit, depositor.address, '0');
 | |
|     //user 2 deposits 1 ETH
 | |
|     const amountETHtoDeposit = await convertToCurrencyDecimals(weth.address, '1');
 | |
| 
 | |
|     //mints WETH to borrower
 | |
|     await weth.connect(borrower.signer).mint(await convertToCurrencyDecimals(weth.address, '1000'));
 | |
| 
 | |
|     //approve protocol to access the borrower wallet
 | |
|     await weth.connect(borrower.signer).approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL);
 | |
| 
 | |
|     await pool
 | |
|       .connect(borrower.signer)
 | |
|       .deposit(weth.address, amountETHtoDeposit, borrower.address, '0');
 | |
| 
 | |
|     //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.Stable, '0', borrower.address);
 | |
| 
 | |
|     const userGlobalDataAfter = await pool.getUserAccountData(borrower.address);
 | |
| 
 | |
|     expect(userGlobalDataAfter.currentLiquidationThreshold.toString()).to.be.bignumber.equal(
 | |
|       '8250',
 | |
|       INVALID_HF
 | |
|     );
 | |
|   });
 | |
| 
 | |
|   it('Drop the health factor below 1', async () => {
 | |
|     const { dai, weth, users, pool, oracle } = testEnv;
 | |
|     const borrower = users[1];
 | |
| 
 | |
|     const daiPrice = await oracle.getAssetPrice(dai.address);
 | |
| 
 | |
|     await oracle.setAssetPrice(
 | |
|       dai.address,
 | |
|       new BigNumber(daiPrice.toString()).multipliedBy(1.18).toFixed(0)
 | |
|     );
 | |
| 
 | |
|     const userGlobalData = await pool.getUserAccountData(borrower.address);
 | |
| 
 | |
|     expect(userGlobalData.healthFactor.toString()).to.be.bignumber.lt(
 | |
|       oneEther.toFixed(0),
 | |
|       INVALID_HF
 | |
|     );
 | |
|   });
 | |
| 
 | |
|   it('Liquidates the borrow', async () => {
 | |
|     const { dai, weth, users, pool, oracle, helpersContract } = testEnv;
 | |
|     const liquidator = users[3];
 | |
|     const borrower = users[1];
 | |
| 
 | |
|     //mints dai to the liquidator
 | |
|     await dai.connect(liquidator.signer).mint(await convertToCurrencyDecimals(dai.address, '1000'));
 | |
| 
 | |
|     //approve protocol to access the liquidator wallet
 | |
|     await dai.connect(liquidator.signer).approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL);
 | |
| 
 | |
|     const daiReserveDataBefore = await helpersContract.getReserveData(dai.address);
 | |
|     const ethReserveDataBefore = await helpersContract.getReserveData(weth.address);
 | |
| 
 | |
|     const userReserveDataBefore = await getUserData(
 | |
|       pool,
 | |
|       helpersContract,
 | |
|       dai.address,
 | |
|       borrower.address
 | |
|     );
 | |
| 
 | |
|     const amountToLiquidate = userReserveDataBefore.currentStableDebt.div(2).toFixed(0);
 | |
| 
 | |
|     await increaseTime(100);
 | |
| 
 | |
|     const tx = await pool
 | |
|       .connect(liquidator.signer)
 | |
|       .liquidationCall(weth.address, dai.address, borrower.address, amountToLiquidate, false);
 | |
| 
 | |
|     const userReserveDataAfter = await getUserData(
 | |
|       pool,
 | |
|       helpersContract,
 | |
|       dai.address,
 | |
|       borrower.address
 | |
|     );
 | |
| 
 | |
|     const daiReserveDataAfter = await helpersContract.getReserveData(dai.address);
 | |
|     const ethReserveDataAfter = await helpersContract.getReserveData(weth.address);
 | |
| 
 | |
|     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(amountToLiquidate).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);
 | |
| 
 | |
|     if (!tx.blockNumber) {
 | |
|       expect(false, 'Invalid block number');
 | |
|       return;
 | |
|     }
 | |
|     const txTimestamp = new BigNumber(
 | |
|       (await DRE.ethers.provider.getBlock(tx.blockNumber)).timestamp
 | |
|     );
 | |
| 
 | |
|     const stableDebtBeforeTx = calcExpectedStableDebtTokenBalance(
 | |
|       userReserveDataBefore.principalStableDebt,
 | |
|       userReserveDataBefore.stableBorrowRate,
 | |
|       userReserveDataBefore.stableRateLastUpdated,
 | |
|       txTimestamp
 | |
|     );
 | |
| 
 | |
|     expect(userReserveDataAfter.currentStableDebt.toString()).to.be.bignumber.almostEqual(
 | |
|       stableDebtBeforeTx.minus(amountToLiquidate).toFixed(0),
 | |
|       'Invalid user debt after liquidation'
 | |
|     );
 | |
| 
 | |
|     //the liquidity index of the principal reserve needs to be bigger than the index before
 | |
|     expect(daiReserveDataAfter.liquidityIndex.toString()).to.be.bignumber.gte(
 | |
|       daiReserveDataBefore.liquidityIndex.toString(),
 | |
|       'Invalid liquidity index'
 | |
|     );
 | |
| 
 | |
|     //the principal APY after a liquidation needs to be lower than the APY before
 | |
|     expect(daiReserveDataAfter.liquidityRate.toString()).to.be.bignumber.lt(
 | |
|       daiReserveDataBefore.liquidityRate.toString(),
 | |
|       'Invalid liquidity APY'
 | |
|     );
 | |
| 
 | |
|     expect(daiReserveDataAfter.availableLiquidity.toString()).to.be.bignumber.almostEqual(
 | |
|       new BigNumber(daiReserveDataBefore.availableLiquidity.toString())
 | |
|         .plus(amountToLiquidate)
 | |
|         .toFixed(0),
 | |
|       'Invalid principal available liquidity'
 | |
|     );
 | |
| 
 | |
|     expect(ethReserveDataAfter.availableLiquidity.toString()).to.be.bignumber.almostEqual(
 | |
|       new BigNumber(ethReserveDataBefore.availableLiquidity.toString())
 | |
|         .minus(expectedCollateralLiquidated)
 | |
|         .toFixed(0),
 | |
|       'Invalid collateral available liquidity'
 | |
|     );
 | |
|   });
 | |
| 
 | |
|   it('User 3 deposits 1000 USDC, user 4 1 WETH, user 4 borrows - drops HF, liquidates the borrow', async () => {
 | |
|     const { usdc, users, pool, oracle, weth, helpersContract } = testEnv;
 | |
| 
 | |
|     const depositor = users[3];
 | |
|     const borrower = users[4];
 | |
|     const liquidator = users[5];
 | |
| 
 | |
|     //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(pool.address, APPROVAL_AMOUNT_LENDING_POOL);
 | |
| 
 | |
|     //depositor deposits 1000 USDC
 | |
|     const amountUSDCtoDeposit = await convertToCurrencyDecimals(usdc.address, '1000');
 | |
| 
 | |
|     await pool
 | |
|       .connect(depositor.signer)
 | |
|       .deposit(usdc.address, amountUSDCtoDeposit, depositor.address, '0');
 | |
| 
 | |
|     //borrower deposits 1 ETH
 | |
|     const amountETHtoDeposit = await convertToCurrencyDecimals(weth.address, '1');
 | |
| 
 | |
|     //mints WETH to borrower
 | |
|     await weth.connect(borrower.signer).mint(await convertToCurrencyDecimals(weth.address, '1000'));
 | |
| 
 | |
|     //approve protocol to access the borrower wallet
 | |
|     await weth.connect(borrower.signer).approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL);
 | |
| 
 | |
|     await pool
 | |
|       .connect(borrower.signer)
 | |
|       .deposit(weth.address, amountETHtoDeposit, borrower.address, '0');
 | |
| 
 | |
|     //borrower 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.9502)
 | |
|         .toFixed(0)
 | |
|     );
 | |
| 
 | |
|     await pool
 | |
|       .connect(borrower.signer)
 | |
|       .borrow(usdc.address, amountUSDCToBorrow, RateMode.Stable, '0', borrower.address);
 | |
| 
 | |
|     //drops HF below 1
 | |
|     await oracle.setAssetPrice(
 | |
|       usdc.address,
 | |
|       new BigNumber(usdcPrice.toString()).multipliedBy(1.12).toFixed(0)
 | |
|     );
 | |
| 
 | |
|     //mints dai to the liquidator
 | |
| 
 | |
|     await usdc
 | |
|       .connect(liquidator.signer)
 | |
|       .mint(await convertToCurrencyDecimals(usdc.address, '1000'));
 | |
| 
 | |
|     //approve protocol to access depositor wallet
 | |
|     await usdc.connect(liquidator.signer).approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL);
 | |
| 
 | |
|     const userReserveDataBefore = await helpersContract.getUserReserveData(
 | |
|       usdc.address,
 | |
|       borrower.address
 | |
|     );
 | |
| 
 | |
|     const usdcReserveDataBefore = await helpersContract.getReserveData(usdc.address);
 | |
|     const ethReserveDataBefore = await helpersContract.getReserveData(weth.address);
 | |
| 
 | |
|     const amountToLiquidate = DRE.ethers.BigNumber.from(
 | |
|       userReserveDataBefore.currentStableDebt.toString()
 | |
|     )
 | |
|       .div(2)
 | |
|       .toString();
 | |
| 
 | |
|     await pool
 | |
|       .connect(liquidator.signer)
 | |
|       .liquidationCall(weth.address, usdc.address, borrower.address, amountToLiquidate, false);
 | |
| 
 | |
|     const userReserveDataAfter = await helpersContract.getUserReserveData(
 | |
|       usdc.address,
 | |
|       borrower.address
 | |
|     );
 | |
| 
 | |
|     const userGlobalDataAfter = await pool.getUserAccountData(borrower.address);
 | |
| 
 | |
|     const usdcReserveDataAfter = await helpersContract.getReserveData(usdc.address);
 | |
|     const ethReserveDataAfter = await helpersContract.getReserveData(weth.address);
 | |
| 
 | |
|     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(amountToLiquidate).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);
 | |
| 
 | |
|     expect(userGlobalDataAfter.healthFactor.toString()).to.be.bignumber.gt(
 | |
|       oneEther.toFixed(0),
 | |
|       'Invalid health factor'
 | |
|     );
 | |
| 
 | |
|     expect(userReserveDataAfter.currentStableDebt.toString()).to.be.bignumber.almostEqual(
 | |
|       new BigNumber(userReserveDataBefore.currentStableDebt.toString())
 | |
|         .minus(amountToLiquidate)
 | |
|         .toFixed(0),
 | |
|       'Invalid user borrow balance after liquidation'
 | |
|     );
 | |
| 
 | |
|     //the liquidity index of the principal reserve needs to be bigger than the index before
 | |
|     expect(usdcReserveDataAfter.liquidityIndex.toString()).to.be.bignumber.gte(
 | |
|       usdcReserveDataBefore.liquidityIndex.toString(),
 | |
|       'Invalid liquidity index'
 | |
|     );
 | |
| 
 | |
|     //the principal APY after a liquidation needs to be lower than the APY before
 | |
|     expect(usdcReserveDataAfter.liquidityRate.toString()).to.be.bignumber.lt(
 | |
|       usdcReserveDataBefore.liquidityRate.toString(),
 | |
|       'Invalid liquidity APY'
 | |
|     );
 | |
| 
 | |
|     expect(usdcReserveDataAfter.availableLiquidity.toString()).to.be.bignumber.almostEqual(
 | |
|       new BigNumber(usdcReserveDataBefore.availableLiquidity.toString())
 | |
|         .plus(amountToLiquidate)
 | |
|         .toFixed(0),
 | |
|       'Invalid principal available liquidity'
 | |
|     );
 | |
| 
 | |
|     expect(ethReserveDataAfter.availableLiquidity.toString()).to.be.bignumber.almostEqual(
 | |
|       new BigNumber(ethReserveDataBefore.availableLiquidity.toString())
 | |
|         .minus(expectedCollateralLiquidated)
 | |
|         .toFixed(0),
 | |
|       'Invalid collateral available liquidity'
 | |
|     );
 | |
|   });
 | |
| 
 | |
|   it('User 4 deposits 10 AAVE - drops HF, liquidates the AAVE, which results on a lower amount being liquidated', async () => {
 | |
|     const { aave, usdc, users, pool, oracle, helpersContract } = testEnv;
 | |
| 
 | |
|     const depositor = users[3];
 | |
|     const borrower = users[4];
 | |
|     const liquidator = users[5];
 | |
| 
 | |
|     //mints AAVE to borrower
 | |
|     await aave.connect(borrower.signer).mint(await convertToCurrencyDecimals(aave.address, '10'));
 | |
| 
 | |
|     //approve protocol to access the borrower wallet
 | |
|     await aave.connect(borrower.signer).approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL);
 | |
| 
 | |
|     //borrower deposits 10 AAVE
 | |
|     const amountToDeposit = await convertToCurrencyDecimals(aave.address, '10');
 | |
| 
 | |
|     await pool
 | |
|       .connect(borrower.signer)
 | |
|       .deposit(aave.address, amountToDeposit, borrower.address, '0');
 | |
|     const usdcPrice = await oracle.getAssetPrice(usdc.address);
 | |
| 
 | |
|     //drops HF below 1
 | |
|     await oracle.setAssetPrice(
 | |
|       usdc.address,
 | |
|       new BigNumber(usdcPrice.toString()).multipliedBy(1.14).toFixed(0)
 | |
|     );
 | |
| 
 | |
|     //mints usdc to the liquidator
 | |
|     await usdc
 | |
|       .connect(liquidator.signer)
 | |
|       .mint(await convertToCurrencyDecimals(usdc.address, '1000'));
 | |
| 
 | |
|     //approve protocol to access depositor wallet
 | |
|     await usdc.connect(liquidator.signer).approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL);
 | |
| 
 | |
|     const userReserveDataBefore = await helpersContract.getUserReserveData(
 | |
|       usdc.address,
 | |
|       borrower.address
 | |
|     );
 | |
| 
 | |
|     const usdcReserveDataBefore = await helpersContract.getReserveData(usdc.address);
 | |
|     const aaveReserveDataBefore = await helpersContract.getReserveData(aave.address);
 | |
| 
 | |
|     const amountToLiquidate = new BigNumber(userReserveDataBefore.currentStableDebt.toString())
 | |
|       .div(2)
 | |
|       .decimalPlaces(0, BigNumber.ROUND_DOWN)
 | |
|       .toFixed(0);
 | |
| 
 | |
|     const collateralPrice = await oracle.getAssetPrice(aave.address);
 | |
|     const principalPrice = await oracle.getAssetPrice(usdc.address);
 | |
| 
 | |
|     await pool
 | |
|       .connect(liquidator.signer)
 | |
|       .liquidationCall(aave.address, usdc.address, borrower.address, amountToLiquidate, false);
 | |
| 
 | |
|     const userReserveDataAfter = await helpersContract.getUserReserveData(
 | |
|       usdc.address,
 | |
|       borrower.address
 | |
|     );
 | |
| 
 | |
|     const userGlobalDataAfter = await pool.getUserAccountData(borrower.address);
 | |
| 
 | |
|     const usdcReserveDataAfter = await helpersContract.getReserveData(usdc.address);
 | |
|     const aaveReserveDataAfter = await helpersContract.getReserveData(aave.address);
 | |
| 
 | |
|     const aaveConfiguration = await helpersContract.getReserveConfigurationData(aave.address);
 | |
|     const collateralDecimals = aaveConfiguration.decimals.toString();
 | |
|     const liquidationBonus = aaveConfiguration.liquidationBonus.toString();
 | |
| 
 | |
|     const principalDecimals = (
 | |
|       await helpersContract.getReserveConfigurationData(usdc.address)
 | |
|     ).decimals.toString();
 | |
| 
 | |
|     const expectedCollateralLiquidated = oneEther.multipliedBy('10');
 | |
| 
 | |
|     const expectedPrincipal = new BigNumber(collateralPrice.toString())
 | |
|       .times(expectedCollateralLiquidated)
 | |
|       .times(new BigNumber(10).pow(principalDecimals))
 | |
|       .div(
 | |
|         new BigNumber(principalPrice.toString()).times(new BigNumber(10).pow(collateralDecimals))
 | |
|       )
 | |
|       .times(10000)
 | |
|       .div(liquidationBonus.toString())
 | |
|       .decimalPlaces(0, BigNumber.ROUND_DOWN);
 | |
| 
 | |
|     expect(userGlobalDataAfter.healthFactor.toString()).to.be.bignumber.gt(
 | |
|       oneEther.toFixed(0),
 | |
|       'Invalid health factor'
 | |
|     );
 | |
| 
 | |
|     expect(userReserveDataAfter.currentStableDebt.toString()).to.be.bignumber.almostEqual(
 | |
|       new BigNumber(userReserveDataBefore.currentStableDebt.toString())
 | |
|         .minus(expectedPrincipal)
 | |
|         .toFixed(0),
 | |
|       'Invalid user borrow balance after liquidation'
 | |
|     );
 | |
| 
 | |
|     expect(usdcReserveDataAfter.availableLiquidity.toString()).to.be.bignumber.almostEqual(
 | |
|       new BigNumber(usdcReserveDataBefore.availableLiquidity.toString())
 | |
|         .plus(expectedPrincipal)
 | |
|         .toFixed(0),
 | |
|       'Invalid principal available liquidity'
 | |
|     );
 | |
| 
 | |
|     expect(aaveReserveDataAfter.availableLiquidity.toString()).to.be.bignumber.almostEqual(
 | |
|       new BigNumber(aaveReserveDataBefore.availableLiquidity.toString())
 | |
|         .minus(expectedCollateralLiquidated)
 | |
|         .toFixed(0),
 | |
|       'Invalid collateral available liquidity'
 | |
|     );
 | |
|   });
 | |
| });
 | 
