hardhat 3.1.4 → 3.1.6

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 (70) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/dist/src/internal/builtin-plugins/artifacts/artifact-manager.d.ts +1 -0
  3. package/dist/src/internal/builtin-plugins/artifacts/artifact-manager.d.ts.map +1 -1
  4. package/dist/src/internal/builtin-plugins/artifacts/artifact-manager.js +4 -0
  5. package/dist/src/internal/builtin-plugins/artifacts/artifact-manager.js.map +1 -1
  6. package/dist/src/internal/builtin-plugins/artifacts/hook-handlers/hre.d.ts.map +1 -1
  7. package/dist/src/internal/builtin-plugins/artifacts/hook-handlers/hre.js +4 -0
  8. package/dist/src/internal/builtin-plugins/artifacts/hook-handlers/hre.js.map +1 -1
  9. package/dist/src/internal/builtin-plugins/coverage/reports/html.d.ts.map +1 -1
  10. package/dist/src/internal/builtin-plugins/coverage/reports/html.js +0 -2
  11. package/dist/src/internal/builtin-plugins/coverage/reports/html.js.map +1 -1
  12. package/dist/src/internal/builtin-plugins/solidity/build-system/build-system.d.ts +6 -4
  13. package/dist/src/internal/builtin-plugins/solidity/build-system/build-system.d.ts.map +1 -1
  14. package/dist/src/internal/builtin-plugins/solidity/build-system/build-system.js +83 -39
  15. package/dist/src/internal/builtin-plugins/solidity/build-system/build-system.js.map +1 -1
  16. package/dist/src/internal/builtin-plugins/solidity/build-system/compiler/compiler.d.ts +1 -7
  17. package/dist/src/internal/builtin-plugins/solidity/build-system/compiler/compiler.d.ts.map +1 -1
  18. package/dist/src/internal/builtin-plugins/solidity/build-system/compiler/compiler.js.map +1 -1
  19. package/dist/src/internal/builtin-plugins/solidity/build-system/compiler/downloader.d.ts +1 -1
  20. package/dist/src/internal/builtin-plugins/solidity/build-system/compiler/downloader.d.ts.map +1 -1
  21. package/dist/src/internal/builtin-plugins/solidity/build-system/compiler/downloader.js +38 -15
  22. package/dist/src/internal/builtin-plugins/solidity/build-system/compiler/downloader.js.map +1 -1
  23. package/dist/src/internal/builtin-plugins/solidity/build-system/compiler/index.d.ts +2 -2
  24. package/dist/src/internal/builtin-plugins/solidity/build-system/compiler/index.d.ts.map +1 -1
  25. package/dist/src/internal/builtin-plugins/solidity/build-system/compiler/index.js +1 -1
  26. package/dist/src/internal/builtin-plugins/solidity/build-system/compiler/index.js.map +1 -1
  27. package/dist/src/internal/builtin-plugins/solidity/build-system/root-paths-utils.d.ts +1 -1
  28. package/dist/src/internal/builtin-plugins/solidity/build-system/root-paths-utils.js +2 -2
  29. package/dist/src/internal/builtin-plugins/solidity/build-system/root-paths-utils.js.map +1 -1
  30. package/dist/src/internal/builtin-plugins/solidity/tasks/build.d.ts.map +1 -1
  31. package/dist/src/internal/builtin-plugins/solidity/tasks/build.js +4 -1
  32. package/dist/src/internal/builtin-plugins/solidity/tasks/build.js.map +1 -1
  33. package/dist/src/internal/builtin-plugins/solidity/type-extensions.d.ts +35 -3
  34. package/dist/src/internal/builtin-plugins/solidity/type-extensions.d.ts.map +1 -1
  35. package/dist/src/internal/builtin-plugins/solidity/type-extensions.js.map +1 -1
  36. package/dist/src/internal/builtin-plugins/solidity-test/reporter.d.ts.map +1 -1
  37. package/dist/src/internal/builtin-plugins/solidity-test/reporter.js +66 -82
  38. package/dist/src/internal/builtin-plugins/solidity-test/reporter.js.map +1 -1
  39. package/dist/src/types/artifacts.d.ts +6 -0
  40. package/dist/src/types/artifacts.d.ts.map +1 -1
  41. package/dist/src/types/solidity/build-system.d.ts +34 -3
  42. package/dist/src/types/solidity/build-system.d.ts.map +1 -1
  43. package/dist/src/types/solidity/compiler.d.ts +9 -0
  44. package/dist/src/types/solidity/compiler.d.ts.map +1 -0
  45. package/dist/src/types/solidity/compiler.js +2 -0
  46. package/dist/src/types/solidity/compiler.js.map +1 -0
  47. package/dist/src/types/solidity.d.ts +1 -0
  48. package/dist/src/types/solidity.d.ts.map +1 -1
  49. package/dist/src/types/solidity.js +1 -0
  50. package/dist/src/types/solidity.js.map +1 -1
  51. package/package.json +3 -3
  52. package/src/internal/builtin-plugins/artifacts/artifact-manager.ts +5 -0
  53. package/src/internal/builtin-plugins/artifacts/hook-handlers/hre.ts +5 -0
  54. package/src/internal/builtin-plugins/coverage/reports/html.ts +0 -3
  55. package/src/internal/builtin-plugins/solidity/build-system/build-system.ts +133 -63
  56. package/src/internal/builtin-plugins/solidity/build-system/compiler/compiler.ts +1 -9
  57. package/src/internal/builtin-plugins/solidity/build-system/compiler/downloader.ts +54 -24
  58. package/src/internal/builtin-plugins/solidity/build-system/compiler/index.ts +4 -2
  59. package/src/internal/builtin-plugins/solidity/build-system/root-paths-utils.ts +2 -2
  60. package/src/internal/builtin-plugins/solidity/tasks/build.ts +4 -1
  61. package/src/internal/builtin-plugins/solidity/type-extensions.ts +66 -3
  62. package/src/internal/builtin-plugins/solidity-test/reporter.ts +85 -104
  63. package/src/types/artifacts.ts +7 -0
  64. package/src/types/solidity/build-system.ts +35 -3
  65. package/src/types/solidity/compiler.ts +10 -0
  66. package/src/types/solidity.ts +1 -0
  67. package/templates/hardhat-2/04-mocha-viem-ts/package.json +1 -1
  68. package/templates/hardhat-3/01-node-test-runner-viem/package.json +10 -10
  69. package/templates/hardhat-3/02-mocha-ethers/package.json +8 -8
  70. package/templates/hardhat-3/03-minimal/package.json +1 -1
