import { eContractid, eNetwork, iMultiPoolsAssets, IReserveParams, tEthereumAddress, } from './types'; import { AaveProtocolDataProvider } from '../types/AaveProtocolDataProvider'; import { chunk, getDb, waitForTx } from './misc-utils'; import { getAToken, getATokensAndRatesHelper, getLendingPoolAddressesProvider, getLendingPoolConfiguratorProxy, } from './contracts-getters'; import { 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) { default: return '0x10'; } }; export const initReservesByHelper = async ( reservesParams: iMultiPoolsAssets, tokenAddresses: { [symbol: string]: tEthereumAddress }, aTokenNamePrefix: string, stableDebtTokenNamePrefix: string, variableDebtTokenNamePrefix: string, symbolPrefix: string, admin: tEthereumAddress, treasuryAddress: tEthereumAddress, incentivesController: tEthereumAddress, poolName: ConfigNames, verify: boolean ) => { const addressProvider = await getLendingPoolAddressesProvider(); // CHUNK CONFIGURATION const initChunks = 1; // Initialize variables for future reserves initialization let reserveSymbols: string[] = []; 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; params: string; }[] = []; let strategyRates: [ string, // addresses provider string, string, string, string, string, string ]; let rateStrategies: Record = {}; let strategyAddresses: Record = {}; const reserves = Object.entries(reservesParams); for (let [symbol, params] of reserves) { if (!tokenAddresses[symbol]) { console.log(`- Skipping init of ${symbol} due token address is not set at markets config`); continue; } const { strategy, aTokenImpl, reserveDecimals } = params; const { optimalUtilizationRate, baseVariableBorrowRate, variableRateSlope1, variableRateSlope2, stableRateSlope1, stableRateSlope2, } = strategy; if (!strategyAddresses[strategy.name]) { // Strategy does not exist, create a new one rateStrategies[strategy.name] = [ addressProvider.address, optimalUtilizationRate, baseVariableBorrowRate, variableRateSlope1, variableRateSlope2, stableRateSlope1, stableRateSlope2, ]; strategyAddresses[strategy.name] = await deployRateStrategy( strategy.name, rateStrategies[strategy.name], verify ); // 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]); } // Prepare input parameters reserveSymbols.push(symbol); initInputParams.push({ 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], treasury: treasuryAddress, 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]), }); } // Deploy init reserves per chunks const chunkedSymbols = chunk(reserveSymbols, initChunks); const chunkedInitInputParams = chunk(initInputParams, initChunks); const configurator = await getLendingPoolConfiguratorProxy(); console.log(`- Reserves initialization in ${chunkedInitInputParams.length} txs`); for (let chunkIndex = 0; chunkIndex < chunkedInitInputParams.length; chunkIndex++) { const tx3 = await waitForTx( await configurator.batchInitReserve(chunkedInitInputParams[chunkIndex]) ); console.log(` - Reserve ready for: ${chunkedSymbols[chunkIndex].join(', ')}`); console.log(' * gasUsed', tx3.gasUsed.toString()); } }; export const getPairsTokenAggregator = ( allAssetsAddresses: { [tokenSymbol: string]: tEthereumAddress; }, aggregatorsAddresses: { [tokenSymbol: string]: tEthereumAddress } ): [string[], string[]] => { const { ETH, USD, WETH, ...assetsAddressesWithoutEth } = allAssetsAddresses; 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]; }; export const configureReservesByHelper = async ( reservesParams: iMultiPoolsAssets, tokenAddresses: { [symbol: string]: tEthereumAddress }, helpers: AaveProtocolDataProvider, admin: tEthereumAddress ) => { const addressProvider = await getLendingPoolAddressesProvider(); const atokenAndRatesDeployer = await getATokensAndRatesHelper(); const tokens: string[] = []; const symbols: string[] = []; const inputParams: { asset: string; baseLTV: BigNumberish; liquidationThreshold: BigNumberish; liquidationBonus: BigNumberish; reserveFactor: BigNumberish; stableBorrowingEnabled: boolean; borrowingEnabled: boolean; }[] = []; for (const [ assetSymbol, { baseLTVAsCollateral, liquidationBonus, liquidationThreshold, reserveFactor, stableBorrowRateEnabled, borrowingEnabled, }, ] of Object.entries(reservesParams) as [string, IReserveParams][]) { if (!tokenAddresses[assetSymbol]) { console.log( `- Skipping init of ${assetSymbol} due token address is not set at markets config` ); continue; } if (baseLTVAsCollateral === '-1') continue; const assetAddressIndex = Object.keys(tokenAddresses).findIndex( (value) => value === assetSymbol ); const [, tokenAddress] = (Object.entries(tokenAddresses) as [string, string][])[ assetAddressIndex ]; const { usageAsCollateralEnabled: alreadyEnabled } = await helpers.getReserveConfigurationData( tokenAddress ); if (alreadyEnabled) { console.log(`- Reserve ${assetSymbol} is already enabled as collateral, skipping`); continue; } // Push data inputParams.push({ asset: tokenAddress, baseLTV: baseLTVAsCollateral, liquidationThreshold: liquidationThreshold, liquidationBonus: liquidationBonus, reserveFactor: reserveFactor, stableBorrowingEnabled: stableBorrowRateEnabled, borrowingEnabled: borrowingEnabled, }); tokens.push(tokenAddress); symbols.push(assetSymbol); } if (tokens.length) { // Set aTokenAndRatesDeployer as temporal admin await waitForTx(await addressProvider.setPoolAdmin(atokenAndRatesDeployer.address)); // Deploy init per chunks const enableChunks = 20; const chunkedSymbols = chunk(symbols, enableChunks); const chunkedInputParams = chunk(inputParams, enableChunks); console.log(`- Configure reserves in ${chunkedInputParams.length} txs`); for (let chunkIndex = 0; chunkIndex < chunkedInputParams.length; chunkIndex++) { await waitForTx( await atokenAndRatesDeployer.configureReserves(chunkedInputParams[chunkIndex]) ); console.log(` - Init for: ${chunkedSymbols[chunkIndex].join(', ')}`); } // Set deployer back as admin await waitForTx(await addressProvider.setPoolAdmin(admin)); } }; const getAddressById = async ( id: string, network: eNetwork ): Promise => (await getDb().get(`${id}.${network}`).value())?.address || undefined; // Function deprecated 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; };