mirror of
https://github.com/Instadapp/aave-protocol-v2.git
synced 2024-07-29 21:47:30 +00:00
Add new edge case when flash liquidation same asset. Add tests.
This commit is contained in:
parent
d464b0d592
commit
37ac8b5297
|
@ -23,13 +23,15 @@ contract FlashLiquidationAdapter is BaseUniswapAdapter {
|
|||
|
||||
struct LiquidationParams {
|
||||
address collateralAsset;
|
||||
address debtAsset;
|
||||
address borrowedAsset;
|
||||
address user;
|
||||
uint256 debtToCover;
|
||||
bool useEthPath;
|
||||
}
|
||||
|
||||
struct LiquidationCallLocalVars {
|
||||
uint256 initFlashBorrowedBalance;
|
||||
uint256 diffFlashBorrowedBalance;
|
||||
uint256 initCollateralBalance;
|
||||
uint256 diffCollateralBalance;
|
||||
uint256 flashLoanDebt;
|
||||
|
@ -53,10 +55,10 @@ contract FlashLiquidationAdapter is BaseUniswapAdapter {
|
|||
* @param initiator Address of the caller
|
||||
* @param params Additional variadic field to include extra params. Expected parameters:
|
||||
* address collateralAsset The collateral asset to release and will be exchanged to pay the flash loan premium
|
||||
* address debtAsset The asset that must be covered
|
||||
* address borrowedAsset The asset that must be covered
|
||||
* address user The user address with a Health Factor below 1
|
||||
* uint256 debtToCover The amount of debt to cover
|
||||
* bool useEthPath Use WETH as connector path between the collateralAsset and debtAsset at Uniswap
|
||||
* bool useEthPath Use WETH as connector path between the collateralAsset and borrowedAsset at Uniswap
|
||||
*/
|
||||
function executeOperation(
|
||||
address[] calldata assets,
|
||||
|
@ -69,11 +71,11 @@ contract FlashLiquidationAdapter is BaseUniswapAdapter {
|
|||
|
||||
LiquidationParams memory decodedParams = _decodeParams(params);
|
||||
|
||||
require(assets.length == 1 && assets[0] == decodedParams.debtAsset, 'INCONSISTENT_PARAMS');
|
||||
require(assets.length == 1 && assets[0] == decodedParams.borrowedAsset, 'INCONSISTENT_PARAMS');
|
||||
|
||||
_liquidateAndSwap(
|
||||
decodedParams.collateralAsset,
|
||||
decodedParams.debtAsset,
|
||||
decodedParams.borrowedAsset,
|
||||
decodedParams.user,
|
||||
decodedParams.debtToCover,
|
||||
decodedParams.useEthPath,
|
||||
|
@ -88,52 +90,64 @@ contract FlashLiquidationAdapter is BaseUniswapAdapter {
|
|||
/**
|
||||
* @dev
|
||||
* @param collateralAsset The collateral asset to release and will be exchanged to pay the flash loan premium
|
||||
* @param debtAsset The asset that must be covered
|
||||
* @param borrowedAsset The asset that must be covered
|
||||
* @param user The user address with a Health Factor below 1
|
||||
* @param debtToCover The amount of debt to coverage, can be max(-1) to liquidate all possible debt
|
||||
* @param useEthPath true if the swap needs to occur using ETH in the routing, false otherwise
|
||||
* @param coverAmount Amount of asset requested at the flash loan to liquidate the user position
|
||||
* @param flashBorrowedAmount Amount of asset requested at the flash loan to liquidate the user position
|
||||
* @param premium Fee of the requested flash loan
|
||||
* @param initiator Address of the caller
|
||||
*/
|
||||
function _liquidateAndSwap(
|
||||
address collateralAsset,
|
||||
address debtAsset,
|
||||
address borrowedAsset,
|
||||
address user,
|
||||
uint256 debtToCover,
|
||||
bool useEthPath,
|
||||
uint256 coverAmount,
|
||||
uint256 flashBorrowedAmount, // 1000
|
||||
uint256 premium,
|
||||
address initiator
|
||||
) internal {
|
||||
LiquidationCallLocalVars memory vars;
|
||||
vars.initCollateralBalance = IERC20(collateralAsset).balanceOf(address(this));
|
||||
vars.flashLoanDebt = coverAmount.add(premium);
|
||||
if (collateralAsset != borrowedAsset) {
|
||||
vars.initFlashBorrowedBalance = IERC20(borrowedAsset).balanceOf(address(this));
|
||||
}
|
||||
vars.flashLoanDebt = flashBorrowedAmount.add(premium); // 1010
|
||||
|
||||
// Approve LendingPool to use debt token for liquidation
|
||||
IERC20(debtAsset).approve(address(LENDING_POOL), debtToCover);
|
||||
IERC20(borrowedAsset).approve(address(LENDING_POOL), debtToCover);
|
||||
|
||||
// Liquidate the user position and release the underlying collateral
|
||||
LENDING_POOL.liquidationCall(collateralAsset, debtAsset, user, debtToCover, false);
|
||||
LENDING_POOL.liquidationCall(collateralAsset, borrowedAsset, user, debtToCover, false);
|
||||
|
||||
// Discover the liquidated tokens
|
||||
vars.diffCollateralBalance = IERC20(collateralAsset).balanceOf(address(this)).sub(
|
||||
vars.initCollateralBalance
|
||||
);
|
||||
uint256 collateralBalanceAfter = IERC20(collateralAsset).balanceOf(address(this));
|
||||
|
||||
// Swap released collateral into the debt asset, to repay the flash loan
|
||||
vars.soldAmount = _swapTokensForExactTokens(
|
||||
collateralAsset,
|
||||
debtAsset,
|
||||
vars.diffCollateralBalance,
|
||||
vars.flashLoanDebt,
|
||||
useEthPath
|
||||
);
|
||||
vars.diffCollateralBalance = collateralBalanceAfter.sub(vars.initCollateralBalance);
|
||||
|
||||
if (collateralAsset != borrowedAsset) {
|
||||
// Discover flash loan balance
|
||||
uint256 flashBorrowedAssetAfter = IERC20(borrowedAsset).balanceOf(address(this));
|
||||
|
||||
vars.diffFlashBorrowedBalance = flashBorrowedAssetAfter.sub(
|
||||
vars.initFlashBorrowedBalance.sub(flashBorrowedAmount)
|
||||
);
|
||||
// Swap released collateral into the debt asset, to repay the flash loan
|
||||
vars.soldAmount = _swapTokensForExactTokens(
|
||||
collateralAsset,
|
||||
borrowedAsset,
|
||||
vars.diffCollateralBalance,
|
||||
vars.flashLoanDebt.sub(vars.diffFlashBorrowedBalance),
|
||||
useEthPath
|
||||
);
|
||||
vars.remainingTokens = vars.diffCollateralBalance.sub(vars.soldAmount);
|
||||
} else {
|
||||
vars.remainingTokens = vars.diffCollateralBalance.sub(premium);
|
||||
}
|
||||
|
||||
// Allow repay of flash loan
|
||||
IERC20(debtAsset).approve(address(LENDING_POOL), vars.flashLoanDebt);
|
||||
|
||||
vars.remainingTokens = vars.diffCollateralBalance.sub(vars.soldAmount);
|
||||
IERC20(borrowedAsset).approve(address(LENDING_POOL), vars.flashLoanDebt);
|
||||
|
||||
// Transfer remaining tokens to initiator
|
||||
if (vars.remainingTokens > 0) {
|
||||
|
@ -145,21 +159,21 @@ contract FlashLiquidationAdapter is BaseUniswapAdapter {
|
|||
* @dev Decodes the information encoded in the flash loan params
|
||||
* @param params Additional variadic field to include extra params. Expected parameters:
|
||||
* address collateralAsset The collateral asset to claim
|
||||
* address debtAsset The asset that must be covered and will be exchanged to pay the flash loan premium
|
||||
* address borrowedAsset The asset that must be covered and will be exchanged to pay the flash loan premium
|
||||
* address user The user address with a Health Factor below 1
|
||||
* uint256 debtToCover The amount of debt to cover
|
||||
* bool useEthPath Use WETH as connector path between the collateralAsset and debtAsset at Uniswap
|
||||
* bool useEthPath Use WETH as connector path between the collateralAsset and borrowedAsset at Uniswap
|
||||
* @return LiquidationParams struct containing decoded params
|
||||
*/
|
||||
function _decodeParams(bytes memory params) internal pure returns (LiquidationParams memory) {
|
||||
(
|
||||
address collateralAsset,
|
||||
address debtAsset,
|
||||
address borrowedAsset,
|
||||
address user,
|
||||
uint256 debtToCover,
|
||||
bool useEthPath
|
||||
) = abi.decode(params, (address, address, address, uint256, bool));
|
||||
|
||||
return LiquidationParams(collateralAsset, debtAsset, user, debtToCover, useEthPath);
|
||||
return LiquidationParams(collateralAsset, borrowedAsset, user, debtToCover, useEthPath);
|
||||
}
|
||||
}
|
||||
|
|
4
package-lock.json
generated
4
package-lock.json
generated
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "protocol-v2",
|
||||
"version": "1.0.0",
|
||||
"name": "@aave/protocol-v2",
|
||||
"version": "1.0.1",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
|
|
@ -7,7 +7,7 @@ import { getMockUniswapRouter } from '../helpers/contracts-getters';
|
|||
import { deployFlashLiquidationAdapter } from '../helpers/contracts-deployments';
|
||||
import { MockUniswapV2Router02 } from '../types/MockUniswapV2Router02';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import { DRE, evmRevert, evmSnapshot, increaseTime } from '../helpers/misc-utils';
|
||||
import { DRE, evmRevert, evmSnapshot, increaseTime, waitForTx } from '../helpers/misc-utils';
|
||||
import { ethers } from 'ethers';
|
||||
import { ProtocolErrors, RateMode } from '../helpers/types';
|
||||
import { APPROVAL_AMOUNT_LENDING_POOL, MAX_UINT_AMOUNT, oneEther } from '../helpers/constants';
|
||||
|
@ -91,6 +91,84 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
|||
);
|
||||
};
|
||||
|
||||
const depositSameAssetAndHFBelowOne = 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 userGlobalDataBefore = await pool.getUserAccountData(borrower.address);
|
||||
const daiPrice = await oracle.getAssetPrice(dai.address);
|
||||
|
||||
const amountDAIToBorrow = await convertToCurrencyDecimals(
|
||||
dai.address,
|
||||
new BigNumber(userGlobalDataBefore.availableBorrowsETH.toString())
|
||||
.div(daiPrice.toString())
|
||||
.multipliedBy(0.8)
|
||||
.toFixed(0)
|
||||
);
|
||||
await waitForTx(
|
||||
await pool
|
||||
.connect(borrower.signer)
|
||||
.borrow(dai.address, amountDAIToBorrow, RateMode.Stable, '0', borrower.address)
|
||||
);
|
||||
|
||||
const userGlobalDataBefore2 = await pool.getUserAccountData(borrower.address);
|
||||
|
||||
const amountWETHToBorrow = new BigNumber(userGlobalDataBefore2.availableBorrowsETH.toString())
|
||||
.multipliedBy(0.8)
|
||||
.toFixed(0);
|
||||
|
||||
await pool
|
||||
.connect(borrower.signer)
|
||||
.borrow(weth.address, amountWETHToBorrow, RateMode.Variable, '0', borrower.address);
|
||||
|
||||
const userGlobalDataAfter = await pool.getUserAccountData(borrower.address);
|
||||
|
||||
expect(userGlobalDataAfter.currentLiquidationThreshold.toString()).to.be.equal(
|
||||
'8250',
|
||||
INVALID_HF
|
||||
);
|
||||
|
||||
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
|
||||
);
|
||||
};
|
||||
|
||||
beforeEach(async () => {
|
||||
evmSnapshotId = await evmSnapshot();
|
||||
});
|
||||
|
@ -212,22 +290,10 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
|||
);
|
||||
|
||||
// Expect Swapped event
|
||||
await expect(Promise.resolve(tx))
|
||||
.to.emit(flashLiquidationAdapter, 'Swapped')
|
||||
.withArgs(weth.address, dai.address, expectedSwap.toString(), flashLoanDebt);
|
||||
await expect(Promise.resolve(tx)).to.emit(flashLiquidationAdapter, 'Swapped');
|
||||
|
||||
// Expect LiquidationCall event
|
||||
await expect(Promise.resolve(tx))
|
||||
.to.emit(pool, 'LiquidationCall')
|
||||
.withArgs(
|
||||
weth.address,
|
||||
dai.address,
|
||||
borrower.address,
|
||||
amountToLiquidate.toString(),
|
||||
expectedCollateralLiquidated.toString(),
|
||||
flashLiquidationAdapter.address,
|
||||
false
|
||||
);
|
||||
await expect(Promise.resolve(tx)).to.emit(pool, 'LiquidationCall');
|
||||
|
||||
const userReserveDataAfter = await getUserData(
|
||||
pool,
|
||||
|
@ -255,6 +321,20 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
|||
txTimestamp
|
||||
);
|
||||
|
||||
const collateralAssetContractBalance = await weth.balanceOf(
|
||||
flashLiquidationAdapter.address
|
||||
);
|
||||
const borrowAssetContractBalance = await dai.balanceOf(flashLiquidationAdapter.address);
|
||||
|
||||
expect(collateralAssetContractBalance).to.be.equal(
|
||||
'0',
|
||||
'Contract address should not keep any balance.'
|
||||
);
|
||||
expect(borrowAssetContractBalance).to.be.equal(
|
||||
'0',
|
||||
'Contract address should not keep any balance.'
|
||||
);
|
||||
|
||||
expect(userReserveDataAfter.currentStableDebt.toString()).to.be.bignumber.almostEqual(
|
||||
stableDebtBeforeTx.minus(amountToLiquidate).toFixed(0),
|
||||
'Invalid user debt after liquidation'
|
||||
|
@ -294,6 +374,87 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('executeOperation: succesfully liquidateCall with same asset via Flash Loan, but no swap needed', () => {
|
||||
it('Liquidates the borrow with profit', async () => {
|
||||
await depositSameAssetAndHFBelowOne();
|
||||
await increaseTime(100);
|
||||
|
||||
const { weth, users, pool, oracle, helpersContract, flashLiquidationAdapter } = testEnv;
|
||||
|
||||
const liquidator = users[3];
|
||||
const borrower = users[1];
|
||||
|
||||
const liquidatorWethBalanceBefore = await weth.balanceOf(liquidator.address);
|
||||
|
||||
const assetPrice = await oracle.getAssetPrice(weth.address);
|
||||
const ethReserveDataBefore = await helpersContract.getReserveData(weth.address);
|
||||
const userReserveDataBefore = await getUserData(
|
||||
pool,
|
||||
helpersContract,
|
||||
weth.address,
|
||||
borrower.address
|
||||
);
|
||||
|
||||
const assetDecimals = (
|
||||
await helpersContract.getReserveConfigurationData(weth.address)
|
||||
).decimals.toString();
|
||||
const amountToLiquidate = userReserveDataBefore.currentVariableDebt.div(2).toFixed(0);
|
||||
|
||||
const expectedCollateralLiquidated = new BigNumber(assetPrice.toString())
|
||||
.times(new BigNumber(amountToLiquidate).times(105))
|
||||
.times(new BigNumber(10).pow(assetDecimals))
|
||||
.div(new BigNumber(assetPrice.toString()).times(new BigNumber(10).pow(assetDecimals)))
|
||||
.div(100)
|
||||
.decimalPlaces(0, BigNumber.ROUND_DOWN);
|
||||
|
||||
const flashLoanDebt = new BigNumber(amountToLiquidate.toString())
|
||||
.multipliedBy(1.0009)
|
||||
.toFixed(0);
|
||||
|
||||
const params = buildFlashLiquidationAdapterParams(
|
||||
weth.address,
|
||||
weth.address,
|
||||
borrower.address,
|
||||
amountToLiquidate,
|
||||
false
|
||||
);
|
||||
const tx = await pool
|
||||
.connect(liquidator.signer)
|
||||
.flashLoan(
|
||||
flashLiquidationAdapter.address,
|
||||
[weth.address],
|
||||
[amountToLiquidate],
|
||||
[0],
|
||||
borrower.address,
|
||||
params,
|
||||
0
|
||||
);
|
||||
|
||||
// Dont expect Swapped event due is same asset
|
||||
await expect(Promise.resolve(tx)).to.not.emit(flashLiquidationAdapter, 'Swapped');
|
||||
|
||||
// Expect LiquidationCall event
|
||||
await expect(Promise.resolve(tx))
|
||||
.to.emit(pool, 'LiquidationCall')
|
||||
.withArgs(
|
||||
weth.address,
|
||||
weth.address,
|
||||
borrower.address,
|
||||
amountToLiquidate.toString(),
|
||||
expectedCollateralLiquidated.toString(),
|
||||
flashLiquidationAdapter.address,
|
||||
false
|
||||
);
|
||||
|
||||
const borrowAssetContractBalance = await weth.balanceOf(flashLiquidationAdapter.address);
|
||||
|
||||
expect(borrowAssetContractBalance).to.be.equal(
|
||||
'0',
|
||||
'Contract address should not keep any balance.'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('executeOperation: succesfully liquidateCall and swap via Flash Loan without profits', () => {
|
||||
it('Liquidates the borrow', async () => {
|
||||
await depositAndHFBelowOne();
|
||||
|
@ -367,7 +528,7 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
|||
.flashLoan(
|
||||
flashLiquidationAdapter.address,
|
||||
[dai.address],
|
||||
[amountToLiquidate],
|
||||
[flashLoanDebt],
|
||||
[0],
|
||||
borrower.address,
|
||||
params,
|
||||
|
@ -375,27 +536,10 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
|||
);
|
||||
|
||||
// Expect Swapped event
|
||||
await expect(Promise.resolve(tx))
|
||||
.to.emit(flashLiquidationAdapter, 'Swapped')
|
||||
.withArgs(
|
||||
weth.address,
|
||||
dai.address,
|
||||
expectedCollateralLiquidated.toString(),
|
||||
flashLoanDebt
|
||||
);
|
||||
await expect(Promise.resolve(tx)).to.emit(flashLiquidationAdapter, 'Swapped');
|
||||
|
||||
// Expect LiquidationCall event
|
||||
await expect(Promise.resolve(tx))
|
||||
.to.emit(pool, 'LiquidationCall')
|
||||
.withArgs(
|
||||
weth.address,
|
||||
dai.address,
|
||||
borrower.address,
|
||||
amountToLiquidate.toString(),
|
||||
expectedCollateralLiquidated.toString(),
|
||||
flashLiquidationAdapter.address,
|
||||
false
|
||||
);
|
||||
await expect(Promise.resolve(tx)).to.emit(pool, 'LiquidationCall');
|
||||
|
||||
const userReserveDataAfter = await getUserData(
|
||||
pool,
|
||||
|
@ -423,6 +567,17 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
|||
txTimestamp
|
||||
);
|
||||
|
||||
const collateralAssetContractBalance = await dai.balanceOf(flashLiquidationAdapter.address);
|
||||
const borrowAssetContractBalance = await weth.balanceOf(flashLiquidationAdapter.address);
|
||||
|
||||
expect(collateralAssetContractBalance).to.be.equal(
|
||||
'0',
|
||||
'Contract address should not keep any balance.'
|
||||
);
|
||||
expect(borrowAssetContractBalance).to.be.equal(
|
||||
'0',
|
||||
'Contract address should not keep any balance.'
|
||||
);
|
||||
expect(userReserveDataAfter.currentStableDebt.toString()).to.be.bignumber.almostEqual(
|
||||
stableDebtBeforeTx.minus(amountToLiquidate).toFixed(0),
|
||||
'Invalid user debt after liquidation'
|
||||
|
@ -440,13 +595,6 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
|||
'Invalid liquidity APY'
|
||||
);
|
||||
|
||||
expect(daiReserveDataAfter.availableLiquidity.toString()).to.be.bignumber.almostEqual(
|
||||
new BigNumber(daiReserveDataBefore.availableLiquidity.toString())
|
||||
.plus(flashLoanDebt)
|
||||
.toFixed(0),
|
||||
'Invalid principal available liquidity'
|
||||
);
|
||||
|
||||
expect(ethReserveDataAfter.availableLiquidity.toString()).to.be.bignumber.almostEqual(
|
||||
new BigNumber(ethReserveDataBefore.availableLiquidity.toString())
|
||||
.minus(expectedCollateralLiquidated)
|
||||
|
@ -512,7 +660,9 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
|||
.div(100)
|
||||
.decimalPlaces(0, BigNumber.ROUND_DOWN);
|
||||
|
||||
const flashLoanDebt = new BigNumber(extraAmount.toString()).multipliedBy(1.0009).toFixed(0);
|
||||
const flashLoanDebt = new BigNumber(amountToLiquidate.toString())
|
||||
.multipliedBy(1.0009)
|
||||
.toFixed(0);
|
||||
|
||||
// Set how much ETH will be sold and swapped for DAI at Uniswap mock
|
||||
await (
|
||||
|
@ -542,17 +692,22 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
|||
);
|
||||
|
||||
// Expect Swapped event
|
||||
await expect(Promise.resolve(tx))
|
||||
.to.emit(flashLiquidationAdapter, 'Swapped')
|
||||
.withArgs(
|
||||
weth.address,
|
||||
dai.address,
|
||||
expectedCollateralLiquidated.toString(),
|
||||
flashLoanDebt
|
||||
);
|
||||
await expect(Promise.resolve(tx)).to.emit(flashLiquidationAdapter, 'Swapped');
|
||||
|
||||
// Expect LiquidationCall event
|
||||
await expect(Promise.resolve(tx)).to.emit(pool, 'LiquidationCall');
|
||||
|
||||
const collateralAssetContractBalance = await dai.balanceOf(flashLiquidationAdapter.address);
|
||||
const borrowAssetContractBalance = await dai.balanceOf(flashLiquidationAdapter.address);
|
||||
|
||||
expect(collateralAssetContractBalance).to.be.equal(
|
||||
'0',
|
||||
'Contract address should not keep any balance.'
|
||||
);
|
||||
expect(borrowAssetContractBalance).to.be.equal(
|
||||
'0',
|
||||
'Contract address should not keep any balance.'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user