2020-12-01 11:39:54 +00:00
|
|
|
import {
|
|
|
|
eContractid,
|
|
|
|
eEthereumNetwork,
|
|
|
|
iMultiPoolsAssets,
|
|
|
|
IReserveParams,
|
|
|
|
tEthereumAddress,
|
|
|
|
} from './types';
|
2020-11-18 18:18:02 +00:00
|
|
|
import { AaveProtocolDataProvider } from '../types/AaveProtocolDataProvider';
|
2020-12-01 11:39:54 +00:00
|
|
|
import { chunk, DRE, getDb, waitForTx } from './misc-utils';
|
2020-10-27 09:58:51 +00:00
|
|
|
import {
|
2020-12-01 11:39:54 +00:00
|
|
|
getAaveProtocolDataProvider,
|
2020-12-01 12:21:46 +00:00
|
|
|
getAToken,
|
2020-10-27 09:58:51 +00:00
|
|
|
getATokensAndRatesHelper,
|
|
|
|
getLendingPoolAddressesProvider,
|
2021-02-01 23:23:11 +00:00
|
|
|
getLendingPoolConfiguratorProxy,
|
2020-10-27 09:58:51 +00:00
|
|
|
getStableAndVariableTokensHelper,
|
|
|
|
} from './contracts-getters';
|
2020-11-18 18:18:02 +00:00
|
|
|
import { rawInsertContractAddressInDb } from './contracts-helpers';
|
2020-12-01 11:39:54 +00:00
|
|
|
import { BigNumber, BigNumberish, Signer } from 'ethers';
|
2020-11-19 16:46:23 +00:00
|
|
|
import {
|
|
|
|
deployDefaultReserveInterestRateStrategy,
|
|
|
|
deployDelegationAwareAToken,
|
2020-11-20 11:11:57 +00:00
|
|
|
deployGenericAToken,
|
2020-11-19 16:46:23 +00:00
|
|
|
deployStableDebtToken,
|
|
|
|
deployVariableDebtToken,
|
|
|
|
} from './contracts-deployments';
|
|
|
|
import { ZERO_ADDRESS } from './constants';
|
2020-12-01 11:39:54 +00:00
|
|
|
import { isZeroAddress } from 'ethereumjs-util';
|
2020-10-15 17:19:02 +00:00
|
|
|
|
2020-12-21 16:13:51 +00:00
|
|
|
export const chooseATokenDeployment = (id: eContractid) => {
|
2020-11-20 11:11:57 +00:00
|
|
|
switch (id) {
|
|
|
|
case eContractid.AToken:
|
|
|
|
return deployGenericAToken;
|
|
|
|
case eContractid.DelegationAwareAToken:
|
|
|
|
return deployDelegationAwareAToken;
|
|
|
|
default:
|
|
|
|
throw Error(`Missing aToken deployment script for: ${id}`);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-10-23 13:18:01 +00:00
|
|
|
export const initReservesByHelper = async (
|
|
|
|
reservesParams: iMultiPoolsAssets<IReserveParams>,
|
2020-11-18 18:18:02 +00:00
|
|
|
tokenAddresses: { [symbol: string]: tEthereumAddress },
|
2020-10-23 16:38:27 +00:00
|
|
|
admin: tEthereumAddress,
|
2020-11-27 15:40:00 +00:00
|
|
|
treasuryAddress: tEthereumAddress,
|
2020-11-19 16:46:23 +00:00
|
|
|
incentivesController: tEthereumAddress,
|
|
|
|
verify: boolean
|
2020-11-30 18:25:06 +00:00
|
|
|
): Promise<BigNumber> => {
|
|
|
|
let gasUsage = BigNumber.from('0');
|
2020-10-27 09:58:51 +00:00
|
|
|
const stableAndVariableDeployer = await getStableAndVariableTokensHelper();
|
|
|
|
const atokenAndRatesDeployer = await getATokensAndRatesHelper();
|
|
|
|
|
|
|
|
const addressProvider = await getLendingPoolAddressesProvider();
|
2020-11-19 16:46:23 +00:00
|
|
|
const poolAddress = await addressProvider.getLendingPool();
|
2020-10-23 13:18:01 +00:00
|
|
|
|
2020-10-23 16:38:27 +00:00
|
|
|
// Set aTokenAndRatesDeployer as temporal admin
|
2020-11-05 11:35:50 +00:00
|
|
|
await waitForTx(await addressProvider.setPoolAdmin(atokenAndRatesDeployer.address));
|
2020-10-23 13:18:01 +00:00
|
|
|
|
2020-10-23 16:38:27 +00:00
|
|
|
// CHUNK CONFIGURATION
|
2020-11-30 18:25:06 +00:00
|
|
|
const tokensChunks = 2;
|
|
|
|
const initChunks = 4;
|
2020-10-23 13:18:01 +00:00
|
|
|
|
2020-11-20 11:11:57 +00:00
|
|
|
// Deploy tokens and rates that uses common aToken in chunks
|
2020-10-23 16:38:27 +00:00
|
|
|
const reservesChunks = chunk(
|
2020-11-20 11:11:57 +00:00
|
|
|
Object.entries(reservesParams).filter(
|
|
|
|
([_, { aTokenImpl }]) => aTokenImpl === eContractid.AToken
|
|
|
|
) as [string, IReserveParams][],
|
2020-10-23 16:38:27 +00:00
|
|
|
tokensChunks
|
|
|
|
);
|
|
|
|
// Initialize variables for future reserves initialization
|
|
|
|
let deployedStableTokens: string[] = [];
|
|
|
|
let deployedVariableTokens: string[] = [];
|
|
|
|
let deployedATokens: string[] = [];
|
|
|
|
let deployedRates: string[] = [];
|
|
|
|
let reserveTokens: string[] = [];
|
|
|
|
let reserveInitDecimals: string[] = [];
|
2020-11-19 16:46:23 +00:00
|
|
|
let reserveSymbols: string[] = [];
|
2020-10-23 16:38:27 +00:00
|
|
|
|
2021-02-01 23:23:11 +00:00
|
|
|
let initInputParams: {
|
|
|
|
aTokenImpl: string,
|
|
|
|
stableDebtTokenImpl: string,
|
|
|
|
variableDebtTokenImpl: string,
|
|
|
|
underlyingAssetDecimals: BigNumberish,
|
|
|
|
interestRateStrategyAddress: string,
|
|
|
|
underlyingAsset: string,
|
|
|
|
treasury: string,
|
|
|
|
incentivesController: string,
|
|
|
|
underlyingAssetName: string,
|
|
|
|
aTokenName: string,
|
|
|
|
aTokenSymbol: string,
|
|
|
|
variableDebtTokenName: string,
|
|
|
|
variableDebtTokenSymbol: string,
|
|
|
|
stableDebtTokenName: string,
|
|
|
|
stableDebtTokenSymbol: string,
|
|
|
|
}[] = [];
|
|
|
|
|
2020-10-23 16:38:27 +00:00
|
|
|
console.log(
|
|
|
|
`- Token deployments in ${reservesChunks.length * 2} txs instead of ${
|
|
|
|
Object.entries(reservesParams).length * 4
|
|
|
|
} txs`
|
|
|
|
);
|
2021-02-01 23:23:11 +00:00
|
|
|
|
2020-10-23 16:38:27 +00:00
|
|
|
for (let reservesChunk of reservesChunks) {
|
|
|
|
// Prepare data
|
|
|
|
const tokens: string[] = [];
|
|
|
|
const symbols: string[] = [];
|
2020-11-18 18:18:02 +00:00
|
|
|
const strategyRates: [
|
|
|
|
BigNumberish,
|
|
|
|
BigNumberish,
|
|
|
|
BigNumberish,
|
|
|
|
BigNumberish,
|
2020-11-19 17:11:53 +00:00
|
|
|
BigNumberish,
|
2020-11-18 18:18:02 +00:00
|
|
|
BigNumberish
|
|
|
|
][] = [];
|
2020-10-23 16:38:27 +00:00
|
|
|
const reservesDecimals: string[] = [];
|
2021-02-06 02:51:12 +00:00
|
|
|
|
2021-01-30 03:52:12 +00:00
|
|
|
const inputParams: {
|
|
|
|
asset: string,
|
|
|
|
rates: [
|
|
|
|
BigNumberish,
|
|
|
|
BigNumberish,
|
|
|
|
BigNumberish,
|
|
|
|
BigNumberish,
|
|
|
|
BigNumberish,
|
|
|
|
BigNumberish
|
|
|
|
]
|
|
|
|
}[] = [];
|
2021-02-06 02:51:12 +00:00
|
|
|
|
2020-11-18 18:18:02 +00:00
|
|
|
for (let [assetSymbol, { reserveDecimals }] of reservesChunk) {
|
2020-10-23 16:38:27 +00:00
|
|
|
const assetAddressIndex = Object.keys(tokenAddresses).findIndex(
|
|
|
|
(value) => value === assetSymbol
|
|
|
|
);
|
|
|
|
const [, tokenAddress] = (Object.entries(tokenAddresses) as [string, string][])[
|
|
|
|
assetAddressIndex
|
|
|
|
];
|
|
|
|
|
|
|
|
const reserveParamIndex = Object.keys(reservesParams).findIndex(
|
|
|
|
(value) => value === assetSymbol
|
|
|
|
);
|
|
|
|
const [
|
|
|
|
,
|
|
|
|
{
|
2020-11-19 17:11:53 +00:00
|
|
|
optimalUtilizationRate,
|
2020-10-23 16:38:27 +00:00
|
|
|
baseVariableBorrowRate,
|
|
|
|
variableRateSlope1,
|
|
|
|
variableRateSlope2,
|
|
|
|
stableRateSlope1,
|
|
|
|
stableRateSlope2,
|
|
|
|
},
|
|
|
|
] = (Object.entries(reservesParams) as [string, IReserveParams][])[reserveParamIndex];
|
|
|
|
// Add to lists
|
|
|
|
tokens.push(tokenAddress);
|
2020-10-28 10:27:16 +00:00
|
|
|
symbols.push(assetSymbol);
|
2020-10-23 16:38:27 +00:00
|
|
|
strategyRates.push([
|
2020-11-19 17:11:53 +00:00
|
|
|
optimalUtilizationRate,
|
2020-10-23 13:18:01 +00:00
|
|
|
baseVariableBorrowRate,
|
|
|
|
variableRateSlope1,
|
|
|
|
variableRateSlope2,
|
|
|
|
stableRateSlope1,
|
|
|
|
stableRateSlope2,
|
2020-10-23 16:38:27 +00:00
|
|
|
]);
|
|
|
|
reservesDecimals.push(reserveDecimals);
|
2021-01-30 03:52:12 +00:00
|
|
|
|
|
|
|
inputParams.push({
|
|
|
|
asset: tokenAddress,
|
|
|
|
rates: [
|
|
|
|
optimalUtilizationRate,
|
|
|
|
baseVariableBorrowRate,
|
|
|
|
variableRateSlope1,
|
|
|
|
variableRateSlope2,
|
|
|
|
stableRateSlope1,
|
|
|
|
stableRateSlope2
|
|
|
|
]
|
|
|
|
});
|
2020-10-23 16:38:27 +00:00
|
|
|
}
|
|
|
|
|
2020-11-10 13:18:48 +00:00
|
|
|
// Deploy stable and variable deployers and save implementations
|
2020-10-23 13:18:01 +00:00
|
|
|
const tx1 = await waitForTx(
|
2021-01-30 03:52:12 +00:00
|
|
|
await stableAndVariableDeployer.initDeployment(tokens, symbols)
|
2020-10-23 13:18:01 +00:00
|
|
|
);
|
2020-11-10 13:18:48 +00:00
|
|
|
tx1.events?.forEach((event, index) => {
|
|
|
|
rawInsertContractAddressInDb(`stableDebt${symbols[index]}`, event?.args?.stableToken);
|
|
|
|
rawInsertContractAddressInDb(`variableDebt${symbols[index]}`, event?.args?.variableToken);
|
|
|
|
});
|
2020-11-30 18:25:06 +00:00
|
|
|
|
2020-11-10 13:18:48 +00:00
|
|
|
// Deploy atokens and rate strategies and save implementations
|
2020-10-23 13:18:01 +00:00
|
|
|
const tx2 = await waitForTx(
|
2021-01-30 03:52:12 +00:00
|
|
|
await atokenAndRatesDeployer.initDeployment(inputParams)
|
2020-10-23 13:18:01 +00:00
|
|
|
);
|
2020-11-10 13:18:48 +00:00
|
|
|
tx2.events?.forEach((event, index) => {
|
|
|
|
rawInsertContractAddressInDb(`a${symbols[index]}`, event?.args?.aToken);
|
|
|
|
rawInsertContractAddressInDb(`strategy${symbols[index]}`, event?.args?.strategy);
|
|
|
|
});
|
|
|
|
|
2020-10-23 16:38:27 +00:00
|
|
|
console.log(` - Deployed aToken, DebtTokens and Strategy for: ${symbols.join(', ')} `);
|
2020-11-30 18:25:06 +00:00
|
|
|
console.log(' * gasUsed: debtTokens batch', tx1.gasUsed.toString());
|
|
|
|
console.log(' * gasUsed: aTokens and Strategy batch', tx2.gasUsed.toString());
|
|
|
|
gasUsage = gasUsage.add(tx1.gasUsed).add(tx2.gasUsed);
|
2021-02-01 23:23:11 +00:00
|
|
|
|
2020-10-23 16:38:27 +00:00
|
|
|
const stableTokens: string[] = tx1.events?.map((e) => e.args?.stableToken) || [];
|
|
|
|
const variableTokens: string[] = tx1.events?.map((e) => e.args?.variableToken) || [];
|
2020-10-23 13:18:01 +00:00
|
|
|
const aTokens: string[] = tx2.events?.map((e) => e.args?.aToken) || [];
|
|
|
|
const strategies: string[] = tx2.events?.map((e) => e.args?.strategy) || [];
|
2020-10-23 16:38:27 +00:00
|
|
|
|
|
|
|
deployedStableTokens = [...deployedStableTokens, ...stableTokens];
|
|
|
|
deployedVariableTokens = [...deployedVariableTokens, ...variableTokens];
|
|
|
|
deployedATokens = [...deployedATokens, ...aTokens];
|
|
|
|
deployedRates = [...deployedRates, ...strategies];
|
|
|
|
reserveInitDecimals = [...reserveInitDecimals, ...reservesDecimals];
|
|
|
|
reserveTokens = [...reserveTokens, ...tokens];
|
2020-11-19 16:46:23 +00:00
|
|
|
reserveSymbols = [...reserveSymbols, ...symbols];
|
|
|
|
}
|
|
|
|
|
2020-11-20 11:11:57 +00:00
|
|
|
// Deploy delegated aware reserves tokens
|
|
|
|
const delegatedAwareReserves = Object.entries(reservesParams).filter(
|
|
|
|
([_, { aTokenImpl }]) => aTokenImpl === eContractid.DelegationAwareAToken
|
|
|
|
) as [string, IReserveParams][];
|
|
|
|
|
|
|
|
for (let [symbol, params] of delegatedAwareReserves) {
|
2020-11-27 17:18:31 +00:00
|
|
|
console.log(` - Deploy ${symbol} delegation aware aToken, debts tokens, and strategy`);
|
2020-11-19 16:46:23 +00:00
|
|
|
const {
|
2020-11-20 11:11:57 +00:00
|
|
|
optimalUtilizationRate,
|
2020-11-19 16:46:23 +00:00
|
|
|
baseVariableBorrowRate,
|
|
|
|
variableRateSlope1,
|
|
|
|
variableRateSlope2,
|
|
|
|
stableRateSlope1,
|
|
|
|
stableRateSlope2,
|
2020-11-20 11:11:57 +00:00
|
|
|
} = params;
|
|
|
|
const deployCustomAToken = chooseATokenDeployment(params.aTokenImpl);
|
|
|
|
const aToken = await deployCustomAToken(
|
|
|
|
[
|
|
|
|
poolAddress,
|
|
|
|
tokenAddresses[symbol],
|
2020-11-27 17:18:31 +00:00
|
|
|
treasuryAddress,
|
2021-02-02 22:44:46 +00:00
|
|
|
ZERO_ADDRESS,
|
2020-11-20 11:11:57 +00:00
|
|
|
`Aave interest bearing ${symbol}`,
|
|
|
|
`a${symbol}`,
|
|
|
|
],
|
2020-11-19 16:46:23 +00:00
|
|
|
verify
|
|
|
|
);
|
2020-11-20 11:11:57 +00:00
|
|
|
const stableDebt = await deployStableDebtToken(
|
2020-11-19 16:46:23 +00:00
|
|
|
[
|
|
|
|
poolAddress,
|
2020-11-20 11:11:57 +00:00
|
|
|
tokenAddresses[symbol],
|
2021-02-02 22:44:46 +00:00
|
|
|
ZERO_ADDRESS, // Incentives controller
|
2020-11-20 11:11:57 +00:00
|
|
|
`Aave stable debt bearing ${symbol}`,
|
2021-02-02 22:44:46 +00:00
|
|
|
`stableDebt${symbol}`
|
2020-11-19 16:46:23 +00:00
|
|
|
],
|
|
|
|
verify
|
|
|
|
);
|
2020-11-20 11:11:57 +00:00
|
|
|
const variableDebt = await deployVariableDebtToken(
|
2020-11-19 16:46:23 +00:00
|
|
|
[
|
|
|
|
poolAddress,
|
2020-11-20 11:11:57 +00:00
|
|
|
tokenAddresses[symbol],
|
2021-02-02 22:44:46 +00:00
|
|
|
ZERO_ADDRESS, // Incentives controller
|
2020-11-20 11:11:57 +00:00
|
|
|
`Aave variable debt bearing ${symbol}`,
|
|
|
|
`variableDebt${symbol}`,
|
2020-11-19 16:46:23 +00:00
|
|
|
],
|
|
|
|
verify
|
|
|
|
);
|
2020-11-20 11:11:57 +00:00
|
|
|
const rates = await deployDefaultReserveInterestRateStrategy(
|
2020-11-19 16:46:23 +00:00
|
|
|
[
|
2020-11-20 11:11:57 +00:00
|
|
|
tokenAddresses[symbol],
|
|
|
|
optimalUtilizationRate,
|
2020-11-19 16:46:23 +00:00
|
|
|
baseVariableBorrowRate,
|
|
|
|
variableRateSlope1,
|
|
|
|
variableRateSlope2,
|
|
|
|
stableRateSlope1,
|
|
|
|
stableRateSlope2,
|
|
|
|
],
|
|
|
|
verify
|
|
|
|
);
|
|
|
|
|
2020-11-20 11:11:57 +00:00
|
|
|
deployedStableTokens.push(stableDebt.address);
|
|
|
|
deployedVariableTokens.push(variableDebt.address);
|
|
|
|
deployedATokens.push(aToken.address);
|
|
|
|
deployedRates.push(rates.address);
|
|
|
|
reserveInitDecimals.push(params.reserveDecimals);
|
|
|
|
reserveTokens.push(tokenAddresses[symbol]);
|
|
|
|
reserveSymbols.push(symbol);
|
2020-10-23 16:38:27 +00:00
|
|
|
}
|
|
|
|
|
2021-02-06 02:51:12 +00:00
|
|
|
for (let i = 0; i < deployedATokens.length; i ++) {
|
|
|
|
initInputParams.push({
|
|
|
|
aTokenImpl: deployedATokens[i],
|
|
|
|
stableDebtTokenImpl: deployedStableTokens[i],
|
|
|
|
variableDebtTokenImpl: deployedVariableTokens[i],
|
|
|
|
underlyingAssetDecimals: reserveInitDecimals[i],
|
|
|
|
interestRateStrategyAddress: deployedRates[i],
|
|
|
|
underlyingAsset: reserveTokens[i],
|
|
|
|
treasury: treasuryAddress,
|
|
|
|
incentivesController: ZERO_ADDRESS,
|
|
|
|
underlyingAssetName: reserveSymbols[i],
|
|
|
|
aTokenName: `Aave interest bearing ${reserveSymbols[i]}`,
|
|
|
|
aTokenSymbol: `a${reserveSymbols[i]}`,
|
|
|
|
variableDebtTokenName: `Aave variable debt bearing ${reserveSymbols[i]}`,
|
|
|
|
variableDebtTokenSymbol: `variableDebt${reserveSymbols[i]}`,
|
|
|
|
stableDebtTokenName: `Aave stable debt bearing ${reserveSymbols[i]}`,
|
|
|
|
stableDebtTokenSymbol: `stableDebt${reserveSymbols[i]}`
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2020-10-23 16:38:27 +00:00
|
|
|
// Deploy init reserves per chunks
|
2020-11-19 16:46:23 +00:00
|
|
|
const chunkedSymbols = chunk(reserveSymbols, initChunks);
|
2021-02-06 02:51:12 +00:00
|
|
|
const chunkedInitInputParams = chunk(initInputParams, initChunks);
|
2020-10-23 16:38:27 +00:00
|
|
|
|
2021-02-01 23:23:11 +00:00
|
|
|
const configurator = await getLendingPoolConfiguratorProxy();
|
|
|
|
await waitForTx(await addressProvider.setPoolAdmin(admin));
|
|
|
|
|
2021-02-06 02:51:12 +00:00
|
|
|
console.log(`- Reserves initialization in ${chunkedInitInputParams.length} txs`);
|
|
|
|
for (let chunkIndex = 0; chunkIndex < chunkedInitInputParams.length; chunkIndex++) {
|
2020-10-23 13:18:01 +00:00
|
|
|
const tx3 = await waitForTx(
|
2021-02-01 23:23:11 +00:00
|
|
|
await configurator.batchInitReserve(chunkedInitInputParams[chunkIndex])
|
2020-10-23 13:18:01 +00:00
|
|
|
);
|
2020-11-30 18:25:06 +00:00
|
|
|
|
2020-10-23 16:38:27 +00:00
|
|
|
console.log(` - Reserve ready for: ${chunkedSymbols[chunkIndex].join(', ')}`);
|
2020-11-30 18:25:06 +00:00
|
|
|
console.log(' * gasUsed', tx3.gasUsed.toString());
|
|
|
|
gasUsage = gasUsage.add(tx3.gasUsed);
|
2020-10-23 13:18:01 +00:00
|
|
|
}
|
2021-02-06 02:51:12 +00:00
|
|
|
|
2020-10-23 16:38:27 +00:00
|
|
|
|
|
|
|
// Set deployer back as admin
|
2020-11-05 11:35:50 +00:00
|
|
|
await waitForTx(await addressProvider.setPoolAdmin(admin));
|
2020-11-30 18:25:06 +00:00
|
|
|
return gasUsage;
|
2020-10-23 13:18:01 +00:00
|
|
|
};
|
2020-10-26 09:41:24 +00:00
|
|
|
|
|
|
|
export const getPairsTokenAggregator = (
|
|
|
|
allAssetsAddresses: {
|
|
|
|
[tokenSymbol: string]: tEthereumAddress;
|
|
|
|
},
|
2020-11-18 18:18:02 +00:00
|
|
|
aggregatorsAddresses: { [tokenSymbol: string]: tEthereumAddress }
|
2020-10-26 09:41:24 +00:00
|
|
|
): [string[], string[]] => {
|
2020-11-18 18:18:02 +00:00
|
|
|
const { ETH, USD, WETH, ...assetsAddressesWithoutEth } = allAssetsAddresses;
|
2020-10-26 09:41:24 +00:00
|
|
|
|
|
|
|
const pairs = Object.entries(assetsAddressesWithoutEth).map(([tokenSymbol, tokenAddress]) => {
|
|
|
|
if (tokenSymbol !== 'WETH' && tokenSymbol !== 'ETH') {
|
|
|
|
const aggregatorAddressIndex = Object.keys(aggregatorsAddresses).findIndex(
|
|
|
|
(value) => value === tokenSymbol
|
|
|
|
);
|
|
|
|
const [, aggregatorAddress] = (Object.entries(aggregatorsAddresses) as [
|
|
|
|
string,
|
|
|
|
tEthereumAddress
|
|
|
|
][])[aggregatorAddressIndex];
|
|
|
|
return [tokenAddress, aggregatorAddress];
|
|
|
|
}
|
|
|
|
}) as [string, string][];
|
|
|
|
|
|
|
|
const mappedPairs = pairs.map(([asset]) => asset);
|
|
|
|
const mappedAggregators = pairs.map(([, source]) => source);
|
|
|
|
|
|
|
|
return [mappedPairs, mappedAggregators];
|
|
|
|
};
|
|
|
|
|
2020-11-28 11:54:54 +00:00
|
|
|
export const configureReservesByHelper = async (
|
2020-10-26 16:43:10 +00:00
|
|
|
reservesParams: iMultiPoolsAssets<IReserveParams>,
|
2020-11-18 18:18:02 +00:00
|
|
|
tokenAddresses: { [symbol: string]: tEthereumAddress },
|
2020-11-10 14:19:47 +00:00
|
|
|
helpers: AaveProtocolDataProvider,
|
2020-10-26 16:43:10 +00:00
|
|
|
admin: tEthereumAddress
|
|
|
|
) => {
|
|
|
|
const addressProvider = await getLendingPoolAddressesProvider();
|
|
|
|
const atokenAndRatesDeployer = await getATokensAndRatesHelper();
|
|
|
|
const tokens: string[] = [];
|
|
|
|
const symbols: string[] = [];
|
|
|
|
const baseLTVA: string[] = [];
|
|
|
|
const liquidationThresholds: string[] = [];
|
|
|
|
const liquidationBonuses: string[] = [];
|
2020-11-28 11:54:54 +00:00
|
|
|
const reserveFactors: string[] = [];
|
|
|
|
const stableRatesEnabled: boolean[] = [];
|
2021-02-06 02:51:12 +00:00
|
|
|
|
2021-01-30 03:52:12 +00:00
|
|
|
const inputParams : {
|
|
|
|
asset: string;
|
|
|
|
baseLTV: BigNumberish;
|
|
|
|
liquidationThreshold: BigNumberish;
|
|
|
|
liquidationBonus: BigNumberish;
|
|
|
|
reserveFactor: BigNumberish;
|
|
|
|
stableBorrowingEnabled: boolean;
|
|
|
|
}[] = [];
|
2020-10-26 09:41:24 +00:00
|
|
|
|
2020-10-26 16:43:10 +00:00
|
|
|
for (const [
|
|
|
|
assetSymbol,
|
2020-11-30 18:25:06 +00:00
|
|
|
{
|
|
|
|
baseLTVAsCollateral,
|
|
|
|
liquidationBonus,
|
|
|
|
liquidationThreshold,
|
|
|
|
reserveFactor,
|
|
|
|
stableBorrowRateEnabled,
|
|
|
|
},
|
2020-10-26 16:43:10 +00:00
|
|
|
] of Object.entries(reservesParams) as [string, IReserveParams][]) {
|
|
|
|
if (baseLTVAsCollateral === '-1') continue;
|
2020-10-26 09:41:24 +00:00
|
|
|
|
2020-10-26 16:43:10 +00:00
|
|
|
const assetAddressIndex = Object.keys(tokenAddresses).findIndex(
|
|
|
|
(value) => value === assetSymbol
|
|
|
|
);
|
|
|
|
const [, tokenAddress] = (Object.entries(tokenAddresses) as [string, string][])[
|
|
|
|
assetAddressIndex
|
|
|
|
];
|
2020-11-18 18:18:02 +00:00
|
|
|
const { usageAsCollateralEnabled: alreadyEnabled } = await helpers.getReserveConfigurationData(
|
2020-10-26 16:43:10 +00:00
|
|
|
tokenAddress
|
|
|
|
);
|
2020-10-26 09:41:24 +00:00
|
|
|
|
2020-10-26 16:43:10 +00:00
|
|
|
if (alreadyEnabled) {
|
|
|
|
console.log(`- Reserve ${assetSymbol} is already enabled as collateral, skipping`);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
// Push data
|
2021-01-30 03:52:12 +00:00
|
|
|
|
|
|
|
inputParams.push({
|
|
|
|
asset: tokenAddress,
|
|
|
|
baseLTV: baseLTVAsCollateral,
|
|
|
|
liquidationThreshold: liquidationThreshold,
|
|
|
|
liquidationBonus: liquidationBonus,
|
|
|
|
reserveFactor: reserveFactor,
|
|
|
|
stableBorrowingEnabled: stableBorrowRateEnabled
|
|
|
|
});
|
|
|
|
|
2020-10-26 16:43:10 +00:00
|
|
|
tokens.push(tokenAddress);
|
|
|
|
symbols.push(assetSymbol);
|
|
|
|
baseLTVA.push(baseLTVAsCollateral);
|
|
|
|
liquidationThresholds.push(liquidationThreshold);
|
|
|
|
liquidationBonuses.push(liquidationBonus);
|
2020-11-28 11:54:54 +00:00
|
|
|
reserveFactors.push(reserveFactor);
|
|
|
|
stableRatesEnabled.push(stableBorrowRateEnabled);
|
2020-10-26 16:43:10 +00:00
|
|
|
}
|
|
|
|
if (tokens.length) {
|
|
|
|
// Set aTokenAndRatesDeployer as temporal admin
|
2020-11-05 11:35:50 +00:00
|
|
|
await waitForTx(await addressProvider.setPoolAdmin(atokenAndRatesDeployer.address));
|
2020-10-26 16:43:10 +00:00
|
|
|
|
|
|
|
// Deploy init per chunks
|
|
|
|
const enableChunks = 20;
|
|
|
|
const chunkedSymbols = chunk(symbols, enableChunks);
|
2021-01-30 03:52:12 +00:00
|
|
|
const chunkedInputParams = chunk(inputParams, enableChunks);
|
|
|
|
|
2021-02-06 02:51:12 +00:00
|
|
|
console.log(`- Configure reserves in ${chunkedInputParams.length} txs`);
|
|
|
|
for (let chunkIndex = 0; chunkIndex < chunkedInputParams.length; chunkIndex++) {
|
2020-10-26 16:43:10 +00:00
|
|
|
await waitForTx(
|
2020-11-28 11:54:54 +00:00
|
|
|
await atokenAndRatesDeployer.configureReserves(
|
2021-01-30 03:52:12 +00:00
|
|
|
chunkedInputParams[chunkIndex],
|
2020-11-18 18:18:02 +00:00
|
|
|
{ gasLimit: 12000000 }
|
2020-10-26 16:43:10 +00:00
|
|
|
)
|
2020-10-26 09:41:24 +00:00
|
|
|
);
|
2020-10-26 16:43:10 +00:00
|
|
|
console.log(` - Init for: ${chunkedSymbols[chunkIndex].join(', ')}`);
|
2020-10-26 09:41:24 +00:00
|
|
|
}
|
2020-10-26 16:43:10 +00:00
|
|
|
// Set deployer back as admin
|
2020-11-05 11:35:50 +00:00
|
|
|
await waitForTx(await addressProvider.setPoolAdmin(admin));
|
2020-10-26 09:41:24 +00:00
|
|
|
}
|
|
|
|
};
|
2020-12-01 11:39:54 +00:00
|
|
|
|
|
|
|
const getAddressById = async (
|
|
|
|
id: string,
|
|
|
|
network: eEthereumNetwork
|
|
|
|
): Promise<tEthereumAddress | undefined> =>
|
|
|
|
(await getDb().get(`${id}.${network}`).value())?.address || undefined;
|
|
|
|
|
|
|
|
export const initTokenReservesByHelper = async (
|
|
|
|
reservesParams: iMultiPoolsAssets<IReserveParams>,
|
|
|
|
tokenAddresses: { [symbol: string]: tEthereumAddress },
|
|
|
|
admin: tEthereumAddress,
|
|
|
|
addressesProviderAddress: tEthereumAddress,
|
|
|
|
ratesHelperAddress: tEthereumAddress,
|
|
|
|
dataProviderAddress: tEthereumAddress,
|
|
|
|
signer: Signer,
|
|
|
|
treasuryAddress: tEthereumAddress,
|
|
|
|
verify: boolean
|
|
|
|
) => {
|
|
|
|
let gasUsage = BigNumber.from('0');
|
|
|
|
const atokenAndRatesDeployer = await (await getATokensAndRatesHelper(ratesHelperAddress)).connect(
|
|
|
|
signer
|
|
|
|
);
|
|
|
|
|
|
|
|
const addressProvider = await (
|
|
|
|
await getLendingPoolAddressesProvider(addressesProviderAddress)
|
|
|
|
).connect(signer);
|
|
|
|
const protocolDataProvider = await (
|
|
|
|
await getAaveProtocolDataProvider(dataProviderAddress)
|
|
|
|
).connect(signer);
|
|
|
|
const poolAddress = await addressProvider.getLendingPool();
|
|
|
|
|
|
|
|
// Set aTokenAndRatesDeployer as temporal admin
|
|
|
|
await waitForTx(await addressProvider.setPoolAdmin(atokenAndRatesDeployer.address));
|
|
|
|
|
|
|
|
// CHUNK CONFIGURATION
|
|
|
|
const initChunks = 4;
|
|
|
|
|
|
|
|
// Initialize variables for future reserves initialization
|
|
|
|
let deployedStableTokens: string[] = [];
|
|
|
|
let deployedVariableTokens: string[] = [];
|
|
|
|
let deployedATokens: string[] = [];
|
|
|
|
let deployedRates: string[] = [];
|
2021-02-06 02:51:12 +00:00
|
|
|
let reserveTokens: string[] = [];
|
2020-12-01 11:39:54 +00:00
|
|
|
let reserveInitDecimals: string[] = [];
|
|
|
|
let reserveSymbols: string[] = [];
|
2021-02-06 02:51:12 +00:00
|
|
|
|
|
|
|
let initInputParams: {
|
|
|
|
aTokenImpl: string,
|
|
|
|
stableDebtTokenImpl: string,
|
|
|
|
variableDebtTokenImpl: string,
|
|
|
|
underlyingAssetDecimals: BigNumberish,
|
|
|
|
interestRateStrategyAddress: string,
|
|
|
|
underlyingAsset: string,
|
|
|
|
treasury: string,
|
|
|
|
incentivesController: string,
|
|
|
|
underlyingAssetName: string,
|
|
|
|
aTokenName: string,
|
|
|
|
aTokenSymbol: string,
|
|
|
|
variableDebtTokenName: string,
|
|
|
|
variableDebtTokenSymbol: string,
|
|
|
|
stableDebtTokenName: string,
|
|
|
|
stableDebtTokenSymbol: string,
|
|
|
|
}[] = [];
|
|
|
|
|
2020-12-01 11:39:54 +00:00
|
|
|
const network =
|
|
|
|
process.env.MAINNET_FORK === 'true'
|
|
|
|
? eEthereumNetwork.main
|
|
|
|
: (DRE.network.name as eEthereumNetwork);
|
|
|
|
// Grab config from DB
|
|
|
|
for (const [symbol, address] of Object.entries(tokenAddresses)) {
|
|
|
|
const { aTokenAddress } = await protocolDataProvider.getReserveTokensAddresses(address);
|
|
|
|
const reserveParamIndex = Object.keys(reservesParams).findIndex((value) => value === symbol);
|
|
|
|
const [, { reserveDecimals: decimals }] = (Object.entries(reservesParams) as [
|
|
|
|
string,
|
|
|
|
IReserveParams
|
|
|
|
][])[reserveParamIndex];
|
|
|
|
|
|
|
|
if (!isZeroAddress(aTokenAddress)) {
|
2020-12-01 12:21:46 +00:00
|
|
|
console.log(`- Skipping ${symbol} due already initialized`);
|
2020-12-01 11:39:54 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
let stableTokenImpl = await getAddressById(`stableDebt${symbol}`, network);
|
|
|
|
let variableTokenImpl = await getAddressById(`variableDebt${symbol}`, network);
|
|
|
|
let aTokenImplementation = await getAddressById(`a${symbol}`, network);
|
|
|
|
let strategyImpl = await getAddressById(`strategy${symbol}`, network);
|
|
|
|
|
|
|
|
if (!stableTokenImpl) {
|
|
|
|
const stableDebt = await deployStableDebtToken(
|
|
|
|
[
|
|
|
|
poolAddress,
|
|
|
|
tokenAddresses[symbol],
|
2021-02-02 22:44:46 +00:00
|
|
|
ZERO_ADDRESS, // Incentives controller
|
2020-12-01 11:39:54 +00:00
|
|
|
`Aave stable debt bearing ${symbol}`,
|
2021-02-02 22:44:46 +00:00
|
|
|
`stableDebt${symbol}`
|
2020-12-01 11:39:54 +00:00
|
|
|
],
|
|
|
|
verify
|
|
|
|
);
|
|
|
|
stableTokenImpl = stableDebt.address;
|
|
|
|
}
|
|
|
|
if (!variableTokenImpl) {
|
|
|
|
const variableDebt = await deployVariableDebtToken(
|
|
|
|
[
|
|
|
|
poolAddress,
|
|
|
|
tokenAddresses[symbol],
|
2021-02-02 22:44:46 +00:00
|
|
|
ZERO_ADDRESS, // Incentives Controller
|
2020-12-01 11:39:54 +00:00
|
|
|
`Aave variable debt bearing ${symbol}`,
|
2021-02-02 22:44:46 +00:00
|
|
|
`variableDebt${symbol}`
|
2020-12-01 11:39:54 +00:00
|
|
|
],
|
|
|
|
verify
|
|
|
|
);
|
|
|
|
variableTokenImpl = variableDebt.address;
|
|
|
|
}
|
|
|
|
if (!aTokenImplementation) {
|
|
|
|
const [, { aTokenImpl }] = (Object.entries(reservesParams) as [string, IReserveParams][])[
|
|
|
|
reserveParamIndex
|
|
|
|
];
|
|
|
|
const deployCustomAToken = chooseATokenDeployment(aTokenImpl);
|
|
|
|
const aToken = await deployCustomAToken(
|
|
|
|
[
|
|
|
|
poolAddress,
|
|
|
|
tokenAddresses[symbol],
|
|
|
|
treasuryAddress,
|
|
|
|
ZERO_ADDRESS,
|
2021-02-02 22:44:46 +00:00
|
|
|
`Aave interest bearing ${symbol}`,
|
|
|
|
`a${symbol}`
|
2020-12-01 11:39:54 +00:00
|
|
|
],
|
|
|
|
verify
|
|
|
|
);
|
|
|
|
aTokenImplementation = aToken.address;
|
|
|
|
}
|
|
|
|
if (!strategyImpl) {
|
|
|
|
const [
|
|
|
|
,
|
|
|
|
{
|
|
|
|
optimalUtilizationRate,
|
|
|
|
baseVariableBorrowRate,
|
|
|
|
variableRateSlope1,
|
|
|
|
variableRateSlope2,
|
|
|
|
stableRateSlope1,
|
|
|
|
stableRateSlope2,
|
|
|
|
},
|
|
|
|
] = (Object.entries(reservesParams) as [string, IReserveParams][])[reserveParamIndex];
|
|
|
|
const rates = await deployDefaultReserveInterestRateStrategy(
|
|
|
|
[
|
|
|
|
tokenAddresses[symbol],
|
|
|
|
optimalUtilizationRate,
|
|
|
|
baseVariableBorrowRate,
|
|
|
|
variableRateSlope1,
|
|
|
|
variableRateSlope2,
|
|
|
|
stableRateSlope1,
|
|
|
|
stableRateSlope2,
|
|
|
|
],
|
|
|
|
verify
|
|
|
|
);
|
|
|
|
strategyImpl = rates.address;
|
|
|
|
}
|
2020-12-01 12:21:46 +00:00
|
|
|
const symbols = [`a${symbol}`, `variableDebt${symbol}`, `stableDebt${symbol}`];
|
|
|
|
const tokens = [aTokenImplementation, variableTokenImpl, stableTokenImpl];
|
|
|
|
for (let index = 0; index < symbols.length; index++) {
|
|
|
|
if (!(await isErc20SymbolCorrect(tokens[index], symbols[index]))) {
|
|
|
|
console.error(`${symbol} and implementation does not match: ${tokens[index]}`);
|
|
|
|
throw Error('Symbol does not match implementation.');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
console.log(`- Added ${symbol} to the initialize batch`);
|
2020-12-01 11:39:54 +00:00
|
|
|
deployedStableTokens.push(stableTokenImpl);
|
|
|
|
deployedVariableTokens.push(variableTokenImpl);
|
|
|
|
deployedATokens.push(aTokenImplementation);
|
2021-02-06 02:51:12 +00:00
|
|
|
reserveTokens.push();
|
2020-12-01 11:39:54 +00:00
|
|
|
deployedRates.push(strategyImpl);
|
|
|
|
reserveInitDecimals.push(decimals.toString());
|
|
|
|
reserveSymbols.push(symbol);
|
|
|
|
}
|
|
|
|
|
2021-02-06 02:51:12 +00:00
|
|
|
for (let i = 0; i < deployedATokens.length; i ++) {
|
|
|
|
initInputParams.push({
|
|
|
|
aTokenImpl: deployedATokens[i],
|
|
|
|
stableDebtTokenImpl: deployedStableTokens[i],
|
|
|
|
variableDebtTokenImpl: deployedVariableTokens[i],
|
|
|
|
underlyingAssetDecimals: reserveInitDecimals[i],
|
|
|
|
interestRateStrategyAddress: deployedRates[i],
|
|
|
|
underlyingAsset: tokenAddresses[reserveSymbols[i]],
|
|
|
|
treasury: treasuryAddress,
|
|
|
|
incentivesController: ZERO_ADDRESS,
|
|
|
|
underlyingAssetName: reserveSymbols[i],
|
|
|
|
aTokenName: `Aave interest bearing ${reserveSymbols[i]}`,
|
|
|
|
aTokenSymbol: `a${reserveSymbols[i]}`,
|
|
|
|
variableDebtTokenName: `Aave variable debt bearing ${reserveSymbols[i]}`,
|
|
|
|
variableDebtTokenSymbol: `variableDebt${reserveSymbols[i]}`,
|
|
|
|
stableDebtTokenName: `Aave stable debt bearing ${reserveSymbols[i]}`,
|
|
|
|
stableDebtTokenSymbol: `stableDebt${reserveSymbols[i]}`
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2020-12-01 11:39:54 +00:00
|
|
|
// Deploy init reserves per chunks
|
|
|
|
const chunkedSymbols = chunk(reserveSymbols, initChunks);
|
2021-02-06 02:51:12 +00:00
|
|
|
const chunkedInitInputParams = chunk(initInputParams, initChunks);
|
|
|
|
|
|
|
|
const configurator = await getLendingPoolConfiguratorProxy();
|
|
|
|
await waitForTx(await addressProvider.setPoolAdmin(admin));
|
2020-12-01 11:39:54 +00:00
|
|
|
|
2021-02-06 02:51:12 +00:00
|
|
|
console.log(`- Reserves initialization in ${chunkedInitInputParams.length} txs`);
|
|
|
|
for (let chunkIndex = 0; chunkIndex < chunkedInitInputParams.length; chunkIndex++) {
|
2020-12-01 11:39:54 +00:00
|
|
|
const tx3 = await waitForTx(
|
2021-02-06 02:51:12 +00:00
|
|
|
await configurator.batchInitReserve(chunkedInitInputParams[chunkIndex])
|
2020-12-01 11:39:54 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
console.log(` - Reserve ready for: ${chunkedSymbols[chunkIndex].join(', ')}`);
|
|
|
|
console.log(' * gasUsed', tx3.gasUsed.toString());
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set deployer back as admin
|
|
|
|
await waitForTx(await addressProvider.setPoolAdmin(admin));
|
|
|
|
return gasUsage;
|
|
|
|
};
|
2020-12-01 12:21:46 +00:00
|
|
|
|
|
|
|
const isErc20SymbolCorrect = async (token: tEthereumAddress, symbol: string) => {
|
|
|
|
const erc20 = await getAToken(token); // using aToken for ERC20 interface
|
|
|
|
const erc20Symbol = await erc20.symbol();
|
|
|
|
return symbol === erc20Symbol;
|
|
|
|
};
|