2020-12-01 11:39:54 +00:00
|
|
|
import {
|
|
|
|
eContractid,
|
2021-02-23 14:42:47 +00:00
|
|
|
eNetwork,
|
2020-12-01 11:39:54 +00:00
|
|
|
iMultiPoolsAssets,
|
|
|
|
IReserveParams,
|
|
|
|
tEthereumAddress,
|
|
|
|
} from './types';
|
2020-11-18 18:18:02 +00:00
|
|
|
import { AaveProtocolDataProvider } from '../types/AaveProtocolDataProvider';
|
2021-07-14 14:41:32 +00:00
|
|
|
import { chunk, getDb, waitForTx } from './misc-utils';
|
2020-10-27 09:58:51 +00:00
|
|
|
import {
|
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
|
|
|
} from './contracts-getters';
|
2020-11-19 16:46:23 +00:00
|
|
|
import {
|
2021-07-14 14:41:32 +00:00
|
|
|
getContractAddressWithJsonFallback,
|
|
|
|
rawInsertContractAddressInDb,
|
|
|
|
} from './contracts-helpers';
|
|
|
|
import { BigNumberish } from 'ethers';
|
|
|
|
import { ConfigNames } from './configuration';
|
|
|
|
import { deployRateStrategy } from './contracts-deployments';
|
|
|
|
|
|
|
|
export const getATokenExtraParams = async (aTokenName: string, tokenAddress: tEthereumAddress) => {
|
|
|
|
console.log(aTokenName);
|
|
|
|
switch (aTokenName) {
|
2020-11-20 11:11:57 +00:00
|
|
|
default:
|
2021-07-14 14:41:32 +00:00
|
|
|
return '0x10';
|
2020-11-20 11:11:57 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
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 },
|
2021-02-19 20:50:06 +00:00
|
|
|
aTokenNamePrefix: string,
|
|
|
|
stableDebtTokenNamePrefix: string,
|
|
|
|
variableDebtTokenNamePrefix: string,
|
|
|
|
symbolPrefix: string,
|
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,
|
2021-07-14 14:41:32 +00:00
|
|
|
poolName: ConfigNames,
|
2020-11-19 16:46:23 +00:00
|
|
|
verify: boolean
|
2021-07-14 14:41:32 +00:00
|
|
|
) => {
|
2020-10-27 09:58:51 +00:00
|
|
|
const addressProvider = await getLendingPoolAddressesProvider();
|
2021-02-10 23:23:05 +00:00
|
|
|
|
2020-10-23 16:38:27 +00:00
|
|
|
// CHUNK CONFIGURATION
|
2021-07-14 14:41:32 +00:00
|
|
|
const initChunks = 1;
|
2020-10-23 13:18:01 +00:00
|
|
|
|
2020-10-23 16:38:27 +00:00
|
|
|
// Initialize variables for future reserves initialization
|
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: {
|
2021-02-23 14:42:47 +00:00
|
|
|
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;
|
2021-02-26 18:18:38 +00:00
|
|
|
params: string;
|
2021-02-01 23:23:11 +00:00
|
|
|
}[] = [];
|
|
|
|
|
2021-02-10 18:52:51 +00:00
|
|
|
let strategyRates: [
|
|
|
|
string, // addresses provider
|
|
|
|
string,
|
|
|
|
string,
|
|
|
|
string,
|
|
|
|
string,
|
|
|
|
string,
|
|
|
|
string
|
|
|
|
];
|
|
|
|
let rateStrategies: Record<string, typeof strategyRates> = {};
|
|
|
|
let strategyAddresses: Record<string, tEthereumAddress> = {};
|
2021-02-10 23:23:05 +00:00
|
|
|
|
2021-07-14 14:41:32 +00:00
|
|
|
const reserves = Object.entries(reservesParams);
|
2020-11-20 11:11:57 +00:00
|
|
|
|
2021-02-10 23:23:05 +00:00
|
|
|
for (let [symbol, params] of reserves) {
|
2021-05-07 13:15:15 +00:00
|
|
|
if (!tokenAddresses[symbol]) {
|
|
|
|
console.log(`- Skipping init of ${symbol} due token address is not set at markets config`);
|
|
|
|
continue;
|
|
|
|
}
|
2021-02-23 14:42:47 +00:00
|
|
|
const { strategy, aTokenImpl, reserveDecimals } = params;
|
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,
|
2021-02-10 23:23:05 +00:00
|
|
|
} = strategy;
|
2021-02-23 14:42:47 +00:00
|
|
|
if (!strategyAddresses[strategy.name]) {
|
2021-02-10 18:52:51 +00:00
|
|
|
// Strategy does not exist, create a new one
|
2021-02-10 23:23:05 +00:00
|
|
|
rateStrategies[strategy.name] = [
|
2021-02-10 18:52:51 +00:00
|
|
|
addressProvider.address,
|
2020-11-20 11:11:57 +00:00
|
|
|
optimalUtilizationRate,
|
2020-11-19 16:46:23 +00:00
|
|
|
baseVariableBorrowRate,
|
|
|
|
variableRateSlope1,
|
|
|
|
variableRateSlope2,
|
|
|
|
stableRateSlope1,
|
|
|
|
stableRateSlope2,
|
2021-02-10 18:52:51 +00:00
|
|
|
];
|
2021-07-14 14:41:32 +00:00
|
|
|
strategyAddresses[strategy.name] = await deployRateStrategy(
|
|
|
|
strategy.name,
|
|
|
|
rateStrategies[strategy.name],
|
|
|
|
verify
|
|
|
|
);
|
|
|
|
|
2021-02-10 23:23:05 +00:00
|
|
|
// This causes the last strategy to be printed twice, once under "DefaultReserveInterestRateStrategy"
|
|
|
|
// and once under the actual `strategyASSET` key.
|
|
|
|
rawInsertContractAddressInDb(strategy.name, strategyAddresses[strategy.name]);
|
2021-02-10 18:52:51 +00:00
|
|
|
}
|
2021-07-14 14:41:32 +00:00
|
|
|
// Prepare input parameters
|
2020-11-20 11:11:57 +00:00
|
|
|
reserveSymbols.push(symbol);
|
2021-02-06 02:51:12 +00:00
|
|
|
initInputParams.push({
|
2021-07-14 14:41:32 +00:00
|
|
|
aTokenImpl: await getContractAddressWithJsonFallback(aTokenImpl, poolName),
|
|
|
|
stableDebtTokenImpl: await getContractAddressWithJsonFallback(
|
|
|
|
eContractid.StableDebtToken,
|
|
|
|
poolName
|
|
|
|
),
|
|
|
|
variableDebtTokenImpl: await getContractAddressWithJsonFallback(
|
|
|
|
eContractid.VariableDebtToken,
|
|
|
|
poolName
|
|
|
|
),
|
|
|
|
underlyingAssetDecimals: reserveDecimals,
|
|
|
|
interestRateStrategyAddress: strategyAddresses[strategy.name],
|
|
|
|
underlyingAsset: tokenAddresses[symbol],
|
2021-02-06 02:51:12 +00:00
|
|
|
treasury: treasuryAddress,
|
2021-07-14 14:41:32 +00:00
|
|
|
incentivesController: incentivesController,
|
|
|
|
underlyingAssetName: symbol,
|
|
|
|
aTokenName: `${aTokenNamePrefix} ${symbol}`,
|
|
|
|
aTokenSymbol: `a${symbolPrefix}${symbol}`,
|
|
|
|
variableDebtTokenName: `${variableDebtTokenNamePrefix} ${symbolPrefix}${symbol}`,
|
|
|
|
variableDebtTokenSymbol: `variableDebt${symbolPrefix}${symbol}`,
|
|
|
|
stableDebtTokenName: `${stableDebtTokenNamePrefix} ${symbol}`,
|
|
|
|
stableDebtTokenSymbol: `stableDebt${symbolPrefix}${symbol}`,
|
|
|
|
params: await getATokenExtraParams(aTokenImpl, tokenAddresses[symbol]),
|
2021-02-06 02:51:12 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
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();
|
|
|
|
|
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-05-10 13:56:47 +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());
|
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
|
|
|
|
);
|
2021-07-14 14:41:32 +00:00
|
|
|
const [, aggregatorAddress] = (
|
|
|
|
Object.entries(aggregatorsAddresses) as [string, tEthereumAddress][]
|
|
|
|
)[aggregatorAddressIndex];
|
2020-10-26 09:41:24 +00:00
|
|
|
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[] = [];
|
2021-02-06 02:51:12 +00:00
|
|
|
|
2021-02-23 14:42:47 +00:00
|
|
|
const inputParams: {
|
2021-01-30 03:52:12 +00:00
|
|
|
asset: string;
|
|
|
|
baseLTV: BigNumberish;
|
|
|
|
liquidationThreshold: BigNumberish;
|
|
|
|
liquidationBonus: BigNumberish;
|
|
|
|
reserveFactor: BigNumberish;
|
|
|
|
stableBorrowingEnabled: boolean;
|
2021-03-31 15:39:59 +00:00
|
|
|
borrowingEnabled: boolean;
|
2021-01-30 03:52:12 +00:00
|
|
|
}[] = [];
|
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,
|
2021-03-31 15:39:59 +00:00
|
|
|
borrowingEnabled,
|
2020-11-30 18:25:06 +00:00
|
|
|
},
|
2020-10-26 16:43:10 +00:00
|
|
|
] of Object.entries(reservesParams) as [string, IReserveParams][]) {
|
2021-05-07 13:15:15 +00:00
|
|
|
if (!tokenAddresses[assetSymbol]) {
|
|
|
|
console.log(
|
|
|
|
`- Skipping init of ${assetSymbol} due token address is not set at markets config`
|
|
|
|
);
|
|
|
|
continue;
|
|
|
|
}
|
2020-10-26 16:43:10 +00:00
|
|
|
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,
|
2021-02-23 14:42:47 +00:00
|
|
|
stableBorrowingEnabled: stableBorrowRateEnabled,
|
2021-03-31 15:39:59 +00:00
|
|
|
borrowingEnabled: borrowingEnabled,
|
2021-01-30 03:52:12 +00:00
|
|
|
});
|
|
|
|
|
2020-10-26 16:43:10 +00:00
|
|
|
tokens.push(tokenAddress);
|
|
|
|
symbols.push(assetSymbol);
|
|
|
|
}
|
|
|
|
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(
|
2021-08-17 16:37:21 +00:00
|
|
|
await atokenAndRatesDeployer.configureReserves(chunkedInputParams[chunkIndex])
|
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,
|
2021-02-23 14:42:47 +00:00
|
|
|
network: eNetwork
|
2020-12-01 11:39:54 +00:00
|
|
|
): Promise<tEthereumAddress | undefined> =>
|
|
|
|
(await getDb().get(`${id}.${network}`).value())?.address || undefined;
|
|
|
|
|
2021-02-10 23:47:31 +00:00
|
|
|
// Function deprecated
|
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;
|
|
|
|
};
|