hardhat 3.14.0 → 3.16.0

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 (71) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/src/internal/builtin-plugins/solidity/type-extensions.d.ts +2 -2
  3. package/dist/src/internal/builtin-plugins/solidity-test/edr-artifacts.d.ts.map +1 -1
  4. package/dist/src/internal/builtin-plugins/solidity-test/edr-artifacts.js +1 -1
  5. package/dist/src/internal/builtin-plugins/solidity-test/edr-artifacts.js.map +1 -1
  6. package/dist/src/internal/builtin-plugins/solidity-test/eip712/canonicalize.d.ts +1 -1
  7. package/dist/src/internal/builtin-plugins/solidity-test/eip712/canonicalize.d.ts.map +1 -1
  8. package/dist/src/internal/builtin-plugins/solidity-test/eip712/canonicalize.js +13 -11
  9. package/dist/src/internal/builtin-plugins/solidity-test/eip712/canonicalize.js.map +1 -1
  10. package/dist/src/internal/builtin-plugins/solidity-test/formatters.d.ts +6 -1
  11. package/dist/src/internal/builtin-plugins/solidity-test/formatters.d.ts.map +1 -1
  12. package/dist/src/internal/builtin-plugins/solidity-test/formatters.js +41 -0
  13. package/dist/src/internal/builtin-plugins/solidity-test/formatters.js.map +1 -1
  14. package/dist/src/internal/builtin-plugins/solidity-test/helpers.d.ts +16 -3
  15. package/dist/src/internal/builtin-plugins/solidity-test/helpers.d.ts.map +1 -1
  16. package/dist/src/internal/builtin-plugins/solidity-test/helpers.js +45 -2
  17. package/dist/src/internal/builtin-plugins/solidity-test/helpers.js.map +1 -1
  18. package/dist/src/internal/builtin-plugins/solidity-test/runner.d.ts.map +1 -1
  19. package/dist/src/internal/builtin-plugins/solidity-test/runner.js +18 -1
  20. package/dist/src/internal/builtin-plugins/solidity-test/runner.js.map +1 -1
  21. package/dist/src/internal/builtin-plugins/solidity-test/task-action.d.ts.map +1 -1
  22. package/dist/src/internal/builtin-plugins/solidity-test/task-action.js +15 -16
  23. package/dist/src/internal/builtin-plugins/solidity-test/task-action.js.map +1 -1
  24. package/package.json +2 -2
  25. package/src/internal/builtin-plugins/solidity/type-extensions.ts +2 -2
  26. package/src/internal/builtin-plugins/solidity-test/edr-artifacts.ts +1 -1
  27. package/src/internal/builtin-plugins/solidity-test/eip712/canonicalize.ts +13 -11
  28. package/src/internal/builtin-plugins/solidity-test/formatters.ts +60 -1
  29. package/src/internal/builtin-plugins/solidity-test/helpers.ts +56 -4
  30. package/src/internal/builtin-plugins/solidity-test/runner.ts +33 -1
  31. package/src/internal/builtin-plugins/solidity-test/task-action.ts +20 -20
  32. package/templates/01-node-test-runner-viem/contracts/Counter.sol +1 -1
  33. package/templates/01-node-test-runner-viem/contracts/Counter.t.sol +1 -1
  34. package/templates/01-node-test-runner-viem/hardhat.config.ts +2 -2
  35. package/templates/01-node-test-runner-viem/package.json +2 -2
  36. package/templates/02-mocha-ethers/contracts/Counter.sol +1 -1
  37. package/templates/02-mocha-ethers/contracts/Counter.t.sol +1 -1
  38. package/templates/02-mocha-ethers/hardhat.config.ts +2 -2
  39. package/templates/02-mocha-ethers/package.json +2 -2
  40. package/templates/03-minimal/hardhat.config.ts +1 -1
  41. package/templates/03-minimal/package.json +1 -1
  42. package/dist/src/internal/builtin-plugins/solidity-test/inline-config/constants.d.ts +0 -9
  43. package/dist/src/internal/builtin-plugins/solidity-test/inline-config/constants.d.ts.map +0 -1
  44. package/dist/src/internal/builtin-plugins/solidity-test/inline-config/constants.js +0 -24
  45. package/dist/src/internal/builtin-plugins/solidity-test/inline-config/constants.js.map +0 -1
  46. package/dist/src/internal/builtin-plugins/solidity-test/inline-config/helpers.d.ts +0 -24
  47. package/dist/src/internal/builtin-plugins/solidity-test/inline-config/helpers.d.ts.map +0 -1
  48. package/dist/src/internal/builtin-plugins/solidity-test/inline-config/helpers.js +0 -80
  49. package/dist/src/internal/builtin-plugins/solidity-test/inline-config/helpers.js.map +0 -1
  50. package/dist/src/internal/builtin-plugins/solidity-test/inline-config/index.d.ts +0 -13
  51. package/dist/src/internal/builtin-plugins/solidity-test/inline-config/index.d.ts.map +0 -1
  52. package/dist/src/internal/builtin-plugins/solidity-test/inline-config/index.js +0 -146
  53. package/dist/src/internal/builtin-plugins/solidity-test/inline-config/index.js.map +0 -1
  54. package/dist/src/internal/builtin-plugins/solidity-test/inline-config/parsing.d.ts +0 -19
  55. package/dist/src/internal/builtin-plugins/solidity-test/inline-config/parsing.d.ts.map +0 -1
  56. package/dist/src/internal/builtin-plugins/solidity-test/inline-config/parsing.js +0 -134
  57. package/dist/src/internal/builtin-plugins/solidity-test/inline-config/parsing.js.map +0 -1
  58. package/dist/src/internal/builtin-plugins/solidity-test/inline-config/types.d.ts +0 -10
  59. package/dist/src/internal/builtin-plugins/solidity-test/inline-config/types.d.ts.map +0 -1
  60. package/dist/src/internal/builtin-plugins/solidity-test/inline-config/types.js +0 -2
  61. package/dist/src/internal/builtin-plugins/solidity-test/inline-config/types.js.map +0 -1
  62. package/dist/src/internal/builtin-plugins/solidity-test/inline-config/validation.d.ts +0 -13
  63. package/dist/src/internal/builtin-plugins/solidity-test/inline-config/validation.d.ts.map +0 -1
  64. package/dist/src/internal/builtin-plugins/solidity-test/inline-config/validation.js +0 -96
  65. package/dist/src/internal/builtin-plugins/solidity-test/inline-config/validation.js.map +0 -1
  66. package/src/internal/builtin-plugins/solidity-test/inline-config/constants.ts +0 -25
  67. package/src/internal/builtin-plugins/solidity-test/inline-config/helpers.ts +0 -110
  68. package/src/internal/builtin-plugins/solidity-test/inline-config/index.ts +0 -285
  69. package/src/internal/builtin-plugins/solidity-test/inline-config/parsing.ts +0 -187
  70. package/src/internal/builtin-plugins/solidity-test/inline-config/types.ts +0 -9
  71. package/src/internal/builtin-plugins/solidity-test/inline-config/validation.ts +0 -144
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hardhat",
3
- "version": "3.14.0",
3
+ "version": "3.16.0",
4
4
  "description": "Hardhat is an extensible developer tool that helps smart contract developers increase productivity by reliably bringing together the tools they want.",
