aave-protocol-v2/helpers/contracts-deployments.ts

820 lines
24 KiB
TypeScript

import { Contract } from 'ethers';
import { DRE, notFalsyOrZeroAddress } 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 { ConfigNames, getReservesConfigByPool, loadPoolConfig } from './configuration';
import { getFirstSigner } from './contracts-getters';
import {
AaveProtocolDataProviderFactory,
ATokenFactory,
ATokensAndRatesHelperFactory,
AaveOracleFactory,
DefaultReserveInterestRateStrategyFactory,
DelegationAwareATokenFactory,
InitializableAdminUpgradeabilityProxyFactory,
LendingPoolAddressesProviderFactory,
LendingPoolAddressesProviderRegistryFactory,
LendingPoolCollateralManagerFactory,
LendingPoolConfiguratorFactory,
LendingPoolFactory,
LendingRateOracleFactory,
MintableDelegationERC20Factory,
MintableERC20Factory,
MockAggregatorFactory,
MockATokenFactory,
MockFlashLoanReceiverFactory,
MockParaSwapAugustusFactory,
MockParaSwapAugustusRegistryFactory,
MockStableDebtTokenFactory,
MockVariableDebtTokenFactory,
MockUniswapV2Router02Factory,
ParaSwapLiquiditySwapAdapterFactory,
PriceOracleFactory,
ReserveLogicFactory,
SelfdestructTransferFactory,
StableDebtTokenFactory,
UniswapLiquiditySwapAdapterFactory,
UniswapRepayAdapterFactory,
VariableDebtTokenFactory,
WalletBalanceProviderFactory,
WETH9MockedFactory,
WETHGatewayFactory,
FlashLiquidationAdapterFactory,
PermissionedVariableDebtTokenFactory,
PermissionedStableDebtTokenFactory,
PermissionedLendingPoolFactory,
PermissionedWETHGatewayFactory
} from '../types';
import {
withSaveAndVerify,
registerContractInJsonDb,
linkBytecode,
insertContractAddressInDb,
deployContract,
verifyContract,
getOptionalParamAddressPerNetwork,
} 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';
import { UiPoolDataProvider } from '../types';
import { eNetwork } from './types';
export const deployUiPoolDataProvider = async (
[incentivesController, aaveOracle]: [tEthereumAddress, tEthereumAddress],
verify?: boolean
) => {
const id = eContractid.UiPoolDataProvider;
const args: string[] = [incentivesController, aaveOracle];
const instance = await deployContract<UiPoolDataProvider>(id, args);
if (verify) {
await verifyContract(id, instance, args);
}
return instance;
};
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.connect(await getFirstSigner()).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.connect(await getFirstSigner()).deploy()
).deployed();
return withSaveAndVerify(validationLogic, eContractid.ValidationLogic, [], verify);
};
export const deployAaveLibraries = async (
verify?: boolean
): Promise<LendingPoolLibraryAddresses> => {
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, lendingPoolImpl?: eContractid) => {
const libraries = await deployAaveLibraries(verify);
let instance;
switch(lendingPoolImpl) {
case eContractid.PermissionedLendingPool:
instance = await new PermissionedLendingPoolFactory(libraries, await getFirstSigner()).deploy();
break;
case eContractid.LendingPool:
default:
instance = await new LendingPoolFactory(libraries, await getFirstSigner()).deploy();
}
await instance.deployTransaction.wait();
await insertContractAddressInDb(eContractid.LendingPoolImpl, instance.address);
return withSaveAndVerify(instance, 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, string],
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<MintableERC20> =>
withSaveAndVerify(
await new MintableERC20Factory(await getFirstSigner()).deploy(...args),
eContractid.MintableERC20,
args,
verify
);
export const deployMintableDelegationERC20 = async (
args: [string, string, string],
verify?: boolean
): Promise<MintableDelegationERC20> =>
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, tEthereumAddress, string, string],
verify: boolean
) => {
const instance = await withSaveAndVerify(
await new StableDebtTokenFactory(await getFirstSigner()).deploy(),
eContractid.StableDebtToken,
[],
verify
);
await instance.initialize(args[0], args[1], args[2], '18', args[3], args[4], '0x10');
return instance;
};
export const deployVariableDebtToken = async (
args: [tEthereumAddress, tEthereumAddress, tEthereumAddress, string, string],
verify: boolean
) => {
const instance = await withSaveAndVerify(
await new VariableDebtTokenFactory(await getFirstSigner()).deploy(),
eContractid.VariableDebtToken,
[],
verify
);
await instance.initialize(args[0], args[1], args[2], '18', args[3], args[4], '0x10');
return instance;
};
export const deployStableDebtTokenByType = async (type: string) => {
//if no instance type is provided, deploying the generic one by default
if(!type) {
return deployGenericStableDebtToken();
}
switch(type) {
case eContractid.StableDebtToken:
return deployGenericStableDebtToken();
case eContractid.PermissionedStableDebtToken:
return deployPermissionedStableDebtToken();
default:
console.log("Cant find the debt token type ", type);
throw "Invalid debt token type";
}
}
export const deployVariableDebtTokenByType = async (type: string, verify?: boolean) => {
//if no instance type is provided, deploying the generic one by default
if(!type) {
return deployGenericVariableDebtToken(verify);
}
switch(type) {
case eContractid.VariableDebtToken:
return deployGenericVariableDebtToken(verify);
case eContractid.PermissionedVariableDebtToken:
return deployPermissionedVariableDebtToken();
default:
console.log("[variable]Cant find token type ", type);
throw "Invalid debt token type";
}
}
export const deployPermissionedStableDebtToken = async () =>
withSaveAndVerify(
await new PermissionedStableDebtTokenFactory(await getFirstSigner()).deploy(),
eContractid.PermissionedStableDebtToken,
[],
false
);
export const deployPermissionedVariableDebtToken = async () =>
withSaveAndVerify(
await new PermissionedVariableDebtTokenFactory(await getFirstSigner()).deploy(),
eContractid.PermissionedVariableDebtToken,
[],
false
);
export const deployGenericStableDebtToken = async (verify?: boolean) =>
withSaveAndVerify(
await new StableDebtTokenFactory(await getFirstSigner()).deploy(),
eContractid.StableDebtToken,
[],
verify
);
export const deployGenericVariableDebtToken = async (verify?: boolean) =>
withSaveAndVerify(
await new VariableDebtTokenFactory(await getFirstSigner()).deploy(),
eContractid.VariableDebtToken,
[],
verify
);
export const deployGenericAToken = async (
[poolAddress, underlyingAssetAddress, treasuryAddress, incentivesController, name, symbol]: [
tEthereumAddress,
tEthereumAddress,
tEthereumAddress,
tEthereumAddress,
string,
string
],
verify: boolean
) => {
const instance = await withSaveAndVerify(
await new ATokenFactory(await getFirstSigner()).deploy(),
eContractid.AToken,
[],
verify
);
await instance.initialize(
poolAddress,
treasuryAddress,
underlyingAssetAddress,
incentivesController,
'18',
name,
symbol,
'0x10'
);
return instance;
};
export const deployGenericATokenImpl = async (verify: boolean) =>
withSaveAndVerify(
await new ATokenFactory(await getFirstSigner()).deploy(),
eContractid.AToken,
[],
verify
);
export const deployDelegationAwareAToken = async (
[pool, underlyingAssetAddress, treasuryAddress, incentivesController, name, symbol]: [
tEthereumAddress,
tEthereumAddress,
tEthereumAddress,
tEthereumAddress,
string,
string
],
verify: boolean
) => {
const instance = await withSaveAndVerify(
await new DelegationAwareATokenFactory(await getFirstSigner()).deploy(),
eContractid.DelegationAwareAToken,
[],
verify
);
await instance.initialize(
pool,
treasuryAddress,
underlyingAssetAddress,
incentivesController,
'18',
name,
symbol,
'0x10'
);
return instance;
};
export const deployDelegationAwareATokenImpl = async (verify: boolean) =>
withSaveAndVerify(
await new DelegationAwareATokenFactory(await getFirstSigner()).deploy(),
eContractid.DelegationAwareAToken,
[],
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 = (<any>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<IReserveParams>].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], verify?: boolean) =>
withSaveAndVerify(
await new WETHGatewayFactory(await getFirstSigner()).deploy(...args),
eContractid.WETHGateway,
args,
verify
);
export const deployPermissionedWETHGateway = async (args: [tEthereumAddress], verify?: boolean) =>
withSaveAndVerify(
await new PermissionedWETHGatewayFactory(await getFirstSigner()).deploy(...args),
eContractid.PermissionedWETHGateway,
args,
verify
);
export const authorizeWETHGateway = async (
wethGateWay: tEthereumAddress,
lendingPool: tEthereumAddress
) =>
await new WETHGatewayFactory(await getFirstSigner())
.attach(wethGateWay)
.authorizeLendingPool(lendingPool);
export const deployMockStableDebtToken = async (
args: [tEthereumAddress, tEthereumAddress, tEthereumAddress, string, string, string],
verify?: boolean
) => {
const instance = await withSaveAndVerify(
await new MockStableDebtTokenFactory(await getFirstSigner()).deploy(),
eContractid.MockStableDebtToken,
[],
verify
);
await instance.initialize(args[0], args[1], args[2], '18', args[3], args[4], args[5]);
return instance;
};
export const deployWETHMocked = async (verify?: boolean) =>
withSaveAndVerify(
await new WETH9MockedFactory(await getFirstSigner()).deploy(),
eContractid.WETHMocked,
[],
verify
);
export const deployMockVariableDebtToken = async (
args: [tEthereumAddress, tEthereumAddress, tEthereumAddress, string, string, string],
verify?: boolean
) => {
const instance = await withSaveAndVerify(
await new MockVariableDebtTokenFactory(await getFirstSigner()).deploy(),
eContractid.MockVariableDebtToken,
[],
verify
);
await instance.initialize(args[0], args[1], args[2], '18', args[3], args[4], args[5]);
return instance;
};
export const deployMockAToken = async (
args: [
tEthereumAddress,
tEthereumAddress,
tEthereumAddress,
tEthereumAddress,
string,
string,
string
],
verify?: boolean
) => {
const instance = await withSaveAndVerify(
await new MockATokenFactory(await getFirstSigner()).deploy(),
eContractid.MockAToken,
[],
verify
);
await instance.initialize(args[0], args[2], args[1], args[3], '18', args[4], args[5], args[6]);
return instance;
};
export const deploySelfdestructTransferMock = async (verify?: boolean) =>
withSaveAndVerify(
await new SelfdestructTransferFactory(await getFirstSigner()).deploy(),
eContractid.SelfdestructTransferMock,
[],
verify
);
export const deployMockUniswapRouter = async (verify?: boolean) =>
withSaveAndVerify(
await new MockUniswapV2Router02Factory(await getFirstSigner()).deploy(),
eContractid.MockUniswapV2Router02,
[],
verify
);
export const deployUniswapLiquiditySwapAdapter = async (
args: [tEthereumAddress, tEthereumAddress, tEthereumAddress],
verify?: boolean
) =>
withSaveAndVerify(
await new UniswapLiquiditySwapAdapterFactory(await getFirstSigner()).deploy(...args),
eContractid.UniswapLiquiditySwapAdapter,
args,
verify
);
export const deployUniswapRepayAdapter = async (
args: [tEthereumAddress, tEthereumAddress, tEthereumAddress],
verify?: boolean
) =>
withSaveAndVerify(
await new UniswapRepayAdapterFactory(await getFirstSigner()).deploy(...args),
eContractid.UniswapRepayAdapter,
args,
verify
);
export const deployFlashLiquidationAdapter = async (
args: [tEthereumAddress, tEthereumAddress, tEthereumAddress],
verify?: boolean
) =>
withSaveAndVerify(
await new FlashLiquidationAdapterFactory(await getFirstSigner()).deploy(...args),
eContractid.FlashLiquidationAdapter,
args,
verify
);
export const chooseATokenDeployment = (id: eContractid) => {
switch (id) {
case eContractid.AToken:
return deployGenericATokenImpl;
case eContractid.DelegationAwareAToken:
return deployDelegationAwareATokenImpl;
default:
throw Error(`Missing aToken implementation deployment script for: ${id}`);
}
};
export const deployATokenImplementations = async (
pool: ConfigNames,
reservesConfig: { [key: string]: IReserveParams },
verify = false
) => {
const poolConfig = loadPoolConfig(pool);
const network = <eNetwork>DRE.network.name;
// Obtain the different AToken implementations of all reserves inside the Market config
const aTokenImplementations = [
...Object.entries(reservesConfig).reduce<Set<eContractid>>((acc, [, entry]) => {
acc.add(entry.aTokenImpl);
return acc;
}, new Set<eContractid>()),
];
for (let x = 0; x < aTokenImplementations.length; x++) {
const aTokenAddress = getOptionalParamAddressPerNetwork(
poolConfig[aTokenImplementations[x].toString()],
network
);
if (!notFalsyOrZeroAddress(aTokenAddress)) {
const deployImplementationMethod = chooseATokenDeployment(aTokenImplementations[x]);
console.log(`Deploying implementation`, aTokenImplementations[x]);
await deployImplementationMethod(verify);
}
}
// Debt tokens, for now all Market configs follows same implementations
const genericStableDebtTokenAddress = getOptionalParamAddressPerNetwork(
poolConfig.StableDebtTokenImplementation,
network
);
const geneticVariableDebtTokenAddress = getOptionalParamAddressPerNetwork(
poolConfig.VariableDebtTokenImplementation,
network
);
if (!notFalsyOrZeroAddress(genericStableDebtTokenAddress)) {
await deployGenericStableDebtToken(verify);
}
if (!notFalsyOrZeroAddress(geneticVariableDebtTokenAddress)) {
await deployGenericVariableDebtToken(verify);
}
};
export const deployRateStrategy = async (
strategyName: string,
args: [tEthereumAddress, string, string, string, string, string, string],
verify: boolean
): Promise<tEthereumAddress> => {
switch (strategyName) {
default:
return await (
await deployDefaultReserveInterestRateStrategy(args, verify)
).address;
}
};
export const deployMockParaSwapAugustus = async (verify?: boolean) =>
withSaveAndVerify(
await new MockParaSwapAugustusFactory(await getFirstSigner()).deploy(),
eContractid.MockParaSwapAugustus,
[],
verify
);
export const deployMockParaSwapAugustusRegistry = async (
args: [tEthereumAddress],
verify?: boolean
) =>
withSaveAndVerify(
await new MockParaSwapAugustusRegistryFactory(await getFirstSigner()).deploy(...args),
eContractid.MockParaSwapAugustusRegistry,
args,
verify
);
export const deployParaSwapLiquiditySwapAdapter = async (
args: [tEthereumAddress, tEthereumAddress],
verify?: boolean
) =>
withSaveAndVerify(
await new ParaSwapLiquiditySwapAdapterFactory(await getFirstSigner()).deploy(...args),
eContractid.ParaSwapLiquiditySwapAdapter,
args,
verify
);