UNPKG

hardhat

Version:

Hardhat is an extensible developer tool that helps smart contract developers increase productivity by reliably bringing together the tools they want.

221 lines 9.25 kB
import { MineOrdering, FRONTIER, HOMESTEAD, DAO_FORK, TANGERINE, SPURIOUS_DRAGON, BYZANTIUM, CONSTANTINOPLE, PETERSBURG, ISTANBUL, MUIR_GLACIER, BERLIN, LONDON, ARROW_GLACIER, GRAY_GLACIER, MERGE, SHANGHAI, CANCUN, PRAGUE, BEDROCK, REGOLITH, CANYON, ECOTONE, FJORD, GRANITE, HOLOCENE, } from "@nomicfoundation/edr"; import { getUnprefixedHexString } from "@nomicfoundation/hardhat-utils/hex"; import { GENERIC_CHAIN_TYPE, L1_CHAIN_TYPE, OPTIMISM_CHAIN_TYPE, } from "../../../../constants.js"; import { FixedValueConfigurationVariable } from "../../../../core/configuration-variables.js"; import { derivePrivateKeys } from "../../accounts/derive-private-keys.js"; import { DEFAULT_EDR_NETWORK_BALANCE, EDR_NETWORK_DEFAULT_PRIVATE_KEYS, isDefaultEdrNetworkHDAccountsConfig, } from "../edr-provider.js"; import { L1HardforkName, OpHardforkName } from "../types/hardfork.js"; import { getL1HardforkName, getOpHardforkName } from "./hardfork.js"; export function hardhatHardforkToEdrSpecId(hardfork, chainType) { return chainType === OPTIMISM_CHAIN_TYPE ? hardhatOpHardforkToEdrSpecId(hardfork) : hardhatL1HardforkToEdrSpecId(hardfork); } function hardhatOpHardforkToEdrSpecId(hardfork) { const hardforkName = getOpHardforkName(hardfork); switch (hardforkName) { case OpHardforkName.BEDROCK: return BEDROCK; case OpHardforkName.REGOLITH: return REGOLITH; case OpHardforkName.CANYON: return CANYON; case OpHardforkName.ECOTONE: return ECOTONE; case OpHardforkName.FJORD: return FJORD; case OpHardforkName.GRANITE: return GRANITE; case OpHardforkName.HOLOCENE: return HOLOCENE; // eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check -- trust but verify default: const _exhaustiveCheck = hardforkName; throw new Error( // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- we want to print the fork `Unknown hardfork name '${hardforkName}', this shouldn't happen`); } } function hardhatL1HardforkToEdrSpecId(hardfork) { const hardforkName = getL1HardforkName(hardfork); switch (hardforkName) { case L1HardforkName.FRONTIER: return FRONTIER; case L1HardforkName.HOMESTEAD: return HOMESTEAD; case L1HardforkName.DAO: return DAO_FORK; case L1HardforkName.TANGERINE_WHISTLE: return TANGERINE; case L1HardforkName.SPURIOUS_DRAGON: return SPURIOUS_DRAGON; case L1HardforkName.BYZANTIUM: return BYZANTIUM; case L1HardforkName.CONSTANTINOPLE: return CONSTANTINOPLE; case L1HardforkName.PETERSBURG: return PETERSBURG; case L1HardforkName.ISTANBUL: return ISTANBUL; case L1HardforkName.MUIR_GLACIER: return MUIR_GLACIER; case L1HardforkName.BERLIN: return BERLIN; case L1HardforkName.LONDON: return LONDON; case L1HardforkName.ARROW_GLACIER: return ARROW_GLACIER; case L1HardforkName.GRAY_GLACIER: return GRAY_GLACIER; case L1HardforkName.MERGE: return MERGE; case L1HardforkName.SHANGHAI: return SHANGHAI; case L1HardforkName.CANCUN: return CANCUN; case L1HardforkName.PRAGUE: return PRAGUE; // eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check -- we want to print the fork default: const _exhaustiveCheck = hardforkName; throw new Error( // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- an enum can be safely cast to a string `Unknown hardfork name '${hardfork}', this shouldn't happen`); } } export function hardhatMiningIntervalToEdrMiningInterval(config) { if (typeof config === "number") { // Is interval mining disabled? if (config === 0) { return undefined; } else { return BigInt(config); } } else { return { min: BigInt(config[0]), max: BigInt(config[1]), }; } } export function hardhatMempoolOrderToEdrMineOrdering(mempoolOrder) { switch (mempoolOrder) { case "fifo": return MineOrdering.Fifo; case "priority": return MineOrdering.Priority; } } // TODO: EDR should handle this conversion. This is a temporary solution. export function edrRpcDebugTraceToHardhat(debugTraceResult) { const structLogs = debugTraceResult.structLogs.map((log) => { const result = { depth: Number(log.depth), gas: Number(log.gas), gasCost: Number(log.gasCost), op: log.opName, pc: Number(log.pc), }; if (log.memory !== undefined) { result.memory = log.memory; } if (log.stack !== undefined) { // Remove 0x prefix which is required by EIP-3155, but not expected by Hardhat. result.stack = log.stack.map(getUnprefixedHexString); } if (log.storage !== undefined) { result.storage = Object.fromEntries(Object.entries(log.storage).map(([key, value]) => [ getUnprefixedHexString(key), getUnprefixedHexString(value), ])); } if (log.error !== undefined) { result.error = { message: log.error, }; } return result; }); // REVM trace adds initial STOP that Hardhat doesn't expect // TODO: double check with EDR team that this is still the case if (structLogs.length > 0 && structLogs[0].op === "STOP") { structLogs.shift(); } /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- debugTraceResult.output is a string, but it's typed as Buffer in Edr */ let returnValue = debugTraceResult.output ?? "0x"; if (returnValue === "0x") { returnValue = ""; } return { failed: !debugTraceResult.pass, gas: Number(debugTraceResult.gasUsed), returnValue, structLogs, }; } export async function hardhatAccountsToEdrOwnedAccounts(accounts) { const normalizedAccounts = await normalizeEdrNetworkAccountsConfig(accounts); const accountPromises = normalizedAccounts.map(async (account) => ({ secretKey: await account.privateKey.getHexString(), balance: account.balance, })); return Promise.all(accountPromises); } export async function normalizeEdrNetworkAccountsConfig(accounts) { if (Array.isArray(accounts)) { return accounts; } const isDefaultConfig = await isDefaultEdrNetworkHDAccountsConfig(accounts); const derivedPrivateKeys = isDefaultConfig ? EDR_NETWORK_DEFAULT_PRIVATE_KEYS : await derivePrivateKeys(await accounts.mnemonic.get(), accounts.path, accounts.initialIndex, accounts.count, await accounts.passphrase.get()); return derivedPrivateKeys.map((privateKey) => ({ privateKey: new FixedValueConfigurationVariable(privateKey), balance: accounts.accountsBalance ?? DEFAULT_EDR_NETWORK_BALANCE, })); } export function hardhatChainDescriptorsToEdrChainOverrides(chainDescriptors, chainType) { return (Array.from(chainDescriptors) // Skip chain descriptors that don't match the expected chain type .filter(([_, descriptor]) => { if (chainType === GENERIC_CHAIN_TYPE) { // When "generic" is requested, include both "generic" and "l1" chains return (descriptor.chainType === GENERIC_CHAIN_TYPE || descriptor.chainType === L1_CHAIN_TYPE); } return descriptor.chainType === chainType; }) .map(([chainId, descriptor]) => ({ chainId, name: descriptor.name, hardforkActivationOverrides: Array.from(descriptor.hardforkHistory ?? new Map()).map(([hardfork, { blockNumber, timestamp }]) => ({ condition: blockNumber !== undefined ? { blockNumber: BigInt(blockNumber) } : { timestamp: BigInt(timestamp) }, hardfork: hardhatHardforkToEdrSpecId(hardfork, descriptor.chainType), })), }))); } export async function hardhatForkingConfigToEdrForkConfig(forkingConfig, chainDescriptors, chainType) { let fork; if (forkingConfig !== undefined && forkingConfig.enabled === true) { const httpHeaders = forkingConfig.httpHeaders !== undefined ? Object.entries(forkingConfig.httpHeaders).map(([name, value]) => ({ name, value, })) : undefined; fork = { blockNumber: forkingConfig.blockNumber, cacheDir: forkingConfig.cacheDir, chainOverrides: hardhatChainDescriptorsToEdrChainOverrides(chainDescriptors, chainType), httpHeaders, url: await forkingConfig.url.getUrl(), }; } return fork; } //# sourceMappingURL=convert-to-edr.js.map