5
5
  "homepage": "https://hardhat.org",
6
6
  "repository": {
@@ -77,7 +77,7 @@
77
77
  "@nomicfoundation/hardhat-test-utils": "^2.0.3"
78
78
  },
79
79
  "dependencies": {
80
- "@nomicfoundation/edr": "0.17.0",
80
+ "@nomicfoundation/edr": "0.19.0",
81
81
  "@nomicfoundation/hardhat-errors": "^3.0.17",
82
82
  "@nomicfoundation/hardhat-utils": "^4.1.6",
83
83
  "@nomicfoundation/hardhat-vendored": "^3.0.4",
@@ -20,7 +20,7 @@ declare module "../../../types/config.js" {
20
20
  * The types of the values don't matter; we use `true` as a convention.
21
21
  *
22
22
  * By default, only "solc" is provided. Plugins can extend this via
23
- * declaration merging to add new compiler types (e.g. "slangSolx").
23
+ * declaration merging to add new compiler types (e.g. "slang-solx").
24
24
  */
25
25
  export interface SolidityCompilerTypeDefinitions {
26
26
  solc: true;
@@ -358,7 +358,7 @@ declare module "../../../types/hooks.js" {
358
358
  /**
359
359
  * Hook to obtain a Compiler instance for a given compiler configuration.
360
360
  * The default handler returns a solc compiler. Plugins can intercept to
361
- * return their own compiler (e.g. SlangSolxCompiler for type: "slangSolx").
361
+ * return their own compiler (e.g. SlangSolxCompiler for type: "slang-solx").
362
362
  *
363
363
  * @param context The hook context.
364
364
  * @param compilerConfig The compiler configuration to get a compiler for.
@@ -18,7 +18,7 @@ export interface EdrArtifactWithMetadata {
18
18
  }
19
19
 
20
20
  export const BUILD_INFO_FORMAT: RegExp =
21
- /^solc-(?<major>\d+)_(?<minor>\d+)_(?<patch>\d+)(?:-(?<compilerType>[a-zA-Z][a-zA-Z0-9]*))?-[0-9a-fA-F]*$/;
21
+ /^solc-(?<major>\d+)_(?<minor>\d+)_(?<patch>\d+)(?:-(?<compilerType>[a-zA-Z][a-zA-Z0-9-]*))?-[0-9a-fA-F]*$/;
22
22
 
23
23
  /**
24
24
  * This function returns all the build infos and associated outputs.
@@ -6,7 +6,7 @@ export const SELECTED_CONFLICT_REMEDIATION =
6
6
  "Rename one of the structs, or scope your `test.solidity.eip712Types.include` / `exclude` globs in `hardhat.config.ts` so that only one of them is selected.";
7
7
 
8
8
  export const DEPENDENCY_CONFLICT_REMEDIATION =
9
- "Rename one of the structs so the name has a single definition. The clashing name is pulled in as a dependency of a selected struct, so if you don't need that selected struct, deselecting it with your `test.solidity.eip712Types.include` / `exclude` globs in `hardhat.config.ts` also resolves the conflict.";
9
+ "Rename one of the structs so the name has a single definition. The clashing name is pulled in as a dependency of a selected struct, but none of its definitions is in a selected source, so you can also resolve the conflict with your `test.solidity.eip712Types.include` / `exclude` globs in `hardhat.config.ts`: include the source containing the canonical definition so it wins the clash, or deselect the struct that depends on it if you don't need it.";
10
10
 
11
11
  /**
12
12
  * Produces the flat list of canonical EIP-712 type strings expected by EDR.
@@ -220,12 +220,14 @@ function transitiveDeps(
220
220
  * - Both sides selected: throw immediately — genuinely ambiguous which to
221
221
  * emit.
222
222
  * - Current side non-selected: defer; the stored definition keeps the name.
223
- * Throw only if the name is reachable from a selected struct (its
224
- * transitive deps), since then which copy got inlined would depend on
225
- * iteration order. Names unreachable from the selected set are silently
226
- * deduped (first wins), so a non-selected struct that merely shares a
227
- * name with a selected root or an unreferenced struct never aborts the
228
- * run.
223
+ * Throw only if the name has no selected definition AND is reachable from
224
+ * a selected struct (its transitive deps), since only then which copy got
225
+ * inlined would depend on iteration order. A name with a selected
226
+ * definition always resolves to it deterministically (selected structs
227
+ * come first), so a non-selected struct that shares a name with a
228
+ * selected one never aborts the run — even when that name is also a
229
+ * dependency of another selected struct. Names unreachable from the
230
+ * selected set are likewise silently deduped (first wins).
229
231
  */
230
232
  function indexByName(
231
233
  structs: CollectedStruct[],
@@ -276,9 +278,9 @@ function indexByName(
276
278
 
277
279
  // Non-selected side, so the stored definition (selected if the name has
278
280
  // one, since selected sources come first) keeps the name. Defer: throw
279
- // later only if the name is reachable from a selected struct. Sharing a
280
- // name with a selected root or an unreferenced struct is harmless and
281
- // must not abort.
281
+ // later only if the name has no selected definition and is reachable from
282
+ // a selected struct. Sharing a name with a selected definition or an
283
+ // unreferenced struct is harmless and must not abort.
282
284
  if (!deferredConflicts.has(struct.name)) {
283
285
  deferredConflicts.set(struct.name, {
284
286
  firstSource: sourceByName.get(struct.name) ?? "<unknown>",
@@ -290,7 +292,7 @@ function indexByName(
290
292
  if (deferredConflicts.size > 0) {
291
293
  const reachable = reachableFromSelected(byName, selectedNames);
292
294
  for (const [name, sources] of deferredConflicts) {
293
- if (reachable.has(name)) {
295
+ if (reachable.has(name) && !selectedNames.has(name)) {
294
296
  throw new HardhatError(
295
297
  HardhatError.ERRORS.CORE.SOLIDITY_TESTS.EIP712_DUPLICATE_STRUCT_NAME,
296
298
  { name, ...sources, remediation: DEPENDENCY_CONFLICT_REMEDIATION },
@@ -1,4 +1,9 @@
1
- import type { ArtifactId } from "@nomicfoundation/edr";
1
+ import type {
2
+ ArtifactId,
3
+ InlineConfigDirectiveProblem,
4
+ InlineConfigError,
5
+ InlineConfigSourceProblem,
6
+ } from "@nomicfoundation/edr";
2
7
 
3
8
  export function formatArtifactId(
4
9
  artifactId: ArtifactId,
@@ -9,3 +14,57 @@ export function formatArtifactId(
9
14
 
10
15
  return `${sourceName}:${artifactId.name}`;
11
16
  }
17
+
18
+ /**
19
+ * Formats the inline test configuration problems that EDR reports, one per
20
+ * line, each located at the user-facing path of the source it was found in.
21
+ */
22
+ export function formatInlineConfigErrors(
23
+ errors: InlineConfigError[],
24
+ sourceNameToUserSourceName: Map<string, string>,
25
+ ): string {
26
+ return errors
27
+ .map((error) => {
28
+ const sourceName =
29
+ sourceNameToUserSourceName.get(error.sourceName) ?? error.sourceName;
30
+
31
+ if (error.kind === "source") {
32
+ return `- ${sourceName}: ${formatInlineConfigSourceProblem(error.problem)}`;
33
+ }
34
+
35
+ return `- ${sourceName}:${error.line}: ${error.contract}.${error.function}: ${formatInlineConfigDirectiveProblem(error.problem)}`;
36
+ })
37
+ .join("\n");
38
+ }
39
+
40
+ function formatInlineConfigDirectiveProblem(
41
+ problem: InlineConfigDirectiveProblem,
42
+ ): string {
43
+ switch (problem.kind) {
44
+ case "InlineConfigInvalidSyntax":
45
+ return `missing "=" in "${problem.directive}"`;
46
+ case "InlineConfigUnsupportedProfile":
47
+ return `unsupported profile "${problem.profile}". Only the "default" profile is supported`;
48
+ case "InlineConfigInvalidKey":
49
+ return `invalid key "${problem.key}"`;
50
+ case "InlineConfigInvalidKeyForTestType":
51
+ return `key "${problem.key}" is not valid for ${problem.testType} tests`;
52
+ case "InlineConfigInvalidValue":
53
+ return `invalid value "${problem.value}" for key "${problem.key}". Expected a ${problem.expected}`;
54
+ case "InlineConfigDuplicateKey":
55
+ return `duplicate key "${problem.key}"`;
56
+ }
57
+ }
58
+
59
+ function formatInlineConfigSourceProblem(
60
+ problem: InlineConfigSourceProblem,
61
+ ): string {
62
+ switch (problem.kind) {
63
+ case "InlineConfigInvalidSolcVersion":
64
+ return "the Solidity version of this source is not supported by the inline configuration parser";
65
+ case "InlineConfigSourceFileNotFound":
66
+ return `the source file could not be read at "${problem.path}": ${problem.reason}`;
67
+ case "InlineConfigDirectiveLocation":
68
+ return `a directive of ${problem.contract}.${problem.function} could not be located: ${problem.reason}`;
69
+ }
70
+ }
@@ -1,3 +1,4 @@
1
+ import type { TestsStream } from "./types.js";
1
2
  import type { Abi } from "../../../types/artifacts.js";
2
3
  import type { ChainType } from "../../../types/network.js";
3
4
  import type { SolidityTestProfileConfig } from "../../../types/test.js";
@@ -6,9 +7,10 @@ import type {
6
7
  PathPermission,
7
8
  Artifact,
8
9
  ObservabilityConfig,
9
- TestFunctionOverride,
10
10
  } from "@nomicfoundation/edr";
11
+ import type { Writable } from "node:stream";
11
12
 
13
+ import { finished } from "node:stream/promises";
12
14
  import { styleText } from "node:util";
13
15
 
14
16
  import {
@@ -43,8 +45,8 @@ interface SolidityTestConfigParams {
43
45
  testPattern?: string;
44
46
  excludeTestPattern?: string;
45
47
  generateGasReport: boolean;
46
- testFunctionOverrides?: TestFunctionOverride[];
47
48
  eip712CanonicalTypes?: string[];
49
+ testSourcePaths?: Record<string, string>;
48
50
  }
49
51
 
50
52
  export async function solidityTestConfigToSolidityTestRunnerConfigArgs({
@@ -57,8 +59,8 @@ export async function solidityTestConfigToSolidityTestRunnerConfigArgs({
57
59
  testPattern,
58
60
  excludeTestPattern,
59
61
  generateGasReport,
60
- testFunctionOverrides,
61
62
  eip712CanonicalTypes,
63
+ testSourcePaths,
62
64
  }: SolidityTestConfigParams): Promise<SolidityTestRunnerConfigArgs> {
63
65
  const fsPermissions: PathPermission[] | undefined = [
64
66
  config.fsPermissions?.readWriteFile?.map((p) => ({
@@ -171,8 +173,8 @@ export async function solidityTestConfigToSolidityTestRunnerConfigArgs({
171
173
  collectStackTraces: shouldAlwaysCollectStackTraces
172
174
  ? CollectStackTraces.Always
173
175
  : CollectStackTraces.OnFailure,
174
- testFunctionOverrides,
175
176
  eip712CanonicalTypes,
177
+ testSourcePaths,
176
178
  };
177
179
  }
178
180
 
@@ -194,6 +196,56 @@ export function isTestSuiteArtifact(artifact: Artifact): boolean {
194
196
  });
195
197
  }
196
198
 
199
+ /**
200
+ * Writes the test reporter's output to `output` and waits for the test run to
201
+ * complete, returning the error that failed it, if any.
202
+ *
203
+ * @param runStream The runner's stream of test events.
204
+ * @param reporterStream The reporter's stream of output, composed from
205
+ * `runStream`.
206
+ * @param output Where the reporter's output is written to.
207
+ * @returns The error that failed the run, or `undefined` if it succeeded.
208
+ */
209
+ export async function writeTestRunOutput(
210
+ runStream: TestsStream,
211
+ reporterStream: NodeJS.ReadableStream,
212
+ output: Writable,
213
+ ): Promise<unknown> {
214
+ const outputStream = reporterStream.pipe(output);
215
+
216
+ // When the runner reports an error it destroys the run stream with it, which
217
+ // also destroys the reporter stream composed from it. `pipe()` neither
218
+ // forwards that error to the output stream nor ends it, so without this
219
+ // listener the reporter stream emits an `error` event with nothing listening,
220
+ // crashing the process, and `finished(outputStream)` below never settles.
221
+ // Attached before any `await` so that it can't miss the event.
222
+ let reporterStreamError: Error | undefined;
223
+ reporterStream.on("error", (error: Error) => {
224
+ reporterStreamError = error;
225
+ if (!outputStream.writableEnded) {
226
+ outputStream.end();
227
+ }
228
+ });
229
+
230
+ let runError: unknown;
231
+ try {
232
+ // NOTE: We're awaiting the original run stream to finish to catch any
233
+ // errors produced by the runner.
234
+ await finished(runStream);
235
+
236
+ // We also await the output stream to finish, as we want to wait for it
237
+ // to avoid returning before the whole output was generated.
238
+ await finished(outputStream);
239
+ } catch (error) {
240
+ runError = error;
241
+ }
242
+
243
+ // Neither await above surfaces an error that reached the reporter stream
244
+ // without failing the run stream, e.g. one thrown by the reporter after the
245
+ // run stream already ended.
246
+ return runError ?? reporterStreamError;
247
+ }
248
+
197
249
  export function warnDeprecatedTestFail(
198
250
  artifact: Artifact,
199
251
  sourceNameToUserSourceName: Map<string, string>,
@@ -3,6 +3,7 @@ import type { ChainType } from "../../../types/network.js";
3
3
  import type {
4
4
  ArtifactId,
5
5
  Artifact,
6
+ InlineConfigError,
6
7
  SolidityTestRunnerConfigArgs,
7
8
  TracingConfigWithBuffers,
8
9
  } from "@nomicfoundation/edr";
@@ -15,7 +16,7 @@ import { ensureError } from "@nomicfoundation/hardhat-utils/error";
15
16
  import { hardhatChainTypeToEdrChainType } from "../../edr/chain-type.js";
16
17
  import { getGlobalEdrContext } from "../../edr/context.js";
17
18
 
18
- import { formatArtifactId } from "./formatters.js";
19
+ import { formatArtifactId, formatInlineConfigErrors } from "./formatters.js";
19
20
 
20
21
  /**
21
22
  * Run all the given solidity tests and returns the stream of results.
@@ -100,6 +101,24 @@ export function run(
100
101
  } catch (error) {
101
102
  ensureError(error);
102
103
 
104
+ // EDR reports the problems it found in the user's inline test config as
105
+ // an `inlineConfigErrors` property on the error. Report them as a
106
+ // dedicated Hardhat error instead of an unhandled EDR error.
107
+ if (hasInlineConfigErrors(error)) {
108
+ stream.destroy(
109
+ new HardhatError(
110
+ HardhatError.ERRORS.CORE.SOLIDITY_TESTS.INVALID_INLINE_CONFIG,
111
+ {
112
+ errors: formatInlineConfigErrors(
113
+ error.inlineConfigErrors,
114
+ sourceNameToUserSourceName,
115
+ ),
116
+ },
117
+ ),
118
+ );
119
+ return;
120
+ }
121
+
103
122
  stream.destroy(
104
123
  new HardhatError(
105
124
  HardhatError.ERRORS.CORE.SOLIDITY_TESTS
@@ -114,3 +133,16 @@ export function run(
114
133
 
115
134
  return stream;
116
135
  }
136
+
137
+ /**
138
+ * EDR attaches the structured inline-config problems to the error that rejects
139
+ * `runSolidityTests`, but as a property of an `Error` rather than a typed
140
+ * error class, so we have to assert their type here.
141
+ */
142
+ function hasInlineConfigErrors(
143
+ error: Error,
144
+ ): error is Error & { inlineConfigErrors: InlineConfigError[] } {
145
+ return (
146
+ "inlineConfigErrors" in error && Array.isArray(error.inlineConfigErrors)
147
+ );
148
+ }
@@ -16,8 +16,6 @@ import type {
16
16
  SuiteResult,
17
17
  } from "@nomicfoundation/edr";
18
18
 
19
- import { finished } from "node:stream/promises";
20
-
21
19
  import { HardhatError } from "@nomicfoundation/hardhat-errors";
22
20
  import { exists } from "@nomicfoundation/hardhat-utils/fs";
23
21
  import { resolveFromRoot } from "@nomicfoundation/hardhat-utils/path";
@@ -40,8 +38,8 @@ import {
40
38
  isTestSuiteArtifact,
41
39
  warnDeprecatedTestFail,
42
40
  solidityTestConfigToSolidityTestRunnerConfigArgs,
41
+ writeTestRunOutput,
43
42
  } from "./helpers.js";
44
- import { getTestFunctionOverrides } from "./inline-config/index.js";
45
43
  import { testReporter } from "./reporter.js";
46
44
  import { run } from "./runner.js";
47
45
  import { DEFAULT_TEST_PROFILE } from "./test-profiles.js";
@@ -198,6 +196,19 @@ const runSolidityTests: NewTaskActionFunction<TestActionArguments> = async (
198
196
  ({ edrArtifact }) => edrArtifact.id,
199
197
  );
200
198
 
199
+ // Maps each test suite's solc source name to its absolute path on disk, so
200
+ // EDR can read the inline test configuration from the sources. A source
201
+ // without an entry has no inline configuration collected.
202
+ //
203
+ // EDR skips every source that carries no inline config directive, so there's
204
+ // no need to filter these paths here.
205
+ const testSourcePaths = Object.fromEntries(
206
+ testSuiteArtifacts.map(({ userSourceName, edrArtifact }) => [
207
+ edrArtifact.id.source,
208
+ resolveFromRoot(hre.config.paths.root, userSourceName),
209
+ ]),
210
+ );
211
+
201
212
  console.log("Running Solidity tests");
202
213
  console.log();
203
214
 
@@ -233,11 +244,6 @@ const runSolidityTests: NewTaskActionFunction<TestActionArguments> = async (
233
244
  }
234
245
  }
235
246
 
236
- const testFunctionOverrides = await getTestFunctionOverrides(
237
- testSuiteArtifacts,
238
- allBuildInfosAndOutputs,
239
- );
240
-
241
247
  const eip712CanonicalTypes = await collectEip712CanonicalTypes(
242
248
  allBuildInfosAndOutputs,
243
249
  sourceNameToUserSourceName,
@@ -257,8 +263,8 @@ const runSolidityTests: NewTaskActionFunction<TestActionArguments> = async (
257
263
  generateGasReport:
258
264
  hre.globalOptions.gasStats ||
259
265
  hre.globalOptions.gasStatsJson !== undefined,
260
- testFunctionOverrides,
261
266
  eip712CanonicalTypes,
267
+ testSourcePaths,
262
268
  });
263
269
  const tracingConfig: TracingConfigWithBuffers = {
264
270
  buildInfos: allBuildInfosAndOutputs.map(({ buildInfo, output }) => ({
@@ -340,20 +346,14 @@ const runSolidityTests: NewTaskActionFunction<TestActionArguments> = async (
340
346
  }
341
347
  });
342
348
 
343
- const outputStream = testReporterStream.pipe(
349
+ const testRunError = await writeTestRunOutput(
350
+ runStream,
351
+ testReporterStream,
344
352
  createNonClosingWriter(process.stdout),
345
353
  );
346
354
 
347
- try {
348
- // NOTE: We're awaiting the original run stream to finish to catch any
349
- // errors produced by the runner.
350
- await finished(runStream);
351
-
352
- // We also await the output stream to finish, as we want to wait for it
353
- // to avoid returning before the whole output was generated.
354
- await finished(outputStream);
355
- } catch (error) {
356
- console.error(error);
355
+ if (testRunError !== undefined) {
356
+ console.error(testRunError);
357
357
  includesErrors = true;
358
358
  }
359
359
 
@@ -1,5 +1,5 @@
1
1
  // SPDX-License-Identifier: UNLICENSED
2
- pragma solidity ^0.8.28;
2
+ pragma solidity ^0.8.34;
3
3
 
4
4
  contract Counter {
5
5
  uint public x;
@@ -1,5 +1,5 @@
1
1
  // SPDX-License-Identifier: UNLICENSED
2
- pragma solidity ^0.8.28;
2
+ pragma solidity ^0.8.34;
3
3
 
4
4
  import {Counter} from "./Counter.sol";
5
5
  import {Test} from "forge-std/Test.sol";
@@ -6,10 +6,10 @@ export default defineConfig({
6
6
  solidity: {
7
7
  profiles: {
8
8
  default: {
9
- version: "0.8.28",
9
+ version: "0.8.34",
10
10
  },
11
11
  production: {
12
- version: "0.8.28",
12
+ version: "0.8.34",
13
13
  settings: {
14
14
  optimizer: {
15
15
  enabled: true,
@@ -5,11 +5,11 @@
5
5
  "description": "A TypeScript Hardhat project using Node Test Runner and Viem",
6
6
  "type": "module",
7
7
  "devDependencies": {
8
- "hardhat": "workspace:^3.14.0",
8
+ "hardhat": "workspace:^3.16.0",
9
9
  "@nomicfoundation/hardhat-toolbox-viem": "workspace:^5.0.7",
10
10
  "@nomicfoundation/hardhat-ignition": "workspace:^3.1.8",
11
11
  "@types/node": "^22.8.5",
12
- "forge-std": "foundry-rs/forge-std#v1.9.4",
12
+ "forge-std": "foundry-rs/forge-std#v1.16.2",
13
13
  "typescript": "~6.0.3",
14
14
  "viem": "^2.47.6"
15
15
  },
@@ -1,5 +1,5 @@
1
1
  // SPDX-License-Identifier: UNLICENSED
2
- pragma solidity ^0.8.28;
2
+ pragma solidity ^0.8.34;
3
3
 
4
4
  contract Counter {
5
5
  uint public x;
@@ -1,5 +1,5 @@
1
1
  // SPDX-License-Identifier: UNLICENSED
2
- pragma solidity ^0.8.28;
2
+ pragma solidity ^0.8.34;
3
3
 
4
4
  import {Counter} from "./Counter.sol";
5
5
  import {Test} from "forge-std/Test.sol";
@@ -6,10 +6,10 @@ export default defineConfig({
6
6
  solidity: {
7
7
  profiles: {
8
8
  default: {
9
- version: "0.8.28",
9
+ version: "0.8.34",
10
10
  },
11
11
  production: {
12
- version: "0.8.28",
12
+ version: "0.8.34",
13
13
  settings: {
14
14
  optimizer: {
15
15
  enabled: true,
@@ -5,7 +5,7 @@
5
5
  "description": "A TypeScript Hardhat project using Mocha and Ethers.js",
6
6
  "type": "module",
7
7
  "devDependencies": {
8
- "hardhat": "workspace:^3.14.0",
8
+ "hardhat": "workspace:^3.16.0",
9
9
  "@nomicfoundation/hardhat-toolbox-mocha-ethers": "workspace:^3.0.7",
10
10
  "@nomicfoundation/hardhat-ethers": "workspace:^4.0.15",
11
11
  "@nomicfoundation/hardhat-ignition": "workspace:^3.1.8",
@@ -15,7 +15,7 @@
15
15
  "@types/node": "^22.8.5",
16
16
  "chai": "^6.2.2",
17
17
  "ethers": "^6.14.0",
18
- "forge-std": "foundry-rs/forge-std#v1.9.4",
18
+ "forge-std": "foundry-rs/forge-std#v1.16.2",
19
19
  "mocha": "^11.0.0",
20
20
  "typescript": "~6.0.3"
21
21
  },
@@ -2,6 +2,6 @@ import { defineConfig } from "hardhat/config";
2
2
 
3
3
  export default defineConfig({
4
4
  solidity: {
5
- version: "0.8.28",
5
+ version: "0.8.34",
6
6
  },
7
7
  });
@@ -5,7 +5,7 @@
5
5
  "description": "A minimal Hardhat project",
6
6
  "type": "module",
7
7
  "devDependencies": {
8
- "hardhat": "workspace:^3.14.0",
8
+ "hardhat": "workspace:^3.16.0",
9
9
  "@types/node": "^22.8.5",
10
10
  "typescript": "~6.0.3"
11
11
  }
@@ -1,9 +0,0 @@
1
- export declare const HARDHAT_CONFIG_PREFIX = "hardhat-config:";
2
- export declare const FORGE_CONFIG_PREFIX = "forge-config:";
3
- /**
4
- * All supported inline config keys and their expected value types.
5
- */
6
- export declare const KEY_TYPES: Record<string, "number" | "boolean" | "string">;
7
- /** Top-level key categories (e.g. "fuzz", "invariant", "allowInternalExpectRevert"). */
8
- export declare const TOP_LEVEL_KEYS: string[];
9
- //# sourceMappingURL=constants.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../../../../src/internal/builtin-plugins/solidity-test/inline-config/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,qBAAqB,oBAAoB,CAAC;AACvD,eAAO,MAAM,mBAAmB,kBAAkB,CAAC;AAEnD;;GAEG;AACH,eAAO,MAAM,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,GAAG,SAAS,GAAG,QAAQ,CAarE,CAAC;AAEF,wFAAwF;AACxF,eAAO,MAAM,cAAc,EAAE,MAAM,EAElC,CAAC"}
@@ -1,24 +0,0 @@
1
- export const HARDHAT_CONFIG_PREFIX = "hardhat-config:";
2
- export const FORGE_CONFIG_PREFIX = "forge-config:";
3
- /**
4
- * All supported inline config keys and their expected value types.
5
- */
6
- export const KEY_TYPES = {
7
- "fuzz.runs": "number",
8
- "fuzz.maxTestRejects": "number",
9
- "fuzz.showLogs": "boolean",
10
- "fuzz.timeout": "number",
11
- "invariant.runs": "number",
12
- "invariant.depth": "number",
13
- "invariant.failOnRevert": "boolean",
14
- "invariant.callOverride": "boolean",
15
- "invariant.timeout": "number",
16
- allowInternalExpectRevert: "boolean",
17
- isolate: "boolean",
18
- evmVersion: "string",
19
- };
20
- /** Top-level key categories (e.g. "fuzz", "invariant", "allowInternalExpectRevert"). */
21
- export const TOP_LEVEL_KEYS = [
22
- ...new Set(Object.keys(KEY_TYPES).map((k) => k.split(".")[0])),
23
- ];
24
- //# sourceMappingURL=constants.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../../../../../src/internal/builtin-plugins/solidity-test/inline-config/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,qBAAqB,GAAG,iBAAiB,CAAC;AACvD,MAAM,CAAC,MAAM,mBAAmB,GAAG,eAAe,CAAC;AAEnD;;GAEG;AACH,MAAM,CAAC,MAAM,SAAS,GAAoD;IACxE,WAAW,EAAE,QAAQ;IACrB,qBAAqB,EAAE,QAAQ;IAC/B,eAAe,EAAE,SAAS;IAC1B,cAAc,EAAE,QAAQ;IACxB,gBAAgB,EAAE,QAAQ;IAC1B,iBAAiB,EAAE,QAAQ;IAC3B,wBAAwB,EAAE,SAAS;IACnC,wBAAwB,EAAE,SAAS;IACnC,mBAAmB,EAAE,QAAQ;IAC7B,yBAAyB,EAAE,SAAS;IACpC,OAAO,EAAE,SAAS;IAClB,UAAU,EAAE,QAAQ;CACrB,CAAC;AAEF,wFAAwF;AACxF,MAAM,CAAC,MAAM,cAAc,GAAa;IACtC,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAC/D,CAAC"}
@@ -1,24 +0,0 @@
1
- import type { RawInlineOverride } from "./types.js";
2
- import type { TestFunctionConfigOverride } from "@nomicfoundation/edr";
3
- /**
4
- * Returns true if the build info bytes contain either of the inline config
5
- * prefixes.
6
- */
7
- export declare function buildInfoContainsInlineConfig(buildInfoBytes: Uint8Array): boolean;
8
- /**
9
- * Finds the function selector for a given function name in the methodIdentifiers
10
- * map. Matches the first entry whose signature starts with `functionName(`.
11
- * Returns the selector prefixed with "0x".
12
- */
13
- export declare function resolveFunctionSelector(methodIdentifiers: Record<string, string>, functionName: string): string | undefined;
14
- /**
15
- * Converts a validated set of raw overrides into a TestFunctionConfigOverride
16
- * object.
17
- */
18
- export declare function buildConfigOverride(overrides: RawInlineOverride[]): TestFunctionConfigOverride;
19
- /**
20
- * Constructs a fully qualified function name, in the format
21
- * "source.sol:ContractName#functionName".
22
- */
23
- export declare function getFunctionFqn(inputSourceName: string, contractName: string, functionName: string): string;
24
- //# sourceMappingURL=helpers.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../../../../src/internal/builtin-plugins/solidity-test/inline-config/helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACpD,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,sBAAsB,CAAC;AAavE;;;GAGG;AACH,wBAAgB,6BAA6B,CAC3C,cAAc,EAAE,UAAU,GACzB,OAAO,CAKT;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EACzC,YAAY,EAAE,MAAM,GACnB,MAAM,GAAG,SAAS,CAUpB;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,iBAAiB,EAAE,GAC7B,0BAA0B,CA4C5B;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,eAAe,EAAE,MAAM,EACvB,YAAY,EAAE,MAAM,EACpB,YAAY,EAAE,MAAM,GACnB,MAAM,CAER"}