import {Contract, Signer, utils, ethers} from "ethers"; import {getDb, BRE} from "./misc-utils"; import { tEthereumAddress, eContractid, tStringTokenSmallUnits, eEthereumNetwork, AavePools, iParamsPerNetwork, iParamsPerPool, } from "./types"; import {LendingPoolAddressesProvider} from "../types/LendingPoolAddressesProvider"; import {MintableErc20} from "../types/MintableErc20"; import {LendingPoolAddressesProviderRegistry} from "../types/LendingPoolAddressesProviderRegistry"; import {FeeProvider} from "../types/FeeProvider"; import {LendingPoolConfigurator} from "../types/LendingPoolConfigurator"; import {readArtifact} from "@nomiclabs/buidler/plugins"; import {Artifact} from "@nomiclabs/buidler/types"; import {LendingPool} from "../types/LendingPool"; import {PriceOracle} from "../types/PriceOracle"; import {MockAggregator} from "../types/MockAggregator"; import {LendingRateOracle} from "../types/LendingRateOracle"; import {DefaultReserveInterestRateStrategy} from "../types/DefaultReserveInterestRateStrategy"; import {LendingPoolLiquidationManager} from "../types/LendingPoolLiquidationManager"; import {TokenDistributor} from "../types/TokenDistributor"; import {InitializableAdminUpgradeabilityProxy} from "../types/InitializableAdminUpgradeabilityProxy"; import {MockFlashLoanReceiver} from "../types/MockFlashLoanReceiver"; import {WalletBalanceProvider} from "../types/WalletBalanceProvider"; import {AToken} from "../types/AToken"; import {AaveProtocolTestHelpers} from "../types/AaveProtocolTestHelpers"; import {MOCK_ETH_ADDRESS} from "./constants"; import BigNumber from "bignumber.js"; import {Ierc20Detailed} from "../types/Ierc20Detailed"; import { StableDebtToken } from "../types/StableDebtToken"; import { VariableDebtToken } from "../types/VariableDebtToken"; export const registerContractInJsonDb = async ( contractId: string, contractInstance: Contract ) => { const currentNetwork = BRE.network.name; if ( currentNetwork !== "buidlerevm" && currentNetwork !== "soliditycoverage" ) { console.log(`*** ${contractId} ***\n`); console.log(`Network: ${currentNetwork}`); console.log(`tx: ${contractInstance.deployTransaction.hash}`); console.log(`contract address: ${contractInstance.address}`); console.log(`deployer address: ${contractInstance.deployTransaction.from}`); console.log(`gas price: ${contractInstance.deployTransaction.gasPrice}`); console.log(`gas used: ${contractInstance.deployTransaction.gasLimit}`); console.log(`\n******`); console.log(); } await getDb() .set(`${contractId}.${currentNetwork}`, { address: contractInstance.address, deployer: contractInstance.deployTransaction.from, }) .write(); }; export const insertContractAddressInDb = async ( id: eContractid, address: tEthereumAddress ) => await getDb() .set(`${id}.${BRE.network.name}`, { address, }) .write(); export const getEthersSigners = async (): Promise => await Promise.all(await BRE.ethers.signers()); export const getEthersSignersAddresses = async (): Promise< tEthereumAddress[] > => await Promise.all( (await BRE.ethers.signers()).map((signer) => signer.getAddress()) ); export const getCurrentBlock = async () => { return BRE.ethers.provider.getBlockNumber(); }; export const decodeAbiNumber = (data: string): number => parseInt(utils.defaultAbiCoder.decode(["uint256"], data).toString()); const deployContract = async ( contractName: string, args: any[] ): Promise => { const contract = (await (await BRE.ethers.getContract(contractName)).deploy( ...args )) as ContractType; await registerContractInJsonDb(contractName, contract); return contract; }; export const getContract = async ( contractName: string, address: string ): Promise => (await BRE.ethers.getContractAt(contractName, address)) as ContractType; export const deployLendingPoolAddressesProvider = async () => await deployContract( eContractid.LendingPoolAddressesProvider, [] ); export const deployLendingPoolAddressesProviderRegistry = async () => await deployContract( eContractid.LendingPoolAddressesProviderRegistry, [] ); export const deployFeeProvider = async () => await deployContract(eContractid.FeeProvider, []); export const deployLendingPoolConfigurator = async () => await deployContract( eContractid.LendingPoolConfigurator, [] ); const deployLibrary = async(libraryId: eContractid) => { const factory = await BRE.ethers.getContractFactory( libraryId ); const library = await factory.deploy(); await library.deployed(); return library } export const linkLibrariesToArtifact = async(artifact: Artifact) => { const userLogic = await deployLibrary(eContractid.UserLogic); const reserveLogic = await deployLibrary(eContractid.ReserveLogic); const genericLogicArtifact = await readArtifact( BRE.config.paths.artifacts, eContractid.GenericLogic ); const linkedGenericLogicByteCode = linkBytecode(genericLogicArtifact, { [eContractid.UserLogic]: userLogic.address, [eContractid.ReserveLogic]: reserveLogic.address, }); const genericLogicFactory = await BRE.ethers.getContractFactory( genericLogicArtifact.abi, linkedGenericLogicByteCode ); const genericLogic = await (await genericLogicFactory.deploy()).deployed(); const validationLogicArtifact = await readArtifact( BRE.config.paths.artifacts, eContractid.ValidationLogic ); const linkedValidationLogicByteCode = linkBytecode(validationLogicArtifact, { [eContractid.UserLogic]: userLogic.address, [eContractid.ReserveLogic]: reserveLogic.address, [eContractid.GenericLogic]: genericLogic.address, }); const validationLogicFactory = await BRE.ethers.getContractFactory( validationLogicArtifact.abi, linkedValidationLogicByteCode ); const validationLogic = await (await validationLogicFactory.deploy()).deployed(); const linkedBytecode = linkBytecode(artifact, { [eContractid.UserLogic]: userLogic.address, [eContractid.ReserveLogic] : reserveLogic.address, [eContractid.GenericLogic] : genericLogic.address, [eContractid.ValidationLogic] : validationLogic.address }); const factory = await BRE.ethers.getContractFactory( artifact.abi, linkedBytecode ); return factory; } export const deployLendingPool = async () => { const lendingPoolArtifact = await readArtifact( BRE.config.paths.artifacts, eContractid.LendingPool ); const factory = await linkLibrariesToArtifact(lendingPoolArtifact); const lendingPool = await factory.deploy(); return (await lendingPool.deployed()) as LendingPool; } export const deployPriceOracle = async () => await deployContract(eContractid.PriceOracle, []); export const deployMockAggregator = async (price: tStringTokenSmallUnits) => await deployContract(eContractid.MockAggregator, [price]); export const deployChainlinkProxyPriceProvider = async ([ assetsAddresses, sourcesAddresses, fallbackOracleAddress, ]: [tEthereumAddress[], tEthereumAddress[], tEthereumAddress]) => await deployContract( eContractid.ChainlinkProxyPriceProvider, [assetsAddresses, sourcesAddresses, fallbackOracleAddress] ); export const deployLendingRateOracle = async () => await deployContract(eContractid.LendingRateOracle, []); export const deployLendingPoolLiquidationManager = async () => { const liquidationManagerArtifact = await readArtifact( BRE.config.paths.artifacts, eContractid.LendingPoolLiquidationManager ); const factory = await linkLibrariesToArtifact(liquidationManagerArtifact); const liquidationManager = await factory.deploy(); return (await liquidationManager.deployed()) as LendingPoolLiquidationManager; } export const deployTokenDistributor = async () => await deployContract(eContractid.TokenDistributor, []); export const deployInitializableAdminUpgradeabilityProxy = async () => await deployContract( eContractid.InitializableAdminUpgradeabilityProxy, [] ); export const deployMockFlashLoanReceiver = async ( addressesProvider: tEthereumAddress ) => await deployContract( eContractid.MockFlashLoanReceiver, [addressesProvider] ); export const deployWalletBalancerProvider = async ( addressesProvider: tEthereumAddress ) => await deployContract( eContractid.WalletBalanceProvider, [addressesProvider] ); export const deployAaveProtocolTestHelpers = async ( addressesProvider: tEthereumAddress ) => await deployContract( eContractid.AaveProtocolTestHelpers, [addressesProvider] ); export const deployMintableErc20 = async ([name, symbol, decimals]: [ string, string, number ]) => await deployContract(eContractid.MintableERC20, [ name, symbol, decimals, ]); export const deployDefaultReserveInterestRateStrategy = async ([ addressesProvider, baseVariableBorrowRate, variableSlope1, variableSlope2, stableSlope1, stableSlope2, ]: [ tEthereumAddress, string, string, string, string, string ]) => await deployContract( eContractid.DefaultReserveInterestRateStrategy, [ addressesProvider, baseVariableBorrowRate, variableSlope1, variableSlope2, stableSlope1, stableSlope2, ] ); export const deployStableDebtToken = async ([ name, symbol, decimals, underlyingAsset, addressesProvider ]: [ string, string, string, tEthereumAddress, tEthereumAddress ]) =>{ const token = await deployContract( eContractid.StableDebtToken, [] ); await token.init( name, symbol, decimals, underlyingAsset, addressesProvider ); return token; } export const deployVariableDebtToken = async ([ name, symbol, decimals, underlyingAsset, addressesProvider ]: [ string, string, string, tEthereumAddress, tEthereumAddress ]) => { const token = await deployContract( eContractid.VariableDebtToken, [] ); await token.init( name, symbol, decimals, underlyingAsset, addressesProvider ); return token; } export const getLendingPoolAddressesProvider = async ( address?: tEthereumAddress ) => { return await getContract( eContractid.LendingPoolAddressesProvider, address || ( await getDb() .get( `${eContractid.LendingPoolAddressesProvider}.${BRE.network.name}` ) .value() ).address ); }; export const getLendingPoolConfiguratorProxy = async ( address?: tEthereumAddress ) => { return await getContract( eContractid.LendingPoolConfigurator, address || ( await getDb() .get(`${eContractid.LendingPoolConfigurator}.${BRE.network.name}`) .value() ).address ); }; export const getLendingPool = async (address?: tEthereumAddress) => { const lendingPoolArtifact = await readArtifact( BRE.config.paths.artifacts, eContractid.LendingPool ); const factory = await linkLibrariesToArtifact(lendingPoolArtifact); return (await factory.attach( address || ( await getDb() .get(`${eContractid.LendingPool}.${BRE.network.name}`) .value() ).address )); }; export const getFeeProvider = async (address?: tEthereumAddress) => { return await getContract( eContractid.FeeProvider, address || ( await getDb() .get(`${eContractid.FeeProvider}.${BRE.network.name}`) .value() ).address ); }; export const getPriceOracle = async (address?: tEthereumAddress) => { return await getContract( eContractid.PriceOracle, address || ( await getDb() .get(`${eContractid.PriceOracle}.${BRE.network.name}`) .value() ).address ); }; export const getAToken = async (address?: tEthereumAddress) => { return await getContract( eContractid.AToken, address || (await getDb().get(`${eContractid.AToken}.${BRE.network.name}`).value()) .address ); }; export const getMintableErc20 = async (address: tEthereumAddress) => { return await getContract( eContractid.MintableERC20, address || ( await getDb() .get(`${eContractid.MintableERC20}.${BRE.network.name}`) .value() ).address ); }; export const getIErc20Detailed = async (address: tEthereumAddress) => { return await getContract( eContractid.IERC20Detailed, address || ( await getDb() .get(`${eContractid.IERC20Detailed}.${BRE.network.name}`) .value() ).address ); }; export const getAaveProtocolTestHelpers = async ( address?: tEthereumAddress ) => { return await getContract( eContractid.AaveProtocolTestHelpers, address || ( await getDb() .get(`${eContractid.AaveProtocolTestHelpers}.${BRE.network.name}`) .value() ).address ); }; export const getInterestRateStrategy = async (address?: tEthereumAddress) => { return await getContract( eContractid.DefaultReserveInterestRateStrategy, address || ( await getDb() .get( `${eContractid.DefaultReserveInterestRateStrategy}.${BRE.network.name}` ) .value() ).address ); }; export const getMockFlashLoanReceiver = async (address?: tEthereumAddress) => { return await getContract( eContractid.MockFlashLoanReceiver, address || ( await getDb() .get(`${eContractid.MockFlashLoanReceiver}.${BRE.network.name}`) .value() ).address ); }; export const getTokenDistributor = async (address?: tEthereumAddress) => { return await getContract( eContractid.TokenDistributor, address || ( await getDb() .get(`${eContractid.TokenDistributor}.${BRE.network.name}`) .value() ).address ); }; export const getLendingRateOracle = async (address?: tEthereumAddress) => { return await getContract( eContractid.LendingRateOracle, address || ( await getDb() .get(`${eContractid.LendingRateOracle}.${BRE.network.name}`) .value() ).address ); }; const linkBytecode = (artifact: Artifact, libraries: any) => { let bytecode = artifact.bytecode; for (const [fileName, fileReferences] of Object.entries( artifact.linkReferences )) { for (const [libName, fixups] of Object.entries(fileReferences)) { const addr = libraries[libName]; if (addr === undefined) { continue; } for (const fixup of fixups) { bytecode = bytecode.substr(0, 2 + fixup.start * 2) + addr.substr(2) + bytecode.substr(2 + (fixup.start + fixup.length) * 2); } } } return bytecode; }; export const getParamPerNetwork = ( {kovan, ropsten, main}: iParamsPerNetwork, network: eEthereumNetwork ) => { switch (network) { case eEthereumNetwork.kovan: return kovan; case eEthereumNetwork.ropsten: return ropsten; case eEthereumNetwork.main: return main; default: return main; } }; export const getParamPerPool = ( {proto, secondary}: iParamsPerPool, pool: AavePools ) => { switch (pool) { case AavePools.proto: return proto; case AavePools.secondary: return secondary; default: return proto; } }; export const convertToCurrencyDecimals = async ( tokenAddress: tEthereumAddress, amount: string ) => { const isEth = tokenAddress === MOCK_ETH_ADDRESS; let decimals = "18"; if (!isEth) { const token = await getIErc20Detailed(tokenAddress); decimals = (await token.decimals()).toString(); } return ethers.utils.parseUnits(amount, decimals); }; export const convertToCurrencyUnits = async ( tokenAddress: string, amount: string ) => { const isEth = tokenAddress === MOCK_ETH_ADDRESS; let decimals = new BigNumber(18); if (!isEth) { const token = await getIErc20Detailed(tokenAddress); decimals = new BigNumber(await token.decimals()); } const currencyUnit = new BigNumber(10).pow(decimals); const amountInCurrencyUnits = new BigNumber(amount).div(currencyUnit); return amountInCurrencyUnits.toFixed(); };