From 94cdefb2e93004c8fd3f9ec3a67c7822623bc202 Mon Sep 17 00:00:00 2001 From: Zer0dot <zer0dot.dev@gmail.com> Date: Mon, 8 Feb 2021 23:50:12 -0500 Subject: [PATCH] Began implementing lp market specific tests --- test-suites/test-lp/atoken-transfer.spec.ts | 6 +- test-suites/test-lp/configurator.spec.ts | 26 ++++ test-suites/test-lp/flashloan.spec.ts | 134 ++++++++++++++++-- .../test-lp/liquidation-atoken.spec.ts | 10 +- .../test-lp/liquidation-underlying.spec.ts | 20 +-- 5 files changed, 167 insertions(+), 29 deletions(-) diff --git a/test-suites/test-lp/atoken-transfer.spec.ts b/test-suites/test-lp/atoken-transfer.spec.ts index 7e7c029b..df58bbcf 100644 --- a/test-suites/test-lp/atoken-transfer.spec.ts +++ b/test-suites/test-lp/atoken-transfer.spec.ts @@ -45,7 +45,7 @@ makeSuite('AToken: Transfer', (testEnv: TestEnv) => { ); }); - it('User 0 deposits 1 WETH and user 1 tries to borrow the WETH with the received DAI as collateral', async () => { + it('User 0 deposits 1 WETH and user 1 tries to borrow the WETH variable with the received DAI as collateral', async () => { const { users, pool, weth, helpersContract } = testEnv; const userAddress = await pool.signer.getAddress(); @@ -61,7 +61,7 @@ makeSuite('AToken: Transfer', (testEnv: TestEnv) => { .borrow( weth.address, ethers.utils.parseEther('0.1'), - RateMode.Stable, + RateMode.Variable, AAVE_REFERRAL, users[1].address ); @@ -71,7 +71,7 @@ makeSuite('AToken: Transfer', (testEnv: TestEnv) => { users[1].address ); - expect(userReserveData.currentStableDebt.toString()).to.be.eq(ethers.utils.parseEther('0.1')); + expect(userReserveData.currentVariableDebt.toString()).to.be.eq(ethers.utils.parseEther('0.1')); }); it('User 1 tries to transfer all the DAI used as collateral back to user 0 (revert expected)', async () => { diff --git a/test-suites/test-lp/configurator.spec.ts b/test-suites/test-lp/configurator.spec.ts index 6483b391..f4557791 100644 --- a/test-suites/test-lp/configurator.spec.ts +++ b/test-suites/test-lp/configurator.spec.ts @@ -316,6 +316,32 @@ makeSuite('LendingPoolConfigurator', (testEnv: TestEnv) => { expect(reserveFactor).to.be.equal(strategyWETH.reserveFactor); }); + it('Disable stable borrow rate to return to the original state on the ETH reserve', async () => { + const { configurator, helpersContract, weth } = testEnv; + await configurator.disableReserveStableRate(weth.address); + const { + decimals, + ltv, + liquidationBonus, + liquidationThreshold, + reserveFactor, + stableBorrowRateEnabled, + borrowingEnabled, + isActive, + isFrozen, + } = await helpersContract.getReserveConfigurationData(weth.address); + + expect(borrowingEnabled).to.be.equal(true); + expect(isActive).to.be.equal(true); + expect(isFrozen).to.be.equal(false); + expect(decimals).to.be.equal(strategyWETH.reserveDecimals); + expect(ltv).to.be.equal(strategyWETH.baseLTVAsCollateral); + expect(liquidationThreshold).to.be.equal(strategyWETH.liquidationThreshold); + expect(liquidationBonus).to.be.equal(strategyWETH.liquidationBonus); + expect(stableBorrowRateEnabled).to.be.equal(strategyWETH.stableBorrowRateEnabled); + expect(reserveFactor).to.be.equal(strategyWETH.reserveFactor); + }); + it('Check the onlyAaveAdmin on disableReserveStableRate', async () => { const { configurator, users, weth } = testEnv; await expect( diff --git a/test-suites/test-lp/flashloan.spec.ts b/test-suites/test-lp/flashloan.spec.ts index 4a5f5576..22e9ade2 100644 --- a/test-suites/test-lp/flashloan.spec.ts +++ b/test-suites/test-lp/flashloan.spec.ts @@ -22,6 +22,7 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => { VL_COLLATERAL_BALANCE_IS_0, TRANSFER_AMOUNT_EXCEEDS_BALANCE, LP_INVALID_FLASHLOAN_MODE, + VL_STABLE_BORROWING_NOT_ENABLED, SAFEERC20_LOWLEVEL_CALL, LP_INVALID_FLASH_LOAN_EXECUTOR_RETURN, LP_BORROW_ALLOWANCE_NOT_ENOUGH, @@ -384,7 +385,39 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => { ).to.be.revertedWith(SAFEERC20_LOWLEVEL_CALL); }); - it('Caller takes a WETH flashloan with mode = 1', async () => { + it('Caller takes a WETH flashloan with mode = 1, should revert since stable borrowing is disabled', async () => { + const { dai, pool, weth, users, helpersContract } = testEnv; + + const caller = users[3]; + + const flashAmount = ethers.utils.parseEther('0.8'); + + await _mockFlashLoanReceiver.setFailExecutionTransfer(true); + + await expect(pool + .connect(caller.signer) + .flashLoan( + _mockFlashLoanReceiver.address, + [weth.address], + [flashAmount], + [1], + caller.address, + '0x10', + '0' + )).to.be.revertedWith(VL_STABLE_BORROWING_NOT_ENABLED); + + const { stableDebtTokenAddress } = await helpersContract.getReserveTokensAddresses( + weth.address + ); + + const wethDebtToken = await getStableDebtToken(stableDebtTokenAddress); + + const callerDebt = await wethDebtToken.balanceOf(caller.address); + + expect(callerDebt.toString()).to.be.equal('0', 'Invalid user debt'); + }); + + it('Caller takes a WETH flashloan with mode = 2', async () => { const { dai, pool, weth, users, helpersContract } = testEnv; const caller = users[3]; @@ -399,24 +432,24 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => { _mockFlashLoanReceiver.address, [weth.address], [flashAmount], - [1], + [2], caller.address, '0x10', '0' ); - const { stableDebtTokenAddress } = await helpersContract.getReserveTokensAddresses( + const { variableDebtTokenAddress } = await helpersContract.getReserveTokensAddresses( weth.address ); - const wethDebtToken = await getStableDebtToken(stableDebtTokenAddress); + const wethDebtToken = await getStableDebtToken(variableDebtTokenAddress); const callerDebt = await wethDebtToken.balanceOf(caller.address); - expect(callerDebt.toString()).to.be.equal('800000000000000000', 'Invalid user debt'); + expect(callerDebt.toString()).to.be.equal(ethers.utils.parseEther('0.8'), 'Invalid user debt'); }); - it('Caller takes a WETH flashloan with mode = 1 onBehalfOf user without allowance', async () => { + it('Caller takes a WETH flashloan with mode = 1 onBehalfOf user without allowance, should revert since stable borrowing is disabled', async () => { const { dai, pool, weth, users, helpersContract } = testEnv; const caller = users[5]; @@ -449,10 +482,46 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => { '0x10', '0' ) + ).to.be.revertedWith(VL_STABLE_BORROWING_NOT_ENABLED); + }); + + it('Caller takes a WETH flashloan with mode = 2 onBehalfOf user without allowance, should revert since allowance is 0', async () => { + const { dai, pool, weth, users, helpersContract } = testEnv; + + const caller = users[5]; + const onBehalfOf = users[4]; + + // Deposit 1000 dai for onBehalfOf user + await dai.connect(onBehalfOf.signer).mint(await convertToCurrencyDecimals(dai.address, '1000')); + + await dai.connect(onBehalfOf.signer).approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL); + + const amountToDeposit = await convertToCurrencyDecimals(dai.address, '1000'); + + await pool + .connect(onBehalfOf.signer) + .deposit(dai.address, amountToDeposit, onBehalfOf.address, '0'); + + const flashAmount = ethers.utils.parseEther('0.8'); + + await _mockFlashLoanReceiver.setFailExecutionTransfer(true); + + await expect( + pool + .connect(caller.signer) + .flashLoan( + _mockFlashLoanReceiver.address, + [weth.address], + [flashAmount], + [2], + onBehalfOf.address, + '0x10', + '0' + ) ).to.be.revertedWith(LP_BORROW_ALLOWANCE_NOT_ENOUGH); }); - it('Caller takes a WETH flashloan with mode = 1 onBehalfOf user with allowance. A loan for onBehalfOf is creatd.', async () => { + it('Caller takes a WETH flashloan with mode = 1 onBehalfOf user with allowance. Should revert since stable borrowing is disabled.', async () => { const { dai, pool, weth, users, helpersContract } = testEnv; const caller = users[5]; @@ -462,14 +531,14 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => { const reserveData = await pool.getReserveData(weth.address); - const stableDebtToken = await getVariableDebtToken(reserveData.stableDebtTokenAddress); + const stableDebtToken = await getStableDebtToken(reserveData.stableDebtTokenAddress); // Deposited for onBehalfOf user already, delegate borrow allowance await stableDebtToken.connect(onBehalfOf.signer).approveDelegation(caller.address, flashAmount); await _mockFlashLoanReceiver.setFailExecutionTransfer(true); - await pool + await expect(pool .connect(caller.signer) .flashLoan( _mockFlashLoanReceiver.address, @@ -479,7 +548,7 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => { onBehalfOf.address, '0x10', '0' - ); + )).to.be.revertedWith(VL_STABLE_BORROWING_NOT_ENABLED); const { stableDebtTokenAddress } = await helpersContract.getReserveTokensAddresses( weth.address @@ -490,7 +559,50 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => { const onBehalfOfDebt = await wethDebtToken.balanceOf(onBehalfOf.address); expect(onBehalfOfDebt.toString()).to.be.equal( - '800000000000000000', + '0', + 'Invalid onBehalfOf user debt' + ); + }); + + it('Caller takes a WETH flashloan with mode = 2 onBehalfOf user with allowance. A loan for onBehalfOf is created.', async () => { + const { dai, pool, weth, users, helpersContract } = testEnv; + + const caller = users[5]; + const onBehalfOf = users[4]; + + const flashAmount = ethers.utils.parseEther('0.8'); + + const reserveData = await pool.getReserveData(weth.address); + + const variableDebtToken = await getVariableDebtToken(reserveData.variableDebtTokenAddress); + + // Deposited for onBehalfOf user already, delegate borrow allowance + await variableDebtToken.connect(onBehalfOf.signer).approveDelegation(caller.address, flashAmount); + + await _mockFlashLoanReceiver.setFailExecutionTransfer(true); + + await expect(pool + .connect(caller.signer) + .flashLoan( + _mockFlashLoanReceiver.address, + [weth.address], + [flashAmount], + [2], + onBehalfOf.address, + '0x10', + '0' + )).to.not.be.reverted; + + const { variableDebtTokenAddress } = await helpersContract.getReserveTokensAddresses( + weth.address + ); + + const wethDebtToken = await getVariableDebtToken(variableDebtTokenAddress); + + const onBehalfOfDebt = await wethDebtToken.balanceOf(onBehalfOf.address); + + expect(onBehalfOfDebt.toString()).to.be.equal( + ethers.utils.parseEther('0.8'), 'Invalid onBehalfOf user debt' ); }); diff --git a/test-suites/test-lp/liquidation-atoken.spec.ts b/test-suites/test-lp/liquidation-atoken.spec.ts index 1b6f9911..90296edb 100644 --- a/test-suites/test-lp/liquidation-atoken.spec.ts +++ b/test-suites/test-lp/liquidation-atoken.spec.ts @@ -230,7 +230,7 @@ makeSuite('LendingPool liquidation - liquidator receiving aToken', (testEnv) => ).to.be.true; }); - it('User 3 deposits 1000 USDC, user 4 1 WETH, user 4 borrows - drops HF, liquidates the borrow', async () => { + it('User 3 deposits 1000 USDC, user 4 1 WETH, user 4 borrows at variable - drops HF, liquidates the borrow', async () => { const { users, pool, usdc, oracle, weth, helpersContract } = testEnv; const depositor = users[3]; const borrower = users[4]; @@ -278,7 +278,7 @@ makeSuite('LendingPool liquidation - liquidator receiving aToken', (testEnv) => await pool .connect(borrower.signer) - .borrow(usdc.address, amountUSDCToBorrow, RateMode.Stable, '0', borrower.address); + .borrow(usdc.address, amountUSDCToBorrow, RateMode.Variable, '0', borrower.address); //drops HF below 1 @@ -302,7 +302,7 @@ makeSuite('LendingPool liquidation - liquidator receiving aToken', (testEnv) => const usdcReserveDataBefore = await helpersContract.getReserveData(usdc.address); const ethReserveDataBefore = await helpersContract.getReserveData(weth.address); - const amountToLiquidate = new BigNumber(userReserveDataBefore.currentStableDebt.toString()) + const amountToLiquidate = new BigNumber(userReserveDataBefore.currentVariableDebt.toString()) .multipliedBy(0.5) .toFixed(0); @@ -345,8 +345,8 @@ makeSuite('LendingPool liquidation - liquidator receiving aToken', (testEnv) => 'Invalid health factor' ); - expect(userReserveDataAfter.currentStableDebt.toString()).to.be.bignumber.almostEqual( - new BigNumber(userReserveDataBefore.currentStableDebt.toString()) + expect(userReserveDataAfter.currentVariableDebt.toString()).to.be.bignumber.almostEqual( + new BigNumber(userReserveDataBefore.currentVariableDebt.toString()) .minus(amountToLiquidate) .toFixed(0), 'Invalid user borrow balance after liquidation' diff --git a/test-suites/test-lp/liquidation-underlying.spec.ts b/test-suites/test-lp/liquidation-underlying.spec.ts index 0c9c4adf..b86a55d6 100644 --- a/test-suites/test-lp/liquidation-underlying.spec.ts +++ b/test-suites/test-lp/liquidation-underlying.spec.ts @@ -5,8 +5,8 @@ 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 { calcExpectedVariableDebtTokenBalance } from './helpers/utils/calculations'; +import { getReserveData, getUserData } from './helpers/utils/helpers'; import { CommonsConfig } from '../../markets/lp/commons'; import { parseEther } from 'ethers/lib/utils'; @@ -91,7 +91,7 @@ makeSuite('LendingPool liquidation - liquidator receiving the underlying asset', await pool .connect(borrower.signer) - .borrow(dai.address, amountDAIToBorrow, RateMode.Stable, '0', borrower.address); + .borrow(dai.address, amountDAIToBorrow, RateMode.Variable, '0', borrower.address); const userGlobalDataAfter = await pool.getUserAccountData(borrower.address); @@ -131,6 +131,7 @@ makeSuite('LendingPool liquidation - liquidator receiving the underlying asset', //approve protocol to access the liquidator wallet await dai.connect(liquidator.signer).approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL); + const daiReserveBefore = await getReserveData(helpersContract, dai.address); const daiReserveDataBefore = await helpersContract.getReserveData(dai.address); const ethReserveDataBefore = await helpersContract.getReserveData(weth.address); @@ -185,16 +186,15 @@ makeSuite('LendingPool liquidation - liquidator receiving the underlying asset', const txTimestamp = new BigNumber( (await DRE.ethers.provider.getBlock(tx.blockNumber)).timestamp ); - - const stableDebtBeforeTx = calcExpectedStableDebtTokenBalance( - userReserveDataBefore.principalStableDebt, - userReserveDataBefore.stableBorrowRate, - userReserveDataBefore.stableRateLastUpdated, + const reserve = await getReserveData + const variableDebtBeforeTx = calcExpectedVariableDebtTokenBalance( + daiReserveBefore, + userReserveDataBefore, txTimestamp ); expect(userReserveDataAfter.currentStableDebt.toString()).to.be.bignumber.almostEqual( - stableDebtBeforeTx.minus(amountToLiquidate).toFixed(0), + variableDebtBeforeTx.minus(amountToLiquidate).toFixed(0), 'Invalid user debt after liquidation' ); @@ -275,7 +275,7 @@ makeSuite('LendingPool liquidation - liquidator receiving the underlying asset', await pool .connect(borrower.signer) - .borrow(usdc.address, amountUSDCToBorrow, RateMode.Stable, '0', borrower.address); + .borrow(usdc.address, amountUSDCToBorrow, RateMode.Variable, '0', borrower.address); //drops HF below 1 await oracle.setAssetPrice(