import { Contract } from 'ethers'; import { DRE } from './misc-utils'; import { tEthereumAddress, eContractid, tStringTokenSmallUnits, AavePools, TokenContractId, iMultiPoolsAssets, IReserveParams, PoolConfiguration, eEthereumNetwork, } from './types'; import { MintableERC20 } from '../types/MintableERC20'; import { MockContract } from 'ethereum-waffle'; import { getReservesConfigByPool } from './configuration'; import { getFirstSigner } from './contracts-getters'; import { ZERO_ADDRESS } from './constants'; import { AaveProtocolDataProviderFactory, ATokenFactory, ATokensAndRatesHelperFactory, AaveOracleFactory, DefaultReserveInterestRateStrategyFactory, DelegationAwareATokenFactory, InitializableAdminUpgradeabilityProxyFactory, LendingPoolAddressesProviderFactory, LendingPoolAddressesProviderRegistryFactory, LendingPoolCollateralManagerFactory, LendingPoolConfiguratorFactory, LendingPoolFactory, LendingRateOracleFactory, MintableDelegationERC20Factory, MintableERC20Factory, MockAggregatorFactory, MockATokenFactory, MockFlashLoanReceiverFactory, MockStableDebtTokenFactory, MockVariableDebtTokenFactory, PriceOracleFactory, ReserveLogicFactory, SelfdestructTransferFactory, StableDebtTokenFactory, VariableDebtTokenFactory, WalletBalanceProviderFactory, WETH9MockedFactory, WETHGatewayFactory, } from '../types'; import { withSaveAndVerify, registerContractInJsonDb, linkBytecode, insertContractAddressInDb, } from './contracts-helpers'; import { StableAndVariableTokensHelperFactory } from '../types/StableAndVariableTokensHelperFactory'; import { MintableDelegationERC20 } from '../types/MintableDelegationERC20'; import { readArtifact as buidlerReadArtifact } from '@nomiclabs/buidler/plugins'; import { HardhatRuntimeEnvironment } from 'hardhat/types'; import { LendingPoolLibraryAddresses } from '../types/LendingPoolFactory'; const readArtifact = async (id: string) => { if (DRE.network.name === eEthereumNetwork.buidlerevm) { return buidlerReadArtifact(DRE.config.paths.artifacts, id); } return (DRE as HardhatRuntimeEnvironment).artifacts.readArtifact(id); }; export const deployLendingPoolAddressesProvider = async (marketId: string, verify?: boolean) => withSaveAndVerify( await new LendingPoolAddressesProviderFactory(await getFirstSigner()).deploy(marketId), eContractid.LendingPoolAddressesProvider, [marketId], verify ); export const deployLendingPoolAddressesProviderRegistry = async (verify?: boolean) => withSaveAndVerify( await new LendingPoolAddressesProviderRegistryFactory(await getFirstSigner()).deploy(), eContractid.LendingPoolAddressesProviderRegistry, [], verify ); export const deployLendingPoolConfigurator = async (verify?: boolean) => { const lendingPoolConfiguratorImpl = await new LendingPoolConfiguratorFactory( await getFirstSigner() ).deploy(); await insertContractAddressInDb( eContractid.LendingPoolConfiguratorImpl, lendingPoolConfiguratorImpl.address ); return withSaveAndVerify( lendingPoolConfiguratorImpl, eContractid.LendingPoolConfigurator, [], verify ); }; export const deployReserveLogicLibrary = async (verify?: boolean) => withSaveAndVerify( await new ReserveLogicFactory(await getFirstSigner()).deploy(), eContractid.ReserveLogic, [], verify ); export const deployGenericLogic = async (reserveLogic: Contract, verify?: boolean) => { const genericLogicArtifact = await readArtifact(eContractid.GenericLogic); const linkedGenericLogicByteCode = linkBytecode(genericLogicArtifact, { [eContractid.ReserveLogic]: reserveLogic.address, }); const genericLogicFactory = await DRE.ethers.getContractFactory( genericLogicArtifact.abi, linkedGenericLogicByteCode ); const genericLogic = await (await genericLogicFactory.deploy()).deployed(); return withSaveAndVerify(genericLogic, eContractid.GenericLogic, [], verify); }; export const deployValidationLogic = async ( reserveLogic: Contract, genericLogic: Contract, verify?: boolean ) => { const validationLogicArtifact = await readArtifact(eContractid.ValidationLogic); const linkedValidationLogicByteCode = linkBytecode(validationLogicArtifact, { [eContractid.ReserveLogic]: reserveLogic.address, [eContractid.GenericLogic]: genericLogic.address, }); const validationLogicFactory = await DRE.ethers.getContractFactory( validationLogicArtifact.abi, linkedValidationLogicByteCode ); const validationLogic = await (await validationLogicFactory.deploy()).deployed(); return withSaveAndVerify(validationLogic, eContractid.ValidationLogic, [], verify); }; export const deployAaveLibraries = async ( verify?: boolean ): Promise => { const reserveLogic = await deployReserveLogicLibrary(verify); const genericLogic = await deployGenericLogic(reserveLogic, verify); const validationLogic = await deployValidationLogic(reserveLogic, genericLogic, verify); // Hardcoded solidity placeholders, if any library changes path this will fail. // The '__$PLACEHOLDER$__ can be calculated via solidity keccak, but the LendingPoolLibraryAddresses Type seems to // require a hardcoded string. // // how-to: // 1. PLACEHOLDER = solidityKeccak256(['string'], `${libPath}:${libName}`).slice(2, 36) // 2. LIB_PLACEHOLDER = `__$${PLACEHOLDER}$__` // or grab placeholdes from LendingPoolLibraryAddresses at Typechain generation. // // libPath example: contracts/libraries/logic/GenericLogic.sol // libName example: GenericLogic return { ['__$de8c0cf1a7d7c36c802af9a64fb9d86036$__']: validationLogic.address, ['__$22cd43a9dda9ce44e9b92ba393b88fb9ac$__']: reserveLogic.address, }; }; export const deployLendingPool = async (verify?: boolean) => { const libraries = await deployAaveLibraries(verify); const lendingPoolImpl = await new LendingPoolFactory(libraries, await getFirstSigner()).deploy(); await insertContractAddressInDb(eContractid.LendingPoolImpl, lendingPoolImpl.address); return withSaveAndVerify(lendingPoolImpl, eContractid.LendingPool, [], verify); }; export const deployPriceOracle = async (verify?: boolean) => withSaveAndVerify( await new PriceOracleFactory(await getFirstSigner()).deploy(), eContractid.PriceOracle, [], verify ); export const deployLendingRateOracle = async (verify?: boolean) => withSaveAndVerify( await new LendingRateOracleFactory(await getFirstSigner()).deploy(), eContractid.LendingRateOracle, [], verify ); export const deployMockAggregator = async (price: tStringTokenSmallUnits, verify?: boolean) => withSaveAndVerify( await new MockAggregatorFactory(await getFirstSigner()).deploy(price), eContractid.MockAggregator, [price], verify ); export const deployAaveOracle = async ( args: [tEthereumAddress[], tEthereumAddress[], tEthereumAddress, tEthereumAddress], verify?: boolean ) => withSaveAndVerify( await new AaveOracleFactory(await getFirstSigner()).deploy(...args), eContractid.AaveOracle, args, verify ); export const deployLendingPoolCollateralManager = async (verify?: boolean) => { const collateralManagerImpl = await new LendingPoolCollateralManagerFactory( await getFirstSigner() ).deploy(); await insertContractAddressInDb( eContractid.LendingPoolCollateralManagerImpl, collateralManagerImpl.address ); return withSaveAndVerify( collateralManagerImpl, eContractid.LendingPoolCollateralManager, [], verify ); }; export const deployInitializableAdminUpgradeabilityProxy = async (verify?: boolean) => withSaveAndVerify( await new InitializableAdminUpgradeabilityProxyFactory(await getFirstSigner()).deploy(), eContractid.InitializableAdminUpgradeabilityProxy, [], verify ); export const deployMockFlashLoanReceiver = async ( addressesProvider: tEthereumAddress, verify?: boolean ) => withSaveAndVerify( await new MockFlashLoanReceiverFactory(await getFirstSigner()).deploy(addressesProvider), eContractid.MockFlashLoanReceiver, [addressesProvider], verify ); export const deployWalletBalancerProvider = async (verify?: boolean) => withSaveAndVerify( await new WalletBalanceProviderFactory(await getFirstSigner()).deploy(), eContractid.WalletBalanceProvider, [], verify ); export const deployAaveProtocolDataProvider = async ( addressesProvider: tEthereumAddress, verify?: boolean ) => withSaveAndVerify( await new AaveProtocolDataProviderFactory(await getFirstSigner()).deploy(addressesProvider), eContractid.AaveProtocolDataProvider, [addressesProvider], verify ); export const deployMintableERC20 = async ( args: [string, string, string], verify?: boolean ): Promise => withSaveAndVerify( await new MintableERC20Factory(await getFirstSigner()).deploy(...args), eContractid.MintableERC20, args, verify ); export const deployMintableDelegationERC20 = async ( args: [string, string, string], verify?: boolean ): Promise => withSaveAndVerify( await new MintableDelegationERC20Factory(await getFirstSigner()).deploy(...args), eContractid.MintableDelegationERC20, args, verify ); export const deployDefaultReserveInterestRateStrategy = async ( args: [tEthereumAddress, string, string, string, string, string, string], verify: boolean ) => withSaveAndVerify( await new DefaultReserveInterestRateStrategyFactory(await getFirstSigner()).deploy(...args), eContractid.DefaultReserveInterestRateStrategy, args, verify ); export const deployStableDebtToken = async ( args: [tEthereumAddress, tEthereumAddress, string, string, tEthereumAddress], verify: boolean ) => withSaveAndVerify( await new StableDebtTokenFactory(await getFirstSigner()).deploy(...args), eContractid.StableDebtToken, args, verify ); export const deployVariableDebtToken = async ( args: [tEthereumAddress, tEthereumAddress, string, string, tEthereumAddress], verify: boolean ) => withSaveAndVerify( await new VariableDebtTokenFactory(await getFirstSigner()).deploy(...args), eContractid.VariableDebtToken, args, verify ); export const deployGenericAToken = async ( [poolAddress, underlyingAssetAddress, treasuryAddress, name, symbol,incentivesController]: [ tEthereumAddress, tEthereumAddress, tEthereumAddress, string, string, tEthereumAddress ], verify: boolean ) => { const args: [ tEthereumAddress, tEthereumAddress, string, string, tEthereumAddress, tEthereumAddress ] = [poolAddress, underlyingAssetAddress, treasuryAddress, name, symbol, incentivesController]; return withSaveAndVerify( await new ATokenFactory(await getFirstSigner()).deploy(...args), eContractid.AToken, args, verify ); }; export const deployDelegationAwareAToken = async ( [poolAddress, underlyingAssetAddress, treasuryAddress, name, symbol, incentivesController]: [ tEthereumAddress, tEthereumAddress, tEthereumAddress, string, string, tEthereumAddress ], verify: boolean ) => { const args: [ tEthereumAddress, tEthereumAddress, string, string, tEthereumAddress, tEthereumAddress ] = [poolAddress, underlyingAssetAddress, treasuryAddress, name, symbol, incentivesController]; return withSaveAndVerify( await new DelegationAwareATokenFactory(await getFirstSigner()).deploy(...args), eContractid.DelegationAwareAToken, args, verify ); }; export const deployAllMockTokens = async (verify?: boolean) => { const tokens: { [symbol: string]: MockContract | MintableERC20 } = {}; const protoConfigData = getReservesConfigByPool(AavePools.proto); for (const tokenSymbol of Object.keys(TokenContractId)) { let decimals = '18'; let configData = (protoConfigData)[tokenSymbol]; tokens[tokenSymbol] = await deployMintableERC20( [tokenSymbol, tokenSymbol, configData ? configData.reserveDecimals : decimals], verify ); await registerContractInJsonDb(tokenSymbol.toUpperCase(), tokens[tokenSymbol]); } return tokens; }; export const deployMockTokens = async (config: PoolConfiguration, verify?: boolean) => { const tokens: { [symbol: string]: MockContract | MintableERC20 } = {}; const defaultDecimals = 18; const configData = config.ReservesConfig; for (const tokenSymbol of Object.keys(configData)) { tokens[tokenSymbol] = await deployMintableERC20( [ tokenSymbol, tokenSymbol, configData[tokenSymbol as keyof iMultiPoolsAssets].reserveDecimals || defaultDecimals.toString(), ], verify ); await registerContractInJsonDb(tokenSymbol.toUpperCase(), tokens[tokenSymbol]); } return tokens; }; export const deployStableAndVariableTokensHelper = async ( args: [tEthereumAddress, tEthereumAddress], verify?: boolean ) => withSaveAndVerify( await new StableAndVariableTokensHelperFactory(await getFirstSigner()).deploy(...args), eContractid.StableAndVariableTokensHelper, args, verify ); export const deployATokensAndRatesHelper = async ( args: [tEthereumAddress, tEthereumAddress, tEthereumAddress], verify?: boolean ) => withSaveAndVerify( await new ATokensAndRatesHelperFactory(await getFirstSigner()).deploy(...args), eContractid.ATokensAndRatesHelper, args, verify ); export const deployWETHGateway = async ( args: [tEthereumAddress, tEthereumAddress], verify?: boolean ) => withSaveAndVerify( await new WETHGatewayFactory(await getFirstSigner()).deploy(...args), eContractid.WETHGateway, args, verify ); export const deployMockStableDebtToken = async ( args: [tEthereumAddress, tEthereumAddress, string, string, tEthereumAddress], verify?: boolean ) => withSaveAndVerify( await new MockStableDebtTokenFactory(await getFirstSigner()).deploy(...args), eContractid.MockStableDebtToken, args, verify ); export const deployWETHMocked = async (verify?: boolean) => withSaveAndVerify( await new WETH9MockedFactory(await getFirstSigner()).deploy(), eContractid.WETHMocked, [], verify ); export const deployMockVariableDebtToken = async ( args: [tEthereumAddress, tEthereumAddress, string, string, tEthereumAddress], verify?: boolean ) => withSaveAndVerify( await new MockVariableDebtTokenFactory(await getFirstSigner()).deploy(...args), eContractid.MockVariableDebtToken, args, verify ); export const deployMockAToken = async ( args: [tEthereumAddress, tEthereumAddress, tEthereumAddress, string, string, tEthereumAddress], verify?: boolean ) => withSaveAndVerify( await new MockATokenFactory(await getFirstSigner()).deploy(...args), eContractid.MockAToken, args, verify ); export const deploySelfdestructTransferMock = async (verify?: boolean) => withSaveAndVerify( await new SelfdestructTransferFactory(await getFirstSigner()).deploy(), eContractid.SelfdestructTransferMock, [], verify );