hardhat 3.0.6 → 3.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (127) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/dist/src/internal/builtin-plugins/coverage/hook-handlers/solidity.d.ts.map +1 -1
  3. package/dist/src/internal/builtin-plugins/coverage/hook-handlers/solidity.js +1 -2
  4. package/dist/src/internal/builtin-plugins/coverage/hook-handlers/solidity.js.map +1 -1
  5. package/dist/src/internal/builtin-plugins/network-manager/edr/edr-provider.d.ts +1 -0
  6. package/dist/src/internal/builtin-plugins/network-manager/edr/edr-provider.d.ts.map +1 -1
  7. package/dist/src/internal/builtin-plugins/network-manager/edr/edr-provider.js +9 -2
  8. package/dist/src/internal/builtin-plugins/network-manager/edr/edr-provider.js.map +1 -1
  9. package/dist/src/internal/builtin-plugins/network-manager/hook-handlers/hre.d.ts.map +1 -1
  10. package/dist/src/internal/builtin-plugins/network-manager/hook-handlers/hre.js +13 -5
  11. package/dist/src/internal/builtin-plugins/network-manager/hook-handlers/hre.js.map +1 -1
  12. package/dist/src/internal/builtin-plugins/network-manager/hook-handlers/network.js +1 -1
  13. package/dist/src/internal/builtin-plugins/network-manager/hook-handlers/network.js.map +1 -1
  14. package/dist/src/internal/builtin-plugins/network-manager/network-manager.d.ts +4 -3
  15. package/dist/src/internal/builtin-plugins/network-manager/network-manager.d.ts.map +1 -1
  16. package/dist/src/internal/builtin-plugins/network-manager/network-manager.js +79 -37
  17. package/dist/src/internal/builtin-plugins/network-manager/network-manager.js.map +1 -1
  18. package/dist/src/internal/builtin-plugins/network-manager/type-validation.js +3 -3
  19. package/dist/src/internal/builtin-plugins/network-manager/type-validation.js.map +1 -1
  20. package/dist/src/internal/builtin-plugins/node/artifacts/build-info-watcher.d.ts +25 -0
  21. package/dist/src/internal/builtin-plugins/node/artifacts/build-info-watcher.d.ts.map +1 -0
  22. package/dist/src/internal/builtin-plugins/node/artifacts/build-info-watcher.js +56 -0
  23. package/dist/src/internal/builtin-plugins/node/artifacts/build-info-watcher.js.map +1 -0
  24. package/dist/src/internal/builtin-plugins/node/helpers.d.ts +12 -0
  25. package/dist/src/internal/builtin-plugins/node/helpers.d.ts.map +1 -1
  26. package/dist/src/internal/builtin-plugins/node/helpers.js +32 -0
  27. package/dist/src/internal/builtin-plugins/node/helpers.js.map +1 -1
  28. package/dist/src/internal/builtin-plugins/node/json-rpc/server.d.ts +3 -10
  29. package/dist/src/internal/builtin-plugins/node/json-rpc/server.d.ts.map +1 -1
  30. package/dist/src/internal/builtin-plugins/node/json-rpc/server.js +1 -1
  31. package/dist/src/internal/builtin-plugins/node/json-rpc/server.js.map +1 -1
  32. package/dist/src/internal/builtin-plugins/node/task-action.d.ts.map +1 -1
  33. package/dist/src/internal/builtin-plugins/node/task-action.js +14 -4
  34. package/dist/src/internal/builtin-plugins/node/task-action.js.map +1 -1
  35. package/dist/src/internal/builtin-plugins/solidity/build-system/build-system.d.ts +13 -5
  36. package/dist/src/internal/builtin-plugins/solidity/build-system/build-system.d.ts.map +1 -1
  37. package/dist/src/internal/builtin-plugins/solidity/build-system/build-system.js +126 -58
  38. package/dist/src/internal/builtin-plugins/solidity/build-system/build-system.js.map +1 -1
  39. package/dist/src/internal/builtin-plugins/solidity/build-system/cache.d.ts +1 -1
  40. package/dist/src/internal/builtin-plugins/solidity/build-system/cache.d.ts.map +1 -1
  41. package/dist/src/internal/builtin-plugins/solidity/hook-handlers/hre.d.ts.map +1 -1
  42. package/dist/src/internal/builtin-plugins/solidity/hook-handlers/hre.js +14 -6
  43. package/dist/src/internal/builtin-plugins/solidity/hook-handlers/hre.js.map +1 -1
  44. package/dist/src/internal/builtin-plugins/solidity/index.d.ts.map +1 -1
  45. package/dist/src/internal/builtin-plugins/solidity/index.js +8 -0
  46. package/dist/src/internal/builtin-plugins/solidity/index.js.map +1 -1
  47. package/dist/src/internal/builtin-plugins/solidity/tasks/build.d.ts +4 -2
  48. package/dist/src/internal/builtin-plugins/solidity/tasks/build.d.ts.map +1 -1
  49. package/dist/src/internal/builtin-plugins/solidity/tasks/build.js +37 -10
  50. package/dist/src/internal/builtin-plugins/solidity/tasks/build.js.map +1 -1
  51. package/dist/src/internal/builtin-plugins/solidity-test/config.d.ts +4 -2
  52. package/dist/src/internal/builtin-plugins/solidity-test/config.d.ts.map +1 -1
  53. package/dist/src/internal/builtin-plugins/solidity-test/config.js +24 -4
  54. package/dist/src/internal/builtin-plugins/solidity-test/config.js.map +1 -1
  55. package/dist/src/internal/builtin-plugins/solidity-test/helpers.d.ts +1 -1
  56. package/dist/src/internal/builtin-plugins/solidity-test/helpers.d.ts.map +1 -1
  57. package/dist/src/internal/builtin-plugins/solidity-test/helpers.js +12 -3
  58. package/dist/src/internal/builtin-plugins/solidity-test/helpers.js.map +1 -1
  59. package/dist/src/internal/builtin-plugins/solidity-test/hook-handlers/config.d.ts.map +1 -1
  60. package/dist/src/internal/builtin-plugins/solidity-test/hook-handlers/config.js +1 -1
  61. package/dist/src/internal/builtin-plugins/solidity-test/hook-handlers/config.js.map +1 -1
  62. package/dist/src/internal/builtin-plugins/solidity-test/task-action.d.ts.map +1 -1
  63. package/dist/src/internal/builtin-plugins/solidity-test/task-action.js +16 -39
  64. package/dist/src/internal/builtin-plugins/solidity-test/task-action.js.map +1 -1
  65. package/dist/src/internal/builtin-plugins/solidity-test/type-extensions.d.ts +17 -7
  66. package/dist/src/internal/builtin-plugins/solidity-test/type-extensions.d.ts.map +1 -1
  67. package/dist/src/internal/core/hook-manager.d.ts.map +1 -1
  68. package/dist/src/internal/core/hook-manager.js +3 -1
  69. package/dist/src/internal/core/hook-manager.js.map +1 -1
  70. package/dist/src/internal/core/hre.d.ts +29 -1
  71. package/dist/src/internal/core/hre.d.ts.map +1 -1
  72. package/dist/src/internal/core/hre.js +57 -20
  73. package/dist/src/internal/core/hre.js.map +1 -1
  74. package/dist/src/internal/core/plugins/detect-plugin-npm-dependency-problems.d.ts +2 -1
  75. package/dist/src/internal/core/plugins/detect-plugin-npm-dependency-problems.d.ts.map +1 -1
  76. package/dist/src/internal/core/plugins/detect-plugin-npm-dependency-problems.js +5 -4
  77. package/dist/src/internal/core/plugins/detect-plugin-npm-dependency-problems.js.map +1 -1
  78. package/dist/src/internal/core/plugins/resolve-plugin-list.js +41 -4
  79. package/dist/src/internal/core/plugins/resolve-plugin-list.js.map +1 -1
  80. package/dist/src/internal/core/tasks/resolved-task.d.ts.map +1 -1
  81. package/dist/src/internal/core/tasks/resolved-task.js +1 -1
  82. package/dist/src/internal/core/tasks/resolved-task.js.map +1 -1
  83. package/dist/src/internal/utils/package.d.ts +1 -0
  84. package/dist/src/internal/utils/package.d.ts.map +1 -1
  85. package/dist/src/internal/utils/package.js +17 -1
  86. package/dist/src/internal/utils/package.js.map +1 -1
  87. package/dist/src/types/hre.d.ts +4 -0
  88. package/dist/src/types/hre.d.ts.map +1 -1
  89. package/dist/src/types/network.d.ts +40 -0
  90. package/dist/src/types/network.d.ts.map +1 -1
  91. package/dist/src/types/plugins.d.ts +8 -0
  92. package/dist/src/types/plugins.d.ts.map +1 -1
  93. package/dist/src/types/solidity/build-system.d.ts +23 -8
  94. package/dist/src/types/solidity/build-system.d.ts.map +1 -1
  95. package/package.json +5 -4
  96. package/src/internal/builtin-plugins/coverage/hook-handlers/solidity.ts +2 -3
  97. package/src/internal/builtin-plugins/network-manager/edr/edr-provider.ts +20 -1
  98. package/src/internal/builtin-plugins/network-manager/hook-handlers/hre.ts +36 -18
  99. package/src/internal/builtin-plugins/network-manager/hook-handlers/network.ts +1 -1
  100. package/src/internal/builtin-plugins/network-manager/network-manager.ts +137 -60
  101. package/src/internal/builtin-plugins/network-manager/type-validation.ts +3 -3
  102. package/src/internal/builtin-plugins/node/artifacts/build-info-watcher.ts +82 -0
  103. package/src/internal/builtin-plugins/node/helpers.ts +64 -0
  104. package/src/internal/builtin-plugins/node/json-rpc/server.ts +3 -10
  105. package/src/internal/builtin-plugins/node/task-action.ts +31 -5
  106. package/src/internal/builtin-plugins/solidity/build-system/build-system.ts +203 -98
  107. package/src/internal/builtin-plugins/solidity/build-system/cache.ts +1 -1
  108. package/src/internal/builtin-plugins/solidity/hook-handlers/hre.ts +22 -5
  109. package/src/internal/builtin-plugins/solidity/index.ts +8 -0
  110. package/src/internal/builtin-plugins/solidity/tasks/build.ts +59 -16
  111. package/src/internal/builtin-plugins/solidity-test/config.ts +46 -3
  112. package/src/internal/builtin-plugins/solidity-test/helpers.ts +17 -4
  113. package/src/internal/builtin-plugins/solidity-test/hook-handlers/config.ts +5 -1
  114. package/src/internal/builtin-plugins/solidity-test/task-action.ts +21 -48
  115. package/src/internal/builtin-plugins/solidity-test/type-extensions.ts +23 -9
  116. package/src/internal/core/hook-manager.ts +9 -1
  117. package/src/internal/core/hre.ts +102 -32
  118. package/src/internal/core/plugins/detect-plugin-npm-dependency-problems.ts +5 -0
  119. package/src/internal/core/plugins/resolve-plugin-list.ts +58 -4
  120. package/src/internal/core/tasks/resolved-task.ts +1 -0
  121. package/src/internal/utils/package.ts +31 -1
  122. package/src/types/hre.ts +4 -0
  123. package/src/types/network.ts +45 -0
  124. package/src/types/plugins.ts +5 -0
  125. package/src/types/solidity/build-system.ts +23 -7
  126. package/templates/hardhat-3/01-node-test-runner-viem/package.json +3 -3
  127. package/templates/hardhat-3/02-mocha-ethers/package.json +5 -5
