diff --git a/test/__setup.spec.ts b/test/__setup.spec.ts deleted file mode 100644 index c9be6515..00000000 --- a/test/__setup.spec.ts +++ /dev/null @@ -1,292 +0,0 @@ -import rawBRE from 'hardhat'; -import { MockContract } from 'ethereum-waffle'; -import { - insertContractAddressInDb, - getEthersSigners, - registerContractInJsonDb, -} from '../helpers/contracts-helpers'; -import { - deployLendingPoolAddressesProvider, - deployMintableERC20, - deployLendingPoolAddressesProviderRegistry, - deployLendingPoolConfigurator, - deployLendingPool, - deployPriceOracle, - deployAaveOracle, - deployLendingPoolCollateralManager, - deployMockFlashLoanReceiver, - deployWalletBalancerProvider, - deployAaveProtocolDataProvider, - deployLendingRateOracle, - deployStableAndVariableTokensHelper, - deployATokensAndRatesHelper, - deployWETHGateway, - deployWETHMocked, - deployMockUniswapRouter, - deployUniswapLiquiditySwapAdapter, - deployUniswapRepayAdapter, - deployFlashLiquidationAdapter, -} from '../helpers/contracts-deployments'; -import { Signer } from 'ethers'; -import { TokenContractId, eContractid, tEthereumAddress, AavePools } from '../helpers/types'; -import { MintableERC20 } from '../types/MintableERC20'; -import { - ConfigNames, - getReservesConfigByPool, - getTreasuryAddress, - loadPoolConfig, -} from '../helpers/configuration'; -import { initializeMakeSuite } from './helpers/make-suite'; - -import { - setInitialAssetPricesInOracle, - deployAllMockAggregators, - setInitialMarketRatesInRatesOracleByHelper, -} from '../helpers/oracles-helpers'; -import { DRE, waitForTx } from '../helpers/misc-utils'; -import { initReservesByHelper, configureReservesByHelper } from '../helpers/init-helpers'; -import AaveConfig from '../markets/aave'; -import { ZERO_ADDRESS } from '../helpers/constants'; -import { - getLendingPool, - getLendingPoolConfiguratorProxy, - getPairsTokenAggregator, -} from '../helpers/contracts-getters'; -import { WETH9Mocked } from '../types/WETH9Mocked'; - -const MOCK_USD_PRICE_IN_WEI = AaveConfig.ProtocolGlobalParams.MockUsdPriceInWei; -const ALL_ASSETS_INITIAL_PRICES = AaveConfig.Mocks.AllAssetsInitialPrices; -const USD_ADDRESS = AaveConfig.ProtocolGlobalParams.UsdAddress; -const MOCK_CHAINLINK_AGGREGATORS_PRICES = AaveConfig.Mocks.AllAssetsInitialPrices; -const LENDING_RATE_ORACLE_RATES_COMMON = AaveConfig.LendingRateOracleRatesCommon; - -const deployAllMockTokens = async (deployer: Signer) => { - const tokens: { [symbol: string]: MockContract | MintableERC20 | WETH9Mocked } = {}; - - const protoConfigData = getReservesConfigByPool(AavePools.proto); - - for (const tokenSymbol of Object.keys(TokenContractId)) { - if (tokenSymbol === 'WETH') { - tokens[tokenSymbol] = await deployWETHMocked(); - await registerContractInJsonDb(tokenSymbol.toUpperCase(), tokens[tokenSymbol]); - continue; - } - let decimals = 18; - - let configData = (protoConfigData)[tokenSymbol]; - - if (!configData) { - decimals = 18; - } - - tokens[tokenSymbol] = await deployMintableERC20([ - tokenSymbol, - tokenSymbol, - configData ? configData.reserveDecimals : 18, - ]); - await registerContractInJsonDb(tokenSymbol.toUpperCase(), tokens[tokenSymbol]); - } - - return tokens; -}; - -const buildTestEnv = async (deployer: Signer, secondaryWallet: Signer) => { - console.time('setup'); - const aaveAdmin = await deployer.getAddress(); - - const mockTokens = await deployAllMockTokens(deployer); - - const addressesProvider = await deployLendingPoolAddressesProvider(AaveConfig.MarketId); - await waitForTx(await addressesProvider.setPoolAdmin(aaveAdmin)); - - //setting users[1] as emergency admin, which is in position 2 in the DRE addresses list - const addressList = await Promise.all( - (await DRE.ethers.getSigners()).map((signer) => signer.getAddress()) - ); - - await waitForTx(await addressesProvider.setEmergencyAdmin(addressList[2])); - - const addressesProviderRegistry = await deployLendingPoolAddressesProviderRegistry(); - await waitForTx( - await addressesProviderRegistry.registerAddressesProvider(addressesProvider.address, 1) - ); - - const lendingPoolImpl = await deployLendingPool(); - - await waitForTx(await addressesProvider.setLendingPoolImpl(lendingPoolImpl.address)); - - const lendingPoolAddress = await addressesProvider.getLendingPool(); - const lendingPoolProxy = await getLendingPool(lendingPoolAddress); - - await insertContractAddressInDb(eContractid.LendingPool, lendingPoolProxy.address); - - const lendingPoolConfiguratorImpl = await deployLendingPoolConfigurator(); - await waitForTx( - await addressesProvider.setLendingPoolConfiguratorImpl(lendingPoolConfiguratorImpl.address) - ); - const lendingPoolConfiguratorProxy = await getLendingPoolConfiguratorProxy( - await addressesProvider.getLendingPoolConfigurator() - ); - await insertContractAddressInDb( - eContractid.LendingPoolConfigurator, - lendingPoolConfiguratorProxy.address - ); - - // Deploy deployment helpers - await deployStableAndVariableTokensHelper([lendingPoolProxy.address, addressesProvider.address]); - await deployATokensAndRatesHelper([ - lendingPoolProxy.address, - addressesProvider.address, - lendingPoolConfiguratorProxy.address, - ]); - - const fallbackOracle = await deployPriceOracle(); - await waitForTx(await fallbackOracle.setEthUsdPrice(MOCK_USD_PRICE_IN_WEI)); - await setInitialAssetPricesInOracle( - ALL_ASSETS_INITIAL_PRICES, - { - WETH: mockTokens.WETH.address, - DAI: mockTokens.DAI.address, - TUSD: mockTokens.TUSD.address, - USDC: mockTokens.USDC.address, - USDT: mockTokens.USDT.address, - SUSD: mockTokens.SUSD.address, - AAVE: mockTokens.AAVE.address, - BAT: mockTokens.BAT.address, - MKR: mockTokens.MKR.address, - LINK: mockTokens.LINK.address, - KNC: mockTokens.KNC.address, - WBTC: mockTokens.WBTC.address, - MANA: mockTokens.MANA.address, - ZRX: mockTokens.ZRX.address, - SNX: mockTokens.SNX.address, - BUSD: mockTokens.BUSD.address, - YFI: mockTokens.BUSD.address, - REN: mockTokens.REN.address, - UNI: mockTokens.UNI.address, - ENJ: mockTokens.ENJ.address, - LpDAI: mockTokens.LpDAI.address, - LpUSDC: mockTokens.LpUSDC.address, - LpUSDT: mockTokens.LpUSDT.address, - LpWBTC: mockTokens.LpWBTC.address, - LpWETH: mockTokens.LpWETH.address, - LpDAIWETH: mockTokens.LpDAIWETH.address, - LpWBTCWETH: mockTokens.LpWBTCWETH.address, - LpAAVEWETH: mockTokens.LpAAVEWETH.address, - LpBATWETH: mockTokens.LpBATWETH.address, - LpUSDCDAI: mockTokens.LpUSDCDAI.address, - LpCRVWETH: mockTokens.LpCRVWETH.address, - LpLINKWETH: mockTokens.LpLINKWETH.address, - LpMKRWETH: mockTokens.LpMKRWETH.address, - LpRENWETH: mockTokens.LpRENWETH.address, - LpSNXWETH: mockTokens.LpSNXWETH.address, - LpUNIWETH: mockTokens.LpUNIWETH.address, - LpUSDCWETH: mockTokens.LpUSDCWETH.address, - LpWBTCUSDC: mockTokens.LpWBTCUSDC.address, - LpYFIWETH: mockTokens.LpYFIWETH.address, - USD: USD_ADDRESS, - }, - fallbackOracle - ); - - const mockAggregators = await deployAllMockAggregators(MOCK_CHAINLINK_AGGREGATORS_PRICES); - - const allTokenAddresses = Object.entries(mockTokens).reduce( - (accum: { [tokenSymbol: string]: tEthereumAddress }, [tokenSymbol, tokenContract]) => ({ - ...accum, - [tokenSymbol]: tokenContract.address, - }), - {} - ); - const allAggregatorsAddresses = Object.entries(mockAggregators).reduce( - (accum: { [tokenSymbol: string]: tEthereumAddress }, [tokenSymbol, aggregator]) => ({ - ...accum, - [tokenSymbol]: aggregator.address, - }), - {} - ); - - const [tokens, aggregators] = getPairsTokenAggregator(allTokenAddresses, allAggregatorsAddresses); - - await deployAaveOracle([tokens, aggregators, fallbackOracle.address, mockTokens.WETH.address]); - await waitForTx(await addressesProvider.setPriceOracle(fallbackOracle.address)); - - const lendingRateOracle = await deployLendingRateOracle(); - await waitForTx(await addressesProvider.setLendingRateOracle(lendingRateOracle.address)); - - const { USD, ...tokensAddressesWithoutUsd } = allTokenAddresses; - const allReservesAddresses = { - ...tokensAddressesWithoutUsd, - }; - await setInitialMarketRatesInRatesOracleByHelper( - LENDING_RATE_ORACLE_RATES_COMMON, - allReservesAddresses, - lendingRateOracle, - aaveAdmin - ); - - const reservesParams = getReservesConfigByPool(AavePools.proto); - - const testHelpers = await deployAaveProtocolDataProvider(addressesProvider.address); - - await insertContractAddressInDb(eContractid.AaveProtocolDataProvider, testHelpers.address); - const admin = await deployer.getAddress(); - - console.log('Initialize configuration'); - - const config = loadPoolConfig(ConfigNames.Aave); - - const treasuryAddress = await getTreasuryAddress(config); - - await initReservesByHelper( - reservesParams, - allReservesAddresses, - admin, - treasuryAddress, - ZERO_ADDRESS, - false - ); - await configureReservesByHelper(reservesParams, allReservesAddresses, testHelpers, admin); - - const collateralManager = await deployLendingPoolCollateralManager(); - await waitForTx( - await addressesProvider.setLendingPoolCollateralManager(collateralManager.address) - ); - await deployMockFlashLoanReceiver(addressesProvider.address); - - const mockUniswapRouter = await deployMockUniswapRouter(); - - const adapterParams: [string, string, string] = [ - addressesProvider.address, - mockUniswapRouter.address, - mockTokens.WETH.address, - ]; - - await deployUniswapLiquiditySwapAdapter(adapterParams); - await deployUniswapRepayAdapter(adapterParams); - await deployFlashLiquidationAdapter(adapterParams); - - await deployWalletBalancerProvider(); - - await deployWETHGateway([mockTokens.WETH.address, lendingPoolAddress]); - - console.timeEnd('setup'); -}; - -before(async () => { - await rawBRE.run('set-DRE'); - const [deployer, secondaryWallet] = await getEthersSigners(); - const MAINNET_FORK = process.env.MAINNET_FORK === 'true'; - - if (MAINNET_FORK) { - await rawBRE.run('aave:mainnet'); - } else { - 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/addresses-provider-registry.spec.ts b/test/addresses-provider-registry.spec.ts deleted file mode 100644 index 5ded1413..00000000 --- a/test/addresses-provider-registry.spec.ts +++ /dev/null @@ -1,100 +0,0 @@ -import { TestEnv, makeSuite } from './helpers/make-suite'; -import { ZERO_ADDRESS } from '../helpers/constants'; -import { ProtocolErrors } from '../helpers/types'; - -const { expect } = require('chai'); - -makeSuite('AddressesProviderRegistry', (testEnv: TestEnv) => { - it('Checks the addresses provider is added to the registry', async () => { - const { addressesProvider, registry } = testEnv; - - const providers = await registry.getAddressesProvidersList(); - - expect(providers.length).to.be.equal(1, 'Invalid length of the addresses providers list'); - expect(providers[0].toString()).to.be.equal( - addressesProvider.address, - ' Invalid addresses provider added to the list' - ); - }); - - it('tries to register an addresses provider with id 0', async () => { - const { users, registry } = testEnv; - const { LPAPR_INVALID_ADDRESSES_PROVIDER_ID } = ProtocolErrors; - - await expect(registry.registerAddressesProvider(users[2].address, '0')).to.be.revertedWith( - LPAPR_INVALID_ADDRESSES_PROVIDER_ID - ); - }); - - it('Registers a new mock addresses provider', async () => { - const { users, registry } = testEnv; - - //simulating an addresses provider using the users[1] wallet address - await registry.registerAddressesProvider(users[1].address, '2'); - - const providers = await registry.getAddressesProvidersList(); - - expect(providers.length).to.be.equal(2, 'Invalid length of the addresses providers list'); - expect(providers[1].toString()).to.be.equal( - users[1].address, - ' Invalid addresses provider added to the list' - ); - }); - - it('Removes the mock addresses provider', async () => { - const { users, registry, addressesProvider } = testEnv; - - const id = await registry.getAddressesProviderIdByAddress(users[1].address); - - expect(id).to.be.equal('2', 'Invalid isRegistered return value'); - - await registry.unregisterAddressesProvider(users[1].address); - - const providers = await registry.getAddressesProvidersList(); - - expect(providers.length).to.be.equal(2, 'Invalid length of the addresses providers list'); - expect(providers[0].toString()).to.be.equal( - addressesProvider.address, - ' Invalid addresses provider added to the list' - ); - expect(providers[1].toString()).to.be.equal(ZERO_ADDRESS, ' Invalid addresses'); - }); - - it('Tries to remove a unregistered addressesProvider', async () => { - const { LPAPR_PROVIDER_NOT_REGISTERED } = ProtocolErrors; - - const { users, registry } = testEnv; - - await expect(registry.unregisterAddressesProvider(users[2].address)).to.be.revertedWith( - LPAPR_PROVIDER_NOT_REGISTERED - ); - }); - - it('Tries to remove a unregistered addressesProvider', async () => { - const { LPAPR_PROVIDER_NOT_REGISTERED } = ProtocolErrors; - - const { users, registry } = testEnv; - - await expect(registry.unregisterAddressesProvider(users[2].address)).to.be.revertedWith( - LPAPR_PROVIDER_NOT_REGISTERED - ); - }); - - it('Tries to add an already added addressesProvider with a different id. Should overwrite the previous id', async () => { - const { users, registry, addressesProvider } = testEnv; - - await registry.registerAddressesProvider(addressesProvider.address, '2'); - - const providers = await registry.getAddressesProvidersList(); - - const id = await registry.getAddressesProviderIdByAddress(addressesProvider.address); - - expect(providers.length).to.be.equal(2, 'Invalid length of the addresses providers list'); - - expect(providers[0].toString()).to.be.equal( - addressesProvider.address, - ' Invalid addresses provider added to the list' - ); - expect(providers[1].toString()).to.be.equal(ZERO_ADDRESS, ' Invalid addresses'); - }); -}); diff --git a/test/atoken-modifiers.spec.ts b/test/atoken-modifiers.spec.ts deleted file mode 100644 index d379210c..00000000 --- a/test/atoken-modifiers.spec.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { expect } from 'chai'; -import { makeSuite, TestEnv } from './helpers/make-suite'; -import { ProtocolErrors } from '../helpers/types'; - -makeSuite('AToken: Modifiers', (testEnv: TestEnv) => { - const { CT_CALLER_MUST_BE_LENDING_POOL } = ProtocolErrors; - - it('Tries to invoke mint not being the LendingPool', async () => { - const { deployer, aDai } = testEnv; - await expect(aDai.mint(deployer.address, '1', '1')).to.be.revertedWith( - CT_CALLER_MUST_BE_LENDING_POOL - ); - }); - - it('Tries to invoke burn not being the LendingPool', async () => { - const { deployer, aDai } = testEnv; - await expect(aDai.burn(deployer.address, deployer.address, '1', '1')).to.be.revertedWith( - CT_CALLER_MUST_BE_LENDING_POOL - ); - }); - - it('Tries to invoke transferOnLiquidation not being the LendingPool', async () => { - const { deployer, users, aDai } = testEnv; - await expect( - aDai.transferOnLiquidation(deployer.address, users[0].address, '1') - ).to.be.revertedWith(CT_CALLER_MUST_BE_LENDING_POOL); - }); - - it('Tries to invoke transferUnderlyingTo not being the LendingPool', async () => { - const { deployer, aDai } = testEnv; - await expect(aDai.transferUnderlyingTo(deployer.address, '1')).to.be.revertedWith( - CT_CALLER_MUST_BE_LENDING_POOL - ); - }); -}); diff --git a/test/atoken-permit.spec.ts b/test/atoken-permit.spec.ts deleted file mode 100644 index bb880fee..00000000 --- a/test/atoken-permit.spec.ts +++ /dev/null @@ -1,312 +0,0 @@ -import { MAX_UINT_AMOUNT, ZERO_ADDRESS } from '../helpers/constants'; -import { BUIDLEREVM_CHAINID } from '../helpers/buidler-constants'; -import { buildPermitParams, getSignatureFromTypedData } from '../helpers/contracts-helpers'; -import { expect } from 'chai'; -import { ethers } from 'ethers'; -import { makeSuite, TestEnv } from './helpers/make-suite'; -import { DRE } from '../helpers/misc-utils'; -import { waitForTx } from '../helpers/misc-utils'; -import { _TypedDataEncoder } from 'ethers/lib/utils'; - -const { parseEther } = ethers.utils; - -makeSuite('AToken: Permit', (testEnv: TestEnv) => { - it('Checks the domain separator', async () => { - const { aDai } = testEnv; - const separator = await aDai.DOMAIN_SEPARATOR(); - - const domain = { - name: await aDai.name(), - version: '1', - chainId: DRE.network.config.chainId, - verifyingContract: aDai.address, - }; - const domainSeparator = _TypedDataEncoder.hashDomain(domain); - - expect(separator).to.be.equal(domainSeparator, 'Invalid domain separator'); - }); - - it('Get aDAI for tests', async () => { - const { dai, pool, deployer } = testEnv; - - await dai.mint(parseEther('20000')); - await dai.approve(pool.address, parseEther('20000')); - - await pool.deposit(dai.address, parseEther('20000'), deployer.address, 0); - }); - - it('Reverts submitting a permit with 0 expiration', async () => { - const { aDai, deployer, users } = testEnv; - const owner = deployer; - const spender = users[1]; - - const tokenName = await aDai.name(); - - const chainId = DRE.network.config.chainId || BUIDLEREVM_CHAINID; - const expiration = 0; - const nonce = (await aDai._nonces(owner.address)).toNumber(); - const permitAmount = ethers.utils.parseEther('2').toString(); - const msgParams = buildPermitParams( - chainId, - aDai.address, - '1', - tokenName, - owner.address, - spender.address, - nonce, - permitAmount, - expiration.toFixed() - ); - - const ownerPrivateKey = require('../test-wallets.js').accounts[0].secretKey; - if (!ownerPrivateKey) { - throw new Error('INVALID_OWNER_PK'); - } - - expect((await aDai.allowance(owner.address, spender.address)).toString()).to.be.equal( - '0', - 'INVALID_ALLOWANCE_BEFORE_PERMIT' - ); - - const { v, r, s } = getSignatureFromTypedData(ownerPrivateKey, msgParams); - - await expect( - aDai - .connect(spender.signer) - .permit(owner.address, spender.address, permitAmount, expiration, v, r, s) - ).to.be.revertedWith('INVALID_EXPIRATION'); - - expect((await aDai.allowance(owner.address, spender.address)).toString()).to.be.equal( - '0', - 'INVALID_ALLOWANCE_AFTER_PERMIT' - ); - }); - - it('Submits a permit with maximum expiration length', async () => { - const { aDai, deployer, users } = testEnv; - const owner = deployer; - const spender = users[1]; - - const chainId = DRE.network.config.chainId || BUIDLEREVM_CHAINID; - const deadline = MAX_UINT_AMOUNT; - const nonce = (await aDai._nonces(owner.address)).toNumber(); - const permitAmount = parseEther('2').toString(); - const msgParams = buildPermitParams( - chainId, - aDai.address, - '1', - await aDai.name(), - owner.address, - spender.address, - nonce, - deadline, - permitAmount - ); - - const ownerPrivateKey = require('../test-wallets.js').accounts[0].secretKey; - if (!ownerPrivateKey) { - throw new Error('INVALID_OWNER_PK'); - } - - expect((await aDai.allowance(owner.address, spender.address)).toString()).to.be.equal( - '0', - 'INVALID_ALLOWANCE_BEFORE_PERMIT' - ); - - const { v, r, s } = getSignatureFromTypedData(ownerPrivateKey, msgParams); - - await waitForTx( - await aDai - .connect(spender.signer) - .permit(owner.address, spender.address, permitAmount, deadline, v, r, s) - ); - - expect((await aDai._nonces(owner.address)).toNumber()).to.be.equal(1); - }); - - it('Cancels the previous permit', async () => { - const { aDai, deployer, users } = testEnv; - const owner = deployer; - const spender = users[1]; - - const chainId = DRE.network.config.chainId || BUIDLEREVM_CHAINID; - const deadline = MAX_UINT_AMOUNT; - const nonce = (await aDai._nonces(owner.address)).toNumber(); - const permitAmount = '0'; - const msgParams = buildPermitParams( - chainId, - aDai.address, - '1', - await aDai.name(), - owner.address, - spender.address, - nonce, - deadline, - permitAmount - ); - - const ownerPrivateKey = require('../test-wallets.js').accounts[0].secretKey; - if (!ownerPrivateKey) { - throw new Error('INVALID_OWNER_PK'); - } - - const { v, r, s } = getSignatureFromTypedData(ownerPrivateKey, msgParams); - - expect((await aDai.allowance(owner.address, spender.address)).toString()).to.be.equal( - ethers.utils.parseEther('2'), - 'INVALID_ALLOWANCE_BEFORE_PERMIT' - ); - - await waitForTx( - await aDai - .connect(spender.signer) - .permit(owner.address, spender.address, permitAmount, deadline, v, r, s) - ); - expect((await aDai.allowance(owner.address, spender.address)).toString()).to.be.equal( - permitAmount, - 'INVALID_ALLOWANCE_AFTER_PERMIT' - ); - - expect((await aDai._nonces(owner.address)).toNumber()).to.be.equal(2); - }); - - it('Tries to submit a permit with invalid nonce', async () => { - const { aDai, deployer, users } = testEnv; - const owner = deployer; - const spender = users[1]; - - const chainId = DRE.network.config.chainId || BUIDLEREVM_CHAINID; - const deadline = MAX_UINT_AMOUNT; - const nonce = 1000; - const permitAmount = '0'; - const msgParams = buildPermitParams( - chainId, - aDai.address, - '1', - await aDai.name(), - owner.address, - spender.address, - nonce, - deadline, - permitAmount - ); - - const ownerPrivateKey = require('../test-wallets.js').accounts[0].secretKey; - if (!ownerPrivateKey) { - throw new Error('INVALID_OWNER_PK'); - } - - const { v, r, s } = getSignatureFromTypedData(ownerPrivateKey, msgParams); - - await expect( - aDai - .connect(spender.signer) - .permit(owner.address, spender.address, permitAmount, deadline, v, r, s) - ).to.be.revertedWith('INVALID_SIGNATURE'); - }); - - it('Tries to submit a permit with invalid expiration (previous to the current block)', async () => { - const { aDai, deployer, users } = testEnv; - const owner = deployer; - const spender = users[1]; - - const chainId = DRE.network.config.chainId || BUIDLEREVM_CHAINID; - const expiration = '1'; - const nonce = (await aDai._nonces(owner.address)).toNumber(); - const permitAmount = '0'; - const msgParams = buildPermitParams( - chainId, - aDai.address, - '1', - await aDai.name(), - owner.address, - spender.address, - nonce, - expiration, - permitAmount - ); - - const ownerPrivateKey = require('../test-wallets.js').accounts[0].secretKey; - if (!ownerPrivateKey) { - throw new Error('INVALID_OWNER_PK'); - } - - const { v, r, s } = getSignatureFromTypedData(ownerPrivateKey, msgParams); - - await expect( - aDai - .connect(spender.signer) - .permit(owner.address, spender.address, expiration, permitAmount, v, r, s) - ).to.be.revertedWith('INVALID_EXPIRATION'); - }); - - it('Tries to submit a permit with invalid signature', async () => { - const { aDai, deployer, users } = testEnv; - const owner = deployer; - const spender = users[1]; - - const chainId = DRE.network.config.chainId || BUIDLEREVM_CHAINID; - const deadline = MAX_UINT_AMOUNT; - const nonce = (await aDai._nonces(owner.address)).toNumber(); - const permitAmount = '0'; - const msgParams = buildPermitParams( - chainId, - aDai.address, - '1', - await aDai.name(), - owner.address, - spender.address, - nonce, - deadline, - permitAmount - ); - - const ownerPrivateKey = require('../test-wallets.js').accounts[0].secretKey; - if (!ownerPrivateKey) { - throw new Error('INVALID_OWNER_PK'); - } - - const { v, r, s } = getSignatureFromTypedData(ownerPrivateKey, msgParams); - - await expect( - aDai - .connect(spender.signer) - .permit(owner.address, ZERO_ADDRESS, permitAmount, deadline, v, r, s) - ).to.be.revertedWith('INVALID_SIGNATURE'); - }); - - it('Tries to submit a permit with invalid owner', async () => { - const { aDai, deployer, users } = testEnv; - const owner = deployer; - const spender = users[1]; - - const chainId = DRE.network.config.chainId || BUIDLEREVM_CHAINID; - const expiration = MAX_UINT_AMOUNT; - const nonce = (await aDai._nonces(owner.address)).toNumber(); - const permitAmount = '0'; - const msgParams = buildPermitParams( - chainId, - aDai.address, - '1', - await aDai.name(), - owner.address, - spender.address, - nonce, - expiration, - permitAmount - ); - - const ownerPrivateKey = require('../test-wallets.js').accounts[0].secretKey; - if (!ownerPrivateKey) { - throw new Error('INVALID_OWNER_PK'); - } - - const { v, r, s } = getSignatureFromTypedData(ownerPrivateKey, msgParams); - - await expect( - aDai - .connect(spender.signer) - .permit(ZERO_ADDRESS, spender.address, expiration, permitAmount, v, r, s) - ).to.be.revertedWith('INVALID_OWNER'); - }); -}); diff --git a/test/atoken-transfer.spec.ts b/test/atoken-transfer.spec.ts deleted file mode 100644 index 7414eea9..00000000 --- a/test/atoken-transfer.spec.ts +++ /dev/null @@ -1,99 +0,0 @@ -import { APPROVAL_AMOUNT_LENDING_POOL, MAX_UINT_AMOUNT, ZERO_ADDRESS } from '../helpers/constants'; -import { convertToCurrencyDecimals } from '../helpers/contracts-helpers'; -import { expect } from 'chai'; -import { ethers } from 'ethers'; -import { RateMode, ProtocolErrors } from '../helpers/types'; -import { makeSuite, TestEnv } from './helpers/make-suite'; -import { CommonsConfig } from '../markets/aave/commons'; - -const AAVE_REFERRAL = CommonsConfig.ProtocolGlobalParams.AaveReferral; - -makeSuite('AToken: Transfer', (testEnv: TestEnv) => { - const { - INVALID_FROM_BALANCE_AFTER_TRANSFER, - INVALID_TO_BALANCE_AFTER_TRANSFER, - VL_TRANSFER_NOT_ALLOWED, - } = ProtocolErrors; - - it('User 0 deposits 1000 DAI, transfers to user 1', async () => { - const { users, pool, dai, aDai } = testEnv; - - await dai.connect(users[0].signer).mint(await convertToCurrencyDecimals(dai.address, '1000')); - - await dai.connect(users[0].signer).approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL); - - //user 1 deposits 1000 DAI - const amountDAItoDeposit = await convertToCurrencyDecimals(dai.address, '1000'); - - await pool - .connect(users[0].signer) - .deposit(dai.address, amountDAItoDeposit, users[0].address, '0'); - - await aDai.connect(users[0].signer).transfer(users[1].address, amountDAItoDeposit); - - const name = await aDai.name(); - - expect(name).to.be.equal('Aave interest bearing DAI'); - - const fromBalance = await aDai.balanceOf(users[0].address); - const toBalance = await aDai.balanceOf(users[1].address); - - expect(fromBalance.toString()).to.be.equal('0', INVALID_FROM_BALANCE_AFTER_TRANSFER); - expect(toBalance.toString()).to.be.equal( - amountDAItoDeposit.toString(), - INVALID_TO_BALANCE_AFTER_TRANSFER - ); - }); - - it('User 0 deposits 1 WETH and user 1 tries to borrow the WETH with the received DAI as collateral', async () => { - const { users, pool, weth, helpersContract } = testEnv; - const userAddress = await pool.signer.getAddress(); - - await weth.connect(users[0].signer).mint(await convertToCurrencyDecimals(weth.address, '1')); - - await weth.connect(users[0].signer).approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL); - - await pool - .connect(users[0].signer) - .deposit(weth.address, ethers.utils.parseEther('1.0'), userAddress, '0'); - await pool - .connect(users[1].signer) - .borrow( - weth.address, - ethers.utils.parseEther('0.1'), - RateMode.Stable, - AAVE_REFERRAL, - users[1].address - ); - - const userReserveData = await helpersContract.getUserReserveData( - weth.address, - users[1].address - ); - - expect(userReserveData.currentStableDebt.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 () => { - const { users, pool, aDai, dai, weth } = testEnv; - - const aDAItoTransfer = await convertToCurrencyDecimals(dai.address, '1000'); - - await expect( - aDai.connect(users[1].signer).transfer(users[0].address, aDAItoTransfer), - VL_TRANSFER_NOT_ALLOWED - ).to.be.revertedWith(VL_TRANSFER_NOT_ALLOWED); - }); - - it('User 1 tries to transfer a small amount of DAI used as collateral back to user 0', async () => { - const { users, pool, aDai, dai, weth } = testEnv; - - const aDAItoTransfer = await convertToCurrencyDecimals(dai.address, '100'); - - await aDai.connect(users[1].signer).transfer(users[0].address, aDAItoTransfer); - - const user0Balance = await aDai.balanceOf(users[0].address); - - expect(user0Balance.toString()).to.be.eq(aDAItoTransfer.toString()); - }); -}); diff --git a/test/configurator.spec.ts b/test/configurator.spec.ts deleted file mode 100644 index 1d888db0..00000000 --- a/test/configurator.spec.ts +++ /dev/null @@ -1,386 +0,0 @@ -import { TestEnv, makeSuite } from './helpers/make-suite'; -import { APPROVAL_AMOUNT_LENDING_POOL, RAY } from '../helpers/constants'; -import { convertToCurrencyDecimals } from '../helpers/contracts-helpers'; -import { ProtocolErrors } from '../helpers/types'; -import { strategyWETH } from '../markets/aave/reservesConfigs'; - -const { expect } = require('chai'); - -makeSuite('LendingPoolConfigurator', (testEnv: TestEnv) => { - const { - CALLER_NOT_POOL_ADMIN, - LPC_RESERVE_LIQUIDITY_NOT_0, - RC_INVALID_LTV, - RC_INVALID_LIQ_THRESHOLD, - RC_INVALID_LIQ_BONUS, - RC_INVALID_DECIMALS, - RC_INVALID_RESERVE_FACTOR, - } = ProtocolErrors; - - it('Reverts trying to set an invalid reserve factor', async () => { - const { configurator, weth } = testEnv; - - const invalidReserveFactor = 65536; - - await expect( - configurator.setReserveFactor(weth.address, invalidReserveFactor) - ).to.be.revertedWith(RC_INVALID_RESERVE_FACTOR); - }); - - it('Deactivates the ETH reserve', async () => { - const { configurator, weth, helpersContract } = testEnv; - await configurator.deactivateReserve(weth.address); - const { isActive } = await helpersContract.getReserveConfigurationData(weth.address); - expect(isActive).to.be.equal(false); - }); - - it('Rectivates the ETH reserve', async () => { - const { configurator, weth, helpersContract } = testEnv; - await configurator.activateReserve(weth.address); - - const { isActive } = await helpersContract.getReserveConfigurationData(weth.address); - expect(isActive).to.be.equal(true); - }); - - it('Check the onlyAaveAdmin on deactivateReserve ', async () => { - const { configurator, users, weth } = testEnv; - await expect( - configurator.connect(users[2].signer).deactivateReserve(weth.address), - CALLER_NOT_POOL_ADMIN - ).to.be.revertedWith(CALLER_NOT_POOL_ADMIN); - }); - - it('Check the onlyAaveAdmin on activateReserve ', async () => { - const { configurator, users, weth } = testEnv; - await expect( - configurator.connect(users[2].signer).activateReserve(weth.address), - CALLER_NOT_POOL_ADMIN - ).to.be.revertedWith(CALLER_NOT_POOL_ADMIN); - }); - - it('Freezes the ETH reserve', async () => { - const { configurator, weth, helpersContract } = testEnv; - - await configurator.freezeReserve(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(true); - 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('Unfreezes the ETH reserve', async () => { - const { configurator, helpersContract, weth } = testEnv; - await configurator.unfreezeReserve(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 freezeReserve ', async () => { - const { configurator, users, weth } = testEnv; - await expect( - configurator.connect(users[2].signer).freezeReserve(weth.address), - CALLER_NOT_POOL_ADMIN - ).to.be.revertedWith(CALLER_NOT_POOL_ADMIN); - }); - - it('Check the onlyAaveAdmin on unfreezeReserve ', async () => { - const { configurator, users, weth } = testEnv; - await expect( - configurator.connect(users[2].signer).unfreezeReserve(weth.address), - CALLER_NOT_POOL_ADMIN - ).to.be.revertedWith(CALLER_NOT_POOL_ADMIN); - }); - - it('Deactivates the ETH reserve for borrowing', async () => { - const { configurator, helpersContract, weth } = testEnv; - await configurator.disableBorrowingOnReserve(weth.address); - const { - decimals, - ltv, - liquidationBonus, - liquidationThreshold, - reserveFactor, - stableBorrowRateEnabled, - borrowingEnabled, - isActive, - isFrozen, - } = await helpersContract.getReserveConfigurationData(weth.address); - - expect(borrowingEnabled).to.be.equal(false); - 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('Activates the ETH reserve for borrowing', async () => { - const { configurator, weth, helpersContract } = testEnv; - await configurator.enableBorrowingOnReserve(weth.address, true); - const { variableBorrowIndex } = await helpersContract.getReserveData(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); - - expect(variableBorrowIndex.toString()).to.be.equal(RAY); - }); - - it('Check the onlyAaveAdmin on disableBorrowingOnReserve ', async () => { - const { configurator, users, weth } = testEnv; - await expect( - configurator.connect(users[2].signer).disableBorrowingOnReserve(weth.address), - CALLER_NOT_POOL_ADMIN - ).to.be.revertedWith(CALLER_NOT_POOL_ADMIN); - }); - - it('Check the onlyAaveAdmin on enableBorrowingOnReserve ', async () => { - const { configurator, users, weth } = testEnv; - await expect( - configurator.connect(users[2].signer).enableBorrowingOnReserve(weth.address, true), - CALLER_NOT_POOL_ADMIN - ).to.be.revertedWith(CALLER_NOT_POOL_ADMIN); - }); - - it('Deactivates the ETH reserve as collateral', async () => { - const { configurator, helpersContract, weth } = testEnv; - await configurator.configureReserveAsCollateral(weth.address, 0, 0, 0); - - 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(18); - expect(ltv).to.be.equal(0); - expect(liquidationThreshold).to.be.equal(0); - expect(liquidationBonus).to.be.equal(0); - expect(stableBorrowRateEnabled).to.be.equal(true); - expect(reserveFactor).to.be.equal(strategyWETH.reserveFactor); - }); - - it('Activates the ETH reserve as collateral', async () => { - const { configurator, helpersContract, weth } = testEnv; - await configurator.configureReserveAsCollateral(weth.address, '8000', '8250', '10500'); - - 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 configureReserveAsCollateral ', async () => { - const { configurator, users, weth } = testEnv; - await expect( - configurator - .connect(users[2].signer) - .configureReserveAsCollateral(weth.address, '7500', '8000', '10500'), - CALLER_NOT_POOL_ADMIN - ).to.be.revertedWith(CALLER_NOT_POOL_ADMIN); - }); - - it('Disable stable borrow rate 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(false); - expect(reserveFactor).to.be.equal(strategyWETH.reserveFactor); - }); - - it('Enables stable borrow rate on the ETH reserve', async () => { - const { configurator, helpersContract, weth } = testEnv; - await configurator.enableReserveStableRate(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(true); - expect(reserveFactor).to.be.equal(strategyWETH.reserveFactor); - }); - - it('Check the onlyAaveAdmin on disableReserveStableRate', async () => { - const { configurator, users, weth } = testEnv; - await expect( - configurator.connect(users[2].signer).disableReserveStableRate(weth.address), - CALLER_NOT_POOL_ADMIN - ).to.be.revertedWith(CALLER_NOT_POOL_ADMIN); - }); - - it('Check the onlyAaveAdmin on enableReserveStableRate', async () => { - const { configurator, users, weth } = testEnv; - await expect( - configurator.connect(users[2].signer).enableReserveStableRate(weth.address), - CALLER_NOT_POOL_ADMIN - ).to.be.revertedWith(CALLER_NOT_POOL_ADMIN); - }); - - it('Changes the reserve factor of WETH', async () => { - const { configurator, helpersContract, weth } = testEnv; - await configurator.setReserveFactor(weth.address, '1000'); - 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(1000); - }); - - it('Check the onlyLendingPoolManager on setReserveFactor', async () => { - const { configurator, users, weth } = testEnv; - await expect( - configurator.connect(users[2].signer).setReserveFactor(weth.address, '2000'), - CALLER_NOT_POOL_ADMIN - ).to.be.revertedWith(CALLER_NOT_POOL_ADMIN); - }); - - it('Reverts when trying to disable the DAI reserve with liquidity on it', async () => { - const { dai, pool, configurator } = testEnv; - const userAddress = await pool.signer.getAddress(); - await dai.mint(await convertToCurrencyDecimals(dai.address, '1000')); - - //approve protocol to access depositor wallet - await dai.approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL); - const amountDAItoDeposit = await convertToCurrencyDecimals(dai.address, '1000'); - - //user 1 deposits 1000 DAI - await pool.deposit(dai.address, amountDAItoDeposit, userAddress, '0'); - - await expect( - configurator.deactivateReserve(dai.address), - LPC_RESERVE_LIQUIDITY_NOT_0 - ).to.be.revertedWith(LPC_RESERVE_LIQUIDITY_NOT_0); - }); -}); diff --git a/test/delegation-aware-atoken.spec.ts b/test/delegation-aware-atoken.spec.ts deleted file mode 100644 index 7b04913e..00000000 --- a/test/delegation-aware-atoken.spec.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { MAX_UINT_AMOUNT, ZERO_ADDRESS } from '../helpers/constants'; -import { BUIDLEREVM_CHAINID } from '../helpers/buidler-constants'; -import { buildPermitParams, getSignatureFromTypedData } from '../helpers/contracts-helpers'; -import { expect } from 'chai'; -import { ethers } from 'ethers'; -import { eEthereumNetwork, ProtocolErrors } from '../helpers/types'; -import { makeSuite, TestEnv } from './helpers/make-suite'; -import { DRE } from '../helpers/misc-utils'; -import { - ConfigNames, - getATokenDomainSeparatorPerNetwork, - getTreasuryAddress, - loadPoolConfig, -} from '../helpers/configuration'; -import { waitForTx } from '../helpers/misc-utils'; -import { - deployDelegationAwareAToken, - deployMintableDelegationERC20, -} from '../helpers/contracts-deployments'; -import { DelegationAwareATokenFactory } from '../types'; -import { DelegationAwareAToken } from '../types/DelegationAwareAToken'; -import { MintableDelegationERC20 } from '../types/MintableDelegationERC20'; -import AaveConfig from '../markets/aave'; - -const { parseEther } = ethers.utils; - -makeSuite('AToken: underlying delegation', (testEnv: TestEnv) => { - const poolConfig = loadPoolConfig(ConfigNames.Commons); - let delegationAToken = {}; - let delegationERC20 = {}; - - it('Deploys a new MintableDelegationERC20 and a DelegationAwareAToken', async () => { - const { pool } = testEnv; - - delegationERC20 = await deployMintableDelegationERC20(['DEL', 'DEL', '18']); - - delegationAToken = await deployDelegationAwareAToken( - [pool.address, delegationERC20.address, await getTreasuryAddress(AaveConfig), ZERO_ADDRESS, 'aDEL', 'aDEL'], - false - ); - - //await delegationAToken.initialize(pool.address, ZERO_ADDRESS, delegationERC20.address, ZERO_ADDRESS, '18', 'aDEL', 'aDEL'); - - console.log((await delegationAToken.decimals()).toString()); - }); - - it('Tries to delegate with the caller not being the Aave admin', async () => { - const { users } = testEnv; - - await expect( - delegationAToken.connect(users[1].signer).delegateUnderlyingTo(users[2].address) - ).to.be.revertedWith(ProtocolErrors.CALLER_NOT_POOL_ADMIN); - }); - - it('Tries to delegate to user 2', async () => { - const { users } = testEnv; - - await delegationAToken.delegateUnderlyingTo(users[2].address); - - const delegateeAddress = await delegationERC20.delegatee(); - - expect(delegateeAddress).to.be.equal(users[2].address); - }); -}); diff --git a/test/flashloan.spec.ts b/test/flashloan.spec.ts deleted file mode 100644 index c6e5dcff..00000000 --- a/test/flashloan.spec.ts +++ /dev/null @@ -1,497 +0,0 @@ -import BigNumber from 'bignumber.js'; - -import { TestEnv, makeSuite } from './helpers/make-suite'; -import { APPROVAL_AMOUNT_LENDING_POOL, oneRay } from '../helpers/constants'; -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; - - before(async () => { - _mockFlashLoanReceiver = await getMockFlashLoanReceiver(); - }); - - it('Deposits WETH into the reserve', async () => { - const { pool, weth } = testEnv; - 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'); - }); - - it('Takes WETH flashloan with mode = 0, returns the funds correctly', async () => { - const { pool, helpersContract, weth } = testEnv; - - await pool.flashLoan( - _mockFlashLoanReceiver.address, - [weth.address], - [ethers.utils.parseEther('0.8')], - [0], - _mockFlashLoanReceiver.address, - '0x10', - '0' - ); - - ethers.utils.parseUnits('10000'); - - const reserveData = await helpersContract.getReserveData(weth.address); - - const currentLiquidityRate = reserveData.liquidityRate; - const currentLiquidityIndex = reserveData.liquidityIndex; - - const totalLiquidity = new BigNumber(reserveData.availableLiquidity.toString()) - .plus(reserveData.totalStableDebt.toString()) - .plus(reserveData.totalVariableDebt.toString()); - - expect(totalLiquidity.toString()).to.be.equal('1000720000000000000'); - expect(currentLiquidityRate.toString()).to.be.equal('0'); - expect(currentLiquidityIndex.toString()).to.be.equal('1000720000000000000000000000'); - }); - - it('Takes an ETH flashloan with mode = 0 as big as the available liquidity', async () => { - const { pool, helpersContract, weth } = testEnv; - - const reserveDataBefore = await helpersContract.getReserveData(weth.address); - const txResult = await pool.flashLoan( - _mockFlashLoanReceiver.address, - [weth.address], - ['1000720000000000000'], - [0], - _mockFlashLoanReceiver.address, - '0x10', - '0' - ); - - const reserveData = await helpersContract.getReserveData(weth.address); - - const currentLiqudityRate = reserveData.liquidityRate; - const currentLiquidityIndex = reserveData.liquidityIndex; - - const totalLiquidity = new BigNumber(reserveData.availableLiquidity.toString()) - .plus(reserveData.totalStableDebt.toString()) - .plus(reserveData.totalVariableDebt.toString()); - - expect(totalLiquidity.toString()).to.be.equal('1001620648000000000'); - expect(currentLiqudityRate.toString()).to.be.equal('0'); - expect(currentLiquidityIndex.toString()).to.be.equal('1001620648000000000000000000'); - }); - - 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); - - 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 - ); - - const wethDebtToken = await getVariableDebtToken(variableDebtTokenAddress); - - const callerDebt = await wethDebtToken.balanceOf(caller.address); - - expect(callerDebt.toString()).to.be.equal('800000000000000000', 'Invalid user debt'); - }); - - 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 () => { - const { usdc, pool, helpersContract, deployer: depositor } = testEnv; - - await _mockFlashLoanReceiver.setFailExecutionTransfer(false); - - const reserveDataBefore = await helpersContract.getReserveData(usdc.address); - - const flashloanAmount = await convertToCurrencyDecimals(usdc.address, '500'); - - await pool.flashLoan( - _mockFlashLoanReceiver.address, - [usdc.address], - [flashloanAmount], - [0], - _mockFlashLoanReceiver.address, - '0x10', - '0' - ); - - const reserveDataAfter = helpersContract.getReserveData(usdc.address); - - const reserveData = await helpersContract.getReserveData(usdc.address); - const userData = await helpersContract.getUserReserveData(usdc.address, depositor.address); - - const totalLiquidity = reserveData.availableLiquidity - .add(reserveData.totalStableDebt) - .add(reserveData.totalVariableDebt) - .toString(); - const currentLiqudityRate = reserveData.liquidityRate.toString(); - const currentLiquidityIndex = reserveData.liquidityIndex.toString(); - const currentUserBalance = userData.currentATokenBalance.toString(); - - const expectedLiquidity = await convertToCurrencyDecimals(usdc.address, '1000.450'); - - expect(totalLiquidity).to.be.equal(expectedLiquidity, 'Invalid total liquidity'); - expect(currentLiqudityRate).to.be.equal('0', 'Invalid liquidity rate'); - expect(currentLiquidityIndex).to.be.equal( - new BigNumber('1.00045').multipliedBy(oneRay).toFixed(), - 'Invalid liquidity index' - ); - expect(currentUserBalance.toString()).to.be.equal(expectedLiquidity, 'Invalid user balance'); - }); - - 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); - - const stableDebtToken = await getVariableDebtToken(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 - .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' - ); - }); -}); diff --git a/test/helpers/actions.ts b/test/helpers/actions.ts deleted file mode 100644 index 7b0081ce..00000000 --- a/test/helpers/actions.ts +++ /dev/null @@ -1,772 +0,0 @@ -import BigNumber from 'bignumber.js'; - -import { - calcExpectedReserveDataAfterBorrow, - calcExpectedReserveDataAfterDeposit, - calcExpectedReserveDataAfterRepay, - calcExpectedReserveDataAfterStableRateRebalance, - calcExpectedReserveDataAfterSwapRateMode, - calcExpectedReserveDataAfterWithdraw, - calcExpectedUserDataAfterBorrow, - calcExpectedUserDataAfterDeposit, - calcExpectedUserDataAfterRepay, - calcExpectedUserDataAfterSetUseAsCollateral, - calcExpectedUserDataAfterStableRateRebalance, - calcExpectedUserDataAfterSwapRateMode, - calcExpectedUserDataAfterWithdraw, -} from './utils/calculations'; -import { getReserveAddressFromSymbol, getReserveData, getUserData } from './utils/helpers'; - -import { convertToCurrencyDecimals } from '../../helpers/contracts-helpers'; -import { - getAToken, - getMintableERC20, - getStableDebtToken, - getVariableDebtToken, -} from '../../helpers/contracts-getters'; -import { MAX_UINT_AMOUNT, ONE_YEAR } from '../../helpers/constants'; -import { SignerWithAddress, TestEnv } from './make-suite'; -import { advanceTimeAndBlock, DRE, timeLatest, waitForTx } from '../../helpers/misc-utils'; - -import chai from 'chai'; -import { ReserveData, UserReserveData } from './utils/interfaces'; -import { ContractReceipt } from 'ethers'; -import { AToken } from '../../types/AToken'; -import { RateMode, tEthereumAddress } from '../../helpers/types'; - -const { expect } = chai; - -const almostEqualOrEqual = function ( - this: any, - expected: ReserveData | UserReserveData, - actual: ReserveData | UserReserveData -) { - const keys = Object.keys(actual); - - keys.forEach((key) => { - if ( - key === 'lastUpdateTimestamp' || - key === 'marketStableRate' || - key === 'symbol' || - key === 'aTokenAddress' || - key === 'decimals' || - key === 'totalStableDebtLastUpdated' - ) { - // skipping consistency check on accessory data - return; - } - - this.assert(actual[key] != undefined, `Property ${key} is undefined in the actual data`); - expect(expected[key] != undefined, `Property ${key} is undefined in the expected data`); - - if (expected[key] == null || actual[key] == null) { - console.log('Found a undefined value for Key ', key, ' value ', expected[key], actual[key]); - } - - if (actual[key] instanceof BigNumber) { - const actualValue = (actual[key]).decimalPlaces(0, BigNumber.ROUND_DOWN); - const expectedValue = (expected[key]).decimalPlaces(0, BigNumber.ROUND_DOWN); - - this.assert( - actualValue.eq(expectedValue) || - actualValue.plus(1).eq(expectedValue) || - actualValue.eq(expectedValue.plus(1)) || - actualValue.plus(2).eq(expectedValue) || - actualValue.eq(expectedValue.plus(2)) || - actualValue.plus(3).eq(expectedValue) || - actualValue.eq(expectedValue.plus(3)), - `expected #{act} to be almost equal or equal #{exp} for property ${key}`, - `expected #{act} to be almost equal or equal #{exp} for property ${key}`, - expectedValue.toFixed(0), - actualValue.toFixed(0) - ); - } else { - this.assert( - actual[key] !== null && - expected[key] !== null && - actual[key].toString() === expected[key].toString(), - `expected #{act} to be equal #{exp} for property ${key}`, - `expected #{act} to be equal #{exp} for property ${key}`, - expected[key], - actual[key] - ); - } - }); -}; - -chai.use(function (chai: any, utils: any) { - chai.Assertion.overwriteMethod('almostEqualOrEqual', function (original: any) { - return function (this: any, expected: ReserveData | UserReserveData) { - const actual = (expected as ReserveData) - ? this._obj - : this._obj; - - almostEqualOrEqual.apply(this, [expected, actual]); - }; - }); -}); - -interface ActionsConfig { - skipIntegrityCheck: boolean; -} - -export const configuration: ActionsConfig = {}; - -export const mint = async (reserveSymbol: string, amount: string, user: SignerWithAddress) => { - const reserve = await getReserveAddressFromSymbol(reserveSymbol); - - const token = await getMintableERC20(reserve); - - await waitForTx( - await token.connect(user.signer).mint(await convertToCurrencyDecimals(reserve, amount)) - ); -}; - -export const approve = async (reserveSymbol: string, user: SignerWithAddress, testEnv: TestEnv) => { - const { pool } = testEnv; - const reserve = await getReserveAddressFromSymbol(reserveSymbol); - - const token = await getMintableERC20(reserve); - - await waitForTx( - await token.connect(user.signer).approve(pool.address, '100000000000000000000000000000') - ); -}; - -export const deposit = async ( - reserveSymbol: string, - amount: string, - sender: SignerWithAddress, - onBehalfOf: tEthereumAddress, - sendValue: string, - expectedResult: string, - testEnv: TestEnv, - revertMessage?: string -) => { - const { pool } = testEnv; - - const reserve = await getReserveAddressFromSymbol(reserveSymbol); - - const amountToDeposit = await convertToCurrencyDecimals(reserve, amount); - - const txOptions: any = {}; - - const { reserveData: reserveDataBefore, userData: userDataBefore } = await getContractsData( - reserve, - onBehalfOf, - testEnv, - sender.address - ); - - if (sendValue) { - txOptions.value = await convertToCurrencyDecimals(reserve, sendValue); - } - - //console.log("Depositing %s %s, expecting %s", amountToDeposit.toString(), reserveSymbol, expectedResult); - - if (expectedResult === 'success') { - const txResult = await waitForTx( - await pool - .connect(sender.signer) - .deposit(reserve, amountToDeposit, onBehalfOf, '0', txOptions) - ); - - const { - reserveData: reserveDataAfter, - userData: userDataAfter, - timestamp, - } = await getContractsData(reserve, onBehalfOf, testEnv, sender.address); - - const { txCost, txTimestamp } = await getTxCostAndTimestamp(txResult); - - const expectedReserveData = calcExpectedReserveDataAfterDeposit( - amountToDeposit.toString(), - reserveDataBefore, - txTimestamp - ); - - const expectedUserReserveData = calcExpectedUserDataAfterDeposit( - amountToDeposit.toString(), - reserveDataBefore, - expectedReserveData, - userDataBefore, - txTimestamp, - timestamp, - txCost - ); - - expectEqual(reserveDataAfter, expectedReserveData); - expectEqual(userDataAfter, expectedUserReserveData); - - // truffleAssert.eventEmitted(txResult, "Deposit", (ev: any) => { - // const {_reserve, _user, _amount} = ev; - // return ( - // _reserve === reserve && - // _user === user && - // new BigNumber(_amount).isEqualTo(new BigNumber(amountToDeposit)) - // ); - // }); - } else if (expectedResult === 'revert') { - await expect( - pool.connect(sender.signer).deposit(reserve, amountToDeposit, onBehalfOf, '0', txOptions), - revertMessage - ).to.be.reverted; - } -}; - -export const withdraw = async ( - reserveSymbol: string, - amount: string, - user: SignerWithAddress, - expectedResult: string, - testEnv: TestEnv, - revertMessage?: string -) => { - const { pool } = testEnv; - - const { - aTokenInstance, - reserve, - userData: userDataBefore, - reserveData: reserveDataBefore, - } = await getDataBeforeAction(reserveSymbol, user.address, testEnv); - - let amountToWithdraw = '0'; - - if (amount !== '-1') { - amountToWithdraw = (await convertToCurrencyDecimals(reserve, amount)).toString(); - } else { - amountToWithdraw = MAX_UINT_AMOUNT; - } - - if (expectedResult === 'success') { - const txResult = await waitForTx( - await pool.connect(user.signer).withdraw(reserve, amountToWithdraw, user.address) - ); - - const { - reserveData: reserveDataAfter, - userData: userDataAfter, - timestamp, - } = await getContractsData(reserve, user.address, testEnv); - - const { txCost, txTimestamp } = await getTxCostAndTimestamp(txResult); - - const expectedReserveData = calcExpectedReserveDataAfterWithdraw( - amountToWithdraw, - reserveDataBefore, - userDataBefore, - txTimestamp - ); - - const expectedUserData = calcExpectedUserDataAfterWithdraw( - amountToWithdraw, - reserveDataBefore, - expectedReserveData, - userDataBefore, - txTimestamp, - timestamp, - txCost - ); - - expectEqual(reserveDataAfter, expectedReserveData); - expectEqual(userDataAfter, expectedUserData); - - // truffleAssert.eventEmitted(txResult, "Redeem", (ev: any) => { - // const {_from, _value} = ev; - // return ( - // _from === user && new BigNumber(_value).isEqualTo(actualAmountRedeemed) - // ); - // }); - } else if (expectedResult === 'revert') { - await expect( - pool.connect(user.signer).withdraw(reserve, amountToWithdraw, user.address), - revertMessage - ).to.be.reverted; - } -}; - -export const delegateBorrowAllowance = async ( - reserve: string, - amount: string, - interestRateMode: string, - user: SignerWithAddress, - receiver: tEthereumAddress, - expectedResult: string, - testEnv: TestEnv, - revertMessage?: string -) => { - const { pool } = testEnv; - - const reserveAddress: tEthereumAddress = await getReserveAddressFromSymbol(reserve); - - const amountToDelegate: string = await ( - await convertToCurrencyDecimals(reserveAddress, amount) - ).toString(); - - const reserveData = await pool.getReserveData(reserveAddress); - - const debtToken = - interestRateMode === '1' - ? await getStableDebtToken(reserveData.stableDebtTokenAddress) - : await getVariableDebtToken(reserveData.variableDebtTokenAddress); - - const delegateAllowancePromise = debtToken - .connect(user.signer) - .approveDelegation(receiver, amountToDelegate); - - if (expectedResult === 'revert' && revertMessage) { - await expect(delegateAllowancePromise, revertMessage).to.be.revertedWith(revertMessage); - return; - } else { - await waitForTx(await delegateAllowancePromise); - const allowance = await debtToken.borrowAllowance(user.address, receiver); - expect(allowance.toString()).to.be.equal( - amountToDelegate, - 'borrowAllowance is set incorrectly' - ); - } -}; - -export const borrow = async ( - reserveSymbol: string, - amount: string, - interestRateMode: string, - user: SignerWithAddress, - onBehalfOf: tEthereumAddress, - timeTravel: string, - expectedResult: string, - testEnv: TestEnv, - revertMessage?: string -) => { - const { pool } = testEnv; - - const reserve = await getReserveAddressFromSymbol(reserveSymbol); - - const { reserveData: reserveDataBefore, userData: userDataBefore } = await getContractsData( - reserve, - onBehalfOf, - testEnv, - user.address - ); - - const amountToBorrow = await convertToCurrencyDecimals(reserve, amount); - //console.log("Borrowing %s %s with rate mode %s expecting", amountToBorrow.toString(), reserveSymbol, interestRateMode, expectedResult); - if (expectedResult === 'success') { - const txResult = await waitForTx( - await pool - .connect(user.signer) - .borrow(reserve, amountToBorrow, interestRateMode, '0', onBehalfOf) - ); - - const { txCost, txTimestamp } = await getTxCostAndTimestamp(txResult); - - if (timeTravel) { - const secondsToTravel = new BigNumber(timeTravel).multipliedBy(ONE_YEAR).div(365).toNumber(); - - await advanceTimeAndBlock(secondsToTravel); - } - - const { - reserveData: reserveDataAfter, - userData: userDataAfter, - timestamp, - } = await getContractsData(reserve, onBehalfOf, testEnv, user.address); - - const expectedReserveData = calcExpectedReserveDataAfterBorrow( - amountToBorrow.toString(), - interestRateMode, - reserveDataBefore, - userDataBefore, - txTimestamp, - timestamp - ); - - const expectedUserData = calcExpectedUserDataAfterBorrow( - amountToBorrow.toString(), - interestRateMode, - reserveDataBefore, - expectedReserveData, - userDataBefore, - txTimestamp, - timestamp - ); - - expectEqual(reserveDataAfter, expectedReserveData); - expectEqual(userDataAfter, expectedUserData); - - // truffleAssert.eventEmitted(txResult, "Borrow", (ev: any) => { - // const { - // _reserve, - // _user, - // _amount, - // _borrowRateMode, - // _borrowRate, - // _originationFee, - // } = ev; - // return ( - // _reserve.toLowerCase() === reserve.toLowerCase() && - // _user.toLowerCase() === user.toLowerCase() && - // new BigNumber(_amount).eq(amountToBorrow) && - // new BigNumber(_borrowRateMode).eq(expectedUserData.borrowRateMode) && - // new BigNumber(_borrowRate).eq(expectedUserData.borrowRate) && - // new BigNumber(_originationFee).eq( - // expectedUserData.originationFee.minus(userDataBefore.originationFee) - // ) - // ); - // }); - } else if (expectedResult === 'revert') { - await expect( - pool.connect(user.signer).borrow(reserve, amountToBorrow, interestRateMode, '0', onBehalfOf), - revertMessage - ).to.be.reverted; - } -}; - -export const repay = async ( - reserveSymbol: string, - amount: string, - rateMode: string, - user: SignerWithAddress, - onBehalfOf: SignerWithAddress, - sendValue: string, - expectedResult: string, - testEnv: TestEnv, - revertMessage?: string -) => { - const { pool } = testEnv; - const reserve = await getReserveAddressFromSymbol(reserveSymbol); - - const { reserveData: reserveDataBefore, userData: userDataBefore } = await getContractsData( - reserve, - onBehalfOf.address, - testEnv - ); - - let amountToRepay = '0'; - - if (amount !== '-1') { - amountToRepay = (await convertToCurrencyDecimals(reserve, amount)).toString(); - } else { - amountToRepay = MAX_UINT_AMOUNT; - } - amountToRepay = '0x' + new BigNumber(amountToRepay).toString(16); - - const txOptions: any = {}; - - if (sendValue) { - const valueToSend = await convertToCurrencyDecimals(reserve, sendValue); - txOptions.value = '0x' + new BigNumber(valueToSend.toString()).toString(16); - } - - if (expectedResult === 'success') { - const txResult = await waitForTx( - await pool - .connect(user.signer) - .repay(reserve, amountToRepay, rateMode, onBehalfOf.address, txOptions) - ); - - const { txCost, txTimestamp } = await getTxCostAndTimestamp(txResult); - - const { - reserveData: reserveDataAfter, - userData: userDataAfter, - timestamp, - } = await getContractsData(reserve, onBehalfOf.address, testEnv); - - const expectedReserveData = calcExpectedReserveDataAfterRepay( - amountToRepay, - rateMode, - reserveDataBefore, - userDataBefore, - txTimestamp, - timestamp - ); - - const expectedUserData = calcExpectedUserDataAfterRepay( - amountToRepay, - rateMode, - reserveDataBefore, - expectedReserveData, - userDataBefore, - user.address, - onBehalfOf.address, - txTimestamp, - timestamp - ); - - expectEqual(reserveDataAfter, expectedReserveData); - expectEqual(userDataAfter, expectedUserData); - - // truffleAssert.eventEmitted(txResult, "Repay", (ev: any) => { - // const {_reserve, _user, _repayer} = ev; - - // return ( - // _reserve.toLowerCase() === reserve.toLowerCase() && - // _user.toLowerCase() === onBehalfOf.toLowerCase() && - // _repayer.toLowerCase() === user.toLowerCase() - // ); - // }); - } else if (expectedResult === 'revert') { - await expect( - pool - .connect(user.signer) - .repay(reserve, amountToRepay, rateMode, onBehalfOf.address, txOptions), - revertMessage - ).to.be.reverted; - } -}; - -export const setUseAsCollateral = async ( - reserveSymbol: string, - user: SignerWithAddress, - useAsCollateral: string, - expectedResult: string, - testEnv: TestEnv, - revertMessage?: string -) => { - const { pool } = testEnv; - - const reserve = await getReserveAddressFromSymbol(reserveSymbol); - - const { reserveData: reserveDataBefore, userData: userDataBefore } = await getContractsData( - reserve, - user.address, - testEnv - ); - - const useAsCollateralBool = useAsCollateral.toLowerCase() === 'true'; - - if (expectedResult === 'success') { - const txResult = await waitForTx( - await pool.connect(user.signer).setUserUseReserveAsCollateral(reserve, useAsCollateralBool) - ); - - const { txCost } = await getTxCostAndTimestamp(txResult); - - const { userData: userDataAfter } = await getContractsData(reserve, user.address, testEnv); - - const expectedUserData = calcExpectedUserDataAfterSetUseAsCollateral( - useAsCollateral.toLocaleLowerCase() === 'true', - reserveDataBefore, - userDataBefore, - txCost - ); - - expectEqual(userDataAfter, expectedUserData); - // if (useAsCollateralBool) { - // truffleAssert.eventEmitted(txResult, 'ReserveUsedAsCollateralEnabled', (ev: any) => { - // const {_reserve, _user} = ev; - // return _reserve === reserve && _user === user; - // }); - // } else { - // truffleAssert.eventEmitted(txResult, 'ReserveUsedAsCollateralDisabled', (ev: any) => { - // const {_reserve, _user} = ev; - // return _reserve === reserve && _user === user; - // }); - // } - } else if (expectedResult === 'revert') { - await expect( - pool.connect(user.signer).setUserUseReserveAsCollateral(reserve, useAsCollateralBool), - revertMessage - ).to.be.reverted; - } -}; - -export const swapBorrowRateMode = async ( - reserveSymbol: string, - user: SignerWithAddress, - rateMode: string, - expectedResult: string, - testEnv: TestEnv, - revertMessage?: string -) => { - const { pool } = testEnv; - - const reserve = await getReserveAddressFromSymbol(reserveSymbol); - - const { reserveData: reserveDataBefore, userData: userDataBefore } = await getContractsData( - reserve, - user.address, - testEnv - ); - - if (expectedResult === 'success') { - const txResult = await waitForTx( - await pool.connect(user.signer).swapBorrowRateMode(reserve, rateMode) - ); - - const { txCost, txTimestamp } = await getTxCostAndTimestamp(txResult); - - const { reserveData: reserveDataAfter, userData: userDataAfter } = await getContractsData( - reserve, - user.address, - testEnv - ); - - const expectedReserveData = calcExpectedReserveDataAfterSwapRateMode( - reserveDataBefore, - userDataBefore, - rateMode, - txTimestamp - ); - - const expectedUserData = calcExpectedUserDataAfterSwapRateMode( - reserveDataBefore, - expectedReserveData, - userDataBefore, - rateMode, - txCost, - txTimestamp - ); - - expectEqual(reserveDataAfter, expectedReserveData); - expectEqual(userDataAfter, expectedUserData); - - // truffleAssert.eventEmitted(txResult, "Swap", (ev: any) => { - // const {_user, _reserve, _newRateMode, _newRate} = ev; - // return ( - // _user === user && - // _reserve == reserve && - // new BigNumber(_newRateMode).eq(expectedUserData.borrowRateMode) && - // new BigNumber(_newRate).eq(expectedUserData.borrowRate) - // ); - // }); - } else if (expectedResult === 'revert') { - await expect(pool.connect(user.signer).swapBorrowRateMode(reserve, rateMode), revertMessage).to - .be.reverted; - } -}; - -export const rebalanceStableBorrowRate = async ( - reserveSymbol: string, - user: SignerWithAddress, - target: SignerWithAddress, - expectedResult: string, - testEnv: TestEnv, - revertMessage?: string -) => { - const { pool } = testEnv; - - const reserve = await getReserveAddressFromSymbol(reserveSymbol); - - const { reserveData: reserveDataBefore, userData: userDataBefore } = await getContractsData( - reserve, - target.address, - testEnv - ); - - if (expectedResult === 'success') { - const txResult = await waitForTx( - await pool.connect(user.signer).rebalanceStableBorrowRate(reserve, target.address) - ); - - const { txCost, txTimestamp } = await getTxCostAndTimestamp(txResult); - - const { reserveData: reserveDataAfter, userData: userDataAfter } = await getContractsData( - reserve, - target.address, - testEnv - ); - - const expectedReserveData = calcExpectedReserveDataAfterStableRateRebalance( - reserveDataBefore, - userDataBefore, - txTimestamp - ); - - const expectedUserData = calcExpectedUserDataAfterStableRateRebalance( - reserveDataBefore, - expectedReserveData, - userDataBefore, - txCost, - txTimestamp - ); - - expectEqual(reserveDataAfter, expectedReserveData); - expectEqual(userDataAfter, expectedUserData); - - // truffleAssert.eventEmitted(txResult, 'RebalanceStableBorrowRate', (ev: any) => { - // const {_user, _reserve, _newStableRate} = ev; - // return ( - // _user.toLowerCase() === target.toLowerCase() && - // _reserve.toLowerCase() === reserve.toLowerCase() && - // new BigNumber(_newStableRate).eq(expectedUserData.borrowRate) - // ); - // }); - } else if (expectedResult === 'revert') { - await expect( - pool.connect(user.signer).rebalanceStableBorrowRate(reserve, target.address), - revertMessage - ).to.be.reverted; - } -}; - -const expectEqual = ( - actual: UserReserveData | ReserveData, - expected: UserReserveData | ReserveData -) => { - if (!configuration.skipIntegrityCheck) { - // @ts-ignore - expect(actual).to.be.almostEqualOrEqual(expected); - } -}; - -interface ActionData { - reserve: string; - reserveData: ReserveData; - userData: UserReserveData; - aTokenInstance: AToken; -} - -const getDataBeforeAction = async ( - reserveSymbol: string, - user: tEthereumAddress, - testEnv: TestEnv -): Promise => { - const reserve = await getReserveAddressFromSymbol(reserveSymbol); - - const { reserveData, userData } = await getContractsData(reserve, user, testEnv); - const aTokenInstance = await getAToken(reserveData.aTokenAddress); - return { - reserve, - reserveData, - userData, - aTokenInstance, - }; -}; - -export const getTxCostAndTimestamp = async (tx: ContractReceipt) => { - if (!tx.blockNumber || !tx.transactionHash || !tx.cumulativeGasUsed) { - throw new Error('No tx blocknumber'); - } - const txTimestamp = new BigNumber((await DRE.ethers.provider.getBlock(tx.blockNumber)).timestamp); - - const txInfo = await DRE.ethers.provider.getTransaction(tx.transactionHash); - const txCost = new BigNumber(tx.cumulativeGasUsed.toString()).multipliedBy( - txInfo.gasPrice.toString() - ); - - return { txCost, txTimestamp }; -}; - -export const getContractsData = async ( - reserve: string, - user: string, - testEnv: TestEnv, - sender?: string -) => { - const { pool, helpersContract } = testEnv; - - const [userData, reserveData, timestamp] = await Promise.all([ - getUserData(pool, helpersContract, reserve, user, sender || user), - getReserveData(helpersContract, reserve), - timeLatest(), - ]); - - return { - reserveData, - userData, - timestamp: new BigNumber(timestamp), - }; -}; diff --git a/test/helpers/almost-equal.ts b/test/helpers/almost-equal.ts deleted file mode 100644 index e0017056..00000000 --- a/test/helpers/almost-equal.ts +++ /dev/null @@ -1,31 +0,0 @@ -import BigNumber from 'bignumber.js'; - -function almostEqualAssertion(this: any, expected: any, actual: any, message: string): 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), - `${message} expected #{act} to be almost equal #{exp}`, - `${message} expected #{act} to be different from #{exp}`, - expected.toString(), - actual.toString() - ); -} - -export function almostEqual() { - return function (chai: any, utils: any) { - chai.Assertion.overwriteMethod('almostEqual', function (original: any) { - return function (this: any, value: any, message: string) { - if (utils.flag(this, 'bignumber')) { - var expected = new BigNumber(value); - var actual = new BigNumber(this._obj); - almostEqualAssertion.apply(this, [expected, actual, message]); - } else { - original.apply(this, arguments); - } - }; - }); - }; -} diff --git a/test/helpers/make-suite.ts b/test/helpers/make-suite.ts deleted file mode 100644 index 4a75e54d..00000000 --- a/test/helpers/make-suite.ts +++ /dev/null @@ -1,191 +0,0 @@ -import { evmRevert, evmSnapshot, DRE } from '../../helpers/misc-utils'; -import { Signer } from 'ethers'; -import { - getLendingPool, - getLendingPoolAddressesProvider, - getAaveProtocolDataProvider, - getAToken, - getMintableERC20, - getLendingPoolConfiguratorProxy, - getPriceOracle, - getLendingPoolAddressesProviderRegistry, - getWETHMocked, - getWETHGateway, - getUniswapLiquiditySwapAdapter, - getUniswapRepayAdapter, - getFlashLiquidationAdapter, -} from '../../helpers/contracts-getters'; -import { eEthereumNetwork, tEthereumAddress } from '../../helpers/types'; -import { LendingPool } from '../../types/LendingPool'; -import { AaveProtocolDataProvider } from '../../types/AaveProtocolDataProvider'; -import { MintableERC20 } from '../../types/MintableERC20'; -import { AToken } from '../../types/AToken'; -import { LendingPoolConfigurator } from '../../types/LendingPoolConfigurator'; - -import chai from 'chai'; -// @ts-ignore -import bignumberChai from 'chai-bignumber'; -import { almostEqual } from './almost-equal'; -import { PriceOracle } from '../../types/PriceOracle'; -import { LendingPoolAddressesProvider } from '../../types/LendingPoolAddressesProvider'; -import { LendingPoolAddressesProviderRegistry } from '../../types/LendingPoolAddressesProviderRegistry'; -import { getEthersSigners } from '../../helpers/contracts-helpers'; -import { UniswapLiquiditySwapAdapter } from '../../types/UniswapLiquiditySwapAdapter'; -import { UniswapRepayAdapter } from '../../types/UniswapRepayAdapter'; -import { getParamPerNetwork } from '../../helpers/contracts-helpers'; -import { WETH9Mocked } from '../../types/WETH9Mocked'; -import { WETHGateway } from '../../types/WETHGateway'; -import { solidity } from 'ethereum-waffle'; -import { AaveConfig } from '../../markets/aave'; -import { FlashLiquidationAdapter } from '../../types'; -import { HardhatRuntimeEnvironment } from 'hardhat/types'; -import { usingTenderly } from '../../helpers/tenderly-utils'; - -chai.use(bignumberChai()); -chai.use(almostEqual()); -chai.use(solidity); - -export interface SignerWithAddress { - signer: Signer; - address: tEthereumAddress; -} -export interface TestEnv { - deployer: SignerWithAddress; - users: SignerWithAddress[]; - pool: LendingPool; - configurator: LendingPoolConfigurator; - oracle: PriceOracle; - helpersContract: AaveProtocolDataProvider; - weth: WETH9Mocked; - aWETH: AToken; - dai: MintableERC20; - aDai: AToken; - usdc: MintableERC20; - aave: MintableERC20; - addressesProvider: LendingPoolAddressesProvider; - uniswapLiquiditySwapAdapter: UniswapLiquiditySwapAdapter; - uniswapRepayAdapter: UniswapRepayAdapter; - registry: LendingPoolAddressesProviderRegistry; - wethGateway: WETHGateway; - flashLiquidationAdapter: FlashLiquidationAdapter; -} - -let buidlerevmSnapshotId: string = '0x1'; -const setBuidlerevmSnapshotId = (id: string) => { - buidlerevmSnapshotId = id; -}; - -const testEnv: TestEnv = { - deployer: {} as SignerWithAddress, - users: [] as SignerWithAddress[], - pool: {} as LendingPool, - configurator: {} as LendingPoolConfigurator, - helpersContract: {} as AaveProtocolDataProvider, - oracle: {} as PriceOracle, - weth: {} as WETH9Mocked, - aWETH: {} as AToken, - dai: {} as MintableERC20, - aDai: {} as AToken, - usdc: {} as MintableERC20, - aave: {} as MintableERC20, - addressesProvider: {} as LendingPoolAddressesProvider, - uniswapLiquiditySwapAdapter: {} as UniswapLiquiditySwapAdapter, - uniswapRepayAdapter: {} as UniswapRepayAdapter, - flashLiquidationAdapter: {} as FlashLiquidationAdapter, - registry: {} as LendingPoolAddressesProviderRegistry, - wethGateway: {} as WETHGateway, -} 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.configurator = await getLendingPoolConfiguratorProxy(); - - testEnv.addressesProvider = await getLendingPoolAddressesProvider(); - - if (process.env.MAINNET_FORK === 'true') { - testEnv.registry = await getLendingPoolAddressesProviderRegistry( - getParamPerNetwork(AaveConfig.ProviderRegistry, eEthereumNetwork.main) - ); - } else { - testEnv.registry = await getLendingPoolAddressesProviderRegistry(); - testEnv.oracle = await getPriceOracle(); - } - - testEnv.helpersContract = await getAaveProtocolDataProvider(); - - const allTokens = await testEnv.helpersContract.getAllATokens(); - const aDaiAddress = allTokens.find((aToken) => aToken.symbol === 'aDAI')?.tokenAddress; - - const aWEthAddress = allTokens.find((aToken) => aToken.symbol === 'aWETH')?.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; - const aaveAddress = reservesTokens.find((token) => token.symbol === 'AAVE')?.tokenAddress; - const wethAddress = reservesTokens.find((token) => token.symbol === 'WETH')?.tokenAddress; - - if (!aDaiAddress || !aWEthAddress) { - process.exit(1); - } - if (!daiAddress || !usdcAddress || !aaveAddress || !wethAddress) { - process.exit(1); - } - - testEnv.aDai = await getAToken(aDaiAddress); - testEnv.aWETH = await getAToken(aWEthAddress); - - testEnv.dai = await getMintableERC20(daiAddress); - testEnv.usdc = await getMintableERC20(usdcAddress); - testEnv.aave = await getMintableERC20(aaveAddress); - testEnv.weth = await getWETHMocked(wethAddress); - testEnv.wethGateway = await getWETHGateway(); - - testEnv.uniswapLiquiditySwapAdapter = await getUniswapLiquiditySwapAdapter(); - testEnv.uniswapRepayAdapter = await getUniswapRepayAdapter(); - testEnv.flashLiquidationAdapter = await getFlashLiquidationAdapter(); -} - -const setSnapshot = async () => { - const hre = DRE as HardhatRuntimeEnvironment; - if (usingTenderly()) { - setBuidlerevmSnapshotId((await hre.tenderlyRPC.getHead()) || '0x1'); - return; - } - setBuidlerevmSnapshotId(await evmSnapshot()); -}; - -const revertHead = async () => { - const hre = DRE as HardhatRuntimeEnvironment; - if (usingTenderly()) { - await hre.tenderlyRPC.setHead(buidlerevmSnapshotId); - return; - } - await evmRevert(buidlerevmSnapshotId); -}; - -export function makeSuite(name: string, tests: (testEnv: TestEnv) => void) { - describe(name, () => { - before(async () => { - await setSnapshot(); - }); - tests(testEnv); - after(async () => { - await revertHead(); - }); - }); -} diff --git a/test/helpers/scenario-engine.ts b/test/helpers/scenario-engine.ts deleted file mode 100644 index 92c686f4..00000000 --- a/test/helpers/scenario-engine.ts +++ /dev/null @@ -1,237 +0,0 @@ -import { TestEnv, SignerWithAddress } from './make-suite'; -import { - mint, - approve, - deposit, - borrow, - withdraw, - repay, - setUseAsCollateral, - swapBorrowRateMode, - rebalanceStableBorrowRate, - delegateBorrowAllowance, -} from './actions'; -import { RateMode } from '../../helpers/types'; - -export interface Action { - name: string; - args?: any; - expected: string; - revertMessage?: string; -} - -export interface Story { - description: string; - actions: Action[]; -} - -export interface Scenario { - title: string; - description: string; - stories: Story[]; -} - -export const executeStory = async (story: Story, testEnv: TestEnv) => { - for (const action of story.actions) { - const { users } = testEnv; - await executeAction(action, users, testEnv); - } -}; - -const executeAction = async (action: Action, users: SignerWithAddress[], testEnv: TestEnv) => { - const { reserve, user: userIndex, borrowRateMode } = action.args; - const { name, expected, revertMessage } = action; - - if (!name || name === '') { - throw 'Action name is missing'; - } - if (!reserve || reserve === '') { - throw 'Invalid reserve selected for deposit'; - } - if (!userIndex || userIndex === '') { - throw `Invalid user selected to deposit into the ${reserve} reserve`; - } - - if (!expected || expected === '') { - throw `An expected resut for action ${name} is required`; - } - - let rateMode: string = RateMode.None; - - if (borrowRateMode) { - if (borrowRateMode === 'none') { - rateMode = RateMode.None; - } else if (borrowRateMode === 'stable') { - rateMode = RateMode.Stable; - } else if (borrowRateMode === 'variable') { - rateMode = RateMode.Variable; - } else { - //random value, to test improper selection of the parameter - rateMode = '4'; - } - } - - const user = users[parseInt(userIndex)]; - - switch (name) { - case 'mint': - const { amount } = action.args; - - if (!amount || amount === '') { - throw `Invalid amount of ${reserve} to mint`; - } - - await mint(reserve, amount, user); - break; - - case 'approve': - await approve(reserve, user, testEnv); - break; - - case 'deposit': - { - const { amount, sendValue, onBehalfOf: onBehalfOfIndex } = action.args; - const onBehalfOf = onBehalfOfIndex - ? users[parseInt(onBehalfOfIndex)].address - : user.address; - - if (!amount || amount === '') { - throw `Invalid amount to deposit into the ${reserve} reserve`; - } - - await deposit( - reserve, - amount, - user, - onBehalfOf, - sendValue, - expected, - testEnv, - revertMessage - ); - } - break; - - case 'delegateBorrowAllowance': - { - const { amount, toUser: toUserIndex } = action.args; - const toUser = users[parseInt(toUserIndex, 10)].address; - if (!amount || amount === '') { - throw `Invalid amount to deposit into the ${reserve} reserve`; - } - - await delegateBorrowAllowance( - reserve, - amount, - rateMode, - user, - toUser, - expected, - testEnv, - revertMessage - ); - } - break; - - case 'withdraw': - { - const { amount } = action.args; - - if (!amount || amount === '') { - throw `Invalid amount to withdraw from the ${reserve} reserve`; - } - - await withdraw(reserve, amount, user, expected, testEnv, revertMessage); - } - break; - case 'borrow': - { - const { amount, timeTravel, onBehalfOf: onBehalfOfIndex } = action.args; - - const onBehalfOf = onBehalfOfIndex - ? users[parseInt(onBehalfOfIndex)].address - : user.address; - - if (!amount || amount === '') { - throw `Invalid amount to borrow from the ${reserve} reserve`; - } - - await borrow( - reserve, - amount, - rateMode, - user, - onBehalfOf, - timeTravel, - expected, - testEnv, - revertMessage - ); - } - break; - - case 'repay': - { - const { amount, borrowRateMode, sendValue } = action.args; - let { onBehalfOf: onBehalfOfIndex } = action.args; - - if (!amount || amount === '') { - throw `Invalid amount to repay into the ${reserve} reserve`; - } - - let userToRepayOnBehalf: SignerWithAddress; - if (!onBehalfOfIndex || onBehalfOfIndex === '') { - console.log( - 'WARNING: No onBehalfOf specified for a repay action. Defaulting to the repayer address' - ); - userToRepayOnBehalf = user; - } else { - userToRepayOnBehalf = users[parseInt(onBehalfOfIndex)]; - } - - await repay( - reserve, - amount, - rateMode, - user, - userToRepayOnBehalf, - sendValue, - expected, - testEnv, - revertMessage - ); - } - break; - - case 'setUseAsCollateral': - { - const { useAsCollateral } = action.args; - - if (!useAsCollateral || useAsCollateral === '') { - throw `A valid value for useAsCollateral needs to be set when calling setUseReserveAsCollateral on reserve ${reserve}`; - } - await setUseAsCollateral(reserve, user, useAsCollateral, expected, testEnv, revertMessage); - } - break; - - case 'swapBorrowRateMode': - await swapBorrowRateMode(reserve, user, rateMode, expected, testEnv, revertMessage); - break; - - case 'rebalanceStableBorrowRate': - { - const { target: targetIndex } = action.args; - - if (!targetIndex || targetIndex === '') { - throw `A target must be selected when trying to rebalance a stable rate`; - } - const target = users[parseInt(targetIndex)]; - - await rebalanceStableBorrowRate(reserve, user, target, expected, testEnv, revertMessage); - } - break; - - default: - throw `Invalid action requested: ${name}`; - } -}; diff --git a/test/helpers/scenarios/borrow-negatives.json b/test/helpers/scenarios/borrow-negatives.json deleted file mode 100644 index 03f4d005..00000000 --- a/test/helpers/scenarios/borrow-negatives.json +++ /dev/null @@ -1,142 +0,0 @@ -{ - "title": "LendingPool: Borrow negatives (reverts)", - "description": "Test cases for the deposit function.", - "stories": [ - { - "description": "User 0 deposits 1000 DAI, user 1 deposits 1 WETH as collateral and tries to borrow 100 DAI with rate mode NONE (revert expected)", - "actions": [ - { - "name": "mint", - "args": { - "reserve": "DAI", - "amount": "1000", - "user": "0" - }, - "expected": "success" - }, - { - "name": "approve", - "args": { - "reserve": "DAI", - "user": "0" - }, - "expected": "success" - }, - { - "name": "deposit", - "args": { - "reserve": "DAI", - "amount": "1000", - "user": "0" - }, - "expected": "success" - }, - { - "name": "mint", - "args": { - "reserve": "WETH", - "amount": "1", - "user": "1" - }, - "expected": "success" - }, - { - "name": "approve", - "args": { - "reserve": "WETH", - "user": "1" - }, - "expected": "success" - }, - { - "name": "deposit", - "args": { - "reserve": "WETH", - "amount": "1", - "user": "1" - }, - "expected": "success" - }, - { - "name": "borrow", - "args": { - "reserve": "DAI", - "amount": "100", - "borrowRateMode": "none", - "user": "1" - }, - "expected": "revert", - "revertMessage": "Invalid interest rate mode selected" - } - ] - }, - { - "description": "User 0 deposits 1000 DAI, user 1 deposits 1 WETH as collateral and tries to borrow 100 DAI with an invalid rate mode (revert expected)", - "actions": [ - { - "name": "mint", - "args": { - "reserve": "DAI", - "amount": "1000", - "user": "0" - }, - "expected": "success" - }, - { - "name": "approve", - "args": { - "reserve": "DAI", - "user": "0" - }, - "expected": "success" - }, - { - "name": "deposit", - "args": { - "reserve": "DAI", - "amount": "1000", - "user": "0" - }, - "expected": "success" - }, - { - "name": "mint", - "args": { - "reserve": "WETH", - "amount": "1", - "user": "1" - }, - "expected": "success" - }, - { - "name": "approve", - "args": { - "reserve": "WETH", - "user": "1" - }, - "expected": "success" - }, - { - "name": "deposit", - "args": { - "reserve": "WETH", - "amount": "1", - "user": "1" - }, - "expected": "success" - }, - { - "name": "borrow", - "args": { - "reserve": "DAI", - "amount": "100", - "borrowRateMode": "invalid", - "user": "1" - }, - "expected": "revert", - "revertMessage": "Invalid interest rate mode selected" - } - ] - } - ] -} diff --git a/test/helpers/scenarios/borrow-repay-stable.json b/test/helpers/scenarios/borrow-repay-stable.json deleted file mode 100644 index bdbf1aff..00000000 --- a/test/helpers/scenarios/borrow-repay-stable.json +++ /dev/null @@ -1,656 +0,0 @@ -{ - "title": "LendingPool: Borrow/repay (stable rate)", - "description": "Test cases for the borrow function, stable mode.", - "stories": [ - { - "description": "User 0 deposits 1000 DAI, user 1 deposits 1 WETH as collateral and borrows 100 DAI at stable rate", - "actions": [ - { - "name": "mint", - "args": { - "reserve": "DAI", - "amount": "1000", - "user": "0" - }, - "expected": "success" - }, - { - "name": "approve", - "args": { - "reserve": "DAI", - "user": "0" - }, - "expected": "success" - }, - { - "name": "deposit", - "args": { - "reserve": "DAI", - "amount": "1000", - "user": "0" - }, - "expected": "success" - }, - { - "name": "mint", - "args": { - "reserve": "WETH", - "amount": "1", - "user": "1" - }, - "expected": "success" - }, - { - "name": "approve", - "args": { - "reserve": "WETH", - "user": "1" - }, - "expected": "success" - }, - { - "name": "deposit", - "args": { - "reserve": "WETH", - - "amount": "1", - "user": "1" - }, - "expected": "success" - }, - { - "name": "borrow", - "args": { - "reserve": "DAI", - "amount": "100", - "borrowRateMode": "stable", - "user": "1", - "timeTravel": "365" - }, - "expected": "success" - } - ] - }, - { - "description": "User 1 tries to borrow the rest of the DAI liquidity (revert expected)", - "actions": [ - { - "name": "borrow", - "args": { - "reserve": "DAI", - "amount": "900", - "borrowRateMode": "stable", - "user": "1" - }, - "expected": "revert", - "revertMessage": "There is not enough collateral to cover a new borrow" - } - ] - }, - { - "description": "User 1 repays half of the DAI borrow after one year", - "actions": [ - { - "name": "mint", - "description": "Mint 10 DAI to cover the interest", - "args": { - "reserve": "DAI", - "amount": "10", - "user": "1" - }, - "expected": "success" - }, - { - "name": "approve", - "args": { - "reserve": "DAI", - "user": "1" - }, - "expected": "success" - }, - { - "name": "repay", - "args": { - "reserve": "DAI", - "amount": "50", - "user": "1", - "onBehalfOf": "1", - "borrowRateMode": "stable" - }, - "expected": "success" - } - ] - }, - { - "description": "User 1 repays the rest of the DAI borrow after one year", - "actions": [ - { - "name": "mint", - "description": "Mint 15 DAI to cover the interest", - "args": { - "reserve": "DAI", - "amount": "15", - "user": "1" - }, - "expected": "success" - }, - { - "name": "approve", - "args": { - "reserve": "DAI", - "user": "1" - }, - "expected": "success" - }, - { - "name": "repay", - "args": { - "reserve": "DAI", - "amount": "-1", - "user": "1", - "onBehalfOf": "1", - "borrowRateMode": "stable" - }, - "expected": "success" - } - ] - }, - { - "description": "User 0 withdraws the deposited DAI plus interest", - "actions": [ - { - "name": "withdraw", - "args": { - "reserve": "DAI", - "amount": "-1", - "user": "0" - }, - "expected": "success" - } - ] - }, - { - "description": "User 1 deposits 1000 DAI, user 2 tries to borrow 1000 DAI at a stable rate without any collateral (revert expected) User 1 withdrawws", - "actions": [ - { - "name": "mint", - "args": { - "reserve": "DAI", - "amount": "1000", - "user": "1" - }, - "expected": "success" - }, - { - "name": "approve", - "args": { - "reserve": "DAI", - "user": "1" - }, - "expected": "success" - }, - { - "name": "deposit", - "args": { - "reserve": "DAI", - "amount": "1000", - "user": "1" - }, - "expected": "success" - }, - { - "name": "borrow", - "args": { - "reserve": "DAI", - "amount": "1000", - "borrowRateMode": "stable", - "user": "2" - }, - "expected": "revert", - "revertMessage": "The collateral balance is 0" - }, - { - "name": "withdraw", - "args": { - "reserve": "DAI", - "amount": "1000", - "user": "1" - }, - "expected": "success" - } - ] - }, - { - "description": "User 0 deposits 1000 DAI, user 1,2,3,4 deposit 1 WETH each and borrow 100 DAI at stable rate. Everything is repaid, user 0 withdraws", - "actions": [ - { - "name": "mint", - "args": { - "reserve": "DAI", - "amount": "1000", - "user": "0" - }, - "expected": "success" - }, - { - "name": "approve", - "args": { - "reserve": "DAI", - "user": "0" - }, - "expected": "success" - }, - { - "name": "deposit", - "args": { - "reserve": "DAI", - "amount": "1000", - "user": "0" - }, - "expected": "success" - }, - { - "name": "mint", - "args": { - "reserve": "WETH", - "amount": "1", - "user": "1" - }, - "expected": "success" - }, - { - "name": "approve", - "args": { - "reserve": "WETH", - "user": "1" - }, - "expected": "success" - }, - { - "name": "deposit", - "args": { - "reserve": "WETH", - "amount": "1", - "user": "1" - }, - "expected": "success" - }, - { - "name": "borrow", - "args": { - "reserve": "DAI", - "amount": "100", - "borrowRateMode": "stable", - "user": "1", - "timeTravel": "365" - }, - "expected": "success" - }, - { - "name": "mint", - "args": { - "reserve": "WETH", - "amount": "1", - "user": "2" - }, - "expected": "success" - }, - { - "name": "approve", - "args": { - "reserve": "WETH", - "user": "2" - }, - "expected": "success" - }, - { - "name": "deposit", - "args": { - "reserve": "WETH", - "amount": "1", - "user": "2" - }, - "expected": "success" - }, - { - "name": "borrow", - "args": { - "reserve": "DAI", - "amount": "100", - "borrowRateMode": "stable", - "user": "2", - "timeTravel": "365" - }, - "expected": "success" - }, - { - "name": "mint", - "args": { - "reserve": "WETH", - "amount": "1", - "user": "3" - }, - "expected": "success" - }, - { - "name": "approve", - "args": { - "reserve": "WETH", - "user": "3" - }, - "expected": "success" - }, - { - "name": "deposit", - "args": { - "reserve": "WETH", - "amount": "1", - "user": "3" - }, - "expected": "success" - }, - { - "name": "borrow", - "args": { - "reserve": "DAI", - "amount": "100", - "borrowRateMode": "stable", - "user": "3", - "timeTravel": "365" - }, - "expected": "success" - }, - { - "name": "mint", - "args": { - "reserve": "WETH", - "amount": "1", - "user": "4" - }, - "expected": "success" - }, - { - "name": "approve", - "args": { - "reserve": "WETH", - "user": "4" - }, - "expected": "success" - }, - { - "name": "deposit", - "args": { - "reserve": "WETH", - "amount": "1", - "user": "4" - }, - "expected": "success" - }, - { - "name": "borrow", - "args": { - "reserve": "DAI", - "amount": "100", - "borrowRateMode": "stable", - "user": "4", - "timeTravel": "365" - }, - "expected": "success" - }, - { - "name": "mint", - "description": "Mint 15 DAI to cover the interest", - "args": { - "reserve": "DAI", - "amount": "15", - "user": "1" - }, - "expected": "success" - }, - { - "name": "approve", - "args": { - "reserve": "DAI", - "user": "1" - }, - "expected": "success" - }, - { - "name": "repay", - "args": { - "reserve": "DAI", - "amount": "-1", - "user": "1", - "onBehalfOf": "1", - "borrowRateMode": "stable" - }, - "expected": "success" - }, - { - "name": "mint", - "description": "Mint 20 DAI to cover the interest", - "args": { - "reserve": "DAI", - "amount": "20", - "user": "2" - }, - "expected": "success" - }, - { - "name": "approve", - "args": { - "reserve": "DAI", - "user": "2" - }, - "expected": "success" - }, - { - "name": "repay", - "args": { - "reserve": "DAI", - "amount": "-1", - "user": "2", - "onBehalfOf": "2", - "borrowRateMode": "stable" - }, - "expected": "success" - }, - { - "name": "mint", - "description": "Mint 30 DAI to cover the interest", - "args": { - "reserve": "DAI", - "amount": "30", - "user": "3" - }, - "expected": "success" - }, - { - "name": "approve", - "args": { - "reserve": "DAI", - "user": "3" - }, - "expected": "success" - }, - { - "name": "repay", - "args": { - "reserve": "DAI", - "amount": "-1", - "user": "3", - "onBehalfOf": "3", - "borrowRateMode": "stable" - }, - "expected": "success" - }, - { - "name": "mint", - "description": "Mint 30 DAI to cover the interest", - "args": { - "reserve": "DAI", - "amount": "30", - "user": "4" - }, - "expected": "success" - }, - { - "name": "approve", - "args": { - "reserve": "DAI", - "user": "4" - }, - "expected": "success" - }, - { - "name": "repay", - "args": { - "reserve": "DAI", - "amount": "-1", - "user": "4", - "onBehalfOf": "4", - "borrowRateMode": "stable" - }, - "expected": "success" - }, - { - "name": "withdraw", - "args": { - "reserve": "DAI", - "amount": "-1", - "user": "0" - }, - "expected": "success" - } - ] - }, - { - "description": "User 0 deposits 1000 DAI, user 1 deposits 2 WETH and borrow 100 DAI at stable rate first, then 100 DAI at variable rate, repays everything. User 0 withdraws", - "actions": [ - { - "name": "mint", - "args": { - "reserve": "DAI", - "amount": "1000", - "user": "0" - }, - "expected": "success" - }, - { - "name": "approve", - "args": { - "reserve": "DAI", - "user": "0" - }, - "expected": "success" - }, - { - "name": "deposit", - "args": { - "reserve": "DAI", - "amount": "1000", - "user": "0" - }, - "expected": "success" - }, - { - "name": "mint", - "args": { - "reserve": "WETH", - "amount": "2", - "user": "1" - }, - "expected": "success" - }, - { - "name": "approve", - "args": { - "reserve": "WETH", - "user": "1" - }, - "expected": "success" - }, - { - "name": "deposit", - "args": { - "reserve": "WETH", - "amount": "2", - "user": "1" - }, - "expected": "success" - }, - { - "name": "borrow", - "args": { - "reserve": "DAI", - "amount": "100", - "borrowRateMode": "stable", - "user": "1", - "timeTravel": "365" - }, - "expected": "success" - }, - { - "name": "borrow", - "args": { - "reserve": "DAI", - "amount": "100", - "borrowRateMode": "variable", - "user": "1", - "timeTravel": "365" - }, - "expected": "success" - }, - { - "name": "mint", - "description": "Mint 50 DAI to cover the interest", - "args": { - "reserve": "DAI", - "amount": "50", - "user": "1" - }, - "expected": "success" - }, - { - "name": "approve", - "args": { - "reserve": "DAI", - "user": "1" - }, - "expected": "success" - }, - { - "name": "repay", - "args": { - "reserve": "DAI", - "amount": "-1", - "user": "1", - "onBehalfOf": "1", - "borrowRateMode": "stable" - }, - "expected": "success" - }, - { - "name": "repay", - "args": { - "reserve": "DAI", - "amount": "-1", - "user": "1", - "onBehalfOf": "1", - "borrowRateMode": "variable" - }, - "expected": "success" - }, - { - "name": "withdraw", - "args": { - "reserve": "DAI", - "amount": "-1", - "user": "0" - }, - "expected": "success" - } - ] - } - ] -} diff --git a/test/helpers/scenarios/borrow-repay-variable.json b/test/helpers/scenarios/borrow-repay-variable.json deleted file mode 100644 index 3c4ce368..00000000 --- a/test/helpers/scenarios/borrow-repay-variable.json +++ /dev/null @@ -1,945 +0,0 @@ -{ - "title": "LendingPool: Borrow/repay (variable rate)", - "description": "Test cases for the borrow function, variable mode.", - "stories": [ - { - "description": "User 2 deposits 1 DAI to account for rounding errors", - "actions": [ - { - "name": "mint", - "args": { - "reserve": "DAI", - "amount": "1", - "user": "2" - }, - "expected": "success" - }, - { - "name": "approve", - "args": { - "reserve": "DAI", - "user": "2" - }, - "expected": "success" - }, - { - "name": "deposit", - "args": { - "reserve": "DAI", - "amount": "1", - "user": "2" - }, - "expected": "success" - } - ] - }, - { - "description": "User 0 deposits 1000 DAI, user 1 deposits 1 WETH as collateral and borrows 100 DAI at variable rate", - "actions": [ - { - "name": "mint", - "args": { - "reserve": "DAI", - "amount": "1000", - "user": "0" - }, - "expected": "success" - }, - { - "name": "approve", - "args": { - "reserve": "DAI", - "user": "0" - }, - "expected": "success" - }, - { - "name": "deposit", - "args": { - "reserve": "DAI", - "amount": "1000", - "user": "0" - }, - "expected": "success" - }, - { - "name": "mint", - "args": { - "reserve": "WETH", - "amount": "1", - "user": "1" - }, - "expected": "success" - }, - { - "name": "approve", - "args": { - "reserve": "WETH", - "user": "1" - }, - "expected": "success" - }, - { - "name": "deposit", - "args": { - "reserve": "WETH", - "amount": "1", - "user": "1" - }, - "expected": "success" - }, - { - "name": "borrow", - "args": { - "reserve": "DAI", - "amount": "100", - "borrowRateMode": "variable", - "user": "1", - "timeTravel": "365" - }, - "expected": "success" - } - ] - }, - { - "description": "User 1 tries to borrow the rest of the DAI liquidity (revert expected)", - "actions": [ - { - "name": "borrow", - "args": { - "reserve": "DAI", - "amount": "900", - "borrowRateMode": "variable", - "user": "1" - }, - "expected": "revert", - "revertMessage": "There is not enough collateral to cover a new borrow" - } - ] - }, - { - "description": "User 1 tries to repay 0 DAI (revert expected)", - "actions": [ - { - "name": "repay", - "args": { - "reserve": "DAI", - "amount": "0", - "user": "1", - "onBehalfOf": "1" - }, - "expected": "revert", - "revertMessage": "Amount must be greater than 0" - } - ] - }, - { - "description": "User 1 repays a small amount of DAI, enough to cover a small part of the interest", - "actions": [ - { - "name": "approve", - "args": { - "reserve": "DAI", - "user": "1" - }, - "expected": "success" - }, - { - "name": "repay", - "args": { - "reserve": "DAI", - "amount": "1.25", - "user": "1", - "onBehalfOf": "1", - "borrowRateMode": "variable" - }, - "expected": "success" - } - ] - }, - { - "description": "User 1 repays the DAI borrow after one year", - "actions": [ - { - "name": "mint", - "description": "Mint 10 DAI to cover the interest", - "args": { - "reserve": "DAI", - "amount": "10", - "user": "1" - }, - "expected": "success" - }, - { - "name": "repay", - "args": { - "reserve": "DAI", - "amount": "-1", - "user": "1", - "onBehalfOf": "1", - "borrowRateMode": "variable" - }, - "expected": "success" - } - ] - }, - { - "description": "User 0 withdraws the deposited DAI plus interest", - "actions": [ - { - "name": "withdraw", - "args": { - "reserve": "DAI", - "amount": "-1", - "user": "0" - }, - "expected": "success" - } - ] - }, - { - "description": "User 1 withdraws the collateral", - "actions": [ - { - "name": "withdraw", - "args": { - "reserve": "WETH", - "amount": "-1", - "user": "1" - }, - "expected": "success" - } - ] - }, - { - "description": "User 2 deposits a small amount of WETH to account for rounding errors", - "actions": [ - { - "name": "mint", - "args": { - "reserve": "WETH", - "amount": "0.001", - "user": "2" - }, - "expected": "success" - }, - { - "name": "approve", - "args": { - "reserve": "WETH", - "user": "2" - }, - "expected": "success" - }, - { - "name": "deposit", - "args": { - "reserve": "WETH", - "amount": "0.001", - "user": "2" - }, - "expected": "success" - } - ] - }, - { - "description": "User 0 deposits 1 WETH, user 1 deposits 100 LINK as collateral and borrows 0.5 ETH at variable rate", - "actions": [ - { - "name": "mint", - "args": { - "reserve": "WETH", - "amount": "1", - "user": "0" - }, - "expected": "success" - }, - { - "name": "approve", - "args": { - "reserve": "WETH", - "user": "0" - }, - "expected": "success" - }, - { - "name": "deposit", - "args": { - "reserve": "WETH", - "amount": "1", - "user": "0" - }, - "expected": "success" - }, - { - "name": "mint", - "args": { - "reserve": "LINK", - "amount": "100", - "user": "1" - }, - "expected": "success" - }, - { - "name": "approve", - "args": { - "reserve": "LINK", - "user": "1" - }, - "expected": "success" - }, - - { - "name": "deposit", - "args": { - "reserve": "LINK", - "amount": "100", - "user": "1" - }, - "expected": "success" - }, - { - "name": "borrow", - "args": { - "reserve": "WETH", - "amount": "0.5", - "borrowRateMode": "variable", - "user": "1", - "timeTravel": "365" - }, - "expected": "success" - } - ] - }, - { - "description": "User 1 tries to repay 0 ETH", - "actions": [ - { - "name": "repay", - "args": { - "reserve": "WETH", - "amount": "0", - "user": "1", - "onBehalfOf": "1", - "borrowRateMode": "variable" - }, - "expected": "revert", - "revertMessage": "Amount must be greater than 0" - } - ] - }, - { - "description": "User 2 tries to repay everything on behalf of user 1 using uint(-1) (revert expected)", - "actions": [ - { - "name": "repay", - "args": { - "reserve": "WETH", - "amount": "-1", - "user": "2", - "borrowRateMode": "variable", - "onBehalfOf": "1" - }, - "expected": "revert", - "revertMessage": "To repay on behalf of an user an explicit amount to repay is needed" - } - ] - }, - { - "description": "User 3 repays a small amount of WETH on behalf of user 1", - "actions": [ - { - "name": "mint", - "args": { - "reserve": "WETH", - "amount": "1", - "user": "3" - }, - "expected": "success" - }, - { - "name": "approve", - "args": { - "reserve": "WETH", - "user": "3" - }, - "expected": "success" - }, - { - "name": "repay", - "args": { - "reserve": "WETH", - "amount": "0.2", - "user": "3", - "borrowRateMode": "variable", - "onBehalfOf": "1" - }, - "expected": "success" - } - ] - }, - { - "description": "User 1 repays the WETH borrow after one year", - "actions": [ - { - "name": "mint", - "args": { - "reserve": "WETH", - "amount": "1", - "user": "2" - }, - "expected": "success" - }, - { - "name": "approve", - "args": { - "reserve": "WETH", - "user": "2" - }, - "expected": "success" - }, - { - "name": "repay", - "args": { - "reserve": "WETH", - "amount": "-1", - "borrowRateMode": "variable", - "user": "1", - "onBehalfOf": "1" - }, - "expected": "success" - } - ] - }, - { - "description": "User 0 withdraws the deposited WETH plus interest", - "actions": [ - { - "name": "withdraw", - "args": { - "reserve": "WETH", - "amount": "-1", - "user": "0" - }, - "expected": "success" - } - ] - }, - { - "description": "User 1 withdraws the collateral", - "actions": [ - { - "name": "withdraw", - "args": { - "reserve": "LINK", - "amount": "-1", - "user": "1" - }, - "expected": "success" - } - ] - }, - - { - "description": "User 2 deposits 1 USDC to account for rounding errors", - "actions": [ - { - "name": "mint", - "args": { - "reserve": "USDC", - "amount": "1", - "user": "2" - }, - "expected": "success" - }, - { - "name": "approve", - "args": { - "reserve": "USDC", - "user": "2" - }, - "expected": "success" - }, - { - "name": "deposit", - "args": { - "reserve": "USDC", - "amount": "1", - "user": "2" - }, - "expected": "success" - } - ] - }, - { - "description": "User 0 deposits 1000 USDC, user 1 deposits 1 WETH as collateral and borrows 100 USDC at variable rate", - "actions": [ - { - "name": "mint", - "args": { - "reserve": "USDC", - "amount": "1000", - "user": "0" - }, - "expected": "success" - }, - { - "name": "approve", - "args": { - "reserve": "USDC", - "user": "0" - }, - "expected": "success" - }, - { - "name": "deposit", - "args": { - "reserve": "USDC", - "amount": "1000", - "user": "0" - }, - "expected": "success" - }, - { - "name": "mint", - "args": { - "reserve": "WETH", - "amount": "1", - "user": "1" - }, - "expected": "success" - }, - { - "name": "approve", - "args": { - "reserve": "WETH", - "user": "1" - }, - "expected": "success" - }, - { - "name": "deposit", - "args": { - "reserve": "WETH", - "amount": "1", - "user": "1" - }, - "expected": "success" - }, - { - "name": "borrow", - "args": { - "reserve": "USDC", - "amount": "100", - "borrowRateMode": "variable", - "user": "1", - "timeTravel": "365" - }, - "expected": "success" - } - ] - }, - { - "description": "User 1 tries to borrow the rest of the USDC liquidity (revert expected)", - "actions": [ - { - "name": "borrow", - "args": { - "reserve": "USDC", - "amount": "900", - "borrowRateMode": "variable", - "user": "1" - }, - "expected": "revert", - "revertMessage": "There is not enough collateral to cover a new borrow" - } - ] - }, - { - "description": "User 1 repays the USDC borrow after one year", - "actions": [ - { - "name": "mint", - "description": "Mint 10 USDC to cover the interest", - "args": { - "reserve": "USDC", - "amount": "10", - "user": "1" - }, - "expected": "success" - }, - { - "name": "approve", - "args": { - "reserve": "USDC", - "user": "1" - }, - "expected": "success" - }, - { - "name": "repay", - "args": { - "reserve": "USDC", - "amount": "-1", - "user": "1", - "onBehalfOf": "1", - "borrowRateMode": "variable" - }, - "expected": "success" - } - ] - }, - { - "description": "User 0 withdraws the deposited USDC plus interest", - "actions": [ - { - "name": "withdraw", - "args": { - "reserve": "USDC", - "amount": "-1", - "user": "0" - }, - "expected": "success" - } - ] - }, - { - "description": "User 1 withdraws the collateral", - "actions": [ - { - "name": "withdraw", - "args": { - "reserve": "WETH", - "amount": "-1", - "user": "1" - }, - "expected": "success" - } - ] - }, - { - "description": "User 1 deposits 1000 DAI, user 3 tries to borrow 1000 DAI without any collateral (revert expected)", - "actions": [ - { - "name": "mint", - "args": { - "reserve": "DAI", - "amount": "1000", - "user": "1" - }, - "expected": "success" - }, - { - "name": "approve", - "args": { - "reserve": "DAI", - "user": "1" - }, - "expected": "success" - }, - { - "name": "deposit", - "args": { - "reserve": "DAI", - "amount": "1000", - "user": "1" - }, - "expected": "success" - }, - { - "name": "borrow", - "args": { - "reserve": "DAI", - "amount": "1000", - "borrowRateMode": "variable", - "user": "3" - }, - "expected": "revert", - "revertMessage": "The collateral balance is 0" - } - ] - }, - { - "description": "user 3 deposits 0.1 ETH collateral to borrow 100 DAI; 0.1 ETH is not enough to borrow 100 DAI (revert expected)", - "actions": [ - { - "name": "mint", - "args": { - "reserve": "WETH", - "amount": "0.1", - "user": "1" - }, - "expected": "success" - }, - { - "name": "approve", - "args": { - "reserve": "WETH", - "user": "1" - }, - "expected": "success" - }, - { - "name": "deposit", - "args": { - "reserve": "WETH", - "amount": "0.1", - "user": "3" - }, - "expected": "success" - }, - { - "name": "borrow", - "args": { - "reserve": "DAI", - "amount": "100", - "borrowRateMode": "variable", - "user": "3" - }, - "expected": "revert", - "revertMessage": "There is not enough collateral to cover a new borrow" - } - ] - }, - { - "description": "user 3 withdraws the 0.1 ETH", - "actions": [ - { - "name": "withdraw", - "args": { - "reserve": "WETH", - "amount": "-1", - "user": "3" - }, - "expected": "success" - } - ] - }, - { - "description": "User 1 deposits 1000 USDC, user 3 tries to borrow 1000 USDC without any collateral (revert expected)", - "actions": [ - { - "name": "mint", - "args": { - "reserve": "USDC", - "amount": "1000", - "user": "1" - }, - "expected": "success" - }, - { - "name": "approve", - "args": { - "reserve": "USDC", - "user": "1" - }, - "expected": "success" - }, - { - "name": "deposit", - "args": { - "reserve": "USDC", - "amount": "1000", - "user": "1" - }, - "expected": "success" - }, - { - "name": "borrow", - "args": { - "reserve": "USDC", - "amount": "1000", - "borrowRateMode": "variable", - "user": "3" - }, - "expected": "revert", - "revertMessage": "The collateral balance is 0" - } - ] - }, - { - "description": "user 3 deposits 0.1 ETH collateral to borrow 100 USDC; 0.1 ETH is not enough to borrow 100 USDC (revert expected)", - "actions": [ - { - "name": "mint", - "args": { - "reserve": "WETH", - "amount": "1", - "user": "3" - }, - "expected": "success" - }, - { - "name": "approve", - "args": { - "reserve": "WETH", - "user": "1" - }, - "expected": "success" - }, - { - "name": "deposit", - "args": { - "reserve": "WETH", - "amount": "0.1", - "user": "3" - }, - "expected": "success" - }, - { - "name": "borrow", - "args": { - "reserve": "USDC", - "amount": "100", - "borrowRateMode": "variable", - "user": "3" - }, - "expected": "revert", - "revertMessage": "There is not enough collateral to cover a new borrow" - } - ] - }, - { - "description": "user 3 withdraws the 0.1 ETH", - "actions": [ - { - "name": "withdraw", - "args": { - "reserve": "WETH", - "amount": "-1", - "user": "3" - }, - "expected": "success" - } - ] - }, - { - "description": "User 0 deposits 1000 DAI, user 6 deposits 2 WETH and borrow 100 DAI at variable rate first, then 100 DAI at stable rate, repays everything. User 0 withdraws", - "actions": [ - { - "name": "mint", - "args": { - "reserve": "DAI", - "amount": "1000", - "user": "0" - }, - "expected": "success" - }, - { - "name": "approve", - "args": { - "reserve": "DAI", - "user": "0" - }, - "expected": "success" - }, - { - "name": "deposit", - "args": { - "reserve": "DAI", - "amount": "1000", - "user": "0" - }, - "expected": "success" - }, - { - "name": "mint", - "args": { - "reserve": "WETH", - "amount": "2", - "user": "6" - }, - "expected": "success" - }, - { - "name": "approve", - "args": { - "reserve": "WETH", - "user": "6" - }, - "expected": "success" - }, - { - "name": "deposit", - "args": { - "reserve": "WETH", - "amount": "2", - "user": "6" - }, - "expected": "success" - }, - { - "name": "borrow", - "args": { - "reserve": "DAI", - "amount": "100", - "borrowRateMode": "variable", - "user": "6", - "timeTravel": "365" - }, - "expected": "success" - }, - { - "name": "borrow", - "args": { - "reserve": "DAI", - "amount": "100", - "borrowRateMode": "stable", - "user": "6", - "timeTravel": "365" - }, - "expected": "success" - }, - { - "name": "mint", - "description": "Mint 50 DAI to cover the interest", - "args": { - "reserve": "DAI", - "amount": "50", - "user": "6" - }, - "expected": "success" - }, - { - "name": "approve", - "args": { - "reserve": "DAI", - "user": "6" - }, - "expected": "success" - }, - { - "name": "repay", - "args": { - "reserve": "DAI", - "amount": "-1", - "user": "6", - "onBehalfOf": "6", - "borrowRateMode": "stable" - }, - "expected": "success" - }, - { - "name": "repay", - "args": { - "reserve": "DAI", - "amount": "-1", - "user": "6", - "onBehalfOf": "6", - "borrowRateMode": "variable" - }, - "expected": "success" - }, - { - "name": "withdraw", - "args": { - "reserve": "DAI", - "amount": "-1", - "user": "0" - }, - "expected": "success" - } - ] - } - ] -} diff --git a/test/helpers/scenarios/credit-delegation.json b/test/helpers/scenarios/credit-delegation.json deleted file mode 100644 index 2efabeb1..00000000 --- a/test/helpers/scenarios/credit-delegation.json +++ /dev/null @@ -1,157 +0,0 @@ -{ - "title": "LendingPool: credit delegation", - "description": "Test cases for the credit delegation related functions.", - "stories": [ - { - "description": "User 3 deposits 1000 WETH. User 0 deposits 1000 DAI, user 0 delegates borrowing of 1 WETH on variable to user 4, user 4 borrows 1 WETH variable on behalf of user 0", - "actions": [ - { - "name": "mint", - "args": { - "reserve": "WETH", - "amount": "1000", - "user": "3" - }, - "expected": "success" - }, - { - "name": "approve", - "args": { - "reserve": "WETH", - "user": "3" - }, - "expected": "success" - }, - { - "name": "deposit", - "args": { - "reserve": "WETH", - "amount": "1000", - "user": "3" - }, - "expected": "success" - }, - { - "name": "mint", - "args": { - "reserve": "DAI", - "amount": "1000", - "user": "0" - }, - "expected": "success" - }, - { - "name": "approve", - "args": { - "reserve": "DAI", - "user": "0" - }, - "expected": "success" - }, - { - "name": "deposit", - "args": { - "reserve": "DAI", - "amount": "1000", - "user": "0" - }, - "expected": "success" - }, - { - "name": "delegateBorrowAllowance", - "args": { - "reserve": "WETH", - "amount": "2", - "user": "0", - "borrowRateMode": "variable", - "toUser": "4" - }, - "expected": "success" - }, - { - "name": "borrow", - "args": { - "reserve": "WETH", - "amount": "1", - "user": "4", - "onBehalfOf": "0", - "borrowRateMode": "variable" - }, - "expected": "success" - } - ] - }, - { - "description": "User 4 trying to borrow 1 WETH stable on behalf of user 0, revert expected", - "actions": [ - { - "name": "borrow", - "args": { - "reserve": "WETH", - "amount": "1", - "user": "4", - "onBehalfOf": "0", - "borrowRateMode": "stable" - }, - "expected": "revert", - "revertMessage": "59" - } - ] - }, - { - "description": "User 0 delegates borrowing of 1 WETH to user 4, user 4 borrows 3 WETH variable on behalf of user 0, revert expected", - "actions": [ - { - "name": "delegateBorrowAllowance", - "args": { - "reserve": "WETH", - "amount": "1", - "user": "0", - "borrowRateMode": "variable", - "toUser": "4" - }, - "expected": "success" - }, - { - "name": "borrow", - "args": { - "reserve": "WETH", - "amount": "3", - "user": "4", - "onBehalfOf": "0", - "borrowRateMode": "variable" - }, - "expected": "revert", - "revertMessage": "59" - } - ] - }, - { - "description": "User 0 delegates borrowing of 1 WETH on stable to user 2, user 2 borrows 1 WETH stable on behalf of user 0", - "actions": [ - { - "name": "delegateBorrowAllowance", - "args": { - "reserve": "WETH", - "amount": "1", - "user": "0", - "borrowRateMode": "stable", - "toUser": "2" - }, - "expected": "success" - }, - { - "name": "borrow", - "args": { - "reserve": "WETH", - "amount": "1", - "user": "2", - "onBehalfOf": "0", - "borrowRateMode": "stable" - }, - "expected": "success" - } - ] - } - ] -} diff --git a/test/helpers/scenarios/deposit.json b/test/helpers/scenarios/deposit.json deleted file mode 100644 index b4b73879..00000000 --- a/test/helpers/scenarios/deposit.json +++ /dev/null @@ -1,266 +0,0 @@ -{ - "title": "LendingPool: Deposit", - "description": "Test cases for the deposit function.", - "stories": [ - { - "description": "User 0 Deposits 1000 DAI in an empty reserve", - "actions": [ - { - "name": "mint", - "args": { - "reserve": "DAI", - "amount": "1000", - "user": "0" - }, - "expected": "success" - }, - { - "name": "approve", - "args": { - "reserve": "DAI", - "user": "0" - }, - "expected": "success" - }, - { - "name": "deposit", - "args": { - "reserve": "DAI", - "amount": "1000", - "user": "0" - }, - "expected": "success" - } - ] - }, - { - "description": "User 1 deposits 1000 DAI after user 0", - "actions": [ - { - "name": "mint", - "args": { - "reserve": "DAI", - "amount": "1000", - "user": "1" - }, - "expected": "success" - }, - { - "name": "approve", - "args": { - "reserve": "DAI", - "user": "1" - }, - "expected": "success" - }, - { - "name": "deposit", - "args": { - "reserve": "DAI", - "amount": "1000", - "user": "1" - }, - "expected": "success" - } - ] - }, - { - "description": "User 0 deposits 1000 USDC in an empty reserve", - "actions": [ - { - "name": "mint", - "args": { - "reserve": "USDC", - "amount": "1000", - "user": "0" - }, - "expected": "success" - }, - { - "name": "approve", - "args": { - "reserve": "USDC", - "user": "0" - }, - "expected": "success" - }, - { - "name": "deposit", - "args": { - "reserve": "USDC", - "amount": "1000", - "user": "0" - }, - "expected": "success" - } - ] - }, - { - "description": "User 1 deposits 1000 USDC after user 0", - "actions": [ - { - "name": "mint", - "args": { - "reserve": "USDC", - "amount": "1000", - "user": "1" - }, - "expected": "success" - }, - { - "name": "approve", - "args": { - "reserve": "USDC", - "user": "1" - }, - "expected": "success" - }, - { - "name": "deposit", - "args": { - "reserve": "USDC", - "amount": "1000", - "user": "1" - }, - "expected": "success" - } - ] - }, - { - "description": "User 0 deposits 1 WETH in an empty reserve", - "actions": [ - { - "name": "mint", - "args": { - "reserve": "WETH", - "amount": "1", - "user": "0" - }, - "expected": "success" - }, - { - "name": "approve", - "args": { - "reserve": "WETH", - "user": "0" - }, - "expected": "success" - }, - { - "name": "deposit", - "args": { - "reserve": "WETH", - "amount": "1", - "user": "0" - }, - "expected": "success" - } - ] - }, - { - "description": "User 1 deposits 1 WETH after user 0", - "actions": [ - { - "name": "mint", - "args": { - "reserve": "WETH", - "amount": "1", - "user": "1" - }, - "expected": "success" - }, - - { - "name": "approve", - "args": { - "reserve": "WETH", - "user": "1" - }, - "expected": "success" - }, - { - "name": "deposit", - "args": { - "reserve": "WETH", - "amount": "1", - "user": "1" - }, - "expected": "success" - } - ] - }, - { - "description": "User 1 deposits 0 WETH (revert expected)", - "actions": [ - { - "name": "mint", - "args": { - "reserve": "WETH", - "amount": "1", - "user": "0" - }, - "expected": "success" - }, - { - "name": "deposit", - "args": { - "reserve": "WETH", - "amount": "0", - "user": "1" - }, - "expected": "revert", - "revertMessage": "Amount must be greater than 0" - } - ] - }, - { - "description": "User 1 deposits 0 DAI", - "actions": [ - { - "name": "deposit", - "args": { - "reserve": "DAI", - "amount": "0", - "user": "1" - }, - "expected": "revert", - "revertMessage": "Amount must be greater than 0" - } - ] - }, - { - "description": "User 1 deposits 100 DAI on behalf of user 2, user 2 tries to borrow 0.1 WETH", - "actions": [ - { - "name": "mint", - "args": { - "reserve": "DAI", - "amount": "100", - "user": "1" - }, - "expected": "success" - }, - { - "name": "deposit", - "args": { - "reserve": "DAI", - "amount": "100", - "user": "1", - "onBehalfOf": "2" - }, - "expected": "success" - }, - { - "name": "borrow", - "args": { - "reserve": "WETH", - "amount": "0.1", - "borrowRateMode": "variable", - "user": "2" - }, - "expected": "success" - } - ] - } - ] -} diff --git a/test/helpers/scenarios/rebalance-stable-rate.json b/test/helpers/scenarios/rebalance-stable-rate.json deleted file mode 100644 index 79c224f8..00000000 --- a/test/helpers/scenarios/rebalance-stable-rate.json +++ /dev/null @@ -1,198 +0,0 @@ -{ - "title": "LendingPool: Rebalance stable rate", - "description": "Test cases for the rebalanceStableBorrowRate() function.", - "stories": [ - { - "description": "User 0 tries to rebalance user 1 who has no borrows in progress (revert expected)", - "actions": [ - { - "name": "rebalanceStableBorrowRate", - "args": { - "reserve": "USDC", - "user": "0", - "target": "1" - }, - "expected": "revert", - "revertMessage": "User does not have any stable rate loan for this reserve" - } - ] - }, - { - "description": "User 0 deposits 1000 USDC, user 1 deposits 7 WETH, borrows 250 USDC at a stable rate, user 0 rebalances user 1 (revert expected)", - "actions": [ - { - "name": "mint", - "args": { - "reserve": "USDC", - "amount": "1000", - "user": "0" - }, - "expected": "success" - }, - { - "name": "approve", - "args": { - "reserve": "USDC", - "user": "0" - }, - "expected": "success" - }, - { - "name": "deposit", - "args": { - "reserve": "USDC", - "amount": "1000", - "user": "0" - }, - "expected": "success" - }, - { - "name": "mint", - "args": { - "reserve": "WETH", - "amount": "7", - "user": "1" - }, - "expected": "success" - }, - { - "name": "approve", - "args": { - "reserve": "WETH", - "user": "1" - }, - "expected": "success" - }, - { - "name": "deposit", - "args": { - "reserve": "WETH", - "amount": "7", - "user": "1" - }, - "expected": "success" - }, - { - "name": "borrow", - "args": { - "reserve": "USDC", - "amount": "250", - "borrowRateMode": "stable", - "user": "1" - }, - "expected": "success" - }, - { - "name": "rebalanceStableBorrowRate", - "args": { - "reserve": "USDC", - "user": "0", - "target": "1" - }, - "expected": "revert", - "revertMessage": "The user borrow is variable and cannot be rebalanced" - } - ] - }, - { - "description": "User 1 borrows another 200 at variable, user 0 tries to rebalance but the conditions are not met (revert expected)", - "actions": [ - { - "name": "borrow", - "args": { - "reserve": "USDC", - "amount": "200", - "borrowRateMode": "variable", - "user": "1" - }, - "expected": "success" - }, - { - "name": "rebalanceStableBorrowRate", - "args": { - "reserve": "USDC", - "user": "0", - "target": "1" - }, - "expected": "revert", - "revertMessage": "Interest rate rebalance conditions were not met" - } - ] - }, - { - "description": "User 1 borrows another 200 at variable, user 0 tries to rebalance but the conditions are not met (revert expected)", - "actions": [ - { - "name": "borrow", - "args": { - "reserve": "USDC", - "amount": "200", - "borrowRateMode": "variable", - "user": "1" - }, - "expected": "success" - }, - { - "name": "rebalanceStableBorrowRate", - "args": { - "reserve": "USDC", - "user": "0", - "target": "1" - }, - "expected": "revert", - "revertMessage": "Interest rate rebalance conditions were not met" - } - ] - }, - { - "description": "User 1 borrows another 100 at variable, user 0 tries to rebalance but the conditions are not met (revert expected)", - "actions": [ - { - "name": "borrow", - "args": { - "reserve": "USDC", - "amount": "280", - "borrowRateMode": "variable", - "user": "1" - }, - "expected": "success" - }, - { - "name": "rebalanceStableBorrowRate", - "args": { - "reserve": "USDC", - "user": "0", - "target": "1" - }, - "expected": "revert", - "revertMessage": "Interest rate rebalance conditions were not met" - } - ] - }, - - { - "description": "User 1 borrows the remaining USDC (usage ratio = 100%) at variable. User 0 rebalances user 1", - "actions": [ - { - "name": "borrow", - "args": { - "reserve": "USDC", - "amount": "20", - "borrowRateMode": "variable", - "user": "1" - }, - "expected": "success" - }, - { - "name": "rebalanceStableBorrowRate", - "args": { - "reserve": "USDC", - "user": "0", - "target": "1" - }, - "expected": "success" - } - ] - } - ] -} diff --git a/test/helpers/scenarios/set-use-as-collateral.json b/test/helpers/scenarios/set-use-as-collateral.json deleted file mode 100644 index 2a206bb9..00000000 --- a/test/helpers/scenarios/set-use-as-collateral.json +++ /dev/null @@ -1,236 +0,0 @@ -{ - "title": "LendingPool: Usage as collateral", - "description": "Test cases for the setUserUseReserveAsCollateral() function.", - "stories": [ - { - "description": "User 0 Deposits 1000 DAI, disables DAI as collateral", - "actions": [ - { - "name": "mint", - "args": { - "reserve": "DAI", - "amount": "1000", - "user": "0" - }, - "expected": "success" - }, - { - "name": "approve", - "args": { - "reserve": "DAI", - "user": "0" - }, - "expected": "success" - }, - { - "name": "deposit", - "args": { - "reserve": "DAI", - "amount": "1000", - "user": "0" - }, - "expected": "success" - }, - { - "name": "setUseAsCollateral", - "args": { - "reserve": "DAI", - "user": "0", - "useAsCollateral": "false" - }, - "expected": "success" - } - ] - }, - { - "description": "User 1 Deposits 2 WETH, disables WETH as collateral, borrows 400 DAI (revert expected)", - "actions": [ - { - "name": "mint", - "args": { - "reserve": "WETH", - "amount": "2", - "user": "1" - }, - "expected": "success" - }, - { - "name": "approve", - "args": { - "reserve": "WETH", - "user": "1" - }, - "expected": "success" - }, - { - "name": "deposit", - "args": { - "reserve": "WETH", - "amount": "2", - "user": "1" - }, - "expected": "success" - }, - { - "name": "setUseAsCollateral", - "args": { - "reserve": "WETH", - "user": "1", - "useAsCollateral": "false" - }, - "expected": "success" - }, - { - "name": "borrow", - "args": { - "reserve": "DAI", - "amount": "400", - "borrowRateMode": "variable", - "user": "1" - }, - "expected": "revert", - "revertMessage": "The collateral balance is 0" - } - ] - }, - { - "description": "User 1 enables WETH as collateral, borrows 400 DAI", - "actions": [ - { - "name": "setUseAsCollateral", - "args": { - "reserve": "WETH", - "user": "1", - "useAsCollateral": "true" - }, - "expected": "success" - }, - { - "name": "borrow", - "args": { - "reserve": "DAI", - "amount": "400", - "borrowRateMode": "variable", - "user": "1" - }, - "expected": "success" - } - ] - }, - { - "description": "User 1 disables WETH as collateral (revert expected)", - "actions": [ - { - "name": "setUseAsCollateral", - "args": { - "reserve": "WETH", - "user": "1", - "useAsCollateral": "false" - }, - "expected": "revert", - "revertMessage": "User deposit is already being used as collateral" - } - ] - }, - { - "description": "User 1 Deposits 10 AAVE, disables WETH as collateral. Should revert as 10 AAVE are not enough to cover the debt (revert expected)", - "actions": [ - { - "name": "mint", - "args": { - "reserve": "AAVE", - "amount": "10", - "user": "1" - }, - "expected": "success" - }, - { - "name": "approve", - "args": { - "reserve": "AAVE", - "user": "1" - }, - "expected": "success" - }, - { - "name": "deposit", - "args": { - "reserve": "AAVE", - "amount": "10", - "user": "1" - }, - "expected": "success" - }, - { - "name": "setUseAsCollateral", - "args": { - "reserve": "WETH", - "user": "1", - "useAsCollateral": "false" - }, - "expected": "revert" - } - ] - }, - { - "description": "User 1 Deposits 640 more AAVE (enough to cover the DAI debt), disables WETH as collateral", - "actions": [ - { - "name": "mint", - "args": { - "reserve": "AAVE", - "amount": "640", - "user": "1" - }, - "expected": "success" - }, - { - "name": "deposit", - "args": { - "reserve": "AAVE", - "amount": "640", - "user": "1" - }, - "expected": "success" - }, - { - "name": "setUseAsCollateral", - "args": { - "reserve": "WETH", - "user": "1", - "useAsCollateral": "false" - }, - "expected": "success" - } - ] - }, - { - "description": "User 1 disables AAVE as collateral (revert expected)", - "actions": [ - { - "name": "setUseAsCollateral", - "args": { - "reserve": "AAVE", - "user": "1", - "useAsCollateral": "false" - }, - "expected": "revert" - } - ] - }, - { - "description": "User 1 reenables WETH as collateral", - "actions": [ - { - "name": "setUseAsCollateral", - "args": { - "reserve": "WETH", - "user": "1", - "useAsCollateral": "true" - }, - "expected": "success" - } - ] - } - ] -} diff --git a/test/helpers/scenarios/swap-rate-mode.json b/test/helpers/scenarios/swap-rate-mode.json deleted file mode 100644 index e966af9a..00000000 --- a/test/helpers/scenarios/swap-rate-mode.json +++ /dev/null @@ -1,167 +0,0 @@ -{ - "title": "LendingPool: Swap rate mode", - "description": "Test cases for the swapBorrowRateMode() function.", - "stories": [ - { - "description": "User 0 tries to swap rate mode without any variable rate loan in progress (revert expected)", - "actions": [ - { - "name": "swapBorrowRateMode", - "args": { - "reserve": "DAI", - "user": "1", - "borrowRateMode": "variable" - }, - "expected": "revert", - "revertMessage": "User does not have a variable rate loan in progress on this reserve" - } - ] - }, - { - "description": "User 0 tries to swap rate mode without any stable rate loan in progress (revert expected)", - "actions": [ - { - "name": "swapBorrowRateMode", - "args": { - "reserve": "DAI", - "user": "1", - "borrowRateMode": "stable" - }, - "expected": "revert", - "revertMessage": "User does not have a stable rate loan in progress on this reserve" - } - ] - }, - { - "description": "User 0 deposits 1000 DAI, user 1 deposits 2 ETH as collateral, borrows 100 DAI at variable rate and swaps to stable after one year", - "actions": [ - { - "name": "mint", - "args": { - "reserve": "DAI", - "amount": "1000", - "user": "0" - }, - "expected": "success" - }, - { - "name": "approve", - "args": { - "reserve": "DAI", - "user": "0" - }, - "expected": "success" - }, - { - "name": "deposit", - "args": { - "reserve": "DAI", - "amount": "1000", - "user": "0" - }, - "expected": "success" - }, - { - "name": "mint", - "args": { - "reserve": "WETH", - "amount": "2", - "user": "1" - }, - "expected": "success" - }, - { - "name": "approve", - "args": { - "reserve": "WETH", - "user": "1" - }, - "expected": "success" - }, - { - "name": "deposit", - "args": { - "reserve": "WETH", - "amount": "2", - "user": "1" - }, - "expected": "success" - }, - { - "name": "borrow", - "args": { - "reserve": "DAI", - "amount": "100", - "borrowRateMode": "variable", - "user": "1", - "timeTravel": "365" - }, - "expected": "success" - }, - { - "name": "swapBorrowRateMode", - "args": { - "reserve": "DAI", - "user": "1", - "borrowRateMode": "variable" - }, - "expected": "success" - } - ] - }, - { - "description": "User 1 borrows another 100 DAI, and swaps back to variable after one year, repays the loan", - "actions": [ - { - "name": "borrow", - "args": { - "reserve": "DAI", - "amount": "100", - "borrowRateMode": "stable", - "user": "1", - "timeTravel": "365" - }, - "expected": "success" - }, - { - "name": "swapBorrowRateMode", - "args": { - "reserve": "DAI", - "user": "1", - "borrowRateMode": "stable" - }, - "expected": "success" - }, - { - "name": "mint", - "description": "Mint 50 DAI to cover the interest", - "args": { - "reserve": "DAI", - "amount": "50", - "user": "1" - }, - "expected": "success" - }, - { - "name": "approve", - "args": { - "reserve": "DAI", - "user": "1" - }, - "expected": "success" - }, - { - "name": "repay", - "args": { - "reserve": "DAI", - "amount": "-1", - "user": "1", - "onBehalfOf": "1", - "borrowRateMode": "variable" - }, - "expected": "success" - } - ] - } - ] -} diff --git a/test/helpers/scenarios/withdraw-negatives.json b/test/helpers/scenarios/withdraw-negatives.json deleted file mode 100644 index fbc5c308..00000000 --- a/test/helpers/scenarios/withdraw-negatives.json +++ /dev/null @@ -1,114 +0,0 @@ -{ - "title": "LendingPool: Redeem negative test cases", - "description": "Redeem function.", - "stories": [ - { - "description": "Users 0 Deposits 1000 DAI and tries to redeem 0 DAI (revert expected)", - "actions": [ - { - "name": "mint", - "args": { - "reserve": "DAI", - "amount": "1000", - "user": "0" - }, - "expected": "success" - }, - { - "name": "approve", - "args": { - "reserve": "DAI", - "user": "0" - }, - "expected": "success" - }, - { - "name": "deposit", - "args": { - "reserve": "DAI", - "amount": "1000", - "user": "0" - }, - "expected": "success" - }, - - { - "name": "withdraw", - "args": { - "reserve": "DAI", - "amount": "0", - "user": "0" - }, - "expected": "revert", - "revertMessage": "Amount to redeem needs to be > 0" - } - ] - }, - { - "description": "Users 0 tries to redeem 1100 DAI from the 1000 DAI deposited (revert expected)", - "actions": [ - { - "name": "withdraw", - "args": { - "reserve": "DAI", - "amount": "1100", - "user": "0" - }, - "expected": "revert", - "revertMessage": "User cannot redeem more than the available balance" - } - ] - }, - { - "description": "Users 1 deposits 1 WETH, borrows 100 DAI, tries to redeem the 1 WETH deposited (revert expected)", - "actions": [ - { - "name": "mint", - "args": { - "reserve": "WETH", - "amount": "1", - "user": "1" - }, - "expected": "success" - }, - { - "name": "approve", - "args": { - "reserve": "WETH", - "user": "1" - }, - "expected": "success" - }, - { - "name": "deposit", - "args": { - "reserve": "WETH", - "amount": "1", - "user": "1" - }, - "expected": "success" - }, - { - "name": "borrow", - "args": { - "reserve": "DAI", - "amount": "100", - "user": "1", - "borrowRateMode": "stable" - }, - "expected": "success" - }, - { - "name": "withdraw", - "args": { - "reserve": "WETH", - "amount": "-1", - "user": "1" - }, - "expected": "revert", - "revertMessage": "Transfer cannot be allowed." - } - ] - } - ] -} diff --git a/test/helpers/scenarios/withdraw.json b/test/helpers/scenarios/withdraw.json deleted file mode 100644 index 5f183eca..00000000 --- a/test/helpers/scenarios/withdraw.json +++ /dev/null @@ -1,340 +0,0 @@ -{ - "title": "LendingPool: withdraw", - "description": "withdraw function.", - "stories": [ - { - "description": "User 0 Deposits 1000 DAI in an empty reserve", - "actions": [ - { - "name": "mint", - "args": { - "reserve": "DAI", - "amount": "1000", - "user": "0" - }, - "expected": "success" - }, - { - "name": "approve", - "args": { - "reserve": "DAI", - "user": "0" - }, - "expected": "success" - }, - { - "name": "deposit", - "args": { - "reserve": "DAI", - "amount": "1000", - "user": "0" - }, - "expected": "success" - } - ] - }, - { - "description": "User 0 withdraws half of the deposited DAI", - "actions": [ - { - "name": "withdraw", - "args": { - "reserve": "DAI", - "amount": "500", - "user": "0" - }, - "expected": "success" - } - ] - }, - { - "description": "User 0 withdraws remaining half of the deposited DAI", - "actions": [ - { - "name": "withdraw", - "args": { - "reserve": "DAI", - "amount": "-1", - "user": "0" - }, - "expected": "success" - } - ] - }, - { - "description": "User 0 Deposits 1000 USDC in an empty reserve", - "actions": [ - { - "name": "mint", - "args": { - "reserve": "USDC", - "amount": "1000", - "user": "0" - }, - "expected": "success" - }, - { - "name": "approve", - "args": { - "reserve": "USDC", - "user": "0" - }, - "expected": "success" - }, - { - "name": "deposit", - "args": { - "reserve": "USDC", - "amount": "1000", - "user": "0" - }, - "expected": "success" - } - ] - }, - { - "description": "User 0 withdraws half of the deposited USDC", - "actions": [ - { - "name": "withdraw", - "args": { - "reserve": "USDC", - "amount": "500", - "user": "0" - }, - "expected": "success" - } - ] - }, - { - "description": "User 0 withdraws remaining half of the deposited USDC", - "actions": [ - { - "name": "withdraw", - "args": { - "reserve": "USDC", - "amount": "-1", - "user": "0" - }, - "expected": "success" - } - ] - }, - { - "description": "User 0 Deposits 1 WETH in an empty reserve", - "actions": [ - { - "name": "mint", - "args": { - "reserve": "WETH", - "amount": "1", - "user": "0" - }, - "expected": "success" - }, - { - "name": "approve", - "args": { - "reserve": "WETH", - "user": "0" - }, - "expected": "success" - }, - { - "name": "deposit", - "args": { - "reserve": "WETH", - "amount": "1", - "user": "0" - }, - "expected": "success" - } - ] - }, - { - "description": "User 0 withdraws half of the deposited WETH", - "actions": [ - { - "name": "withdraw", - "args": { - "reserve": "WETH", - "amount": "0.5", - "user": "0" - }, - "expected": "success" - } - ] - }, - { - "description": "User 0 withdraws remaining half of the deposited ETH", - "actions": [ - { - "name": "withdraw", - "args": { - "reserve": "WETH", - "amount": "-1", - "user": "0" - }, - "expected": "success" - } - ] - }, - { - "description": "Users 0 and 1 Deposit 1000 DAI, both withdraw", - "actions": [ - { - "name": "mint", - "args": { - "reserve": "DAI", - "amount": "1000", - "user": "1" - }, - "expected": "success" - }, - { - "name": "approve", - "args": { - "reserve": "DAI", - "user": "1" - }, - "expected": "success" - }, - { - "name": "deposit", - "args": { - "reserve": "DAI", - "amount": "1000", - "user": "0" - }, - "expected": "success" - }, - { - "name": "deposit", - "args": { - "reserve": "DAI", - "amount": "1000", - "user": "1" - }, - "expected": "success" - }, - { - "name": "withdraw", - "args": { - "reserve": "DAI", - "amount": "-1", - "user": "0" - }, - "expected": "success" - }, - { - "name": "withdraw", - "args": { - "reserve": "DAI", - "amount": "-1", - "user": "1" - }, - "expected": "success" - } - ] - }, - { - "description": "Users 0 deposits 1000 DAI, user 1 Deposit 1000 USDC and 1 WETH, borrows 100 DAI. User 1 tries to withdraw all the USDC", - "actions": [ - { - "name": "deposit", - "args": { - "reserve": "DAI", - "amount": "1000", - "user": "0" - }, - "expected": "success" - }, - { - "name": "mint", - "args": { - "reserve": "USDC", - "amount": "1000", - "user": "1" - }, - "expected": "success" - }, - { - "name": "approve", - "args": { - "reserve": "USDC", - "user": "1" - }, - "expected": "success" - }, - { - "name": "deposit", - "args": { - "reserve": "USDC", - "amount": "1000", - "user": "1" - }, - "expected": "success" - }, - { - "name": "mint", - "args": { - "reserve": "WETH", - "amount": "1", - "user": "1" - }, - "expected": "success" - }, - { - "name": "approve", - "args": { - "reserve": "WETH", - "user": "1" - }, - "expected": "success" - }, - { - "name": "deposit", - "args": { - "reserve": "WETH", - "amount": "1", - "user": "1" - }, - "expected": "success" - }, - { - "name": "borrow", - "args": { - "reserve": "DAI", - "amount": "100", - "user": "1", - "borrowRateMode": "stable" - }, - "expected": "success" - }, - { - "name": "withdraw", - "args": { - "reserve": "USDC", - "amount": "-1", - "user": "1" - }, - "expected": "success" - } - ] - }, - { - "description": "Users 1 tries to withdraw 0.05 WETH, which does not bring the HF below 1", - "actions": [ - { - "name": "withdraw", - "args": { - "reserve": "WETH", - "amount": "0.05", - "user": "1" - }, - "expected": "success" - } - ] - } - ] -} diff --git a/test/helpers/utils/calculations.ts b/test/helpers/utils/calculations.ts deleted file mode 100644 index aeb9d74e..00000000 --- a/test/helpers/utils/calculations.ts +++ /dev/null @@ -1,1434 +0,0 @@ -import BigNumber from 'bignumber.js'; -import { ONE_YEAR, RAY, MAX_UINT_AMOUNT, PERCENTAGE_FACTOR } from '../../../helpers/constants'; -import { - IReserveParams, - iAavePoolAssets, - RateMode, - tEthereumAddress, -} from '../../../helpers/types'; -import './math'; -import { ReserveData, UserReserveData } from './interfaces'; - -export const strToBN = (amount: string): BigNumber => new BigNumber(amount); - -interface Configuration { - reservesParams: iAavePoolAssets; -} - -export const configuration: Configuration = {}; - -export const calcExpectedUserDataAfterDeposit = ( - amountDeposited: string, - reserveDataBeforeAction: ReserveData, - reserveDataAfterAction: ReserveData, - userDataBeforeAction: UserReserveData, - txTimestamp: BigNumber, - currentTimestamp: BigNumber, - txCost: BigNumber -): UserReserveData => { - const expectedUserData = {}; - - expectedUserData.currentStableDebt = calcExpectedStableDebtTokenBalance( - userDataBeforeAction.principalStableDebt, - userDataBeforeAction.stableBorrowRate, - userDataBeforeAction.stableRateLastUpdated, - txTimestamp - ); - - expectedUserData.currentVariableDebt = calcExpectedVariableDebtTokenBalance( - reserveDataBeforeAction, - userDataBeforeAction, - txTimestamp - ); - - expectedUserData.principalStableDebt = userDataBeforeAction.principalStableDebt; - expectedUserData.scaledVariableDebt = userDataBeforeAction.scaledVariableDebt; - expectedUserData.variableBorrowIndex = userDataBeforeAction.variableBorrowIndex; - expectedUserData.stableBorrowRate = userDataBeforeAction.stableBorrowRate; - expectedUserData.stableRateLastUpdated = userDataBeforeAction.stableRateLastUpdated; - - expectedUserData.liquidityRate = reserveDataAfterAction.liquidityRate; - - expectedUserData.scaledATokenBalance = calcExpectedScaledATokenBalance( - userDataBeforeAction, - reserveDataAfterAction.liquidityIndex, - new BigNumber(amountDeposited), - new BigNumber(0) - ); - expectedUserData.currentATokenBalance = calcExpectedATokenBalance( - reserveDataBeforeAction, - userDataBeforeAction, - txTimestamp - ).plus(amountDeposited); - - if (userDataBeforeAction.currentATokenBalance.eq(0)) { - expectedUserData.usageAsCollateralEnabled = true; - } else { - expectedUserData.usageAsCollateralEnabled = userDataBeforeAction.usageAsCollateralEnabled; - } - - expectedUserData.variableBorrowIndex = userDataBeforeAction.variableBorrowIndex; - expectedUserData.walletBalance = userDataBeforeAction.walletBalance.minus(amountDeposited); - - expectedUserData.currentStableDebt = expectedUserData.principalStableDebt = calcExpectedStableDebtTokenBalance( - userDataBeforeAction.principalStableDebt, - userDataBeforeAction.stableBorrowRate, - userDataBeforeAction.stableRateLastUpdated, - txTimestamp - ); - - expectedUserData.currentVariableDebt = expectedUserData.principalStableDebt = calcExpectedVariableDebtTokenBalance( - reserveDataBeforeAction, - userDataBeforeAction, - txTimestamp - ); - - return expectedUserData; -}; - -export const calcExpectedUserDataAfterWithdraw = ( - amountWithdrawn: string, - reserveDataBeforeAction: ReserveData, - reserveDataAfterAction: ReserveData, - userDataBeforeAction: UserReserveData, - txTimestamp: BigNumber, - currentTimestamp: BigNumber, - txCost: BigNumber -): UserReserveData => { - const expectedUserData = {}; - - const aTokenBalance = calcExpectedATokenBalance( - reserveDataBeforeAction, - userDataBeforeAction, - txTimestamp - ); - - if (amountWithdrawn == MAX_UINT_AMOUNT) { - amountWithdrawn = aTokenBalance.toFixed(0); - } - - expectedUserData.scaledATokenBalance = calcExpectedScaledATokenBalance( - userDataBeforeAction, - reserveDataAfterAction.liquidityIndex, - new BigNumber(0), - new BigNumber(amountWithdrawn) - ); - - expectedUserData.currentATokenBalance = aTokenBalance.minus(amountWithdrawn); - - expectedUserData.principalStableDebt = userDataBeforeAction.principalStableDebt; - expectedUserData.scaledVariableDebt = userDataBeforeAction.scaledVariableDebt; - - expectedUserData.currentStableDebt = calcExpectedStableDebtTokenBalance( - userDataBeforeAction.principalStableDebt, - userDataBeforeAction.stableBorrowRate, - userDataBeforeAction.stableRateLastUpdated, - txTimestamp - ); - - expectedUserData.currentVariableDebt = calcExpectedVariableDebtTokenBalance( - reserveDataBeforeAction, - userDataBeforeAction, - txTimestamp - ); - - expectedUserData.variableBorrowIndex = userDataBeforeAction.variableBorrowIndex; - expectedUserData.stableBorrowRate = userDataBeforeAction.stableBorrowRate; - expectedUserData.stableRateLastUpdated = userDataBeforeAction.stableRateLastUpdated; - - expectedUserData.liquidityRate = reserveDataAfterAction.liquidityRate; - - if (userDataBeforeAction.currentATokenBalance.eq(0)) { - expectedUserData.usageAsCollateralEnabled = true; - } else { - //if the user is withdrawing everything, usageAsCollateralEnabled must be false - if (expectedUserData.currentATokenBalance.eq(0)) { - expectedUserData.usageAsCollateralEnabled = false; - } else { - expectedUserData.usageAsCollateralEnabled = userDataBeforeAction.usageAsCollateralEnabled; - } - } - - expectedUserData.walletBalance = userDataBeforeAction.walletBalance.plus(amountWithdrawn); - - return expectedUserData; -}; - -export const calcExpectedReserveDataAfterDeposit = ( - amountDeposited: string, - reserveDataBeforeAction: ReserveData, - txTimestamp: BigNumber -): ReserveData => { - const expectedReserveData: ReserveData = {}; - - expectedReserveData.address = reserveDataBeforeAction.address; - - expectedReserveData.totalLiquidity = new BigNumber(reserveDataBeforeAction.totalLiquidity).plus( - amountDeposited - ); - expectedReserveData.availableLiquidity = new BigNumber( - reserveDataBeforeAction.availableLiquidity - ).plus(amountDeposited); - - expectedReserveData.averageStableBorrowRate = reserveDataBeforeAction.averageStableBorrowRate; - expectedReserveData.liquidityIndex = calcExpectedLiquidityIndex( - reserveDataBeforeAction, - txTimestamp - ); - expectedReserveData.variableBorrowIndex = calcExpectedVariableBorrowIndex( - reserveDataBeforeAction, - txTimestamp - ); - - expectedReserveData.totalStableDebt = calcExpectedTotalStableDebt( - reserveDataBeforeAction.principalStableDebt, - reserveDataBeforeAction.averageStableBorrowRate, - reserveDataBeforeAction.totalStableDebtLastUpdated, - txTimestamp - ); - expectedReserveData.totalVariableDebt = calcExpectedTotalVariableDebt( - reserveDataBeforeAction, - expectedReserveData.variableBorrowIndex - ); - - expectedReserveData.scaledVariableDebt = reserveDataBeforeAction.scaledVariableDebt; - expectedReserveData.principalStableDebt = reserveDataBeforeAction.principalStableDebt; - - expectedReserveData.utilizationRate = calcExpectedUtilizationRate( - expectedReserveData.totalStableDebt, - expectedReserveData.totalVariableDebt, - expectedReserveData.totalLiquidity - ); - const rates = calcExpectedInterestRates( - reserveDataBeforeAction.symbol, - reserveDataBeforeAction.marketStableRate, - expectedReserveData.utilizationRate, - expectedReserveData.totalStableDebt, - expectedReserveData.totalVariableDebt, - expectedReserveData.averageStableBorrowRate - ); - expectedReserveData.liquidityRate = rates[0]; - expectedReserveData.stableBorrowRate = rates[1]; - expectedReserveData.variableBorrowRate = rates[2]; - - return expectedReserveData; -}; - -export const calcExpectedReserveDataAfterWithdraw = ( - amountWithdrawn: string, - reserveDataBeforeAction: ReserveData, - userDataBeforeAction: UserReserveData, - txTimestamp: BigNumber -): ReserveData => { - const expectedReserveData: ReserveData = {}; - - expectedReserveData.address = reserveDataBeforeAction.address; - - if (amountWithdrawn == MAX_UINT_AMOUNT) { - amountWithdrawn = calcExpectedATokenBalance( - reserveDataBeforeAction, - userDataBeforeAction, - txTimestamp - ).toFixed(); - } - - expectedReserveData.availableLiquidity = new BigNumber( - reserveDataBeforeAction.availableLiquidity - ).minus(amountWithdrawn); - - expectedReserveData.principalStableDebt = reserveDataBeforeAction.principalStableDebt; - expectedReserveData.scaledVariableDebt = reserveDataBeforeAction.scaledVariableDebt; - - expectedReserveData.liquidityIndex = calcExpectedLiquidityIndex( - reserveDataBeforeAction, - txTimestamp - ); - expectedReserveData.variableBorrowIndex = calcExpectedVariableBorrowIndex( - reserveDataBeforeAction, - txTimestamp - ); - - expectedReserveData.totalStableDebt = calcExpectedTotalStableDebt( - reserveDataBeforeAction.principalStableDebt, - reserveDataBeforeAction.averageStableBorrowRate, - reserveDataBeforeAction.totalStableDebtLastUpdated, - txTimestamp - ); - expectedReserveData.totalVariableDebt = expectedReserveData.scaledVariableDebt.rayMul( - expectedReserveData.variableBorrowIndex - ); - - expectedReserveData.averageStableBorrowRate = reserveDataBeforeAction.averageStableBorrowRate; - - expectedReserveData.totalLiquidity = new BigNumber(reserveDataBeforeAction.availableLiquidity) - .minus(amountWithdrawn) - .plus(expectedReserveData.totalVariableDebt) - .plus(expectedReserveData.totalStableDebt); - - expectedReserveData.utilizationRate = calcExpectedUtilizationRate( - expectedReserveData.totalStableDebt, - expectedReserveData.totalVariableDebt, - expectedReserveData.totalLiquidity - ); - const rates = calcExpectedInterestRates( - reserveDataBeforeAction.symbol, - reserveDataBeforeAction.marketStableRate, - expectedReserveData.utilizationRate, - expectedReserveData.totalStableDebt, - expectedReserveData.totalVariableDebt, - expectedReserveData.averageStableBorrowRate - ); - expectedReserveData.liquidityRate = rates[0]; - expectedReserveData.stableBorrowRate = rates[1]; - expectedReserveData.variableBorrowRate = rates[2]; - - return expectedReserveData; -}; - -export const calcExpectedReserveDataAfterBorrow = ( - amountBorrowed: string, - borrowRateMode: string, - reserveDataBeforeAction: ReserveData, - userDataBeforeAction: UserReserveData, - txTimestamp: BigNumber, - currentTimestamp: BigNumber -): ReserveData => { - const expectedReserveData = {}; - - expectedReserveData.address = reserveDataBeforeAction.address; - - const amountBorrowedBN = new BigNumber(amountBorrowed); - - expectedReserveData.liquidityIndex = calcExpectedLiquidityIndex( - reserveDataBeforeAction, - txTimestamp - ); - - expectedReserveData.variableBorrowIndex = calcExpectedVariableBorrowIndex( - reserveDataBeforeAction, - txTimestamp - ); - - expectedReserveData.availableLiquidity = reserveDataBeforeAction.availableLiquidity.minus( - amountBorrowedBN - ); - - expectedReserveData.lastUpdateTimestamp = txTimestamp; - - if (borrowRateMode == RateMode.Stable) { - expectedReserveData.scaledVariableDebt = reserveDataBeforeAction.scaledVariableDebt; - - const expectedVariableDebtAfterTx = expectedReserveData.scaledVariableDebt.rayMul( - expectedReserveData.variableBorrowIndex - ); - - const expectedStableDebtUntilTx = calcExpectedTotalStableDebt( - reserveDataBeforeAction.principalStableDebt, - reserveDataBeforeAction.averageStableBorrowRate, - reserveDataBeforeAction.totalStableDebtLastUpdated, - txTimestamp - ); - - expectedReserveData.principalStableDebt = expectedStableDebtUntilTx.plus(amountBorrowedBN); - - expectedReserveData.averageStableBorrowRate = calcExpectedAverageStableBorrowRate( - reserveDataBeforeAction.averageStableBorrowRate, - expectedStableDebtUntilTx, - amountBorrowedBN, - reserveDataBeforeAction.stableBorrowRate - ); - - const totalLiquidityAfterTx = expectedReserveData.availableLiquidity - .plus(expectedReserveData.principalStableDebt) - .plus(expectedVariableDebtAfterTx); - - const utilizationRateAfterTx = calcExpectedUtilizationRate( - expectedReserveData.principalStableDebt, //the expected principal debt is the total debt immediately after the tx - expectedVariableDebtAfterTx, - totalLiquidityAfterTx - ); - - const ratesAfterTx = calcExpectedInterestRates( - reserveDataBeforeAction.symbol, - reserveDataBeforeAction.marketStableRate, - utilizationRateAfterTx, - expectedReserveData.principalStableDebt, - expectedVariableDebtAfterTx, - expectedReserveData.averageStableBorrowRate - ); - - expectedReserveData.liquidityRate = ratesAfterTx[0]; - - expectedReserveData.stableBorrowRate = ratesAfterTx[1]; - - expectedReserveData.variableBorrowRate = ratesAfterTx[2]; - - expectedReserveData.totalStableDebt = calcExpectedTotalStableDebt( - expectedReserveData.principalStableDebt, - expectedReserveData.averageStableBorrowRate, - txTimestamp, - currentTimestamp - ); - - expectedReserveData.totalVariableDebt = reserveDataBeforeAction.scaledVariableDebt.rayMul( - calcExpectedReserveNormalizedDebt( - expectedReserveData.variableBorrowRate, - expectedReserveData.variableBorrowIndex, - txTimestamp, - currentTimestamp - ) - ); - - expectedReserveData.totalLiquidity = expectedReserveData.availableLiquidity - .plus(expectedReserveData.totalVariableDebt) - .plus(expectedReserveData.totalStableDebt); - - expectedReserveData.utilizationRate = calcExpectedUtilizationRate( - expectedReserveData.totalStableDebt, - expectedReserveData.totalVariableDebt, - expectedReserveData.totalLiquidity - ); - } else { - expectedReserveData.principalStableDebt = reserveDataBeforeAction.principalStableDebt; - - const totalStableDebtAfterTx = calcExpectedStableDebtTokenBalance( - reserveDataBeforeAction.principalStableDebt, - reserveDataBeforeAction.averageStableBorrowRate, - reserveDataBeforeAction.totalStableDebtLastUpdated, - txTimestamp - ); - - expectedReserveData.totalStableDebt = calcExpectedTotalStableDebt( - reserveDataBeforeAction.principalStableDebt, - reserveDataBeforeAction.averageStableBorrowRate, - reserveDataBeforeAction.totalStableDebtLastUpdated, - currentTimestamp - ); - - expectedReserveData.averageStableBorrowRate = reserveDataBeforeAction.averageStableBorrowRate; - - expectedReserveData.scaledVariableDebt = reserveDataBeforeAction.scaledVariableDebt.plus( - amountBorrowedBN.rayDiv(expectedReserveData.variableBorrowIndex) - ); - - const totalVariableDebtAfterTx = expectedReserveData.scaledVariableDebt.rayMul( - expectedReserveData.variableBorrowIndex - ); - - const utilizationRateAfterTx = calcExpectedUtilizationRate( - totalStableDebtAfterTx, - totalVariableDebtAfterTx, - expectedReserveData.availableLiquidity - .plus(totalStableDebtAfterTx) - .plus(totalVariableDebtAfterTx) - ); - - const rates = calcExpectedInterestRates( - reserveDataBeforeAction.symbol, - reserveDataBeforeAction.marketStableRate, - utilizationRateAfterTx, - totalStableDebtAfterTx, - totalVariableDebtAfterTx, - expectedReserveData.averageStableBorrowRate - ); - - expectedReserveData.liquidityRate = rates[0]; - - expectedReserveData.stableBorrowRate = rates[1]; - - expectedReserveData.variableBorrowRate = rates[2]; - - expectedReserveData.totalVariableDebt = expectedReserveData.scaledVariableDebt.rayMul( - calcExpectedReserveNormalizedDebt( - expectedReserveData.variableBorrowRate, - expectedReserveData.variableBorrowIndex, - txTimestamp, - currentTimestamp - ) - ); - - expectedReserveData.totalLiquidity = expectedReserveData.availableLiquidity - .plus(expectedReserveData.totalStableDebt) - .plus(expectedReserveData.totalVariableDebt); - - expectedReserveData.utilizationRate = calcExpectedUtilizationRate( - expectedReserveData.totalStableDebt, - expectedReserveData.totalVariableDebt, - expectedReserveData.totalLiquidity - ); - } - - return expectedReserveData; -}; - -export const calcExpectedReserveDataAfterRepay = ( - amountRepaid: string, - borrowRateMode: RateMode, - reserveDataBeforeAction: ReserveData, - userDataBeforeAction: UserReserveData, - txTimestamp: BigNumber, - currentTimestamp: BigNumber -): ReserveData => { - const expectedReserveData: ReserveData = {}; - - expectedReserveData.address = reserveDataBeforeAction.address; - - let amountRepaidBN = new BigNumber(amountRepaid); - - const userStableDebt = calcExpectedStableDebtTokenBalance( - userDataBeforeAction.principalStableDebt, - userDataBeforeAction.stableBorrowRate, - userDataBeforeAction.stableRateLastUpdated, - txTimestamp - ); - - const userVariableDebt = calcExpectedVariableDebtTokenBalance( - reserveDataBeforeAction, - userDataBeforeAction, - txTimestamp - ); - - //if amount repaid == MAX_UINT_AMOUNT, user is repaying everything - if (amountRepaidBN.abs().eq(MAX_UINT_AMOUNT)) { - if (borrowRateMode == RateMode.Stable) { - amountRepaidBN = userStableDebt; - } else { - amountRepaidBN = userVariableDebt; - } - } - - expectedReserveData.liquidityIndex = calcExpectedLiquidityIndex( - reserveDataBeforeAction, - txTimestamp - ); - expectedReserveData.variableBorrowIndex = calcExpectedVariableBorrowIndex( - reserveDataBeforeAction, - txTimestamp - ); - - if (borrowRateMode == RateMode.Stable) { - const expectedDebt = calcExpectedTotalStableDebt( - reserveDataBeforeAction.principalStableDebt, - reserveDataBeforeAction.averageStableBorrowRate, - reserveDataBeforeAction.totalStableDebtLastUpdated, - txTimestamp - ); - - expectedReserveData.principalStableDebt = expectedReserveData.totalStableDebt = expectedDebt.minus( - amountRepaidBN - ); - - //due to accumulation errors, the total stable debt might be smaller than the last user debt. - //in this case we simply set the total supply and avg stable rate to 0. - if (expectedReserveData.totalStableDebt.lt(0)) { - expectedReserveData.principalStableDebt = expectedReserveData.totalStableDebt = expectedReserveData.averageStableBorrowRate = new BigNumber( - 0 - ); - } else { - expectedReserveData.averageStableBorrowRate = calcExpectedAverageStableBorrowRate( - reserveDataBeforeAction.averageStableBorrowRate, - expectedDebt, - amountRepaidBN.negated(), - userDataBeforeAction.stableBorrowRate - ); - - //also due to accumulation errors, the final avg stable rate when the last user repays might be negative. - //if that is the case, it means a small leftover of total stable debt is left, which can be erased. - - if (expectedReserveData.averageStableBorrowRate.lt(0)) { - expectedReserveData.principalStableDebt = expectedReserveData.totalStableDebt = expectedReserveData.averageStableBorrowRate = new BigNumber( - 0 - ); - } - } - - expectedReserveData.scaledVariableDebt = reserveDataBeforeAction.scaledVariableDebt; - - expectedReserveData.totalVariableDebt = expectedReserveData.scaledVariableDebt.rayMul( - expectedReserveData.variableBorrowIndex - ); - } else { - expectedReserveData.scaledVariableDebt = reserveDataBeforeAction.scaledVariableDebt.minus( - amountRepaidBN.rayDiv(expectedReserveData.variableBorrowIndex) - ); - - expectedReserveData.totalVariableDebt = expectedReserveData.scaledVariableDebt.rayMul( - expectedReserveData.variableBorrowIndex - ); - - expectedReserveData.principalStableDebt = reserveDataBeforeAction.principalStableDebt; - expectedReserveData.totalStableDebt = reserveDataBeforeAction.totalStableDebt; - - expectedReserveData.averageStableBorrowRate = reserveDataBeforeAction.averageStableBorrowRate; - } - - expectedReserveData.availableLiquidity = reserveDataBeforeAction.availableLiquidity.plus( - amountRepaidBN - ); - - expectedReserveData.totalLiquidity = expectedReserveData.availableLiquidity - .plus(expectedReserveData.totalStableDebt) - .plus(expectedReserveData.totalVariableDebt); - - expectedReserveData.utilizationRate = calcExpectedUtilizationRate( - expectedReserveData.totalStableDebt, - expectedReserveData.totalVariableDebt, - expectedReserveData.totalLiquidity - ); - - const rates = calcExpectedInterestRates( - reserveDataBeforeAction.symbol, - reserveDataBeforeAction.marketStableRate, - expectedReserveData.utilizationRate, - expectedReserveData.totalStableDebt, - expectedReserveData.totalVariableDebt, - expectedReserveData.averageStableBorrowRate - ); - expectedReserveData.liquidityRate = rates[0]; - - expectedReserveData.stableBorrowRate = rates[1]; - - expectedReserveData.variableBorrowRate = rates[2]; - - expectedReserveData.lastUpdateTimestamp = txTimestamp; - - return expectedReserveData; -}; - -export const calcExpectedUserDataAfterBorrow = ( - amountBorrowed: string, - interestRateMode: string, - reserveDataBeforeAction: ReserveData, - expectedDataAfterAction: ReserveData, - userDataBeforeAction: UserReserveData, - txTimestamp: BigNumber, - currentTimestamp: BigNumber -): UserReserveData => { - const expectedUserData = {}; - - const amountBorrowedBN = new BigNumber(amountBorrowed); - - if (interestRateMode == RateMode.Stable) { - const stableDebtUntilTx = calcExpectedStableDebtTokenBalance( - userDataBeforeAction.principalStableDebt, - userDataBeforeAction.stableBorrowRate, - userDataBeforeAction.stableRateLastUpdated, - txTimestamp - ); - - expectedUserData.principalStableDebt = stableDebtUntilTx.plus(amountBorrowed); - expectedUserData.stableRateLastUpdated = txTimestamp; - - expectedUserData.stableBorrowRate = calcExpectedUserStableRate( - stableDebtUntilTx, - userDataBeforeAction.stableBorrowRate, - amountBorrowedBN, - reserveDataBeforeAction.stableBorrowRate - ); - - expectedUserData.currentStableDebt = calcExpectedStableDebtTokenBalance( - expectedUserData.principalStableDebt, - expectedUserData.stableBorrowRate, - txTimestamp, - currentTimestamp - ); - - expectedUserData.scaledVariableDebt = userDataBeforeAction.scaledVariableDebt; - } else { - expectedUserData.scaledVariableDebt = reserveDataBeforeAction.scaledVariableDebt.plus( - amountBorrowedBN.rayDiv(expectedDataAfterAction.variableBorrowIndex) - ); - - expectedUserData.principalStableDebt = userDataBeforeAction.principalStableDebt; - - expectedUserData.stableBorrowRate = userDataBeforeAction.stableBorrowRate; - - expectedUserData.stableRateLastUpdated = userDataBeforeAction.stableRateLastUpdated; - - expectedUserData.currentStableDebt = calcExpectedStableDebtTokenBalance( - userDataBeforeAction.principalStableDebt, - userDataBeforeAction.stableBorrowRate, - userDataBeforeAction.stableRateLastUpdated, - currentTimestamp - ); - } - - expectedUserData.currentVariableDebt = calcExpectedVariableDebtTokenBalance( - expectedDataAfterAction, - expectedUserData, - currentTimestamp - ); - - expectedUserData.liquidityRate = expectedDataAfterAction.liquidityRate; - - expectedUserData.usageAsCollateralEnabled = userDataBeforeAction.usageAsCollateralEnabled; - - expectedUserData.currentATokenBalance = calcExpectedATokenBalance( - expectedDataAfterAction, - userDataBeforeAction, - currentTimestamp - ); - - expectedUserData.scaledATokenBalance = userDataBeforeAction.scaledATokenBalance; - - expectedUserData.walletBalance = userDataBeforeAction.walletBalance.plus(amountBorrowed); - - return expectedUserData; -}; - -export const calcExpectedUserDataAfterRepay = ( - totalRepaid: string, - rateMode: RateMode, - reserveDataBeforeAction: ReserveData, - expectedDataAfterAction: ReserveData, - userDataBeforeAction: UserReserveData, - user: string, - onBehalfOf: string, - txTimestamp: BigNumber, - currentTimestamp: BigNumber -): UserReserveData => { - const expectedUserData = {}; - - const variableDebt = calcExpectedVariableDebtTokenBalance( - reserveDataBeforeAction, - userDataBeforeAction, - currentTimestamp - ); - - const stableDebt = calcExpectedStableDebtTokenBalance( - userDataBeforeAction.principalStableDebt, - userDataBeforeAction.stableBorrowRate, - userDataBeforeAction.stableRateLastUpdated, - currentTimestamp - ); - - let totalRepaidBN = new BigNumber(totalRepaid); - if (totalRepaidBN.abs().eq(MAX_UINT_AMOUNT)) { - totalRepaidBN = rateMode == RateMode.Stable ? stableDebt : variableDebt; - } - - if (rateMode == RateMode.Stable) { - expectedUserData.scaledVariableDebt = userDataBeforeAction.scaledVariableDebt; - expectedUserData.currentVariableDebt = variableDebt; - - expectedUserData.principalStableDebt = expectedUserData.currentStableDebt = stableDebt.minus( - totalRepaidBN - ); - - if (expectedUserData.currentStableDebt.eq('0')) { - //user repaid everything - expectedUserData.stableBorrowRate = expectedUserData.stableRateLastUpdated = new BigNumber( - '0' - ); - } else { - expectedUserData.stableBorrowRate = userDataBeforeAction.stableBorrowRate; - expectedUserData.stableRateLastUpdated = txTimestamp; - } - } else { - expectedUserData.currentStableDebt = userDataBeforeAction.principalStableDebt; - expectedUserData.principalStableDebt = stableDebt; - expectedUserData.stableBorrowRate = userDataBeforeAction.stableBorrowRate; - expectedUserData.stableRateLastUpdated = userDataBeforeAction.stableRateLastUpdated; - - expectedUserData.scaledVariableDebt = userDataBeforeAction.scaledVariableDebt.minus( - totalRepaidBN.rayDiv(expectedDataAfterAction.variableBorrowIndex) - ); - expectedUserData.currentVariableDebt = expectedUserData.scaledVariableDebt.rayMul( - expectedDataAfterAction.variableBorrowIndex - ); - } - - expectedUserData.liquidityRate = expectedDataAfterAction.liquidityRate; - - expectedUserData.usageAsCollateralEnabled = userDataBeforeAction.usageAsCollateralEnabled; - - expectedUserData.currentATokenBalance = calcExpectedATokenBalance( - reserveDataBeforeAction, - userDataBeforeAction, - txTimestamp - ); - expectedUserData.scaledATokenBalance = userDataBeforeAction.scaledATokenBalance; - - if (user === onBehalfOf) { - expectedUserData.walletBalance = userDataBeforeAction.walletBalance.minus(totalRepaidBN); - } else { - //wallet balance didn't change - expectedUserData.walletBalance = userDataBeforeAction.walletBalance; - } - - return expectedUserData; -}; - -export const calcExpectedUserDataAfterSetUseAsCollateral = ( - useAsCollateral: boolean, - reserveDataBeforeAction: ReserveData, - userDataBeforeAction: UserReserveData, - txCost: BigNumber -): UserReserveData => { - const expectedUserData = { ...userDataBeforeAction }; - - expectedUserData.usageAsCollateralEnabled = useAsCollateral; - - return expectedUserData; -}; - -export const calcExpectedReserveDataAfterSwapRateMode = ( - reserveDataBeforeAction: ReserveData, - userDataBeforeAction: UserReserveData, - rateMode: string, - txTimestamp: BigNumber -): ReserveData => { - const expectedReserveData: ReserveData = {}; - - expectedReserveData.address = reserveDataBeforeAction.address; - - const variableDebt = calcExpectedVariableDebtTokenBalance( - reserveDataBeforeAction, - userDataBeforeAction, - txTimestamp - ); - - const stableDebt = calcExpectedStableDebtTokenBalance( - userDataBeforeAction.principalStableDebt, - userDataBeforeAction.stableBorrowRate, - userDataBeforeAction.stableRateLastUpdated, - txTimestamp - ); - - expectedReserveData.liquidityIndex = calcExpectedLiquidityIndex( - reserveDataBeforeAction, - txTimestamp - ); - - expectedReserveData.variableBorrowIndex = calcExpectedVariableBorrowIndex( - reserveDataBeforeAction, - txTimestamp - ); - - expectedReserveData.availableLiquidity = reserveDataBeforeAction.availableLiquidity; - - const totalStableDebtUntilTx = calcExpectedTotalStableDebt( - reserveDataBeforeAction.principalStableDebt, - reserveDataBeforeAction.averageStableBorrowRate, - reserveDataBeforeAction.totalStableDebtLastUpdated, - txTimestamp - ); - - if (rateMode === RateMode.Stable) { - //swap user stable debt to variable - expectedReserveData.scaledVariableDebt = reserveDataBeforeAction.scaledVariableDebt.plus( - stableDebt.rayDiv(expectedReserveData.variableBorrowIndex) - ); - - expectedReserveData.totalVariableDebt = expectedReserveData.scaledVariableDebt.rayMul( - expectedReserveData.variableBorrowIndex - ); - - expectedReserveData.principalStableDebt = expectedReserveData.totalStableDebt = totalStableDebtUntilTx.minus( - stableDebt - ); - - expectedReserveData.averageStableBorrowRate = calcExpectedAverageStableBorrowRate( - reserveDataBeforeAction.averageStableBorrowRate, - expectedReserveData.principalStableDebt.plus(stableDebt), - stableDebt.negated(), - userDataBeforeAction.stableBorrowRate - ); - } else { - //swap variable to stable - - expectedReserveData.principalStableDebt = expectedReserveData.totalStableDebt = totalStableDebtUntilTx.plus( - variableDebt - ); - - expectedReserveData.scaledVariableDebt = reserveDataBeforeAction.scaledVariableDebt.minus( - variableDebt.rayDiv(expectedReserveData.variableBorrowIndex) - ); - - expectedReserveData.totalVariableDebt = expectedReserveData.scaledVariableDebt.rayMul( - expectedReserveData.variableBorrowIndex - ); - - expectedReserveData.averageStableBorrowRate = calcExpectedAverageStableBorrowRate( - reserveDataBeforeAction.averageStableBorrowRate, - reserveDataBeforeAction.totalStableDebt, - variableDebt, - reserveDataBeforeAction.stableBorrowRate - ); - } - - expectedReserveData.totalLiquidity = reserveDataBeforeAction.availableLiquidity - .plus(expectedReserveData.totalStableDebt) - .plus(expectedReserveData.totalVariableDebt); - - expectedReserveData.utilizationRate = calcExpectedUtilizationRate( - expectedReserveData.totalStableDebt, - expectedReserveData.totalVariableDebt, - expectedReserveData.totalLiquidity - ); - - const rates = calcExpectedInterestRates( - reserveDataBeforeAction.symbol, - reserveDataBeforeAction.marketStableRate, - expectedReserveData.utilizationRate, - expectedReserveData.totalStableDebt, - expectedReserveData.totalVariableDebt, - expectedReserveData.averageStableBorrowRate - ); - expectedReserveData.liquidityRate = rates[0]; - - expectedReserveData.stableBorrowRate = rates[1]; - - expectedReserveData.variableBorrowRate = rates[2]; - - return expectedReserveData; -}; - -export const calcExpectedUserDataAfterSwapRateMode = ( - reserveDataBeforeAction: ReserveData, - expectedDataAfterAction: ReserveData, - userDataBeforeAction: UserReserveData, - rateMode: string, - txCost: BigNumber, - txTimestamp: BigNumber -): UserReserveData => { - const expectedUserData = { ...userDataBeforeAction }; - - const stableDebtBalance = calcExpectedStableDebtTokenBalance( - userDataBeforeAction.principalStableDebt, - userDataBeforeAction.stableBorrowRate, - userDataBeforeAction.stableRateLastUpdated, - txTimestamp - ); - - const variableDebtBalance = calcExpectedVariableDebtTokenBalance( - reserveDataBeforeAction, - userDataBeforeAction, - txTimestamp - ); - - expectedUserData.currentATokenBalance = calcExpectedATokenBalance( - reserveDataBeforeAction, - userDataBeforeAction, - txTimestamp - ); - - if (rateMode === RateMode.Stable) { - // swap to variable - expectedUserData.currentStableDebt = expectedUserData.principalStableDebt = new BigNumber(0); - - expectedUserData.stableBorrowRate = new BigNumber(0); - - expectedUserData.scaledVariableDebt = userDataBeforeAction.scaledVariableDebt.plus( - stableDebtBalance.rayDiv(expectedDataAfterAction.variableBorrowIndex) - ); - expectedUserData.currentVariableDebt = expectedUserData.scaledVariableDebt.rayMul( - expectedDataAfterAction.variableBorrowIndex - ); - - expectedUserData.stableRateLastUpdated = new BigNumber(0); - } else { - expectedUserData.principalStableDebt = expectedUserData.currentStableDebt = userDataBeforeAction.currentStableDebt.plus( - variableDebtBalance - ); - - //weighted average of the previous and the current - expectedUserData.stableBorrowRate = calcExpectedUserStableRate( - stableDebtBalance, - userDataBeforeAction.stableBorrowRate, - variableDebtBalance, - reserveDataBeforeAction.stableBorrowRate - ); - - expectedUserData.stableRateLastUpdated = txTimestamp; - - expectedUserData.currentVariableDebt = expectedUserData.scaledVariableDebt = new BigNumber(0); - } - - expectedUserData.liquidityRate = expectedDataAfterAction.liquidityRate; - - return expectedUserData; -}; - -export const calcExpectedReserveDataAfterStableRateRebalance = ( - reserveDataBeforeAction: ReserveData, - userDataBeforeAction: UserReserveData, - txTimestamp: BigNumber -): ReserveData => { - const expectedReserveData: ReserveData = {}; - - expectedReserveData.address = reserveDataBeforeAction.address; - - const userStableDebt = calcExpectedStableDebtTokenBalance( - userDataBeforeAction.principalStableDebt, - userDataBeforeAction.stableBorrowRate, - userDataBeforeAction.stableRateLastUpdated, - txTimestamp - ); - - expectedReserveData.liquidityIndex = calcExpectedLiquidityIndex( - reserveDataBeforeAction, - txTimestamp - ); - - expectedReserveData.variableBorrowIndex = calcExpectedVariableBorrowIndex( - reserveDataBeforeAction, - txTimestamp - ); - - expectedReserveData.scaledVariableDebt = reserveDataBeforeAction.scaledVariableDebt; - expectedReserveData.totalVariableDebt = expectedReserveData.scaledVariableDebt.rayMul( - expectedReserveData.variableBorrowIndex - ); - - expectedReserveData.principalStableDebt = expectedReserveData.totalStableDebt = calcExpectedTotalStableDebt( - reserveDataBeforeAction.principalStableDebt, - reserveDataBeforeAction.averageStableBorrowRate, - reserveDataBeforeAction.totalStableDebtLastUpdated, - txTimestamp - ); - - expectedReserveData.availableLiquidity = reserveDataBeforeAction.availableLiquidity; - - expectedReserveData.totalLiquidity = expectedReserveData.availableLiquidity - .plus(expectedReserveData.totalStableDebt) - .plus(expectedReserveData.totalVariableDebt); - - //removing the stable liquidity at the old rate - - const avgRateBefore = calcExpectedAverageStableBorrowRateRebalance( - reserveDataBeforeAction.averageStableBorrowRate, - expectedReserveData.totalStableDebt, - userStableDebt.negated(), - userDataBeforeAction.stableBorrowRate - ); - // adding it again at the new rate - - expectedReserveData.averageStableBorrowRate = calcExpectedAverageStableBorrowRateRebalance( - avgRateBefore, - expectedReserveData.totalStableDebt.minus(userStableDebt), - userStableDebt, - reserveDataBeforeAction.stableBorrowRate - ); - - expectedReserveData.utilizationRate = calcExpectedUtilizationRate( - expectedReserveData.totalStableDebt, - expectedReserveData.totalVariableDebt, - expectedReserveData.totalLiquidity - ); - - const rates = calcExpectedInterestRates( - reserveDataBeforeAction.symbol, - reserveDataBeforeAction.marketStableRate, - expectedReserveData.utilizationRate, - expectedReserveData.totalStableDebt, - expectedReserveData.totalVariableDebt, - expectedReserveData.averageStableBorrowRate - ); - - expectedReserveData.liquidityRate = rates[0]; - - expectedReserveData.stableBorrowRate = rates[1]; - - expectedReserveData.variableBorrowRate = rates[2]; - - return expectedReserveData; -}; - -export const calcExpectedUserDataAfterStableRateRebalance = ( - reserveDataBeforeAction: ReserveData, - expectedDataAfterAction: ReserveData, - userDataBeforeAction: UserReserveData, - txCost: BigNumber, - txTimestamp: BigNumber -): UserReserveData => { - const expectedUserData = { ...userDataBeforeAction }; - - expectedUserData.principalStableDebt = userDataBeforeAction.principalStableDebt; - - expectedUserData.principalVariableDebt = calcExpectedVariableDebtTokenBalance( - reserveDataBeforeAction, - userDataBeforeAction, - txTimestamp - ); - expectedUserData.currentStableDebt = expectedUserData.principalStableDebt = calcExpectedStableDebtTokenBalance( - userDataBeforeAction.principalStableDebt, - userDataBeforeAction.stableBorrowRate, - userDataBeforeAction.stableRateLastUpdated, - txTimestamp - ); - - expectedUserData.currentVariableDebt = calcExpectedVariableDebtTokenBalance( - reserveDataBeforeAction, - userDataBeforeAction, - txTimestamp - ); - - expectedUserData.stableRateLastUpdated = txTimestamp; - - expectedUserData.principalVariableDebt = userDataBeforeAction.principalVariableDebt; - - // Stable rate after burn - expectedUserData.stableBorrowRate = expectedDataAfterAction.averageStableBorrowRate; - expectedUserData.liquidityRate = expectedDataAfterAction.liquidityRate; - - expectedUserData.currentATokenBalance = calcExpectedATokenBalance( - reserveDataBeforeAction, - userDataBeforeAction, - txTimestamp - ); - - return expectedUserData; -}; - -const calcExpectedScaledATokenBalance = ( - userDataBeforeAction: UserReserveData, - index: BigNumber, - amountAdded: BigNumber, - amountTaken: BigNumber -) => { - return userDataBeforeAction.scaledATokenBalance - .plus(amountAdded.rayDiv(index)) - .minus(amountTaken.rayDiv(index)); -}; - -export const calcExpectedATokenBalance = ( - reserveData: ReserveData, - userData: UserReserveData, - currentTimestamp: BigNumber -) => { - const index = calcExpectedReserveNormalizedIncome(reserveData, currentTimestamp); - - const { scaledATokenBalance: scaledBalanceBeforeAction } = userData; - - return scaledBalanceBeforeAction.rayMul(index); -}; - -const calcExpectedAverageStableBorrowRate = ( - avgStableRateBefore: BigNumber, - totalStableDebtBefore: BigNumber, - amountChanged: string | BigNumber, - rate: BigNumber -) => { - const weightedTotalBorrows = avgStableRateBefore.multipliedBy(totalStableDebtBefore); - const weightedAmountBorrowed = rate.multipliedBy(amountChanged); - const totalBorrowedStable = totalStableDebtBefore.plus(amountChanged); - - if (totalBorrowedStable.eq(0)) return new BigNumber('0'); - - return weightedTotalBorrows - .plus(weightedAmountBorrowed) - .div(totalBorrowedStable) - .decimalPlaces(0, BigNumber.ROUND_DOWN); -}; - -const calcExpectedAverageStableBorrowRateRebalance = ( - avgStableRateBefore: BigNumber, - totalStableDebtBefore: BigNumber, - amountChanged: BigNumber, - rate: BigNumber -) => { - const weightedTotalBorrows = avgStableRateBefore.rayMul(totalStableDebtBefore); - const weightedAmountBorrowed = rate.rayMul(amountChanged.wadToRay()); - const totalBorrowedStable = totalStableDebtBefore.plus(amountChanged.wadToRay()); - - if (totalBorrowedStable.eq(0)) return new BigNumber('0'); - - return weightedTotalBorrows - .plus(weightedAmountBorrowed) - .rayDiv(totalBorrowedStable) - .decimalPlaces(0, BigNumber.ROUND_DOWN); -}; - -export const calcExpectedVariableDebtTokenBalance = ( - reserveData: ReserveData, - userData: UserReserveData, - currentTimestamp: BigNumber -) => { - const normalizedDebt = calcExpectedReserveNormalizedDebt( - reserveData.variableBorrowRate, - reserveData.variableBorrowIndex, - reserveData.lastUpdateTimestamp, - currentTimestamp - ); - - const { scaledVariableDebt } = userData; - - return scaledVariableDebt.rayMul(normalizedDebt); -}; - -export const calcExpectedStableDebtTokenBalance = ( - principalStableDebt: BigNumber, - stableBorrowRate: BigNumber, - stableRateLastUpdated: BigNumber, - currentTimestamp: BigNumber -) => { - if ( - stableBorrowRate.eq(0) || - currentTimestamp.eq(stableRateLastUpdated) || - stableRateLastUpdated.eq(0) - ) { - return principalStableDebt; - } - - const cumulatedInterest = calcCompoundedInterest( - stableBorrowRate, - currentTimestamp, - stableRateLastUpdated - ); - - return principalStableDebt.rayMul(cumulatedInterest); -}; - -const calcLinearInterest = ( - rate: BigNumber, - currentTimestamp: BigNumber, - lastUpdateTimestamp: BigNumber -) => { - const timeDifference = currentTimestamp.minus(lastUpdateTimestamp); - - const cumulatedInterest = rate - .multipliedBy(timeDifference) - .dividedBy(new BigNumber(ONE_YEAR)) - .plus(RAY); - - return cumulatedInterest; -}; - -const calcCompoundedInterest = ( - rate: BigNumber, - currentTimestamp: BigNumber, - lastUpdateTimestamp: BigNumber -) => { - const timeDifference = currentTimestamp.minus(lastUpdateTimestamp); - - if (timeDifference.eq(0)) { - return new BigNumber(RAY); - } - - const expMinusOne = timeDifference.minus(1); - const expMinusTwo = timeDifference.gt(2) ? timeDifference.minus(2) : 0; - - const ratePerSecond = rate.div(ONE_YEAR); - - const basePowerTwo = ratePerSecond.rayMul(ratePerSecond); - const basePowerThree = basePowerTwo.rayMul(ratePerSecond); - - const secondTerm = timeDifference.times(expMinusOne).times(basePowerTwo).div(2); - const thirdTerm = timeDifference - .times(expMinusOne) - .times(expMinusTwo) - .times(basePowerThree) - .div(6); - - return new BigNumber(RAY) - .plus(ratePerSecond.times(timeDifference)) - .plus(secondTerm) - .plus(thirdTerm); -}; - -export const calcExpectedInterestRates = ( - reserveSymbol: string, - marketStableRate: BigNumber, - utilizationRate: BigNumber, - totalStableDebt: BigNumber, - totalVariableDebt: BigNumber, - averageStableBorrowRate: BigNumber -): BigNumber[] => { - const { reservesParams } = configuration; - - const reserveIndex = Object.keys(reservesParams).findIndex((value) => value === reserveSymbol); - const [, reserveConfiguration] = (Object.entries(reservesParams) as [string, IReserveParams][])[ - reserveIndex - ]; - - let stableBorrowRate: BigNumber = marketStableRate; - let variableBorrowRate: BigNumber = new BigNumber(reserveConfiguration.strategy.baseVariableBorrowRate); - - const optimalRate = new BigNumber(reserveConfiguration.strategy.optimalUtilizationRate); - const excessRate = new BigNumber(RAY).minus(optimalRate); - if (utilizationRate.gt(optimalRate)) { - const excessUtilizationRateRatio = utilizationRate - .minus(reserveConfiguration.strategy.optimalUtilizationRate) - .rayDiv(excessRate); - - stableBorrowRate = stableBorrowRate - .plus(reserveConfiguration.strategy.stableRateSlope1) - .plus( - new BigNumber(reserveConfiguration.strategy.stableRateSlope2).rayMul(excessUtilizationRateRatio) - ); - - variableBorrowRate = variableBorrowRate - .plus(reserveConfiguration.strategy.variableRateSlope1) - .plus( - new BigNumber(reserveConfiguration.strategy.variableRateSlope2).rayMul(excessUtilizationRateRatio) - ); - } else { - stableBorrowRate = stableBorrowRate.plus( - new BigNumber(reserveConfiguration.strategy.stableRateSlope1).rayMul( - utilizationRate.rayDiv(new BigNumber(optimalRate)) - ) - ); - - variableBorrowRate = variableBorrowRate.plus( - utilizationRate - .rayDiv(optimalRate) - .rayMul(new BigNumber(reserveConfiguration.strategy.variableRateSlope1)) - ); - } - - const expectedOverallRate = calcExpectedOverallBorrowRate( - totalStableDebt, - totalVariableDebt, - variableBorrowRate, - averageStableBorrowRate - ); - const liquidityRate = expectedOverallRate - .rayMul(utilizationRate) - .percentMul(new BigNumber(PERCENTAGE_FACTOR).minus(reserveConfiguration.reserveFactor)); - - return [liquidityRate, stableBorrowRate, variableBorrowRate]; -}; - -export const calcExpectedOverallBorrowRate = ( - totalStableDebt: BigNumber, - totalVariableDebt: BigNumber, - currentVariableBorrowRate: BigNumber, - currentAverageStableBorrowRate: BigNumber -): BigNumber => { - const totalBorrows = totalStableDebt.plus(totalVariableDebt); - - if (totalBorrows.eq(0)) return strToBN('0'); - - const weightedVariableRate = totalVariableDebt.wadToRay().rayMul(currentVariableBorrowRate); - - const weightedStableRate = totalStableDebt.wadToRay().rayMul(currentAverageStableBorrowRate); - - const overallBorrowRate = weightedVariableRate - .plus(weightedStableRate) - .rayDiv(totalBorrows.wadToRay()); - - return overallBorrowRate; -}; - -export const calcExpectedUtilizationRate = ( - totalStableDebt: BigNumber, - totalVariableDebt: BigNumber, - totalLiquidity: BigNumber -): BigNumber => { - if (totalStableDebt.eq('0') && totalVariableDebt.eq('0')) { - return strToBN('0'); - } - - const utilization = totalStableDebt.plus(totalVariableDebt).rayDiv(totalLiquidity); - - return utilization; -}; - -const calcExpectedReserveNormalizedIncome = ( - reserveData: ReserveData, - currentTimestamp: BigNumber -) => { - const { liquidityRate, liquidityIndex, lastUpdateTimestamp } = reserveData; - - //if utilization rate is 0, nothing to compound - if (liquidityRate.eq('0')) { - return liquidityIndex; - } - - const cumulatedInterest = calcLinearInterest( - liquidityRate, - currentTimestamp, - lastUpdateTimestamp - ); - - const income = cumulatedInterest.rayMul(liquidityIndex); - - return income; -}; - -const calcExpectedReserveNormalizedDebt = ( - variableBorrowRate: BigNumber, - variableBorrowIndex: BigNumber, - lastUpdateTimestamp: BigNumber, - currentTimestamp: BigNumber -) => { - //if utilization rate is 0, nothing to compound - if (variableBorrowRate.eq('0')) { - return variableBorrowIndex; - } - - const cumulatedInterest = calcCompoundedInterest( - variableBorrowRate, - currentTimestamp, - lastUpdateTimestamp - ); - - const debt = cumulatedInterest.rayMul(variableBorrowIndex); - - return debt; -}; - -const calcExpectedUserStableRate = ( - balanceBefore: BigNumber, - rateBefore: BigNumber, - amount: BigNumber, - rateNew: BigNumber -) => { - return balanceBefore - .times(rateBefore) - .plus(amount.times(rateNew)) - .div(balanceBefore.plus(amount)); -}; - -const calcExpectedLiquidityIndex = (reserveData: ReserveData, timestamp: BigNumber) => { - //if utilization rate is 0, nothing to compound - if (reserveData.utilizationRate.eq('0')) { - return reserveData.liquidityIndex; - } - - const cumulatedInterest = calcLinearInterest( - reserveData.liquidityRate, - timestamp, - reserveData.lastUpdateTimestamp - ); - - return cumulatedInterest.rayMul(reserveData.liquidityIndex); -}; - -const calcExpectedVariableBorrowIndex = (reserveData: ReserveData, timestamp: BigNumber) => { - //if totalVariableDebt is 0, nothing to compound - if (reserveData.totalVariableDebt.eq('0')) { - return reserveData.variableBorrowIndex; - } - - const cumulatedInterest = calcCompoundedInterest( - reserveData.variableBorrowRate, - timestamp, - reserveData.lastUpdateTimestamp - ); - - return cumulatedInterest.rayMul(reserveData.variableBorrowIndex); -}; - -const calcExpectedTotalStableDebt = ( - principalStableDebt: BigNumber, - averageStableBorrowRate: BigNumber, - lastUpdateTimestamp: BigNumber, - currentTimestamp: BigNumber -) => { - const cumulatedInterest = calcCompoundedInterest( - averageStableBorrowRate, - currentTimestamp, - lastUpdateTimestamp - ); - - return cumulatedInterest.rayMul(principalStableDebt); -}; - -const calcExpectedTotalVariableDebt = ( - reserveData: ReserveData, - expectedVariableDebtIndex: BigNumber -) => { - return reserveData.scaledVariableDebt.rayMul(expectedVariableDebtIndex); -}; diff --git a/test/helpers/utils/helpers.ts b/test/helpers/utils/helpers.ts deleted file mode 100644 index fc7a9709..00000000 --- a/test/helpers/utils/helpers.ts +++ /dev/null @@ -1,128 +0,0 @@ -import { LendingPool } from '../../../types/LendingPool'; -import { ReserveData, UserReserveData } from './interfaces'; -import { - getLendingRateOracle, - getIErc20Detailed, - getMintableERC20, - getAToken, - getStableDebtToken, - getVariableDebtToken, -} from '../../../helpers/contracts-getters'; -import { tEthereumAddress } from '../../../helpers/types'; -import BigNumber from 'bignumber.js'; -import { getDb, DRE } from '../../../helpers/misc-utils'; -import { AaveProtocolDataProvider } from '../../../types/AaveProtocolDataProvider'; - -export const getReserveData = async ( - helper: AaveProtocolDataProvider, - reserve: tEthereumAddress -): Promise => { - const [reserveData, tokenAddresses, rateOracle, token] = await Promise.all([ - helper.getReserveData(reserve), - helper.getReserveTokensAddresses(reserve), - getLendingRateOracle(), - getIErc20Detailed(reserve), - ]); - - const stableDebtToken = await getStableDebtToken(tokenAddresses.stableDebtTokenAddress); - const variableDebtToken = await getVariableDebtToken(tokenAddresses.variableDebtTokenAddress); - - const { 0: principalStableDebt } = await stableDebtToken.getSupplyData(); - const totalStableDebtLastUpdated = await stableDebtToken.getTotalSupplyLastUpdated(); - - const scaledVariableDebt = await variableDebtToken.scaledTotalSupply(); - - const rate = (await rateOracle.getMarketBorrowRate(reserve)).toString(); - const symbol = await token.symbol(); - const decimals = new BigNumber(await token.decimals()); - - const totalLiquidity = new BigNumber(reserveData.availableLiquidity.toString()) - .plus(reserveData.totalStableDebt.toString()) - .plus(reserveData.totalVariableDebt.toString()); - - const utilizationRate = new BigNumber( - totalLiquidity.eq(0) - ? 0 - : new BigNumber(reserveData.totalStableDebt.toString()) - .plus(reserveData.totalVariableDebt.toString()) - .rayDiv(totalLiquidity) - ); - - return { - totalLiquidity, - utilizationRate, - availableLiquidity: new BigNumber(reserveData.availableLiquidity.toString()), - totalStableDebt: new BigNumber(reserveData.totalStableDebt.toString()), - totalVariableDebt: new BigNumber(reserveData.totalVariableDebt.toString()), - liquidityRate: new BigNumber(reserveData.liquidityRate.toString()), - variableBorrowRate: new BigNumber(reserveData.variableBorrowRate.toString()), - stableBorrowRate: new BigNumber(reserveData.stableBorrowRate.toString()), - averageStableBorrowRate: new BigNumber(reserveData.averageStableBorrowRate.toString()), - liquidityIndex: new BigNumber(reserveData.liquidityIndex.toString()), - variableBorrowIndex: new BigNumber(reserveData.variableBorrowIndex.toString()), - lastUpdateTimestamp: new BigNumber(reserveData.lastUpdateTimestamp), - totalStableDebtLastUpdated: new BigNumber(totalStableDebtLastUpdated), - principalStableDebt: new BigNumber(principalStableDebt.toString()), - scaledVariableDebt: new BigNumber(scaledVariableDebt.toString()), - address: reserve, - aTokenAddress: tokenAddresses.aTokenAddress, - symbol, - decimals, - marketStableRate: new BigNumber(rate), - }; -}; - -export const getUserData = async ( - pool: LendingPool, - helper: AaveProtocolDataProvider, - reserve: string, - user: tEthereumAddress, - sender?: tEthereumAddress -): Promise => { - const [userData, scaledATokenBalance] = await Promise.all([ - helper.getUserReserveData(reserve, user), - getATokenUserData(reserve, user, helper), - ]); - - const token = await getMintableERC20(reserve); - const walletBalance = new BigNumber((await token.balanceOf(sender || user)).toString()); - - return { - scaledATokenBalance: new BigNumber(scaledATokenBalance), - currentATokenBalance: new BigNumber(userData.currentATokenBalance.toString()), - currentStableDebt: new BigNumber(userData.currentStableDebt.toString()), - currentVariableDebt: new BigNumber(userData.currentVariableDebt.toString()), - principalStableDebt: new BigNumber(userData.principalStableDebt.toString()), - scaledVariableDebt: new BigNumber(userData.scaledVariableDebt.toString()), - stableBorrowRate: new BigNumber(userData.stableBorrowRate.toString()), - liquidityRate: new BigNumber(userData.liquidityRate.toString()), - usageAsCollateralEnabled: userData.usageAsCollateralEnabled, - stableRateLastUpdated: new BigNumber(userData.stableRateLastUpdated.toString()), - walletBalance, - }; -}; - -export const getReserveAddressFromSymbol = async (symbol: string) => { - const token = await getMintableERC20( - (await getDb().get(`${symbol}.${DRE.network.name}`).value()).address - ); - - if (!token) { - throw `Could not find instance for contract ${symbol}`; - } - return token.address; -}; - -const getATokenUserData = async ( - reserve: string, - user: string, - helpersContract: AaveProtocolDataProvider -) => { - const aTokenAddress: string = (await helpersContract.getReserveTokensAddresses(reserve)) - .aTokenAddress; - - const aToken = await getAToken(aTokenAddress); - - const scaledBalance = await aToken.scaledBalanceOf(user); - return scaledBalance.toString(); -}; diff --git a/test/helpers/utils/interfaces/index.ts b/test/helpers/utils/interfaces/index.ts deleted file mode 100644 index 17660fcc..00000000 --- a/test/helpers/utils/interfaces/index.ts +++ /dev/null @@ -1,40 +0,0 @@ -import BigNumber from 'bignumber.js'; - -export interface UserReserveData { - scaledATokenBalance: BigNumber; - currentATokenBalance: BigNumber; - currentStableDebt: BigNumber; - currentVariableDebt: BigNumber; - principalStableDebt: BigNumber; - scaledVariableDebt: BigNumber; - liquidityRate: BigNumber; - stableBorrowRate: BigNumber; - stableRateLastUpdated: BigNumber; - usageAsCollateralEnabled: Boolean; - walletBalance: BigNumber; - [key: string]: BigNumber | string | Boolean; -} - -export interface ReserveData { - address: string; - symbol: string; - decimals: BigNumber; - totalLiquidity: BigNumber; - availableLiquidity: BigNumber; - totalStableDebt: BigNumber; - totalVariableDebt: BigNumber; - principalStableDebt: BigNumber; - scaledVariableDebt: BigNumber; - averageStableBorrowRate: BigNumber; - variableBorrowRate: BigNumber; - stableBorrowRate: BigNumber; - utilizationRate: BigNumber; - liquidityIndex: BigNumber; - variableBorrowIndex: BigNumber; - aTokenAddress: string; - marketStableRate: BigNumber; - lastUpdateTimestamp: BigNumber; - totalStableDebtLastUpdated: BigNumber; - liquidityRate: BigNumber; - [key: string]: BigNumber | string; -} diff --git a/test/helpers/utils/math.ts b/test/helpers/utils/math.ts deleted file mode 100644 index efd296e0..00000000 --- a/test/helpers/utils/math.ts +++ /dev/null @@ -1,97 +0,0 @@ -import BigNumber from 'bignumber.js'; -import { - RAY, - WAD, - HALF_RAY, - HALF_WAD, - WAD_RAY_RATIO, - HALF_PERCENTAGE, - PERCENTAGE_FACTOR, -} from '../../../helpers/constants'; - -declare module 'bignumber.js' { - interface BigNumber { - ray: () => BigNumber; - wad: () => BigNumber; - halfRay: () => BigNumber; - halfWad: () => BigNumber; - halfPercentage: () => BigNumber; - wadMul: (a: BigNumber) => BigNumber; - wadDiv: (a: BigNumber) => BigNumber; - rayMul: (a: BigNumber) => BigNumber; - rayDiv: (a: BigNumber) => BigNumber; - percentMul: (a: BigNumber) => BigNumber; - percentDiv: (a: BigNumber) => BigNumber; - rayToWad: () => BigNumber; - wadToRay: () => BigNumber; - } -} - -BigNumber.prototype.ray = (): BigNumber => { - return new BigNumber(RAY).decimalPlaces(0); -}; -BigNumber.prototype.wad = (): BigNumber => { - return new BigNumber(WAD).decimalPlaces(0); -}; - -BigNumber.prototype.halfRay = (): BigNumber => { - return new BigNumber(HALF_RAY).decimalPlaces(0, BigNumber.ROUND_DOWN); -}; - -BigNumber.prototype.halfWad = (): BigNumber => { - return new BigNumber(HALF_WAD).decimalPlaces(0, BigNumber.ROUND_DOWN); -}; - -BigNumber.prototype.wadMul = function (b: BigNumber): BigNumber { - return this.halfWad().plus(this.multipliedBy(b)).div(WAD).decimalPlaces(0, BigNumber.ROUND_DOWN); -}; - -BigNumber.prototype.wadDiv = function (a: BigNumber): BigNumber { - const halfA = a.div(2).decimalPlaces(0, BigNumber.ROUND_DOWN); - - return halfA.plus(this.multipliedBy(WAD)).div(a).decimalPlaces(0, BigNumber.ROUND_DOWN); -}; - -BigNumber.prototype.rayMul = function (a: BigNumber): BigNumber { - return this.halfRay().plus(this.multipliedBy(a)).div(RAY).decimalPlaces(0, BigNumber.ROUND_DOWN); -}; - -BigNumber.prototype.rayDiv = function (a: BigNumber): BigNumber { - const halfA = a.div(2).decimalPlaces(0, BigNumber.ROUND_DOWN); - - return halfA - .plus(this.multipliedBy(RAY)) - .decimalPlaces(0, BigNumber.ROUND_DOWN) - .div(a) - .decimalPlaces(0, BigNumber.ROUND_DOWN); -}; - -BigNumber.prototype.rayToWad = function (): BigNumber { - const halfRatio = new BigNumber(WAD_RAY_RATIO).div(2); - - return halfRatio.plus(this).div(WAD_RAY_RATIO).decimalPlaces(0, BigNumber.ROUND_DOWN); -}; - -BigNumber.prototype.wadToRay = function (): BigNumber { - return this.multipliedBy(WAD_RAY_RATIO).decimalPlaces(0, BigNumber.ROUND_DOWN); -}; - -BigNumber.prototype.halfPercentage = (): BigNumber => { - return new BigNumber(HALF_PERCENTAGE).decimalPlaces(0, BigNumber.ROUND_DOWN); -}; - -BigNumber.prototype.percentMul = function (b: BigNumber): BigNumber { - return this.halfPercentage() - .plus(this.multipliedBy(b)) - .div(PERCENTAGE_FACTOR) - .decimalPlaces(0, BigNumber.ROUND_DOWN); -}; - -BigNumber.prototype.percentDiv = function (a: BigNumber): BigNumber { - const halfA = a.div(2).decimalPlaces(0, BigNumber.ROUND_DOWN); - - return halfA - .plus(this.multipliedBy(PERCENTAGE_FACTOR)) - .div(a) - .decimalPlaces(0, BigNumber.ROUND_DOWN); -}; diff --git a/test/lending-pool-addresses-provider.spec.ts b/test/lending-pool-addresses-provider.spec.ts deleted file mode 100644 index 48570458..00000000 --- a/test/lending-pool-addresses-provider.spec.ts +++ /dev/null @@ -1,101 +0,0 @@ -import { expect } from 'chai'; -import { createRandomAddress } from '../helpers/misc-utils'; -import { makeSuite, TestEnv } from './helpers/make-suite'; -import { ProtocolErrors } from '../helpers/types'; -import { ethers } from 'ethers'; -import { ZERO_ADDRESS } from '../helpers/constants'; -import { waitForTx } from '../helpers/misc-utils'; -import { deployLendingPool } from '../helpers/contracts-deployments'; - -const { utils } = ethers; - -makeSuite('LendingPoolAddressesProvider', (testEnv: TestEnv) => { - it('Test the accessibility of the LendingPoolAddressesProvider', async () => { - const { addressesProvider, users } = testEnv; - const mockAddress = createRandomAddress(); - const { INVALID_OWNER_REVERT_MSG } = ProtocolErrors; - - await addressesProvider.transferOwnership(users[1].address); - - for (const contractFunction of [ - addressesProvider.setMarketId, - addressesProvider.setLendingPoolImpl, - addressesProvider.setLendingPoolConfiguratorImpl, - addressesProvider.setLendingPoolCollateralManager, - addressesProvider.setPoolAdmin, - addressesProvider.setPriceOracle, - addressesProvider.setLendingRateOracle, - ]) { - await expect(contractFunction(mockAddress)).to.be.revertedWith(INVALID_OWNER_REVERT_MSG); - } - - await expect( - addressesProvider.setAddress(utils.keccak256(utils.toUtf8Bytes('RANDOM_ID')), mockAddress) - ).to.be.revertedWith(INVALID_OWNER_REVERT_MSG); - - await expect( - addressesProvider.setAddressAsProxy( - utils.keccak256(utils.toUtf8Bytes('RANDOM_ID')), - mockAddress - ) - ).to.be.revertedWith(INVALID_OWNER_REVERT_MSG); - }); - - it('Tests adding a proxied address with `setAddressAsProxy()`', async () => { - const { addressesProvider, users } = testEnv; - const { INVALID_OWNER_REVERT_MSG } = ProtocolErrors; - - const currentAddressesProviderOwner = users[1]; - - const mockLendingPool = await deployLendingPool(); - const proxiedAddressId = utils.keccak256(utils.toUtf8Bytes('RANDOM_PROXIED')); - - const proxiedAddressSetReceipt = await waitForTx( - await addressesProvider - .connect(currentAddressesProviderOwner.signer) - .setAddressAsProxy(proxiedAddressId, mockLendingPool.address) - ); - - if (!proxiedAddressSetReceipt.events || proxiedAddressSetReceipt.events?.length < 1) { - throw new Error('INVALID_EVENT_EMMITED'); - } - - expect(proxiedAddressSetReceipt.events[0].event).to.be.equal('ProxyCreated'); - expect(proxiedAddressSetReceipt.events[1].event).to.be.equal('AddressSet'); - expect(proxiedAddressSetReceipt.events[1].args?.id).to.be.equal(proxiedAddressId); - expect(proxiedAddressSetReceipt.events[1].args?.newAddress).to.be.equal( - mockLendingPool.address - ); - expect(proxiedAddressSetReceipt.events[1].args?.hasProxy).to.be.equal(true); - }); - - it('Tests adding a non proxied address with `setAddress()`', async () => { - const { addressesProvider, users } = testEnv; - const { INVALID_OWNER_REVERT_MSG } = ProtocolErrors; - - const currentAddressesProviderOwner = users[1]; - const mockNonProxiedAddress = createRandomAddress(); - const nonProxiedAddressId = utils.keccak256(utils.toUtf8Bytes('RANDOM_NON_PROXIED')); - - const nonProxiedAddressSetReceipt = await waitForTx( - await addressesProvider - .connect(currentAddressesProviderOwner.signer) - .setAddress(nonProxiedAddressId, mockNonProxiedAddress) - ); - - expect(mockNonProxiedAddress.toLowerCase()).to.be.equal( - (await addressesProvider.getAddress(nonProxiedAddressId)).toLowerCase() - ); - - if (!nonProxiedAddressSetReceipt.events || nonProxiedAddressSetReceipt.events?.length < 1) { - throw new Error('INVALID_EVENT_EMMITED'); - } - - expect(nonProxiedAddressSetReceipt.events[0].event).to.be.equal('AddressSet'); - expect(nonProxiedAddressSetReceipt.events[0].args?.id).to.be.equal(nonProxiedAddressId); - expect(nonProxiedAddressSetReceipt.events[0].args?.newAddress).to.be.equal( - mockNonProxiedAddress - ); - expect(nonProxiedAddressSetReceipt.events[0].args?.hasProxy).to.be.equal(false); - }); -}); diff --git a/test/liquidation-atoken.spec.ts b/test/liquidation-atoken.spec.ts deleted file mode 100644 index 6483162c..00000000 --- a/test/liquidation-atoken.spec.ts +++ /dev/null @@ -1,379 +0,0 @@ -import BigNumber from 'bignumber.js'; - -import { DRE } 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 { calcExpectedVariableDebtTokenBalance } from './helpers/utils/calculations'; -import { getUserData, getReserveData } from './helpers/utils/helpers'; - -const chai = require('chai'); -const { expect } = chai; - -makeSuite('LendingPool liquidation - liquidator receiving aToken', (testEnv) => { - const { - LPCM_HEALTH_FACTOR_NOT_BELOW_THRESHOLD, - INVALID_HF, - LPCM_SPECIFIED_CURRENCY_NOT_BORROWED_BY_USER, - LPCM_COLLATERAL_CANNOT_BE_LIQUIDATED, - LP_IS_PAUSED, - } = ProtocolErrors; - - it('Deposits WETH, borrows DAI/Check liquidation fails because health factor is above 1', 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'); - - const amountETHtoDeposit = await convertToCurrencyDecimals(weth.address, '1'); - - //mints WETH to borrower - await weth.connect(borrower.signer).mint(amountETHtoDeposit); - - //approve protocol to access borrower wallet - await weth.connect(borrower.signer).approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL); - - //user 2 deposits 1 WETH - 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.Variable, '0', borrower.address); - - const userGlobalDataAfter = await pool.getUserAccountData(borrower.address); - - expect(userGlobalDataAfter.currentLiquidationThreshold.toString()).to.be.bignumber.equal( - '8250', - 'Invalid liquidation threshold' - ); - - //someone tries to liquidate user 2 - await expect( - pool.liquidationCall(weth.address, dai.address, borrower.address, 1, true) - ).to.be.revertedWith(LPCM_HEALTH_FACTOR_NOT_BELOW_THRESHOLD); - }); - - it('Drop the health factor below 1', async () => { - const { dai, 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.15).toFixed(0) - ); - - const userGlobalData = await pool.getUserAccountData(borrower.address); - - expect(userGlobalData.healthFactor.toString()).to.be.bignumber.lt( - oneEther.toString(), - INVALID_HF - ); - }); - - it('Tries to liquidate a different currency than the loan principal', async () => { - const { pool, users, weth } = testEnv; - const borrower = users[1]; - //user 2 tries to borrow - await expect( - pool.liquidationCall(weth.address, weth.address, borrower.address, oneEther.toString(), true) - ).revertedWith(LPCM_SPECIFIED_CURRENCY_NOT_BORROWED_BY_USER); - }); - - it('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(LPCM_COLLATERAL_CANNOT_BE_LIQUIDATED); - }); - - it('Liquidates the borrow', async () => { - const { pool, dai, weth, aWETH, aDai, users, oracle, helpersContract, deployer } = 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(pool.address, APPROVAL_AMOUNT_LENDING_POOL); - - const daiReserveDataBefore = await getReserveData(helpersContract, dai.address); - const ethReserveDataBefore = await helpersContract.getReserveData(weth.address); - - const userReserveDataBefore = await getUserData( - pool, - helpersContract, - dai.address, - borrower.address - ); - - const amountToLiquidate = new BigNumber(userReserveDataBefore.currentVariableDebt.toString()) - .div(2) - .toFixed(0); - - const tx = await pool.liquidationCall( - weth.address, - dai.address, - borrower.address, - amountToLiquidate, - true - ); - - const userReserveDataAfter = await helpersContract.getUserReserveData( - dai.address, - borrower.address - ); - - const userGlobalDataAfter = await pool.getUserAccountData(borrower.address); - - const daiReserveDataAfter = await helpersContract.getReserveData(dai.address); - const ethReserveDataAfter = await helpersContract.getReserveData(weth.address); - - const collateralPrice = (await oracle.getAssetPrice(weth.address)).toString(); - const principalPrice = (await oracle.getAssetPrice(dai.address)).toString(); - - const collateralDecimals = ( - await helpersContract.getReserveConfigurationData(weth.address) - ).decimals.toString(); - const principalDecimals = ( - await helpersContract.getReserveConfigurationData(dai.address) - ).decimals.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); - - if (!tx.blockNumber) { - expect(false, 'Invalid block number'); - return; - } - - const txTimestamp = new BigNumber( - (await DRE.ethers.provider.getBlock(tx.blockNumber)).timestamp - ); - - const variableDebtBeforeTx = calcExpectedVariableDebtTokenBalance( - daiReserveDataBefore, - userReserveDataBefore, - txTimestamp - ); - - expect(userGlobalDataAfter.healthFactor.toString()).to.be.bignumber.gt( - oneEther.toFixed(0), - 'Invalid health factor' - ); - - expect(userReserveDataAfter.currentVariableDebt.toString()).to.be.bignumber.almostEqual( - new BigNumber(variableDebtBeforeTx).minus(amountToLiquidate).toFixed(0), - 'Invalid user borrow balance after liquidation' - ); - - expect(daiReserveDataAfter.availableLiquidity.toString()).to.be.bignumber.almostEqual( - new BigNumber(daiReserveDataBefore.availableLiquidity.toString()) - .plus(amountToLiquidate) - .toFixed(0), - 'Invalid principal available liquidity' - ); - - //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(ethReserveDataAfter.availableLiquidity.toString()).to.be.bignumber.almostEqual( - new BigNumber(ethReserveDataBefore.availableLiquidity.toString()).toFixed(0), - 'Invalid collateral available liquidity' - ); - - expect( - (await helpersContract.getUserReserveData(weth.address, deployer.address)) - .usageAsCollateralEnabled - ).to.be.true; - }); - - it('User 3 deposits 1000 USDC, user 4 1 WETH, user 4 borrows - drops HF, liquidates the borrow', async () => { - const { users, pool, usdc, oracle, weth, helpersContract } = 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(pool.address, APPROVAL_AMOUNT_LENDING_POOL); - - //user 3 deposits 1000 USDC - const amountUSDCtoDeposit = await convertToCurrencyDecimals(usdc.address, '1000'); - - await pool - .connect(depositor.signer) - .deposit(usdc.address, amountUSDCtoDeposit, depositor.address, '0'); - - //user 4 deposits 1 ETH - const amountETHtoDeposit = await convertToCurrencyDecimals(weth.address, '1'); - - //mints WETH to borrower - await weth.connect(borrower.signer).mint(amountETHtoDeposit); - - //approve protocol to access 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 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.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.mint(await convertToCurrencyDecimals(usdc.address, '1000')); - - //approve protocol to access depositor wallet - await usdc.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 = new BigNumber(userReserveDataBefore.currentStableDebt.toString()) - .multipliedBy(0.5) - .toFixed(0); - - await pool.liquidationCall( - weth.address, - usdc.address, - borrower.address, - amountToLiquidate, - true - ); - - 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)).toString(); - const principalPrice = (await oracle.getAssetPrice(usdc.address)).toString(); - - const collateralDecimals = ( - await helpersContract.getReserveConfigurationData(weth.address) - ).decimals.toString(); - const principalDecimals = ( - await helpersContract.getReserveConfigurationData(usdc.address) - ).decimals.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); - - 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' - ); - - expect(usdcReserveDataAfter.availableLiquidity.toString()).to.be.bignumber.almostEqual( - new BigNumber(usdcReserveDataBefore.availableLiquidity.toString()) - .plus(amountToLiquidate) - .toFixed(0), - 'Invalid principal available liquidity' - ); - - //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(ethReserveDataAfter.availableLiquidity.toString()).to.be.bignumber.almostEqual( - new BigNumber(ethReserveDataBefore.availableLiquidity.toString()).toFixed(0), - 'Invalid collateral available liquidity' - ); - }); -}); diff --git a/test/liquidation-underlying.spec.ts b/test/liquidation-underlying.spec.ts deleted file mode 100644 index 0e37d331..00000000 --- a/test/liquidation-underlying.spec.ts +++ /dev/null @@ -1,492 +0,0 @@ -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' - ); - }); -}); diff --git a/test/mainnet/check-list.spec.ts b/test/mainnet/check-list.spec.ts deleted file mode 100644 index 99020fa2..00000000 --- a/test/mainnet/check-list.spec.ts +++ /dev/null @@ -1,366 +0,0 @@ -import { MAX_UINT_AMOUNT } from '../../helpers/constants'; -import { convertToCurrencyDecimals } from '../../helpers/contracts-helpers'; -import { makeSuite, TestEnv } from '../helpers/make-suite'; -import { parseEther } from 'ethers/lib/utils'; -import { DRE, waitForTx } from '../../helpers/misc-utils'; -import { BigNumber } from 'ethers'; -import { getStableDebtToken, getVariableDebtToken } from '../../helpers/contracts-getters'; -import { deploySelfdestructTransferMock } from '../../helpers/contracts-deployments'; -import { IUniswapV2Router02Factory } from '../../types/IUniswapV2Router02Factory'; - -const { expect } = require('chai'); - -const UNISWAP_ROUTER = '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D'; - -makeSuite('Mainnet Check list', (testEnv: TestEnv) => { - const zero = BigNumber.from('0'); - const depositSize = parseEther('5'); - const daiSize = parseEther('10000'); - it('Deposit WETH', async () => { - const { users, wethGateway, aWETH, pool } = testEnv; - - const user = users[1]; - - // Deposit with native ETH - await wethGateway.connect(user.signer).depositETH(user.address, '0', { value: depositSize }); - - const aTokensBalance = await aWETH.balanceOf(user.address); - - expect(aTokensBalance).to.be.gt(zero); - expect(aTokensBalance).to.be.gte(depositSize); - }); - - it('Withdraw WETH - Partial', async () => { - const { users, wethGateway, aWETH, pool } = testEnv; - - const user = users[1]; - const priorEthersBalance = await user.signer.getBalance(); - const aTokensBalance = await aWETH.balanceOf(user.address); - - expect(aTokensBalance).to.be.gt(zero, 'User should have aTokens.'); - - // Partially withdraw native ETH - const partialWithdraw = await convertToCurrencyDecimals(aWETH.address, '2'); - - // Approve the aTokens to Gateway so Gateway can withdraw and convert to Ether - const approveTx = await aWETH - .connect(user.signer) - .approve(wethGateway.address, MAX_UINT_AMOUNT); - const { gasUsed: approveGas } = await waitForTx(approveTx); - - // Partial Withdraw and send native Ether to user - const { gasUsed: withdrawGas } = await waitForTx( - await wethGateway.connect(user.signer).withdrawETH(partialWithdraw, user.address) - ); - - const afterPartialEtherBalance = await user.signer.getBalance(); - const afterPartialATokensBalance = await aWETH.balanceOf(user.address); - const gasCosts = approveGas.add(withdrawGas).mul(approveTx.gasPrice); - - expect(afterPartialEtherBalance).to.be.equal( - priorEthersBalance.add(partialWithdraw).sub(gasCosts), - 'User ETHER balance should contain the partial withdraw' - ); - expect(afterPartialATokensBalance).to.be.equal( - aTokensBalance.sub(partialWithdraw), - 'User aWETH balance should be substracted' - ); - }); - - it('Withdraw WETH - Full', async () => { - const { users, aWETH, wethGateway, pool } = testEnv; - - const user = users[1]; - const priorEthersBalance = await user.signer.getBalance(); - const aTokensBalance = await aWETH.balanceOf(user.address); - - expect(aTokensBalance).to.be.gt(zero, 'User should have aTokens.'); - - // Approve the aTokens to Gateway so Gateway can withdraw and convert to Ether - const approveTx = await aWETH - .connect(user.signer) - .approve(wethGateway.address, MAX_UINT_AMOUNT); - const { gasUsed: approveGas } = await waitForTx(approveTx); - - // Full withdraw - const { gasUsed: withdrawGas } = await waitForTx( - await wethGateway.connect(user.signer).withdrawETH(MAX_UINT_AMOUNT, user.address) - ); - - const afterFullEtherBalance = await user.signer.getBalance(); - const afterFullATokensBalance = await aWETH.balanceOf(user.address); - const gasCosts = approveGas.add(withdrawGas).mul(approveTx.gasPrice); - - expect(afterFullEtherBalance).to.be.eq( - priorEthersBalance.add(aTokensBalance).sub(gasCosts), - 'User ETHER balance should contain the full withdraw' - ); - expect(afterFullATokensBalance).to.be.eq(0, 'User aWETH balance should be zero'); - }); - - it('Borrow stable WETH and Full Repay with ETH', async () => { - const { users, wethGateway, aWETH, dai, aDai, weth, pool, helpersContract } = testEnv; - const borrowSize = parseEther('1'); - const repaySize = borrowSize.add(borrowSize.mul(5).div(100)); - const user = users[1]; - - const { stableDebtTokenAddress } = await helpersContract.getReserveTokensAddresses( - weth.address - ); - - const stableDebtToken = await getStableDebtToken(stableDebtTokenAddress); - - // Deposit 10000 DAI - await dai.connect(user.signer).mint(daiSize); - await dai.connect(user.signer).approve(pool.address, daiSize); - await pool.connect(user.signer).deposit(dai.address, daiSize, user.address, '0'); - - const aTokensBalance = await aDai.balanceOf(user.address); - - expect(aTokensBalance).to.be.gt(zero); - expect(aTokensBalance).to.be.gte(daiSize); - - // Borrow WETH with WETH as collateral - await waitForTx( - await pool.connect(user.signer).borrow(weth.address, borrowSize, '1', '0', user.address) - ); - - const debtBalance = await stableDebtToken.balanceOf(user.address); - - expect(debtBalance).to.be.gt(zero); - - // Full Repay WETH with native ETH - await waitForTx( - await wethGateway - .connect(user.signer) - .repayETH(MAX_UINT_AMOUNT, '1', user.address, { value: repaySize }) - ); - - const debtBalanceAfterRepay = await stableDebtToken.balanceOf(user.address); - expect(debtBalanceAfterRepay).to.be.eq(zero); - }); - - it('Borrow variable WETH and Full Repay with ETH', async () => { - const { users, wethGateway, aWETH, weth, pool, helpersContract } = testEnv; - const borrowSize = parseEther('1'); - const repaySize = borrowSize.add(borrowSize.mul(5).div(100)); - const user = users[1]; - - const { variableDebtTokenAddress } = await helpersContract.getReserveTokensAddresses( - weth.address - ); - - const varDebtToken = await getVariableDebtToken(variableDebtTokenAddress); - - // Deposit with native ETH - await wethGateway.connect(user.signer).depositETH(user.address, '0', { value: depositSize }); - - const aTokensBalance = await aWETH.balanceOf(user.address); - - expect(aTokensBalance).to.be.gt(zero); - expect(aTokensBalance).to.be.gte(depositSize); - - // Borrow WETH with WETH as collateral - await waitForTx( - await pool.connect(user.signer).borrow(weth.address, borrowSize, '2', '0', user.address) - ); - - const debtBalance = await varDebtToken.balanceOf(user.address); - - expect(debtBalance).to.be.gt(zero); - - // Partial Repay WETH loan with native ETH - const partialPayment = repaySize.div(2); - await waitForTx( - await wethGateway - .connect(user.signer) - .repayETH(partialPayment, '2', user.address, { value: partialPayment }) - ); - - const debtBalanceAfterPartialRepay = await varDebtToken.balanceOf(user.address); - expect(debtBalanceAfterPartialRepay).to.be.lt(debtBalance); - - // Full Repay WETH loan with native ETH - await waitForTx( - await wethGateway - .connect(user.signer) - .repayETH(MAX_UINT_AMOUNT, '2', user.address, { value: repaySize }) - ); - const debtBalanceAfterFullRepay = await varDebtToken.balanceOf(user.address); - expect(debtBalanceAfterFullRepay).to.be.eq(zero); - }); - - it('Borrow ETH via delegateApprove ETH and repays back', async () => { - const { users, wethGateway, aWETH, weth, helpersContract } = testEnv; - const borrowSize = parseEther('1'); - const user = users[2]; - const { variableDebtTokenAddress } = await helpersContract.getReserveTokensAddresses( - weth.address - ); - const varDebtToken = await getVariableDebtToken(variableDebtTokenAddress); - - const priorDebtBalance = await varDebtToken.balanceOf(user.address); - expect(priorDebtBalance).to.be.eq(zero); - - // Deposit WETH with native ETH - await wethGateway.connect(user.signer).depositETH(user.address, '0', { value: depositSize }); - - const aTokensBalance = await aWETH.balanceOf(user.address); - - expect(aTokensBalance).to.be.gt(zero); - expect(aTokensBalance).to.be.gte(depositSize); - - // Delegates borrowing power of WETH to WETHGateway - await waitForTx( - await varDebtToken.connect(user.signer).approveDelegation(wethGateway.address, borrowSize) - ); - - // Borrows ETH with WETH as collateral - await waitForTx(await wethGateway.connect(user.signer).borrowETH(borrowSize, '2', '0')); - - const debtBalance = await varDebtToken.balanceOf(user.address); - - expect(debtBalance).to.be.gt(zero); - - // Full Repay WETH loan with native ETH - await waitForTx( - await wethGateway - .connect(user.signer) - .repayETH(MAX_UINT_AMOUNT, '2', user.address, { value: borrowSize.mul(2) }) - ); - const debtBalanceAfterFullRepay = await varDebtToken.balanceOf(user.address); - expect(debtBalanceAfterFullRepay).to.be.eq(zero); - }); - - it('Should revert if receiver function receives Ether if not WETH', async () => { - const { users, wethGateway } = testEnv; - const user = users[0]; - const amount = parseEther('1'); - - // Call receiver function (empty data + value) - await expect( - user.signer.sendTransaction({ - to: wethGateway.address, - value: amount, - gasLimit: DRE.network.config.gas, - }) - ).to.be.revertedWith('Receive not allowed'); - }); - - it('Should revert if fallback functions is called with Ether', async () => { - const { users, wethGateway } = testEnv; - const user = users[0]; - const amount = parseEther('1'); - const fakeABI = ['function wantToCallFallback()']; - const abiCoder = new DRE.ethers.utils.Interface(fakeABI); - const fakeMethodEncoded = abiCoder.encodeFunctionData('wantToCallFallback', []); - - // Call fallback function with value - await expect( - user.signer.sendTransaction({ - to: wethGateway.address, - data: fakeMethodEncoded, - value: amount, - gasLimit: DRE.network.config.gas, - }) - ).to.be.revertedWith('Fallback not allowed'); - }); - - it('Should revert if fallback functions is called', async () => { - const { users, wethGateway } = testEnv; - const user = users[0]; - - const fakeABI = ['function wantToCallFallback()']; - const abiCoder = new DRE.ethers.utils.Interface(fakeABI); - const fakeMethodEncoded = abiCoder.encodeFunctionData('wantToCallFallback', []); - - // Call fallback function without value - await expect( - user.signer.sendTransaction({ - to: wethGateway.address, - data: fakeMethodEncoded, - gasLimit: DRE.network.config.gas, - }) - ).to.be.revertedWith('Fallback not allowed'); - }); - - it('Getters should retrieve correct state', async () => { - const { aWETH, weth, pool, wethGateway } = testEnv; - - const WETHAddress = await wethGateway.getWETHAddress(); - const aWETHAddress = await wethGateway.getAWETHAddress(); - const poolAddress = await wethGateway.getLendingPoolAddress(); - - expect(WETHAddress).to.be.equal(weth.address); - expect(aWETHAddress).to.be.equal(aWETH.address); - expect(poolAddress).to.be.equal(pool.address); - }); - - it('Owner can do emergency token recovery', async () => { - const { users, weth, dai, wethGateway, deployer } = testEnv; - const user = users[0]; - const amount = parseEther('1'); - - const uniswapRouter = IUniswapV2Router02Factory.connect(UNISWAP_ROUTER, user.signer); - await uniswapRouter.swapETHForExactTokens( - amount, // 1 DAI - [weth.address, dai.address], // Uniswap paths WETH - DAI - user.address, - (await DRE.ethers.provider.getBlock('latest')).timestamp + 300, - { - value: amount, // 1 Ether, we get refund of the unneeded Ether to buy 1 DAI - } - ); - const daiBalanceAfterMint = await dai.balanceOf(user.address); - - await dai.connect(user.signer).transfer(wethGateway.address, amount); - const daiBalanceAfterBadTransfer = await dai.balanceOf(user.address); - expect(daiBalanceAfterBadTransfer).to.be.eq( - daiBalanceAfterMint.sub(amount), - 'User should have lost the funds here.' - ); - - await wethGateway - .connect(deployer.signer) - .emergencyTokenTransfer(dai.address, user.address, amount); - const daiBalanceAfterRecovery = await dai.balanceOf(user.address); - - expect(daiBalanceAfterRecovery).to.be.eq( - daiBalanceAfterMint, - 'User should recover the funds due emergency token transfer' - ); - }); - - it('Owner can do emergency native ETH recovery', async () => { - const { users, wethGateway, deployer } = testEnv; - const user = users[0]; - const amount = parseEther('1'); - const userBalancePriorCall = await user.signer.getBalance(); - - // Deploy contract with payable selfdestruct contract - const selfdestructContract = await deploySelfdestructTransferMock(); - - // Selfdestruct the mock, pointing to WETHGateway address - const callTx = await selfdestructContract - .connect(user.signer) - .destroyAndTransfer(wethGateway.address, { value: amount }); - const { gasUsed } = await waitForTx(callTx); - const gasFees = gasUsed.mul(callTx.gasPrice); - const userBalanceAfterCall = await user.signer.getBalance(); - - expect(userBalanceAfterCall).to.be.eq(userBalancePriorCall.sub(amount).sub(gasFees), ''); - ('User should have lost the funds'); - - // Recover the funds from the contract and sends back to the user - await wethGateway.connect(deployer.signer).emergencyEtherTransfer(user.address, amount); - - const userBalanceAfterRecovery = await user.signer.getBalance(); - const wethGatewayAfterRecovery = await DRE.ethers.provider.getBalance(wethGateway.address); - - expect(userBalanceAfterRecovery).to.be.eq( - userBalancePriorCall.sub(gasFees), - 'User should recover the funds due emergency eth transfer.' - ); - expect(wethGatewayAfterRecovery).to.be.eq('0', 'WETHGateway ether balance should be zero.'); - }); -}); diff --git a/test/pausable-functions.spec.ts b/test/pausable-functions.spec.ts deleted file mode 100644 index 2ac975ac..00000000 --- a/test/pausable-functions.spec.ts +++ /dev/null @@ -1,330 +0,0 @@ -import { makeSuite, TestEnv } from './helpers/make-suite'; -import { ProtocolErrors, RateMode } from '../helpers/types'; -import { APPROVAL_AMOUNT_LENDING_POOL, oneEther } from '../helpers/constants'; -import { convertToCurrencyDecimals } from '../helpers/contracts-helpers'; -import { parseEther, parseUnits } from 'ethers/lib/utils'; -import { BigNumber } from 'bignumber.js'; -import { MockFlashLoanReceiver } from '../types/MockFlashLoanReceiver'; -import { getMockFlashLoanReceiver } from '../helpers/contracts-getters'; - -const { expect } = require('chai'); - -makeSuite('Pausable Pool', (testEnv: TestEnv) => { - let _mockFlashLoanReceiver = {} as MockFlashLoanReceiver; - - const { - LP_IS_PAUSED, - INVALID_FROM_BALANCE_AFTER_TRANSFER, - INVALID_TO_BALANCE_AFTER_TRANSFER, - } = ProtocolErrors; - - before(async () => { - _mockFlashLoanReceiver = await getMockFlashLoanReceiver(); - }); - - it('User 0 deposits 1000 DAI. Configurator pauses pool. Transfers to user 1 reverts. Configurator unpauses the network and next transfer succees', async () => { - const { users, pool, dai, aDai, configurator } = testEnv; - - const amountDAItoDeposit = await convertToCurrencyDecimals(dai.address, '1000'); - - await dai.connect(users[0].signer).mint(amountDAItoDeposit); - - // user 0 deposits 1000 DAI - await dai.connect(users[0].signer).approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL); - await pool - .connect(users[0].signer) - .deposit(dai.address, amountDAItoDeposit, users[0].address, '0'); - - const user0Balance = await aDai.balanceOf(users[0].address); - const user1Balance = await aDai.balanceOf(users[1].address); - - // Configurator pauses the pool - await configurator.connect(users[1].signer).setPoolPause(true); - - // User 0 tries the transfer to User 1 - await expect( - aDai.connect(users[0].signer).transfer(users[1].address, amountDAItoDeposit) - ).to.revertedWith(LP_IS_PAUSED); - - const pausedFromBalance = await aDai.balanceOf(users[0].address); - const pausedToBalance = await aDai.balanceOf(users[1].address); - - expect(pausedFromBalance).to.be.equal( - user0Balance.toString(), - INVALID_TO_BALANCE_AFTER_TRANSFER - ); - expect(pausedToBalance.toString()).to.be.equal( - user1Balance.toString(), - INVALID_FROM_BALANCE_AFTER_TRANSFER - ); - - // Configurator unpauses the pool - await configurator.connect(users[1].signer).setPoolPause(false); - - // User 0 succeeds transfer to User 1 - await aDai.connect(users[0].signer).transfer(users[1].address, amountDAItoDeposit); - - const fromBalance = await aDai.balanceOf(users[0].address); - const toBalance = await aDai.balanceOf(users[1].address); - - expect(fromBalance.toString()).to.be.equal( - user0Balance.sub(amountDAItoDeposit), - INVALID_FROM_BALANCE_AFTER_TRANSFER - ); - expect(toBalance.toString()).to.be.equal( - user1Balance.add(amountDAItoDeposit), - INVALID_TO_BALANCE_AFTER_TRANSFER - ); - }); - - it('Deposit', async () => { - const { users, pool, dai, aDai, configurator } = testEnv; - - const amountDAItoDeposit = await convertToCurrencyDecimals(dai.address, '1000'); - - await dai.connect(users[0].signer).mint(amountDAItoDeposit); - - // user 0 deposits 1000 DAI - await dai.connect(users[0].signer).approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL); - - // Configurator pauses the pool - await configurator.connect(users[1].signer).setPoolPause(true); - await expect( - pool.connect(users[0].signer).deposit(dai.address, amountDAItoDeposit, users[0].address, '0') - ).to.revertedWith(LP_IS_PAUSED); - - // Configurator unpauses the pool - await configurator.connect(users[1].signer).setPoolPause(false); - }); - - it('Withdraw', async () => { - const { users, pool, dai, aDai, configurator } = testEnv; - - const amountDAItoDeposit = await convertToCurrencyDecimals(dai.address, '1000'); - - await dai.connect(users[0].signer).mint(amountDAItoDeposit); - - // user 0 deposits 1000 DAI - await dai.connect(users[0].signer).approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL); - await pool - .connect(users[0].signer) - .deposit(dai.address, amountDAItoDeposit, users[0].address, '0'); - - // Configurator pauses the pool - await configurator.connect(users[1].signer).setPoolPause(true); - - // user tries to burn - await expect( - pool.connect(users[0].signer).withdraw(dai.address, amountDAItoDeposit, users[0].address) - ).to.revertedWith(LP_IS_PAUSED); - - // Configurator unpauses the pool - await configurator.connect(users[1].signer).setPoolPause(false); - }); - - it('Borrow', async () => { - const { pool, dai, users, configurator } = testEnv; - - const user = users[1]; - // Pause the pool - await configurator.connect(users[1].signer).setPoolPause(true); - - // Try to execute liquidation - await expect( - pool.connect(user.signer).borrow(dai.address, '1', '1', '0', user.address) - ).revertedWith(LP_IS_PAUSED); - - // Unpause the pool - await configurator.connect(users[1].signer).setPoolPause(false); - }); - - it('Repay', async () => { - const { pool, dai, users, configurator } = testEnv; - - const user = users[1]; - // Pause the pool - await configurator.connect(users[1].signer).setPoolPause(true); - - // Try to execute liquidation - await expect(pool.connect(user.signer).repay(dai.address, '1', '1', user.address)).revertedWith( - LP_IS_PAUSED - ); - - // Unpause the pool - await configurator.connect(users[1].signer).setPoolPause(false); - }); - - it('Flash loan', async () => { - const { dai, pool, weth, users, configurator } = testEnv; - - const caller = users[3]; - - const flashAmount = parseEther('0.8'); - - await _mockFlashLoanReceiver.setFailExecutionTransfer(true); - - // Pause pool - await configurator.connect(users[1].signer).setPoolPause(true); - - await expect( - pool - .connect(caller.signer) - .flashLoan( - _mockFlashLoanReceiver.address, - [weth.address], - [flashAmount], - [1], - caller.address, - '0x10', - '0' - ) - ).revertedWith(LP_IS_PAUSED); - - // Unpause pool - await configurator.connect(users[1].signer).setPoolPause(false); - }); - - it('Liquidation call', async () => { - const { users, pool, usdc, oracle, weth, configurator, helpersContract } = 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(pool.address, APPROVAL_AMOUNT_LENDING_POOL); - - //user 3 deposits 1000 USDC - const amountUSDCtoDeposit = await convertToCurrencyDecimals(usdc.address, '1000'); - - await pool - .connect(depositor.signer) - .deposit(usdc.address, amountUSDCtoDeposit, depositor.address, '0'); - - //user 4 deposits 1 ETH - const amountETHtoDeposit = await convertToCurrencyDecimals(weth.address, '1'); - - //mints WETH to borrower - await weth.connect(borrower.signer).mint(amountETHtoDeposit); - - //approve protocol to access 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 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.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.2).toFixed(0) - ); - - //mints dai to the liquidator - await usdc.mint(await convertToCurrencyDecimals(usdc.address, '1000')); - await usdc.approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL); - - const userReserveDataBefore = await helpersContract.getUserReserveData( - usdc.address, - borrower.address - ); - - const amountToLiquidate = new BigNumber(userReserveDataBefore.currentStableDebt.toString()) - .multipliedBy(0.5) - .toFixed(0); - - // Pause pool - await configurator.connect(users[1].signer).setPoolPause(true); - - // Do liquidation - await expect( - pool.liquidationCall(weth.address, usdc.address, borrower.address, amountToLiquidate, true) - ).revertedWith(LP_IS_PAUSED); - - // Unpause pool - await configurator.connect(users[1].signer).setPoolPause(false); - }); - - it('SwapBorrowRateMode', async () => { - const { pool, weth, dai, usdc, users, configurator } = testEnv; - const user = users[1]; - const amountWETHToDeposit = parseEther('10'); - const amountDAIToDeposit = parseEther('120'); - const amountToBorrow = parseUnits('65', 6); - - await weth.connect(user.signer).mint(amountWETHToDeposit); - await weth.connect(user.signer).approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL); - await pool.connect(user.signer).deposit(weth.address, amountWETHToDeposit, user.address, '0'); - - await dai.connect(user.signer).mint(amountDAIToDeposit); - await dai.connect(user.signer).approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL); - await pool.connect(user.signer).deposit(dai.address, amountDAIToDeposit, user.address, '0'); - - await pool.connect(user.signer).borrow(usdc.address, amountToBorrow, 2, 0, user.address); - - // Pause pool - await configurator.connect(users[1].signer).setPoolPause(true); - - // Try to repay - await expect( - pool.connect(user.signer).swapBorrowRateMode(usdc.address, RateMode.Stable) - ).revertedWith(LP_IS_PAUSED); - - // Unpause pool - await configurator.connect(users[1].signer).setPoolPause(false); - }); - - it('RebalanceStableBorrowRate', async () => { - const { pool, dai, users, configurator } = testEnv; - const user = users[1]; - // Pause pool - await configurator.connect(users[1].signer).setPoolPause(true); - - await expect( - pool.connect(user.signer).rebalanceStableBorrowRate(dai.address, user.address) - ).revertedWith(LP_IS_PAUSED); - - // Unpause pool - await configurator.connect(users[1].signer).setPoolPause(false); - }); - - it('setUserUseReserveAsCollateral', async () => { - const { pool, weth, users, configurator } = testEnv; - const user = users[1]; - - const amountWETHToDeposit = parseEther('1'); - await weth.connect(user.signer).mint(amountWETHToDeposit); - await weth.connect(user.signer).approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL); - await pool.connect(user.signer).deposit(weth.address, amountWETHToDeposit, user.address, '0'); - - // Pause pool - await configurator.connect(users[1].signer).setPoolPause(true); - - await expect( - pool.connect(user.signer).setUserUseReserveAsCollateral(weth.address, false) - ).revertedWith(LP_IS_PAUSED); - - // Unpause pool - await configurator.connect(users[1].signer).setPoolPause(false); - }); -}); diff --git a/test/pool-modifiers.spec.ts b/test/pool-modifiers.spec.ts deleted file mode 100644 index fb915b15..00000000 --- a/test/pool-modifiers.spec.ts +++ /dev/null @@ -1,241 +0,0 @@ -// import {iATokenBase, iAssetsWithoutETH, ITestEnvWithoutInstances, RateMode} from '../utils/types'; -// import { -// LendingPoolConfiguratorInstance, -// LendingPoolInstance, -// ATokenInstance, -// LendingPoolCoreInstance, -// MintableERC20Instance, -// } from '../utils/typechain-types/truffle-contracts'; -// import {testEnvProviderWithoutInstances} from '../utils/truffle/dlp-tests-env'; -// import {oneEther, ETHEREUM_ADDRESS} from '../utils/constants'; -// import {convertToCurrencyDecimals} from '../utils/misc-utils'; - -// const expectRevert = require('@openzeppelin/test-helpers').expectRevert; - -// contract('LendingPool: Modifiers', async ([deployer, ...users]) => { -// let _testEnvProvider: ITestEnvWithoutInstances; -// let _lendingPoolConfiguratorInstance: LendingPoolConfiguratorInstance; -// let _lendingPoolInstance: LendingPoolInstance; -// let _lendingPoolCoreInstance: LendingPoolCoreInstance; -// let _aTokenInstances: iATokenBase; -// let _tokenInstances: iAssetsWithoutETH; - -// before('Initializing LendingPool test variables', async () => { -// console.time('setup-test'); -// _testEnvProvider = await testEnvProviderWithoutInstances(artifacts, [deployer, ...users]); - -// const { -// getAllAssetsInstances, -// getLendingPoolInstance, -// getLendingPoolCoreInstance, -// getLendingPoolConfiguratorInstance, -// getATokenInstances, -// } = _testEnvProvider; -// const instances = await Promise.all([ -// getLendingPoolInstance(), -// getLendingPoolCoreInstance(), -// getLendingPoolConfiguratorInstance(), -// getATokenInstances(), -// getAllAssetsInstances(), -// ]); - -// _lendingPoolInstance = instances[0]; -// _lendingPoolCoreInstance = instances[1]; -// _lendingPoolConfiguratorInstance = instances[2]; - -// _aTokenInstances = instances[3]; -// _tokenInstances = instances[4]; -// console.timeEnd('setup-test'); -// }); - -// it('Tries to deposit in an inactive reserve', async () => { -// //using the deployer address as a fake reserve address -// await expectRevert( -// _lendingPoolInstance.deposit(deployer, '1', '0'), -// 'Action requires an active reserve' -// ); -// }); - -// it('Tries to invoke redeemUnderlying on an reserve, from a non-aToken address', async () => { -// await expectRevert( -// _lendingPoolInstance.redeemUnderlying(ETHEREUM_ADDRESS, deployer, '1', '0'), -// 'The caller of this function can only be the aToken contract of this reserve' -// ); -// }); - -// it('Tries to borrow from an inactive reserve', async () => { -// //using the deployer address as a fake reserve address -// await expectRevert( -// _lendingPoolInstance.borrow(deployer, '1', '0', RateMode.Stable), -// 'Action requires an active reserve' -// ); -// }); - -// it('Tries to repay in an inactive reserve', async () => { -// //using the deployer address as a fake reserve address -// await expectRevert( -// _lendingPoolInstance.repay(deployer, '1', deployer), -// 'Action requires an active reserve' -// ); -// }); - -// it('Tries to swapBorrowRateMode on an inactive reserve', async () => { -// //using the deployer address as a fake reserve address -// await expectRevert( -// _lendingPoolInstance.swapBorrowRateMode(deployer), -// 'Action requires an active reserve' -// ); -// }); - -// it('Tries to rebalanceStableBorrowRate on an inactive reserve', async () => { -// //using the deployer address as a fake reserve address -// await expectRevert( -// _lendingPoolInstance.rebalanceStableBorrowRate(deployer, deployer), -// 'Action requires an active reserve' -// ); -// }); - -// it('Tries to setUserUseReserveAsCollateral on an inactive reserve', async () => { -// //using the deployer address as a fake reserve address -// await expectRevert( -// _lendingPoolInstance.setUserUseReserveAsCollateral(deployer, true), -// 'Action requires an active reserve' -// ); -// }); - -// it('Tries to invoke liquidationCall on an inactive reserve', async () => { -// //using the deployer address as a fake reserve address -// await expectRevert( -// _lendingPoolInstance.liquidationCall(ETHEREUM_ADDRESS, deployer, deployer, '1', false), -// 'Action requires an active reserve' -// ); -// }); - -// it('Tries to invoke liquidationCall on an inactive collateral', async () => { -// //using the deployer address as a fake reserve address -// await expectRevert( -// _lendingPoolInstance.liquidationCall(deployer, ETHEREUM_ADDRESS, deployer, '1', false), -// 'Action requires an active reserve' -// ); -// }); - -// it('Freezes the ETH reserve', async () => { -// await _lendingPoolConfiguratorInstance.freezeReserve(ETHEREUM_ADDRESS); -// }); - -// it('tries to deposit in a freezed reserve', async () => { -// await expectRevert( -// _lendingPoolInstance.deposit(ETHEREUM_ADDRESS, '1', '0'), -// 'Action requires an unfreezed reserve' -// ); -// }); - -// it('tries to borrow from a freezed reserve', async () => { -// await expectRevert( -// _lendingPoolInstance.borrow(ETHEREUM_ADDRESS, '1', '0', '0'), -// 'Action requires an unfreezed reserve' -// ); -// }); - -// it('tries to swap interest rate mode in a freezed reserve', async () => { -// await expectRevert( -// _lendingPoolInstance.swapBorrowRateMode(ETHEREUM_ADDRESS), -// 'Action requires an unfreezed reserve' -// ); -// }); - -// it('tries to disable as collateral a freezed reserve', async () => { -// await expectRevert( -// _lendingPoolInstance.setUserUseReserveAsCollateral(ETHEREUM_ADDRESS, false), -// 'Action requires an unfreezed reserve' -// ); -// }); - -// it('unfreezes the reserve, user deposits 1 ETH, freezes the reserve, check that the user can redeem', async () => { -// const {aWETH} = _aTokenInstances; - -// //unfreezes the reserve -// await _lendingPoolConfiguratorInstance.unfreezeReserve(ETHEREUM_ADDRESS); - -// //deposit 1 ETH -// await _lendingPoolInstance.deposit(ETHEREUM_ADDRESS, oneEther, '0', { -// value: oneEther.toString(), -// }); - -// //freezes the reserve -// await _lendingPoolConfiguratorInstance.freezeReserve(ETHEREUM_ADDRESS); - -// const balance = await aWETH.balanceOf(deployer); - -// await aWETH.redeem(balance); -// }); - -// it('unfreezes the reserve, user 0 deposits 100 DAI, user 1 deposits 1 ETH and borrows 50 DAI, freezes the reserve, checks that the user 1 can repay', async () => { -// const {aWETH, aDAI} = _aTokenInstances; -// const {DAI} = _tokenInstances; - -// //unfreezes the reserve -// await _lendingPoolConfiguratorInstance.unfreezeReserve(ETHEREUM_ADDRESS); - -// const amountDAI = await convertToCurrencyDecimals(DAI.address, '100'); - -// //user 0 deposits 100 DAI -// await DAI.mint(amountDAI, {from: users[0]}); - -// await DAI.approve(_lendingPoolCoreInstance.address, amountDAI, {from: users[0]}); - -// await _lendingPoolInstance.deposit(DAI.address, amountDAI, '0', {from: users[0]}); - -// //user 1 deposits 1 ETH -// await _lendingPoolInstance.deposit(ETHEREUM_ADDRESS, oneEther, '0', { -// from: users[1], -// value: oneEther.toString(), -// }); - -// const amountDAIToBorrow = await convertToCurrencyDecimals(DAI.address, '10'); - -// //user 1 borrows 10 DAI -// await _lendingPoolInstance.borrow(DAI.address, amountDAIToBorrow, RateMode.Stable, '0', { -// from: users[1], -// }); - -// //freezes the reserve -// await _lendingPoolConfiguratorInstance.freezeReserve(ETHEREUM_ADDRESS); - -// //user 1 repays 1 DAI -// await DAI.approve(_lendingPoolCoreInstance.address, amountDAIToBorrow, {from: users[1]}); - -// await _lendingPoolInstance.repay(DAI.address, oneEther, users[1], {from: users[1]}); -// }); - -// it('Check that liquidationCall can be executed on a freezed reserve', async () => { -// const {aWETH, aDAI} = _aTokenInstances; -// const {DAI} = _tokenInstances; - -// //user 2 tries to liquidate - -// await expectRevert( -// _lendingPoolInstance.liquidationCall( -// ETHEREUM_ADDRESS, -// DAI.address, -// users[1], -// oneEther, -// true, -// {from: users[2]} -// ), -// 'Health factor is not below the threshold' -// ); -// }); - -// it('Check that rebalanceStableBorrowRate can be executed on a freezed reserve', async () => { -// const {aWETH, aDAI} = _aTokenInstances; -// const {DAI} = _tokenInstances; - -// //user 2 tries to liquidate - -// await expectRevert( -// _lendingPoolInstance.rebalanceStableBorrowRate(DAI.address, users[1]), -// 'Interest rate rebalance conditions were not met' -// ); -// }); -// }); diff --git a/test/rate-strategy.spec.ts b/test/rate-strategy.spec.ts deleted file mode 100644 index b56c754e..00000000 --- a/test/rate-strategy.spec.ts +++ /dev/null @@ -1,165 +0,0 @@ -// import { -// IReserveParams, -// iAavePoolAssets, -// iAssetsWithoutETH, -// ITestEnvWithoutInstances, -// } from "../utils/types" -// import { - -// LendingPoolAddressesProviderInstance, - -// DefaultReserveInterestRateStrategyInstance, -// MintableERC20Instance, -// } from "../utils/typechain-types/truffle-contracts" -// import { testEnvProviderWithoutInstances} from "../utils/truffle/dlp-tests-env" -// import {RAY} from "../utils/constants" -// import BigNumber from "bignumber.js" - -// const {expect} = require("chai") - -// contract("Interest rate strategy", async ([deployer, ...users]) => { -// let _testEnvProvider: ITestEnvWithoutInstances -// let _strategyInstance: DefaultReserveInterestRateStrategyInstance -// let _tokenInstances: iAssetsWithoutETH -// let _addressesProviderInstance: LendingPoolAddressesProviderInstance -// let _reservesParams: iAavePoolAssets - -// before("Initializing test variables", async () => { -// console.time('setup-test'); -// _testEnvProvider = await testEnvProviderWithoutInstances( -// artifacts, -// [deployer, ...users], -// ) - -// const { -// getAllAssetsInstances, -// getLendingPoolAddressesProviderInstance, -// getAavePoolReservesParams, -// } = _testEnvProvider - -// const instances = await Promise.all([ -// getAllAssetsInstances(), -// getLendingPoolAddressesProviderInstance() -// ]) - -// _tokenInstances = instances[0] -// _addressesProviderInstance = instances[1] -// _reservesParams = await getAavePoolReservesParams() -// console.timeEnd('setup-test'); -// }) - -// it("Deploys a new instance of a DefaultReserveInterestRateStrategy contract", async () => { -// const {DAI: daiInstance} = _tokenInstances - -// const {DAI: daiConfiguration} = _reservesParams - -// const contract: any = await artifacts.require("DefaultReserveInterestRateStrategy") -// const mathLibrary = await artifacts.require("WadRayMath") -// const mathLibraryInstance = await mathLibrary.new() - -// await contract.link("WadRayMath", mathLibraryInstance.address) - -// _strategyInstance = await contract.new( -// daiInstance.address, -// _addressesProviderInstance.address, -// daiConfiguration.baseVariableBorrowRate, -// daiConfiguration.variableRateSlope1, -// daiConfiguration.variableRateSlope2, -// daiConfiguration.stableRateSlope1, -// daiConfiguration.stableRateSlope2, -// ) -// }) - -// it("Checks rates at 0% utilization rate", async () => { -// const {DAI: daiInstance} = _tokenInstances -// const {DAI: daiConfiguration} = _reservesParams -// const data: any = await _strategyInstance.calculateInterestRates( -// daiInstance.address, -// "1000000000000000000", -// "0", -// "0", -// "0", -// ) - -// expect(data.currentLiquidityRate.toString()).to.be.equal("0", "Invalid liquidity rate") -// expect(data.currentStableBorrowRate.toString()).to.be.equal( -// new BigNumber(0.039).times(RAY).toFixed(0), -// "Invalid stable rate", -// ) -// expect(data.currentVariableBorrowRate.toString()).to.be.equal( -// daiConfiguration.baseVariableBorrowRate, -// "Invalid variable rate", -// ) -// }) - -// it("Checks rates at 80% utilization rate", async () => { -// const {DAI: daiInstance} = _tokenInstances -// const {DAI: daiConfiguration} = _reservesParams -// const data: any = await _strategyInstance.calculateInterestRates( -// daiInstance.address, -// "200000000000000000", -// "0", -// "800000000000000000", -// "0", -// ) - -// const expectedVariableRate = new BigNumber(daiConfiguration.baseVariableBorrowRate) -// .plus(daiConfiguration.variableRateSlope1) - -// expect(data.currentLiquidityRate.toString()).to.be.equal( -// expectedVariableRate.times(0.8).toFixed(0), -// "Invalid liquidity rate", -// ) - -// expect(data.currentVariableBorrowRate.toString()).to.be.equal( -// new BigNumber(daiConfiguration.baseVariableBorrowRate) -// .plus(daiConfiguration.variableRateSlope1) -// .toFixed(0), -// "Invalid variable rate", -// ) - -// expect(data.currentStableBorrowRate.toString()).to.be.equal( -// new BigNumber(0.039) -// .times(RAY) -// .plus(daiConfiguration.stableRateSlope1) -// .toFixed(0), -// "Invalid stable rate", -// ) -// }) - -// it("Checks rates at 100% utilization rate", async () => { -// const {DAI: daiInstance} = _tokenInstances -// const {DAI: daiConfiguration} = _reservesParams -// const data: any = await _strategyInstance.calculateInterestRates( -// daiInstance.address, -// "0", -// "0", -// "1000000000000000000", -// "0", -// ) - -// const expectedVariableRate = new BigNumber(daiConfiguration.baseVariableBorrowRate) -// .plus(daiConfiguration.variableRateSlope1) -// .plus(daiConfiguration.variableRateSlope2) -// .toFixed(0) - -// expect(data.currentLiquidityRate.toString()).to.be.equal( -// expectedVariableRate, -// "Invalid liquidity rate", -// ) - -// expect(data.currentVariableBorrowRate.toString()).to.be.equal( -// expectedVariableRate, -// "Invalid variable rate", -// ) - -// expect(data.currentStableBorrowRate.toString()).to.be.equal( -// new BigNumber(0.039) -// .times(RAY) -// .plus(daiConfiguration.stableRateSlope1) -// .plus(daiConfiguration.stableRateSlope2) -// .toFixed(0), -// "Invalid stable rate", -// ) -// }) -// }) diff --git a/test/scenario.spec.ts b/test/scenario.spec.ts deleted file mode 100644 index b7b3c318..00000000 --- a/test/scenario.spec.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { configuration as actionsConfiguration } from './helpers/actions'; -import { configuration as calculationsConfiguration } from './helpers/utils/calculations'; - -import fs from 'fs'; -import BigNumber from 'bignumber.js'; -import { makeSuite } from './helpers/make-suite'; -import { getReservesConfigByPool } from '../helpers/configuration'; -import { AavePools, iAavePoolAssets, IReserveParams } from '../helpers/types'; -import { executeStory } from './helpers/scenario-engine'; - -const scenarioFolder = './test/helpers/scenarios/'; - -const selectedScenarios: string[] = []; - -fs.readdirSync(scenarioFolder).forEach((file) => { - if (selectedScenarios.length > 0 && !selectedScenarios.includes(file)) return; - - const scenario = require(`./helpers/scenarios/${file}`); - - makeSuite(scenario.title, async (testEnv) => { - before('Initializing configuration', async () => { - // Sets BigNumber for this suite, instead of globally - BigNumber.config({ DECIMAL_PLACES: 0, ROUNDING_MODE: BigNumber.ROUND_DOWN }); - - actionsConfiguration.skipIntegrityCheck = false; //set this to true to execute solidity-coverage - - calculationsConfiguration.reservesParams = >( - getReservesConfigByPool(AavePools.proto) - ); - }); - after('Reset', () => { - // Reset BigNumber - BigNumber.config({ DECIMAL_PLACES: 20, ROUNDING_MODE: BigNumber.ROUND_HALF_UP }); - }); - - for (const story of scenario.stories) { - it(story.description, async function () { - // Retry the test scenarios up to 4 times if an error happens, due erratic HEVM network errors - this.retries(4); - await executeStory(story, testEnv); - }); - } - }); -}); diff --git a/test/stable-rate-economy.spec.ts b/test/stable-rate-economy.spec.ts deleted file mode 100644 index 1c2c156a..00000000 --- a/test/stable-rate-economy.spec.ts +++ /dev/null @@ -1,199 +0,0 @@ -// import { -// LendingPoolInstance, -// LendingPoolCoreInstance, -// MintableERC20Instance, -// ATokenInstance, -// } from "../utils/typechain-types/truffle-contracts" -// import { -// iATokenBase, -// iAssetsWithoutETH, -// ITestEnvWithoutInstances, -// RateMode, -// } from "../utils/types" -// import { -// APPROVAL_AMOUNT_LENDING_POOL_CORE, -// ETHEREUM_ADDRESS, -// } from "../utils/constants" -// import { testEnvProviderWithoutInstances} from "../utils/truffle/dlp-tests-env" -// import {convertToCurrencyDecimals} from "../utils/misc-utils" - -// const expectRevert = require("@openzeppelin/test-helpers").expectRevert - -// contract("LendingPool - stable rate economy tests", async ([deployer, ...users]) => { -// let _testEnvProvider: ITestEnvWithoutInstances -// let _lendingPoolInstance: LendingPoolInstance -// let _lendingPoolCoreInstance: LendingPoolCoreInstance -// let _aTokenInstances: iATokenBase -// let _tokenInstances: iAssetsWithoutETH - -// let _daiAddress: string - -// let _depositorAddress: string -// let _borrowerAddress: string - -// let _web3: Web3 - -// before("Initializing LendingPool test variables", async () => { -// console.time('setup-test'); -// _testEnvProvider = await testEnvProviderWithoutInstances( -// artifacts, -// [deployer, ...users] -// ) - -// const { -// getWeb3, -// getAllAssetsInstances, -// getFirstBorrowerAddressOnTests, -// getFirstDepositorAddressOnTests, -// getLendingPoolInstance, -// getLendingPoolCoreInstance, -// getATokenInstances -// } = _testEnvProvider - -// const instances = await Promise.all([ -// getLendingPoolInstance(), -// getLendingPoolCoreInstance(), -// getATokenInstances(), -// getAllAssetsInstances() -// ]) -// _lendingPoolInstance = instances[0] -// _lendingPoolCoreInstance = instances[1] -// _aTokenInstances = instances[2] -// _tokenInstances = instances[3] -// _daiAddress = _tokenInstances.DAI.address -// _depositorAddress = await getFirstDepositorAddressOnTests() -// _borrowerAddress = await getFirstBorrowerAddressOnTests() - -// _web3 = await getWeb3() -// console.timeEnd('setup-test'); -// }) - -// it("BORROW - Test user cannot borrow using the same currency as collateral", async () => { -// const {aDAI: aDaiInstance} = _aTokenInstances -// const {DAI: daiInstance} = _tokenInstances - -// //mints DAI to depositor -// await daiInstance.mint(await convertToCurrencyDecimals(daiInstance.address, "1000"), { -// from: _depositorAddress, -// }) - -// //mints DAI to borrower -// await daiInstance.mint(await convertToCurrencyDecimals(daiInstance.address, "1000"), { -// from: _borrowerAddress, -// }) - -// //approve protocol to access depositor wallet -// await daiInstance.approve(_lendingPoolCoreInstance.address, APPROVAL_AMOUNT_LENDING_POOL_CORE, { -// from: _depositorAddress, -// }) - -// //approve protocol to access borrower wallet -// await daiInstance.approve(_lendingPoolCoreInstance.address, APPROVAL_AMOUNT_LENDING_POOL_CORE, { -// from: _borrowerAddress, -// }) - -// const amountDAItoDeposit = await convertToCurrencyDecimals(_daiAddress, "1000") - -// //user 1 deposits 1000 DAI -// const txResult = await _lendingPoolInstance.deposit(_daiAddress, amountDAItoDeposit, "0", { -// from: _depositorAddress, -// }) - -// //user 2 deposits 1000 DAI, tries to borrow. Needs to be reverted as you can't borrow at a stable rate with the same collateral as the currency. -// const amountDAIToDepositBorrower = await convertToCurrencyDecimals(_daiAddress, "1000") -// await _lendingPoolInstance.deposit(_daiAddress, amountDAIToDepositBorrower, "0", { -// from: _borrowerAddress, -// }) - -// const data: any = await _lendingPoolInstance.getReserveData(_daiAddress) - -// //user 2 tries to borrow -// const amountDAIToBorrow = await convertToCurrencyDecimals(_daiAddress, "250") - -// //user 2 tries to borrow -// await expectRevert( -// _lendingPoolInstance.borrow(_daiAddress, amountDAIToBorrow, RateMode.Stable, "0", { -// from: _borrowerAddress, -// }), -// "User cannot borrow the selected amount with a stable rate", -// ) -// }) - -// it("BORROW - Test user cannot borrow more than 25% of the liquidity available", async () => { -// const {aDAI: aDaiInstance} = _aTokenInstances -// const {DAI: daiInstance} = _tokenInstances - -// //redeem the DAI previously deposited -// const amountADAIToRedeem = await convertToCurrencyDecimals(aDaiInstance.address, "1000") -// await aDaiInstance.redeem(amountADAIToRedeem, { -// from: _borrowerAddress, -// }) - -// //user 2 deposits 5 ETH tries to borrow. needs to be reverted as you can't borrow more than 25% of the available reserve (250 DAI) -// const amountETHToDeposit = await convertToCurrencyDecimals(ETHEREUM_ADDRESS, "5") -// await _lendingPoolInstance.deposit(ETHEREUM_ADDRESS, amountETHToDeposit, "0", { -// from: _borrowerAddress, -// value: amountETHToDeposit, -// }) - -// const data: any = await _lendingPoolInstance.getReserveData(_daiAddress) - -// const amountDAIToBorrow = await convertToCurrencyDecimals(_daiAddress, "500") - -// //user 2 tries to borrow -// await expectRevert( -// _lendingPoolInstance.borrow(_daiAddress, amountDAIToBorrow, RateMode.Stable, "0", { -// from: _borrowerAddress, -// }), -// "User is trying to borrow too much liquidity at a stable rate", -// ) -// }) - -// it("BORROW - Test user can still borrow a currency that he previously deposited as a collateral but he transferred/redeemed", async () => { -// const {aDAI: aDaiInstance} = _aTokenInstances -// const {DAI: daiInstance} = _tokenInstances - -// const user = users[2] - -// //user deposits 1000 DAI -// await daiInstance.mint(await convertToCurrencyDecimals(daiInstance.address, "1000"), { -// from: user, -// }) -// await daiInstance.approve(_lendingPoolCoreInstance.address, APPROVAL_AMOUNT_LENDING_POOL_CORE, { -// from: user, -// }) - -// const amountDAIToDeposit = await convertToCurrencyDecimals(daiInstance.address, "1000") -// await _lendingPoolInstance.deposit(daiInstance.address, amountDAIToDeposit, "0", { -// from: user, -// }) - -// //user deposits 5 ETH as collateral -// const amountETHToDeposit = await convertToCurrencyDecimals(ETHEREUM_ADDRESS, "5") -// await _lendingPoolInstance.deposit(ETHEREUM_ADDRESS, amountETHToDeposit, "0", { -// from: user, -// value: amountETHToDeposit, -// }) - -// //user transfers to another address all the overlying aDAI - -// const aDAIBalance = await aDaiInstance.balanceOf(user) - -// await aDaiInstance.transfer(users[3], aDAIBalance, { -// from: user, -// }) - -// //check the underlying balance is 0 -// const userData: any = await _lendingPoolInstance.getUserReserveData(daiInstance.address, user) - -// expect(userData.currentATokenBalance.toString()).to.be.equal("0") - -// //user tries to borrow the DAI at a stable rate using the ETH as collateral -// const amountDAIToBorrow = await convertToCurrencyDecimals(_daiAddress, "100") - -// //user tries to borrow. No revert expected -// await _lendingPoolInstance.borrow(_daiAddress, amountDAIToBorrow, RateMode.Stable, "0", { -// from: user, -// }) -// }) -// }) diff --git a/test/stable-token.spec.ts b/test/stable-token.spec.ts deleted file mode 100644 index ab588a81..00000000 --- a/test/stable-token.spec.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { expect } from 'chai'; -import { makeSuite, TestEnv } from './helpers/make-suite'; -import { ProtocolErrors } from '../helpers/types'; -import { getStableDebtToken } from '../helpers/contracts-getters'; - -makeSuite('Stable debt token tests', (testEnv: TestEnv) => { - const { CT_CALLER_MUST_BE_LENDING_POOL } = ProtocolErrors; - - it('Tries to invoke mint not being the LendingPool', async () => { - const { deployer, pool, dai, helpersContract } = testEnv; - - const daiStableDebtTokenAddress = (await helpersContract.getReserveTokensAddresses(dai.address)) - .stableDebtTokenAddress; - - const stableDebtContract = await getStableDebtToken(daiStableDebtTokenAddress); - - await expect( - stableDebtContract.mint(deployer.address, deployer.address, '1', '1') - ).to.be.revertedWith(CT_CALLER_MUST_BE_LENDING_POOL); - }); - - it('Tries to invoke burn not being the LendingPool', async () => { - const { deployer, dai, helpersContract } = testEnv; - - const daiStableDebtTokenAddress = (await helpersContract.getReserveTokensAddresses(dai.address)) - .stableDebtTokenAddress; - - const stableDebtContract = await getStableDebtToken(daiStableDebtTokenAddress); - - const name = await stableDebtContract.name(); - - expect(name).to.be.equal('Aave stable debt bearing DAI'); - await expect(stableDebtContract.burn(deployer.address, '1')).to.be.revertedWith( - CT_CALLER_MUST_BE_LENDING_POOL - ); - }); -}); diff --git a/test/subgraph-scenarios.spec.ts b/test/subgraph-scenarios.spec.ts deleted file mode 100644 index 27f0b994..00000000 --- a/test/subgraph-scenarios.spec.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { configuration as actionsConfiguration } from './helpers/actions'; -import { configuration as calculationsConfiguration } from './helpers/utils/calculations'; - -import BigNumber from 'bignumber.js'; -import { makeSuite } from './helpers/make-suite'; -import { getReservesConfigByPool } from '../helpers/configuration'; -import { AavePools, iAavePoolAssets, IReserveParams } from '../helpers/types'; -import { executeStory } from './helpers/scenario-engine'; - -makeSuite('Subgraph scenario tests', async (testEnv) => { - let story: any; - let scenario; - before('Initializing configuration', async () => { - const scenario = require(`./helpers/scenarios/borrow-repay-stable`); - story = scenario.stories[0]; - // Sets BigNumber for this suite, instead of globally - BigNumber.config({ DECIMAL_PLACES: 0, ROUNDING_MODE: BigNumber.ROUND_DOWN }); - - actionsConfiguration.skipIntegrityCheck = false; //set this to true to execute solidity-coverage - - calculationsConfiguration.reservesParams = >( - getReservesConfigByPool(AavePools.proto) - ); - }); - after('Reset', () => { - // Reset BigNumber - BigNumber.config({ DECIMAL_PLACES: 20, ROUNDING_MODE: BigNumber.ROUND_HALF_UP }); - }); - it('deposit-borrow', async () => { - await executeStory(story, testEnv); - }); -}); diff --git a/test/uniswapAdapters.base.spec.ts b/test/uniswapAdapters.base.spec.ts deleted file mode 100644 index 80f76725..00000000 --- a/test/uniswapAdapters.base.spec.ts +++ /dev/null @@ -1,227 +0,0 @@ -import { makeSuite, TestEnv } from './helpers/make-suite'; -import { convertToCurrencyDecimals } from '../helpers/contracts-helpers'; -import { getMockUniswapRouter } from '../helpers/contracts-getters'; -import { MockUniswapV2Router02 } from '../types/MockUniswapV2Router02'; -import BigNumber from 'bignumber.js'; -import { evmRevert, evmSnapshot } from '../helpers/misc-utils'; -import { ethers } from 'ethers'; -import { USD_ADDRESS } from '../helpers/constants'; -const { parseEther } = ethers.utils; - -const { expect } = require('chai'); - -makeSuite('Uniswap adapters', (testEnv: TestEnv) => { - let mockUniswapRouter: MockUniswapV2Router02; - let evmSnapshotId: string; - - before(async () => { - mockUniswapRouter = await getMockUniswapRouter(); - }); - - beforeEach(async () => { - evmSnapshotId = await evmSnapshot(); - }); - - afterEach(async () => { - await evmRevert(evmSnapshotId); - }); - - describe('BaseUniswapAdapter', () => { - describe('getAmountsOut', () => { - it('should return the estimated amountOut and prices for the asset swap', async () => { - const { weth, dai, uniswapLiquiditySwapAdapter, oracle } = testEnv; - - const amountIn = parseEther('1'); - const flashloanPremium = amountIn.mul(9).div(10000); - const amountToSwap = amountIn.sub(flashloanPremium); - - const wethPrice = await oracle.getAssetPrice(weth.address); - const daiPrice = await oracle.getAssetPrice(dai.address); - const usdPrice = await oracle.getAssetPrice(USD_ADDRESS); - - const expectedDaiAmount = await convertToCurrencyDecimals( - dai.address, - new BigNumber(amountToSwap.toString()).div(daiPrice.toString()).toFixed(0) - ); - - const outPerInPrice = amountToSwap - .mul(parseEther('1')) - .mul(parseEther('1')) - .div(expectedDaiAmount.mul(parseEther('1'))); - const ethUsdValue = amountIn - .mul(wethPrice) - .div(parseEther('1')) - .mul(usdPrice) - .div(parseEther('1')); - const daiUsdValue = expectedDaiAmount - .mul(daiPrice) - .div(parseEther('1')) - .mul(usdPrice) - .div(parseEther('1')); - - await mockUniswapRouter.setAmountOut( - amountToSwap, - weth.address, - dai.address, - expectedDaiAmount - ); - - const result = await uniswapLiquiditySwapAdapter.getAmountsOut( - amountIn, - weth.address, - dai.address - ); - - expect(result['0']).to.be.eq(expectedDaiAmount); - expect(result['1']).to.be.eq(outPerInPrice); - expect(result['2']).to.be.eq(ethUsdValue); - expect(result['3']).to.be.eq(daiUsdValue); - }); - it('should work correctly with different decimals', async () => { - const { aave, usdc, uniswapLiquiditySwapAdapter, oracle } = testEnv; - - const amountIn = parseEther('10'); - const flashloanPremium = amountIn.mul(9).div(10000); - const amountToSwap = amountIn.sub(flashloanPremium); - - const aavePrice = await oracle.getAssetPrice(aave.address); - const usdcPrice = await oracle.getAssetPrice(usdc.address); - const usdPrice = await oracle.getAssetPrice(USD_ADDRESS); - - const expectedUSDCAmount = await convertToCurrencyDecimals( - usdc.address, - new BigNumber(amountToSwap.toString()).div(usdcPrice.toString()).toFixed(0) - ); - - const outPerInPrice = amountToSwap - .mul(parseEther('1')) - .mul('1000000') // usdc 6 decimals - .div(expectedUSDCAmount.mul(parseEther('1'))); - - const aaveUsdValue = amountIn - .mul(aavePrice) - .div(parseEther('1')) - .mul(usdPrice) - .div(parseEther('1')); - - const usdcUsdValue = expectedUSDCAmount - .mul(usdcPrice) - .div('1000000') // usdc 6 decimals - .mul(usdPrice) - .div(parseEther('1')); - - await mockUniswapRouter.setAmountOut( - amountToSwap, - aave.address, - usdc.address, - expectedUSDCAmount - ); - - const result = await uniswapLiquiditySwapAdapter.getAmountsOut( - amountIn, - aave.address, - usdc.address - ); - - expect(result['0']).to.be.eq(expectedUSDCAmount); - expect(result['1']).to.be.eq(outPerInPrice); - expect(result['2']).to.be.eq(aaveUsdValue); - expect(result['3']).to.be.eq(usdcUsdValue); - }); - }); - - describe('getAmountsIn', () => { - it('should return the estimated required amountIn for the asset swap', async () => { - const { weth, dai, uniswapLiquiditySwapAdapter, oracle } = testEnv; - - const amountIn = parseEther('1'); - const flashloanPremium = amountIn.mul(9).div(10000); - const amountToSwap = amountIn.add(flashloanPremium); - - const wethPrice = await oracle.getAssetPrice(weth.address); - const daiPrice = await oracle.getAssetPrice(dai.address); - const usdPrice = await oracle.getAssetPrice(USD_ADDRESS); - - const amountOut = await convertToCurrencyDecimals( - dai.address, - new BigNumber(amountIn.toString()).div(daiPrice.toString()).toFixed(0) - ); - - const inPerOutPrice = amountOut - .mul(parseEther('1')) - .mul(parseEther('1')) - .div(amountToSwap.mul(parseEther('1'))); - - const ethUsdValue = amountToSwap - .mul(wethPrice) - .div(parseEther('1')) - .mul(usdPrice) - .div(parseEther('1')); - const daiUsdValue = amountOut - .mul(daiPrice) - .div(parseEther('1')) - .mul(usdPrice) - .div(parseEther('1')); - - await mockUniswapRouter.setAmountIn(amountOut, weth.address, dai.address, amountIn); - - const result = await uniswapLiquiditySwapAdapter.getAmountsIn( - amountOut, - weth.address, - dai.address - ); - - expect(result['0']).to.be.eq(amountToSwap); - expect(result['1']).to.be.eq(inPerOutPrice); - expect(result['2']).to.be.eq(ethUsdValue); - expect(result['3']).to.be.eq(daiUsdValue); - }); - it('should work correctly with different decimals', async () => { - const { aave, usdc, uniswapLiquiditySwapAdapter, oracle } = testEnv; - - const amountIn = parseEther('10'); - const flashloanPremium = amountIn.mul(9).div(10000); - const amountToSwap = amountIn.add(flashloanPremium); - - const aavePrice = await oracle.getAssetPrice(aave.address); - const usdcPrice = await oracle.getAssetPrice(usdc.address); - const usdPrice = await oracle.getAssetPrice(USD_ADDRESS); - - const amountOut = await convertToCurrencyDecimals( - usdc.address, - new BigNumber(amountToSwap.toString()).div(usdcPrice.toString()).toFixed(0) - ); - - const inPerOutPrice = amountOut - .mul(parseEther('1')) - .mul(parseEther('1')) - .div(amountToSwap.mul('1000000')); // usdc 6 decimals - - const aaveUsdValue = amountToSwap - .mul(aavePrice) - .div(parseEther('1')) - .mul(usdPrice) - .div(parseEther('1')); - - const usdcUsdValue = amountOut - .mul(usdcPrice) - .div('1000000') // usdc 6 decimals - .mul(usdPrice) - .div(parseEther('1')); - - await mockUniswapRouter.setAmountIn(amountOut, aave.address, usdc.address, amountIn); - - const result = await uniswapLiquiditySwapAdapter.getAmountsIn( - amountOut, - aave.address, - usdc.address - ); - - expect(result['0']).to.be.eq(amountToSwap); - expect(result['1']).to.be.eq(inPerOutPrice); - expect(result['2']).to.be.eq(aaveUsdValue); - expect(result['3']).to.be.eq(usdcUsdValue); - }); - }); - }); -}); diff --git a/test/uniswapAdapters.flashLiquidation.spec.ts b/test/uniswapAdapters.flashLiquidation.spec.ts deleted file mode 100644 index 063c6930..00000000 --- a/test/uniswapAdapters.flashLiquidation.spec.ts +++ /dev/null @@ -1,850 +0,0 @@ -import { makeSuite, TestEnv } from './helpers/make-suite'; -import { - convertToCurrencyDecimals, - buildFlashLiquidationAdapterParams, -} from '../helpers/contracts-helpers'; -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, 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'; -import { getUserData } from './helpers/utils/helpers'; -import { calcExpectedStableDebtTokenBalance } from './helpers/utils/calculations'; -const { expect } = require('chai'); - -makeSuite('Uniswap adapters', (testEnv: TestEnv) => { - let mockUniswapRouter: MockUniswapV2Router02; - let evmSnapshotId: string; - const { INVALID_HF, LP_LIQUIDATION_CALL_FAILED } = ProtocolErrors; - - before(async () => { - mockUniswapRouter = await getMockUniswapRouter(); - }); - - const depositAndHFBelowOne = 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.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.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 - ); - }; - - 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(); - }); - - afterEach(async () => { - await evmRevert(evmSnapshotId); - }); - - describe('Flash Liquidation Adapter', () => { - 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 }); - }); - - describe('constructor', () => { - it('should deploy with correct parameters', async () => { - const { addressesProvider, weth } = testEnv; - await deployFlashLiquidationAdapter([ - addressesProvider.address, - mockUniswapRouter.address, - weth.address, - ]); - }); - - it('should revert if not valid addresses provider', async () => { - const { weth } = testEnv; - expect( - deployFlashLiquidationAdapter([ - mockUniswapRouter.address, - mockUniswapRouter.address, - weth.address, - ]) - ).to.be.reverted; - }); - }); - - describe('executeOperation: succesfully liquidateCall and swap via Flash Loan with profits', () => { - it('Liquidates the borrow with profit', async () => { - await depositAndHFBelowOne(); - await increaseTime(100); - - const { - dai, - weth, - users, - pool, - oracle, - helpersContract, - flashLiquidationAdapter, - } = testEnv; - - const liquidator = users[3]; - const borrower = users[1]; - const expectedSwap = ethers.utils.parseEther('0.4'); - - const liquidatorWethBalanceBefore = await weth.balanceOf(liquidator.address); - - // Set how much ETH will be sold and swapped for DAI at Uniswap mock - await (await mockUniswapRouter.setAmountToSwap(weth.address, expectedSwap)).wait(); - - const collateralPrice = await oracle.getAssetPrice(weth.address); - const principalPrice = await oracle.getAssetPrice(dai.address); - 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 collateralDecimals = ( - await helpersContract.getReserveConfigurationData(weth.address) - ).decimals.toString(); - const principalDecimals = ( - await helpersContract.getReserveConfigurationData(dai.address) - ).decimals.toString(); - const amountToLiquidate = userReserveDataBefore.currentStableDebt.div(2).toFixed(0); - - 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); - - const flashLoanDebt = new BigNumber(amountToLiquidate.toString()) - .multipliedBy(1.0009) - .toFixed(0); - - const expectedProfit = ethers.BigNumber.from(expectedCollateralLiquidated.toString()).sub( - expectedSwap - ); - - const params = buildFlashLiquidationAdapterParams( - weth.address, - dai.address, - borrower.address, - amountToLiquidate, - false - ); - const tx = await pool - .connect(liquidator.signer) - .flashLoan( - flashLiquidationAdapter.address, - [dai.address], - [amountToLiquidate], - [0], - borrower.address, - params, - 0 - ); - - // Expect Swapped event - await expect(Promise.resolve(tx)).to.emit(flashLiquidationAdapter, 'Swapped'); - - // Expect LiquidationCall event - await expect(Promise.resolve(tx)).to.emit(pool, 'LiquidationCall'); - - const userReserveDataAfter = await getUserData( - pool, - helpersContract, - dai.address, - borrower.address - ); - const liquidatorWethBalanceAfter = await weth.balanceOf(liquidator.address); - - const daiReserveDataAfter = await helpersContract.getReserveData(dai.address); - const ethReserveDataAfter = await helpersContract.getReserveData(weth.address); - - 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 - ); - - 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' - ); - - //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(flashLoanDebt) - .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' - ); - - // Profit after flash loan liquidation - expect(liquidatorWethBalanceAfter).to.be.equal( - liquidatorWethBalanceBefore.add(expectedProfit), - 'Invalid expected WETH profit' - ); - }); - }); - - 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(); - await increaseTime(100); - - const { - dai, - weth, - users, - pool, - oracle, - helpersContract, - flashLiquidationAdapter, - } = testEnv; - - const liquidator = users[3]; - const borrower = users[1]; - const liquidatorWethBalanceBefore = await weth.balanceOf(liquidator.address); - - const collateralPrice = await oracle.getAssetPrice(weth.address); - const principalPrice = await oracle.getAssetPrice(dai.address); - 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 collateralDecimals = ( - await helpersContract.getReserveConfigurationData(weth.address) - ).decimals.toString(); - const principalDecimals = ( - await helpersContract.getReserveConfigurationData(dai.address) - ).decimals.toString(); - const amountToLiquidate = userReserveDataBefore.currentStableDebt.div(2).toFixed(0); - - 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); - - 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 ( - await mockUniswapRouter.setAmountToSwap( - weth.address, - expectedCollateralLiquidated.toString() - ) - ).wait(); - - const params = buildFlashLiquidationAdapterParams( - weth.address, - dai.address, - borrower.address, - amountToLiquidate, - false - ); - const tx = await pool - .connect(liquidator.signer) - .flashLoan( - flashLiquidationAdapter.address, - [dai.address], - [flashLoanDebt], - [0], - borrower.address, - params, - 0 - ); - - // Expect Swapped event - await expect(Promise.resolve(tx)).to.emit(flashLiquidationAdapter, 'Swapped'); - - // Expect LiquidationCall event - await expect(Promise.resolve(tx)).to.emit(pool, 'LiquidationCall'); - - const userReserveDataAfter = await getUserData( - pool, - helpersContract, - dai.address, - borrower.address - ); - const liquidatorWethBalanceAfter = await weth.balanceOf(liquidator.address); - - const daiReserveDataAfter = await helpersContract.getReserveData(dai.address); - const ethReserveDataAfter = await helpersContract.getReserveData(weth.address); - - 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 - ); - - 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' - ); - - //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(ethReserveDataAfter.availableLiquidity.toString()).to.be.bignumber.almostEqual( - new BigNumber(ethReserveDataBefore.availableLiquidity.toString()) - .minus(expectedCollateralLiquidated) - .toFixed(0), - 'Invalid collateral available liquidity' - ); - - // Net Profit == 0 after flash loan liquidation - expect(liquidatorWethBalanceAfter).to.be.equal( - liquidatorWethBalanceBefore, - 'Invalid expected WETH profit' - ); - }); - }); - - describe('executeOperation: succesfully liquidateCall all available debt and swap via Flash Loan ', () => { - it('Liquidates the borrow', async () => { - await depositAndHFBelowOne(); - await increaseTime(100); - - const { - dai, - weth, - users, - pool, - oracle, - helpersContract, - flashLiquidationAdapter, - } = testEnv; - - const liquidator = users[3]; - const borrower = users[1]; - const liquidatorWethBalanceBefore = await weth.balanceOf(liquidator.address); - - const collateralPrice = await oracle.getAssetPrice(weth.address); - const principalPrice = await oracle.getAssetPrice(dai.address); - 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 collateralDecimals = ( - await helpersContract.getReserveConfigurationData(weth.address) - ).decimals.toString(); - const principalDecimals = ( - await helpersContract.getReserveConfigurationData(dai.address) - ).decimals.toString(); - const amountToLiquidate = userReserveDataBefore.currentStableDebt.div(2).toFixed(0); - const extraAmount = new BigNumber(amountToLiquidate).times('1.15').toFixed(0); - - 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); - - 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 ( - await mockUniswapRouter.setAmountToSwap( - weth.address, - expectedCollateralLiquidated.toString() - ) - ).wait(); - - const params = buildFlashLiquidationAdapterParams( - weth.address, - dai.address, - borrower.address, - MAX_UINT_AMOUNT, - false - ); - const tx = await pool - .connect(liquidator.signer) - .flashLoan( - flashLiquidationAdapter.address, - [dai.address], - [extraAmount], - [0], - borrower.address, - params, - 0 - ); - - // Expect Swapped event - 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.' - ); - }); - }); - - describe('executeOperation: invalid params', async () => { - it('Revert if debt asset is different than requested flash loan token', async () => { - await depositAndHFBelowOne(); - - const { dai, weth, users, pool, helpersContract, flashLiquidationAdapter } = testEnv; - - const liquidator = users[3]; - const borrower = users[1]; - const expectedSwap = ethers.utils.parseEther('0.4'); - - // Set how much ETH will be sold and swapped for DAI at Uniswap mock - await (await mockUniswapRouter.setAmountToSwap(weth.address, expectedSwap)).wait(); - - const userReserveDataBefore = await getUserData( - pool, - helpersContract, - dai.address, - borrower.address - ); - - const amountToLiquidate = userReserveDataBefore.currentStableDebt.div(2).toFixed(0); - - // Wrong debt asset - const params = buildFlashLiquidationAdapterParams( - weth.address, - weth.address, // intentionally bad - borrower.address, - amountToLiquidate, - false - ); - await expect( - pool - .connect(liquidator.signer) - .flashLoan( - flashLiquidationAdapter.address, - [dai.address], - [amountToLiquidate], - [0], - borrower.address, - params, - 0 - ) - ).to.be.revertedWith('INCONSISTENT_PARAMS'); - }); - - it('Revert if debt asset amount to liquidate is greater than requested flash loan', async () => { - await depositAndHFBelowOne(); - - const { dai, weth, users, pool, helpersContract, flashLiquidationAdapter } = testEnv; - - const liquidator = users[3]; - const borrower = users[1]; - const expectedSwap = ethers.utils.parseEther('0.4'); - - // Set how much ETH will be sold and swapped for DAI at Uniswap mock - await (await mockUniswapRouter.setAmountToSwap(weth.address, expectedSwap)).wait(); - - const userReserveDataBefore = await getUserData( - pool, - helpersContract, - dai.address, - borrower.address - ); - - const amountToLiquidate = userReserveDataBefore.currentStableDebt.div(2); - - // Correct params - const params = buildFlashLiquidationAdapterParams( - weth.address, - dai.address, - borrower.address, - amountToLiquidate.toString(), - false - ); - // Bad flash loan params: requested DAI amount below amountToLiquidate - await expect( - pool - .connect(liquidator.signer) - .flashLoan( - flashLiquidationAdapter.address, - [dai.address], - [amountToLiquidate.div(2).toString()], - [0], - borrower.address, - params, - 0 - ) - ).to.be.revertedWith(LP_LIQUIDATION_CALL_FAILED); - }); - - it('Revert if requested multiple assets', async () => { - await depositAndHFBelowOne(); - - const { dai, weth, users, pool, helpersContract, flashLiquidationAdapter } = testEnv; - - const liquidator = users[3]; - const borrower = users[1]; - const expectedSwap = ethers.utils.parseEther('0.4'); - - // Set how much ETH will be sold and swapped for DAI at Uniswap mock - await (await mockUniswapRouter.setAmountToSwap(weth.address, expectedSwap)).wait(); - - const userReserveDataBefore = await getUserData( - pool, - helpersContract, - dai.address, - borrower.address - ); - - const amountToLiquidate = userReserveDataBefore.currentStableDebt.div(2); - - // Correct params - const params = buildFlashLiquidationAdapterParams( - weth.address, - dai.address, - borrower.address, - amountToLiquidate.toString(), - false - ); - // Bad flash loan params: requested multiple assets - await expect( - pool - .connect(liquidator.signer) - .flashLoan( - flashLiquidationAdapter.address, - [dai.address, weth.address], - [10, 10], - [0], - borrower.address, - params, - 0 - ) - ).to.be.revertedWith('INCONSISTENT_PARAMS'); - }); - }); - }); -}); diff --git a/test/uniswapAdapters.liquiditySwap.spec.ts b/test/uniswapAdapters.liquiditySwap.spec.ts deleted file mode 100644 index 1e30b2b3..00000000 --- a/test/uniswapAdapters.liquiditySwap.spec.ts +++ /dev/null @@ -1,1854 +0,0 @@ -import { makeSuite, TestEnv } from './helpers/make-suite'; -import { - convertToCurrencyDecimals, - getContract, - buildPermitParams, - getSignatureFromTypedData, - buildLiquiditySwapParams, -} from '../helpers/contracts-helpers'; -import { getMockUniswapRouter } from '../helpers/contracts-getters'; -import { deployUniswapLiquiditySwapAdapter } from '../helpers/contracts-deployments'; -import { MockUniswapV2Router02 } from '../types/MockUniswapV2Router02'; -import { Zero } from '@ethersproject/constants'; -import BigNumber from 'bignumber.js'; -import { DRE, evmRevert, evmSnapshot } from '../helpers/misc-utils'; -import { ethers } from 'ethers'; -import { eContractid } from '../helpers/types'; -import { AToken } from '../types/AToken'; -import { BUIDLEREVM_CHAINID } from '../helpers/buidler-constants'; -import { MAX_UINT_AMOUNT } from '../helpers/constants'; -const { parseEther } = ethers.utils; - -const { expect } = require('chai'); - -makeSuite('Uniswap adapters', (testEnv: TestEnv) => { - let mockUniswapRouter: MockUniswapV2Router02; - let evmSnapshotId: string; - - before(async () => { - mockUniswapRouter = await getMockUniswapRouter(); - }); - - beforeEach(async () => { - evmSnapshotId = await evmSnapshot(); - }); - - afterEach(async () => { - await evmRevert(evmSnapshotId); - }); - - describe('UniswapLiquiditySwapAdapter', () => { - describe('constructor', () => { - it('should deploy with correct parameters', async () => { - const { addressesProvider, weth } = testEnv; - await deployUniswapLiquiditySwapAdapter([ - addressesProvider.address, - mockUniswapRouter.address, - weth.address, - ]); - }); - - it('should revert if not valid addresses provider', async () => { - const { weth } = testEnv; - expect( - deployUniswapLiquiditySwapAdapter([ - mockUniswapRouter.address, - mockUniswapRouter.address, - weth.address, - ]) - ).to.be.reverted; - }); - }); - - describe('executeOperation', () => { - beforeEach(async () => { - const { users, weth, dai, usdc, pool, deployer } = testEnv; - const userAddress = users[0].address; - - // Provide liquidity - await dai.mint(parseEther('20000')); - await dai.approve(pool.address, parseEther('20000')); - await pool.deposit(dai.address, parseEther('20000'), deployer.address, 0); - - const usdcAmount = await convertToCurrencyDecimals(usdc.address, '10'); - await usdc.mint(usdcAmount); - await usdc.approve(pool.address, usdcAmount); - await pool.deposit(usdc.address, usdcAmount, deployer.address, 0); - - // Make a deposit for user - await weth.mint(parseEther('100')); - await weth.approve(pool.address, parseEther('100')); - await pool.deposit(weth.address, parseEther('100'), userAddress, 0); - }); - - it('should correctly swap tokens and deposit the out tokens in the pool', async () => { - const { - users, - weth, - oracle, - dai, - aDai, - aWETH, - pool, - uniswapLiquiditySwapAdapter, - } = testEnv; - const user = users[0].signer; - const userAddress = users[0].address; - - const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); - - const daiPrice = await oracle.getAssetPrice(dai.address); - const expectedDaiAmount = await convertToCurrencyDecimals( - dai.address, - new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) - ); - - await mockUniswapRouter.setAmountToReturn(weth.address, expectedDaiAmount); - - // User will swap liquidity 10 aEth to aDai - const liquidityToSwap = parseEther('10'); - await aWETH.connect(user).approve(uniswapLiquiditySwapAdapter.address, liquidityToSwap); - const userAEthBalanceBefore = await aWETH.balanceOf(userAddress); - - // Subtract the FL fee from the amount to be swapped 0,09% - const flashloanAmount = new BigNumber(liquidityToSwap.toString()).div(1.0009).toFixed(0); - - const params = buildLiquiditySwapParams( - [dai.address], - [expectedDaiAmount], - [0], - [0], - [0], - [0], - ['0x0000000000000000000000000000000000000000000000000000000000000000'], - ['0x0000000000000000000000000000000000000000000000000000000000000000'], - [false] - ); - - await expect( - pool - .connect(user) - .flashLoan( - uniswapLiquiditySwapAdapter.address, - [weth.address], - [flashloanAmount.toString()], - [0], - userAddress, - params, - 0 - ) - ) - .to.emit(uniswapLiquiditySwapAdapter, 'Swapped') - .withArgs(weth.address, dai.address, flashloanAmount.toString(), expectedDaiAmount); - - const adapterWethBalance = await weth.balanceOf(uniswapLiquiditySwapAdapter.address); - const adapterDaiBalance = await dai.balanceOf(uniswapLiquiditySwapAdapter.address); - const adapterDaiAllowance = await dai.allowance( - uniswapLiquiditySwapAdapter.address, - userAddress - ); - const userADaiBalance = await aDai.balanceOf(userAddress); - const userAEthBalance = await aWETH.balanceOf(userAddress); - - expect(adapterWethBalance).to.be.eq(Zero); - expect(adapterDaiBalance).to.be.eq(Zero); - expect(adapterDaiAllowance).to.be.eq(Zero); - expect(userADaiBalance).to.be.eq(expectedDaiAmount); - expect(userAEthBalance).to.be.lt(userAEthBalanceBefore); - expect(userAEthBalance).to.be.gte(userAEthBalanceBefore.sub(liquidityToSwap)); - }); - - it('should correctly swap and deposit multiple tokens', async () => { - const { - users, - weth, - oracle, - dai, - aDai, - aWETH, - usdc, - pool, - uniswapLiquiditySwapAdapter, - } = testEnv; - const user = users[0].signer; - const userAddress = users[0].address; - - const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); - - const daiPrice = await oracle.getAssetPrice(dai.address); - const expectedDaiAmountForEth = await convertToCurrencyDecimals( - dai.address, - new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) - ); - - const amountUSDCtoSwap = await convertToCurrencyDecimals(usdc.address, '10'); - const usdcPrice = await oracle.getAssetPrice(usdc.address); - - const collateralDecimals = (await usdc.decimals()).toString(); - const principalDecimals = (await dai.decimals()).toString(); - - const expectedDaiAmountForUsdc = await convertToCurrencyDecimals( - dai.address, - new BigNumber(amountUSDCtoSwap.toString()) - .times( - new BigNumber(usdcPrice.toString()).times(new BigNumber(10).pow(principalDecimals)) - ) - .div( - new BigNumber(daiPrice.toString()).times(new BigNumber(10).pow(collateralDecimals)) - ) - .toFixed(0) - ); - - // Make a deposit for user - await usdc.connect(user).mint(amountUSDCtoSwap); - await usdc.connect(user).approve(pool.address, amountUSDCtoSwap); - await pool.connect(user).deposit(usdc.address, amountUSDCtoSwap, userAddress, 0); - - const aUsdcData = await pool.getReserveData(usdc.address); - const aUsdc = await getContract(eContractid.AToken, aUsdcData.aTokenAddress); - - await mockUniswapRouter.setAmountToReturn(weth.address, expectedDaiAmountForEth); - await mockUniswapRouter.setAmountToReturn(usdc.address, expectedDaiAmountForUsdc); - - await aWETH.connect(user).approve(uniswapLiquiditySwapAdapter.address, amountWETHtoSwap); - const userAEthBalanceBefore = await aWETH.balanceOf(userAddress); - await aUsdc.connect(user).approve(uniswapLiquiditySwapAdapter.address, amountUSDCtoSwap); - const userAUsdcBalanceBefore = await aUsdc.balanceOf(userAddress); - - // Subtract the FL fee from the amount to be swapped 0,09% - const wethFlashloanAmount = new BigNumber(amountWETHtoSwap.toString()) - .div(1.0009) - .toFixed(0); - const usdcFlashloanAmount = new BigNumber(amountUSDCtoSwap.toString()) - .div(1.0009) - .toFixed(0); - - const params = buildLiquiditySwapParams( - [dai.address, dai.address], - [expectedDaiAmountForEth, expectedDaiAmountForUsdc], - [0, 0], - [0, 0], - [0, 0], - [0, 0], - [ - '0x0000000000000000000000000000000000000000000000000000000000000000', - '0x0000000000000000000000000000000000000000000000000000000000000000', - ], - [ - '0x0000000000000000000000000000000000000000000000000000000000000000', - '0x0000000000000000000000000000000000000000000000000000000000000000', - ], - [false, false] - ); - - await pool - .connect(user) - .flashLoan( - uniswapLiquiditySwapAdapter.address, - [weth.address, usdc.address], - [wethFlashloanAmount.toString(), usdcFlashloanAmount.toString()], - [0, 0], - userAddress, - params, - 0 - ); - - const adapterWethBalance = await weth.balanceOf(uniswapLiquiditySwapAdapter.address); - const adapterDaiBalance = await dai.balanceOf(uniswapLiquiditySwapAdapter.address); - const adapterDaiAllowance = await dai.allowance( - uniswapLiquiditySwapAdapter.address, - userAddress - ); - const userADaiBalance = await aDai.balanceOf(userAddress); - const userAEthBalance = await aWETH.balanceOf(userAddress); - const userAUsdcBalance = await aUsdc.balanceOf(userAddress); - - expect(adapterWethBalance).to.be.eq(Zero); - expect(adapterDaiBalance).to.be.eq(Zero); - expect(adapterDaiAllowance).to.be.eq(Zero); - expect(userADaiBalance).to.be.eq(expectedDaiAmountForEth.add(expectedDaiAmountForUsdc)); - expect(userAEthBalance).to.be.lt(userAEthBalanceBefore); - expect(userAEthBalance).to.be.gte(userAEthBalanceBefore.sub(amountWETHtoSwap)); - expect(userAUsdcBalance).to.be.lt(userAUsdcBalanceBefore); - expect(userAUsdcBalance).to.be.gte(userAUsdcBalanceBefore.sub(amountUSDCtoSwap)); - }); - - it('should correctly swap and deposit multiple tokens using permit', async () => { - const { - users, - weth, - oracle, - dai, - aDai, - aWETH, - usdc, - pool, - uniswapLiquiditySwapAdapter, - } = testEnv; - const user = users[0].signer; - const userAddress = users[0].address; - const chainId = DRE.network.config.chainId || BUIDLEREVM_CHAINID; - const deadline = MAX_UINT_AMOUNT; - - const ownerPrivateKey = require('../test-wallets.js').accounts[1].secretKey; - if (!ownerPrivateKey) { - throw new Error('INVALID_OWNER_PK'); - } - - const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); - - const daiPrice = await oracle.getAssetPrice(dai.address); - const expectedDaiAmountForEth = await convertToCurrencyDecimals( - dai.address, - new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) - ); - - const amountUSDCtoSwap = await convertToCurrencyDecimals(usdc.address, '10'); - const usdcPrice = await oracle.getAssetPrice(usdc.address); - - const collateralDecimals = (await usdc.decimals()).toString(); - const principalDecimals = (await dai.decimals()).toString(); - - const expectedDaiAmountForUsdc = await convertToCurrencyDecimals( - dai.address, - new BigNumber(amountUSDCtoSwap.toString()) - .times( - new BigNumber(usdcPrice.toString()).times(new BigNumber(10).pow(principalDecimals)) - ) - .div( - new BigNumber(daiPrice.toString()).times(new BigNumber(10).pow(collateralDecimals)) - ) - .toFixed(0) - ); - - // Make a deposit for user - await usdc.connect(user).mint(amountUSDCtoSwap); - await usdc.connect(user).approve(pool.address, amountUSDCtoSwap); - await pool.connect(user).deposit(usdc.address, amountUSDCtoSwap, userAddress, 0); - - const aUsdcData = await pool.getReserveData(usdc.address); - const aUsdc = await getContract(eContractid.AToken, aUsdcData.aTokenAddress); - - await mockUniswapRouter.setAmountToReturn(weth.address, expectedDaiAmountForEth); - await mockUniswapRouter.setAmountToReturn(usdc.address, expectedDaiAmountForUsdc); - - const userAEthBalanceBefore = await aWETH.balanceOf(userAddress); - const userAUsdcBalanceBefore = await aUsdc.balanceOf(userAddress); - - const wethFlashloanAmount = new BigNumber(amountWETHtoSwap.toString()) - .div(1.0009) - .toFixed(0); - - const usdcFlashloanAmount = new BigNumber(amountUSDCtoSwap.toString()) - .div(1.0009) - .toFixed(0); - - const aWethNonce = (await aWETH._nonces(userAddress)).toNumber(); - const aWethMsgParams = buildPermitParams( - chainId, - aWETH.address, - '1', - await aWETH.name(), - userAddress, - uniswapLiquiditySwapAdapter.address, - aWethNonce, - deadline, - amountWETHtoSwap.toString() - ); - const { v: aWETHv, r: aWETHr, s: aWETHs } = getSignatureFromTypedData( - ownerPrivateKey, - aWethMsgParams - ); - - const aUsdcNonce = (await aUsdc._nonces(userAddress)).toNumber(); - const aUsdcMsgParams = buildPermitParams( - chainId, - aUsdc.address, - '1', - await aUsdc.name(), - userAddress, - uniswapLiquiditySwapAdapter.address, - aUsdcNonce, - deadline, - amountUSDCtoSwap.toString() - ); - const { v: aUsdcv, r: aUsdcr, s: aUsdcs } = getSignatureFromTypedData( - ownerPrivateKey, - aUsdcMsgParams - ); - const params = buildLiquiditySwapParams( - [dai.address, dai.address], - [expectedDaiAmountForEth, expectedDaiAmountForUsdc], - [0, 0], - [amountWETHtoSwap, amountUSDCtoSwap], - [deadline, deadline], - [aWETHv, aUsdcv], - [aWETHr, aUsdcr], - [aWETHs, aUsdcs], - [false, false] - ); - - await pool - .connect(user) - .flashLoan( - uniswapLiquiditySwapAdapter.address, - [weth.address, usdc.address], - [wethFlashloanAmount.toString(), usdcFlashloanAmount.toString()], - [0, 0], - userAddress, - params, - 0 - ); - - const adapterWethBalance = await weth.balanceOf(uniswapLiquiditySwapAdapter.address); - const adapterDaiBalance = await dai.balanceOf(uniswapLiquiditySwapAdapter.address); - const adapterDaiAllowance = await dai.allowance( - uniswapLiquiditySwapAdapter.address, - userAddress - ); - const userADaiBalance = await aDai.balanceOf(userAddress); - const userAEthBalance = await aWETH.balanceOf(userAddress); - const userAUsdcBalance = await aUsdc.balanceOf(userAddress); - - expect(adapterWethBalance).to.be.eq(Zero); - expect(adapterDaiBalance).to.be.eq(Zero); - expect(adapterDaiAllowance).to.be.eq(Zero); - expect(userADaiBalance).to.be.eq(expectedDaiAmountForEth.add(expectedDaiAmountForUsdc)); - expect(userAEthBalance).to.be.lt(userAEthBalanceBefore); - expect(userAEthBalance).to.be.gte(userAEthBalanceBefore.sub(amountWETHtoSwap)); - expect(userAUsdcBalance).to.be.lt(userAUsdcBalanceBefore); - expect(userAUsdcBalance).to.be.gte(userAUsdcBalanceBefore.sub(amountUSDCtoSwap)); - }); - - it('should correctly swap tokens with permit', async () => { - const { - users, - weth, - oracle, - dai, - aDai, - aWETH, - pool, - uniswapLiquiditySwapAdapter, - } = testEnv; - const user = users[0].signer; - const userAddress = users[0].address; - - const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); - - const daiPrice = await oracle.getAssetPrice(dai.address); - const expectedDaiAmount = await convertToCurrencyDecimals( - dai.address, - new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) - ); - - await mockUniswapRouter.setAmountToReturn(weth.address, expectedDaiAmount); - - // User will swap liquidity 10 aEth to aDai - const liquidityToSwap = parseEther('10'); - const userAEthBalanceBefore = await aWETH.balanceOf(userAddress); - - // Subtract the FL fee from the amount to be swapped 0,09% - const flashloanAmount = new BigNumber(liquidityToSwap.toString()).div(1.0009).toFixed(0); - - const chainId = DRE.network.config.chainId || BUIDLEREVM_CHAINID; - const deadline = MAX_UINT_AMOUNT; - const nonce = (await aWETH._nonces(userAddress)).toNumber(); - const msgParams = buildPermitParams( - chainId, - aWETH.address, - '1', - await aWETH.name(), - userAddress, - uniswapLiquiditySwapAdapter.address, - nonce, - deadline, - liquidityToSwap.toString() - ); - - const ownerPrivateKey = require('../test-wallets.js').accounts[1].secretKey; - if (!ownerPrivateKey) { - throw new Error('INVALID_OWNER_PK'); - } - - const { v, r, s } = getSignatureFromTypedData(ownerPrivateKey, msgParams); - - const params = buildLiquiditySwapParams( - [dai.address], - [expectedDaiAmount], - [0], - [liquidityToSwap], - [deadline], - [v], - [r], - [s], - [false] - ); - - await expect( - pool - .connect(user) - .flashLoan( - uniswapLiquiditySwapAdapter.address, - [weth.address], - [flashloanAmount.toString()], - [0], - userAddress, - params, - 0 - ) - ) - .to.emit(uniswapLiquiditySwapAdapter, 'Swapped') - .withArgs(weth.address, dai.address, flashloanAmount.toString(), expectedDaiAmount); - - const adapterWethBalance = await weth.balanceOf(uniswapLiquiditySwapAdapter.address); - const adapterDaiBalance = await dai.balanceOf(uniswapLiquiditySwapAdapter.address); - const adapterDaiAllowance = await dai.allowance( - uniswapLiquiditySwapAdapter.address, - userAddress - ); - const userADaiBalance = await aDai.balanceOf(userAddress); - const userAEthBalance = await aWETH.balanceOf(userAddress); - - expect(adapterWethBalance).to.be.eq(Zero); - expect(adapterDaiBalance).to.be.eq(Zero); - expect(adapterDaiAllowance).to.be.eq(Zero); - expect(userADaiBalance).to.be.eq(expectedDaiAmount); - expect(userAEthBalance).to.be.lt(userAEthBalanceBefore); - expect(userAEthBalance).to.be.gte(userAEthBalanceBefore.sub(liquidityToSwap)); - }); - - it('should revert if inconsistent params', async () => { - const { users, weth, oracle, dai, aWETH, pool, uniswapLiquiditySwapAdapter } = testEnv; - const user = users[0].signer; - const userAddress = users[0].address; - - const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); - - const daiPrice = await oracle.getAssetPrice(dai.address); - const expectedDaiAmount = await convertToCurrencyDecimals( - dai.address, - new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) - ); - - await mockUniswapRouter.setAmountToReturn(weth.address, expectedDaiAmount); - - // User will swap liquidity 10 aEth to aDai - const liquidityToSwap = parseEther('10'); - await aWETH.connect(user).approve(uniswapLiquiditySwapAdapter.address, liquidityToSwap); - - // Subtract the FL fee from the amount to be swapped 0,09% - const flashloanAmount = new BigNumber(liquidityToSwap.toString()).div(1.0009).toFixed(0); - - const params = buildLiquiditySwapParams( - [dai.address, weth.address], - [expectedDaiAmount], - [0], - [0], - [0], - [0], - ['0x0000000000000000000000000000000000000000000000000000000000000000'], - ['0x0000000000000000000000000000000000000000000000000000000000000000'], - [false] - ); - - await expect( - pool - .connect(user) - .flashLoan( - uniswapLiquiditySwapAdapter.address, - [weth.address], - [flashloanAmount.toString()], - [0], - userAddress, - params, - 0 - ) - ).to.be.revertedWith('INCONSISTENT_PARAMS'); - - const params2 = buildLiquiditySwapParams( - [dai.address, weth.address], - [expectedDaiAmount], - [0, 0], - [0, 0], - [0, 0], - [0], - ['0x0000000000000000000000000000000000000000000000000000000000000000'], - ['0x0000000000000000000000000000000000000000000000000000000000000000'], - [false] - ); - - await expect( - pool - .connect(user) - .flashLoan( - uniswapLiquiditySwapAdapter.address, - [weth.address], - [flashloanAmount.toString()], - [0], - userAddress, - params2, - 0 - ) - ).to.be.revertedWith('INCONSISTENT_PARAMS'); - - const params3 = buildLiquiditySwapParams( - [dai.address, weth.address], - [expectedDaiAmount], - [0, 0], - [0], - [0, 0], - [0, 0], - ['0x0000000000000000000000000000000000000000000000000000000000000000'], - ['0x0000000000000000000000000000000000000000000000000000000000000000'], - [false] - ); - - await expect( - pool - .connect(user) - .flashLoan( - uniswapLiquiditySwapAdapter.address, - [weth.address], - [flashloanAmount.toString()], - [0], - userAddress, - params3, - 0 - ) - ).to.be.revertedWith('INCONSISTENT_PARAMS'); - - const params4 = buildLiquiditySwapParams( - [dai.address, weth.address], - [expectedDaiAmount], - [0], - [0], - [0], - [0], - [ - '0x0000000000000000000000000000000000000000000000000000000000000000', - '0x0000000000000000000000000000000000000000000000000000000000000000', - ], - ['0x0000000000000000000000000000000000000000000000000000000000000000'], - [false] - ); - - await expect( - pool - .connect(user) - .flashLoan( - uniswapLiquiditySwapAdapter.address, - [weth.address], - [flashloanAmount.toString()], - [0], - userAddress, - params4, - 0 - ) - ).to.be.revertedWith('INCONSISTENT_PARAMS'); - - const params5 = buildLiquiditySwapParams( - [dai.address, weth.address], - [expectedDaiAmount], - [0], - [0], - [0], - [0], - ['0x0000000000000000000000000000000000000000000000000000000000000000'], - [ - '0x0000000000000000000000000000000000000000000000000000000000000000', - '0x0000000000000000000000000000000000000000000000000000000000000000', - ], - [false] - ); - - await expect( - pool - .connect(user) - .flashLoan( - uniswapLiquiditySwapAdapter.address, - [weth.address], - [flashloanAmount.toString()], - [0], - userAddress, - params5, - 0 - ) - ).to.be.revertedWith('INCONSISTENT_PARAMS'); - - const params6 = buildLiquiditySwapParams( - [dai.address, weth.address], - [expectedDaiAmount, expectedDaiAmount], - [0], - [0], - [0], - [0], - ['0x0000000000000000000000000000000000000000000000000000000000000000'], - ['0x0000000000000000000000000000000000000000000000000000000000000000'], - [false] - ); - - await expect( - pool - .connect(user) - .flashLoan( - uniswapLiquiditySwapAdapter.address, - [weth.address], - [flashloanAmount.toString()], - [0], - userAddress, - params6, - 0 - ) - ).to.be.revertedWith('INCONSISTENT_PARAMS'); - - const params7 = buildLiquiditySwapParams( - [dai.address], - [expectedDaiAmount], - [0, 0], - [0], - [0], - [0], - ['0x0000000000000000000000000000000000000000000000000000000000000000'], - ['0x0000000000000000000000000000000000000000000000000000000000000000'], - [false] - ); - - await expect( - pool - .connect(user) - .flashLoan( - uniswapLiquiditySwapAdapter.address, - [weth.address], - [flashloanAmount.toString()], - [0], - userAddress, - params7, - 0 - ) - ).to.be.revertedWith('INCONSISTENT_PARAMS'); - - const params8 = buildLiquiditySwapParams( - [dai.address], - [expectedDaiAmount], - [0], - [0, 0], - [0], - [0], - ['0x0000000000000000000000000000000000000000000000000000000000000000'], - ['0x0000000000000000000000000000000000000000000000000000000000000000'], - [false] - ); - - await expect( - pool - .connect(user) - .flashLoan( - uniswapLiquiditySwapAdapter.address, - [weth.address], - [flashloanAmount.toString()], - [0], - userAddress, - params8, - 0 - ) - ).to.be.revertedWith('INCONSISTENT_PARAMS'); - - const params9 = buildLiquiditySwapParams( - [dai.address], - [expectedDaiAmount], - [0], - [0], - [0], - [0], - ['0x0000000000000000000000000000000000000000000000000000000000000000'], - ['0x0000000000000000000000000000000000000000000000000000000000000000'], - [false, false] - ); - - await expect( - pool - .connect(user) - .flashLoan( - uniswapLiquiditySwapAdapter.address, - [weth.address], - [flashloanAmount.toString()], - [0], - userAddress, - params9, - 0 - ) - ).to.be.revertedWith('INCONSISTENT_PARAMS'); - }); - - it('should revert if caller not lending pool', async () => { - const { users, weth, oracle, dai, aWETH, uniswapLiquiditySwapAdapter } = testEnv; - const user = users[0].signer; - const userAddress = users[0].address; - - const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); - - const daiPrice = await oracle.getAssetPrice(dai.address); - const expectedDaiAmount = await convertToCurrencyDecimals( - dai.address, - new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) - ); - - await mockUniswapRouter.setAmountToReturn(weth.address, expectedDaiAmount); - - // User will swap liquidity 10 aEth to aDai - const liquidityToSwap = parseEther('10'); - await aWETH.connect(user).approve(uniswapLiquiditySwapAdapter.address, liquidityToSwap); - - // Subtract the FL fee from the amount to be swapped 0,09% - const flashloanAmount = new BigNumber(liquidityToSwap.toString()).div(1.0009).toFixed(0); - - const params = buildLiquiditySwapParams( - [dai.address], - [expectedDaiAmount], - [0], - [0], - [0], - [0], - ['0x0000000000000000000000000000000000000000000000000000000000000000'], - ['0x0000000000000000000000000000000000000000000000000000000000000000'], - [false] - ); - - await expect( - uniswapLiquiditySwapAdapter - .connect(user) - .executeOperation( - [weth.address], - [flashloanAmount.toString()], - [0], - userAddress, - params - ) - ).to.be.revertedWith('CALLER_MUST_BE_LENDING_POOL'); - }); - - it('should work correctly with tokens of different decimals', async () => { - const { - users, - usdc, - oracle, - dai, - aDai, - uniswapLiquiditySwapAdapter, - pool, - deployer, - } = testEnv; - const user = users[0].signer; - const userAddress = users[0].address; - - const amountUSDCtoSwap = await convertToCurrencyDecimals(usdc.address, '10'); - const liquidity = await convertToCurrencyDecimals(usdc.address, '20000'); - - // Provide liquidity - await usdc.mint(liquidity); - await usdc.approve(pool.address, liquidity); - await pool.deposit(usdc.address, liquidity, deployer.address, 0); - - // Make a deposit for user - await usdc.connect(user).mint(amountUSDCtoSwap); - await usdc.connect(user).approve(pool.address, amountUSDCtoSwap); - await pool.connect(user).deposit(usdc.address, amountUSDCtoSwap, userAddress, 0); - - const usdcPrice = await oracle.getAssetPrice(usdc.address); - const daiPrice = await oracle.getAssetPrice(dai.address); - - // usdc 6 - const collateralDecimals = (await usdc.decimals()).toString(); - const principalDecimals = (await dai.decimals()).toString(); - - const expectedDaiAmount = await convertToCurrencyDecimals( - dai.address, - new BigNumber(amountUSDCtoSwap.toString()) - .times( - new BigNumber(usdcPrice.toString()).times(new BigNumber(10).pow(principalDecimals)) - ) - .div( - new BigNumber(daiPrice.toString()).times(new BigNumber(10).pow(collateralDecimals)) - ) - .toFixed(0) - ); - - await mockUniswapRouter.connect(user).setAmountToReturn(usdc.address, expectedDaiAmount); - - const aUsdcData = await pool.getReserveData(usdc.address); - const aUsdc = await getContract(eContractid.AToken, aUsdcData.aTokenAddress); - const aUsdcBalance = await aUsdc.balanceOf(userAddress); - await aUsdc.connect(user).approve(uniswapLiquiditySwapAdapter.address, aUsdcBalance); - // Subtract the FL fee from the amount to be swapped 0,09% - const flashloanAmount = new BigNumber(amountUSDCtoSwap.toString()).div(1.0009).toFixed(0); - - const params = buildLiquiditySwapParams( - [dai.address], - [expectedDaiAmount], - [0], - [0], - [0], - [0], - ['0x0000000000000000000000000000000000000000000000000000000000000000'], - ['0x0000000000000000000000000000000000000000000000000000000000000000'], - [false] - ); - - await expect( - pool - .connect(user) - .flashLoan( - uniswapLiquiditySwapAdapter.address, - [usdc.address], - [flashloanAmount.toString()], - [0], - userAddress, - params, - 0 - ) - ) - .to.emit(uniswapLiquiditySwapAdapter, 'Swapped') - .withArgs(usdc.address, dai.address, flashloanAmount.toString(), expectedDaiAmount); - - const adapterUsdcBalance = await usdc.balanceOf(uniswapLiquiditySwapAdapter.address); - const adapterDaiBalance = await dai.balanceOf(uniswapLiquiditySwapAdapter.address); - const adapterDaiAllowance = await dai.allowance( - uniswapLiquiditySwapAdapter.address, - userAddress - ); - const aDaiBalance = await aDai.balanceOf(userAddress); - - expect(adapterUsdcBalance).to.be.eq(Zero); - expect(adapterDaiBalance).to.be.eq(Zero); - expect(adapterDaiAllowance).to.be.eq(Zero); - expect(aDaiBalance).to.be.eq(expectedDaiAmount); - }); - - it('should revert when min amount to receive exceeds the max slippage amount', async () => { - const { users, weth, oracle, dai, aWETH, pool, uniswapLiquiditySwapAdapter } = testEnv; - const user = users[0].signer; - const userAddress = users[0].address; - - const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); - - const daiPrice = await oracle.getAssetPrice(dai.address); - const expectedDaiAmount = await convertToCurrencyDecimals( - dai.address, - new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) - ); - - await mockUniswapRouter.setAmountToReturn(weth.address, expectedDaiAmount); - const smallExpectedDaiAmount = expectedDaiAmount.div(2); - - // User will swap liquidity 10 aEth to aDai - const liquidityToSwap = parseEther('10'); - await aWETH.connect(user).approve(uniswapLiquiditySwapAdapter.address, liquidityToSwap); - - // Subtract the FL fee from the amount to be swapped 0,09% - const flashloanAmount = new BigNumber(liquidityToSwap.toString()).div(1.0009).toFixed(0); - - const params = buildLiquiditySwapParams( - [dai.address], - [smallExpectedDaiAmount], - [0], - [0], - [0], - [0], - ['0x0000000000000000000000000000000000000000000000000000000000000000'], - ['0x0000000000000000000000000000000000000000000000000000000000000000'], - [false] - ); - - await expect( - pool - .connect(user) - .flashLoan( - uniswapLiquiditySwapAdapter.address, - [weth.address], - [flashloanAmount.toString()], - [0], - userAddress, - params, - 0 - ) - ).to.be.revertedWith('minAmountOut exceed max slippage'); - }); - - it('should correctly swap tokens all the balance', async () => { - const { - users, - weth, - oracle, - dai, - aDai, - aWETH, - pool, - uniswapLiquiditySwapAdapter, - } = testEnv; - const user = users[0].signer; - const userAddress = users[0].address; - - const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); - - const daiPrice = await oracle.getAssetPrice(dai.address); - const expectedDaiAmount = await convertToCurrencyDecimals( - dai.address, - new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) - ); - - await mockUniswapRouter.setAmountToReturn(weth.address, expectedDaiAmount); - - // Remove other balance - await aWETH.connect(user).transfer(users[1].address, parseEther('90')); - const userAEthBalanceBefore = await aWETH.balanceOf(userAddress); - - // User will swap liquidity 10 aEth to aDai - const liquidityToSwap = parseEther('10'); - expect(userAEthBalanceBefore).to.be.eq(liquidityToSwap); - await aWETH.connect(user).approve(uniswapLiquiditySwapAdapter.address, liquidityToSwap); - - const params = buildLiquiditySwapParams( - [dai.address], - [expectedDaiAmount], - [1], - [0], - [0], - [0], - ['0x0000000000000000000000000000000000000000000000000000000000000000'], - ['0x0000000000000000000000000000000000000000000000000000000000000000'], - [false] - ); - - // Flashloan + premium > aToken balance. Then it will only swap the balance - premium - const flashloanFee = liquidityToSwap.mul(9).div(10000); - const swappedAmount = liquidityToSwap.sub(flashloanFee); - - await expect( - pool - .connect(user) - .flashLoan( - uniswapLiquiditySwapAdapter.address, - [weth.address], - [liquidityToSwap.toString()], - [0], - userAddress, - params, - 0 - ) - ) - .to.emit(uniswapLiquiditySwapAdapter, 'Swapped') - .withArgs(weth.address, dai.address, swappedAmount.toString(), expectedDaiAmount); - - const adapterWethBalance = await weth.balanceOf(uniswapLiquiditySwapAdapter.address); - const adapterDaiBalance = await dai.balanceOf(uniswapLiquiditySwapAdapter.address); - const adapterDaiAllowance = await dai.allowance( - uniswapLiquiditySwapAdapter.address, - userAddress - ); - const userADaiBalance = await aDai.balanceOf(userAddress); - const userAEthBalance = await aWETH.balanceOf(userAddress); - const adapterAEthBalance = await aWETH.balanceOf(uniswapLiquiditySwapAdapter.address); - - expect(adapterWethBalance).to.be.eq(Zero); - expect(adapterDaiBalance).to.be.eq(Zero); - expect(adapterDaiAllowance).to.be.eq(Zero); - expect(userADaiBalance).to.be.eq(expectedDaiAmount); - expect(userAEthBalance).to.be.eq(Zero); - expect(adapterAEthBalance).to.be.eq(Zero); - }); - - it('should correctly swap tokens all the balance using permit', async () => { - const { - users, - weth, - oracle, - dai, - aDai, - aWETH, - pool, - uniswapLiquiditySwapAdapter, - } = testEnv; - const user = users[0].signer; - const userAddress = users[0].address; - - const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); - - const daiPrice = await oracle.getAssetPrice(dai.address); - const expectedDaiAmount = await convertToCurrencyDecimals( - dai.address, - new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) - ); - - await mockUniswapRouter.setAmountToReturn(weth.address, expectedDaiAmount); - - // Remove other balance - await aWETH.connect(user).transfer(users[1].address, parseEther('90')); - const userAEthBalanceBefore = await aWETH.balanceOf(userAddress); - - const liquidityToSwap = parseEther('10'); - expect(userAEthBalanceBefore).to.be.eq(liquidityToSwap); - - const chainId = DRE.network.config.chainId || BUIDLEREVM_CHAINID; - const deadline = MAX_UINT_AMOUNT; - const nonce = (await aWETH._nonces(userAddress)).toNumber(); - const msgParams = buildPermitParams( - chainId, - aWETH.address, - '1', - await aWETH.name(), - userAddress, - uniswapLiquiditySwapAdapter.address, - nonce, - deadline, - liquidityToSwap.toString() - ); - - const ownerPrivateKey = require('../test-wallets.js').accounts[1].secretKey; - if (!ownerPrivateKey) { - throw new Error('INVALID_OWNER_PK'); - } - - const { v, r, s } = getSignatureFromTypedData(ownerPrivateKey, msgParams); - - const params = buildLiquiditySwapParams( - [dai.address], - [expectedDaiAmount], - [1], - [liquidityToSwap], - [deadline], - [v], - [r], - [s], - [false] - ); - - // Flashloan + premium > aToken balance. Then it will only swap the balance - premium - const flashloanFee = liquidityToSwap.mul(9).div(10000); - const swappedAmount = liquidityToSwap.sub(flashloanFee); - - await expect( - pool - .connect(user) - .flashLoan( - uniswapLiquiditySwapAdapter.address, - [weth.address], - [liquidityToSwap.toString()], - [0], - userAddress, - params, - 0 - ) - ) - .to.emit(uniswapLiquiditySwapAdapter, 'Swapped') - .withArgs(weth.address, dai.address, swappedAmount.toString(), expectedDaiAmount); - - const adapterWethBalance = await weth.balanceOf(uniswapLiquiditySwapAdapter.address); - const adapterDaiBalance = await dai.balanceOf(uniswapLiquiditySwapAdapter.address); - const adapterDaiAllowance = await dai.allowance( - uniswapLiquiditySwapAdapter.address, - userAddress - ); - const userADaiBalance = await aDai.balanceOf(userAddress); - const userAEthBalance = await aWETH.balanceOf(userAddress); - const adapterAEthBalance = await aWETH.balanceOf(uniswapLiquiditySwapAdapter.address); - - expect(adapterWethBalance).to.be.eq(Zero); - expect(adapterDaiBalance).to.be.eq(Zero); - expect(adapterDaiAllowance).to.be.eq(Zero); - expect(userADaiBalance).to.be.eq(expectedDaiAmount); - expect(userAEthBalance).to.be.eq(Zero); - expect(adapterAEthBalance).to.be.eq(Zero); - }); - }); - - describe('swapAndDeposit', () => { - beforeEach(async () => { - const { users, weth, dai, pool, deployer } = testEnv; - const userAddress = users[0].address; - - // Provide liquidity - await dai.mint(parseEther('20000')); - await dai.approve(pool.address, parseEther('20000')); - await pool.deposit(dai.address, parseEther('20000'), deployer.address, 0); - - // Make a deposit for user - await weth.mint(parseEther('100')); - await weth.approve(pool.address, parseEther('100')); - await pool.deposit(weth.address, parseEther('100'), userAddress, 0); - }); - - it('should correctly swap tokens and deposit the out tokens in the pool', async () => { - const { users, weth, oracle, dai, aDai, aWETH, uniswapLiquiditySwapAdapter } = testEnv; - const user = users[0].signer; - const userAddress = users[0].address; - - const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); - - const daiPrice = await oracle.getAssetPrice(dai.address); - const expectedDaiAmount = await convertToCurrencyDecimals( - dai.address, - new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) - ); - - await mockUniswapRouter.setAmountToReturn(weth.address, expectedDaiAmount); - - // User will swap liquidity 10 aEth to aDai - const liquidityToSwap = parseEther('10'); - await aWETH.connect(user).approve(uniswapLiquiditySwapAdapter.address, liquidityToSwap); - const userAEthBalanceBefore = await aWETH.balanceOf(userAddress); - - await expect( - uniswapLiquiditySwapAdapter.connect(user).swapAndDeposit( - [weth.address], - [dai.address], - [amountWETHtoSwap], - [expectedDaiAmount], - [ - { - amount: 0, - deadline: 0, - v: 0, - r: '0x0000000000000000000000000000000000000000000000000000000000000000', - s: '0x0000000000000000000000000000000000000000000000000000000000000000', - }, - ], - [false] - ) - ) - .to.emit(uniswapLiquiditySwapAdapter, 'Swapped') - .withArgs(weth.address, dai.address, amountWETHtoSwap.toString(), expectedDaiAmount); - - const adapterWethBalance = await weth.balanceOf(uniswapLiquiditySwapAdapter.address); - const adapterDaiBalance = await dai.balanceOf(uniswapLiquiditySwapAdapter.address); - const adapterDaiAllowance = await dai.allowance( - uniswapLiquiditySwapAdapter.address, - userAddress - ); - const userADaiBalance = await aDai.balanceOf(userAddress); - const userAEthBalance = await aWETH.balanceOf(userAddress); - - expect(adapterWethBalance).to.be.eq(Zero); - expect(adapterDaiBalance).to.be.eq(Zero); - expect(adapterDaiAllowance).to.be.eq(Zero); - expect(userADaiBalance).to.be.eq(expectedDaiAmount); - expect(userAEthBalance).to.be.lt(userAEthBalanceBefore); - expect(userAEthBalance).to.be.gte(userAEthBalanceBefore.sub(liquidityToSwap)); - }); - - it('should correctly swap tokens using permit', async () => { - const { users, weth, oracle, dai, aDai, aWETH, uniswapLiquiditySwapAdapter } = testEnv; - const user = users[0].signer; - const userAddress = users[0].address; - - const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); - - const daiPrice = await oracle.getAssetPrice(dai.address); - const expectedDaiAmount = await convertToCurrencyDecimals( - dai.address, - new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) - ); - - await mockUniswapRouter.setAmountToReturn(weth.address, expectedDaiAmount); - - // User will swap liquidity 10 aEth to aDai - const liquidityToSwap = parseEther('10'); - const userAEthBalanceBefore = await aWETH.balanceOf(userAddress); - - const chainId = DRE.network.config.chainId || BUIDLEREVM_CHAINID; - const deadline = MAX_UINT_AMOUNT; - const nonce = (await aWETH._nonces(userAddress)).toNumber(); - const msgParams = buildPermitParams( - chainId, - aWETH.address, - '1', - await aWETH.name(), - userAddress, - uniswapLiquiditySwapAdapter.address, - nonce, - deadline, - liquidityToSwap.toString() - ); - - const ownerPrivateKey = require('../test-wallets.js').accounts[1].secretKey; - if (!ownerPrivateKey) { - throw new Error('INVALID_OWNER_PK'); - } - - const { v, r, s } = getSignatureFromTypedData(ownerPrivateKey, msgParams); - - await expect( - uniswapLiquiditySwapAdapter.connect(user).swapAndDeposit( - [weth.address], - [dai.address], - [amountWETHtoSwap], - [expectedDaiAmount], - [ - { - amount: liquidityToSwap, - deadline, - v, - r, - s, - }, - ], - [false] - ) - ) - .to.emit(uniswapLiquiditySwapAdapter, 'Swapped') - .withArgs(weth.address, dai.address, amountWETHtoSwap.toString(), expectedDaiAmount); - - const adapterWethBalance = await weth.balanceOf(uniswapLiquiditySwapAdapter.address); - const adapterDaiBalance = await dai.balanceOf(uniswapLiquiditySwapAdapter.address); - const adapterDaiAllowance = await dai.allowance( - uniswapLiquiditySwapAdapter.address, - userAddress - ); - const userADaiBalance = await aDai.balanceOf(userAddress); - const userAEthBalance = await aWETH.balanceOf(userAddress); - - expect(adapterWethBalance).to.be.eq(Zero); - expect(adapterDaiBalance).to.be.eq(Zero); - expect(adapterDaiAllowance).to.be.eq(Zero); - expect(userADaiBalance).to.be.eq(expectedDaiAmount); - expect(userAEthBalance).to.be.lt(userAEthBalanceBefore); - expect(userAEthBalance).to.be.gte(userAEthBalanceBefore.sub(liquidityToSwap)); - }); - - it('should revert if inconsistent params', async () => { - const { users, weth, dai, uniswapLiquiditySwapAdapter, oracle } = testEnv; - const user = users[0].signer; - - const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); - const daiPrice = await oracle.getAssetPrice(dai.address); - const expectedDaiAmount = await convertToCurrencyDecimals( - dai.address, - new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) - ); - - await expect( - uniswapLiquiditySwapAdapter.connect(user).swapAndDeposit( - [weth.address, dai.address], - [dai.address], - [amountWETHtoSwap], - [expectedDaiAmount], - [ - { - amount: 0, - deadline: 0, - v: 0, - r: '0x0000000000000000000000000000000000000000000000000000000000000000', - s: '0x0000000000000000000000000000000000000000000000000000000000000000', - }, - ], - [false] - ) - ).to.be.revertedWith('INCONSISTENT_PARAMS'); - - await expect( - uniswapLiquiditySwapAdapter.connect(user).swapAndDeposit( - [weth.address], - [dai.address, weth.address], - [amountWETHtoSwap], - [expectedDaiAmount], - [ - { - amount: 0, - deadline: 0, - v: 0, - r: '0x0000000000000000000000000000000000000000000000000000000000000000', - s: '0x0000000000000000000000000000000000000000000000000000000000000000', - }, - ], - [false] - ) - ).to.be.revertedWith('INCONSISTENT_PARAMS'); - - await expect( - uniswapLiquiditySwapAdapter.connect(user).swapAndDeposit( - [weth.address], - [dai.address], - [amountWETHtoSwap, amountWETHtoSwap], - [expectedDaiAmount], - [ - { - amount: 0, - deadline: 0, - v: 0, - r: '0x0000000000000000000000000000000000000000000000000000000000000000', - s: '0x0000000000000000000000000000000000000000000000000000000000000000', - }, - ], - [false] - ) - ).to.be.revertedWith('INCONSISTENT_PARAMS'); - - await expect( - uniswapLiquiditySwapAdapter - .connect(user) - .swapAndDeposit( - [weth.address], - [dai.address], - [amountWETHtoSwap], - [expectedDaiAmount], - [], - [false] - ) - ).to.be.revertedWith('INCONSISTENT_PARAMS'); - - await expect( - uniswapLiquiditySwapAdapter.connect(user).swapAndDeposit( - [weth.address], - [dai.address], - [amountWETHtoSwap], - [expectedDaiAmount, expectedDaiAmount], - [ - { - amount: 0, - deadline: 0, - v: 0, - r: '0x0000000000000000000000000000000000000000000000000000000000000000', - s: '0x0000000000000000000000000000000000000000000000000000000000000000', - }, - ], - [false] - ) - ).to.be.revertedWith('INCONSISTENT_PARAMS'); - }); - - it('should revert when min amount to receive exceeds the max slippage amount', async () => { - const { users, weth, oracle, dai, aWETH, uniswapLiquiditySwapAdapter } = testEnv; - const user = users[0].signer; - - const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); - - const daiPrice = await oracle.getAssetPrice(dai.address); - const expectedDaiAmount = await convertToCurrencyDecimals( - dai.address, - new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) - ); - - await mockUniswapRouter.setAmountToReturn(weth.address, expectedDaiAmount); - const smallExpectedDaiAmount = expectedDaiAmount.div(2); - - // User will swap liquidity 10 aEth to aDai - const liquidityToSwap = parseEther('10'); - await aWETH.connect(user).approve(uniswapLiquiditySwapAdapter.address, liquidityToSwap); - - await expect( - uniswapLiquiditySwapAdapter.connect(user).swapAndDeposit( - [weth.address], - [dai.address], - [amountWETHtoSwap], - [smallExpectedDaiAmount], - [ - { - amount: 0, - deadline: 0, - v: 0, - r: '0x0000000000000000000000000000000000000000000000000000000000000000', - s: '0x0000000000000000000000000000000000000000000000000000000000000000', - }, - ], - [false] - ) - ).to.be.revertedWith('minAmountOut exceed max slippage'); - }); - - it('should correctly swap tokens and deposit multiple tokens', async () => { - const { - users, - weth, - usdc, - oracle, - dai, - aDai, - aWETH, - uniswapLiquiditySwapAdapter, - pool, - } = testEnv; - const user = users[0].signer; - const userAddress = users[0].address; - - const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); - - const daiPrice = await oracle.getAssetPrice(dai.address); - const expectedDaiAmountForEth = await convertToCurrencyDecimals( - dai.address, - new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) - ); - - const amountUSDCtoSwap = await convertToCurrencyDecimals(usdc.address, '10'); - const usdcPrice = await oracle.getAssetPrice(usdc.address); - - const collateralDecimals = (await usdc.decimals()).toString(); - const principalDecimals = (await dai.decimals()).toString(); - - const expectedDaiAmountForUsdc = await convertToCurrencyDecimals( - dai.address, - new BigNumber(amountUSDCtoSwap.toString()) - .times( - new BigNumber(usdcPrice.toString()).times(new BigNumber(10).pow(principalDecimals)) - ) - .div( - new BigNumber(daiPrice.toString()).times(new BigNumber(10).pow(collateralDecimals)) - ) - .toFixed(0) - ); - - // Make a deposit for user - await usdc.connect(user).mint(amountUSDCtoSwap); - await usdc.connect(user).approve(pool.address, amountUSDCtoSwap); - await pool.connect(user).deposit(usdc.address, amountUSDCtoSwap, userAddress, 0); - - const aUsdcData = await pool.getReserveData(usdc.address); - const aUsdc = await getContract(eContractid.AToken, aUsdcData.aTokenAddress); - - await mockUniswapRouter.setAmountToReturn(weth.address, expectedDaiAmountForEth); - await mockUniswapRouter.setAmountToReturn(usdc.address, expectedDaiAmountForUsdc); - - await aWETH.connect(user).approve(uniswapLiquiditySwapAdapter.address, amountWETHtoSwap); - const userAEthBalanceBefore = await aWETH.balanceOf(userAddress); - await aUsdc.connect(user).approve(uniswapLiquiditySwapAdapter.address, amountUSDCtoSwap); - const userAUsdcBalanceBefore = await aUsdc.balanceOf(userAddress); - - await uniswapLiquiditySwapAdapter.connect(user).swapAndDeposit( - [weth.address, usdc.address], - [dai.address, dai.address], - [amountWETHtoSwap, amountUSDCtoSwap], - [expectedDaiAmountForEth, expectedDaiAmountForUsdc], - [ - { - amount: 0, - deadline: 0, - v: 0, - r: '0x0000000000000000000000000000000000000000000000000000000000000000', - s: '0x0000000000000000000000000000000000000000000000000000000000000000', - }, - { - amount: 0, - deadline: 0, - v: 0, - r: '0x0000000000000000000000000000000000000000000000000000000000000000', - s: '0x0000000000000000000000000000000000000000000000000000000000000000', - }, - ], - [false, false] - ); - - const adapterWethBalance = await weth.balanceOf(uniswapLiquiditySwapAdapter.address); - const adapterDaiBalance = await dai.balanceOf(uniswapLiquiditySwapAdapter.address); - const adapterDaiAllowance = await dai.allowance( - uniswapLiquiditySwapAdapter.address, - userAddress - ); - const userADaiBalance = await aDai.balanceOf(userAddress); - const userAEthBalance = await aWETH.balanceOf(userAddress); - const userAUsdcBalance = await aUsdc.balanceOf(userAddress); - - expect(adapterWethBalance).to.be.eq(Zero); - expect(adapterDaiBalance).to.be.eq(Zero); - expect(adapterDaiAllowance).to.be.eq(Zero); - expect(userADaiBalance).to.be.eq(expectedDaiAmountForEth.add(expectedDaiAmountForUsdc)); - expect(userAEthBalance).to.be.lt(userAEthBalanceBefore); - expect(userAEthBalance).to.be.gte(userAEthBalanceBefore.sub(amountWETHtoSwap)); - expect(userAUsdcBalance).to.be.lt(userAUsdcBalanceBefore); - expect(userAUsdcBalance).to.be.gte(userAUsdcBalanceBefore.sub(amountUSDCtoSwap)); - }); - - it('should correctly swap tokens and deposit multiple tokens using permit', async () => { - const { - users, - weth, - usdc, - oracle, - dai, - aDai, - aWETH, - uniswapLiquiditySwapAdapter, - pool, - } = testEnv; - const user = users[0].signer; - const userAddress = users[0].address; - const chainId = DRE.network.config.chainId || BUIDLEREVM_CHAINID; - const deadline = MAX_UINT_AMOUNT; - - const ownerPrivateKey = require('../test-wallets.js').accounts[1].secretKey; - if (!ownerPrivateKey) { - throw new Error('INVALID_OWNER_PK'); - } - - const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); - - const daiPrice = await oracle.getAssetPrice(dai.address); - const expectedDaiAmountForEth = await convertToCurrencyDecimals( - dai.address, - new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) - ); - - const amountUSDCtoSwap = await convertToCurrencyDecimals(usdc.address, '10'); - const usdcPrice = await oracle.getAssetPrice(usdc.address); - - const collateralDecimals = (await usdc.decimals()).toString(); - const principalDecimals = (await dai.decimals()).toString(); - - const expectedDaiAmountForUsdc = await convertToCurrencyDecimals( - dai.address, - new BigNumber(amountUSDCtoSwap.toString()) - .times( - new BigNumber(usdcPrice.toString()).times(new BigNumber(10).pow(principalDecimals)) - ) - .div( - new BigNumber(daiPrice.toString()).times(new BigNumber(10).pow(collateralDecimals)) - ) - .toFixed(0) - ); - - // Make a deposit for user - await usdc.connect(user).mint(amountUSDCtoSwap); - await usdc.connect(user).approve(pool.address, amountUSDCtoSwap); - await pool.connect(user).deposit(usdc.address, amountUSDCtoSwap, userAddress, 0); - - const aUsdcData = await pool.getReserveData(usdc.address); - const aUsdc = await getContract(eContractid.AToken, aUsdcData.aTokenAddress); - - await mockUniswapRouter.setAmountToReturn(weth.address, expectedDaiAmountForEth); - await mockUniswapRouter.setAmountToReturn(usdc.address, expectedDaiAmountForUsdc); - - const userAEthBalanceBefore = await aWETH.balanceOf(userAddress); - const userAUsdcBalanceBefore = await aUsdc.balanceOf(userAddress); - - const aWethNonce = (await aWETH._nonces(userAddress)).toNumber(); - const aWethMsgParams = buildPermitParams( - chainId, - aWETH.address, - '1', - await aWETH.name(), - userAddress, - uniswapLiquiditySwapAdapter.address, - aWethNonce, - deadline, - amountWETHtoSwap.toString() - ); - const { v: aWETHv, r: aWETHr, s: aWETHs } = getSignatureFromTypedData( - ownerPrivateKey, - aWethMsgParams - ); - - const aUsdcNonce = (await aUsdc._nonces(userAddress)).toNumber(); - const aUsdcMsgParams = buildPermitParams( - chainId, - aUsdc.address, - '1', - await aUsdc.name(), - userAddress, - uniswapLiquiditySwapAdapter.address, - aUsdcNonce, - deadline, - amountUSDCtoSwap.toString() - ); - const { v: aUsdcv, r: aUsdcr, s: aUsdcs } = getSignatureFromTypedData( - ownerPrivateKey, - aUsdcMsgParams - ); - - await uniswapLiquiditySwapAdapter.connect(user).swapAndDeposit( - [weth.address, usdc.address], - [dai.address, dai.address], - [amountWETHtoSwap, amountUSDCtoSwap], - [expectedDaiAmountForEth, expectedDaiAmountForUsdc], - [ - { - amount: amountWETHtoSwap, - deadline, - v: aWETHv, - r: aWETHr, - s: aWETHs, - }, - { - amount: amountUSDCtoSwap, - deadline, - v: aUsdcv, - r: aUsdcr, - s: aUsdcs, - }, - ], - [false, false] - ); - - const adapterWethBalance = await weth.balanceOf(uniswapLiquiditySwapAdapter.address); - const adapterDaiBalance = await dai.balanceOf(uniswapLiquiditySwapAdapter.address); - const adapterDaiAllowance = await dai.allowance( - uniswapLiquiditySwapAdapter.address, - userAddress - ); - const userADaiBalance = await aDai.balanceOf(userAddress); - const userAEthBalance = await aWETH.balanceOf(userAddress); - const userAUsdcBalance = await aUsdc.balanceOf(userAddress); - - expect(adapterWethBalance).to.be.eq(Zero); - expect(adapterDaiBalance).to.be.eq(Zero); - expect(adapterDaiAllowance).to.be.eq(Zero); - expect(userADaiBalance).to.be.eq(expectedDaiAmountForEth.add(expectedDaiAmountForUsdc)); - expect(userAEthBalance).to.be.lt(userAEthBalanceBefore); - expect(userAEthBalance).to.be.gte(userAEthBalanceBefore.sub(amountWETHtoSwap)); - expect(userAUsdcBalance).to.be.lt(userAUsdcBalanceBefore); - expect(userAUsdcBalance).to.be.gte(userAUsdcBalanceBefore.sub(amountUSDCtoSwap)); - }); - - it('should correctly swap all the balance when using a bigger amount', async () => { - const { users, weth, oracle, dai, aDai, aWETH, uniswapLiquiditySwapAdapter } = testEnv; - const user = users[0].signer; - const userAddress = users[0].address; - - const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); - - const daiPrice = await oracle.getAssetPrice(dai.address); - const expectedDaiAmount = await convertToCurrencyDecimals( - dai.address, - new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) - ); - - await mockUniswapRouter.setAmountToReturn(weth.address, expectedDaiAmount); - - // Remove other balance - await aWETH.connect(user).transfer(users[1].address, parseEther('90')); - const userAEthBalanceBefore = await aWETH.balanceOf(userAddress); - - // User will swap liquidity 10 aEth to aDai - const liquidityToSwap = parseEther('10'); - expect(userAEthBalanceBefore).to.be.eq(liquidityToSwap); - - // User will swap liquidity 10 aEth to aDai - await aWETH.connect(user).approve(uniswapLiquiditySwapAdapter.address, liquidityToSwap); - - // Only has 10 atokens, so all the balance will be swapped - const bigAmountToSwap = parseEther('100'); - - await expect( - uniswapLiquiditySwapAdapter.connect(user).swapAndDeposit( - [weth.address], - [dai.address], - [bigAmountToSwap], - [expectedDaiAmount], - [ - { - amount: 0, - deadline: 0, - v: 0, - r: '0x0000000000000000000000000000000000000000000000000000000000000000', - s: '0x0000000000000000000000000000000000000000000000000000000000000000', - }, - ], - [false] - ) - ) - .to.emit(uniswapLiquiditySwapAdapter, 'Swapped') - .withArgs(weth.address, dai.address, amountWETHtoSwap.toString(), expectedDaiAmount); - - const adapterWethBalance = await weth.balanceOf(uniswapLiquiditySwapAdapter.address); - const adapterDaiBalance = await dai.balanceOf(uniswapLiquiditySwapAdapter.address); - const adapterDaiAllowance = await dai.allowance( - uniswapLiquiditySwapAdapter.address, - userAddress - ); - const userADaiBalance = await aDai.balanceOf(userAddress); - const userAEthBalance = await aWETH.balanceOf(userAddress); - const adapterAEthBalance = await aWETH.balanceOf(uniswapLiquiditySwapAdapter.address); - - expect(adapterWethBalance).to.be.eq(Zero); - expect(adapterDaiBalance).to.be.eq(Zero); - expect(adapterDaiAllowance).to.be.eq(Zero); - expect(userADaiBalance).to.be.eq(expectedDaiAmount); - expect(userAEthBalance).to.be.eq(Zero); - expect(adapterAEthBalance).to.be.eq(Zero); - }); - - it('should correctly swap all the balance when using permit', async () => { - const { users, weth, oracle, dai, aDai, aWETH, uniswapLiquiditySwapAdapter } = testEnv; - const user = users[0].signer; - const userAddress = users[0].address; - - const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); - - const daiPrice = await oracle.getAssetPrice(dai.address); - const expectedDaiAmount = await convertToCurrencyDecimals( - dai.address, - new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) - ); - - await mockUniswapRouter.setAmountToReturn(weth.address, expectedDaiAmount); - - // Remove other balance - await aWETH.connect(user).transfer(users[1].address, parseEther('90')); - const userAEthBalanceBefore = await aWETH.balanceOf(userAddress); - - // User will swap liquidity 10 aEth to aDai - const liquidityToSwap = parseEther('10'); - expect(userAEthBalanceBefore).to.be.eq(liquidityToSwap); - - // Only has 10 atokens, so all the balance will be swapped - const bigAmountToSwap = parseEther('100'); - - const chainId = DRE.network.config.chainId || BUIDLEREVM_CHAINID; - const deadline = MAX_UINT_AMOUNT; - - const ownerPrivateKey = require('../test-wallets.js').accounts[1].secretKey; - if (!ownerPrivateKey) { - throw new Error('INVALID_OWNER_PK'); - } - const aWethNonce = (await aWETH._nonces(userAddress)).toNumber(); - const aWethMsgParams = buildPermitParams( - chainId, - aWETH.address, - '1', - await aWETH.name(), - userAddress, - uniswapLiquiditySwapAdapter.address, - aWethNonce, - deadline, - bigAmountToSwap.toString() - ); - const { v, r, s } = getSignatureFromTypedData(ownerPrivateKey, aWethMsgParams); - - await expect( - uniswapLiquiditySwapAdapter.connect(user).swapAndDeposit( - [weth.address], - [dai.address], - [bigAmountToSwap], - [expectedDaiAmount], - [ - { - amount: bigAmountToSwap, - deadline, - v, - r, - s, - }, - ], - [false] - ) - ) - .to.emit(uniswapLiquiditySwapAdapter, 'Swapped') - .withArgs(weth.address, dai.address, amountWETHtoSwap.toString(), expectedDaiAmount); - - const adapterWethBalance = await weth.balanceOf(uniswapLiquiditySwapAdapter.address); - const adapterDaiBalance = await dai.balanceOf(uniswapLiquiditySwapAdapter.address); - const adapterDaiAllowance = await dai.allowance( - uniswapLiquiditySwapAdapter.address, - userAddress - ); - const userADaiBalance = await aDai.balanceOf(userAddress); - const userAEthBalance = await aWETH.balanceOf(userAddress); - const adapterAEthBalance = await aWETH.balanceOf(uniswapLiquiditySwapAdapter.address); - - expect(adapterWethBalance).to.be.eq(Zero); - expect(adapterDaiBalance).to.be.eq(Zero); - expect(adapterDaiAllowance).to.be.eq(Zero); - expect(userADaiBalance).to.be.eq(expectedDaiAmount); - expect(userAEthBalance).to.be.eq(Zero); - expect(adapterAEthBalance).to.be.eq(Zero); - }); - }); - }); -}); diff --git a/test/uniswapAdapters.repay.spec.ts b/test/uniswapAdapters.repay.spec.ts deleted file mode 100644 index c271917e..00000000 --- a/test/uniswapAdapters.repay.spec.ts +++ /dev/null @@ -1,1469 +0,0 @@ -import { makeSuite, TestEnv } from './helpers/make-suite'; -import { - convertToCurrencyDecimals, - getContract, - buildPermitParams, - getSignatureFromTypedData, - buildRepayAdapterParams, -} from '../helpers/contracts-helpers'; -import { getMockUniswapRouter } from '../helpers/contracts-getters'; -import { deployUniswapRepayAdapter } from '../helpers/contracts-deployments'; -import { MockUniswapV2Router02 } from '../types/MockUniswapV2Router02'; -import { Zero } from '@ethersproject/constants'; -import BigNumber from 'bignumber.js'; -import { DRE, evmRevert, evmSnapshot } from '../helpers/misc-utils'; -import { ethers } from 'ethers'; -import { eContractid } from '../helpers/types'; -import { StableDebtToken } from '../types/StableDebtToken'; -import { BUIDLEREVM_CHAINID } from '../helpers/buidler-constants'; -import { MAX_UINT_AMOUNT } from '../helpers/constants'; -import { VariableDebtToken } from '../types'; -const { parseEther } = ethers.utils; - -const { expect } = require('chai'); - -makeSuite('Uniswap adapters', (testEnv: TestEnv) => { - let mockUniswapRouter: MockUniswapV2Router02; - let evmSnapshotId: string; - - before(async () => { - mockUniswapRouter = await getMockUniswapRouter(); - }); - - beforeEach(async () => { - evmSnapshotId = await evmSnapshot(); - }); - - afterEach(async () => { - await evmRevert(evmSnapshotId); - }); - - describe('UniswapRepayAdapter', () => { - beforeEach(async () => { - const { users, weth, dai, usdc, aave, pool, deployer } = testEnv; - const userAddress = users[0].address; - - // Provide liquidity - await dai.mint(parseEther('20000')); - await dai.approve(pool.address, parseEther('20000')); - await pool.deposit(dai.address, parseEther('20000'), deployer.address, 0); - - const usdcLiquidity = await convertToCurrencyDecimals(usdc.address, '2000000'); - await usdc.mint(usdcLiquidity); - await usdc.approve(pool.address, usdcLiquidity); - await pool.deposit(usdc.address, usdcLiquidity, deployer.address, 0); - - await weth.mint(parseEther('100')); - await weth.approve(pool.address, parseEther('100')); - await pool.deposit(weth.address, parseEther('100'), deployer.address, 0); - - await aave.mint(parseEther('1000000')); - await aave.approve(pool.address, parseEther('1000000')); - await pool.deposit(aave.address, parseEther('1000000'), deployer.address, 0); - - // Make a deposit for user - await weth.mint(parseEther('1000')); - await weth.approve(pool.address, parseEther('1000')); - await pool.deposit(weth.address, parseEther('1000'), userAddress, 0); - - await aave.mint(parseEther('1000000')); - await aave.approve(pool.address, parseEther('1000000')); - await pool.deposit(aave.address, parseEther('1000000'), userAddress, 0); - - await usdc.mint(usdcLiquidity); - await usdc.approve(pool.address, usdcLiquidity); - await pool.deposit(usdc.address, usdcLiquidity, userAddress, 0); - }); - - describe('constructor', () => { - it('should deploy with correct parameters', async () => { - const { addressesProvider, weth } = testEnv; - await deployUniswapRepayAdapter([ - addressesProvider.address, - mockUniswapRouter.address, - weth.address, - ]); - }); - - it('should revert if not valid addresses provider', async () => { - const { weth } = testEnv; - expect( - deployUniswapRepayAdapter([ - mockUniswapRouter.address, - mockUniswapRouter.address, - weth.address, - ]) - ).to.be.reverted; - }); - }); - - describe('executeOperation', () => { - it('should correctly swap tokens and repay debt', async () => { - const { - users, - pool, - weth, - aWETH, - oracle, - dai, - uniswapRepayAdapter, - helpersContract, - } = testEnv; - const user = users[0].signer; - const userAddress = users[0].address; - - const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); - - const daiPrice = await oracle.getAssetPrice(dai.address); - const expectedDaiAmount = await convertToCurrencyDecimals( - dai.address, - new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) - ); - - // Open user Debt - await pool.connect(user).borrow(dai.address, expectedDaiAmount, 1, 0, userAddress); - - const daiStableDebtTokenAddress = ( - await helpersContract.getReserveTokensAddresses(dai.address) - ).stableDebtTokenAddress; - - const daiStableDebtContract = await getContract( - eContractid.StableDebtToken, - daiStableDebtTokenAddress - ); - - const userDaiStableDebtAmountBefore = await daiStableDebtContract.balanceOf(userAddress); - - const liquidityToSwap = amountWETHtoSwap; - await aWETH.connect(user).approve(uniswapRepayAdapter.address, liquidityToSwap); - const userAEthBalanceBefore = await aWETH.balanceOf(userAddress); - - await mockUniswapRouter.connect(user).setAmountToSwap(weth.address, liquidityToSwap); - - const flashLoanDebt = new BigNumber(expectedDaiAmount.toString()) - .multipliedBy(1.0009) - .toFixed(0); - - await mockUniswapRouter.setAmountIn( - flashLoanDebt, - weth.address, - dai.address, - liquidityToSwap - ); - - const params = buildRepayAdapterParams( - weth.address, - liquidityToSwap, - 1, - 0, - 0, - 0, - '0x0000000000000000000000000000000000000000000000000000000000000000', - '0x0000000000000000000000000000000000000000000000000000000000000000', - false - ); - - await expect( - pool - .connect(user) - .flashLoan( - uniswapRepayAdapter.address, - [dai.address], - [expectedDaiAmount.toString()], - [0], - userAddress, - params, - 0 - ) - ) - .to.emit(uniswapRepayAdapter, 'Swapped') - .withArgs(weth.address, dai.address, liquidityToSwap.toString(), flashLoanDebt); - - const adapterWethBalance = await weth.balanceOf(uniswapRepayAdapter.address); - const adapterDaiBalance = await dai.balanceOf(uniswapRepayAdapter.address); - const userDaiStableDebtAmount = await daiStableDebtContract.balanceOf(userAddress); - const userAEthBalance = await aWETH.balanceOf(userAddress); - - expect(adapterWethBalance).to.be.eq(Zero); - expect(adapterDaiBalance).to.be.eq(Zero); - expect(userDaiStableDebtAmountBefore).to.be.gte(expectedDaiAmount); - expect(userDaiStableDebtAmount).to.be.lt(expectedDaiAmount); - expect(userAEthBalance).to.be.lt(userAEthBalanceBefore); - expect(userAEthBalance).to.be.gte(userAEthBalanceBefore.sub(liquidityToSwap)); - }); - - it('should correctly swap tokens and repay debt with permit', async () => { - const { - users, - pool, - weth, - aWETH, - oracle, - dai, - uniswapRepayAdapter, - helpersContract, - } = testEnv; - const user = users[0].signer; - const userAddress = users[0].address; - - const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); - - const daiPrice = await oracle.getAssetPrice(dai.address); - const expectedDaiAmount = await convertToCurrencyDecimals( - dai.address, - new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) - ); - - // Open user Debt - await pool.connect(user).borrow(dai.address, expectedDaiAmount, 1, 0, userAddress); - - const daiStableDebtTokenAddress = ( - await helpersContract.getReserveTokensAddresses(dai.address) - ).stableDebtTokenAddress; - - const daiStableDebtContract = await getContract( - eContractid.StableDebtToken, - daiStableDebtTokenAddress - ); - - const userDaiStableDebtAmountBefore = await daiStableDebtContract.balanceOf(userAddress); - - const liquidityToSwap = amountWETHtoSwap; - const userAEthBalanceBefore = await aWETH.balanceOf(userAddress); - - const chainId = DRE.network.config.chainId || BUIDLEREVM_CHAINID; - const deadline = MAX_UINT_AMOUNT; - const nonce = (await aWETH._nonces(userAddress)).toNumber(); - const msgParams = buildPermitParams( - chainId, - aWETH.address, - '1', - await aWETH.name(), - userAddress, - uniswapRepayAdapter.address, - nonce, - deadline, - liquidityToSwap.toString() - ); - - const ownerPrivateKey = require('../test-wallets.js').accounts[1].secretKey; - if (!ownerPrivateKey) { - throw new Error('INVALID_OWNER_PK'); - } - - const { v, r, s } = getSignatureFromTypedData(ownerPrivateKey, msgParams); - - await mockUniswapRouter.connect(user).setAmountToSwap(weth.address, liquidityToSwap); - - const flashLoanDebt = new BigNumber(expectedDaiAmount.toString()) - .multipliedBy(1.0009) - .toFixed(0); - - await mockUniswapRouter.setAmountIn( - flashLoanDebt, - weth.address, - dai.address, - liquidityToSwap - ); - - const params = buildRepayAdapterParams( - weth.address, - liquidityToSwap, - 1, - liquidityToSwap, - deadline, - v, - r, - s, - false - ); - - await expect( - pool - .connect(user) - .flashLoan( - uniswapRepayAdapter.address, - [dai.address], - [expectedDaiAmount.toString()], - [0], - userAddress, - params, - 0 - ) - ) - .to.emit(uniswapRepayAdapter, 'Swapped') - .withArgs(weth.address, dai.address, liquidityToSwap.toString(), flashLoanDebt); - - const adapterWethBalance = await weth.balanceOf(uniswapRepayAdapter.address); - const adapterDaiBalance = await dai.balanceOf(uniswapRepayAdapter.address); - const userDaiStableDebtAmount = await daiStableDebtContract.balanceOf(userAddress); - const userAEthBalance = await aWETH.balanceOf(userAddress); - - expect(adapterWethBalance).to.be.eq(Zero); - expect(adapterDaiBalance).to.be.eq(Zero); - expect(userDaiStableDebtAmountBefore).to.be.gte(expectedDaiAmount); - expect(userDaiStableDebtAmount).to.be.lt(expectedDaiAmount); - expect(userAEthBalance).to.be.lt(userAEthBalanceBefore); - expect(userAEthBalance).to.be.gte(userAEthBalanceBefore.sub(liquidityToSwap)); - }); - - it('should revert if caller not lending pool', async () => { - const { users, pool, weth, aWETH, oracle, dai, uniswapRepayAdapter } = testEnv; - const user = users[0].signer; - const userAddress = users[0].address; - - const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); - - const daiPrice = await oracle.getAssetPrice(dai.address); - const expectedDaiAmount = await convertToCurrencyDecimals( - dai.address, - new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) - ); - - // Open user Debt - await pool.connect(user).borrow(dai.address, expectedDaiAmount, 1, 0, userAddress); - - const liquidityToSwap = amountWETHtoSwap; - await aWETH.connect(user).approve(uniswapRepayAdapter.address, liquidityToSwap); - - await mockUniswapRouter.connect(user).setAmountToSwap(weth.address, liquidityToSwap); - - const params = buildRepayAdapterParams( - weth.address, - liquidityToSwap, - 1, - 0, - 0, - 0, - '0x0000000000000000000000000000000000000000000000000000000000000000', - '0x0000000000000000000000000000000000000000000000000000000000000000', - false - ); - - await expect( - uniswapRepayAdapter - .connect(user) - .executeOperation( - [dai.address], - [expectedDaiAmount.toString()], - [0], - userAddress, - params - ) - ).to.be.revertedWith('CALLER_MUST_BE_LENDING_POOL'); - }); - - it('should revert if there is not debt to repay with the specified rate mode', async () => { - const { users, pool, weth, oracle, dai, uniswapRepayAdapter, aWETH } = testEnv; - const user = users[0].signer; - const userAddress = users[0].address; - - const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); - - await weth.connect(user).mint(amountWETHtoSwap); - await weth.connect(user).transfer(uniswapRepayAdapter.address, amountWETHtoSwap); - - const daiPrice = await oracle.getAssetPrice(dai.address); - const expectedDaiAmount = await convertToCurrencyDecimals( - dai.address, - new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) - ); - - // Open user Debt - await pool.connect(user).borrow(dai.address, expectedDaiAmount, 2, 0, userAddress); - - const liquidityToSwap = amountWETHtoSwap; - await aWETH.connect(user).approve(uniswapRepayAdapter.address, liquidityToSwap); - - await mockUniswapRouter.connect(user).setAmountToSwap(weth.address, liquidityToSwap); - - const params = buildRepayAdapterParams( - weth.address, - liquidityToSwap, - 1, - 0, - 0, - 0, - '0x0000000000000000000000000000000000000000000000000000000000000000', - '0x0000000000000000000000000000000000000000000000000000000000000000', - false - ); - - await expect( - pool - .connect(user) - .flashLoan( - uniswapRepayAdapter.address, - [dai.address], - [expectedDaiAmount.toString()], - [0], - userAddress, - params, - 0 - ) - ).to.be.reverted; - }); - - it('should revert if there is not debt to repay', async () => { - const { users, pool, weth, oracle, dai, uniswapRepayAdapter, aWETH } = testEnv; - const user = users[0].signer; - const userAddress = users[0].address; - - const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); - - await weth.connect(user).mint(amountWETHtoSwap); - await weth.connect(user).transfer(uniswapRepayAdapter.address, amountWETHtoSwap); - - const daiPrice = await oracle.getAssetPrice(dai.address); - const expectedDaiAmount = await convertToCurrencyDecimals( - dai.address, - new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) - ); - - const liquidityToSwap = amountWETHtoSwap; - await aWETH.connect(user).approve(uniswapRepayAdapter.address, liquidityToSwap); - - await mockUniswapRouter.connect(user).setAmountToSwap(weth.address, liquidityToSwap); - - const params = buildRepayAdapterParams( - weth.address, - liquidityToSwap, - 1, - 0, - 0, - 0, - '0x0000000000000000000000000000000000000000000000000000000000000000', - '0x0000000000000000000000000000000000000000000000000000000000000000', - false - ); - - await expect( - pool - .connect(user) - .flashLoan( - uniswapRepayAdapter.address, - [dai.address], - [expectedDaiAmount.toString()], - [0], - userAddress, - params, - 0 - ) - ).to.be.reverted; - }); - - it('should revert when max amount allowed to swap is bigger than max slippage', async () => { - const { users, pool, weth, oracle, dai, aWETH, uniswapRepayAdapter } = testEnv; - const user = users[0].signer; - const userAddress = users[0].address; - - const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); - - const daiPrice = await oracle.getAssetPrice(dai.address); - const expectedDaiAmount = await convertToCurrencyDecimals( - dai.address, - new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) - ); - - // Open user Debt - await pool.connect(user).borrow(dai.address, expectedDaiAmount, 1, 0, userAddress); - - const bigMaxAmountToSwap = amountWETHtoSwap.mul(2); - await aWETH.connect(user).approve(uniswapRepayAdapter.address, bigMaxAmountToSwap); - - await mockUniswapRouter.connect(user).setAmountToSwap(weth.address, bigMaxAmountToSwap); - - const flashLoanDebt = new BigNumber(expectedDaiAmount.toString()) - .multipliedBy(1.0009) - .toFixed(0); - - await mockUniswapRouter.setAmountIn( - flashLoanDebt, - weth.address, - dai.address, - bigMaxAmountToSwap - ); - - const params = buildRepayAdapterParams( - weth.address, - bigMaxAmountToSwap, - 1, - 0, - 0, - 0, - '0x0000000000000000000000000000000000000000000000000000000000000000', - '0x0000000000000000000000000000000000000000000000000000000000000000', - false - ); - - await expect( - pool - .connect(user) - .flashLoan( - uniswapRepayAdapter.address, - [dai.address], - [expectedDaiAmount.toString()], - [0], - userAddress, - params, - 0 - ) - ).to.be.revertedWith('maxAmountToSwap exceed max slippage'); - }); - - it('should swap, repay debt and pull the needed ATokens leaving no leftovers', async () => { - const { - users, - pool, - weth, - aWETH, - oracle, - dai, - uniswapRepayAdapter, - helpersContract, - } = testEnv; - const user = users[0].signer; - const userAddress = users[0].address; - - const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); - - const daiPrice = await oracle.getAssetPrice(dai.address); - const expectedDaiAmount = await convertToCurrencyDecimals( - dai.address, - new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) - ); - - // Open user Debt - await pool.connect(user).borrow(dai.address, expectedDaiAmount, 1, 0, userAddress); - - const daiStableDebtTokenAddress = ( - await helpersContract.getReserveTokensAddresses(dai.address) - ).stableDebtTokenAddress; - - const daiStableDebtContract = await getContract( - eContractid.StableDebtToken, - daiStableDebtTokenAddress - ); - - const userDaiStableDebtAmountBefore = await daiStableDebtContract.balanceOf(userAddress); - - const liquidityToSwap = amountWETHtoSwap; - await aWETH.connect(user).approve(uniswapRepayAdapter.address, liquidityToSwap); - const userAEthBalanceBefore = await aWETH.balanceOf(userAddress); - const userWethBalanceBefore = await weth.balanceOf(userAddress); - - const actualWEthSwapped = new BigNumber(liquidityToSwap.toString()) - .multipliedBy(0.995) - .toFixed(0); - - await mockUniswapRouter.connect(user).setAmountToSwap(weth.address, actualWEthSwapped); - - const flashLoanDebt = new BigNumber(expectedDaiAmount.toString()) - .multipliedBy(1.0009) - .toFixed(0); - - await mockUniswapRouter.setAmountIn( - flashLoanDebt, - weth.address, - dai.address, - actualWEthSwapped - ); - - const params = buildRepayAdapterParams( - weth.address, - liquidityToSwap, - 1, - 0, - 0, - 0, - '0x0000000000000000000000000000000000000000000000000000000000000000', - '0x0000000000000000000000000000000000000000000000000000000000000000', - false - ); - - await expect( - pool - .connect(user) - .flashLoan( - uniswapRepayAdapter.address, - [dai.address], - [expectedDaiAmount.toString()], - [0], - userAddress, - params, - 0 - ) - ) - .to.emit(uniswapRepayAdapter, 'Swapped') - .withArgs(weth.address, dai.address, actualWEthSwapped.toString(), flashLoanDebt); - - const adapterWethBalance = await weth.balanceOf(uniswapRepayAdapter.address); - const adapterDaiBalance = await dai.balanceOf(uniswapRepayAdapter.address); - const userDaiStableDebtAmount = await daiStableDebtContract.balanceOf(userAddress); - const userAEthBalance = await aWETH.balanceOf(userAddress); - const adapterAEthBalance = await aWETH.balanceOf(uniswapRepayAdapter.address); - const userWethBalance = await weth.balanceOf(userAddress); - - expect(adapterAEthBalance).to.be.eq(Zero); - expect(adapterWethBalance).to.be.eq(Zero); - expect(adapterDaiBalance).to.be.eq(Zero); - expect(userDaiStableDebtAmountBefore).to.be.gte(expectedDaiAmount); - expect(userDaiStableDebtAmount).to.be.lt(expectedDaiAmount); - expect(userAEthBalance).to.be.lt(userAEthBalanceBefore); - expect(userAEthBalance).to.be.eq(userAEthBalanceBefore.sub(actualWEthSwapped)); - expect(userWethBalance).to.be.eq(userWethBalanceBefore); - }); - - it('should correctly swap tokens and repay the whole stable debt', async () => { - const { - users, - pool, - weth, - aWETH, - oracle, - dai, - uniswapRepayAdapter, - helpersContract, - } = testEnv; - const user = users[0].signer; - const userAddress = users[0].address; - - const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); - - const daiPrice = await oracle.getAssetPrice(dai.address); - const expectedDaiAmount = await convertToCurrencyDecimals( - dai.address, - new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) - ); - - // Open user Debt - await pool.connect(user).borrow(dai.address, expectedDaiAmount, 1, 0, userAddress); - - const daiStableDebtTokenAddress = ( - await helpersContract.getReserveTokensAddresses(dai.address) - ).stableDebtTokenAddress; - - const daiStableDebtContract = await getContract( - eContractid.StableDebtToken, - daiStableDebtTokenAddress - ); - - const userDaiStableDebtAmountBefore = await daiStableDebtContract.balanceOf(userAddress); - - // Add a % to repay on top of the debt - const liquidityToSwap = new BigNumber(amountWETHtoSwap.toString()) - .multipliedBy(1.1) - .toFixed(0); - - await aWETH.connect(user).approve(uniswapRepayAdapter.address, liquidityToSwap); - const userAEthBalanceBefore = await aWETH.balanceOf(userAddress); - - // Add a % to repay on top of the debt - const amountToRepay = new BigNumber(expectedDaiAmount.toString()) - .multipliedBy(1.1) - .toFixed(0); - - await mockUniswapRouter.connect(user).setAmountToSwap(weth.address, amountWETHtoSwap); - await mockUniswapRouter.setDefaultMockValue(amountWETHtoSwap); - - const params = buildRepayAdapterParams( - weth.address, - liquidityToSwap, - 1, - 0, - 0, - 0, - '0x0000000000000000000000000000000000000000000000000000000000000000', - '0x0000000000000000000000000000000000000000000000000000000000000000', - false - ); - - await pool - .connect(user) - .flashLoan( - uniswapRepayAdapter.address, - [dai.address], - [amountToRepay.toString()], - [0], - userAddress, - params, - 0 - ); - - const adapterWethBalance = await weth.balanceOf(uniswapRepayAdapter.address); - const adapterDaiBalance = await dai.balanceOf(uniswapRepayAdapter.address); - const userDaiStableDebtAmount = await daiStableDebtContract.balanceOf(userAddress); - const userAEthBalance = await aWETH.balanceOf(userAddress); - const adapterAEthBalance = await aWETH.balanceOf(uniswapRepayAdapter.address); - - expect(adapterAEthBalance).to.be.eq(Zero); - expect(adapterWethBalance).to.be.eq(Zero); - expect(adapterDaiBalance).to.be.eq(Zero); - expect(userDaiStableDebtAmountBefore).to.be.gte(expectedDaiAmount); - expect(userDaiStableDebtAmount).to.be.eq(Zero); - expect(userAEthBalance).to.be.lt(userAEthBalanceBefore); - expect(userAEthBalance).to.be.gte(userAEthBalanceBefore.sub(liquidityToSwap)); - }); - - it('should correctly swap tokens and repay the whole variable debt', async () => { - const { - users, - pool, - weth, - aWETH, - oracle, - dai, - uniswapRepayAdapter, - helpersContract, - } = testEnv; - const user = users[0].signer; - const userAddress = users[0].address; - - const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); - - const daiPrice = await oracle.getAssetPrice(dai.address); - const expectedDaiAmount = await convertToCurrencyDecimals( - dai.address, - new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) - ); - - // Open user Debt - await pool.connect(user).borrow(dai.address, expectedDaiAmount, 2, 0, userAddress); - - const daiStableVariableTokenAddress = ( - await helpersContract.getReserveTokensAddresses(dai.address) - ).variableDebtTokenAddress; - - const daiVariableDebtContract = await getContract( - eContractid.VariableDebtToken, - daiStableVariableTokenAddress - ); - - const userDaiVariableDebtAmountBefore = await daiVariableDebtContract.balanceOf( - userAddress - ); - - // Add a % to repay on top of the debt - const liquidityToSwap = new BigNumber(amountWETHtoSwap.toString()) - .multipliedBy(1.1) - .toFixed(0); - - await aWETH.connect(user).approve(uniswapRepayAdapter.address, liquidityToSwap); - const userAEthBalanceBefore = await aWETH.balanceOf(userAddress); - - // Add a % to repay on top of the debt - const amountToRepay = new BigNumber(expectedDaiAmount.toString()) - .multipliedBy(1.1) - .toFixed(0); - - await mockUniswapRouter.connect(user).setAmountToSwap(weth.address, amountWETHtoSwap); - await mockUniswapRouter.setDefaultMockValue(amountWETHtoSwap); - - const params = buildRepayAdapterParams( - weth.address, - liquidityToSwap, - 2, - 0, - 0, - 0, - '0x0000000000000000000000000000000000000000000000000000000000000000', - '0x0000000000000000000000000000000000000000000000000000000000000000', - false - ); - - await pool - .connect(user) - .flashLoan( - uniswapRepayAdapter.address, - [dai.address], - [amountToRepay.toString()], - [0], - userAddress, - params, - 0 - ); - - const adapterWethBalance = await weth.balanceOf(uniswapRepayAdapter.address); - const adapterDaiBalance = await dai.balanceOf(uniswapRepayAdapter.address); - const userDaiVariableDebtAmount = await daiVariableDebtContract.balanceOf(userAddress); - const userAEthBalance = await aWETH.balanceOf(userAddress); - const adapterAEthBalance = await aWETH.balanceOf(uniswapRepayAdapter.address); - - expect(adapterAEthBalance).to.be.eq(Zero); - expect(adapterWethBalance).to.be.eq(Zero); - expect(adapterDaiBalance).to.be.eq(Zero); - expect(userDaiVariableDebtAmountBefore).to.be.gte(expectedDaiAmount); - expect(userDaiVariableDebtAmount).to.be.eq(Zero); - expect(userAEthBalance).to.be.lt(userAEthBalanceBefore); - expect(userAEthBalance).to.be.gte(userAEthBalanceBefore.sub(liquidityToSwap)); - }); - - it('should correctly repay debt via flash loan using the same asset as collateral', async () => { - const { users, pool, aDai, dai, uniswapRepayAdapter, helpersContract } = testEnv; - const user = users[0].signer; - const userAddress = users[0].address; - - // Add deposit for user - await dai.mint(parseEther('30')); - await dai.approve(pool.address, parseEther('30')); - await pool.deposit(dai.address, parseEther('30'), userAddress, 0); - - const amountCollateralToSwap = parseEther('10'); - const debtAmount = parseEther('10'); - - // Open user Debt - await pool.connect(user).borrow(dai.address, debtAmount, 2, 0, userAddress); - - const daiVariableDebtTokenAddress = ( - await helpersContract.getReserveTokensAddresses(dai.address) - ).variableDebtTokenAddress; - - const daiVariableDebtContract = await getContract( - eContractid.VariableDebtToken, - daiVariableDebtTokenAddress - ); - - const userDaiVariableDebtAmountBefore = await daiVariableDebtContract.balanceOf( - userAddress - ); - - const flashLoanDebt = new BigNumber(amountCollateralToSwap.toString()) - .multipliedBy(1.0009) - .toFixed(0); - - await aDai.connect(user).approve(uniswapRepayAdapter.address, flashLoanDebt); - const userADaiBalanceBefore = await aDai.balanceOf(userAddress); - const userDaiBalanceBefore = await dai.balanceOf(userAddress); - - const params = buildRepayAdapterParams( - dai.address, - amountCollateralToSwap, - 2, - 0, - 0, - 0, - '0x0000000000000000000000000000000000000000000000000000000000000000', - '0x0000000000000000000000000000000000000000000000000000000000000000', - false - ); - - await pool - .connect(user) - .flashLoan( - uniswapRepayAdapter.address, - [dai.address], - [amountCollateralToSwap.toString()], - [0], - userAddress, - params, - 0 - ); - - const adapterDaiBalance = await dai.balanceOf(uniswapRepayAdapter.address); - const userDaiVariableDebtAmount = await daiVariableDebtContract.balanceOf(userAddress); - const userADaiBalance = await aDai.balanceOf(userAddress); - const adapterADaiBalance = await aDai.balanceOf(uniswapRepayAdapter.address); - const userDaiBalance = await dai.balanceOf(userAddress); - - expect(adapterADaiBalance).to.be.eq(Zero, 'adapter aDAI balance should be zero'); - expect(adapterDaiBalance).to.be.eq(Zero, 'adapter DAI balance should be zero'); - expect(userDaiVariableDebtAmountBefore).to.be.gte( - debtAmount, - ' user DAI variable debt before should be gte debtAmount' - ); - expect(userDaiVariableDebtAmount).to.be.lt( - debtAmount, - 'user dai variable debt amount should be lt debt amount' - ); - expect(userADaiBalance).to.be.lt( - userADaiBalanceBefore, - 'user aDAI balance should be lt aDAI prior balance' - ); - expect(userADaiBalance).to.be.gte( - userADaiBalanceBefore.sub(flashLoanDebt), - 'user aDAI balance should be gte aDAI prior balance sub flash loan debt' - ); - expect(userDaiBalance).to.be.eq(userDaiBalanceBefore, 'user dai balance eq prior balance'); - }); - }); - - describe('swapAndRepay', () => { - it('should correctly swap tokens and repay debt', async () => { - const { - users, - pool, - weth, - aWETH, - oracle, - dai, - uniswapRepayAdapter, - helpersContract, - } = testEnv; - const user = users[0].signer; - const userAddress = users[0].address; - - const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); - - const daiPrice = await oracle.getAssetPrice(dai.address); - const expectedDaiAmount = await convertToCurrencyDecimals( - dai.address, - new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) - ); - - // Open user Debt - await pool.connect(user).borrow(dai.address, expectedDaiAmount, 1, 0, userAddress); - - const daiStableDebtTokenAddress = ( - await helpersContract.getReserveTokensAddresses(dai.address) - ).stableDebtTokenAddress; - - const daiStableDebtContract = await getContract( - eContractid.StableDebtToken, - daiStableDebtTokenAddress - ); - - const userDaiStableDebtAmountBefore = await daiStableDebtContract.balanceOf(userAddress); - - const liquidityToSwap = amountWETHtoSwap; - await aWETH.connect(user).approve(uniswapRepayAdapter.address, liquidityToSwap); - const userAEthBalanceBefore = await aWETH.balanceOf(userAddress); - - await mockUniswapRouter.setAmountToSwap(weth.address, liquidityToSwap); - - await mockUniswapRouter.setDefaultMockValue(liquidityToSwap); - - await uniswapRepayAdapter.connect(user).swapAndRepay( - weth.address, - dai.address, - liquidityToSwap, - expectedDaiAmount, - 1, - { - amount: 0, - deadline: 0, - v: 0, - r: '0x0000000000000000000000000000000000000000000000000000000000000000', - s: '0x0000000000000000000000000000000000000000000000000000000000000000', - }, - false - ); - - const adapterWethBalance = await weth.balanceOf(uniswapRepayAdapter.address); - const adapterDaiBalance = await dai.balanceOf(uniswapRepayAdapter.address); - const userDaiStableDebtAmount = await daiStableDebtContract.balanceOf(userAddress); - const userAEthBalance = await aWETH.balanceOf(userAddress); - - expect(adapterWethBalance).to.be.eq(Zero); - expect(adapterDaiBalance).to.be.eq(Zero); - expect(userDaiStableDebtAmountBefore).to.be.gte(expectedDaiAmount); - expect(userDaiStableDebtAmount).to.be.lt(expectedDaiAmount); - expect(userAEthBalance).to.be.lt(userAEthBalanceBefore); - expect(userAEthBalance).to.be.gte(userAEthBalanceBefore.sub(liquidityToSwap)); - }); - - it('should correctly swap tokens and repay debt with permit', async () => { - const { - users, - pool, - weth, - aWETH, - oracle, - dai, - uniswapRepayAdapter, - helpersContract, - } = testEnv; - const user = users[0].signer; - const userAddress = users[0].address; - - const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); - - const daiPrice = await oracle.getAssetPrice(dai.address); - const expectedDaiAmount = await convertToCurrencyDecimals( - dai.address, - new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) - ); - - // Open user Debt - await pool.connect(user).borrow(dai.address, expectedDaiAmount, 1, 0, userAddress); - - const daiStableDebtTokenAddress = ( - await helpersContract.getReserveTokensAddresses(dai.address) - ).stableDebtTokenAddress; - - const daiStableDebtContract = await getContract( - eContractid.StableDebtToken, - daiStableDebtTokenAddress - ); - - const userDaiStableDebtAmountBefore = await daiStableDebtContract.balanceOf(userAddress); - - const liquidityToSwap = amountWETHtoSwap; - const userAEthBalanceBefore = await aWETH.balanceOf(userAddress); - - await mockUniswapRouter.setAmountToSwap(weth.address, liquidityToSwap); - - await mockUniswapRouter.setDefaultMockValue(liquidityToSwap); - - const chainId = DRE.network.config.chainId || BUIDLEREVM_CHAINID; - const deadline = MAX_UINT_AMOUNT; - const nonce = (await aWETH._nonces(userAddress)).toNumber(); - const msgParams = buildPermitParams( - chainId, - aWETH.address, - '1', - await aWETH.name(), - userAddress, - uniswapRepayAdapter.address, - nonce, - deadline, - liquidityToSwap.toString() - ); - - const ownerPrivateKey = require('../test-wallets.js').accounts[1].secretKey; - if (!ownerPrivateKey) { - throw new Error('INVALID_OWNER_PK'); - } - - const { v, r, s } = getSignatureFromTypedData(ownerPrivateKey, msgParams); - - await uniswapRepayAdapter.connect(user).swapAndRepay( - weth.address, - dai.address, - liquidityToSwap, - expectedDaiAmount, - 1, - { - amount: liquidityToSwap, - deadline, - v, - r, - s, - }, - false - ); - - const adapterWethBalance = await weth.balanceOf(uniswapRepayAdapter.address); - const adapterDaiBalance = await dai.balanceOf(uniswapRepayAdapter.address); - const userDaiStableDebtAmount = await daiStableDebtContract.balanceOf(userAddress); - const userAEthBalance = await aWETH.balanceOf(userAddress); - - expect(adapterWethBalance).to.be.eq(Zero); - expect(adapterDaiBalance).to.be.eq(Zero); - expect(userDaiStableDebtAmountBefore).to.be.gte(expectedDaiAmount); - expect(userDaiStableDebtAmount).to.be.lt(expectedDaiAmount); - expect(userAEthBalance).to.be.lt(userAEthBalanceBefore); - expect(userAEthBalance).to.be.gte(userAEthBalanceBefore.sub(liquidityToSwap)); - }); - - it('should revert if there is not debt to repay', async () => { - const { users, weth, aWETH, oracle, dai, uniswapRepayAdapter } = testEnv; - const user = users[0].signer; - - const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); - - const daiPrice = await oracle.getAssetPrice(dai.address); - const expectedDaiAmount = await convertToCurrencyDecimals( - dai.address, - new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) - ); - - const liquidityToSwap = amountWETHtoSwap; - await aWETH.connect(user).approve(uniswapRepayAdapter.address, liquidityToSwap); - - await mockUniswapRouter.setAmountToSwap(weth.address, liquidityToSwap); - - await mockUniswapRouter.setDefaultMockValue(liquidityToSwap); - - await expect( - uniswapRepayAdapter.connect(user).swapAndRepay( - weth.address, - dai.address, - liquidityToSwap, - expectedDaiAmount, - 1, - { - amount: 0, - deadline: 0, - v: 0, - r: '0x0000000000000000000000000000000000000000000000000000000000000000', - s: '0x0000000000000000000000000000000000000000000000000000000000000000', - }, - false - ) - ).to.be.reverted; - }); - - it('should revert when max amount allowed to swap is bigger than max slippage', async () => { - const { users, pool, weth, aWETH, oracle, dai, uniswapRepayAdapter } = testEnv; - const user = users[0].signer; - const userAddress = users[0].address; - - const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); - - const daiPrice = await oracle.getAssetPrice(dai.address); - const expectedDaiAmount = await convertToCurrencyDecimals( - dai.address, - new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) - ); - - // Open user Debt - await pool.connect(user).borrow(dai.address, expectedDaiAmount, 1, 0, userAddress); - - const bigMaxAmountToSwap = amountWETHtoSwap.mul(2); - await aWETH.connect(user).approve(uniswapRepayAdapter.address, bigMaxAmountToSwap); - - await mockUniswapRouter.connect(user).setAmountToSwap(weth.address, bigMaxAmountToSwap); - - await mockUniswapRouter.setDefaultMockValue(bigMaxAmountToSwap); - - await expect( - uniswapRepayAdapter.connect(user).swapAndRepay( - weth.address, - dai.address, - bigMaxAmountToSwap, - expectedDaiAmount, - 1, - { - amount: 0, - deadline: 0, - v: 0, - r: '0x0000000000000000000000000000000000000000000000000000000000000000', - s: '0x0000000000000000000000000000000000000000000000000000000000000000', - }, - false - ) - ).to.be.revertedWith('maxAmountToSwap exceed max slippage'); - }); - - it('should swap, repay debt and pull the needed ATokens leaving no leftovers', async () => { - const { - users, - pool, - weth, - aWETH, - oracle, - dai, - uniswapRepayAdapter, - helpersContract, - } = testEnv; - const user = users[0].signer; - const userAddress = users[0].address; - - const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); - - const daiPrice = await oracle.getAssetPrice(dai.address); - const expectedDaiAmount = await convertToCurrencyDecimals( - dai.address, - new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) - ); - - // Open user Debt - await pool.connect(user).borrow(dai.address, expectedDaiAmount, 1, 0, userAddress); - - const daiStableDebtTokenAddress = ( - await helpersContract.getReserveTokensAddresses(dai.address) - ).stableDebtTokenAddress; - - const daiStableDebtContract = await getContract( - eContractid.StableDebtToken, - daiStableDebtTokenAddress - ); - - const userDaiStableDebtAmountBefore = await daiStableDebtContract.balanceOf(userAddress); - - const liquidityToSwap = amountWETHtoSwap; - await aWETH.connect(user).approve(uniswapRepayAdapter.address, liquidityToSwap); - const userAEthBalanceBefore = await aWETH.balanceOf(userAddress); - const userWethBalanceBefore = await weth.balanceOf(userAddress); - - const actualWEthSwapped = new BigNumber(liquidityToSwap.toString()) - .multipliedBy(0.995) - .toFixed(0); - - await mockUniswapRouter.connect(user).setAmountToSwap(weth.address, actualWEthSwapped); - - await mockUniswapRouter.setDefaultMockValue(actualWEthSwapped); - - await uniswapRepayAdapter.connect(user).swapAndRepay( - weth.address, - dai.address, - liquidityToSwap, - expectedDaiAmount, - 1, - { - amount: 0, - deadline: 0, - v: 0, - r: '0x0000000000000000000000000000000000000000000000000000000000000000', - s: '0x0000000000000000000000000000000000000000000000000000000000000000', - }, - false - ); - - const adapterWethBalance = await weth.balanceOf(uniswapRepayAdapter.address); - const adapterDaiBalance = await dai.balanceOf(uniswapRepayAdapter.address); - const userDaiStableDebtAmount = await daiStableDebtContract.balanceOf(userAddress); - const userAEthBalance = await aWETH.balanceOf(userAddress); - const adapterAEthBalance = await aWETH.balanceOf(uniswapRepayAdapter.address); - const userWethBalance = await weth.balanceOf(userAddress); - - expect(adapterAEthBalance).to.be.eq(Zero); - expect(adapterWethBalance).to.be.eq(Zero); - expect(adapterDaiBalance).to.be.eq(Zero); - expect(userDaiStableDebtAmountBefore).to.be.gte(expectedDaiAmount); - expect(userDaiStableDebtAmount).to.be.lt(expectedDaiAmount); - expect(userAEthBalance).to.be.lt(userAEthBalanceBefore); - expect(userAEthBalance).to.be.eq(userAEthBalanceBefore.sub(actualWEthSwapped)); - expect(userWethBalance).to.be.eq(userWethBalanceBefore); - }); - - it('should correctly swap tokens and repay the whole stable debt', async () => { - const { - users, - pool, - weth, - aWETH, - oracle, - dai, - uniswapRepayAdapter, - helpersContract, - } = testEnv; - const user = users[0].signer; - const userAddress = users[0].address; - - const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); - - const daiPrice = await oracle.getAssetPrice(dai.address); - const expectedDaiAmount = await convertToCurrencyDecimals( - dai.address, - new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) - ); - - // Open user Debt - await pool.connect(user).borrow(dai.address, expectedDaiAmount, 1, 0, userAddress); - - const daiStableDebtTokenAddress = ( - await helpersContract.getReserveTokensAddresses(dai.address) - ).stableDebtTokenAddress; - - const daiStableDebtContract = await getContract( - eContractid.StableDebtToken, - daiStableDebtTokenAddress - ); - - const userDaiStableDebtAmountBefore = await daiStableDebtContract.balanceOf(userAddress); - - // Add a % to repay on top of the debt - const liquidityToSwap = new BigNumber(amountWETHtoSwap.toString()) - .multipliedBy(1.1) - .toFixed(0); - - await aWETH.connect(user).approve(uniswapRepayAdapter.address, liquidityToSwap); - const userAEthBalanceBefore = await aWETH.balanceOf(userAddress); - - // Add a % to repay on top of the debt - const amountToRepay = new BigNumber(expectedDaiAmount.toString()) - .multipliedBy(1.1) - .toFixed(0); - - await mockUniswapRouter.connect(user).setAmountToSwap(weth.address, amountWETHtoSwap); - await mockUniswapRouter.setDefaultMockValue(amountWETHtoSwap); - - await uniswapRepayAdapter.connect(user).swapAndRepay( - weth.address, - dai.address, - liquidityToSwap, - amountToRepay, - 1, - { - amount: 0, - deadline: 0, - v: 0, - r: '0x0000000000000000000000000000000000000000000000000000000000000000', - s: '0x0000000000000000000000000000000000000000000000000000000000000000', - }, - false - ); - - const adapterWethBalance = await weth.balanceOf(uniswapRepayAdapter.address); - const adapterDaiBalance = await dai.balanceOf(uniswapRepayAdapter.address); - const userDaiStableDebtAmount = await daiStableDebtContract.balanceOf(userAddress); - const userAEthBalance = await aWETH.balanceOf(userAddress); - const adapterAEthBalance = await aWETH.balanceOf(uniswapRepayAdapter.address); - - expect(adapterAEthBalance).to.be.eq(Zero); - expect(adapterWethBalance).to.be.eq(Zero); - expect(adapterDaiBalance).to.be.eq(Zero); - expect(userDaiStableDebtAmountBefore).to.be.gte(expectedDaiAmount); - expect(userDaiStableDebtAmount).to.be.eq(Zero); - expect(userAEthBalance).to.be.lt(userAEthBalanceBefore); - expect(userAEthBalance).to.be.gte(userAEthBalanceBefore.sub(liquidityToSwap)); - }); - - it('should correctly swap tokens and repay the whole variable debt', async () => { - const { - users, - pool, - weth, - aWETH, - oracle, - dai, - uniswapRepayAdapter, - helpersContract, - } = testEnv; - const user = users[0].signer; - const userAddress = users[0].address; - - const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); - - const daiPrice = await oracle.getAssetPrice(dai.address); - const expectedDaiAmount = await convertToCurrencyDecimals( - dai.address, - new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) - ); - - // Open user Debt - await pool.connect(user).borrow(dai.address, expectedDaiAmount, 2, 0, userAddress); - - const daiStableVariableTokenAddress = ( - await helpersContract.getReserveTokensAddresses(dai.address) - ).variableDebtTokenAddress; - - const daiVariableDebtContract = await getContract( - eContractid.VariableDebtToken, - daiStableVariableTokenAddress - ); - - const userDaiVariableDebtAmountBefore = await daiVariableDebtContract.balanceOf( - userAddress - ); - - // Add a % to repay on top of the debt - const liquidityToSwap = new BigNumber(amountWETHtoSwap.toString()) - .multipliedBy(1.1) - .toFixed(0); - - await aWETH.connect(user).approve(uniswapRepayAdapter.address, liquidityToSwap); - const userAEthBalanceBefore = await aWETH.balanceOf(userAddress); - - // Add a % to repay on top of the debt - const amountToRepay = new BigNumber(expectedDaiAmount.toString()) - .multipliedBy(1.1) - .toFixed(0); - - await mockUniswapRouter.connect(user).setAmountToSwap(weth.address, amountWETHtoSwap); - await mockUniswapRouter.setDefaultMockValue(amountWETHtoSwap); - - await uniswapRepayAdapter.connect(user).swapAndRepay( - weth.address, - dai.address, - liquidityToSwap, - amountToRepay, - 2, - { - amount: 0, - deadline: 0, - v: 0, - r: '0x0000000000000000000000000000000000000000000000000000000000000000', - s: '0x0000000000000000000000000000000000000000000000000000000000000000', - }, - false - ); - - const adapterWethBalance = await weth.balanceOf(uniswapRepayAdapter.address); - const adapterDaiBalance = await dai.balanceOf(uniswapRepayAdapter.address); - const userDaiVariableDebtAmount = await daiVariableDebtContract.balanceOf(userAddress); - const userAEthBalance = await aWETH.balanceOf(userAddress); - const adapterAEthBalance = await aWETH.balanceOf(uniswapRepayAdapter.address); - - expect(adapterAEthBalance).to.be.eq(Zero); - expect(adapterWethBalance).to.be.eq(Zero); - expect(adapterDaiBalance).to.be.eq(Zero); - expect(userDaiVariableDebtAmountBefore).to.be.gte(expectedDaiAmount); - expect(userDaiVariableDebtAmount).to.be.eq(Zero); - expect(userAEthBalance).to.be.lt(userAEthBalanceBefore); - expect(userAEthBalance).to.be.gte(userAEthBalanceBefore.sub(liquidityToSwap)); - }); - - it('should correctly repay debt using the same asset as collateral', async () => { - const { users, pool, dai, uniswapRepayAdapter, helpersContract, aDai } = testEnv; - const user = users[0].signer; - const userAddress = users[0].address; - - // Add deposit for user - await dai.mint(parseEther('30')); - await dai.approve(pool.address, parseEther('30')); - await pool.deposit(dai.address, parseEther('30'), userAddress, 0); - - const amountCollateralToSwap = parseEther('4'); - - const debtAmount = parseEther('3'); - - // Open user Debt - await pool.connect(user).borrow(dai.address, debtAmount, 2, 0, userAddress); - - const daiVariableDebtTokenAddress = ( - await helpersContract.getReserveTokensAddresses(dai.address) - ).variableDebtTokenAddress; - - const daiVariableDebtContract = await getContract( - eContractid.StableDebtToken, - daiVariableDebtTokenAddress - ); - - const userDaiVariableDebtAmountBefore = await daiVariableDebtContract.balanceOf( - userAddress - ); - - await aDai.connect(user).approve(uniswapRepayAdapter.address, amountCollateralToSwap); - const userADaiBalanceBefore = await aDai.balanceOf(userAddress); - const userDaiBalanceBefore = await dai.balanceOf(userAddress); - - await uniswapRepayAdapter.connect(user).swapAndRepay( - dai.address, - dai.address, - amountCollateralToSwap, - amountCollateralToSwap, - 2, - { - amount: 0, - deadline: 0, - v: 0, - r: '0x0000000000000000000000000000000000000000000000000000000000000000', - s: '0x0000000000000000000000000000000000000000000000000000000000000000', - }, - false - ); - - const adapterDaiBalance = await dai.balanceOf(uniswapRepayAdapter.address); - const userDaiVariableDebtAmount = await daiVariableDebtContract.balanceOf(userAddress); - const userADaiBalance = await aDai.balanceOf(userAddress); - const adapterADaiBalance = await aDai.balanceOf(uniswapRepayAdapter.address); - const userDaiBalance = await dai.balanceOf(userAddress); - - expect(adapterADaiBalance).to.be.eq(Zero, 'adapter aADAI should be zero'); - expect(adapterDaiBalance).to.be.eq(Zero, 'adapter DAI should be zero'); - expect(userDaiVariableDebtAmountBefore).to.be.gte( - debtAmount, - 'user dai variable debt before should be gte debtAmount' - ); - expect(userDaiVariableDebtAmount).to.be.lt( - debtAmount, - 'current user dai variable debt amount should be less than debtAmount' - ); - expect(userADaiBalance).to.be.lt( - userADaiBalanceBefore, - 'current user aDAI balance should be less than prior balance' - ); - expect(userADaiBalance).to.be.gte( - userADaiBalanceBefore.sub(amountCollateralToSwap), - 'current user aDAI balance should be gte user balance sub swapped collateral' - ); - expect(userDaiBalance).to.be.eq( - userDaiBalanceBefore, - 'user DAI balance should remain equal' - ); - }); - }); - }); -}); diff --git a/test/upgradeability.spec.ts b/test/upgradeability.spec.ts deleted file mode 100644 index 95e3a8fe..00000000 --- a/test/upgradeability.spec.ts +++ /dev/null @@ -1,234 +0,0 @@ -import { expect } from 'chai'; -import { makeSuite, TestEnv } from './helpers/make-suite'; -import { ProtocolErrors, eContractid } from '../helpers/types'; -import { deployContract, getContract } from '../helpers/contracts-helpers'; -import { MockAToken } from '../types/MockAToken'; -import { MockStableDebtToken } from '../types/MockStableDebtToken'; -import { MockVariableDebtToken } from '../types/MockVariableDebtToken'; -import { ZERO_ADDRESS } from '../helpers/constants'; -import { - getAToken, - getMockStableDebtToken, - getMockVariableDebtToken, - getStableDebtToken, - getVariableDebtToken, -} from '../helpers/contracts-getters'; -import { - deployMockAToken, - deployMockStableDebtToken, - deployMockVariableDebtToken, -} from '../helpers/contracts-deployments'; - -makeSuite('Upgradeability', (testEnv: TestEnv) => { - const { CALLER_NOT_POOL_ADMIN } = ProtocolErrors; - let newATokenAddress: string; - let newStableTokenAddress: string; - let newVariableTokenAddress: string; - - before('deploying instances', async () => { - const { dai, pool } = testEnv; - const aTokenInstance = await deployMockAToken([ - pool.address, - dai.address, - ZERO_ADDRESS, - ZERO_ADDRESS, - 'Aave Interest bearing DAI updated', - 'aDAI', - ]); - - const stableDebtTokenInstance = await deployMockStableDebtToken([ - pool.address, - dai.address, - ZERO_ADDRESS, - 'Aave stable debt bearing DAI updated', - 'stableDebtDAI', - ]); - - const variableDebtTokenInstance = await deployMockVariableDebtToken([ - pool.address, - dai.address, - ZERO_ADDRESS, - 'Aave variable debt bearing DAI updated', - 'variableDebtDAI', - ]); - - newATokenAddress = aTokenInstance.address; - newVariableTokenAddress = variableDebtTokenInstance.address; - newStableTokenAddress = stableDebtTokenInstance.address; - }); - - it('Tries to update the DAI Atoken implementation with a different address than the lendingPoolManager', async () => { - const { dai, configurator, users } = testEnv; - - const name = await (await getAToken(newATokenAddress)).name(); - const symbol = await (await getAToken(newATokenAddress)).symbol(); - - const updateATokenInputParams: { - asset: string; - treasury: string; - incentivesController: string; - name: string; - symbol: string; - implementation: string; - } = { - asset: dai.address, - treasury: ZERO_ADDRESS, - incentivesController: ZERO_ADDRESS, - name: name, - symbol: symbol, - implementation: newATokenAddress, - }; - await expect( - configurator.connect(users[1].signer).updateAToken(updateATokenInputParams) - ).to.be.revertedWith(CALLER_NOT_POOL_ADMIN); - }); - - it('Upgrades the DAI Atoken implementation ', async () => { - const { dai, configurator, aDai } = testEnv; - - const name = await (await getAToken(newATokenAddress)).name(); - const symbol = await (await getAToken(newATokenAddress)).symbol(); - - const updateATokenInputParams: { - asset: string; - treasury: string; - incentivesController: string; - name: string; - symbol: string; - implementation: string; - } = { - asset: dai.address, - treasury: ZERO_ADDRESS, - incentivesController: ZERO_ADDRESS, - name: name, - symbol: symbol, - implementation: newATokenAddress, - }; - await configurator.updateAToken(updateATokenInputParams); - - const tokenName = await aDai.name(); - - expect(tokenName).to.be.eq('Aave Interest bearing DAI updated', 'Invalid token name'); - }); - - it('Tries to update the DAI Stable debt token implementation with a different address than the lendingPoolManager', async () => { - const { dai, configurator, users } = testEnv; - - const name = await (await getStableDebtToken(newStableTokenAddress)).name(); - const symbol = await (await getStableDebtToken(newStableTokenAddress)).symbol(); - - - const updateDebtTokenInput: { - asset: string; - incentivesController: string; - name: string; - symbol: string; - implementation: string; - } = { - asset: dai.address, - incentivesController: ZERO_ADDRESS, - name: name, - symbol: symbol, - implementation: newStableTokenAddress, - } - - await expect( - configurator - .connect(users[1].signer) - .updateStableDebtToken(updateDebtTokenInput) - ).to.be.revertedWith(CALLER_NOT_POOL_ADMIN); - }); - - it('Upgrades the DAI stable debt token implementation ', async () => { - const { dai, configurator, pool, helpersContract } = testEnv; - - const name = await (await getStableDebtToken(newStableTokenAddress)).name(); - const symbol = await (await getStableDebtToken(newStableTokenAddress)).symbol(); - - - const updateDebtTokenInput: { - asset: string; - incentivesController: string; - name: string; - symbol: string; - implementation: string; - } = { - asset: dai.address, - incentivesController: ZERO_ADDRESS, - name: name, - symbol: symbol, - implementation: newStableTokenAddress, - } - - await configurator.updateStableDebtToken(updateDebtTokenInput); - - const { stableDebtTokenAddress } = await helpersContract.getReserveTokensAddresses(dai.address); - - const debtToken = await getMockStableDebtToken(stableDebtTokenAddress); - - const tokenName = await debtToken.name(); - - expect(tokenName).to.be.eq('Aave stable debt bearing DAI updated', 'Invalid token name'); - }); - - it('Tries to update the DAI variable debt token implementation with a different address than the lendingPoolManager', async () => { - const {dai, configurator, users} = testEnv; - - const name = await (await getVariableDebtToken(newVariableTokenAddress)).name(); - const symbol = await (await getVariableDebtToken(newVariableTokenAddress)).symbol(); - - const updateDebtTokenInput: { - asset: string; - incentivesController: string; - name: string; - symbol: string; - implementation: string; - } = { - asset: dai.address, - incentivesController: ZERO_ADDRESS, - name: name, - symbol: symbol, - implementation: newVariableTokenAddress, - } - - await expect( - configurator - .connect(users[1].signer) - .updateVariableDebtToken(updateDebtTokenInput) - ).to.be.revertedWith(CALLER_NOT_POOL_ADMIN); - }); - - it('Upgrades the DAI variable debt token implementation ', async () => { - const {dai, configurator, pool, helpersContract} = testEnv; - - const name = await (await getVariableDebtToken(newVariableTokenAddress)).name(); - const symbol = await (await getVariableDebtToken(newVariableTokenAddress)).symbol(); - - const updateDebtTokenInput: { - asset: string; - incentivesController: string; - name: string; - symbol: string; - implementation: string; - } = { - asset: dai.address, - incentivesController: ZERO_ADDRESS, - name: name, - symbol: symbol, - implementation: newVariableTokenAddress, - } - //const name = await (await getAToken(newATokenAddress)).name(); - - await configurator.updateVariableDebtToken(updateDebtTokenInput); - - const { variableDebtTokenAddress } = await helpersContract.getReserveTokensAddresses( - dai.address - ); - - const debtToken = await getMockVariableDebtToken(variableDebtTokenAddress); - - const tokenName = await debtToken.name(); - - expect(tokenName).to.be.eq('Aave variable debt bearing DAI updated', 'Invalid token name'); - }); -}); diff --git a/test/variable-debt-token.spec.ts b/test/variable-debt-token.spec.ts deleted file mode 100644 index 0faf7087..00000000 --- a/test/variable-debt-token.spec.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { expect } from 'chai'; -import { makeSuite, TestEnv } from './helpers/make-suite'; -import { ProtocolErrors, TokenContractId, eContractid } from '../helpers/types'; -import { getVariableDebtToken } from '../helpers/contracts-getters'; - -makeSuite('Variable debt token tests', (testEnv: TestEnv) => { - const { CT_CALLER_MUST_BE_LENDING_POOL } = ProtocolErrors; - - it('Tries to invoke mint not being the LendingPool', async () => { - const { deployer, pool, dai, helpersContract } = testEnv; - - const daiVariableDebtTokenAddress = ( - await helpersContract.getReserveTokensAddresses(dai.address) - ).variableDebtTokenAddress; - - const variableDebtContract = await getVariableDebtToken(daiVariableDebtTokenAddress); - - await expect( - variableDebtContract.mint(deployer.address, deployer.address, '1', '1') - ).to.be.revertedWith(CT_CALLER_MUST_BE_LENDING_POOL); - }); - - it('Tries to invoke burn not being the LendingPool', async () => { - const { deployer, pool, dai, helpersContract } = testEnv; - - const daiVariableDebtTokenAddress = ( - await helpersContract.getReserveTokensAddresses(dai.address) - ).variableDebtTokenAddress; - - const variableDebtContract = await getVariableDebtToken(daiVariableDebtTokenAddress); - - await expect(variableDebtContract.burn(deployer.address, '1', '1')).to.be.revertedWith( - CT_CALLER_MUST_BE_LENDING_POOL - ); - }); -}); diff --git a/test/weth-gateway.spec.ts b/test/weth-gateway.spec.ts deleted file mode 100644 index eadf9703..00000000 --- a/test/weth-gateway.spec.ts +++ /dev/null @@ -1,370 +0,0 @@ -import { MAX_UINT_AMOUNT } from '../helpers/constants'; -import { convertToCurrencyDecimals } from '../helpers/contracts-helpers'; -import { makeSuite, TestEnv } from './helpers/make-suite'; -import { parseEther } from 'ethers/lib/utils'; -import { DRE, waitForTx } from '../helpers/misc-utils'; -import { BigNumber } from 'ethers'; -import { getStableDebtToken, getVariableDebtToken } from '../helpers/contracts-getters'; -import { deploySelfdestructTransferMock } from '../helpers/contracts-deployments'; - -const { expect } = require('chai'); - -makeSuite('Use native ETH at LendingPool via WETHGateway', (testEnv: TestEnv) => { - const zero = BigNumber.from('0'); - const depositSize = parseEther('5'); - const daiSize = parseEther('10000'); - it('Deposit WETH via WethGateway and DAI', async () => { - const { users, wethGateway, aWETH } = testEnv; - - const user = users[1]; - const depositor = users[0]; - - // Deposit liquidity with native ETH - await wethGateway - .connect(depositor.signer) - .depositETH(depositor.address, '0', { value: depositSize }); - - // Deposit with native ETH - await wethGateway.connect(user.signer).depositETH(user.address, '0', { value: depositSize }); - - const aTokensBalance = await aWETH.balanceOf(user.address); - - expect(aTokensBalance).to.be.gt(zero); - expect(aTokensBalance).to.be.gte(depositSize); - }); - - it('Withdraw WETH - Partial', async () => { - const { users, wethGateway, aWETH, pool } = testEnv; - - const user = users[1]; - const priorEthersBalance = await user.signer.getBalance(); - const aTokensBalance = await aWETH.balanceOf(user.address); - - expect(aTokensBalance).to.be.gt(zero, 'User should have aTokens.'); - - // Partially withdraw native ETH - const partialWithdraw = await convertToCurrencyDecimals(aWETH.address, '2'); - - // Approve the aTokens to Gateway so Gateway can withdraw and convert to Ether - const approveTx = await aWETH - .connect(user.signer) - .approve(wethGateway.address, MAX_UINT_AMOUNT); - const { gasUsed: approveGas } = await waitForTx(approveTx); - - // Partial Withdraw and send native Ether to user - const { gasUsed: withdrawGas } = await waitForTx( - await wethGateway.connect(user.signer).withdrawETH(partialWithdraw, user.address) - ); - - const afterPartialEtherBalance = await user.signer.getBalance(); - const afterPartialATokensBalance = await aWETH.balanceOf(user.address); - const gasCosts = approveGas.add(withdrawGas).mul(approveTx.gasPrice); - - expect(afterPartialEtherBalance).to.be.equal( - priorEthersBalance.add(partialWithdraw).sub(gasCosts), - 'User ETHER balance should contain the partial withdraw' - ); - expect(afterPartialATokensBalance).to.be.equal( - aTokensBalance.sub(partialWithdraw), - 'User aWETH balance should be substracted' - ); - }); - - it('Withdraw WETH - Full', async () => { - const { users, aWETH, wethGateway, pool } = testEnv; - - const user = users[1]; - const priorEthersBalance = await user.signer.getBalance(); - const aTokensBalance = await aWETH.balanceOf(user.address); - - expect(aTokensBalance).to.be.gt(zero, 'User should have aTokens.'); - - // Approve the aTokens to Gateway so Gateway can withdraw and convert to Ether - const approveTx = await aWETH - .connect(user.signer) - .approve(wethGateway.address, MAX_UINT_AMOUNT); - const { gasUsed: approveGas } = await waitForTx(approveTx); - - // Full withdraw - const { gasUsed: withdrawGas } = await waitForTx( - await wethGateway.connect(user.signer).withdrawETH(MAX_UINT_AMOUNT, user.address) - ); - - const afterFullEtherBalance = await user.signer.getBalance(); - const afterFullATokensBalance = await aWETH.balanceOf(user.address); - const gasCosts = approveGas.add(withdrawGas).mul(approveTx.gasPrice); - - expect(afterFullEtherBalance).to.be.eq( - priorEthersBalance.add(aTokensBalance).sub(gasCosts), - 'User ETHER balance should contain the full withdraw' - ); - expect(afterFullATokensBalance).to.be.eq(0, 'User aWETH balance should be zero'); - }); - - it('Borrow stable WETH and Full Repay with ETH', async () => { - const { users, wethGateway, aDai, weth, dai, pool, helpersContract } = testEnv; - const borrowSize = parseEther('1'); - const repaySize = borrowSize.add(borrowSize.mul(5).div(100)); - const user = users[1]; - const depositor = users[0]; - - // Deposit with native ETH - await wethGateway - .connect(depositor.signer) - .depositETH(depositor.address, '0', { value: depositSize }); - - const { stableDebtTokenAddress } = await helpersContract.getReserveTokensAddresses( - weth.address - ); - - const stableDebtToken = await getStableDebtToken(stableDebtTokenAddress); - - // Deposit 10000 DAI - await dai.connect(user.signer).mint(daiSize); - await dai.connect(user.signer).approve(pool.address, daiSize); - await pool.connect(user.signer).deposit(dai.address, daiSize, user.address, '0'); - - const aTokensBalance = await aDai.balanceOf(user.address); - - expect(aTokensBalance).to.be.gt(zero); - expect(aTokensBalance).to.be.gte(daiSize); - - // Borrow WETH with WETH as collateral - await waitForTx( - await pool.connect(user.signer).borrow(weth.address, borrowSize, '1', '0', user.address) - ); - - const debtBalance = await stableDebtToken.balanceOf(user.address); - - expect(debtBalance).to.be.gt(zero); - - // Full Repay WETH with native ETH - await waitForTx( - await wethGateway - .connect(user.signer) - .repayETH(MAX_UINT_AMOUNT, '1', user.address, { value: repaySize }) - ); - - const debtBalanceAfterRepay = await stableDebtToken.balanceOf(user.address); - expect(debtBalanceAfterRepay).to.be.eq(zero); - - // Withdraw DAI - await aDai.connect(user.signer).approve(pool.address, MAX_UINT_AMOUNT); - await pool.connect(user.signer).withdraw(dai.address, MAX_UINT_AMOUNT, user.address); - }); - - it('Borrow variable WETH and Full Repay with ETH', async () => { - const { users, wethGateway, aWETH, weth, pool, helpersContract } = testEnv; - const borrowSize = parseEther('1'); - const repaySize = borrowSize.add(borrowSize.mul(5).div(100)); - const user = users[1]; - - const { variableDebtTokenAddress } = await helpersContract.getReserveTokensAddresses( - weth.address - ); - - const varDebtToken = await getVariableDebtToken(variableDebtTokenAddress); - - // Deposit with native ETH - await wethGateway.connect(user.signer).depositETH(user.address, '0', { value: depositSize }); - - const aTokensBalance = await aWETH.balanceOf(user.address); - - expect(aTokensBalance).to.be.gt(zero); - expect(aTokensBalance).to.be.gte(depositSize); - - // Borrow WETH with WETH as collateral - await waitForTx( - await pool.connect(user.signer).borrow(weth.address, borrowSize, '2', '0', user.address) - ); - - const debtBalance = await varDebtToken.balanceOf(user.address); - - expect(debtBalance).to.be.gt(zero); - - // Partial Repay WETH loan with native ETH - const partialPayment = repaySize.div(2); - await waitForTx( - await wethGateway - .connect(user.signer) - .repayETH(partialPayment, '2', user.address, { value: partialPayment }) - ); - - const debtBalanceAfterPartialRepay = await varDebtToken.balanceOf(user.address); - expect(debtBalanceAfterPartialRepay).to.be.lt(debtBalance); - - // Full Repay WETH loan with native ETH - await waitForTx( - await wethGateway - .connect(user.signer) - .repayETH(MAX_UINT_AMOUNT, '2', user.address, { value: repaySize }) - ); - const debtBalanceAfterFullRepay = await varDebtToken.balanceOf(user.address); - expect(debtBalanceAfterFullRepay).to.be.eq(zero); - }); - - it('Borrow ETH via delegateApprove ETH and repays back', async () => { - const { users, wethGateway, aWETH, weth, helpersContract } = testEnv; - const borrowSize = parseEther('1'); - const user = users[2]; - const { variableDebtTokenAddress } = await helpersContract.getReserveTokensAddresses( - weth.address - ); - const varDebtToken = await getVariableDebtToken(variableDebtTokenAddress); - - const priorDebtBalance = await varDebtToken.balanceOf(user.address); - expect(priorDebtBalance).to.be.eq(zero); - - // Deposit WETH with native ETH - await wethGateway.connect(user.signer).depositETH(user.address, '0', { value: depositSize }); - - const aTokensBalance = await aWETH.balanceOf(user.address); - - expect(aTokensBalance).to.be.gt(zero); - expect(aTokensBalance).to.be.gte(depositSize); - - // Delegates borrowing power of WETH to WETHGateway - await waitForTx( - await varDebtToken.connect(user.signer).approveDelegation(wethGateway.address, borrowSize) - ); - - // Borrows ETH with WETH as collateral - await waitForTx(await wethGateway.connect(user.signer).borrowETH(borrowSize, '2', '0')); - - const debtBalance = await varDebtToken.balanceOf(user.address); - - expect(debtBalance).to.be.gt(zero); - - // Full Repay WETH loan with native ETH - await waitForTx( - await wethGateway - .connect(user.signer) - .repayETH(MAX_UINT_AMOUNT, '2', user.address, { value: borrowSize.mul(2) }) - ); - const debtBalanceAfterFullRepay = await varDebtToken.balanceOf(user.address); - expect(debtBalanceAfterFullRepay).to.be.eq(zero); - }); - - it('Should revert if receiver function receives Ether if not WETH', async () => { - const { users, wethGateway } = testEnv; - const user = users[0]; - const amount = parseEther('1'); - - // Call receiver function (empty data + value) - await expect( - user.signer.sendTransaction({ - to: wethGateway.address, - value: amount, - gasLimit: DRE.network.config.gas, - }) - ).to.be.revertedWith('Receive not allowed'); - }); - - it('Should revert if fallback functions is called with Ether', async () => { - const { users, wethGateway } = testEnv; - const user = users[0]; - const amount = parseEther('1'); - const fakeABI = ['function wantToCallFallback()']; - const abiCoder = new DRE.ethers.utils.Interface(fakeABI); - const fakeMethodEncoded = abiCoder.encodeFunctionData('wantToCallFallback', []); - - // Call fallback function with value - await expect( - user.signer.sendTransaction({ - to: wethGateway.address, - data: fakeMethodEncoded, - value: amount, - gasLimit: DRE.network.config.gas, - }) - ).to.be.revertedWith('Fallback not allowed'); - }); - - it('Should revert if fallback functions is called', async () => { - const { users, wethGateway } = testEnv; - const user = users[0]; - - const fakeABI = ['function wantToCallFallback()']; - const abiCoder = new DRE.ethers.utils.Interface(fakeABI); - const fakeMethodEncoded = abiCoder.encodeFunctionData('wantToCallFallback', []); - - // Call fallback function without value - await expect( - user.signer.sendTransaction({ - to: wethGateway.address, - data: fakeMethodEncoded, - gasLimit: DRE.network.config.gas, - }) - ).to.be.revertedWith('Fallback not allowed'); - }); - - it('Getters should retrieve correct state', async () => { - const { aWETH, weth, pool, wethGateway } = testEnv; - - const WETHAddress = await wethGateway.getWETHAddress(); - const aWETHAddress = await wethGateway.getAWETHAddress(); - const poolAddress = await wethGateway.getLendingPoolAddress(); - - expect(WETHAddress).to.be.equal(weth.address); - expect(aWETHAddress).to.be.equal(aWETH.address); - expect(poolAddress).to.be.equal(pool.address); - }); - - it('Owner can do emergency token recovery', async () => { - const { users, dai, wethGateway, deployer } = testEnv; - const user = users[0]; - const amount = parseEther('1'); - - await dai.connect(user.signer).mint(amount); - const daiBalanceAfterMint = await dai.balanceOf(user.address); - - await dai.connect(user.signer).transfer(wethGateway.address, amount); - const daiBalanceAfterBadTransfer = await dai.balanceOf(user.address); - expect(daiBalanceAfterBadTransfer).to.be.eq( - daiBalanceAfterMint.sub(amount), - 'User should have lost the funds here.' - ); - - await wethGateway - .connect(deployer.signer) - .emergencyTokenTransfer(dai.address, user.address, amount); - const daiBalanceAfterRecovery = await dai.balanceOf(user.address); - - expect(daiBalanceAfterRecovery).to.be.eq( - daiBalanceAfterMint, - 'User should recover the funds due emergency token transfer' - ); - }); - - it('Owner can do emergency native ETH recovery', async () => { - const { users, wethGateway, deployer } = testEnv; - const user = users[0]; - const amount = parseEther('1'); - const userBalancePriorCall = await user.signer.getBalance(); - - // Deploy contract with payable selfdestruct contract - const selfdestructContract = await deploySelfdestructTransferMock(); - - // Selfdestruct the mock, pointing to WETHGateway address - const callTx = await selfdestructContract - .connect(user.signer) - .destroyAndTransfer(wethGateway.address, { value: amount }); - const { gasUsed } = await waitForTx(callTx); - const gasFees = gasUsed.mul(callTx.gasPrice); - const userBalanceAfterCall = await user.signer.getBalance(); - - expect(userBalanceAfterCall).to.be.eq(userBalancePriorCall.sub(amount).sub(gasFees), ''); - ('User should have lost the funds'); - - // Recover the funds from the contract and sends back to the user - await wethGateway.connect(deployer.signer).emergencyEtherTransfer(user.address, amount); - - const userBalanceAfterRecovery = await user.signer.getBalance(); - const wethGatewayAfterRecovery = await DRE.ethers.provider.getBalance(wethGateway.address); - - expect(userBalanceAfterRecovery).to.be.eq( - userBalancePriorCall.sub(gasFees), - 'User should recover the funds due emergency eth transfer.' - ); - expect(wethGatewayAfterRecovery).to.be.eq('0', 'WETHGateway ether balance should be zero.'); - }); -});