@@ -1,5 +1,4 @@
1
1
  import type { CompileCache } from "./cache.js";
2
- import type { Compiler } from "./compiler/compiler.js";
3
2
  import type { DependencyGraphImplementation } from "./dependency-graph.js";
4
3
  import type { Artifact } from "../../../../types/artifacts.js";
5
4
  import type { SolcConfig, SolidityConfig } from "../../../../types/config.js";
@@ -16,13 +15,16 @@ import type {
16
15
  EmitArtifactsResult,
17
16
  RunCompilationJobResult,
18
17
  BuildScope,
18
+ CacheHitInfo,
19
19
  } from "../../../../types/solidity/build-system.js";
20
- import type { CompilationJob } from "../../../../types/solidity/compilation-job.js";
21
20
  import type {
21
+ CompilationJob,
22
+ Compiler,
22
23
  CompilerOutput,
23
24
  CompilerOutputError,
24
- } from "../../../../types/solidity/compiler-io.js";
25
- import type { SolidityBuildInfo } from "../../../../types/solidity.js";
25
+ DependencyGraph,
26
+ SolidityBuildInfo,
27
+ } from "../../../../types/solidity.js";
26
28
 
27
29
  import os from "node:os";
28
30
  import path from "node:path";
@@ -62,7 +64,7 @@ import {
62
64
  } from "./artifacts.js";
63
65
  import { loadCache, saveCache } from "./cache.js";
64
66
  import { CompilationJobImplementation } from "./compilation-job.js";
65
- import { downloadConfiguredCompilers, getCompiler } from "./compiler/index.js";
67
+ import { downloadSolcCompilers, getCompiler } from "./compiler/index.js";
66
68
  import { buildDependencyGraph } from "./dependency-graph-building.js";
67
69
  import { readSourceFileFactory } from "./read-source-file.js";