@@ -24,6 +24,14 @@ const buildTask = task("build", "Build project")
24
24
  description: "An optional list of files to compile",
25
25
  defaultValue: [],
26
26
  })
27
+ .addFlag({
28
+ name: "noTests",
29
+ description: "Skip solidity tests compilation",
30
+ })
31
+ .addFlag({
32
+ name: "noContracts",
33
+ description: "Skip solidity contracts compilation",
34
+ })
27
35
  .setAction(async () => import("./tasks/build.js"))
28
36
  .build();
29
37
 
@@ -1,3 +1,5 @@
1
+ import type { HardhatRuntimeEnvironment } from "../../../../types/hre.js";
2
+ import type { BuildScope } from "../../../../types/solidity.js";
1
3
  import type { NewTaskActionFunction } from "../../../../types/tasks.js";
2
4
 
3
5
  import { resolveFromRoot } from "@nomicfoundation/hardhat-utils/path";
@@ -5,27 +7,65 @@ import { resolveFromRoot } from "@nomicfoundation/hardhat-utils/path";
5
7
  import { throwIfSolidityBuildFailed } from "../build-results.js";
6
8
  import { isNpmRootPath } from "../build-system/root-paths-utils.js";
7
9
 
8
- interface CompileActionArguments {
10
+ interface BuildActionArguments {
9
11
  force: boolean;
10
12
  files: string[];
11
13
  quiet: boolean;
12
14
  defaultBuildProfile: string | undefined;
15
+ noTests: boolean;
16
+ noContracts: boolean;
13
17
  }
14
18
 
15
- const buildAction: NewTaskActionFunction<CompileActionArguments> = async (
16
- { force, files, quiet, defaultBuildProfile },
17
- { solidity, globalOptions },
19
+ const buildAction: NewTaskActionFunction<BuildActionArguments> = async (
20
+ args: BuildActionArguments,
21
+ hre,
18
22
  ) => {
19
- const rootPaths =
20
- files.length === 0
21
- ? await solidity.getRootFilePaths()
22
- : files.map((file) => {
23
- if (isNpmRootPath(file)) {
24
- return file;
25
- }
23
+ const contractRootPaths = [];
24
+ const testRootPaths = [];
26
25
 
27
- return resolveFromRoot(process.cwd(), file);
28
- });
26
+ if (args.noContracts === false) {
27
+ contractRootPaths.push(...(await buildForScope("contracts", args, hre)));
28
+ }
29
+
30
+ if (args.noTests === false) {
31
+ testRootPaths.push(...(await buildForScope("tests", args, hre)));
32
+ }
33
+
34
+ return { contractRootPaths, testRootPaths };
35
+ };
36
+
37
+ async function buildForScope(
38
+ scope: BuildScope,
39
+ { force, files, quiet, defaultBuildProfile }: BuildActionArguments,
40
+ { solidity, globalOptions }: HardhatRuntimeEnvironment,
41
+ ) {
42
+ // If no specific files are passed, it means a full compilation, i.e. all source files
43
+ const isFullCompilation = files.length === 0;
44
+
45
+ const rootPaths = [];
46
+
47
+ if (isFullCompilation) {
48
+ rootPaths.push(...(await solidity.getRootFilePaths({ scope })));
49
+ } else {
50
+ for (const file of files) {
51
+ if (isNpmRootPath(file)) {
52
+ rootPaths.push(file);
53
+ }
54
+
55
+ const rootPath = resolveFromRoot(process.cwd(), file);
56
+
57
+ if ((await solidity.getScope(rootPath)) !== scope) {
58
+ continue;
59
+ }
60
+
61
+ rootPaths.push(rootPath);
62
+ }
63
+
64
+ // If a file list has been passed but none match this scope, we don't run the build
65
+ if (rootPaths.length === 0) {
66
+ return [];
67
+ }
68
+ }
29
69
 
30
70
  const buildProfile = globalOptions.buildProfile ?? defaultBuildProfile;
31
71
 
@@ -33,14 +73,17 @@ const buildAction: NewTaskActionFunction<CompileActionArguments> = async (
33
73
  force,
34
74
  buildProfile,
35
75
  quiet,
76
+ scope,
36
77
  });
37
78
 
38
79
  throwIfSolidityBuildFailed(results);
39
80
 
40
81
  // If we recompiled the entire project we cleanup the artifacts
41
- if (files.length === 0) {
42
- await solidity.cleanupArtifacts(rootPaths);
82
+ if (isFullCompilation) {
83
+ await solidity.cleanupArtifacts(rootPaths, { scope });
43
84
  }
44
- };
85
+
86
+ return rootPaths;
87
+ }
45
88
 
46
89
  export default buildAction;
@@ -1,6 +1,14 @@
1
1
  import type { HardhatUserConfig } from "../../../config.js";
2
- import type { HardhatConfig } from "../../../types/config.js";
2
+ import type {
3
+ ConfigurationVariableResolver,
4
+ HardhatConfig,
5
+ ResolvedConfigurationVariable,
6
+ } from "../../../types/config.js";
3
7
  import type { HardhatUserConfigValidationError } from "../../../types/hooks.js";
8
+ import type {
9
+ SolidityTestForkingConfig,
10
+ SolidityTestUserConfig,
11
+ } from "../../../types/test.js";
4
12
 
5
13
  import path from "node:path";
6
14
 
@@ -8,6 +16,8 @@ import { isObject } from "@nomicfoundation/hardhat-utils/lang";
8
16
  import { resolveFromRoot } from "@nomicfoundation/hardhat-utils/path";
9
17
  import {
10
18
  conditionalUnionType,
19
+ sensitiveStringSchema,
20
+ sensitiveUrlSchema,
11
21
  validateUserConfigZodType,
12
22
  } from "@nomicfoundation/hardhat-zod-utils";
13
23
  import { z } from "zod";
@@ -49,9 +59,9 @@ const solidityTestUserConfigType = z.object({
49
59
  .optional(),
50
60
  forking: z
51
61
  .object({
52
- url: z.string().optional(),
62
+ url: z.optional(sensitiveUrlSchema),
53
63
  blockNumber: z.bigint().optional(),
54
- rpcEndpoints: z.record(z.string()).optional(),
64
+ rpcEndpoints: z.record(sensitiveStringSchema).optional(),
55
65
  })
56
66
  .optional(),
57
67
  invariant: z
@@ -88,6 +98,32 @@ const userConfigType = z.object({
88
98
  .optional(),
89
99
  });
90
100
 
101
+ export function resolveSolidityTestForkingConfig(
102
+ forkingUserConfig: SolidityTestUserConfig["forking"],
103
+ resolveConfigurationVariable: ConfigurationVariableResolver,
104
+ ): SolidityTestForkingConfig | undefined {
105
+ if (forkingUserConfig === undefined) {
106
+ return undefined;
107
+ }
108
+
109
+ const resolvedRpcEndpoints: Record<string, ResolvedConfigurationVariable> =
110
+ {};
111
+ if (forkingUserConfig.rpcEndpoints !== undefined) {
112
+ for (const [name, url] of Object.entries(forkingUserConfig.rpcEndpoints)) {
113
+ resolvedRpcEndpoints[name] = resolveConfigurationVariable(url);
114
+ }
115
+ }
116
+
117
+ return {
118
+ ...forkingUserConfig,
119
+ url:
120
+ forkingUserConfig.url !== undefined
121
+ ? resolveConfigurationVariable(forkingUserConfig.url)
122
+ : undefined,
123
+ rpcEndpoints: resolvedRpcEndpoints,
124
+ };
125
+ }
126
+
91
127
  export function validateSolidityTestUserConfig(
92
128
  userConfig: unknown,
93
129
  ): HardhatUserConfigValidationError[] {
@@ -97,6 +133,7 @@ export function validateSolidityTestUserConfig(
97
133
  export async function resolveSolidityTestUserConfig(
98
134
  userConfig: HardhatUserConfig,
99
135
  resolvedConfig: HardhatConfig,
136
+ resolveConfigurationVariable: ConfigurationVariableResolver,
100
137
  ): Promise<HardhatConfig> {
101
138
  let testsPath = userConfig.paths?.tests;
102
139
 
@@ -106,9 +143,15 @@ export async function resolveSolidityTestUserConfig(
106
143
 
107
144
  const defaultRpcCachePath = path.join(resolvedConfig.paths.cache, "edr");
108
145
 
146
+ const resolvedForking = resolveSolidityTestForkingConfig(
147
+ userConfig.test?.solidity?.forking,
148
+ resolveConfigurationVariable,
149
+ );
150
+
109
151
  const solidityTest = {
110
152
  rpcCachePath: defaultRpcCachePath,
111
153
  ...userConfig.test?.solidity,
154
+ forking: resolvedForking,
112
155
  };
113
156
 
114
157
  return {
@@ -34,14 +34,14 @@ export function solidityTestConfigToRunOptions(
34
34
  return config;
35
35
  }
36
36
 
37
- export function solidityTestConfigToSolidityTestRunnerConfigArgs(
37
+ export async function solidityTestConfigToSolidityTestRunnerConfigArgs(
38
38
  chainType: ChainType,
39
39
  projectRoot: string,
40
40
  config: SolidityTestConfig,
41
41
  verbosity: number,
42
42
  observability?: ObservabilityConfig,
43
43
  testPattern?: string,
44
- ): SolidityTestRunnerConfigArgs {
44
+ ): Promise<SolidityTestRunnerConfigArgs> {
45
45
  const fsPermissions: PathPermission[] | undefined = [
46
46
  config.fsPermissions?.readWriteFile?.map((p) => ({
47
47
  access: FsAccessPermission.ReadWriteFile,
@@ -98,9 +98,22 @@ export function solidityTestConfigToSolidityTestRunnerConfigArgs(
98
98
 
99
99
  const blockDifficulty = config.prevRandao;
100
100
 
101
- const ethRpcUrl = config.forking?.url;
101
+ let ethRpcUrl: string | undefined;
102
+ if (config.forking?.url !== undefined) {
103
+ ethRpcUrl = await config.forking.url.get();
104
+ }
105
+
102
106
  const forkBlockNumber = config.forking?.blockNumber;
103
- const rpcEndpoints = config.forking?.rpcEndpoints;
107
+
108
+ let rpcEndpoints: Record<string, string> | undefined;
109
+ if (config.forking?.rpcEndpoints !== undefined) {
110
+ rpcEndpoints = {};
111
+ for (const [name, configValue] of Object.entries(
112
+ config.forking.rpcEndpoints,
113
+ )) {
114
+ rpcEndpoints[name] = await configValue.get();
115
+ }
116
+ }
104
117
 
105
118
  return {
106
119
  projectRoot,
@@ -19,7 +19,11 @@ export default async (): Promise<Partial<ConfigHooks>> => {
19
19
  resolveConfigurationVariable,
20
20
  );
21
21
 
22
- return resolveSolidityTestUserConfig(userConfig, resolvedConfig);
22
+ return resolveSolidityTestUserConfig(
23
+ userConfig,
24
+ resolvedConfig,
25
+ resolveConfigurationVariable,
26
+ );
23
27
  },
24
28
  };
25
29
 
@@ -1,6 +1,5 @@
1
1
  import type { RunOptions } from "./runner.js";
2
2
  import type { TestEvent } from "./types.js";
3
- import type { BuildOptions } from "../../../types/solidity/build-system.js";
4
3
  import type { NewTaskActionFunction } from "../../../types/tasks.js";
5
4
  import type {
6
5
  ObservabilityConfig,
@@ -14,18 +13,17 @@ import {
14
13
  assertHardhatInvariant,
15
14
  HardhatError,
16
15
  } from "@nomicfoundation/hardhat-errors";
17
- import { getAllFilesMatching } from "@nomicfoundation/hardhat-utils/fs";
18
16
  import { resolveFromRoot } from "@nomicfoundation/hardhat-utils/path";
19
17
  import { createNonClosingWriter } from "@nomicfoundation/hardhat-utils/stream";
20
18
 
21
19
  import { HardhatRuntimeEnvironmentImplementation } from "../../core/hre.js";
22
20
  import { isSupportedChainType } from "../../edr/chain-type.js";
21
+ import { ArtifactManagerImplementation } from "../artifacts/artifact-manager.js";
23
22
  import {
24
23
  markTestRunDone,
25
24
  markTestRunStart,
26
25
  markTestWorkerDone,
27
26
  } from "../coverage/helpers.js";
28
- import { throwIfSolidityBuildFailed } from "../solidity/build-results.js";
29
27
 
30
28
  import { getEdrArtifacts, getBuildInfos } from "./edr-artifacts.js";
31
29
  import {
@@ -49,8 +47,6 @@ const runSolidityTests: NewTaskActionFunction<TestActionArguments> = async (
49
47
  { testFiles, chainType, grep, noCompile, verbosity },
50
48
  hre,
51
49
  ) => {
52
- let rootFilePaths: string[];
53
-
54
50
  if (!isSupportedChainType(chainType)) {
55
51
  throw new HardhatError(
56
52
  HardhatError.ERRORS.CORE.ARGUMENTS.INVALID_VALUE_FOR_TYPE,
@@ -62,48 +58,25 @@ const runSolidityTests: NewTaskActionFunction<TestActionArguments> = async (
62
58
  );
63
59
  }
64
60
 
65
- // NOTE: We run the compile task first to ensure all the artifacts for them are generated
66
- // Then, we compile just the test sources. We don't do it in one go because the user
67
- // is likely to use different compilation options for the tests and the sources.
68
- if (noCompile === false) {
69
- await hre.tasks.getTask("compile").run();
70
- }
61
+ // Run the compile task for test files
71
62
 
72
- if (testFiles.length > 0) {
73
- rootFilePaths = testFiles.map((f) =>
74
- resolveFromRoot(hre.config.paths.root, f),
75
- );
76
- } else {
77
- // NOTE: A test file is either a file with a `.sol` extension in the `tests.solidity`
78
- // directory or a file with a `.t.sol` extension in the `sources.solidity` directory
79
- rootFilePaths = (
80
- await Promise.all([
81
- getAllFilesMatching(hre.config.paths.tests.solidity, (f) =>
82
- f.endsWith(".sol"),
83
- ),
84
- ...hre.config.paths.sources.solidity.map(async (dir) => {
85
- return getAllFilesMatching(dir, (f) => f.endsWith(".t.sol"));
86
- }),
87
- ])
88
- ).flat(1);
89
- }
90
- // NOTE: We remove duplicates in case there is an intersection between
91
- // the tests.solidity paths and the sources paths
92
- rootFilePaths = Array.from(new Set(rootFilePaths));
93
-
94
- // NOTE: We are not skipping the test compilation even if the noCompile flag is set
95
- // because the user cannot run test compilation outside of the test task yet.
96
- // TODO: Allow users to run test compilation outside of the test task.
97
- const buildOptions: BuildOptions = {
98
- force: false,
99
- buildProfile: hre.globalOptions.buildProfile ?? "default",
100
- quiet: true,
101
- };
102
- const results = await hre.solidity.build(rootFilePaths, buildOptions);
103
- throwIfSolidityBuildFailed(results);
63
+ const { testRootPaths }: { testRootPaths: string[] } = await hre.tasks
64
+ .getTask("compile")
65
+ .run({
66
+ quiet: true,
67
+ force: false,
68
+ files: testFiles,
69
+ noContracts: noCompile,
70
+ });
71
+
72
+ const artifactsDirectory = await hre.solidity.getArtifactsDirectory("tests");
73
+
74
+ const artifactsManager = new ArtifactManagerImplementation(
75
+ artifactsDirectory,
76
+ );
104
77
 
105
- const buildInfos = await getBuildInfos(hre.artifacts);
106
- const edrArtifacts = await getEdrArtifacts(hre.artifacts);
78
+ const buildInfos = await getBuildInfos(artifactsManager);
79
+ const edrArtifacts = await getEdrArtifacts(artifactsManager);
107
80
 
108
81
  const sourceNameToUserSourceName = new Map(
109
82
  edrArtifacts.map(({ userSourceName, edrAtifact }) => [
@@ -114,7 +87,7 @@ const runSolidityTests: NewTaskActionFunction<TestActionArguments> = async (
114
87
 
115
88
  edrArtifacts.forEach(({ userSourceName, edrAtifact }) => {
116
89
  if (
117
- rootFilePaths.includes(
90
+ testRootPaths.includes(
118
91
  resolveFromRoot(hre.config.paths.root, userSourceName),
119
92
  ) &&
120
93
  isTestSuiteArtifact(edrAtifact)
@@ -125,7 +98,7 @@ const runSolidityTests: NewTaskActionFunction<TestActionArguments> = async (
125
98
 
126
99
  const testSuiteIds = edrArtifacts
127
100
  .filter(({ userSourceName }) =>
128
- rootFilePaths.includes(
101
+ testRootPaths.includes(
129
102
  resolveFromRoot(hre.config.paths.root, userSourceName),
130
103
  ),
131
104
  )
@@ -160,7 +133,7 @@ const runSolidityTests: NewTaskActionFunction<TestActionArguments> = async (
160
133
  }
161
134
 
162
135
  const config: SolidityTestRunnerConfigArgs =
163
- solidityTestConfigToSolidityTestRunnerConfigArgs(
136
+ await solidityTestConfigToSolidityTestRunnerConfigArgs(
164
137
  chainType,
165
138
  hre.config.paths.root,
166
139
  solidityTestConfig,
@@ -1,4 +1,8 @@
1
1
  import "../../../types/config.js";
2
+ import type {
3
+ SensitiveString,
4
+ ResolvedConfigurationVariable,
5
+ } from "../../../types/config.js";
2
6
 
3
7
  declare module "../../../types/config.js" {
4
8
  export interface TestPathsUserConfig {
@@ -11,7 +15,7 @@ declare module "../../../types/config.js" {
11
15
  }
12
16
 
13
17
  declare module "../../../types/test.js" {
14
- export interface SolidityTestUserConfig {
18
+ export interface SolidityTestConfigBase {
15
19
  timeout?: number;
16
20
  fsPermissions?: {
17
21
  readWriteFile?: string[];
@@ -33,12 +37,6 @@ declare module "../../../types/test.js" {
33
37
  prevRandao?: bigint;
34
38
  blockGasLimit?: bigint | false;
35
39
 
36
- forking?: {
37
- url?: string;
38
- blockNumber?: bigint;
39
- rpcEndpoints?: Record<string, string>;
40
- };
41
-
42
40
  fuzz?: {
43
41
  failurePersistDir?: string;
44
42
  failurePersistFile?: string;
@@ -62,13 +60,29 @@ declare module "../../../types/test.js" {
62
60
  };
63
61
  }
64
62
 
63
+ export interface SolidityTestForkingUserConfig {
64
+ url?: SensitiveString;
65
+ blockNumber?: bigint;
66
+ rpcEndpoints?: Record<string, SensitiveString>;
67
+ }
68
+
69
+ export interface SolidityTestUserConfig extends SolidityTestConfigBase {
70
+ forking?: SolidityTestForkingUserConfig;
71
+ }
72
+
65
73
  export interface HardhatTestUserConfig {
66
74
  solidity?: SolidityTestUserConfig;
67
75
  }
68
76
 
69
- // eslint-disable-next-line @typescript-eslint/no-empty-interface -- This could be an extension point
70
- export interface SolidityTestConfig extends SolidityTestUserConfig {}
77
+ export interface SolidityTestForkingConfig {
78
+ url?: ResolvedConfigurationVariable;
79
+ blockNumber?: bigint;
80
+ rpcEndpoints?: Record<string, ResolvedConfigurationVariable>;
81
+ }
71
82
 
83
+ export interface SolidityTestConfig extends SolidityTestConfigBase {
84
+ forking?: SolidityTestForkingConfig;
85
+ }
72
86
  export interface HardhatTestConfig {
73
87
  solidity: SolidityTestConfig;
74
88
  }
@@ -13,6 +13,7 @@ import type { HardhatPlugin } from "../../types/plugins.js";
13
13
  import type { LastParameter, Return } from "../../types/utils.js";
14
14
 
15
15
  import { assertHardhatInvariant } from "@nomicfoundation/hardhat-errors";
16
+ import { ensureError } from "@nomicfoundation/hardhat-utils/error";
16
17
  import { AsyncMutex } from "@nomicfoundation/hardhat-utils/synchronization";
17
18
 
18
19
  import { detectPluginNpmDependencyProblems } from "./plugins/detect-plugin-npm-dependency-problems.js";
@@ -297,7 +298,14 @@ export class HookManagerImplementation implements HookManager {
297
298
  try {
298
299
  factory = (await hookHandlerCategoryFactory()).default;
299
300
  } catch (error) {
300
- await detectPluginNpmDependencyProblems(this.#projectRoot, plugin);
301
+ ensureError(error);
302
+
303
+ await detectPluginNpmDependencyProblems(
304
+ this.#projectRoot,
305
+ plugin,
306
+ error,
307
+ );
308
+
301
309
  throw error;
302
310
  }
303
311
 
@@ -12,7 +12,11 @@ import type {
12
12
  GlobalOptions,
13
13
  GlobalOptionDefinitions,
14
14
  } from "../../types/global-options.js";
15
- import type { HookContext, HookManager } from "../../types/hooks.js";
15
+ import type {
16
+ HardhatUserConfigValidationError,
17
+ HookContext,
18
+ HookManager,
19
+ } from "../../types/hooks.js";
16
20
  import type { HardhatRuntimeEnvironment } from "../../types/hre.js";
17
21
  import type { NetworkManager } from "../../types/network.js";
18
22
  import type { HardhatPlugin } from "../../types/plugins.js";
@@ -25,6 +29,8 @@ import { HardhatError } from "@nomicfoundation/hardhat-errors";
25
29
  import { findClosestPackageRoot } from "@nomicfoundation/hardhat-utils/package";
26
30
  import { resolveFromRoot } from "@nomicfoundation/hardhat-utils/path";
27
31
 
32
+ import { getEdrVersion, getHardhatVersion } from "../utils/package.js";
33
+
28
34
  import { validateUserConfig } from "./config-validation.js";
29
35
  import { resolveConfigurationVariable } from "./configuration-variables.js";
30
36
  import {
@@ -62,26 +68,31 @@ export class HardhatRuntimeEnvironmentImplementation
62
68
  unsafeOptions?.resolvedPlugins ??
63
69
  (await resolvePluginList(resolvedProjectRoot, inputUserConfig.plugins));
64
70
 
71
+ const [hardhatVersion, edrVersion] = await Promise.all([
72
+ getHardhatVersion(),
73
+ getEdrVersion(),
74
+ ]);
75
+
76
+ const versions = {
77
+ hardhat: hardhatVersion,
78
+ edr: edrVersion,
79
+ };
65
80
  const hooks = new HookManagerImplementation(
66
81
  resolvedProjectRoot,
67
82
  resolvedPlugins,
68
83
  );
69
84
 
70
- // extend user config:
71
- const extendedUserConfig = await runUserConfigExtensions(
72
- hooks,
85
+ const configResolutionResult = await resolveUserConfigToHardhatConfig(
73
86
  inputUserConfig,
74
- );
75
-
76
- // validate config
77
- const userConfigValidationErrors = await validateUserConfig(
78
87
  hooks,
79
- extendedUserConfig,
88
+ resolvedProjectRoot,
89
+ userProvidedGlobalOptions.config,
90
+ resolvedPlugins,
80
91
  );
81
92
 
82
- if (userConfigValidationErrors.length > 0) {
93
+ if (!configResolutionResult.success) {
83
94
  throw new HardhatError(HardhatError.ERRORS.CORE.GENERAL.INVALID_CONFIG, {
84
- errors: `\t${userConfigValidationErrors
95
+ errors: `\t${configResolutionResult.userConfigValidationErrors
85
96
  .map(
86
97
  (error) =>
87
98
  `* Config error in config.${error.path.join(".")}: ${error.message}`,
@@ -90,26 +101,7 @@ export class HardhatRuntimeEnvironmentImplementation
90
101
  });
91
102
  }
92
103
 
93
- // Resolve config
94
-
95
- const resolvedConfig = await resolveUserConfig(
96
- resolvedProjectRoot,
97
- userProvidedGlobalOptions.config,
98
- hooks,
99
- resolvedPlugins,
100
- extendedUserConfig,
101
- );
102
-
103
- // We override the plugins and the project root, as we want to prevent
104
- // the plugins from changing them
105
- const config: HardhatConfig = {
106
- ...resolvedConfig,
107
- paths: {
108
- ...resolvedConfig.paths,
109
- root: resolvedProjectRoot,
110
- },
111
- plugins: resolvedPlugins,
112
- };
104
+ const { config, extendedUserConfig } = configResolutionResult;
113
105
 
114
106
  const globalOptionDefinitions =
115
107
  unsafeOptions?.globalOptionDefinitions ??
@@ -122,7 +114,6 @@ export class HardhatRuntimeEnvironmentImplementation
122
114
 
123
115
  // Set the HookContext in the hook manager so that non-config hooks can
124
116
  // use it
125
-
126
117
  const interruptions = new UserInterruptionManagerImplementation(hooks);
127
118
 
128
119
  const hre = new HardhatRuntimeEnvironmentImplementation(
@@ -131,6 +122,7 @@ export class HardhatRuntimeEnvironmentImplementation
131
122
  hooks,
132
123
  interruptions,
133
124
  globalOptions,
125
+ versions,
134
126
  globalOptionDefinitions,
135
127
  );
136
128
 
@@ -160,6 +152,10 @@ export class HardhatRuntimeEnvironmentImplementation
160
152
  public readonly hooks: HookManager,
161
153
  public readonly interruptions: UserInterruptionManager,
162
154
  public readonly globalOptions: GlobalOptions,
155
+ public readonly versions: {
156
+ readonly hardhat: string;
157
+ readonly edr: string;
158
+ },
163
159
  globalOptionDefinitions: GlobalOptionDefinitions,
164
160
  ) {
165
161
  this.tasks = new TaskManagerImplementation(this, globalOptionDefinitions);
@@ -180,6 +176,80 @@ export async function resolveProjectRoot(
180
176
  return findClosestPackageRoot(absolutePathWithinProject ?? process.cwd());
181
177
  }
182
178
 
179
+ /**
180
+ * Runs the provided Hardhat user config through the resolution process,
181
+ * invoking relevant plugin hooks (both internal and external) to extend
182
+ * and transform the config into a full HardhatConfig.
183
+ *
184
+ * @param hooks - The HookManager used to run config extension and validation
185
+ * hooks.
186
+ * @param inputUserConfig - The initial user provided Hardhat config object.
187
+ * @param resolvedProjectRoot - The project root path.
188
+ * @param userProvidedConfigPath - The user provided Hardhat config file path.
189
+ * @param resolvedPlugins - The list of plugins, we do not want the plugins
190
+ * overwriting them so we re-add them to the final HardhatConfig.
191
+ * @returns Either an object containing the resolved HardhatConfig and the
192
+ * extended version of the user config, or a list of validation errors.
193
+ */
194
+ export async function resolveUserConfigToHardhatConfig(
195
+ inputUserConfig: HardhatUserConfig,
196
+ hooks: HookManager,
197
+ resolvedProjectRoot: string,
198
+ userProvidedConfigPath: string | undefined,
199
+ resolvedPlugins: HardhatPlugin[],
200
+ ): Promise<
201
+ | {
202
+ success: true;
203
+ config: HardhatConfig;
204
+ extendedUserConfig: HardhatUserConfig;
205
+ }
206
+ | {
207
+ success: false;
208
+ userConfigValidationErrors: HardhatUserConfigValidationError[];
209
+ }
210
+ > {
211
+ // extend user config:
212
+ const extendedUserConfig = await runUserConfigExtensions(
213
+ hooks,
214
+ inputUserConfig,
215
+ );
216
+
217
+ // validate config
218
+ const userConfigValidationErrors = await validateUserConfig(
219
+ hooks,
220
+ extendedUserConfig,
221
+ );
222
+
223
+ if (userConfigValidationErrors.length > 0) {
224
+ return {
225
+ success: false,
226
+ userConfigValidationErrors,
227
+ };
228
+ }
229
+
230
+ // Resolve config
231
+ const resolvedConfig = await resolveUserConfig(
232
+ resolvedProjectRoot,
233
+ userProvidedConfigPath,
234
+ hooks,
235
+ resolvedPlugins,
236
+ extendedUserConfig,
237
+ );
238
+
239
+ // We override the plugins and the project root, as we want to prevent
240
+ // the plugins from changing them
241
+ const config: HardhatConfig = {
242
+ ...resolvedConfig,
243
+ paths: {
244
+ ...resolvedConfig.paths,
245
+ root: resolvedProjectRoot,
246
+ },
247
+ plugins: resolvedPlugins,
248
+ };
249
+
250
+ return { success: true, config, extendedUserConfig };
251
+ }
252
+
183
253
  async function runUserConfigExtensions(
184
254
  hooks: HookManager,
185
255
  config: HardhatUserConfig,