diff --git a/v-next/hardhat/src/internal/builtin-plugins/network-manager/accounts/constants.ts b/v-next/hardhat/src/internal/builtin-plugins/network-manager/accounts/constants.ts new file mode 100644 index 0000000000..74c48ab1e6 --- /dev/null +++ b/v-next/hardhat/src/internal/builtin-plugins/network-manager/accounts/constants.ts @@ -0,0 +1,16 @@ +import type { SensitiveString } from "../../../../types/config.js"; + +export interface DefaultHDAccountsConfigParams { + initialIndex: number; + count: number; + path: string; + passphrase: SensitiveString; +} + +export const DEFAULT_HD_ACCOUNTS_CONFIG_PARAMS: DefaultHDAccountsConfigParams = + { + initialIndex: 0, + count: 20, + path: "m/44'/60'/0'/0", + passphrase: "", + }; diff --git a/v-next/hardhat/src/internal/builtin-plugins/network-manager/accounts/derive-private-keys.ts b/v-next/hardhat/src/internal/builtin-plugins/network-manager/accounts/derive-private-keys.ts index b42ea51487..9cec412fe1 100644 --- a/v-next/hardhat/src/internal/builtin-plugins/network-manager/accounts/derive-private-keys.ts +++ b/v-next/hardhat/src/internal/builtin-plugins/network-manager/accounts/derive-private-keys.ts @@ -1,34 +1,18 @@ -import type { SensitiveString } from "../../../../types/config.js"; - import { HardhatError } from "@ignored/hardhat-vnext-errors"; +import { bytesToHexString } from "@ignored/hardhat-vnext-utils/bytes"; import { mnemonicToSeedSync } from "ethereum-cryptography/bip39"; import { HDKey } from "ethereum-cryptography/hdkey"; const HD_PATH_REGEX = /^m(:?\/\d+'?)+\/?$/; -export interface DefaultHDAccountsConfigParams { - initialIndex: number; - count: number; - path: string; - passphrase: SensitiveString; -} - -export const DEFAULT_HD_ACCOUNTS_CONFIG_PARAMS: DefaultHDAccountsConfigParams = - { - initialIndex: 0, - count: 20, - path: "m/44'/60'/0'/0", - passphrase: "", - }; - export function derivePrivateKeys( mnemonic: string, hdpath: string, initialIndex: number, count: number, passphrase: string, -): Buffer[] { - if (hdpath.match(HD_PATH_REGEX) === null) { +): string[] { + if (!HD_PATH_REGEX.test(hdpath)) { throw new HardhatError(HardhatError.ERRORS.NETWORK.INVALID_HD_PATH, { path: hdpath, }); @@ -38,7 +22,7 @@ export function derivePrivateKeys( hdpath += "/"; } - const privateKeys: Buffer[] = []; + const privateKeys: string[] = []; for (let i = initialIndex; i < initialIndex + count; i++) { const privateKey = deriveKeyFromMnemonicAndPath( @@ -64,7 +48,7 @@ function deriveKeyFromMnemonicAndPath( mnemonic: string, hdPath: string, passphrase: string, -): Buffer | undefined { +): string | undefined { // NOTE: If mnemonic has space or newline at the beginning or end, it will be trimmed. // This is because mnemonic containing them may generate different private keys. const trimmedMnemonic = mnemonic.trim(); @@ -76,5 +60,5 @@ function deriveKeyFromMnemonicAndPath( return derived.privateKey === null ? undefined - : Buffer.from(derived.privateKey); + : bytesToHexString(derived.privateKey); } diff --git a/v-next/hardhat/src/internal/builtin-plugins/network-manager/base-provider.ts b/v-next/hardhat/src/internal/builtin-plugins/network-manager/base-provider.ts new file mode 100644 index 0000000000..fff787c436 --- /dev/null +++ b/v-next/hardhat/src/internal/builtin-plugins/network-manager/base-provider.ts @@ -0,0 +1,76 @@ +import type { + EthereumProvider, + JsonRpcRequest, + JsonRpcResponse, + RequestArguments, + SuccessfulJsonRpcResponse, +} from "../../../types/providers.js"; + +import EventEmitter from "node:events"; +import util from "node:util"; + +import { ensureError } from "@ignored/hardhat-vnext-utils/error"; + +export abstract class BaseProvider + extends EventEmitter + implements EthereumProvider +{ + public abstract request( + requestArguments: RequestArguments, + ): Promise; + public abstract close(): Promise; + + public send( + method: string, + params?: unknown[], + ): Promise { + return this.request({ method, params }); + } + + public sendAsync( + jsonRpcRequest: JsonRpcRequest, + callback: (error: any, jsonRpcResponse: JsonRpcResponse) => void, + ): void { + const handleJsonRpcRequest = async () => { + let jsonRpcResponse: JsonRpcResponse; + try { + const result = await this.request({ + method: jsonRpcRequest.method, + params: jsonRpcRequest.params, + }); + jsonRpcResponse = { + jsonrpc: "2.0", + id: jsonRpcRequest.id, + result, + }; + } catch (error) { + ensureError(error); + + if (!("code" in error) || error.code === undefined) { + throw error; + } + + /* eslint-disable-next-line @typescript-eslint/restrict-template-expressions + -- Allow string interpolation of unknown `error.code`. It will be converted + to a number, and we will handle NaN cases appropriately afterwards. */ + const errorCode = parseInt(`${error.code}`, 10); + jsonRpcResponse = { + jsonrpc: "2.0", + id: jsonRpcRequest.id, + error: { + code: !isNaN(errorCode) ? errorCode : -1, + message: error.message, + data: { + stack: error.stack, + name: error.name, + }, + }, + }; + } + + return jsonRpcResponse; + }; + + util.callbackify(handleJsonRpcRequest)(callback); + } +} diff --git a/v-next/hardhat/src/internal/builtin-plugins/network-manager/config-resolution.ts b/v-next/hardhat/src/internal/builtin-plugins/network-manager/config-resolution.ts index 3cb63b84d5..da06839c24 100644 --- a/v-next/hardhat/src/internal/builtin-plugins/network-manager/config-resolution.ts +++ b/v-next/hardhat/src/internal/builtin-plugins/network-manager/config-resolution.ts @@ -1,5 +1,5 @@ import type { - ConfigurationResolver, + ConfigurationVariableResolver, EdrNetworkAccountsConfig, EdrNetworkAccountsUserConfig, EdrNetworkChainConfig, @@ -22,7 +22,7 @@ import { normalizeHexString, } from "@ignored/hardhat-vnext-utils/hex"; -import { DEFAULT_HD_ACCOUNTS_CONFIG_PARAMS } from "./accounts/derive-private-keys.js"; +import { DEFAULT_HD_ACCOUNTS_CONFIG_PARAMS } from "./accounts/constants.js"; import { DEFAULT_EDR_NETWORK_HD_ACCOUNTS_CONFIG_PARAMS, EDR_NETWORK_DEFAULT_COINBASE, @@ -36,7 +36,7 @@ export function resolveGasConfig(value: GasUserConfig = "auto"): GasConfig { export function resolveHttpNetworkAccounts( accounts: HttpNetworkAccountsUserConfig | undefined = "remote", - resolveConfigurationVariable: ConfigurationResolver, + resolveConfigurationVariable: ConfigurationVariableResolver, ): HttpNetworkAccountsConfig { if (Array.isArray(accounts)) { return accounts.map((acc) => { @@ -68,7 +68,7 @@ export function resolveEdrNetworkAccounts( accounts: | EdrNetworkAccountsUserConfig | undefined = DEFAULT_EDR_NETWORK_HD_ACCOUNTS_CONFIG_PARAMS, - resolveConfigurationVariable: ConfigurationResolver, + resolveConfigurationVariable: ConfigurationVariableResolver, ): EdrNetworkAccountsConfig { if (Array.isArray(accounts)) { return accounts.map(({ privateKey, balance }) => { @@ -102,20 +102,12 @@ export function resolveEdrNetworkAccounts( export function resolveForkingConfig( forkingUserConfig: EdrNetworkForkingUserConfig | undefined, cacheDir: string, - resolveConfigurationVariable: ConfigurationResolver, + resolveConfigurationVariable: ConfigurationVariableResolver, ): EdrNetworkForkingConfig | undefined { if (forkingUserConfig === undefined) { return undefined; } - const httpHeaders = - forkingUserConfig.httpHeaders !== undefined - ? Object.entries(forkingUserConfig.httpHeaders).map(([name, value]) => ({ - name, - value, - })) - : undefined; - return { enabled: forkingUserConfig.enabled ?? true, url: resolveConfigurationVariable(forkingUserConfig.url), @@ -124,7 +116,7 @@ export function resolveForkingConfig( forkingUserConfig.blockNumber !== undefined ? BigInt(forkingUserConfig.blockNumber) : undefined, - httpHeaders, + httpHeaders: forkingUserConfig.httpHeaders, }; } diff --git a/v-next/hardhat/src/internal/builtin-plugins/network-manager/edr/edr-context.ts b/v-next/hardhat/src/internal/builtin-plugins/network-manager/edr/edr-context.ts new file mode 100644 index 0000000000..e6774c5e2f --- /dev/null +++ b/v-next/hardhat/src/internal/builtin-plugins/network-manager/edr/edr-context.ts @@ -0,0 +1,31 @@ +import { + EdrContext, + GENERIC_CHAIN_TYPE, + genericChainProviderFactory, + L1_CHAIN_TYPE, + l1ProviderFactory, + OPTIMISM_CHAIN_TYPE, + optimismProviderFactory, +} from "@ignored/edr-optimism"; + +let _globalEdrContext: EdrContext | undefined; + +export async function getGlobalEdrContext(): Promise { + if (_globalEdrContext === undefined) { + _globalEdrContext = new EdrContext(); + await _globalEdrContext.registerProviderFactory( + GENERIC_CHAIN_TYPE, + genericChainProviderFactory(), + ); + await _globalEdrContext.registerProviderFactory( + L1_CHAIN_TYPE, + l1ProviderFactory(), + ); + await _globalEdrContext.registerProviderFactory( + OPTIMISM_CHAIN_TYPE, + optimismProviderFactory(), + ); + } + + return _globalEdrContext; +} diff --git a/v-next/hardhat/src/internal/builtin-plugins/network-manager/edr/edr-provider.ts b/v-next/hardhat/src/internal/builtin-plugins/network-manager/edr/edr-provider.ts index 906eadcb25..f0ac749899 100644 --- a/v-next/hardhat/src/internal/builtin-plugins/network-manager/edr/edr-provider.ts +++ b/v-next/hardhat/src/internal/builtin-plugins/network-manager/edr/edr-provider.ts @@ -3,10 +3,8 @@ import type { LoggerConfig } from "./types/logger.js"; import type { TracingConfig } from "./types/node-types.js"; import type { EdrNetworkConfig } from "../../../../types/config.js"; import type { - EthereumProvider, EthSubscription, FailedJsonRpcResponse, - JsonRpcRequest, JsonRpcResponse, RequestArguments, SuccessfulJsonRpcResponse, @@ -15,7 +13,7 @@ import type { CompilerInput, CompilerOutput, } from "../../../../types/solidity/compiler-io.js"; -import type { DefaultHDAccountsConfigParams } from "../accounts/derive-private-keys.js"; +import type { DefaultHDAccountsConfigParams } from "../accounts/constants.js"; import type { JsonRpcRequestWrapperFunction } from "../network-manager.js"; import type { RawTrace, @@ -28,32 +26,26 @@ import type { ProviderConfig, } from "@ignored/edr-optimism"; -import EventEmitter from "node:events"; -import util from "node:util"; - import { - EdrContext, createModelsAndDecodeBytecodes, initializeVmTraceDecoder, SolidityTracer, VmTracer, - GENERIC_CHAIN_TYPE, - OPTIMISM_CHAIN_TYPE, - genericChainProviderFactory, - optimismProviderFactory, } from "@ignored/edr-optimism"; import { toSeconds } from "@ignored/hardhat-vnext-utils/date"; -import { ensureError } from "@ignored/hardhat-vnext-utils/error"; +import { deepEqual } from "@ignored/hardhat-vnext-utils/lang"; import chalk from "chalk"; import debug from "debug"; import { - HARDHAT_NETWORK_RESET_EVENT, - HARDHAT_NETWORK_REVERT_SNAPSHOT_EVENT, + EDR_NETWORK_RESET_EVENT, + EDR_NETWORK_REVERT_SNAPSHOT_EVENT, } from "../../../constants.js"; -import { DEFAULT_HD_ACCOUNTS_CONFIG_PARAMS } from "../accounts/derive-private-keys.js"; +import { DEFAULT_HD_ACCOUNTS_CONFIG_PARAMS } from "../accounts/constants.js"; +import { BaseProvider } from "../base-provider.js"; import { getJsonRpcRequest, isFailedJsonRpcResponse } from "../json-rpc.js"; +import { getGlobalEdrContext } from "./edr-context.js"; import { InvalidArgumentsError, InvalidInputError, @@ -71,6 +63,7 @@ import { hardhatAccountsToEdrGenesisAccounts, hardhatChainsToEdrChains, hardhatForkingConfigToEdrForkConfig, + hardhatChainTypeToEdrChainType, } from "./utils/convert-to-edr.js"; import { printLine, replaceLastLine } from "./utils/logger.js"; @@ -95,25 +88,35 @@ export const DEFAULT_EDR_NETWORK_HD_ACCOUNTS_CONFIG_PARAMS: EdrNetworkDefaultHDA accountsBalance: DEFAULT_EDR_NETWORK_BALANCE, }; -// Lazy initialize the global EDR context. -let _globalEdrContext: EdrContext | undefined; -export async function getGlobalEdrContext(): Promise { - if (_globalEdrContext === undefined) { - // Only one is allowed to exist - _globalEdrContext = new EdrContext(); - await _globalEdrContext.registerProviderFactory( - GENERIC_CHAIN_TYPE, - genericChainProviderFactory(), - ); - await _globalEdrContext.registerProviderFactory( - OPTIMISM_CHAIN_TYPE, - optimismProviderFactory(), - ); - } - - return _globalEdrContext; +export async function isDefaultEdrNetworkHDAccountsConfig( + account: unknown, +): Promise { + return deepEqual(account, DEFAULT_EDR_NETWORK_HD_ACCOUNTS_CONFIG_PARAMS); } +export const EDR_NETWORK_DEFAULT_PRIVATE_KEYS: string[] = [ + "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80", + "0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d", + "0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a", + "0x7c852118294e51e653712a81e05800f419141751be58f605c371e15141b007a6", + "0x47e179ec197488593b187f80a00eb0da91f1b9d0b13f8733639f19c30a34926a", + "0x8b3a350cf5c34c9194ca85829a2df0ec3153be0318b5e2d3348e872092edffba", + "0x92db14e403b83dfe3df233f83dfa3a0d7096f21ca9b0d6d6b8d88b2b4ec1564e", + "0x4bbbf85ce3377467afe5d46f804f221813b2bb87f24d81f60f1fcdbf7cbf4356", + "0xdbda1821b80551c9d65939329250298aa3472ba22feea921c0cf5d620ea67b97", + "0x2a871d0798f97d79848a013d4936a73bf4cc922c825d33c1cf7073dff6d409c6", + "0xf214f2b2cd398c806f84e317254e0f0b801d0643303237d97a22a48e01628897", + "0x701b615bbdfb9de65240bc28bd21bbc0d996645a3dd57e7b12bc2bdf6f192c82", + "0xa267530f49f8280200edf313ee7af6b827f2a8bce2897751d06a843f644967b1", + "0x47c99abed3324a2707c28affff1267e45918ec8c3f20b8aa892e8b065d2942dd", + "0xc526ee95bf44d8fc405a158bb884d9d1238d99f0612e9f33d006bb0789009aaa", + "0x8166f546bab6da521a8369cab06c5d2b9e46670292d85c875ee9ec20e84ffb61", + "0xea6c44ac03bff858b476bba40716402b03e41b8e97e276d1baec7c37d42484a0", + "0x689af8efa8c651a91ad287602527f3af2fe9f6501a7ac4b061667b5a93e037fd", + "0xde9be858da4a475276426320d5e9262ecfc3ba460bfac56360bfa6c4c28b4ee0", + "0xdf57089febbacf7ba0bc227dafbffa9fc08a93fdc68e1e42411a14efcf23656e", +]; + interface EdrProviderConfig { networkConfig: EdrNetworkConfig; loggerConfig?: LoggerConfig; @@ -121,9 +124,9 @@ interface EdrProviderConfig { jsonRpcRequestWrapper?: JsonRpcRequestWrapperFunction; } -export class EdrProvider extends EventEmitter implements EthereumProvider { - readonly #provider: Provider; - readonly #vmTraceDecoder: VmTraceDecoder; +export class EdrProvider extends BaseProvider { + readonly #provider: Readonly; + readonly #vmTraceDecoder: Readonly; readonly #jsonRpcRequestWrapper?: JsonRpcRequestWrapperFunction; #failedStackTraces: number = 0; @@ -149,9 +152,7 @@ export class EdrProvider extends EventEmitter implements EthereumProvider { const context = await getGlobalEdrContext(); const provider = await context.createProvider( - networkConfig.chainType === "optimism" - ? OPTIMISM_CHAIN_TYPE - : GENERIC_CHAIN_TYPE, // TODO: l1 is missing here + hardhatChainTypeToEdrChainType(networkConfig.chainType), providerConfig, { enable: loggerConfig.enabled, @@ -270,9 +271,9 @@ export class EdrProvider extends EventEmitter implements EthereumProvider { } if (args.method === "hardhat_reset") { - this.emit(HARDHAT_NETWORK_RESET_EVENT); + this.emit(EDR_NETWORK_RESET_EVENT); } else if (args.method === "evm_revert") { - this.emit(HARDHAT_NETWORK_REVERT_SNAPSHOT_EVENT); + this.emit(EDR_NETWORK_REVERT_SNAPSHOT_EVENT); } // this can only happen if a wrapper doesn't call the default @@ -310,60 +311,6 @@ export class EdrProvider extends EventEmitter implements EthereumProvider { // TODO: what needs cleaned up? } - public async send(method: string, params?: unknown[]): Promise { - return this.request({ method, params }); - } - - public sendAsync( - jsonRpcRequest: JsonRpcRequest, - callback: (error: any, jsonRpcResponse: JsonRpcResponse) => void, - ): void { - // TODO: this is a straight copy of the HTTP Provider, - // can we pull this out and share the logic. - const handleJsonRpcRequest = async () => { - let jsonRpcResponse: JsonRpcResponse; - try { - const result = await this.request({ - method: jsonRpcRequest.method, - params: jsonRpcRequest.params, - }); - - jsonRpcResponse = { - jsonrpc: "2.0", - id: jsonRpcRequest.id, - result, - }; - } catch (error) { - ensureError(error); - - if (!("code" in error) || error.code === undefined) { - throw error; - } - - /* eslint-disable-next-line @typescript-eslint/restrict-template-expressions - -- Allow string interpolation of unknown `error.code`. It will be converted - to a number, and we will handle NaN cases appropriately afterwards. */ - const errorCode = parseInt(`${error.code}`, 10); - jsonRpcResponse = { - jsonrpc: "2.0", - id: jsonRpcRequest.id, - error: { - code: !isNaN(errorCode) ? errorCode : -1, - message: error.message, - data: { - stack: error.stack, - name: error.name, - }, - }, - }; - } - - return jsonRpcResponse; - }; - - util.callbackify(handleJsonRpcRequest)(callback); - } - #isErrorResponse(response: any): response is FailedJsonRpcResponse { return typeof response.error !== "undefined"; } diff --git a/v-next/hardhat/src/internal/builtin-plugins/network-manager/edr/utils/chain-type.ts b/v-next/hardhat/src/internal/builtin-plugins/network-manager/edr/utils/chain-type.ts new file mode 100644 index 0000000000..dc991a800f --- /dev/null +++ b/v-next/hardhat/src/internal/builtin-plugins/network-manager/edr/utils/chain-type.ts @@ -0,0 +1,17 @@ +import type { ChainType } from "../../../../../types/network.js"; + +import { + GENERIC_CHAIN_TYPE, + L1_CHAIN_TYPE, + OPTIMISM_CHAIN_TYPE, +} from "../../../../constants.js"; + +export function isEdrSupportedChainType( + chainType: unknown, +): chainType is ChainType { + return ( + chainType === GENERIC_CHAIN_TYPE || + chainType === L1_CHAIN_TYPE || + chainType === OPTIMISM_CHAIN_TYPE + ); +} diff --git a/v-next/hardhat/src/internal/builtin-plugins/network-manager/edr/utils/convert-to-edr.ts b/v-next/hardhat/src/internal/builtin-plugins/network-manager/edr/utils/convert-to-edr.ts index 4cfca939ea..a1b9bb2651 100644 --- a/v-next/hardhat/src/internal/builtin-plugins/network-manager/edr/utils/convert-to-edr.ts +++ b/v-next/hardhat/src/internal/builtin-plugins/network-manager/edr/utils/convert-to-edr.ts @@ -7,6 +7,7 @@ import type { EdrNetworkMempoolConfig, EdrNetworkMiningConfig, } from "../../../../../types/config.js"; +import type { ChainType } from "../../../../../types/network.js"; import type { RpcDebugTraceOutput, RpcStructLog } from "../types/output.js"; import type { IntervalRange, @@ -35,12 +36,19 @@ import { MERGE, SHANGHAI, CANCUN, + OPTIMISM_CHAIN_TYPE as EDR_OPTIMISM_CHAIN_TYPE, + L1_CHAIN_TYPE as EDR_L1_CHAIN_TYPE, + GENERIC_CHAIN_TYPE as EDR_GENERIC_CHAIN_TYPE, } from "@ignored/edr-optimism"; -import { bytesToHexString } from "@ignored/hardhat-vnext-utils/bytes"; +import { 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 } from "../edr-provider.js"; +import { + DEFAULT_EDR_NETWORK_BALANCE, + EDR_NETWORK_DEFAULT_PRIVATE_KEYS, + isDefaultEdrNetworkHDAccountsConfig, +} from "../edr-provider.js"; import { HardforkName } from "../types/hardfork.js"; import { getHardforkName } from "./hardfork.js"; @@ -241,14 +249,19 @@ async function normalizeEdrNetworkAccountsConfig( return accounts; } - return derivePrivateKeys( - await accounts.mnemonic.get(), - accounts.path, - accounts.initialIndex, - accounts.count, - await accounts.passphrase.get(), - ).map((pk) => ({ - privateKey: new FixedValueConfigurationVariable(bytesToHexString(pk)), + const isDefaultConfig = await isDefaultEdrNetworkHDAccountsConfig(accounts); + const derivedPrivateKeys = isDefaultConfig + ? EDR_NETWORK_DEFAULT_PRIVATE_KEYS + : 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, })); } @@ -284,12 +297,34 @@ export async function hardhatForkingConfigToEdrForkConfig( ): Promise { let fork: ForkConfig | undefined; if (forkingConfig !== undefined && forkingConfig.enabled === true) { + const httpHeaders = + forkingConfig.httpHeaders !== undefined + ? Object.entries(forkingConfig.httpHeaders).map(([name, value]) => ({ + name, + value, + })) + : undefined; + fork = { jsonRpcUrl: await forkingConfig.url.getUrl(), blockNumber: forkingConfig.blockNumber, - httpHeaders: forkingConfig.httpHeaders, + httpHeaders, }; } return fork; } + +export function hardhatChainTypeToEdrChainType( + chainType: ChainType | undefined, +): string { + if (chainType === OPTIMISM_CHAIN_TYPE) { + return EDR_OPTIMISM_CHAIN_TYPE; + } + + if (chainType === L1_CHAIN_TYPE) { + return EDR_L1_CHAIN_TYPE; + } + + return EDR_GENERIC_CHAIN_TYPE; +} diff --git a/v-next/hardhat/src/internal/builtin-plugins/network-manager/hook-handlers/config.ts b/v-next/hardhat/src/internal/builtin-plugins/network-manager/hook-handlers/config.ts index 0d8c83fac4..a509f5e85a 100644 --- a/v-next/hardhat/src/internal/builtin-plugins/network-manager/hook-handlers/config.ts +++ b/v-next/hardhat/src/internal/builtin-plugins/network-manager/hook-handlers/config.ts @@ -14,6 +14,7 @@ import type { ConfigHooks } from "../../../../types/hooks.js"; import { HardhatError } from "@ignored/hardhat-vnext-errors"; +import { GENERIC_CHAIN_TYPE } from "../../../constants.js"; import { resolveChains, resolveCoinbase, @@ -172,7 +173,7 @@ export async function resolveUserConfig( return { ...resolvedConfig, - defaultChainType: resolvedConfig.defaultChainType ?? "generic", + defaultChainType: resolvedConfig.defaultChainType ?? GENERIC_CHAIN_TYPE, defaultNetwork: resolvedConfig.defaultNetwork ?? "hardhat", networks: resolvedNetworks, }; diff --git a/v-next/hardhat/src/internal/builtin-plugins/network-manager/hook-handlers/network.ts b/v-next/hardhat/src/internal/builtin-plugins/network-manager/hook-handlers/network.ts index d8aaaa590c..69bd798cf5 100644 --- a/v-next/hardhat/src/internal/builtin-plugins/network-manager/hook-handlers/network.ts +++ b/v-next/hardhat/src/internal/builtin-plugins/network-manager/hook-handlers/network.ts @@ -15,7 +15,7 @@ import type { import { deepClone } from "@ignored/hardhat-vnext-utils/lang"; import { isJsonRpcResponse } from "../json-rpc.js"; -import { createHandlersArray } from "../request-handlers/hanlders-array.js"; +import { createHandlersArray } from "../request-handlers/handlers-array.js"; export default async (): Promise> => { // This map is essential for managing multiple network connections in Hardhat V3. diff --git a/v-next/hardhat/src/internal/builtin-plugins/network-manager/http-provider.ts b/v-next/hardhat/src/internal/builtin-plugins/network-manager/http-provider.ts index 477cf70130..2f5a06016d 100644 --- a/v-next/hardhat/src/internal/builtin-plugins/network-manager/http-provider.ts +++ b/v-next/hardhat/src/internal/builtin-plugins/network-manager/http-provider.ts @@ -1,6 +1,5 @@ import type { JsonRpcRequestWrapperFunction } from "./network-manager.js"; import type { - EthereumProvider, JsonRpcRequest, JsonRpcResponse, RequestArguments, @@ -11,11 +10,7 @@ import type { RequestOptions, } from "@ignored/hardhat-vnext-utils/request"; -import EventEmitter from "node:events"; -import util from "node:util"; - import { HardhatError } from "@ignored/hardhat-vnext-errors"; -import { ensureError } from "@ignored/hardhat-vnext-utils/error"; import { sleep, isObject } from "@ignored/hardhat-vnext-utils/lang"; import { getDispatcher, @@ -27,8 +22,13 @@ import { ResponseStatusCodeError, } from "@ignored/hardhat-vnext-utils/request"; +import { + EDR_NETWORK_RESET_EVENT, + EDR_NETWORK_REVERT_SNAPSHOT_EVENT, +} from "../../constants.js"; import { getHardhatVersion } from "../../utils/package.js"; +import { BaseProvider } from "./base-provider.js"; import { getJsonRpcRequest, isFailedJsonRpcResponse, @@ -49,11 +49,11 @@ interface HttpProviderConfig { testDispatcher?: Dispatcher; } -export class HttpProvider extends EventEmitter implements EthereumProvider { +export class HttpProvider extends BaseProvider { readonly #url: string; readonly #networkName: string; - readonly #extraHeaders: Record; - readonly #dispatcher: Dispatcher; + readonly #extraHeaders: Readonly>; + readonly #dispatcher: Readonly; readonly #jsonRpcRequestWrapper?: JsonRpcRequestWrapperFunction; #nextRequestId = 1; @@ -145,7 +145,12 @@ export class HttpProvider extends EventEmitter implements EthereumProvider { throw error; } - // TODO: emit hardhat network events (hardhat_reset, evm_revert) + if (jsonRpcRequest.method === "hardhat_reset") { + this.emit(EDR_NETWORK_RESET_EVENT); + } + if (jsonRpcRequest.method === "evm_revert") { + this.emit(EDR_NETWORK_REVERT_SNAPSHOT_EVENT); + } return jsonRpcResponse.result; } @@ -155,78 +160,10 @@ export class HttpProvider extends EventEmitter implements EthereumProvider { await this.#dispatcher.close(); } - public send( - method: string, - params?: unknown[], - ): Promise { - return this.request({ method, params }); - } - - public sendAsync( - jsonRpcRequest: JsonRpcRequest, - callback: (error: any, jsonRpcResponse: JsonRpcResponse) => void, - ): void { - const handleJsonRpcRequest = async () => { - let jsonRpcResponse: JsonRpcResponse; - try { - const result = await this.request({ - method: jsonRpcRequest.method, - params: jsonRpcRequest.params, - }); - jsonRpcResponse = { - jsonrpc: "2.0", - id: jsonRpcRequest.id, - result, - }; - } catch (error) { - ensureError(error); - - if (!("code" in error) || error.code === undefined) { - throw error; - } - - /* eslint-disable-next-line @typescript-eslint/restrict-template-expressions - -- Allow string interpolation of unknown `error.code`. It will be converted - to a number, and we will handle NaN cases appropriately afterwards. */ - const errorCode = parseInt(`${error.code}`, 10); - jsonRpcResponse = { - jsonrpc: "2.0", - id: jsonRpcRequest.id, - error: { - code: !isNaN(errorCode) ? errorCode : -1, - message: error.message, - data: { - stack: error.stack, - name: error.name, - }, - }, - }; - } - - return jsonRpcResponse; - }; - - util.callbackify(handleJsonRpcRequest)(callback); - } - - // TODO as we removed sendBatch, I think we can remove all the overloads - // that return an array of responses async #fetchJsonRpcResponse( jsonRpcRequest: JsonRpcRequest, - retryCount?: number, - ): Promise; - async #fetchJsonRpcResponse( - jsonRpcRequest: JsonRpcRequest[], - retryCount?: number, - ): Promise; - async #fetchJsonRpcResponse( - jsonRpcRequest: JsonRpcRequest | JsonRpcRequest[], - retryCount?: number, - ): Promise; - async #fetchJsonRpcResponse( - jsonRpcRequest: JsonRpcRequest | JsonRpcRequest[], retryCount = 0, - ): Promise { + ): Promise { const requestOptions: RequestOptions = { extraHeaders: { "User-Agent": `Hardhat ${await getHardhatVersion()}`, @@ -312,7 +249,7 @@ export class HttpProvider extends EventEmitter implements EthereumProvider { } async #retry( - request: JsonRpcRequest | JsonRpcRequest[], + request: JsonRpcRequest, retryAfterSeconds: number, retryCount: number, ) { diff --git a/v-next/hardhat/src/internal/builtin-plugins/network-manager/json-rpc.ts b/v-next/hardhat/src/internal/builtin-plugins/network-manager/json-rpc.ts index b845dba37b..7cd945f919 100644 --- a/v-next/hardhat/src/internal/builtin-plugins/network-manager/json-rpc.ts +++ b/v-next/hardhat/src/internal/builtin-plugins/network-manager/json-rpc.ts @@ -33,23 +33,17 @@ export function getJsonRpcRequest( return requestObject; } -export function parseJsonRpcResponse( - text: string, -): JsonRpcResponse | JsonRpcResponse[] { +export function parseJsonRpcResponse(text: string): JsonRpcResponse { try { const json: unknown = JSON.parse(text); - if (Array.isArray(json)) { - if (json.every(isJsonRpcResponse)) { - return json; - } - } else if (isJsonRpcResponse(json)) { - return json; + if (!isJsonRpcResponse(json)) { + /* eslint-disable-next-line no-restricted-syntax -- allow throwing a + generic error here as it will be handled in the catch block */ + throw new Error("Invalid JSON-RPC response"); } - /* eslint-disable-next-line no-restricted-syntax -- allow throwing a - generic error here as it will be handled in the catch block */ - throw new Error(); + return json; } catch { throw new HardhatError(HardhatError.ERRORS.NETWORK.INVALID_JSON_RESPONSE, { response: text, @@ -133,7 +127,9 @@ export function isFailedJsonRpcResponse( return "error" in payload && payload.error !== undefined; } -export function getRequestParams(requestArguments: RequestArguments): any[] { +export function getRequestParams( + requestArguments: RequestArguments, +): unknown[] { if (requestArguments.params === undefined) { return []; } diff --git a/v-next/hardhat/src/internal/builtin-plugins/network-manager/network-manager.ts b/v-next/hardhat/src/internal/builtin-plugins/network-manager/network-manager.ts index 5f2daec7d5..cef9ff8cd2 100644 --- a/v-next/hardhat/src/internal/builtin-plugins/network-manager/network-manager.ts +++ b/v-next/hardhat/src/internal/builtin-plugins/network-manager/network-manager.ts @@ -15,6 +15,7 @@ import type { import { HardhatError } from "@ignored/hardhat-vnext-errors"; import { EdrProvider } from "./edr/edr-provider.js"; +import { isEdrSupportedChainType } from "./edr/utils/chain-type.js"; import { HttpProvider } from "./http-provider.js"; import { NetworkConnectionImplementation } from "./network-connection.js"; import { isNetworkConfig, validateNetworkConfig } from "./type-validation.js"; @@ -28,7 +29,7 @@ export class NetworkManagerImplementation implements NetworkManager { readonly #defaultNetwork: string; readonly #defaultChainType: DefaultChainType; readonly #networkConfigs: Readonly>>; - readonly #hookManager: HookManager; + readonly #hookManager: Readonly; #nextConnectionId = 0; @@ -137,7 +138,9 @@ export class NetworkManagerImplementation implements NetworkManager { }); } - // We only need to capture the hook manager in the closures below + /* Capture the hook manager in a local variable to avoid retaining a + reference to the NetworkManager instance, allowing the garbage collector + to clean up the NetworkConnectionImplementation instances properly. */ const hookManager = this.#hookManager; const createProvider = async ( @@ -155,11 +158,7 @@ export class NetworkManagerImplementation implements NetworkManager { ); if (resolvedNetworkConfig.type === "edr") { - if ( - resolvedChainType !== "optimism" && - resolvedChainType !== "generic" && - resolvedChainType !== "l1" - ) { + if (!isEdrSupportedChainType(resolvedChainType)) { throw new HardhatError( HardhatError.ERRORS.GENERAL.UNSUPPORTED_OPERATION, { operation: `Simulating chain type ${resolvedChainType}` }, diff --git a/v-next/hardhat/src/internal/builtin-plugins/network-manager/request-handlers/hanlders-array.ts b/v-next/hardhat/src/internal/builtin-plugins/network-manager/request-handlers/handlers-array.ts similarity index 100% rename from v-next/hardhat/src/internal/builtin-plugins/network-manager/request-handlers/hanlders-array.ts rename to v-next/hardhat/src/internal/builtin-plugins/network-manager/request-handlers/handlers-array.ts diff --git a/v-next/hardhat/src/internal/builtin-plugins/network-manager/request-handlers/handlers/accounts/hd-wallet-handler.ts b/v-next/hardhat/src/internal/builtin-plugins/network-manager/request-handlers/handlers/accounts/hd-wallet-handler.ts index a09fdb2765..a2b0d6ac07 100644 --- a/v-next/hardhat/src/internal/builtin-plugins/network-manager/request-handlers/handlers/accounts/hd-wallet-handler.ts +++ b/v-next/hardhat/src/internal/builtin-plugins/network-manager/request-handlers/handlers/accounts/hd-wallet-handler.ts @@ -1,7 +1,5 @@ import type { EthereumProvider } from "../../../../../../types/providers.js"; -import { bytesToHexString } from "@ignored/hardhat-vnext-utils/hex"; - import { derivePrivateKeys } from "../../../accounts/derive-private-keys.js"; import { LocalAccountsHandler } from "./local-accounts.js"; @@ -15,20 +13,14 @@ export class HDWalletHandler extends LocalAccountsHandler { count: number = 10, passphrase: string = "", ) { - // NOTE: If mnemonic has space or newline at the beginning or end, it will be trimmed. - // This is because mnemonic containing them may generate different private keys. - const trimmedMnemonic = mnemonic.trim(); - const privateKeys = derivePrivateKeys( - trimmedMnemonic, + mnemonic, hdpath, initialIndex, count, passphrase, ); - const privateKeysAsHex = privateKeys.map((pk) => bytesToHexString(pk)); - - super(provider, privateKeysAsHex); + super(provider, privateKeys); } } diff --git a/v-next/hardhat/src/internal/builtin-plugins/network-manager/request-handlers/handlers/accounts/sender.ts b/v-next/hardhat/src/internal/builtin-plugins/network-manager/request-handlers/handlers/accounts/sender.ts index c47b98bd72..440c817b97 100644 --- a/v-next/hardhat/src/internal/builtin-plugins/network-manager/request-handlers/handlers/accounts/sender.ts +++ b/v-next/hardhat/src/internal/builtin-plugins/network-manager/request-handlers/handlers/accounts/sender.ts @@ -1,4 +1,3 @@ -import type { JsonRpcTransactionData } from "./types.js"; import type { EthereumProvider, JsonRpcRequest, @@ -7,6 +6,7 @@ import type { import type { RequestHandler } from "../../types.js"; import { HardhatError } from "@ignored/hardhat-vnext-errors"; +import { isObject } from "@ignored/hardhat-vnext-utils/lang"; import { getRequestParams } from "../../../json-rpc.js"; @@ -34,10 +34,9 @@ export abstract class SenderHandler implements RequestHandler { method === "eth_call" || method === "eth_estimateGas" ) { - // TODO: from V2 - Should we validate this type? - const tx: JsonRpcTransactionData = params[0]; + const [tx] = params; - if (tx !== undefined && tx.from === undefined) { + if (isObject(tx) && tx.from === undefined) { const senderAccount = await this.getSender(); if (senderAccount !== undefined) { diff --git a/v-next/hardhat/src/internal/builtin-plugins/network-manager/request-handlers/handlers/accounts/types.ts b/v-next/hardhat/src/internal/builtin-plugins/network-manager/request-handlers/handlers/accounts/types.ts deleted file mode 100644 index 565d514fc6..0000000000 --- a/v-next/hardhat/src/internal/builtin-plugins/network-manager/request-handlers/handlers/accounts/types.ts +++ /dev/null @@ -1,9 +0,0 @@ -export interface JsonRpcTransactionData { - from?: string; - to?: string; - gas?: string | number; - gasPrice?: string | number; - value?: string | number; - data?: string; - nonce?: string | number; -} diff --git a/v-next/hardhat/src/internal/builtin-plugins/network-manager/request-handlers/handlers/gas/automatic-gas-handler.ts b/v-next/hardhat/src/internal/builtin-plugins/network-manager/request-handlers/handlers/gas/automatic-gas-handler.ts index 163a28c515..bb64f85614 100644 --- a/v-next/hardhat/src/internal/builtin-plugins/network-manager/request-handlers/handlers/gas/automatic-gas-handler.ts +++ b/v-next/hardhat/src/internal/builtin-plugins/network-manager/request-handlers/handlers/gas/automatic-gas-handler.ts @@ -5,6 +5,8 @@ import type { } from "../../../../../../types/providers.js"; import type { RequestHandler } from "../../types.js"; +import { isObject } from "@ignored/hardhat-vnext-utils/lang"; + import { getRequestParams } from "../../../json-rpc.js"; import { MultipliedGasEstimation } from "./multiplied-gas-estimation.js"; @@ -38,10 +40,9 @@ export class AutomaticGasHandler } const params = getRequestParams(jsonRpcRequest); + const [tx] = params; - // TODO: from V2 - Should we validate this type? - const tx = params[0]; - if (tx !== undefined && tx.gas === undefined) { + if (isObject(tx) && tx.gas === undefined) { tx.gas = await this.getMultipliedGasEstimation(params); } diff --git a/v-next/hardhat/src/internal/builtin-plugins/network-manager/request-handlers/handlers/gas/automatic-gas-price-handler.ts b/v-next/hardhat/src/internal/builtin-plugins/network-manager/request-handlers/handlers/gas/automatic-gas-price-handler.ts index 885139ae87..ec541da3d7 100644 --- a/v-next/hardhat/src/internal/builtin-plugins/network-manager/request-handlers/handlers/gas/automatic-gas-price-handler.ts +++ b/v-next/hardhat/src/internal/builtin-plugins/network-manager/request-handlers/handlers/gas/automatic-gas-price-handler.ts @@ -44,11 +44,9 @@ export class AutomaticGasPriceHandler implements RequestHandler { } const params = getRequestParams(jsonRpcRequest); + const [tx] = params; - // TODO: from V2 - Should we validate this type? - const tx = params[0]; - - if (tx === undefined) { + if (!isObject(tx)) { return jsonRpcRequest; } @@ -84,12 +82,12 @@ export class AutomaticGasPriceHandler implements RequestHandler { } let maxFeePerGas = - tx.maxFeePerGas !== undefined + typeof tx.maxFeePerGas === "string" ? hexStringToBigInt(tx.maxFeePerGas) : suggestedEip1559Values.maxFeePerGas; const maxPriorityFeePerGas = - tx.maxPriorityFeePerGas !== undefined + typeof tx.maxPriorityFeePerGas === "string" ? hexStringToBigInt(tx.maxPriorityFeePerGas) : suggestedEip1559Values.maxPriorityFeePerGas; diff --git a/v-next/hardhat/src/internal/builtin-plugins/network-manager/request-handlers/handlers/gas/fixed-gas-handler.ts b/v-next/hardhat/src/internal/builtin-plugins/network-manager/request-handlers/handlers/gas/fixed-gas-handler.ts index 352359f050..4b263d7257 100644 --- a/v-next/hardhat/src/internal/builtin-plugins/network-manager/request-handlers/handlers/gas/fixed-gas-handler.ts +++ b/v-next/hardhat/src/internal/builtin-plugins/network-manager/request-handlers/handlers/gas/fixed-gas-handler.ts @@ -5,6 +5,8 @@ import type { import type { RequestHandler } from "../../types.js"; import type { PrefixedHexString } from "@ignored/hardhat-vnext-utils/hex"; +import { isObject } from "@ignored/hardhat-vnext-utils/lang"; + import { getRequestParams } from "../../../json-rpc.js"; /** @@ -26,11 +28,9 @@ export class FixedGasHandler implements RequestHandler { } const params = getRequestParams(jsonRpcRequest); + const [tx] = params; - // TODO: from V2 - Should we validate this type? - const tx = params[0]; - - if (tx !== undefined && tx.gas === undefined) { + if (isObject(tx) && tx.gas === undefined) { tx.gas = this.#gas; } diff --git a/v-next/hardhat/src/internal/builtin-plugins/network-manager/request-handlers/handlers/gas/fixed-gas-price-handler.ts b/v-next/hardhat/src/internal/builtin-plugins/network-manager/request-handlers/handlers/gas/fixed-gas-price-handler.ts index 9ff1b43083..bcdb165bdb 100644 --- a/v-next/hardhat/src/internal/builtin-plugins/network-manager/request-handlers/handlers/gas/fixed-gas-price-handler.ts +++ b/v-next/hardhat/src/internal/builtin-plugins/network-manager/request-handlers/handlers/gas/fixed-gas-price-handler.ts @@ -5,6 +5,8 @@ import type { import type { RequestHandler } from "../../types.js"; import type { PrefixedHexString } from "@ignored/hardhat-vnext-utils/hex"; +import { isObject } from "@ignored/hardhat-vnext-utils/lang"; + import { getRequestParams } from "../../../json-rpc.js"; /** @@ -26,13 +28,11 @@ export class FixedGasPriceHandler implements RequestHandler { } const params = getRequestParams(jsonRpcRequest); - - // TODO: from V2 - Should we validate this type? - const tx = params[0]; + const [tx] = params; // Temporary change to ignore EIP-1559 if ( - tx !== undefined && + isObject(tx) && tx.gasPrice === undefined && tx.maxFeePerGas === undefined && tx.maxPriorityFeePerGas === undefined diff --git a/v-next/hardhat/src/internal/builtin-plugins/network-manager/rpc/types/quantity.ts b/v-next/hardhat/src/internal/builtin-plugins/network-manager/rpc/types/quantity.ts index 6fe4c26e61..181d398ce1 100644 --- a/v-next/hardhat/src/internal/builtin-plugins/network-manager/rpc/types/quantity.ts +++ b/v-next/hardhat/src/internal/builtin-plugins/network-manager/rpc/types/quantity.ts @@ -3,11 +3,11 @@ import type { ZodType } from "zod"; import { conditionalUnionType } from "@ignored/hardhat-vnext-zod-utils"; import { z } from "zod"; -import { isBigInt, isRpcQuantityString } from "../utils.js"; +import { isRpcQuantityString } from "../utils.js"; export const rpcQuantity: ZodType = conditionalUnionType( [ - [isBigInt, z.bigint()], + [(data) => typeof data === "bigint", z.bigint()], [isRpcQuantityString, z.string()], ], "Expected a bigint or a valid RPC quantity string", diff --git a/v-next/hardhat/src/internal/builtin-plugins/network-manager/rpc/utils.ts b/v-next/hardhat/src/internal/builtin-plugins/network-manager/rpc/utils.ts index 26ecc38290..25318c4343 100644 --- a/v-next/hardhat/src/internal/builtin-plugins/network-manager/rpc/utils.ts +++ b/v-next/hardhat/src/internal/builtin-plugins/network-manager/rpc/utils.ts @@ -1,14 +1,9 @@ export function isRpcQuantityString(u: unknown): u is string { return ( - typeof u === "string" && - u.match(/^0x(?:0|(?:[1-9a-fA-F][0-9a-fA-F]*))$/) !== null + typeof u === "string" && /^0x(?:0|(?:[1-9a-fA-F][0-9a-fA-F]*))$/.test(u) ); } export function isRpcDataString(u: unknown): u is string { - return typeof u === "string" && u.match(/^0x(?:[0-9a-fA-F]{2})*$/) !== null; -} - -export function isBigInt(x: unknown): x is bigint { - return typeof x === "bigint"; + return typeof u === "string" && /^0x(?:[0-9a-fA-F]{2})*$/.test(u); } diff --git a/v-next/hardhat/src/internal/builtin-plugins/network-manager/type-extensions/config.ts b/v-next/hardhat/src/internal/builtin-plugins/network-manager/type-extensions/config.ts index bbb90b46cb..93a5dec461 100644 --- a/v-next/hardhat/src/internal/builtin-plugins/network-manager/type-extensions/config.ts +++ b/v-next/hardhat/src/internal/builtin-plugins/network-manager/type-extensions/config.ts @@ -1,5 +1,4 @@ import type { ChainType, DefaultChainType } from "../../../../types/network.js"; -import type { HttpHeader } from "@ignored/edr-optimism"; import "../../../../types/config.js"; declare module "../../../../types/config.js" { @@ -227,7 +226,7 @@ declare module "../../../../types/config.js" { url: ResolvedConfigurationVariable; cacheDir: string; blockNumber?: bigint; - httpHeaders?: HttpHeader[]; + httpHeaders?: Record; } export interface EdrNetworkMiningConfig { diff --git a/v-next/hardhat/src/internal/builtin-plugins/network-manager/type-validation.ts b/v-next/hardhat/src/internal/builtin-plugins/network-manager/type-validation.ts index 1aabf35534..31b7b13c11 100644 --- a/v-next/hardhat/src/internal/builtin-plugins/network-manager/type-validation.ts +++ b/v-next/hardhat/src/internal/builtin-plugins/network-manager/type-validation.ts @@ -24,6 +24,12 @@ import { } from "@ignored/hardhat-vnext-zod-utils"; import { z } from "zod"; +import { + GENERIC_CHAIN_TYPE, + L1_CHAIN_TYPE, + OPTIMISM_CHAIN_TYPE, +} from "../../constants.js"; + import { hardforkGte, HardforkName, @@ -71,8 +77,12 @@ const httpNetworkAccountsUserConfigSchema = conditionalUnionType( ); const chainTypeUserConfigSchema = unionType( - [z.literal("l1"), z.literal("optimism"), z.literal("generic")], - "Expected 'l1', 'optimism', or 'generic'", + [ + z.literal(L1_CHAIN_TYPE), + z.literal(OPTIMISM_CHAIN_TYPE), + z.literal(GENERIC_CHAIN_TYPE), + ], + `Expected '${L1_CHAIN_TYPE}', '${OPTIMISM_CHAIN_TYPE}', or '${GENERIC_CHAIN_TYPE}'`, ); const gasUnitUserConfigSchema = unionType( @@ -270,8 +280,12 @@ const userConfigSchema = z.object({ }); const chainTypeConfigSchema = unionType( - [z.literal("l1"), z.literal("optimism"), z.literal("generic")], - "Expected 'l1', 'optimism', or 'generic'", + [ + z.literal(L1_CHAIN_TYPE), + z.literal(OPTIMISM_CHAIN_TYPE), + z.literal(GENERIC_CHAIN_TYPE), + ], + `Expected '${L1_CHAIN_TYPE}', '${OPTIMISM_CHAIN_TYPE}', or '${GENERIC_CHAIN_TYPE}'`, ); const gasUnitConfigSchema = nonnegativeBigIntSchema; diff --git a/v-next/hardhat/src/internal/builtin-plugins/node/task-action.ts b/v-next/hardhat/src/internal/builtin-plugins/node/task-action.ts index 1d20955fe4..887c23afa4 100644 --- a/v-next/hardhat/src/internal/builtin-plugins/node/task-action.ts +++ b/v-next/hardhat/src/internal/builtin-plugins/node/task-action.ts @@ -7,6 +7,7 @@ import chalk from "chalk"; import { resolveConfigurationVariable } from "../../core/configuration-variables.js"; import { resolveForkingConfig } from "../network-manager/config-resolution.js"; +import { isEdrSupportedChainType } from "../network-manager/edr/utils/chain-type.js"; import { JsonRpcServerImplementation } from "./json-rpc/server.js"; @@ -47,11 +48,7 @@ const nodeAction: NewTaskActionFunction = async ( const networkConfigOverride: Partial = {}; if (args.chainType !== "") { - if ( - args.chainType !== "generic" && - args.chainType !== "l1" && - args.chainType !== "optimism" - ) { + if (!isEdrSupportedChainType(args.chainType)) { // NOTE: We could make the error more specific here. throw new HardhatError( HardhatError.ERRORS.ARGUMENTS.INVALID_VALUE_FOR_TYPE, diff --git a/v-next/hardhat/src/internal/constants.ts b/v-next/hardhat/src/internal/constants.ts index 17ed46844e..d6b4fee16d 100644 --- a/v-next/hardhat/src/internal/constants.ts +++ b/v-next/hardhat/src/internal/constants.ts @@ -2,6 +2,9 @@ export const HARDHAT_PACKAGE_NAME = "hardhat"; export const HARDHAT_NAME = "Hardhat"; export const HARDHAT_WEBSITE_URL = "https://hardhat.org/"; -export const HARDHAT_NETWORK_RESET_EVENT = "hardhatNetworkReset"; -export const HARDHAT_NETWORK_REVERT_SNAPSHOT_EVENT = - "hardhatNetworkRevertSnapshot"; +export const EDR_NETWORK_RESET_EVENT = "hardhatNetworkReset"; +export const EDR_NETWORK_REVERT_SNAPSHOT_EVENT = "hardhatNetworkRevertSnapshot"; + +export const GENERIC_CHAIN_TYPE = "generic"; +export const L1_CHAIN_TYPE = "l1"; +export const OPTIMISM_CHAIN_TYPE = "optimism"; diff --git a/v-next/hardhat/src/types/config.ts b/v-next/hardhat/src/types/config.ts index e801e37381..0ca64af217 100644 --- a/v-next/hardhat/src/types/config.ts +++ b/v-next/hardhat/src/types/config.ts @@ -49,7 +49,7 @@ export interface ResolvedConfigurationVariable { /** * A function that resolves a configuration variable. */ -export type ConfigurationResolver = ( +export type ConfigurationVariableResolver = ( variableOrString: ConfigurationVariable | string, ) => ResolvedConfigurationVariable; diff --git a/v-next/hardhat/test/internal/builtin-plugins/network-manager/hook-handlers/config.ts b/v-next/hardhat/test/internal/builtin-plugins/network-manager/hook-handlers/config.ts index 7462a5571c..e908750145 100644 --- a/v-next/hardhat/test/internal/builtin-plugins/network-manager/hook-handlers/config.ts +++ b/v-next/hardhat/test/internal/builtin-plugins/network-manager/hook-handlers/config.ts @@ -15,6 +15,10 @@ import { resolveUserConfig, } from "../../../../../src/internal/builtin-plugins/network-manager/hook-handlers/config.js"; import { validateNetworkUserConfig } from "../../../../../src/internal/builtin-plugins/network-manager/type-validation.js"; +import { + GENERIC_CHAIN_TYPE, + L1_CHAIN_TYPE, +} from "../../../../../src/internal/constants.js"; import { FixedValueConfigurationVariable, resolveConfigurationVariable, @@ -98,13 +102,13 @@ describe("network-manager/hook-handlers/config", () => { describe("validateUserConfig", () => { it("should pass if the config is valid", async () => { const config: HardhatUserConfig = { - defaultChainType: "generic", + defaultChainType: GENERIC_CHAIN_TYPE, defaultNetwork: "localhost", networks: { localhost: { type: "http", chainId: 1337, - chainType: "l1", + chainType: L1_CHAIN_TYPE, from: "0x123", gas: "auto", gasMultiplier: 1.5, @@ -1210,7 +1214,7 @@ describe("network-manager/hook-handlers/config", () => { next, ); - assert.equal(resolvedConfig.defaultChainType, "generic"); + assert.equal(resolvedConfig.defaultChainType, GENERIC_CHAIN_TYPE); assert.equal(resolvedConfig.defaultNetwork, "hardhat"); assert.deepEqual(resolvedConfig.networks, { localhost: { @@ -1233,13 +1237,13 @@ describe("network-manager/hook-handlers/config", () => { const userConfig: HardhatUserConfig = { // To change the defaultChainType, we need to augment the Hardhat types. // Since this can't be done for a single test, we'll leave this untested. - defaultChainType: "generic", + defaultChainType: GENERIC_CHAIN_TYPE, defaultNetwork: "myNetwork", networks: { myNetwork: { type: "http", chainId: 1234, - chainType: "l1", + chainType: L1_CHAIN_TYPE, from: "0x123", gas: "auto", gasMultiplier: 1.5, @@ -1266,14 +1270,14 @@ describe("network-manager/hook-handlers/config", () => { next, ); - assert.equal(resolvedConfig.defaultChainType, "generic"); + assert.equal(resolvedConfig.defaultChainType, GENERIC_CHAIN_TYPE); assert.equal(resolvedConfig.defaultNetwork, "myNetwork"); assert.equal(resolvedConfig.networks.myNetwork.type, "http"); assert.deepEqual(resolvedConfig.networks, { myNetwork: { type: "http", chainId: 1234, - chainType: "l1", + chainType: L1_CHAIN_TYPE, from: "0x123", gas: "auto", gasMultiplier: 1.5, @@ -1299,7 +1303,7 @@ describe("network-manager/hook-handlers/config", () => { myNetwork: { type: "http", chainId: 1234, - chainType: "l1", + chainType: L1_CHAIN_TYPE, from: "0x123", gas: "auto", gasMultiplier: 1.5, @@ -1335,7 +1339,7 @@ describe("network-manager/hook-handlers/config", () => { myNetwork: { type: "http", chainId: 1234, - chainType: "l1", + chainType: L1_CHAIN_TYPE, from: "0x123", gas: "auto", gasMultiplier: 1.5, @@ -1371,7 +1375,7 @@ describe("network-manager/hook-handlers/config", () => { myNetwork: { type: "http", chainId: 1234, - chainType: "l1", + chainType: L1_CHAIN_TYPE, from: "0x123", gas: "auto", gasMultiplier: 1.5, @@ -1405,7 +1409,7 @@ describe("network-manager/hook-handlers/config", () => { myNetwork: { type: "http", chainId: 1234, - chainType: "l1", + chainType: L1_CHAIN_TYPE, from: "0x123", gas: "auto", gasMultiplier: 1.5, diff --git a/v-next/hardhat/test/internal/builtin-plugins/network-manager/network-connection.ts b/v-next/hardhat/test/internal/builtin-plugins/network-manager/network-connection.ts index 6076ae8dd3..c0af02b123 100644 --- a/v-next/hardhat/test/internal/builtin-plugins/network-manager/network-connection.ts +++ b/v-next/hardhat/test/internal/builtin-plugins/network-manager/network-connection.ts @@ -6,6 +6,7 @@ import { describe, it } from "node:test"; import { HttpProvider } from "../../../../src/internal/builtin-plugins/network-manager/http-provider.js"; import { NetworkConnectionImplementation } from "../../../../src/internal/builtin-plugins/network-manager/network-connection.js"; +import { GENERIC_CHAIN_TYPE } from "../../../../src/internal/constants.js"; import { FixedValueConfigurationVariable } from "../../../../src/internal/core/configuration-variables.js"; describe("NetworkConnectionImplementation", () => { @@ -43,7 +44,7 @@ describe("NetworkConnectionImplementation", () => { const networkConnection = await NetworkConnectionImplementation.create( 1, "localhost", - "generic", + GENERIC_CHAIN_TYPE, localhostNetworkConfig, closeConnection, createProvider, @@ -51,7 +52,7 @@ describe("NetworkConnectionImplementation", () => { assert.equal(networkConnection.id, 1); assert.equal(networkConnection.networkName, "localhost"); - assert.equal(networkConnection.chainType, "generic"); + assert.equal(networkConnection.chainType, GENERIC_CHAIN_TYPE); assert.deepEqual(networkConnection.networkConfig, localhostNetworkConfig); assert.deepEqual(networkConnection.provider, expectedProvider); }); diff --git a/v-next/hardhat/test/internal/builtin-plugins/network-manager/network-manager.ts b/v-next/hardhat/test/internal/builtin-plugins/network-manager/network-manager.ts index 2960b4e7a2..c9e962ab98 100644 --- a/v-next/hardhat/test/internal/builtin-plugins/network-manager/network-manager.ts +++ b/v-next/hardhat/test/internal/builtin-plugins/network-manager/network-manager.ts @@ -17,6 +17,11 @@ import { expectTypeOf } from "expect-type"; import { createHardhatRuntimeEnvironment } from "../../../../src/hre.js"; import { NetworkManagerImplementation } from "../../../../src/internal/builtin-plugins/network-manager/network-manager.js"; import { validateNetworkConfig } from "../../../../src/internal/builtin-plugins/network-manager/type-validation.js"; +import { + GENERIC_CHAIN_TYPE, + L1_CHAIN_TYPE, + OPTIMISM_CHAIN_TYPE, +} from "../../../../src/internal/constants.js"; import { FixedValueConfigurationVariable } from "../../../../src/internal/core/configuration-variables.js"; describe("NetworkManagerImplementation", () => { @@ -52,7 +57,7 @@ describe("NetworkManagerImplementation", () => { myNetwork: { type: "http", chainId: undefined, - chainType: "optimism", + chainType: OPTIMISM_CHAIN_TYPE, from: undefined, gas: "auto", gasMultiplier: 1, @@ -68,7 +73,7 @@ describe("NetworkManagerImplementation", () => { hre = await createHardhatRuntimeEnvironment({}); networkManager = new NetworkManagerImplementation( "localhost", - "generic", + GENERIC_CHAIN_TYPE, networks, hre.hooks, ); @@ -78,42 +83,42 @@ describe("NetworkManagerImplementation", () => { it("should connect to the default network and chain type if none are provided", async () => { const networkConnection = await networkManager.connect(); assert.equal(networkConnection.networkName, "localhost"); - assert.equal(networkConnection.chainType, "generic"); + assert.equal(networkConnection.chainType, GENERIC_CHAIN_TYPE); assert.deepEqual(networkConnection.networkConfig, networks.localhost); }); it("should connect to the specified network and default chain type if none are provided and the network doesn't have a chain type", async () => { const networkConnection = await networkManager.connect("customNetwork"); assert.equal(networkConnection.networkName, "customNetwork"); - assert.equal(networkConnection.chainType, "generic"); + assert.equal(networkConnection.chainType, GENERIC_CHAIN_TYPE); assert.deepEqual(networkConnection.networkConfig, networks.customNetwork); }); it("should connect to the specified network and use it's chain type if none is provided and the network has a chain type", async () => { const networkConnection = await networkManager.connect("myNetwork"); assert.equal(networkConnection.networkName, "myNetwork"); - assert.equal(networkConnection.chainType, "optimism"); + assert.equal(networkConnection.chainType, OPTIMISM_CHAIN_TYPE); assert.deepEqual(networkConnection.networkConfig, networks.myNetwork); }); it("should connect to the specified network and chain type", async () => { const networkConnection = await networkManager.connect( "myNetwork", - "optimism", + OPTIMISM_CHAIN_TYPE, ); assert.equal(networkConnection.networkName, "myNetwork"); - assert.equal(networkConnection.chainType, "optimism"); + assert.equal(networkConnection.chainType, OPTIMISM_CHAIN_TYPE); assert.deepEqual(networkConnection.networkConfig, networks.myNetwork); }); it("should override the network's chain config with the specified chain config", async () => { const networkConnection = await networkManager.connect( "myNetwork", - "optimism", + OPTIMISM_CHAIN_TYPE, { chainId: 1234 }, ); assert.equal(networkConnection.networkName, "myNetwork"); - assert.equal(networkConnection.chainType, "optimism"); + assert.equal(networkConnection.chainType, OPTIMISM_CHAIN_TYPE); assert.deepEqual(networkConnection.networkConfig, { ...networks.myNetwork, chainId: 1234, @@ -132,7 +137,9 @@ describe("NetworkManagerImplementation", () => { await assertRejectsWithHardhatError( /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Cast to test validation error */ - networkManager.connect("myNetwork", "l1", { type: "l1" } as any), + networkManager.connect("myNetwork", L1_CHAIN_TYPE, { + type: L1_CHAIN_TYPE, + } as any), HardhatError.ERRORS.NETWORK.INVALID_CONFIG_OVERRIDE, { errors: `\t* The type of the network cannot be changed.`, @@ -142,7 +149,9 @@ describe("NetworkManagerImplementation", () => { await assertRejectsWithHardhatError( /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Cast to test validation error */ - networkManager.connect("myNetwork", "l1", { type: undefined } as any), + networkManager.connect("myNetwork", L1_CHAIN_TYPE, { + type: undefined, + } as any), HardhatError.ERRORS.NETWORK.INVALID_CONFIG_OVERRIDE, { errors: `\t* The type of the network cannot be changed.`, @@ -154,7 +163,7 @@ describe("NetworkManagerImplementation", () => { await assertRejectsWithHardhatError( /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Cast to test validation error */ - networkManager.connect("myNetwork", "optimism", { + networkManager.connect("myNetwork", OPTIMISM_CHAIN_TYPE, { chainId: "1234", } as any), HardhatError.ERRORS.NETWORK.INVALID_CONFIG_OVERRIDE, @@ -166,12 +175,12 @@ describe("NetworkManagerImplementation", () => { it("should throw an error if the specified chain type doesn't match the network's chain type", async () => { await assertRejectsWithHardhatError( - networkManager.connect("myNetwork", "l1"), + networkManager.connect("myNetwork", L1_CHAIN_TYPE), HardhatError.ERRORS.NETWORK.INVALID_CHAIN_TYPE, { networkName: "myNetwork", - chainType: "l1", - networkChainType: "optimism", + chainType: L1_CHAIN_TYPE, + networkChainType: OPTIMISM_CHAIN_TYPE, }, ); }); @@ -207,7 +216,7 @@ describe("NetworkManagerImplementation", () => { it("should create a NetworkConnection with the provided chain type", async () => { const networkConnection = await networkManager.connect( "localhost", - "l1", + L1_CHAIN_TYPE, ); expectTypeOf(networkConnection).toEqualTypeOf< NetworkConnection<"l1"> diff --git a/v-next/hardhat/test/internal/builtin-plugins/network-manager/request-handlers/handlers/accounts/automatic-sender-handler.ts b/v-next/hardhat/test/internal/builtin-plugins/network-manager/request-handlers/handlers/accounts/automatic-sender-handler.ts index c891371761..65f34a9222 100644 --- a/v-next/hardhat/test/internal/builtin-plugins/network-manager/request-handlers/handlers/accounts/automatic-sender-handler.ts +++ b/v-next/hardhat/test/internal/builtin-plugins/network-manager/request-handlers/handlers/accounts/automatic-sender-handler.ts @@ -1,9 +1,8 @@ -import type { JsonRpcTransactionData } from "../../../../../../../src/internal/builtin-plugins/network-manager/request-handlers/handlers/accounts/types.js"; - import assert from "node:assert/strict"; import { before, describe, it } from "node:test"; import { numberToHexString } from "@ignored/hardhat-vnext-utils/hex"; +import { isObject } from "@ignored/hardhat-vnext-utils/lang"; import { getJsonRpcRequest, @@ -15,7 +14,14 @@ import { EthereumMockedProvider } from "../../ethereum-mocked-provider.js"; describe("AutomaticSenderHandler", function () { let automaticSenderHandler: AutomaticSenderHandler; let mockedProvider: EthereumMockedProvider; - let tx: JsonRpcTransactionData; + let tx: { + from?: string; + to: string; + gas: string; + gasPrice: string; + value: string; + nonce: string; + }; before(() => { mockedProvider = new EthereumMockedProvider(); @@ -40,10 +46,9 @@ describe("AutomaticSenderHandler", function () { await automaticSenderHandler.handle(jsonRpcRequest); - assert.equal( - getRequestParams(jsonRpcRequest)[0].from, - "0x123006d4548a3ac17d72b372ae1e416bf65b8eaf", - ); + const [requestTx] = getRequestParams(jsonRpcRequest); + assert.ok(isObject(requestTx), "tx is not an object"); + assert.equal(requestTx.from, "0x123006d4548a3ac17d72b372ae1e416bf65b8eaf"); }); it("should not replace transaction's from", async () => { @@ -51,10 +56,9 @@ describe("AutomaticSenderHandler", function () { const jsonRpcRequest = getJsonRpcRequest(1, "eth_sendTransaction", [tx]); - assert.equal( - getRequestParams(jsonRpcRequest)[0].from, - "0x000006d4548a3ac17d72b372ae1e416bf65b8ead", - ); + const [requestTx] = getRequestParams(jsonRpcRequest); + assert.ok(isObject(requestTx), "tx is not an object"); + assert.equal(requestTx.from, "0x000006d4548a3ac17d72b372ae1e416bf65b8ead"); }); it("should not fail on eth_calls if provider doesn't have any accounts", async () => { @@ -66,6 +70,8 @@ describe("AutomaticSenderHandler", function () { await automaticSenderHandler.handle(jsonRpcRequest); - assert.equal(getRequestParams(jsonRpcRequest)[0].value, "asd"); + const [requestTx] = getRequestParams(jsonRpcRequest); + assert.ok(isObject(requestTx), "tx is not an object"); + assert.equal(requestTx.value, "asd"); }); }); diff --git a/v-next/hardhat/test/internal/builtin-plugins/network-manager/request-handlers/handlers/accounts/fixed-sender-handler.ts b/v-next/hardhat/test/internal/builtin-plugins/network-manager/request-handlers/handlers/accounts/fixed-sender-handler.ts index 08e171d987..2285af0639 100644 --- a/v-next/hardhat/test/internal/builtin-plugins/network-manager/request-handlers/handlers/accounts/fixed-sender-handler.ts +++ b/v-next/hardhat/test/internal/builtin-plugins/network-manager/request-handlers/handlers/accounts/fixed-sender-handler.ts @@ -1,9 +1,8 @@ -import type { JsonRpcTransactionData } from "../../../../../../../src/internal/builtin-plugins/network-manager/request-handlers/handlers/accounts/types.js"; - import assert from "node:assert/strict"; import { before, describe, it } from "node:test"; import { numberToHexString } from "@ignored/hardhat-vnext-utils/hex"; +import { isObject } from "@ignored/hardhat-vnext-utils/lang"; import { getJsonRpcRequest, @@ -15,7 +14,14 @@ import { EthereumMockedProvider } from "../../ethereum-mocked-provider.js"; describe("FixedSenderHandler", function () { let fixedSenderHandler: FixedSenderHandler; let mockedProvider: EthereumMockedProvider; - let tx: JsonRpcTransactionData; + let tx: { + from?: string; + to: string; + gas: string; + gasPrice: string; + value: string; + nonce: string; + }; before(() => { mockedProvider = new EthereumMockedProvider(); @@ -39,10 +45,9 @@ describe("FixedSenderHandler", function () { await fixedSenderHandler.handle(jsonRpcRequest); - assert.equal( - getRequestParams(jsonRpcRequest)[0].from, - "0x2a97a65d5673a2c61e95ce33cecadf24f654f96d", - ); + const [requestTx] = getRequestParams(jsonRpcRequest); + assert.ok(isObject(requestTx), "tx is not an object"); + assert.equal(requestTx.from, "0x2a97a65d5673a2c61e95ce33cecadf24f654f96d"); }); it("should not replace transaction's from", async () => { @@ -52,9 +57,8 @@ describe("FixedSenderHandler", function () { await fixedSenderHandler.handle(jsonRpcRequest); - assert.equal( - getRequestParams(jsonRpcRequest)[0].from, - "0x000006d4548a3ac17d72b372ae1e416bf65b8ead", - ); + const [requestTx] = getRequestParams(jsonRpcRequest); + assert.ok(isObject(requestTx), "tx is not an object"); + assert.equal(requestTx.from, "0x000006d4548a3ac17d72b372ae1e416bf65b8ead"); }); }); diff --git a/v-next/hardhat/test/internal/builtin-plugins/network-manager/request-handlers/handlers/gas/automatic-gas-handler.ts b/v-next/hardhat/test/internal/builtin-plugins/network-manager/request-handlers/handlers/gas/automatic-gas-handler.ts index 6ca98ba49d..f9e4de47b3 100644 --- a/v-next/hardhat/test/internal/builtin-plugins/network-manager/request-handlers/handlers/gas/automatic-gas-handler.ts +++ b/v-next/hardhat/test/internal/builtin-plugins/network-manager/request-handlers/handlers/gas/automatic-gas-handler.ts @@ -2,6 +2,7 @@ import assert from "node:assert/strict"; import { beforeEach, describe, it } from "node:test"; import { numberToHexString } from "@ignored/hardhat-vnext-utils/hex"; +import { isObject } from "@ignored/hardhat-vnext-utils/lang"; import { getJsonRpcRequest, @@ -48,9 +49,11 @@ describe("AutomaticGasHandler", () => { ]); await automaticGasHandler.handle(jsonRpcRequest); + const [tx] = getRequestParams(jsonRpcRequest); + assert.ok(isObject(tx), "tx is not an object"); assert.equal( - getRequestParams(jsonRpcRequest)[0].gas, + tx.gas, numberToHexString(Math.floor(FIXED_GAS_LIMIT * GAS_MULTIPLIER)), ); }); @@ -72,9 +75,11 @@ describe("AutomaticGasHandler", () => { ); await automaticGasHandler.handle(jsonRpcRequest); + const [tx] = getRequestParams(jsonRpcRequest); + assert.ok(isObject(tx), "tx is not an object"); assert.equal( - getRequestParams(jsonRpcRequest)[0].gas, + tx.gas, numberToHexString(Math.floor(FIXED_GAS_LIMIT * GAS_MULTIPLIER2)), ); }); @@ -91,9 +96,11 @@ describe("AutomaticGasHandler", () => { automaticGasHandler = new AutomaticGasHandler(mockedProvider); await automaticGasHandler.handle(jsonRpcRequest); + const [tx] = getRequestParams(jsonRpcRequest); + assert.ok(isObject(tx), "tx is not an object"); assert.equal( - getRequestParams(jsonRpcRequest)[0].gas, + tx.gas, numberToHexString(Math.floor(FIXED_GAS_LIMIT * DEFAULT_GAS_MULTIPLIER)), ); }); @@ -109,8 +116,10 @@ describe("AutomaticGasHandler", () => { ]); await automaticGasHandler.handle(jsonRpcRequest); + const [tx] = getRequestParams(jsonRpcRequest); - assert.equal(getRequestParams(jsonRpcRequest)[0].gas, 567); + assert.ok(isObject(tx), "tx is not an object"); + assert.equal(tx.gas, 567); }); it("should forward the other calls", async () => { @@ -123,7 +132,9 @@ describe("AutomaticGasHandler", () => { ]); await automaticGasHandler.handle(jsonRpcRequest); + const [tx] = getRequestParams(jsonRpcRequest); - assert.equal(getRequestParams(jsonRpcRequest)[0].gas, undefined); + assert.ok(isObject(tx), "tx is not an object"); + assert.equal(tx.gas, undefined); }); }); diff --git a/v-next/hardhat/test/internal/builtin-plugins/network-manager/request-handlers/handlers/gas/automatic-gas-price-handler.ts b/v-next/hardhat/test/internal/builtin-plugins/network-manager/request-handlers/handlers/gas/automatic-gas-price-handler.ts index 01b8448039..3ff05d8659 100644 --- a/v-next/hardhat/test/internal/builtin-plugins/network-manager/request-handlers/handlers/gas/automatic-gas-price-handler.ts +++ b/v-next/hardhat/test/internal/builtin-plugins/network-manager/request-handlers/handlers/gas/automatic-gas-price-handler.ts @@ -2,6 +2,7 @@ import assert from "node:assert/strict"; import { beforeEach, describe, it } from "node:test"; import { numberToHexString } from "@ignored/hardhat-vnext-utils/hex"; +import { isObject } from "@ignored/hardhat-vnext-utils/lang"; import { getJsonRpcRequest, @@ -39,8 +40,10 @@ describe("AutomaticGasPriceHandler", () => { ]); automaticGasPriceHandler.handle(jsonRpcRequest); + const [tx] = getRequestParams(jsonRpcRequest); - assert.equal(getRequestParams(jsonRpcRequest)[0].gasPrice, 456); + assert.ok(isObject(tx), "tx is not an object"); + assert.equal(tx.gasPrice, 456); }); it("shouldn't replace the provided maxFeePerGas and maxPriorityFeePerGas values", async () => { @@ -55,12 +58,11 @@ describe("AutomaticGasPriceHandler", () => { ]); automaticGasPriceHandler.handle(jsonRpcRequest); + const [tx] = getRequestParams(jsonRpcRequest); - assert.equal(getRequestParams(jsonRpcRequest)[0].maxFeePerGas, 456); - assert.equal( - getRequestParams(jsonRpcRequest)[0].maxPriorityFeePerGas, - 789, - ); + assert.ok(isObject(tx), "tx is not an object"); + assert.equal(tx.maxFeePerGas, 456); + assert.equal(tx.maxPriorityFeePerGas, 789); }); }); @@ -95,12 +97,11 @@ describe("AutomaticGasPriceHandler", () => { ]); await automaticGasPriceHandler.handle(jsonRpcRequest); + const [tx] = getRequestParams(jsonRpcRequest); - assert.equal( - getRequestParams(jsonRpcRequest)[0].maxPriorityFeePerGas, - "0x4", - ); - assert.equal(getRequestParams(jsonRpcRequest)[0].maxFeePerGas, "0x99"); + assert.ok(isObject(tx), "tx is not an object"); + assert.equal(tx.maxPriorityFeePerGas, "0x4"); + assert.equal(tx.maxFeePerGas, "0x99"); }); it("should add the reward to the maxFeePerGas if not big enough", async () => { @@ -114,12 +115,11 @@ describe("AutomaticGasPriceHandler", () => { ]); await automaticGasPriceHandler.handle(jsonRpcRequest); + const [tx] = getRequestParams(jsonRpcRequest); - assert.equal( - getRequestParams(jsonRpcRequest)[0].maxPriorityFeePerGas, - "0x4", - ); - assert.equal(getRequestParams(jsonRpcRequest)[0].maxFeePerGas, "0x5"); + assert.ok(isObject(tx), "tx is not an object"); + assert.equal(tx.maxPriorityFeePerGas, "0x4"); + assert.equal(tx.maxFeePerGas, "0x5"); }); it("should use the expected max base fee of N blocks in the future if maxFeePerGas is missing", async () => { @@ -141,15 +141,11 @@ describe("AutomaticGasPriceHandler", () => { ); await automaticGasPriceHandler.handle(jsonRpcRequest); + const [tx] = getRequestParams(jsonRpcRequest); - assert.equal( - getRequestParams(jsonRpcRequest)[0].maxPriorityFeePerGas, - "0x1", - ); - assert.equal( - getRequestParams(jsonRpcRequest)[0].maxFeePerGas, - numberToHexString(expectedBaseFee), - ); + assert.ok(isObject(tx), "tx is not an object"); + assert.equal(tx.maxPriorityFeePerGas, "0x1"); + assert.equal(tx.maxFeePerGas, numberToHexString(expectedBaseFee)); }); }); @@ -190,15 +186,11 @@ describe("AutomaticGasPriceHandler", () => { ); await automaticGasPriceHandler.handle(jsonRpcRequest); + const [tx] = getRequestParams(jsonRpcRequest); - assert.equal( - getRequestParams(jsonRpcRequest)[0].maxPriorityFeePerGas, - "0x1", - ); - assert.equal( - getRequestParams(jsonRpcRequest)[0].maxFeePerGas, - numberToHexString(expectedBaseFee), - ); + assert.ok(isObject(tx), "tx is not an object"); + assert.equal(tx.maxPriorityFeePerGas, "0x1"); + assert.equal(tx.maxFeePerGas, numberToHexString(expectedBaseFee)); }); }); @@ -241,15 +233,11 @@ describe("AutomaticGasPriceHandler", () => { ); await automaticGasPriceHandler.handle(jsonRpcRequest); + const [tx] = getRequestParams(jsonRpcRequest); - assert.equal( - getRequestParams(jsonRpcRequest)[0].maxPriorityFeePerGas, - "0x12", - ); - assert.equal( - getRequestParams(jsonRpcRequest)[0].maxFeePerGas, - numberToHexString(expectedBaseFee), - ); + assert.ok(isObject(tx), "tx is not an object"); + assert.equal(tx.maxPriorityFeePerGas, "0x12"); + assert.equal(tx.maxFeePerGas, numberToHexString(expectedBaseFee)); }); }); @@ -295,11 +283,10 @@ describe("AutomaticGasPriceHandler", () => { ]); await automaticGasPriceHandler.handle(jsonRpcRequest); + const [tx] = getRequestParams(jsonRpcRequest); - assert.equal( - getRequestParams(jsonRpcRequest)[0].gasPrice, - numberToHexString(FIXED_GAS_PRICE), - ); + assert.ok(isObject(tx), "tx is not an object"); + assert.equal(tx.gasPrice, numberToHexString(FIXED_GAS_PRICE)); }); it("should use gasPrice as default maxPriorityFeePerGas, adding it to maxFeePerGas if necessary", async () => { @@ -313,15 +300,14 @@ describe("AutomaticGasPriceHandler", () => { ]); await automaticGasPriceHandler.handle(jsonRpcRequest); + const [tx] = getRequestParams(jsonRpcRequest); + assert.ok(isObject(tx), "tx is not an object"); assert.equal( - getRequestParams(jsonRpcRequest)[0].maxPriorityFeePerGas, + tx.maxPriorityFeePerGas, numberToHexString(FIXED_GAS_PRICE), ); - assert.equal( - getRequestParams(jsonRpcRequest)[0].maxFeePerGas, - numberToHexString(FIXED_GAS_PRICE + 1), - ); + assert.equal(tx.maxFeePerGas, numberToHexString(FIXED_GAS_PRICE + 1)); }); it("should use gasPrice as default maxFeePerGas, fixing maxPriorityFee to it if necessary", async () => { @@ -335,13 +321,15 @@ describe("AutomaticGasPriceHandler", () => { ]); await automaticGasPriceHandler.handle(jsonRpcRequest); + const [tx] = getRequestParams(jsonRpcRequest); + assert.ok(isObject(tx), "tx is not an object"); assert.equal( - getRequestParams(jsonRpcRequest)[0].maxPriorityFeePerGas, + tx.maxPriorityFeePerGas, numberToHexString(FIXED_GAS_PRICE + 2), ); assert.equal( - getRequestParams(jsonRpcRequest)[0].maxFeePerGas, + tx.maxFeePerGas, numberToHexString(FIXED_GAS_PRICE * 2 + 2), ); }); diff --git a/v-next/hardhat/test/internal/builtin-plugins/network-manager/request-handlers/handlers/gas/fixed-gas-handler.ts b/v-next/hardhat/test/internal/builtin-plugins/network-manager/request-handlers/handlers/gas/fixed-gas-handler.ts index 66fbb1f8a7..7d6fb8cbd4 100644 --- a/v-next/hardhat/test/internal/builtin-plugins/network-manager/request-handlers/handlers/gas/fixed-gas-handler.ts +++ b/v-next/hardhat/test/internal/builtin-plugins/network-manager/request-handlers/handlers/gas/fixed-gas-handler.ts @@ -2,6 +2,7 @@ import assert from "node:assert/strict"; import { beforeEach, describe, it } from "node:test"; import { numberToHexString } from "@ignored/hardhat-vnext-utils/hex"; +import { isObject } from "@ignored/hardhat-vnext-utils/lang"; import { getJsonRpcRequest, @@ -28,11 +29,10 @@ describe("FixedGasHandler", () => { ]); fixedGasHandler.handle(jsonRpcRequest); + const [tx] = getRequestParams(jsonRpcRequest); - assert.equal( - getRequestParams(jsonRpcRequest)[0].gas, - numberToHexString(FIXED_GAS_LIMIT), - ); + assert.ok(isObject(tx), "tx is not an object"); + assert.equal(tx.gas, numberToHexString(FIXED_GAS_LIMIT)); }); it("shouldn't replace the provided gas", async () => { @@ -46,8 +46,10 @@ describe("FixedGasHandler", () => { ]); fixedGasHandler.handle(jsonRpcRequest); + const [tx] = getRequestParams(jsonRpcRequest); - assert.equal(getRequestParams(jsonRpcRequest)[0].gas, 1456); + assert.ok(isObject(tx), "tx is not an object"); + assert.equal(tx.gas, 1456); }); it("should forward the other calls and not modify the gas", async () => { @@ -60,7 +62,9 @@ describe("FixedGasHandler", () => { ]); fixedGasHandler.handle(jsonRpcRequest); + const [tx] = getRequestParams(jsonRpcRequest); - assert.equal(getRequestParams(jsonRpcRequest)[0].gas, undefined); + assert.ok(isObject(tx), "tx is not an object"); + assert.equal(tx.gas, undefined); }); }); diff --git a/v-next/hardhat/test/internal/builtin-plugins/network-manager/request-handlers/handlers/gas/fixed-gas-price-handler.ts b/v-next/hardhat/test/internal/builtin-plugins/network-manager/request-handlers/handlers/gas/fixed-gas-price-handler.ts index 354c43d141..f2fc91bdb4 100644 --- a/v-next/hardhat/test/internal/builtin-plugins/network-manager/request-handlers/handlers/gas/fixed-gas-price-handler.ts +++ b/v-next/hardhat/test/internal/builtin-plugins/network-manager/request-handlers/handlers/gas/fixed-gas-price-handler.ts @@ -2,6 +2,7 @@ import assert from "node:assert/strict"; import { beforeEach, describe, it } from "node:test"; import { numberToHexString } from "@ignored/hardhat-vnext-utils/hex"; +import { isObject } from "@ignored/hardhat-vnext-utils/lang"; import { getJsonRpcRequest, @@ -30,11 +31,10 @@ describe("FixedGasPriceHandler", () => { ]); fixedGasPriceHandler.handle(jsonRpcRequest); + const [tx] = getRequestParams(jsonRpcRequest); - assert.equal( - getRequestParams(jsonRpcRequest)[0].gasPrice, - numberToHexString(FIXED_GAS_PRICE), - ); + assert.ok(isObject(tx), "tx is not an object"); + assert.equal(tx.gasPrice, numberToHexString(FIXED_GAS_PRICE)); }); it("shouldn't replace the provided gasPrice", async () => { @@ -48,8 +48,10 @@ describe("FixedGasPriceHandler", () => { ]); fixedGasPriceHandler.handle(jsonRpcRequest); + const [tx] = getRequestParams(jsonRpcRequest); - assert.equal(getRequestParams(jsonRpcRequest)[0].gasPrice, 14567); + assert.ok(isObject(tx), "tx is not an object"); + assert.equal(tx.gasPrice, 14567); }); it("should forward the other calls and not modify the gasPrice", async () => { @@ -62,7 +64,9 @@ describe("FixedGasPriceHandler", () => { ]); fixedGasPriceHandler.handle(jsonRpcRequest); + const [tx] = getRequestParams(jsonRpcRequest); - assert.equal(getRequestParams(jsonRpcRequest)[0].gas, undefined); + assert.ok(isObject(tx), "tx is not an object"); + assert.equal(tx.gas, undefined); }); });