2021-02-07 03:10:29 +00:00
import BigNumber from 'bignumber.js' ;
import { TestEnv , makeSuite } from './helpers/make-suite' ;
2021-06-10 10:29:50 +00:00
import { APPROVAL_AMOUNT_LENDING_POOL , MAX_UINT_AMOUNT , oneRay } from '../../helpers/constants' ;
2021-02-07 03:10:29 +00:00
import { convertToCurrencyDecimals , getContract } from '../../helpers/contracts-helpers' ;
import { ethers } from 'ethers' ;
import { MockFlashLoanReceiver } from '../../types/MockFlashLoanReceiver' ;
import { ProtocolErrors , eContractid } from '../../helpers/types' ;
import { VariableDebtToken } from '../../types/VariableDebtToken' ;
import { StableDebtToken } from '../../types/StableDebtToken' ;
import {
getMockFlashLoanReceiver ,
getStableDebtToken ,
getVariableDebtToken ,
} from '../../helpers/contracts-getters' ;
const { expect } = require ( 'chai' ) ;
makeSuite ( 'LendingPool FlashLoan function' , ( testEnv : TestEnv ) = > {
let _mockFlashLoanReceiver = { } as MockFlashLoanReceiver ;
const {
VL_COLLATERAL_BALANCE_IS_0 ,
TRANSFER_AMOUNT_EXCEEDS_BALANCE ,
LP_INVALID_FLASHLOAN_MODE ,
SAFEERC20_LOWLEVEL_CALL ,
LP_INVALID_FLASH_LOAN_EXECUTOR_RETURN ,
LP_BORROW_ALLOWANCE_NOT_ENOUGH ,
} = ProtocolErrors ;
2021-06-21 06:13:20 +00:00
const TOTAL_PREMIUM = 9 ;
const PREMIUM_TO_PROTOCOL = 3 ;
const PREMIUM_TO_LP = TOTAL_PREMIUM - PREMIUM_TO_PROTOCOL ;
2021-02-07 03:10:29 +00:00
before ( async ( ) = > {
_mockFlashLoanReceiver = await getMockFlashLoanReceiver ( ) ;
} ) ;
2021-06-21 06:13:20 +00:00
it ( 'Configurator sets total premium = 9 bps, premium to protocol = 3 bps' , async ( ) = > {
const { configurator , pool } = testEnv ;
await configurator . updateFlashloanPremiumTotal ( TOTAL_PREMIUM ) ;
await configurator . updateFlashloanPremiumToProtocol ( PREMIUM_TO_PROTOCOL ) ;
expect ( await pool . FLASHLOAN_PREMIUM_TOTAL ( ) ) . to . be . equal ( TOTAL_PREMIUM ) ;
expect ( await pool . FLASHLOAN_PREMIUM_TO_PROTOCOL ( ) ) . to . be . equal ( PREMIUM_TO_PROTOCOL ) ;
} ) ;
2021-02-07 03:10:29 +00:00
it ( 'Deposits WETH into the reserve' , async ( ) = > {
2021-06-21 06:13:20 +00:00
const { pool , weth , aave , dai } = testEnv ;
2021-02-07 03:10:29 +00:00
const userAddress = await pool . signer . getAddress ( ) ;
const amountToDeposit = ethers . utils . parseEther ( '1' ) ;
await weth . mint ( amountToDeposit ) ;
await weth . approve ( pool . address , APPROVAL_AMOUNT_LENDING_POOL ) ;
await pool . deposit ( weth . address , amountToDeposit , userAddress , '0' ) ;
2021-06-10 10:29:50 +00:00
await aave . mint ( amountToDeposit ) ;
await aave . approve ( pool . address , APPROVAL_AMOUNT_LENDING_POOL ) ;
await pool . deposit ( aave . address , amountToDeposit , userAddress , '0' ) ;
2021-06-21 06:13:20 +00:00
await dai . mint ( amountToDeposit ) ;
await dai . approve ( pool . address , APPROVAL_AMOUNT_LENDING_POOL ) ;
await pool . deposit ( dai . address , amountToDeposit , userAddress , '0' ) ;
2021-02-07 03:10:29 +00:00
} ) ;
2021-06-21 06:13:20 +00:00
it ( 'Takes WETH + Dai flash loan with mode = 0, returns the funds correctly' , async ( ) = > {
const { pool , helpersContract , weth , aWETH , dai , aDai } = testEnv ;
2021-02-07 03:10:29 +00:00
2021-06-21 06:13:20 +00:00
const wethFlashBorrowedAmount = ethers . utils . parseEther ( '0.8' ) ;
const daiFlashBorrowedAmount = ethers . utils . parseEther ( '0.3' ) ;
const wethTotalFees = new BigNumber (
wethFlashBorrowedAmount . mul ( TOTAL_PREMIUM ) . div ( 10000 ) . toString ( )
) ;
const wethFeesToProtocol = wethFlashBorrowedAmount . mul ( PREMIUM_TO_PROTOCOL ) . div ( 10000 ) ;
const wethFeesToLp = wethFlashBorrowedAmount . mul ( PREMIUM_TO_LP ) . div ( 10000 ) ;
const daiTotalFees = new BigNumber (
daiFlashBorrowedAmount . mul ( TOTAL_PREMIUM ) . div ( 10000 ) . toString ( )
) ;
const daiFeesToProtocol = daiFlashBorrowedAmount . mul ( PREMIUM_TO_PROTOCOL ) . div ( 10000 ) ;
const daiFeesToLp = daiFlashBorrowedAmount . mul ( PREMIUM_TO_LP ) . div ( 10000 ) ;
2021-06-10 10:29:50 +00:00
2021-06-21 06:13:20 +00:00
const wethLiquidityIndexAdded = wethFeesToLp
. mul ( ethers . BigNumber . from ( 10 ) . pow ( 27 ) )
. div ( ( await aWETH . totalSupply ( ) ) . toString ( ) ) ;
2021-06-10 10:29:50 +00:00
2021-06-21 06:13:20 +00:00
const daiLiquidityIndexAdded = daiFeesToLp
. mul ( ethers . BigNumber . from ( 10 ) . pow ( 27 ) )
. div ( ( await aDai . totalSupply ( ) ) . toString ( ) ) ;
let wethReserveData = await helpersContract . getReserveData ( weth . address ) ;
let daiReserveData = await helpersContract . getReserveData ( dai . address ) ;
const wethLiquidityIndexBefore = wethReserveData . liquidityIndex ;
const daiLiquidityIndexBefore = daiReserveData . liquidityIndex ;
const wethTotalLiquidityBefore = new BigNumber ( wethReserveData . availableLiquidity . toString ( ) )
. plus ( wethReserveData . totalStableDebt . toString ( ) )
. plus ( wethReserveData . totalVariableDebt . toString ( ) ) ;
const daiTotalLiquidityBefore = new BigNumber ( daiReserveData . availableLiquidity . toString ( ) )
. plus ( daiReserveData . totalStableDebt . toString ( ) )
. plus ( daiReserveData . totalVariableDebt . toString ( ) ) ;
const wethReservesBefore = await aWETH . balanceOf ( await aWETH . RESERVE_TREASURY_ADDRESS ( ) ) ;
const daiReservesBefore = await aDai . balanceOf ( await aDai . RESERVE_TREASURY_ADDRESS ( ) ) ;
2021-06-10 10:29:50 +00:00
2021-02-07 03:10:29 +00:00
await pool . flashLoan (
_mockFlashLoanReceiver . address ,
2021-06-21 06:13:20 +00:00
[ weth . address , dai . address ] ,
[ wethFlashBorrowedAmount , daiFlashBorrowedAmount ] ,
[ 0 , 0 ] ,
2021-02-07 03:10:29 +00:00
_mockFlashLoanReceiver . address ,
'0x10' ,
'0'
) ;
2021-06-21 06:13:20 +00:00
await pool . mintToTreasury ( [ weth . address , dai . address ] ) ;
2021-02-07 03:10:29 +00:00
2021-06-21 06:13:20 +00:00
wethReserveData = await helpersContract . getReserveData ( weth . address ) ;
daiReserveData = await helpersContract . getReserveData ( dai . address ) ;
2021-02-07 03:10:29 +00:00
2021-06-21 06:13:20 +00:00
const wethCurrentLiquidityRate = wethReserveData . liquidityRate ;
const wethCurrentLiquidityIndex = wethReserveData . liquidityIndex ;
const daiCurrentLiquidityRate = daiReserveData . liquidityRate ;
const daiCurrentLiquidityIndex = daiReserveData . liquidityIndex ;
2021-02-07 03:10:29 +00:00
2021-06-21 06:13:20 +00:00
const wethTotalLiquidityAfter = new BigNumber ( wethReserveData . availableLiquidity . toString ( ) )
. plus ( wethReserveData . totalStableDebt . toString ( ) )
. plus ( wethReserveData . totalVariableDebt . toString ( ) ) ;
2021-02-07 03:10:29 +00:00
2021-06-21 06:13:20 +00:00
const daiTotalLiquidityAfter = new BigNumber ( daiReserveData . availableLiquidity . toString ( ) )
. plus ( daiReserveData . totalStableDebt . toString ( ) )
. plus ( daiReserveData . totalVariableDebt . toString ( ) ) ;
const wethReservesAfter = await aWETH . balanceOf ( await aWETH . RESERVE_TREASURY_ADDRESS ( ) ) ;
const daiReservesAfter = await aDai . balanceOf ( await aDai . RESERVE_TREASURY_ADDRESS ( ) ) ;
expect ( wethTotalLiquidityBefore . plus ( wethTotalFees ) . toString ( ) ) . to . be . equal (
wethTotalLiquidityAfter . toString ( )
) ;
expect ( wethCurrentLiquidityRate . toString ( ) ) . to . be . equal ( '0' ) ;
expect ( wethCurrentLiquidityIndex . toString ( ) ) . to . be . equal (
wethLiquidityIndexBefore . add ( wethLiquidityIndexAdded . toString ( ) ) . toString ( )
) ;
expect ( wethReservesAfter ) . to . be . equal ( wethReservesBefore . add ( wethFeesToProtocol ) ) ;
expect ( daiTotalLiquidityBefore . plus ( daiTotalFees ) . toString ( ) ) . to . be . equal (
daiTotalLiquidityAfter . toString ( )
) ;
expect ( daiCurrentLiquidityRate . toString ( ) ) . to . be . equal ( '0' ) ;
expect ( daiCurrentLiquidityIndex . toString ( ) ) . to . be . equal (
daiLiquidityIndexBefore . add ( daiLiquidityIndexAdded . toString ( ) ) . toString ( )
) ;
expect ( daiReservesAfter ) . to . be . equal ( daiReservesBefore . add ( daiFeesToProtocol ) ) ;
2021-02-07 03:10:29 +00:00
} ) ;
2021-06-10 10:29:50 +00:00
it ( 'Takes an authorized AAVE flash loan with mode = 0, returns the funds correctly' , async ( ) = > {
const {
pool ,
helpersContract ,
aave ,
configurator ,
users : [ , , , authorizedUser ] ,
} = testEnv ;
await configurator . authorizeFlashBorrower ( authorizedUser . address ) ;
const flashBorrowedAmount = ethers . utils . parseEther ( '0.8' ) ;
2021-06-21 06:13:20 +00:00
const totalFees = new BigNumber ( 0 ) ;
2021-06-10 10:29:50 +00:00
let reserveData = await helpersContract . getReserveData ( aave . address ) ;
const totalLiquidityBefore = new BigNumber ( reserveData . availableLiquidity . toString ( ) )
. plus ( reserveData . totalStableDebt . toString ( ) )
. plus ( reserveData . totalVariableDebt . toString ( ) ) ;
2021-02-07 03:10:29 +00:00
2021-06-10 10:29:50 +00:00
await pool
. connect ( authorizedUser . signer )
. flashLoan (
_mockFlashLoanReceiver . address ,
[ aave . address ] ,
[ flashBorrowedAmount ] ,
[ 0 ] ,
_mockFlashLoanReceiver . address ,
'0x10' ,
'0'
) ;
2021-06-10 17:06:02 +00:00
await pool . mintToTreasury ( [ aave . address ] ) ;
2021-06-10 10:29:50 +00:00
reserveData = await helpersContract . getReserveData ( aave . address ) ;
const totalLiquidityAfter = new BigNumber ( reserveData . availableLiquidity . toString ( ) )
. plus ( reserveData . totalStableDebt . toString ( ) )
. plus ( reserveData . totalVariableDebt . toString ( ) ) ;
2021-06-21 06:13:20 +00:00
expect ( totalLiquidityBefore . plus ( totalFees ) . toString ( ) ) . to . be . equal (
totalLiquidityAfter . toString ( )
) ;
2021-06-10 10:29:50 +00:00
} ) ;
2021-02-07 03:10:29 +00:00
it ( 'Takes an ETH flashloan with mode = 0 as big as the available liquidity' , async ( ) = > {
2021-06-21 06:13:20 +00:00
const { pool , helpersContract , weth , aWETH } = testEnv ;
2021-02-07 03:10:29 +00:00
2021-06-10 10:29:50 +00:00
let reserveData = await helpersContract . getReserveData ( weth . address ) ;
2021-06-21 06:13:20 +00:00
const totalLiquidityBefore = reserveData . availableLiquidity
. add ( reserveData . totalStableDebt )
. add ( reserveData . totalVariableDebt ) ;
const flashBorrowedAmount = totalLiquidityBefore ;
2021-06-10 10:29:50 +00:00
2021-06-21 06:13:20 +00:00
const totalFees = new BigNumber ( flashBorrowedAmount . mul ( TOTAL_PREMIUM ) . div ( 10000 ) . toString ( ) ) ;
const feesToProtocol = flashBorrowedAmount . mul ( PREMIUM_TO_PROTOCOL ) . div ( 10000 ) ;
const feesToLp = flashBorrowedAmount . mul ( PREMIUM_TO_LP ) . div ( 10000 ) ;
const liquidityIndexBefore = reserveData . liquidityIndex ;
const liquidityIndexAdded = feesToLp
. mul ( ethers . BigNumber . from ( 10 ) . pow ( 27 ) )
. div ( ( await aWETH . totalSupply ( ) ) . toString ( ) )
. mul ( liquidityIndexBefore )
. div ( ethers . BigNumber . from ( 10 ) . pow ( 27 ) ) ;
2021-06-10 10:29:50 +00:00
2021-06-21 06:13:20 +00:00
const reservesBefore = await aWETH . balanceOf ( await aWETH . RESERVE_TREASURY_ADDRESS ( ) ) ;
2021-06-10 10:29:50 +00:00
2021-02-07 03:10:29 +00:00
const txResult = await pool . flashLoan (
_mockFlashLoanReceiver . address ,
[ weth . address ] ,
2021-06-21 06:13:20 +00:00
[ flashBorrowedAmount ] ,
2021-02-07 03:10:29 +00:00
[ 0 ] ,
_mockFlashLoanReceiver . address ,
'0x10' ,
'0'
) ;
2021-06-10 10:29:50 +00:00
await pool . mintToTreasury ( [ weth . address ] ) ;
reserveData = await helpersContract . getReserveData ( weth . address ) ;
2021-06-21 06:13:20 +00:00
const currentLiquidityRate = reserveData . liquidityRate ;
2021-02-07 03:10:29 +00:00
const currentLiquidityIndex = reserveData . liquidityIndex ;
2021-06-21 06:13:20 +00:00
const totalLiquidityAfter = new BigNumber ( reserveData . availableLiquidity . toString ( ) )
2021-02-07 03:10:29 +00:00
. plus ( reserveData . totalStableDebt . toString ( ) )
. plus ( reserveData . totalVariableDebt . toString ( ) ) ;
2021-06-21 06:13:20 +00:00
const reservesAfter = await aWETH . balanceOf ( await aWETH . RESERVE_TREASURY_ADDRESS ( ) ) ;
expect ( new BigNumber ( totalLiquidityBefore . toString ( ) ) . plus ( totalFees ) . toString ( ) ) . to . be . equal (
totalLiquidityAfter . toString ( )
) ;
expect ( currentLiquidityRate . toString ( ) ) . to . be . equal ( '0' ) ;
expect ( currentLiquidityIndex . toString ( ) ) . to . be . equal (
liquidityIndexBefore . add ( liquidityIndexAdded . toString ( ) ) . toString ( )
) ;
expect (
reservesAfter . sub ( feesToProtocol ) . mul ( liquidityIndexBefore ) . div ( currentLiquidityIndex )
) . to . be . equal ( reservesBefore ) ;
2021-02-07 03:10:29 +00:00
} ) ;
it ( 'Takes WETH flashloan, does not return the funds with mode = 0. (revert expected)' , async ( ) = > {
const { pool , weth , users } = testEnv ;
const caller = users [ 1 ] ;
await _mockFlashLoanReceiver . setFailExecutionTransfer ( true ) ;
await expect (
pool
. connect ( caller . signer )
. flashLoan (
_mockFlashLoanReceiver . address ,
[ weth . address ] ,
[ ethers . utils . parseEther ( '0.8' ) ] ,
[ 0 ] ,
caller . address ,
'0x10' ,
'0'
)
) . to . be . revertedWith ( SAFEERC20_LOWLEVEL_CALL ) ;
} ) ;
it ( 'Takes WETH flashloan, simulating a receiver as EOA (revert expected)' , async ( ) = > {
const { pool , weth , users } = testEnv ;
const caller = users [ 1 ] ;
await _mockFlashLoanReceiver . setFailExecutionTransfer ( true ) ;
await _mockFlashLoanReceiver . setSimulateEOA ( true ) ;
await expect (
pool
. connect ( caller . signer )
. flashLoan (
_mockFlashLoanReceiver . address ,
[ weth . address ] ,
[ ethers . utils . parseEther ( '0.8' ) ] ,
[ 0 ] ,
caller . address ,
'0x10' ,
'0'
)
) . to . be . revertedWith ( LP_INVALID_FLASH_LOAN_EXECUTOR_RETURN ) ;
} ) ;
it ( 'Takes a WETH flashloan with an invalid mode. (revert expected)' , async ( ) = > {
const { pool , weth , users } = testEnv ;
const caller = users [ 1 ] ;
await _mockFlashLoanReceiver . setSimulateEOA ( false ) ;
await _mockFlashLoanReceiver . setFailExecutionTransfer ( true ) ;
await expect (
pool
. connect ( caller . signer )
. flashLoan (
_mockFlashLoanReceiver . address ,
[ weth . address ] ,
[ ethers . utils . parseEther ( '0.8' ) ] ,
[ 4 ] ,
caller . address ,
'0x10' ,
'0'
)
) . to . be . reverted ;
} ) ;
it ( 'Caller deposits 1000 DAI as collateral, Takes WETH flashloan with mode = 2, does not return the funds. A variable loan for caller is created' , async ( ) = > {
const { dai , pool , weth , users , helpersContract } = testEnv ;
const caller = users [ 1 ] ;
await dai . connect ( caller . signer ) . mint ( await convertToCurrencyDecimals ( dai . address , '1000' ) ) ;
await dai . connect ( caller . signer ) . approve ( pool . address , APPROVAL_AMOUNT_LENDING_POOL ) ;
const amountToDeposit = await convertToCurrencyDecimals ( dai . address , '1000' ) ;
await pool . connect ( caller . signer ) . deposit ( dai . address , amountToDeposit , caller . address , '0' ) ;
await _mockFlashLoanReceiver . setFailExecutionTransfer ( true ) ;
2021-06-10 10:29:50 +00:00
let reserveData = await helpersContract . getReserveData ( weth . address ) ;
let totalLiquidityBefore = new BigNumber ( reserveData . availableLiquidity . toString ( ) )
. plus ( reserveData . totalStableDebt . toString ( ) )
. plus ( reserveData . totalVariableDebt . toString ( ) ) ;
2021-02-07 03:10:29 +00:00
await pool
. connect ( caller . signer )
. flashLoan (
_mockFlashLoanReceiver . address ,
[ weth . address ] ,
[ ethers . utils . parseEther ( '0.8' ) ] ,
[ 2 ] ,
caller . address ,
'0x10' ,
'0'
) ;
const { variableDebtTokenAddress } = await helpersContract . getReserveTokensAddresses (
weth . address
) ;
2021-06-10 10:29:50 +00:00
reserveData = await helpersContract . getReserveData ( weth . address ) ;
2021-02-07 03:10:29 +00:00
2021-06-10 10:29:50 +00:00
const totalLiquidityAfter = new BigNumber ( reserveData . availableLiquidity . toString ( ) )
. plus ( reserveData . totalStableDebt . toString ( ) )
. plus ( reserveData . totalVariableDebt . toString ( ) ) ;
expect ( totalLiquidityAfter . toString ( ) ) . to . be . equal (
ethers . BigNumber . from ( totalLiquidityBefore . toString ( ) )
) ;
2021-02-07 03:10:29 +00:00
2021-06-10 10:29:50 +00:00
const wethDebtToken = await getVariableDebtToken ( variableDebtTokenAddress ) ;
2021-02-07 03:10:29 +00:00
const callerDebt = await wethDebtToken . balanceOf ( caller . address ) ;
expect ( callerDebt . toString ( ) ) . to . be . equal ( '800000000000000000' , 'Invalid user debt' ) ;
2021-06-10 10:29:50 +00:00
// repays debt for later, so no interest accrue
await weth . connect ( caller . signer ) . mint ( await convertToCurrencyDecimals ( weth . address , '1000' ) ) ;
await weth . connect ( caller . signer ) . approve ( pool . address , APPROVAL_AMOUNT_LENDING_POOL ) ;
await pool . connect ( caller . signer ) . repay ( weth . address , MAX_UINT_AMOUNT , 2 , caller . address ) ;
2021-02-07 03:10:29 +00:00
} ) ;
it ( 'tries to take a flashloan that is bigger than the available liquidity (revert expected)' , async ( ) = > {
const { pool , weth , users } = testEnv ;
const caller = users [ 1 ] ;
await expect (
pool . connect ( caller . signer ) . flashLoan (
_mockFlashLoanReceiver . address ,
[ weth . address ] ,
[ '1004415000000000000' ] , //slightly higher than the available liquidity
[ 2 ] ,
caller . address ,
'0x10' ,
'0'
) ,
TRANSFER_AMOUNT_EXCEEDS_BALANCE
) . to . be . revertedWith ( SAFEERC20_LOWLEVEL_CALL ) ;
} ) ;
it ( 'tries to take a flashloan using a non contract address as receiver (revert expected)' , async ( ) = > {
const { pool , deployer , weth , users } = testEnv ;
const caller = users [ 1 ] ;
await expect (
pool . flashLoan (
deployer . address ,
[ weth . address ] ,
[ '1000000000000000000' ] ,
[ 2 ] ,
caller . address ,
'0x10' ,
'0'
)
) . to . be . reverted ;
} ) ;
it ( 'Deposits USDC into the reserve' , async ( ) = > {
const { usdc , pool } = testEnv ;
const userAddress = await pool . signer . getAddress ( ) ;
await usdc . mint ( await convertToCurrencyDecimals ( usdc . address , '1000' ) ) ;
await usdc . approve ( pool . address , APPROVAL_AMOUNT_LENDING_POOL ) ;
const amountToDeposit = await convertToCurrencyDecimals ( usdc . address , '1000' ) ;
await pool . deposit ( usdc . address , amountToDeposit , userAddress , '0' ) ;
} ) ;
it ( 'Takes out a 500 USDC flashloan, returns the funds correctly' , async ( ) = > {
2021-06-21 06:13:20 +00:00
const { usdc , aUsdc , pool , helpersContract , deployer : depositor } = testEnv ;
2021-02-07 03:10:29 +00:00
await _mockFlashLoanReceiver . setFailExecutionTransfer ( false ) ;
2021-06-21 06:13:20 +00:00
const flashBorrowedAmount = await convertToCurrencyDecimals ( usdc . address , '500' ) ;
const totalFees = new BigNumber ( flashBorrowedAmount . mul ( TOTAL_PREMIUM ) . div ( 10000 ) . toString ( ) ) ;
const feesToProtocol = flashBorrowedAmount . mul ( PREMIUM_TO_PROTOCOL ) . div ( 10000 ) ;
const feesToLp = flashBorrowedAmount . mul ( PREMIUM_TO_LP ) . div ( 10000 ) ;
const liquidityIndexAdded = feesToLp
. mul ( ethers . BigNumber . from ( 10 ) . pow ( 27 ) )
. div ( ( await aUsdc . totalSupply ( ) ) . toString ( ) ) ;
2021-02-07 03:10:29 +00:00
2021-06-21 06:13:20 +00:00
let reserveData = await helpersContract . getReserveData ( usdc . address ) ;
const liquidityIndexBefore = reserveData . liquidityIndex ;
const totalLiquidityBefore = new BigNumber ( reserveData . availableLiquidity . toString ( ) )
. plus ( reserveData . totalStableDebt . toString ( ) )
. plus ( reserveData . totalVariableDebt . toString ( ) ) ;
const reservesBefore = await aUsdc . balanceOf ( await aUsdc . RESERVE_TREASURY_ADDRESS ( ) ) ;
2021-02-07 03:10:29 +00:00
await pool . flashLoan (
_mockFlashLoanReceiver . address ,
[ usdc . address ] ,
2021-06-21 06:13:20 +00:00
[ flashBorrowedAmount ] ,
2021-02-07 03:10:29 +00:00
[ 0 ] ,
_mockFlashLoanReceiver . address ,
'0x10' ,
'0'
) ;
2021-06-21 06:13:20 +00:00
await pool . mintToTreasury ( [ usdc . address ] ) ;
2021-02-07 03:10:29 +00:00
2021-06-21 06:13:20 +00:00
reserveData = await helpersContract . getReserveData ( usdc . address ) ;
2021-02-07 03:10:29 +00:00
2021-06-21 06:13:20 +00:00
const currentLiquidityRate = reserveData . liquidityRate ;
const currentLiquidityIndex = reserveData . liquidityIndex ;
const totalLiquidityAfter = new BigNumber ( reserveData . availableLiquidity . toString ( ) )
. plus ( reserveData . totalStableDebt . toString ( ) )
. plus ( reserveData . totalVariableDebt . toString ( ) ) ;
const reservesAfter = await aUsdc . balanceOf ( await aUsdc . RESERVE_TREASURY_ADDRESS ( ) ) ;
expect ( totalLiquidityBefore . plus ( totalFees ) . toString ( ) ) . to . be . equal (
totalLiquidityAfter . toString ( )
) ;
expect ( currentLiquidityRate . toString ( ) ) . to . be . equal ( '0' ) ;
expect ( currentLiquidityIndex . toString ( ) ) . to . be . equal (
liquidityIndexBefore . add ( liquidityIndexAdded . toString ( ) ) . toString ( )
2021-02-07 03:10:29 +00:00
) ;
2021-06-21 06:13:20 +00:00
expect ( reservesAfter ) . to . be . equal ( reservesBefore . add ( feesToProtocol ) ) ;
2021-02-07 03:10:29 +00:00
} ) ;
it ( 'Takes out a 500 USDC flashloan with mode = 0, does not return the funds. (revert expected)' , async ( ) = > {
const { usdc , pool , users } = testEnv ;
const caller = users [ 2 ] ;
const flashloanAmount = await convertToCurrencyDecimals ( usdc . address , '500' ) ;
await _mockFlashLoanReceiver . setFailExecutionTransfer ( true ) ;
await expect (
pool
. connect ( caller . signer )
. flashLoan (
_mockFlashLoanReceiver . address ,
[ usdc . address ] ,
[ flashloanAmount ] ,
[ 2 ] ,
caller . address ,
'0x10' ,
'0'
)
) . to . be . revertedWith ( VL_COLLATERAL_BALANCE_IS_0 ) ;
} ) ;
it ( 'Caller deposits 5 WETH as collateral, Takes a USDC flashloan with mode = 2, does not return the funds. A loan for caller is created' , async ( ) = > {
const { usdc , pool , weth , users , helpersContract } = testEnv ;
const caller = users [ 2 ] ;
await weth . connect ( caller . signer ) . mint ( await convertToCurrencyDecimals ( weth . address , '5' ) ) ;
await weth . connect ( caller . signer ) . approve ( pool . address , APPROVAL_AMOUNT_LENDING_POOL ) ;
const amountToDeposit = await convertToCurrencyDecimals ( weth . address , '5' ) ;
await pool . connect ( caller . signer ) . deposit ( weth . address , amountToDeposit , caller . address , '0' ) ;
await _mockFlashLoanReceiver . setFailExecutionTransfer ( true ) ;
const flashloanAmount = await convertToCurrencyDecimals ( usdc . address , '500' ) ;
await pool
. connect ( caller . signer )
. flashLoan (
_mockFlashLoanReceiver . address ,
[ usdc . address ] ,
[ flashloanAmount ] ,
[ 2 ] ,
caller . address ,
'0x10' ,
'0'
) ;
const { variableDebtTokenAddress } = await helpersContract . getReserveTokensAddresses (
usdc . address
) ;
const usdcDebtToken = await getVariableDebtToken ( variableDebtTokenAddress ) ;
const callerDebt = await usdcDebtToken . balanceOf ( caller . address ) ;
expect ( callerDebt . toString ( ) ) . to . be . equal ( '500000000' , 'Invalid user debt' ) ;
} ) ;
it ( 'Caller deposits 1000 DAI as collateral, Takes a WETH flashloan with mode = 0, does not approve the transfer of the funds' , async ( ) = > {
const { dai , pool , weth , users } = testEnv ;
const caller = users [ 3 ] ;
await dai . connect ( caller . signer ) . mint ( await convertToCurrencyDecimals ( dai . address , '1000' ) ) ;
await dai . connect ( caller . signer ) . approve ( pool . address , APPROVAL_AMOUNT_LENDING_POOL ) ;
const amountToDeposit = await convertToCurrencyDecimals ( dai . address , '1000' ) ;
await pool . connect ( caller . signer ) . deposit ( dai . address , amountToDeposit , caller . address , '0' ) ;
const flashAmount = ethers . utils . parseEther ( '0.8' ) ;
await _mockFlashLoanReceiver . setFailExecutionTransfer ( false ) ;
await _mockFlashLoanReceiver . setAmountToApprove ( flashAmount . div ( 2 ) ) ;
await expect (
pool
. connect ( caller . signer )
. flashLoan (
_mockFlashLoanReceiver . address ,
[ weth . address ] ,
[ flashAmount ] ,
[ 0 ] ,
caller . address ,
'0x10' ,
'0'
)
) . to . be . revertedWith ( SAFEERC20_LOWLEVEL_CALL ) ;
} ) ;
it ( 'Caller takes a WETH flashloan with mode = 1' , async ( ) = > {
const { dai , pool , weth , users , helpersContract } = testEnv ;
const caller = users [ 3 ] ;
const flashAmount = ethers . utils . parseEther ( '0.8' ) ;
await _mockFlashLoanReceiver . setFailExecutionTransfer ( true ) ;
await pool
. connect ( caller . signer )
. flashLoan (
_mockFlashLoanReceiver . address ,
[ weth . address ] ,
[ flashAmount ] ,
[ 1 ] ,
caller . address ,
'0x10' ,
'0'
) ;
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 ( '800000000000000000' , 'Invalid user debt' ) ;
} ) ;
it ( 'Caller takes a WETH flashloan with mode = 1 onBehalfOf user without allowance' , 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 ] ,
[ 1 ] ,
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 ( ) = > {
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 ) ;
2021-02-09 23:14:38 +00:00
const stableDebtToken = await getStableDebtToken ( reserveData . stableDebtTokenAddress ) ;
2021-02-07 03:10:29 +00:00
// Deposited for onBehalfOf user already, delegate borrow allowance
await stableDebtToken . connect ( onBehalfOf . signer ) . approveDelegation ( caller . address , flashAmount ) ;
await _mockFlashLoanReceiver . setFailExecutionTransfer ( true ) ;
await pool
. connect ( caller . signer )
. flashLoan (
_mockFlashLoanReceiver . address ,
[ weth . address ] ,
[ flashAmount ] ,
[ 1 ] ,
onBehalfOf . address ,
'0x10' ,
'0'
) ;
const { stableDebtTokenAddress } = await helpersContract . getReserveTokensAddresses (
weth . address
) ;
const wethDebtToken = await getStableDebtToken ( stableDebtTokenAddress ) ;
const onBehalfOfDebt = await wethDebtToken . balanceOf ( onBehalfOf . address ) ;
expect ( onBehalfOfDebt . toString ( ) ) . to . be . equal (
'800000000000000000' ,
'Invalid onBehalfOf user debt'
) ;
} ) ;
} ) ;