68
70
  import {
@@ -75,10 +77,24 @@ import { SolcConfigSelector } from "./solc-config-selection.js";
75
77
 
76
78
  const log = debug("hardhat:core:solidity:build-system");
77
79
 
80
+ // Compiler warnings to suppress from build output.
81
+ // Each rule specifies a warning message and the source file it applies to.
82
+ // This allows suppressing known warnings from internal files (e.g., console.sol)
83
+ // while still showing the same warning type from user code.
84
+ export const SUPPRESSED_WARNINGS: Array<{
85
+ message: string;
86
+ sourceFile: string;
87
+ }> = [
88
+ {
89
+ message:
90
+ "Natspec memory-safe-assembly special comment for inline assembly is deprecated and scheduled for removal. Use the memory-safe block annotation instead.",
91
+ sourceFile: path.normalize("hardhat/console.sol"),
92
+ },
93
+ ];
94
+
78
95
  interface CompilationResult {
79
96
  compilationJob: CompilationJob;
80
97
  compilerOutput: CompilerOutput;
81
- cached: boolean;
82
98
  compiler: Compiler;
83
99
  }
84
100
 
@@ -91,11 +107,29 @@ export interface SolidityBuildSystemOptions {
91
107
  readonly solidityTestsPath: string;
92
108
  }
93
109
 
110
+ /**
111
+ * Returns the formatted root path for a dependency graph that has exactly one
112
+ * root file.
113
+ *
114
+ * @param dependencyGraph A dependency graph with exactly one root file.
115
+ * @returns The formatted root path.
116
+ * @throws If the graph doesn't have exactly one root file.
117
+ */
118
+ function getSingleRootFilePath(dependencyGraph: DependencyGraph): string {
119
+ assertHardhatInvariant(
120
+ dependencyGraph.getRoots().size === 1,
121
+ "dependency graph doesn't have exactly 1 root file",
122
+ );
123
+
124
+ const [userSourceName, root] = [...dependencyGraph.getRoots().entries()][0];
125
+ return formatRootPath(userSourceName, root);
126
+ }
127
+
94
128
  export class SolidityBuildSystemImplementation implements SolidityBuildSystem {
95
129
  readonly #hooks: HookManager;
96
130
  readonly #options: SolidityBuildSystemOptions;
97
131
  #compileCache: CompileCache = {};
98
- #downloadedCompilers = false;
132
+ #configuredCompilersDownloaded = false;
99
133
 
100
134
  constructor(hooks: HookManager, options: SolidityBuildSystemOptions) {
101
135
  this.#hooks = hooks;
@@ -165,6 +199,19 @@ export class SolidityBuildSystemImplementation implements SolidityBuildSystem {
165
199
  public async build(
166
200
  rootFilePaths: string[],
167
201
  _options?: BuildOptions,
202
+ ): Promise<CompilationJobCreationError | Map<string, FileBuildResult>> {
203
+ return this.#hooks.runHandlerChain(
204
+ "solidity",
205
+ "build",
206
+ [rootFilePaths, _options],
207
+ async (_context, nextRootFilePaths, nextOptions) =>
208
+ this.#build(nextRootFilePaths, nextOptions),
209
+ );
210
+ }
211
+
212
+ async #build(
213
+ rootFilePaths: string[],
214
+ _options?: BuildOptions,
168
215
  ): Promise<CompilationJobCreationError | Map<string, FileBuildResult>> {
169
216
  const options: Required<BuildOptions> = {
170
217
  buildProfile: DEFAULT_BUILD_PROFILE,
@@ -196,7 +243,7 @@ export class SolidityBuildSystemImplementation implements SolidityBuildSystem {
196
243
  spinner.start();
197
244
 
198
245
  try {
199
- const { compilationJobsPerFile, indexedIndividualJobs } =
246
+ const { compilationJobsPerFile, indexedIndividualJobs, cacheHits } =
200
247
  compilationJobsResult;
201
248
 
202
249
  const runnableCompilationJobs = [
@@ -222,7 +269,6 @@ export class SolidityBuildSystemImplementation implements SolidityBuildSystem {
222
269
  return {
223
270
  compilationJob: runnableCompilationJob,
224
271
  compilerOutput: output,
225
- cached: false,
226
272
  compiler,
227
273
  };
228
274
  },
@@ -234,13 +280,11 @@ export class SolidityBuildSystemImplementation implements SolidityBuildSystem {
234
280
  },
235
281
  );
236
282
 
237
- const uncachedResults = results.filter((result) => !result.cached);
238
- const uncachedSuccessfulResults = uncachedResults.filter(
283
+ const successfulResults = results.filter(
239
284
  (result) => !this.#hasCompilationErrors(result.compilerOutput),
240
285
  );
241
286
 
242
- const isSuccessfulBuild =
243
- uncachedResults.length === uncachedSuccessfulResults.length;
287
+ const isSuccessfulBuild = results.length === successfulResults.length;
244
288
 
245
289
  const contractArtifactsGeneratedByCompilationJob: Map<
246
290
  CompilationJob,
@@ -319,18 +363,6 @@ export class SolidityBuildSystemImplementation implements SolidityBuildSystem {
319
363
  continue;
320
364
  }
321
365
 
322
- if (result.cached) {
323
- resultsMap.set(formatRootPath(userSourceName, root), {
324
- type: FileBuildResultType.CACHE_HIT,
325
- compilationJob: result.compilationJob,
326
- contractArtifactsGenerated:
327
- contractArtifactsGenerated.get(userSourceName) ?? [],
328
- warnings: errors,
329
- });
330
-
331
- continue;
332
- }
333
-
334
366
  resultsMap.set(formatRootPath(userSourceName, root), {
335
367
  type: FileBuildResultType.BUILD_SUCCESS,
336
368
  compilationJob: result.compilationJob,
@@ -341,6 +373,15 @@ export class SolidityBuildSystemImplementation implements SolidityBuildSystem {
341
373
  }
342
374
  }
343
375
 
376
+ // Add cache hits to the results map
377
+ for (const [rootFilePath, cacheHitInfo] of cacheHits.entries()) {
378
+ resultsMap.set(rootFilePath, {
379
+ type: FileBuildResultType.CACHE_HIT,
380
+ buildId: cacheHitInfo.buildId,
381
+ contractArtifactsGenerated: cacheHitInfo.artifactPaths,
382
+ });
383
+ }
384
+
344
385
  if (!options.quiet) {
345
386
  if (isSuccessfulBuild) {
346
387
  await this.#printCompilationResult(runnableCompilationJobs, {
@@ -438,14 +479,10 @@ export class SolidityBuildSystemImplementation implements SolidityBuildSystem {
438
479
 
439
480
  await individualJob.getBuildId(); // precompute
440
481
 
441
- assertHardhatInvariant(
442
- subgraph.getRoots().size === 1,
443
- "individual subgraph doesn't have exactly 1 root file",
482
+ indexedIndividualJobs.set(
483
+ getSingleRootFilePath(subgraph),
484
+ individualJob,
444
485
  );
445
-
446
- const rootFilePath = Array.from(subgraph.getRoots().keys())[0];
447
-
448
- indexedIndividualJobs.set(rootFilePath, individualJob);
449
486
  }),
450
487
  );
451
488
 
@@ -454,6 +491,7 @@ export class SolidityBuildSystemImplementation implements SolidityBuildSystem {
454
491
 
455
492
  // Select which files to compile
456
493
  const rootFilesToCompile: Set<string> = new Set();
494
+ const cacheHits: Map<string, CacheHitInfo> = new Map();
457
495
 
458
496
  const isolated = buildProfile.isolated;
459
497
 
@@ -503,6 +541,16 @@ export class SolidityBuildSystemImplementation implements SolidityBuildSystem {
503
541
  break;
504
542
  }
505
543
  }
544
+
545
+ // If file was not added to rootFilesToCompile, it's a cache hit
546
+ if (!rootFilesToCompile.has(rootFile)) {
547
+ // Extract buildId from buildInfoPath (format: <dir>/<buildId>.json)
548
+ const buildId = path.basename(cacheResult.buildInfoPath, ".json");
549
+ cacheHits.set(getSingleRootFilePath(compilationJob.dependencyGraph), {
550
+ buildId,
551
+ artifactPaths,
552
+ });
553
+ }
506
554
  }
507
555
 
508
556
  if (!isolated) {
@@ -518,12 +566,7 @@ export class SolidityBuildSystemImplementation implements SolidityBuildSystem {
518
566
  // based on reference, and not by deep equality. It misses some merging
519
567
  // opportunities, but this is Hardhat v2's behavior and works well enough.
520
568
  for (const [config, subgraph] of subgraphsWithConfig) {
521
- assertHardhatInvariant(
522
- subgraph.getRoots().size === 1,
523
- "there should be only 1 root file on subgraph",
524
- );
525
-
526
- const rootFile = Array.from(subgraph.getRoots().keys())[0];
569
+ const rootFile = getSingleRootFilePath(subgraph);
527
570
 
528
571
  // Skip root files with cache hit (should not recompile)
529
572
  if (!rootFilesToCompile.has(rootFile)) {
@@ -544,12 +587,7 @@ export class SolidityBuildSystemImplementation implements SolidityBuildSystem {
544
587
  // isolated mode
545
588
  subgraphsWithConfig = subgraphsWithConfig.filter(
546
589
  ([_config, subgraph]) => {
547
- assertHardhatInvariant(
548
- subgraph.getRoots().size === 1,
549
- "there should be only 1 root file on subgraph",
550
- );
551
-
552
- const rootFile = Array.from(subgraph.getRoots().keys())[0];
590
+ const rootFile = getSingleRootFilePath(subgraph);
553
591
 
554
592
  return rootFilesToCompile.has(rootFile);
555
593
  },
@@ -581,7 +619,7 @@ export class SolidityBuildSystemImplementation implements SolidityBuildSystem {
581
619
  }
582
620
  }
583
621
 
584
- return { compilationJobsPerFile, indexedIndividualJobs };
622
+ return { compilationJobsPerFile, indexedIndividualJobs, cacheHits };
585
623
  }
586
624
 
587
625
  #getBuildProfile(buildProfileName: string = DEFAULT_BUILD_PROFILE) {
@@ -633,9 +671,17 @@ export class SolidityBuildSystemImplementation implements SolidityBuildSystem {
633
671
  "The long version of the compiler should match the long version of the compilation job",
634
672
  );
635
673
 
636
- const output = await compiler.compile(
637
- await runnableCompilationJob.getSolcInput(),
674
+ const input = await runnableCompilationJob.getSolcInput();
675
+
676
+ const output = await this.#hooks.runHandlerChain(
677
+ "solidity",
678
+ "invokeSolc",
679
+ [compiler, input, runnableCompilationJob.solcConfig],
680
+ async (_context, nextCompiler, nextSolcInput) => {
681
+ return nextCompiler.compile(nextSolcInput);
682
+ },
638
683
  );
684
+
639
685
  return { output, compiler };
640
686
  }
641
687
 
@@ -727,7 +773,7 @@ export class SolidityBuildSystemImplementation implements SolidityBuildSystem {
727
773
  }
728
774
  }
729
775
 
730
- artifactsPerFile.set(userSourceName, paths);
776
+ artifactsPerFile.set(formatRootPath(userSourceName, root), paths);
731
777
 
732
778
  // Write the type declaration file, only for contracts
733
779
  if (scope === "contracts") {
@@ -735,7 +781,10 @@ export class SolidityBuildSystemImplementation implements SolidityBuildSystem {
735
781
  fileFolder,
736
782
  "artifacts.d.ts",
737
783
  );
738
- typeFilePaths.set(userSourceName, artifactsDeclarationFilePath);
784
+ typeFilePaths.set(
785
+ formatRootPath(userSourceName, root),
786
+ artifactsDeclarationFilePath,
787
+ );
739
788
 
740
789
  const artifactsDeclarationFile = getArtifactsDeclarationFile(artifacts);
741
790
 
@@ -936,22 +985,31 @@ export class SolidityBuildSystemImplementation implements SolidityBuildSystem {
936
985
  }
937
986
 
938
987
  public async compileBuildInfo(
939
- _buildInfo: SolidityBuildInfo,
940
- _options?: CompileBuildInfoOptions,
988
+ buildInfo: SolidityBuildInfo,
989
+ options?: CompileBuildInfoOptions,
941
990
  ): Promise<CompilerOutput> {
942
- // TODO: Download the buildinfo compiler version
943
- assertHardhatInvariant(false, "Method not implemented.");
991
+ const quiet = options?.quiet ?? false;
992
+
993
+ // We download the compiler for the build info as it may not be configured
994
+ // in the HH config, hence not downloaded with the other compilers
995
+ await downloadSolcCompilers(new Set([buildInfo.solcVersion]), quiet);
996
+
997
+ const compiler = await getCompiler(buildInfo.solcVersion, {
998
+ preferWasm: false,
999
+ });
1000
+
1001
+ return compiler.compile(buildInfo.input);
944
1002
  }
945
1003
 
946
1004
  async #downloadConfiguredCompilers(quiet = false): Promise<void> {
947
- // TODO: For the alpha release, we always print this message
1005
+ // We always print that we are downloading the compilers
948
1006
  quiet = false;
949
- if (this.#downloadedCompilers) {
1007
+ if (this.#configuredCompilersDownloaded) {
950
1008
  return;
951
1009
  }
952
1010
 
953
- await downloadConfiguredCompilers(this.#getAllCompilerVersions(), quiet);
954
- this.#downloadedCompilers = true;
1011
+ await downloadSolcCompilers(this.#getAllCompilerVersions(), quiet);
1012
+ this.#configuredCompilersDownloaded = true;
955
1013
  }
956
1014
 
957
1015
  #getAllCompilerVersions(): Set<string> {
@@ -1008,11 +1066,10 @@ export class SolidityBuildSystemImplementation implements SolidityBuildSystem {
1008
1066
  isolated: boolean,
1009
1067
  scope: BuildScope,
1010
1068
  ): Promise<void> {
1011
- const rootFilePaths = result.compilationJob.dependencyGraph
1069
+ for (const [userSourceName, root] of result.compilationJob.dependencyGraph
1012
1070
  .getRoots()
1013
- .keys();
1014
-
1015
- for (const rootFilePath of rootFilePaths) {
1071
+ .entries()) {
1072
+ const rootFilePath = formatRootPath(userSourceName, root);
1016
1073
  const individualJob = indexedIndividualJobs.get(rootFilePath);
1017
1074
 
1018
1075
  assertHardhatInvariant(
@@ -1055,9 +1112,14 @@ export class SolidityBuildSystemImplementation implements SolidityBuildSystem {
1055
1112
  return;
1056
1113
  }
1057
1114
 
1115
+ // Filter out specific warnings that should be suppressed
1116
+ const filteredErrors = errors.filter(
1117
+ (error) => !this.#shouldSuppressWarning(error),
1118
+ );
1119
+
1058
1120
  console.log();
1059
1121
 
1060
- for (const error of errors) {
1122
+ for (const error of filteredErrors) {
1061
1123
  if (error.severity === "error") {
1062
1124
  const errorMessage: string =
1063
1125
  this.#getFormattedInternalCompilerErrorMessage(error) ??
@@ -1077,7 +1139,7 @@ export class SolidityBuildSystemImplementation implements SolidityBuildSystem {
1077
1139
  }
1078
1140
  }
1079
1141
 
1080
- const hasConsoleErrors: boolean = errors.some((e) =>
1142
+ const hasConsoleErrors: boolean = filteredErrors.some((e) =>
1081
1143
  this.#isConsoleLogError(e),
1082
1144
  );
1083
1145
 
@@ -1091,6 +1153,14 @@ export class SolidityBuildSystemImplementation implements SolidityBuildSystem {
1091
1153
  }
1092
1154
  }
1093
1155
 
1156
+ #shouldSuppressWarning(error: CompilerOutputError): boolean {
1157
+ const msg = error.formattedMessage ?? error.message;
1158
+
1159
+ return SUPPRESSED_WARNINGS.some(
1160
+ (rule) => msg.includes(rule.message) && msg.includes(rule.sourceFile),
1161
+ );
1162
+ }
1163
+
1094
1164
  async #printCompilationResult(
1095
1165
  runnableCompilationJobs: CompilationJob[],
1096
1166
  options: { scope: BuildScope },
@@ -2,6 +2,7 @@ import type {
2
2
  CompilerInput,
3
3
  CompilerOutput,
4
4
  } from "../../../../../types/solidity/compiler-io.js";
5
+ import type { Compiler } from "../../../../../types/solidity/compiler.js";
5
6
 
6
7
  import { spawn } from "node:child_process";
7
8
  import fsPromises from "node:fs/promises";
@@ -23,15 +24,6 @@ import {
23
24
  import { createNonClosingWriter } from "@nomicfoundation/hardhat-utils/stream";
24
25
  import * as semver from "semver";
25
26
 
26
- export interface Compiler {
27
- readonly version: string;
28
- readonly longVersion: string;
29
- readonly compilerPath: string;
30
- readonly isSolcJs: boolean;
31
-
32
- compile(input: CompilerInput): Promise<CompilerOutput>;
33
- }
34
-
35
27
  /**
36
28
  * Spawns a compilation process and returns its output.
37
29
  *
@@ -1,4 +1,4 @@
1
- import type { Compiler } from "./compiler.js";
1
+ import type { Compiler } from "../../../../../../src/types/solidity.js";
2
2
 
3
3
  import { execFile } from "node:child_process";
4
4
  import os from "node:os";
@@ -32,6 +32,8 @@ import { NativeCompiler, SolcJsCompiler } from "./compiler.js";
32
32
  const log = debug("hardhat:solidity:downloader");
33
33
 
34
34
  const COMPILER_REPOSITORY_URL = "https://binaries.soliditylang.org";
35
+ const DEFAULT_COMPILER_DOWNLOAD_RETRY_COUNT = 3;
36
+ const DEFAULT_COMPILER_DOWNLOAD_RETRY_DELAY_MS = 2000;
35
37
 
36
38
  // We use a mirror of nikitastupin/solc because downloading directly from
37
39
  // github has rate limiting issues
@@ -211,29 +213,27 @@ export class CompilerDownloaderImplementation implements CompilerDownloader {
211
213
 
212
214
  const build = await this.#getCompilerBuild(version);
213
215
 
214
- let downloadPath: string;
215
- try {
216
- downloadPath = await this.#downloadCompiler(build);
217
- } catch (e) {
218
- ensureError(e);
219
-
220
- throw new HardhatError(
221
- HardhatError.ERRORS.CORE.SOLIDITY.DOWNLOAD_FAILED,
222
- {
223
- remoteVersion: build.longVersion,
224
- },
225
- e,
226
- );
227
- }
228
-
229
- const verified = await this.#verifyCompilerDownload(build, downloadPath);
230
- if (!verified) {
231
- throw new HardhatError(
232
- HardhatError.ERRORS.CORE.SOLIDITY.INVALID_DOWNLOAD,
233
- {
234
- remoteVersion: build.longVersion,
235
- },
236
- );
216
+ let downloadPath: string = "";
217
+ for (let i = 0; i <= DEFAULT_COMPILER_DOWNLOAD_RETRY_COUNT; i++) {
218
+ try {
219
+ downloadPath = await this.#downloadAndVerifyCompiler(build);
220
+ break;
221
+ } catch (e) {
222
+ if (i === DEFAULT_COMPILER_DOWNLOAD_RETRY_COUNT) {
223
+ ensureError(e);
224
+ throw e;
225
+ } else {
226
+ const attempt = i + 1;
227
+
228
+ log(
229
+ `Download or verification failed for solc ${version}, retrying (attempt ${attempt} of ${DEFAULT_COMPILER_DOWNLOAD_RETRY_COUNT})`,
230
+ );
231
+
232
+ await new Promise((resolve) =>
233
+ setTimeout(resolve, DEFAULT_COMPILER_DOWNLOAD_RETRY_DELAY_MS),
234
+ );
235
+ }
236
+ }
237
237
  }
238
238
 
239
239
  return this.#postProcessCompilerDownload(build, downloadPath);
@@ -391,6 +391,36 @@ export class CompilerDownloaderImplementation implements CompilerDownloader {
391
391
  }
392
392
  }
393
393
 
394
+ async #downloadAndVerifyCompiler(build: CompilerBuild): Promise<string> {
395
+ let downloadPath: string = "";
396
+
397
+ try {
398
+ downloadPath = await this.#downloadCompiler(build);
399
+ } catch (e) {
400
+ ensureError(e);
401
+
402
+ throw new HardhatError(
403
+ HardhatError.ERRORS.CORE.SOLIDITY.DOWNLOAD_FAILED,
404
+ {
405
+ remoteVersion: build.longVersion,
406
+ },
407
+ e,
408
+ );
409
+ }
410
+
411
+ const verified = await this.#verifyCompilerDownload(build, downloadPath);
412
+ if (!verified) {
413
+ throw new HardhatError(
414
+ HardhatError.ERRORS.CORE.SOLIDITY.INVALID_DOWNLOAD,
415
+ {
416
+ remoteVersion: build.longVersion,
417
+ },
418
+ );
419
+ }
420
+
421
+ return downloadPath;
422
+ }
423
+
394
424
  async #downloadCompiler(build: CompilerBuild): Promise<string> {
395
425
  // use the explicit URL if available or the default solc download URL if not
396
426
  const defaultUrl = `${COMPILER_REPOSITORY_URL}/${this.#platform}`;
@@ -1,3 +1,5 @@
1
+ import type { Compiler } from "../../../../../types/solidity.js";
2
+
1
3
  import { execFile } from "node:child_process";
2
4
  import path from "node:path";
3
5
  import { pathToFileURL } from "node:url";
@@ -11,7 +13,7 @@ import { exists, isBinaryFile } from "@nomicfoundation/hardhat-utils/fs";
11
13
  import { getCacheDir } from "@nomicfoundation/hardhat-utils/global-dir";
12
14
  import debug from "debug";
13
15
 
14
- import { NativeCompiler, SolcJsCompiler, type Compiler } from "./compiler.js";
16
+ import { NativeCompiler, SolcJsCompiler } from "./compiler.js";
15
17
  import {
16
18
  CompilerDownloaderImplementation,
17
19
  CompilerPlatform,
@@ -26,7 +28,7 @@ async function getGlobalCompilersCacheDir(): Promise<string> {
26
28
 
27
29
  const log = debug("hardhat:core:solidity:build-system:compiler");
28
30
 
29
- export async function downloadConfiguredCompilers(
31
+ export async function downloadSolcCompilers(
30
32
  versions: Set<string>,
31
33
  quiet: boolean,
32
34
  ): Promise<void> {
@@ -63,7 +63,7 @@ export function isNpmParsedRootPath(
63
63
 
64
64
  /**
65
65
  * Formats the path of a root file, making it compatible with the
66
- * SolidityBuildSystem APIs.
66
+ * SolidityBuildSystem APIs, which expect an absolute path or an npm: root path.
67
67
  *
68
68
  * @param userSourceName The user source name of the root file.
69
69
  * @param rootFile The root file.
@@ -74,7 +74,7 @@ export function formatRootPath(
74
74
  rootFile: ResolvedFile,
75
75
  ): string {
76
76
  if (rootFile.type !== ResolvedFileType.NPM_PACKAGE_FILE) {
77
- return userSourceName;
77
+ return rootFile.fsPath;
78
78
  }
79
79
 
80
80
  return `npm:${userSourceName}`;
@@ -114,7 +114,10 @@ async function buildForScope(
114
114
 
115
115
  // If we recompiled the entire project we cleanup the artifacts
116
116
  if (isFullCompilation) {
117
- await solidity.cleanupArtifacts(rootPaths, { scope });
117
+ // Use the root files from the build results, which may include
118
+ // additional files added by plugins hooking into solidity#build
119
+ const builtRootPaths = [...results.keys()];
120
+ await solidity.cleanupArtifacts(builtRootPaths, { scope });
118
121
  }
119
122
 
120
123
  return { rootPaths, usedFiles };
@@ -1,5 +1,15 @@
1
- import type { SolidityBuildSystem } from "../../../types/solidity/build-system.js";
2
- import type { CompilerInput } from "../../../types/solidity.js";
1
+ import type { SolcConfig } from "../../../types/config.js";
2
+ import type {
3
+ BuildOptions,
4
+ CompilationJobCreationError,
5
+ FileBuildResult,
6
+ SolidityBuildSystem,
7
+ } from "../../../types/solidity/build-system.js";
8
+ import type {
9
+ Compiler,
10
+ CompilerInput,
11
+ CompilerOutput,
12
+ } from "../../../types/solidity.js";
3
13
 
4
14
  import "../../../types/config.js";
5
15
  declare module "../../../types/config.js" {
@@ -123,7 +133,10 @@ declare module "../../../types/hooks.js" {
123
133
  ) => Promise<void>;
124
134
 
125
135
  /**
126
- * Hook triggered within the compilation job when its' solc input is first constructed.
136
+ * Hook triggered to preprocess a Solidity file and manipulate its contents
137
+ * before it is passed along for compilation. Only files directly under
138
+ * the Hardhat project are preprocessed, Solidity files from npm
139
+ * dependencies are not included.
127
140
  *
128
141
  * @param context The hook context.
129
142
  * @param inputSourceName The input source name of the project file.
@@ -177,5 +190,55 @@ declare module "../../../types/hooks.js" {
177
190
  nextAbsolutePath: string,
178
191
  ) => Promise<string>,
179
192
  ) => Promise<string>;
193
+
194
+ /**
195
+ * Hook triggered when a Solidity build process is run using the `build`
196
+ * method of the Solidity build system.
197
+ *
198
+ * @param context The hook context.
199
+ * @param rootFilePaths The files to build, which can be either absolute
200
+ * paths or `npm:<package-name>/<file-path>` URIs.
201
+ * @param options The options to use when building the files.
202
+ * @param next A function to call the next handler for this hook.
203
+ */
204
+ build: (
205
+ context: HookContext,
206
+ rootFilePaths: string[],
207
+ options: BuildOptions | undefined,
208
+ next: (
209
+ nextContext: HookContext,
210
+ nextRootFilePaths: string[],
211
+ nextOptions: BuildOptions | undefined,
212
+ ) => Promise<CompilationJobCreationError | Map<string, FileBuildResult>>,
213
+ ) => Promise<CompilationJobCreationError | Map<string, FileBuildResult>>;
214
+
215
+ /**
216
+ * Hook triggered to invoke a passed in Solc compiler on the
217
+ * Solc input generated for a given compilation job.
218
+ * This hook allows for manipulating the Solc input passed into the Solc
219
+ * compiler Hardhat has selected for the compilation job, and similarly to
220
+ * manipulate the Solc output.
221
+ *
222
+ * @param context The hook context.
223
+ * @param compile The Solc compiler selected by Hardhat for this compilation
224
+ * job.
225
+ * @param solcInput The solc input json constructed from the compilation
226
+ * job.
227
+ * @param solcConfig The configuration used to setup solc e.g. version.
228
+ * @param next A function to call the next handler for this hook, or the
229
+ * default implementation if no more handlers exist.
230
+ */
231
+ invokeSolc(
232
+ context: HookContext,
233
+ compiler: Compiler,
234
+ solcInput: CompilerInput,
235
+ solcConfig: SolcConfig,
236
+ next: (
237
+ nextContext: HookContext,
238
+ nextCompiler: Compiler,
239
+ nextSolcInput: CompilerInput,
240
+ nextSolcConfig: SolcConfig,
241
+ ) => Promise<CompilerOutput>,
242
+ ): Promise<CompilerOutput>;
180
243
  }
181
244
  }