aave-protocol-v2/test/__setup.spec.ts

529 lines
17 KiB
TypeScript
Raw Normal View History

2020-07-13 08:54:08 +00:00
import rawBRE from '@nomiclabs/buidler';
import {MockContract} from 'ethereum-waffle';
import {
deployLendingPoolAddressesProvider,
deployMintableErc20,
deployLendingPoolAddressesProviderRegistry,
deployLendingPoolConfigurator,
deployLendingPool,
deployPriceOracle,
getLendingPoolConfiguratorProxy,
deployMockAggregator,
deployChainlinkProxyPriceProvider,
deployLendingRateOracle,
deployDefaultReserveInterestRateStrategy,
deployLendingPoolCollateralManager,
deployMockFlashLoanReceiver,
deployWalletBalancerProvider,
getLendingPool,
insertContractAddressInDb,
2020-06-08 15:36:40 +00:00
deployAaveProtocolTestHelpers,
getEthersSigners,
registerContractInJsonDb,
2020-06-30 12:09:28 +00:00
deployStableDebtToken,
deployVariableDebtToken,
2020-08-19 12:23:41 +00:00
deployGenericAToken,
deployMockSwapAdapter,
2020-07-13 08:54:08 +00:00
} from '../helpers/contracts-helpers';
import {LendingPoolAddressesProvider} from '../types/LendingPoolAddressesProvider';
import {ContractTransaction, Signer} from 'ethers';
import {
TokenContractId,
eContractid,
iAssetBase,
tEthereumAddress,
iAssetAggregatorBase,
IMarketRates,
iMultiPoolsAssets,
AavePools,
IReserveParams,
2020-07-13 08:54:08 +00:00
} from '../helpers/types';
import {MintableErc20} from '../types/MintableErc20';
import {
MOCK_USD_PRICE_IN_WEI,
ALL_ASSETS_INITIAL_PRICES,
USD_ADDRESS,
MOCK_CHAINLINK_AGGREGATORS_PRICES,
LENDING_RATE_ORACLE_RATES_COMMON,
getReservesConfigByPool,
getFeeDistributionParamsCommon,
ZERO_ADDRESS,
2020-07-13 08:54:08 +00:00
} from '../helpers/constants';
import {PriceOracle} from '../types/PriceOracle';
import {MockAggregator} from '../types/MockAggregator';
import {LendingRateOracle} from '../types/LendingRateOracle';
import {LendingPool} from '../types/LendingPool';
import {LendingPoolConfigurator} from '../types/LendingPoolConfigurator';
import {initializeMakeSuite} from './helpers/make-suite';
2020-08-19 14:10:08 +00:00
import path from 'path';
import fs from 'fs';
['misc'].forEach((folder) => {
const tasksPath = path.join(__dirname, '../', 'tasks', folder);
2020-08-19 14:10:08 +00:00
fs.readdirSync(tasksPath).forEach((task) => require(`${tasksPath}/${task}`));
});
const deployAllMockTokens = async (deployer: Signer) => {
const tokens: {[symbol: string]: MockContract | MintableErc20} = {};
2020-06-26 19:28:18 +00:00
const protoConfigData = getReservesConfigByPool(AavePools.proto);
const secondaryConfigData = getReservesConfigByPool(AavePools.secondary);
for (const tokenSymbol of Object.keys(TokenContractId)) {
2020-08-19 12:23:41 +00:00
let decimals = 18;
2020-07-03 09:15:30 +00:00
2020-08-19 12:23:41 +00:00
let configData = (<any>protoConfigData)[tokenSymbol];
2020-07-03 09:15:30 +00:00
2020-08-19 12:23:41 +00:00
if (!configData) {
configData = (<any>secondaryConfigData)[tokenSymbol];
}
2020-06-26 19:28:18 +00:00
2020-08-19 12:23:41 +00:00
if (!configData) {
decimals = 18;
}
2020-07-03 09:15:30 +00:00
2020-08-19 12:23:41 +00:00
tokens[tokenSymbol] = await deployMintableErc20([
tokenSymbol,
tokenSymbol,
configData ? configData.reserveDecimals : 18,
]);
await registerContractInJsonDb(tokenSymbol.toUpperCase(), tokens[tokenSymbol]);
}
return tokens;
};
const setInitialAssetPricesInOracle = async (
prices: iAssetBase<tEthereumAddress>,
assetsAddresses: iAssetBase<tEthereumAddress>,
priceOracleInstance: PriceOracle
) => {
2020-07-13 08:54:08 +00:00
for (const [assetSymbol, price] of Object.entries(prices) as [string, string][]) {
const assetAddressIndex = Object.keys(assetsAddresses).findIndex(
(value) => value === assetSymbol
);
2020-07-13 08:54:08 +00:00
const [, assetAddress] = (Object.entries(assetsAddresses) as [string, string][])[
assetAddressIndex
];
await waitForTx(await priceOracleInstance.setAssetPrice(assetAddress, price));
}
};
2020-07-13 08:54:08 +00:00
const deployAllMockAggregators = async (initialPrices: iAssetAggregatorBase<string>) => {
const aggregators: {[tokenSymbol: string]: MockAggregator} = {};
for (const tokenContractName of Object.keys(initialPrices)) {
2020-07-13 08:54:08 +00:00
if (tokenContractName !== 'ETH') {
const priceIndex = Object.keys(initialPrices).findIndex(
(value) => value === tokenContractName
);
2020-07-13 08:54:08 +00:00
const [, price] = (Object.entries(initialPrices) as [string, string][])[priceIndex];
aggregators[tokenContractName] = await deployMockAggregator(price);
}
}
return aggregators;
};
const getPairsTokenAggregator = (
allAssetsAddresses: {
[tokenSymbol: string]: tEthereumAddress;
},
aggregatorsAddresses: {[tokenSymbol: string]: tEthereumAddress}
): [string[], string[]] => {
const {ETH, ...assetsAddressesWithoutEth} = allAssetsAddresses;
2020-07-13 08:54:08 +00:00
const pairs = Object.entries(assetsAddressesWithoutEth).map(([tokenSymbol, tokenAddress]) => {
if (tokenSymbol !== 'ETH') {
const aggregatorAddressIndex = Object.keys(aggregatorsAddresses).findIndex(
(value) => value === tokenSymbol
);
const [, aggregatorAddress] = (Object.entries(aggregatorsAddresses) as [
string,
tEthereumAddress
][])[aggregatorAddressIndex];
return [tokenAddress, aggregatorAddress];
}
2020-07-13 08:54:08 +00:00
});
const mappedPairs = pairs.map(([asset]) => asset);
const mappedAggregators = pairs.map(([, source]) => source);
return [mappedPairs, mappedAggregators];
};
const setInitialMarketRatesInRatesOracle = async (
marketRates: iMultiPoolsAssets<IMarketRates>,
assetsAddresses: {[x: string]: tEthereumAddress},
lendingRateOracleInstance: LendingRateOracle
) => {
for (const [assetSymbol, {borrowRate}] of Object.entries(marketRates) as [
string,
IMarketRates
][]) {
const assetAddressIndex = Object.keys(assetsAddresses).findIndex(
(value) => value === assetSymbol
);
2020-07-13 08:54:08 +00:00
const [, assetAddress] = (Object.entries(assetsAddresses) as [string, string][])[
assetAddressIndex
];
await lendingRateOracleInstance.setMarketBorrowRate(assetAddress, borrowRate);
}
};
const initReserves = async (
reservesParams: iMultiPoolsAssets<IReserveParams>,
tokenAddresses: {[symbol: string]: tEthereumAddress},
lendingPoolAddressesProvider: LendingPoolAddressesProvider,
2020-06-20 23:40:03 +00:00
lendingPool: LendingPool,
lendingPoolConfigurator: LendingPoolConfigurator,
aavePool: AavePools
) => {
if (aavePool !== AavePools.proto && aavePool !== AavePools.secondary) {
console.log(`Invalid Aave pool ${aavePool}`);
process.exit(1);
}
2020-07-13 08:54:08 +00:00
for (let [assetSymbol, {reserveDecimals}] of Object.entries(reservesParams) as [
string,
IReserveParams
][]) {
const assetAddressIndex = Object.keys(tokenAddresses).findIndex(
(value) => value === assetSymbol
);
2020-07-13 08:54:08 +00:00
const [, tokenAddress] = (Object.entries(tokenAddresses) as [string, string][])[
assetAddressIndex
];
2020-07-03 09:15:30 +00:00
2020-06-26 12:34:44 +00:00
const {isActive: reserveInitialized} = await lendingPool.getReserveConfigurationData(
tokenAddress
);
if (reserveInitialized) {
2020-07-13 08:54:08 +00:00
console.log(`Reserve ${assetSymbol} is already active, skipping configuration`);
continue;
}
try {
const reserveParamIndex = Object.keys(reservesParams).findIndex(
(value) => value === assetSymbol
);
const [
,
{
baseVariableBorrowRate,
variableRateSlope1,
variableRateSlope2,
stableRateSlope1,
stableRateSlope2,
},
2020-07-13 08:54:08 +00:00
] = (Object.entries(reservesParams) as [string, IReserveParams][])[reserveParamIndex];
const rateStrategyContract = await deployDefaultReserveInterestRateStrategy([
lendingPoolAddressesProvider.address,
baseVariableBorrowRate,
variableRateSlope1,
variableRateSlope2,
stableRateSlope1,
stableRateSlope2,
]);
2020-06-30 12:09:28 +00:00
const stableDebtToken = await deployStableDebtToken([
2020-08-19 12:23:41 +00:00
`Aave stable debt bearing ${assetSymbol === 'WETH' ? 'ETH' : assetSymbol}`,
`stableDebt${assetSymbol === 'WETH' ? 'ETH' : assetSymbol}`,
2020-06-30 12:09:28 +00:00
tokenAddress,
2020-08-11 07:36:46 +00:00
lendingPool.address,
2020-07-13 08:54:08 +00:00
]);
2020-06-30 12:09:28 +00:00
const variableDebtToken = await deployVariableDebtToken([
2020-08-19 12:23:41 +00:00
`Aave variable debt bearing ${assetSymbol === 'WETH' ? 'ETH' : assetSymbol}`,
`variableDebt${assetSymbol === 'WETH' ? 'ETH' : assetSymbol}`,
2020-06-30 12:09:28 +00:00
tokenAddress,
2020-08-11 07:36:46 +00:00
lendingPool.address,
2020-07-13 08:54:08 +00:00
]);
2020-07-03 09:15:30 +00:00
2020-08-07 17:29:13 +00:00
const aToken = await deployGenericAToken([
lendingPool.address,
tokenAddress,
2020-08-19 12:23:41 +00:00
`Aave interest bearing ${assetSymbol === 'WETH' ? 'ETH' : assetSymbol}`,
`a${assetSymbol === 'WETH' ? 'ETH' : assetSymbol}`,
]);
2020-08-07 17:29:13 +00:00
if (process.env.POOL === AavePools.secondary) {
2020-07-13 08:54:08 +00:00
if (assetSymbol.search('UNI') === -1) {
assetSymbol = `Uni${assetSymbol}`;
} else {
2020-07-13 08:54:08 +00:00
assetSymbol = assetSymbol.replace(/_/g, '').replace('UNI', 'Uni');
}
}
await lendingPoolConfigurator.initReserve(
tokenAddress,
2020-08-07 17:29:13 +00:00
aToken.address,
2020-06-30 12:09:28 +00:00
stableDebtToken.address,
variableDebtToken.address,
reserveDecimals,
rateStrategyContract.address
);
} catch (e) {
2020-07-13 08:54:08 +00:00
console.log(`Reserve initialization for ${assetSymbol} failed with error ${e}. Skipped.`);
}
}
};
const enableReservesToBorrow = async (
reservesParams: iMultiPoolsAssets<IReserveParams>,
tokenAddresses: {[symbol: string]: tEthereumAddress},
2020-06-20 23:40:03 +00:00
lendingPool: LendingPool,
lendingPoolConfigurator: LendingPoolConfigurator
) => {
2020-07-13 08:54:08 +00:00
for (const [assetSymbol, {borrowingEnabled, stableBorrowRateEnabled}] of Object.entries(
reservesParams
) as [string, IReserveParams][]) {
if (!borrowingEnabled) continue;
try {
const assetAddressIndex = Object.keys(tokenAddresses).findIndex(
(value) => value === assetSymbol
);
2020-07-13 08:54:08 +00:00
const [, tokenAddress] = (Object.entries(tokenAddresses) as [string, string][])[
assetAddressIndex
];
const {
borrowingEnabled: borrowingAlreadyEnabled,
} = await lendingPool.getReserveConfigurationData(tokenAddress);
if (borrowingAlreadyEnabled) {
2020-07-13 08:54:08 +00:00
console.log(`Reserve ${assetSymbol} is already enabled for borrowing, skipping`);
continue;
}
2020-07-13 08:54:08 +00:00
await lendingPoolConfigurator.enableBorrowingOnReserve(tokenAddress, stableBorrowRateEnabled);
} catch (e) {
console.log(
`Enabling reserve for borrowings for ${assetSymbol} failed with error ${e}. Skipped.`
);
}
}
};
const enableReservesAsCollateral = async (
reservesParams: iMultiPoolsAssets<IReserveParams>,
tokenAddresses: {[symbol: string]: tEthereumAddress},
2020-06-20 23:40:03 +00:00
lendingPool: LendingPool,
lendingPoolConfigurator: LendingPoolConfigurator
) => {
for (const [
assetSymbol,
{baseLTVAsCollateral, liquidationBonus, liquidationThreshold},
] of Object.entries(reservesParams) as [string, IReserveParams][]) {
2020-07-13 08:54:08 +00:00
if (baseLTVAsCollateral === '-1') continue;
const assetAddressIndex = Object.keys(tokenAddresses).findIndex(
(value) => value === assetSymbol
);
2020-07-13 08:54:08 +00:00
const [, tokenAddress] = (Object.entries(tokenAddresses) as [string, string][])[
assetAddressIndex
];
const {
usageAsCollateralEnabled: alreadyEnabled,
} = await lendingPool.getReserveConfigurationData(tokenAddress);
if (alreadyEnabled) {
2020-07-13 08:54:08 +00:00
console.log(`Reserve ${assetSymbol} is already enabled as collateral, skipping`);
continue;
}
try {
await lendingPoolConfigurator.enableReserveAsCollateral(
tokenAddress,
baseLTVAsCollateral,
liquidationThreshold,
liquidationBonus
);
} catch (e) {
console.log(
`Enabling reserve as collateral for ${assetSymbol} failed with error ${e}. Skipped.`
);
}
}
};
export const waitForTx = async (tx: ContractTransaction) => await tx.wait();
const buildTestEnv = async (deployer: Signer, secondaryWallet: Signer) => {
2020-07-13 08:54:08 +00:00
console.time('setup');
2020-09-16 12:09:42 +00:00
const aaveAdmin = await deployer.getAddress();
2020-06-08 15:36:40 +00:00
const mockTokens = await deployAllMockTokens(deployer);
const addressesProvider = await deployLendingPoolAddressesProvider();
2020-09-16 12:09:42 +00:00
await waitForTx(await addressesProvider.setAaveAdmin(aaveAdmin));
const addressesProviderRegistry = await deployLendingPoolAddressesProviderRegistry();
await waitForTx(
2020-07-13 08:54:08 +00:00
await addressesProviderRegistry.registerAddressesProvider(addressesProvider.address, 0)
);
const lendingPoolImpl = await deployLendingPool();
2020-06-20 23:40:03 +00:00
2020-07-13 08:54:08 +00:00
console.log('Deployed lending pool, address:', lendingPoolImpl.address);
await waitForTx(await addressesProvider.setLendingPoolImpl(lendingPoolImpl.address));
2020-06-20 23:40:03 +00:00
2020-07-13 08:54:08 +00:00
console.log('Added pool to addresses provider');
2020-06-20 23:40:03 +00:00
2020-07-13 08:54:08 +00:00
const address = await addressesProvider.getLendingPool();
console.log('Address is ', address);
const lendingPoolProxy = await getLendingPool(address);
2020-06-20 23:40:03 +00:00
2020-07-13 08:54:08 +00:00
console.log('implementation set, address:', lendingPoolProxy.address);
2020-06-20 23:40:03 +00:00
2020-07-13 08:54:08 +00:00
await insertContractAddressInDb(eContractid.LendingPool, lendingPoolProxy.address);
2020-07-23 15:18:06 +00:00
const lendingPoolConfiguratorImpl = await deployLendingPoolConfigurator();
await waitForTx(
await addressesProvider.setLendingPoolConfiguratorImpl(lendingPoolConfiguratorImpl.address)
);
const lendingPoolConfiguratorProxy = await getLendingPoolConfiguratorProxy(
await addressesProvider.getLendingPoolConfigurator()
);
await insertContractAddressInDb(
eContractid.LendingPoolConfigurator,
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,
LEND: mockTokens.LEND.address,
BAT: mockTokens.BAT.address,
REP: mockTokens.REP.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,
USD: USD_ADDRESS,
UNI_DAI_ETH: mockTokens.UNI_DAI_ETH.address,
UNI_USDC_ETH: mockTokens.UNI_USDC_ETH.address,
UNI_SETH_ETH: mockTokens.UNI_SETH_ETH.address,
UNI_LEND_ETH: mockTokens.UNI_LEND_ETH.address,
UNI_MKR_ETH: mockTokens.UNI_MKR_ETH.address,
UNI_LINK_ETH: mockTokens.UNI_LINK_ETH.address,
},
fallbackOracle
);
2020-07-13 08:54:08 +00:00
const mockAggregators = await deployAllMockAggregators(MOCK_CHAINLINK_AGGREGATORS_PRICES);
const allTokenAddresses = Object.entries(mockTokens).reduce(
2020-07-13 08:54:08 +00:00
(accum: {[tokenSymbol: string]: tEthereumAddress}, [tokenSymbol, tokenContract]) => ({
...accum,
[tokenSymbol]: tokenContract.address,
}),
{}
);
const allAggregatorsAddresses = Object.entries(mockAggregators).reduce(
2020-07-13 08:54:08 +00:00
(accum: {[tokenSymbol: string]: tEthereumAddress}, [tokenSymbol, aggregator]) => ({
...accum,
[tokenSymbol]: aggregator.address,
}),
{}
);
2020-07-13 08:54:08 +00:00
const [tokens, aggregators] = getPairsTokenAggregator(allTokenAddresses, allAggregatorsAddresses);
const chainlinkProxyPriceProvider = await deployChainlinkProxyPriceProvider([
tokens,
aggregators,
fallbackOracle.address,
]);
2020-07-13 08:54:08 +00:00
await waitForTx(await addressesProvider.setPriceOracle(fallbackOracle.address));
const lendingRateOracle = await deployLendingRateOracle();
2020-07-13 08:54:08 +00:00
await waitForTx(await addressesProvider.setLendingRateOracle(lendingRateOracle.address));
const {USD, ...tokensAddressesWithoutUsd} = allTokenAddresses;
const allReservesAddresses = {
...tokensAddressesWithoutUsd,
};
await setInitialMarketRatesInRatesOracle(
LENDING_RATE_ORACLE_RATES_COMMON,
allReservesAddresses,
lendingRateOracle
);
const {
UNI_DAI_ETH,
UNI_USDC_ETH,
UNI_SETH_ETH,
UNI_LINK_ETH,
UNI_MKR_ETH,
UNI_LEND_ETH,
...protoPoolReservesAddresses
} = <{[symbol: string]: tEthereumAddress}>allReservesAddresses;
const reservesParams = getReservesConfigByPool(AavePools.proto);
2020-07-13 08:54:08 +00:00
console.log('Initialize configuration');
await initReserves(
reservesParams,
protoPoolReservesAddresses,
addressesProvider,
2020-06-20 23:40:03 +00:00
lendingPoolProxy,
lendingPoolConfiguratorProxy,
AavePools.proto
);
await enableReservesToBorrow(
reservesParams,
protoPoolReservesAddresses,
2020-06-20 23:40:03 +00:00
lendingPoolProxy,
lendingPoolConfiguratorProxy
);
await enableReservesAsCollateral(
reservesParams,
protoPoolReservesAddresses,
2020-06-20 23:40:03 +00:00
lendingPoolProxy,
lendingPoolConfiguratorProxy
);
const collateralManager = await deployLendingPoolCollateralManager();
await waitForTx(
await addressesProvider.setLendingPoolCollateralManager(collateralManager.address)
);
2020-07-13 08:54:08 +00:00
const mockFlashLoanReceiver = await deployMockFlashLoanReceiver(addressesProvider.address);
await insertContractAddressInDb(eContractid.MockFlashLoanReceiver, mockFlashLoanReceiver.address);
2020-09-09 14:35:49 +00:00
const mockSwapAdapter = await deployMockSwapAdapter(addressesProvider.address);
await insertContractAddressInDb(eContractid.MockSwapAdapter, mockSwapAdapter.address);
await deployWalletBalancerProvider(addressesProvider.address);
2020-07-13 08:54:08 +00:00
const testHelpers = await deployAaveProtocolTestHelpers(addressesProvider.address);
2020-06-08 15:36:40 +00:00
2020-07-13 08:54:08 +00:00
await insertContractAddressInDb(eContractid.AaveProtocolTestHelpers, testHelpers.address);
2020-06-08 15:36:40 +00:00
2020-07-13 08:54:08 +00:00
console.timeEnd('setup');
};
before(async () => {
2020-07-13 08:54:08 +00:00
await rawBRE.run('set-bre');
const [deployer, secondaryWallet] = await getEthersSigners();
2020-07-13 08:54:08 +00:00
console.log('-> Deploying test environment...');
await buildTestEnv(deployer, secondaryWallet);
await initializeMakeSuite();
2020-07-13 08:54:08 +00:00
console.log('\n***************');
console.log('Setup and snapshot finished');
console.log('***************\n');
});