diff --git a/.changeset/four-lies-flash.md b/.changeset/four-lies-flash.md new file mode 100644 index 00000000000..214882a3992 --- /dev/null +++ b/.changeset/four-lies-flash.md @@ -0,0 +1,5 @@ +--- +"hardhat": patch +--- + +Allow overriding the type of the network configs `default` and `localhost` [#7805](https://github.com/NomicFoundation/hardhat/pull/7805) 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 a17807bb8c7..d7bcea55817 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 @@ -38,33 +38,54 @@ export async function extendUserConfig( const networks: Record = extendedConfig.networks ?? {}; - const localhostConfig: Omit = { - // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- This is always http - ...(networks.localhost as HttpNetworkUserConfig), - }; + const localhostConfig: NetworkUserConfig | undefined = networks.localhost; + const defaultConfig: NetworkUserConfig | undefined = networks.default; - const defaultConfig: Partial = { - // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- This is always edr - ...(networks.default as EdrNetworkUserConfig), - }; + let extendedLocalhostConfig: NetworkUserConfig; + if ( + localhostConfig === undefined || + localhostConfig.type === undefined || + localhostConfig.type === "http" + ) { + extendedLocalhostConfig = { + url: "http://localhost:8545", + type: "http", + /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions + -- We cast it here because otherwise TS complains that some fields are + always overwritten, which is not true for js incomplete configs. */ + ...(localhostConfig as Partial), + }; + } else { + extendedLocalhostConfig = localhostConfig; + } + + let extendedDefaultConfig: NetworkUserConfig; + if ( + defaultConfig === undefined || + defaultConfig.type === undefined || + defaultConfig.type === "edr-simulated" + ) { + extendedDefaultConfig = { + chainId: 31337, + gas: "auto", + gasMultiplier: 1, + gasPrice: "auto", + type: "edr-simulated", + /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions + -- We cast it here because otherwise TS complains that some fields are + always overwritten, which is not true for js incomplete configs. */ + ...(defaultConfig as Partial), + }; + } else { + extendedDefaultConfig = defaultConfig; + } return { ...extendedConfig, networks: { ...networks, - localhost: { - url: "http://localhost:8545", - ...localhostConfig, - type: "http", - }, - [DEFAULT_NETWORK_NAME]: { - chainId: 31337, - gas: "auto", - gasMultiplier: 1, - gasPrice: "auto", - ...defaultConfig, - type: "edr-simulated", - }, + localhost: extendedLocalhostConfig, + [DEFAULT_NETWORK_NAME]: extendedDefaultConfig, }, }; } 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 25db2727d66..48d1587ea6c 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 @@ -41,6 +41,43 @@ describe("network-manager/hook-handlers/config", () => { }); }); + it("should extend the localhost network when its type is undefined", async () => { + const config = { + networks: { + localhost: {}, + }, + }; + const next = async (nextConfig: HardhatUserConfig) => nextConfig; + + /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions + -- testing incomplete config for js users */ + const extendedConfig = await extendUserConfig(config as any, next); + assert.deepEqual(extendedConfig.networks?.localhost, { + type: "http", + url: "http://localhost:8545", + }); + }); + + it("should extend the default network when its type is undefined", async () => { + const config = { + networks: { + default: {}, + }, + }; + const next = async (nextConfig: HardhatUserConfig) => nextConfig; + + /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions + -- testing incomplete config for js users */ + const extendedConfig = await extendUserConfig(config as any, next); + assert.deepEqual(extendedConfig.networks?.default, { + chainId: 31337, + gas: "auto", + gasMultiplier: 1, + gasPrice: "auto", + type: "edr-simulated", + }); + }); + it("should allow setting other properties of the localhost network", async () => { const config: HardhatUserConfig = { networks: { @@ -79,24 +116,40 @@ describe("network-manager/hook-handlers/config", () => { }); }); - it("should not allow overriding the type of the localhost network", async () => { + it("should allow overriding the type of the localhost network", async () => { const config = { networks: { localhost: { - type: "http2", + type: "edr-simulated", }, }, - }; + } as const; const next = async (nextConfig: HardhatUserConfig) => nextConfig; - /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions - -- testing invalid network type for js users */ - const extendedConfig = await extendUserConfig(config as any, next); + const extendedConfig = await extendUserConfig(config, next); assert.deepEqual(extendedConfig.networks?.localhost, { - url: "http://localhost:8545", - type: "http", + type: "edr-simulated", }); }); + + it("should allow overriding the type of the default network", async () => { + const config = { + networks: { + default: { + type: "http", + url: "http://localhost:8545", + }, + }, + } as const; + const next = async (nextConfig: HardhatUserConfig) => nextConfig; + + const extendedConfig = await extendUserConfig(config, next); + assert.equal(extendedConfig.networks?.default.type, "http"); + assert.equal( + extendedConfig.networks?.default.url, + "http://localhost:8545", + ); + }); }); describe("validateUserConfig", () => { @@ -1331,6 +1384,93 @@ describe("network-manager/hook-handlers/config", () => { }); }); + it("should resolve the localhost network when its type is overridden to edr-simulated", async () => { + // This is how the user config looks like after it's been extended + // by the extendUserConfig hook handler when the user overrides + // the localhost network type to "edr-simulated". + const extendedConfig: HardhatUserConfig = { + paths: { + cache: "/tmp/hardhat-cache", + }, + networks: { + localhost: { + type: "edr-simulated", + }, + }, + }; + + const resolvedConfig = await resolveUserConfig( + extendedConfig, + (variable) => resolveConfigurationVariable(hre.hooks, variable), + next, + ); + + const localhost = resolvedConfig.networks.localhost; + assert( + localhost.type === "edr-simulated", + "The network type should be edr-simulated", + ); + + assert.equal(localhost.chainId, 31337); + assert.equal(localhost.chainType, undefined); + assert.equal(localhost.from, undefined); + assert.equal(localhost.gas, "auto"); + assert.equal(localhost.gasMultiplier, 1); + assert.equal(localhost.gasPrice, "auto"); + + // EDR-specific fields + assert.equal(localhost.allowBlocksWithSameTimestamp, false); + assert.equal(localhost.allowUnlimitedContractSize, false); + assert.equal(localhost.blockGasLimit, 60_000_000n); + assert.deepEqual(localhost.mining, { + auto: true, + interval: 0, + mempool: { order: "priority" }, + }); + assert.equal(localhost.throwOnCallFailures, true); + assert.equal(localhost.throwOnTransactionFailures, true); + assert.equal(localhost.loggingEnabled, false); + assert.equal(localhost.minGasPrice, 0n); + assert.equal(localhost.networkId, 31337); + assert.equal(localhost.forking, undefined); + }); + + it("should resolve the default network when its type is overridden to http", async () => { + // This is how the user config looks like after it's been extended + // by the extendUserConfig hook handler when the user overrides + // the default network type to "http". + const extendedConfig: HardhatUserConfig = { + networks: { + default: { + type: "http", + url: "http://localhost:8545", + }, + }, + }; + + const resolvedConfig = await resolveUserConfig( + extendedConfig, + (variable) => resolveConfigurationVariable(hre.hooks, variable), + next, + ); + + assert.deepEqual(resolvedConfig.networks, { + default: { + type: "http", + chainId: undefined, + chainType: undefined, + from: undefined, + gas: "auto", + gasMultiplier: 1, + gasPrice: "auto", + accounts: "remote", + url: new FixedValueConfigurationVariable("http://localhost:8545"), + timeout: 300_000, + httpHeaders: {}, + }, + }); + }); + describe("accounts", () => { it("should normalize the accounts' private keys", async () => { const userConfig: HardhatUserConfig = {