UNPKG

hardhat-deploy

Version:

Hardhat plugin for replicable smart contract deployments and easy testing across multiple EVM chains, with support for proxies, diamonds, named accounts, and deployment fixtures

258 lines 9.55 kB
import { configVariable } from 'hardhat/config'; import { enhanceEnvIfNeeded } from 'rocketh'; import { loadEnvironmentFromFiles, chainByCanonicalName } from '@rocketh/node'; export function setupHardhatDeploy(extensions) { async function loadEnvironmentFromHardhatWithExtensions(required) { const env = await loadEnvironmentFromHardhat(required); return enhanceEnvIfNeeded(env, extensions); } return { loadEnvironmentFromHardhat: loadEnvironmentFromHardhatWithExtensions, }; } export async function generateForkConfig(params) { const fork = process.env.HARDHAT_FORK; const connection = params.connection || fork ? await params.hre.network.connect({ network: 'fork' }) : await params.hre.network.connect(); let provider = connection.provider; let environment = connection.networkName; let forkChainId; if (fork) { // if (options?.useChainIdOfForkedNetwork) { // const forkNetworkConfig = params.hre.config.networks[fork]; // if (forkNetworkConfig.type === 'edr-simulated') { // forkChainId = forkNetworkConfig.chainId; // } else if (forkNetworkConfig.chainId) { // forkChainId = forkNetworkConfig.chainId; // } else { // if ('url' in forkNetworkConfig) { // const url = await forkNetworkConfig.url.getUrl(); // const response = await fetch(url, { // method: 'POST', // headers: { // 'Content-Type': 'application/json', // }, // body: JSON.stringify({ // jsonrpc: '2.0', // id: 1, // method: 'eth_chainId', // params: [], // }), // }); // const json = (await response.json()) as {result: string}; // forkChainId = Number(json.result); // } else { // throw new Error(`cannot fetch chainId`); // } // } // } environment = { fork, }; } if (forkChainId) { const originalProvider = provider; const chainId = forkChainId; async function request(args) { if (args.method === 'eth_chainId') { return `0x${chainId.toString(16)}`; } return originalProvider.request(args); } provider = new Proxy(originalProvider, { get: function (target, property, receiver) { switch (property) { case 'request': return request; default: return originalProvider[property]; } }, }); } return { provider, environment, connection, isFork: !!fork }; } export async function loadEnvironmentFromHardhat(params) { const { connection, environment, provider, isFork } = await generateForkConfig(params); const isEDR = connection.networkConfig.type === 'edr-simulated' ? true : undefined; // console.log(`loading environments...`); return loadEnvironmentFromFiles({ provider, environment, extra: { connection, }, saveDeployments: isFork ? false : undefined, autoImpersonate: isEDR, }); } function getVariable(prefix, name) { // We transform dash into underscore as dash are not supported everywhere in env var names const variableName = (prefix + name).replaceAll('-', '_'); let uri = process.env[variableName]; if (uri === 'SECRET') { return configVariable(`SECRET_${variableName}`); } else if (uri?.startsWith('SECRET:')) { const splitted = uri.split(':'); if (splitted.length !== 2) { throw new Error(`invalid secret uri ${uri}`); } return configVariable(`SECRET_${prefix + splitted[1]}`); } return uri; } export function getRPC(networkName) { let uri = getVariable('ETH_NODE_URI_', networkName); if (uri && uri !== '') { return uri; } uri = process.env.ETH_NODE_URI; if (uri) { uri = uri.replace('{{networkName}}', networkName); } if (!uri || uri === '') { if (networkName === 'localhost') { return 'http://localhost:8545'; } return uri; // throw new Error(`no uri specified or for network ${networkName}`); } if (uri.indexOf('{{') >= 0) { throw new Error(`invalid uri or network not supported by node provider : ${uri}`); } return uri; } export function getMnemonic(networkName, doNotDefault) { if (networkName) { const mnemonic = getVariable('MNEMONIC_', networkName); if (mnemonic && mnemonic !== '') { return mnemonic; } } const mnemonic = process.env.MNEMONIC; if (!mnemonic || mnemonic === '') { if (doNotDefault) { return undefined; } return 'test test test test test test test test test test test junk'; } return mnemonic; } export function getAccounts(networkName, doNotDefault) { const mnemonic = getMnemonic(networkName, doNotDefault); if (!mnemonic) { return undefined; } return { mnemonic }; } export function addNetworksFromEnv(networks) { const newNetworks = networks ? { ...networks } : {}; const allEnv = Object.keys(process.env); for (const envKey of allEnv) { if (envKey.startsWith(`ETH_NODE_URI_`) && envKey.length > `ETH_NODE_URI_`.length) { const networkName = envKey.slice(`ETH_NODE_URI_`.length); const url = getRPC(networkName); if (!newNetworks[networkName]) { if (url) { newNetworks[networkName] = { type: 'http', url, accounts: getAccounts(networkName), }; } else { // TODO ? // console.error(`no url for network ${networkName}`); } } else { console.error(`duplicated network ${networkName}`); } } } return newNetworks; } const listOfNetworkNamesWithTestAccountAllowed = ['hardhat', 'localhost', 'memory', 'test']; export function addNetworksFromKnownList(networks) { const newNetworks = networks ? { ...networks } : {}; const canonicalNames = Object.keys(chainByCanonicalName); for (const canonicalName of canonicalNames) { const chain = chainByCanonicalName[canonicalName]; const url = getRPC(canonicalName) || chain.rpcUrls.default.http[0]; if (!newNetworks[canonicalName]) { if (url) { newNetworks[canonicalName] = { type: 'http', url, accounts: getAccounts(canonicalName, !listOfNetworkNamesWithTestAccountAllowed.includes(canonicalName)), chainType: chain.chainType === 'op-stack' ? 'op' : undefined, chainId: chain.id, }; } else { console.error(`no url for chain ${canonicalName}`); } } else { // console.error(`duplicated chain ${canonicalName}`); } } return newNetworks; } export function addForkConfiguration(networks) { const currentNetworkName = process.env.HARDHAT_FORK; let forkURL; let hardhatAccounts; if (currentNetworkName && currentNetworkName !== 'hardhat' && currentNetworkName !== 'edr' && currentNetworkName !== 'edr-simulated' && currentNetworkName !== 'memory') { const currentNetwork = networks[currentNetworkName]; if (currentNetwork) { if (currentNetwork.type === 'http') { forkURL = currentNetwork.url; if (currentNetwork.accounts && typeof currentNetwork.accounts === 'object' && 'mnemonic' in currentNetwork.accounts) { hardhatAccounts = currentNetwork.accounts; } // else if (currentNetwork.accounts && Array.isArray(currentNetwork.accounts)) { // hardhatAccounts = currentNetwork.accounts.map((v) => ({ // balance: '10000000000000000000000', // privateKey: v, // })); // } } } if (!forkURL) { const errorMessage = `no rpc URL found for ${currentNetworkName}, cannot fork`; throw new Error(errorMessage); // console.error(errorMessage); } const existingForkConfiguration = networks.fork && networks.fork.type === 'edr-simulated' ? networks.fork : { type: 'edr-simulated', chainType: 'l1' }; const forkNetwork = { ...existingForkConfiguration, ...{ accounts: hardhatAccounts || existingForkConfiguration?.accounts, forking: forkURL ? { url: forkURL, blockNumber: process.env.HARDHAT_FORK_NUMBER ? parseInt(process.env.HARDHAT_FORK_NUMBER) : undefined, } : undefined, }, }; const newNetworks = { ...networks, fork: forkNetwork, }; return newNetworks; } return networks; } //# sourceMappingURL=helpers.js.map