import {Contract, Signer, utils} from "ethers"; import {getDb, BRE} from "./misc-utils"; import { tEthereumAddress, eContractid, tStringTokenSmallUnits, eEthereumNetwork, AavePools, iParamsPerNetwork, iParamsPerPool, } from "./types"; import {Example} from "../types/Example"; import {LendingPoolAddressesProvider} from "../types/LendingPoolAddressesProvider"; import {MintableErc20} from "../types/MintableErc20"; import {LendingPoolAddressesProviderRegistry} from "../types/LendingPoolAddressesProviderRegistry"; import {FeeProvider} from "../types/FeeProvider"; import {LendingPoolParametersProvider} from "../types/LendingPoolParametersProvider"; import {LendingPoolCore} from "../types/LendingPoolCore"; import {LendingPoolConfigurator} from "../types/LendingPoolConfigurator"; import {readArtifact} from "@nomiclabs/buidler/plugins"; import {Artifact} from "@nomiclabs/buidler/types"; import {LendingPoolDataProvider} from "../types/LendingPoolDataProvider"; 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 {MockOneSplit} from "../types/MockOneSplit"; import {OneSplitAdapter} from "../types/OneSplitAdapter"; 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"; 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; }; const getContract = async ( contractName: string, address: string ): Promise => (await BRE.ethers.getContractAt(contractName, address)) as ContractType; export const deployExampleContract = async () => await deployContract(eContractid.Example, []); 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 deployLendingPoolParametersProvider = async () => await deployContract( eContractid.LendingPoolParametersProvider, [] ); export const deployLendingPoolCore = async () => { const CoreLibraryFactory = await BRE.ethers.getContractFactory( eContractid.CoreLibrary ); const coreLibrary = await CoreLibraryFactory.deploy(); await coreLibrary.deployed(); const lendingPoolCoreArtifact = await readArtifact( BRE.config.paths.artifacts, eContractid.LendingPoolCore ); const linkedBytecode = linkBytecode(lendingPoolCoreArtifact, { [eContractid.CoreLibrary]: coreLibrary.address, }); const LendingPoolCoreFactory = await BRE.ethers.getContractFactory( lendingPoolCoreArtifact.abi, linkedBytecode ); const lendingPoolCore = await LendingPoolCoreFactory.deploy({ gasLimit: 9500000, }); return (await lendingPoolCore.deployed()) as LendingPoolCore; }; export const deployLendingPoolConfigurator = async () => await deployContract( eContractid.LendingPoolConfigurator, [] ); export const deployLendingPoolDataProvider = async () => await deployContract( eContractid.LendingPoolDataProvider, [] ); export const deployLendingPool = async () => await deployContract(eContractid.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 () => await deployContract( eContractid.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 deployMockOneSplit = async (tokenToBurn: tEthereumAddress) => await deployContract(eContractid.MockOneSplit, [tokenToBurn]); export const deployOneSplitAdapter = async () => await deployContract(eContractid.OneSplitAdapter, []); 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 ([ reserve, addressesProvider, baseVariableBorrowRate, variableSlope1, variableSlope2, stableSlope1, stableSlope2, ]: [ tEthereumAddress, tEthereumAddress, string, string, string, string, string ]) => await deployContract( eContractid.DefaultReserveInterestRateStrategy, [ reserve, addressesProvider, baseVariableBorrowRate, variableSlope1, variableSlope2, stableSlope1, stableSlope2, ] ); 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) => { return await getContract( eContractid.LendingPool, address || ( await getDb() .get(`${eContractid.LendingPool}.${BRE.network.name}`) .value() ).address ); }; export const getLendingPoolCore = async (address?: tEthereumAddress) => { const CoreLibraryFactory = await BRE.ethers.getContractFactory( eContractid.CoreLibrary ); const coreLibrary = await CoreLibraryFactory.deploy(); await coreLibrary.deployed(); const lendingPoolCoreArtifact = await readArtifact( BRE.config.paths.artifacts, eContractid.LendingPoolCore ); const linkedBytecode = linkBytecode(lendingPoolCoreArtifact, { [eContractid.CoreLibrary]: coreLibrary.address, }); const LendingPoolCoreFactory = await BRE.ethers.getContractFactory( lendingPoolCoreArtifact.abi, linkedBytecode ); return ( await LendingPoolCoreFactory.attach( address || ( await getDb() .get(`${eContractid.LendingPoolCore}.${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 getLendingPoolParametersProvider = async ( address?: tEthereumAddress ) => { return await getContract( eContractid.LendingPoolParametersProvider, address || ( await getDb() .get( `${eContractid.LendingPoolParametersProvider}.${BRE.network.name}` ) .value() ).address ); }; export const getLendingPoolDataProvider = async ( address?: tEthereumAddress ) => { return await getContract( eContractid.LendingPoolDataProvider, address || ( await getDb() .get(`${eContractid.LendingPoolDataProvider}.${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 ); }; 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 = new BigNumber(18); if (!isEth) { const token = await getIErc20Detailed(tokenAddress); decimals = new BigNumber(await token.decimals()); } const currencyUnit = new BigNumber(10).pow(decimals); const amountInCurrencyDecimals = new BigNumber(amount).multipliedBy( currencyUnit ); return amountInCurrencyDecimals.toFixed(); }; 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(); };