hardhat 2.13.0-dev.0 → 2.13.0-dev.1

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 (116) hide show
  1. package/builtin-tasks/compile.js +1 -10
  2. package/builtin-tasks/compile.js.map +1 -1
  3. package/builtin-tasks/task-names.d.ts +0 -1
  4. package/builtin-tasks/task-names.d.ts.map +1 -1
  5. package/builtin-tasks/task-names.js +2 -3
  6. package/builtin-tasks/task-names.js.map +1 -1
  7. package/internal/artifacts/caching.d.ts +27 -0
  8. package/internal/artifacts/caching.d.ts.map +1 -0
  9. package/internal/artifacts/caching.js +167 -0
  10. package/internal/artifacts/caching.js.map +1 -0
  11. package/internal/artifacts/index.d.ts +44 -0
  12. package/internal/artifacts/index.d.ts.map +1 -0
  13. package/internal/artifacts/index.js +187 -0
  14. package/internal/artifacts/index.js.map +1 -0
  15. package/internal/artifacts/mutable.d.ts +29 -0
  16. package/internal/artifacts/mutable.d.ts.map +1 -0
  17. package/internal/artifacts/mutable.js +226 -0
  18. package/internal/artifacts/mutable.js.map +1 -0
  19. package/internal/artifacts/readonly.d.ts +88 -0
  20. package/internal/artifacts/readonly.d.ts.map +1 -0
  21. package/internal/artifacts/readonly.js +324 -0
  22. package/internal/artifacts/readonly.js.map +1 -0
  23. package/internal/cli/cli.js +5 -2
  24. package/internal/cli/cli.js.map +1 -1
  25. package/internal/core/config/config-env.d.ts +7 -1
  26. package/internal/core/config/config-env.d.ts.map +1 -1
  27. package/internal/core/config/config-env.js +13 -2
  28. package/internal/core/config/config-env.js.map +1 -1
  29. package/internal/core/config/extenders.d.ts +7 -4
  30. package/internal/core/config/extenders.d.ts.map +1 -1
  31. package/internal/core/config/extenders.js +12 -5
  32. package/internal/core/config/extenders.js.map +1 -1
  33. package/internal/core/errors-list.d.ts +7 -0
  34. package/internal/core/errors-list.d.ts.map +1 -1
  35. package/internal/core/errors-list.js +9 -0
  36. package/internal/core/errors-list.js.map +1 -1
  37. package/internal/core/runtime-environment.d.ts +2 -2
  38. package/internal/core/runtime-environment.d.ts.map +1 -1
  39. package/internal/core/runtime-environment.js +2 -2
  40. package/internal/core/runtime-environment.js.map +1 -1
  41. package/internal/hardhat-network/provider/fork/ForkBlockchain.d.ts.map +1 -1
  42. package/internal/hardhat-network/provider/fork/ForkBlockchain.js +9 -1
  43. package/internal/hardhat-network/provider/fork/ForkBlockchain.js.map +1 -1
  44. package/internal/hardhat-network/provider/transactions/ReadOnlyValidUnknownTypeTransaction.d.ts +32 -0
  45. package/internal/hardhat-network/provider/transactions/ReadOnlyValidUnknownTypeTransaction.d.ts.map +1 -0
  46. package/internal/hardhat-network/provider/transactions/ReadOnlyValidUnknownTypeTransaction.js +87 -0
  47. package/internal/hardhat-network/provider/transactions/ReadOnlyValidUnknownTypeTransaction.js.map +1 -0
  48. package/internal/hardhat-network/provider/utils/bloom.d.ts +28 -0
  49. package/internal/hardhat-network/provider/utils/bloom.d.ts.map +1 -0
  50. package/internal/hardhat-network/provider/utils/bloom.js +73 -0
  51. package/internal/hardhat-network/provider/utils/bloom.js.map +1 -0
  52. package/internal/hardhat-network/provider/utils/convertToRethnet.d.ts +26 -1
  53. package/internal/hardhat-network/provider/utils/convertToRethnet.d.ts.map +1 -1
  54. package/internal/hardhat-network/provider/utils/convertToRethnet.js +189 -6
  55. package/internal/hardhat-network/provider/utils/convertToRethnet.js.map +1 -1
  56. package/internal/hardhat-network/provider/vm/block-builder.d.ts +30 -0
  57. package/internal/hardhat-network/provider/vm/block-builder.d.ts.map +1 -0
  58. package/internal/hardhat-network/provider/vm/block-builder.js +147 -0
  59. package/internal/hardhat-network/provider/vm/block-builder.js.map +1 -0
  60. package/internal/hardhat-network/provider/vm/dual.d.ts +43 -0
  61. package/internal/hardhat-network/provider/vm/dual.d.ts.map +1 -0
  62. package/internal/hardhat-network/provider/vm/dual.js +120 -0
  63. package/internal/hardhat-network/provider/vm/dual.js.map +1 -0
  64. package/internal/hardhat-network/provider/vm/ethereumjs.d.ts +55 -0
  65. package/internal/hardhat-network/provider/vm/ethereumjs.d.ts.map +1 -0
  66. package/internal/hardhat-network/provider/vm/ethereumjs.js +272 -0
  67. package/internal/hardhat-network/provider/vm/ethereumjs.js.map +1 -0
  68. package/internal/hardhat-network/provider/vm/rethnet.d.ts +111 -0
  69. package/internal/hardhat-network/provider/vm/rethnet.d.ts.map +1 -0
  70. package/internal/hardhat-network/provider/vm/rethnet.js +171 -0
  71. package/internal/hardhat-network/provider/vm/rethnet.js.map +1 -0
  72. package/internal/hardhat-network/provider/vm/vm-adapter.d.ts +36 -0
  73. package/internal/hardhat-network/provider/vm/vm-adapter.d.ts.map +1 -0
  74. package/internal/hardhat-network/provider/vm/vm-adapter.js +3 -0
  75. package/internal/hardhat-network/provider/vm/vm-adapter.js.map +1 -0
  76. package/internal/lib/hardhat-lib.d.ts.map +1 -1
  77. package/internal/lib/hardhat-lib.js +4 -1
  78. package/internal/lib/hardhat-lib.js.map +1 -1
  79. package/internal/solidity/compiler/compiler-input.d.ts.map +1 -1
  80. package/internal/solidity/compiler/compiler-input.js +5 -1
  81. package/internal/solidity/compiler/compiler-input.js.map +1 -1
  82. package/internal/solidity/compiler/downloader.d.ts.map +1 -1
  83. package/internal/solidity/compiler/downloader.js +10 -12
  84. package/internal/solidity/compiler/downloader.js.map +1 -1
  85. package/internal/solidity/resolver.d.ts +3 -4
  86. package/internal/solidity/resolver.d.ts.map +1 -1
  87. package/internal/solidity/resolver.js +3 -5
  88. package/internal/solidity/resolver.js.map +1 -1
  89. package/package.json +1 -1
  90. package/register.js +4 -1
  91. package/register.js.map +1 -1
  92. package/src/builtin-tasks/compile.ts +1 -16
  93. package/src/builtin-tasks/task-names.ts +0 -2
  94. package/src/internal/artifacts/caching.ts +239 -0
  95. package/src/internal/artifacts/index.ts +296 -0
  96. package/src/internal/artifacts/mutable.ts +330 -0
  97. package/src/internal/artifacts/readonly.ts +438 -0
  98. package/src/internal/cli/cli.ts +6 -1
  99. package/src/internal/core/config/config-env.ts +13 -1
  100. package/src/internal/core/config/extenders.ts +15 -6
  101. package/src/internal/core/errors-list.ts +9 -0
  102. package/src/internal/core/runtime-environment.ts +3 -1
  103. package/src/internal/hardhat-network/provider/fork/ForkBlockchain.ts +15 -3
  104. package/src/internal/hardhat-network/provider/transactions/ReadOnlyValidUnknownTypeTransaction.ts +162 -0
  105. package/src/internal/lib/hardhat-lib.ts +6 -1
  106. package/src/internal/solidity/compiler/compiler-input.ts +7 -1
  107. package/src/internal/solidity/compiler/downloader.ts +11 -11
  108. package/src/internal/solidity/resolver.ts +3 -8
  109. package/src/register.ts +6 -1
  110. package/src/types/artifacts.ts +104 -4
  111. package/src/types/runtime.ts +7 -1
  112. package/types/artifacts.d.ts +90 -4
  113. package/types/artifacts.d.ts.map +1 -1
  114. package/types/runtime.d.ts +6 -1
  115. package/types/runtime.d.ts.map +1 -1
  116. package/src/internal/artifacts.ts +0 -918
@@ -1,918 +0,0 @@
1
- import debug from "debug";
2
- import fsExtra from "fs-extra";
3
- import * as os from "os";
4
- import * as path from "path";
5
- import fsPromises from "fs/promises";
6
-
7
- import {
8
- Artifact,
9
- Artifacts as IArtifacts,
10
- BuildInfo,
11
- CompilerInput,
12
- CompilerOutput,
13
- DebugFile,
14
- } from "../types";
15
- import {
16
- getFullyQualifiedName,
17
- isFullyQualifiedName,
18
- parseFullyQualifiedName,
19
- findDistance,
20
- } from "../utils/contract-names";
21
- import { replaceBackslashes } from "../utils/source-names";
22
-
23
- import {
24
- ARTIFACT_FORMAT_VERSION,
25
- BUILD_INFO_DIR_NAME,
26
- BUILD_INFO_FORMAT_VERSION,
27
- DEBUG_FILE_FORMAT_VERSION,
28
- EDIT_DISTANCE_THRESHOLD,
29
- } from "./constants";
30
- import { HardhatError } from "./core/errors";
31
- import { ERRORS } from "./core/errors-list";
32
- import { createNonCryptographicHashBasedIdentifier } from "./util/hash";
33
- import {
34
- FileNotFoundError,
35
- getAllFilesMatching,
36
- getAllFilesMatchingSync,
37
- getFileTrueCase,
38
- getFileTrueCaseSync,
39
- } from "./util/fs-utils";
40
-
41
- const log = debug("hardhat:core:artifacts");
42
-
43
- interface Cache {
44
- artifactPaths?: string[];
45
- debugFilePaths?: string[];
46
- buildInfoPaths?: string[];
47
- artifactNameToArtifactPathCache: Map<string, string>;
48
- artifactFQNToBuildInfoPathCache: Map<string, string>;
49
- }
50
-
51
- export class Artifacts implements IArtifacts {
52
- private _validArtifacts: Array<{ sourceName: string; artifacts: string[] }>;
53
-
54
- // Undefined means that the cache is disabled.
55
- private _cache?: Cache = {
56
- artifactNameToArtifactPathCache: new Map(),
57
- artifactFQNToBuildInfoPathCache: new Map(),
58
- };
59
-
60
- constructor(private _artifactsPath: string) {
61
- this._validArtifacts = [];
62
- }
63
-
64
- public addValidArtifacts(
65
- validArtifacts: Array<{ sourceName: string; artifacts: string[] }>
66
- ) {
67
- this._validArtifacts.push(...validArtifacts);
68
- }
69
-
70
- public async readArtifact(name: string): Promise<Artifact> {
71
- const artifactPath = await this._getArtifactPath(name);
72
- return fsExtra.readJson(artifactPath);
73
- }
74
-
75
- public readArtifactSync(name: string): Artifact {
76
- const artifactPath = this._getArtifactPathSync(name);
77
- return fsExtra.readJsonSync(artifactPath);
78
- }
79
-
80
- public async artifactExists(name: string): Promise<boolean> {
81
- const artifactPath = await this._getArtifactPath(name);
82
- return fsExtra.pathExists(artifactPath);
83
- }
84
-
85
- public async getAllFullyQualifiedNames(): Promise<string[]> {
86
- const paths = await this.getArtifactPaths();
87
- return paths.map((p) => this._getFullyQualifiedNameFromPath(p)).sort();
88
- }
89
-
90
- public async getBuildInfo(
91
- fullyQualifiedName: string
92
- ): Promise<BuildInfo | undefined> {
93
- let buildInfoPath =
94
- this._cache?.artifactFQNToBuildInfoPathCache.get(fullyQualifiedName);
95
-
96
- if (buildInfoPath === undefined) {
97
- const artifactPath =
98
- this.formArtifactPathFromFullyQualifiedName(fullyQualifiedName);
99
-
100
- const debugFilePath = this._getDebugFilePath(artifactPath);
101
- buildInfoPath = await this._getBuildInfoFromDebugFile(debugFilePath);
102
-
103
- if (buildInfoPath === undefined) {
104
- return undefined;
105
- }
106
-
107
- this._cache?.artifactFQNToBuildInfoPathCache.set(
108
- fullyQualifiedName,
109
- buildInfoPath
110
- );
111
- }
112
-
113
- return fsExtra.readJSON(buildInfoPath);
114
- }
115
-
116
- public async getArtifactPaths(): Promise<string[]> {
117
- const cached = this._cache?.artifactPaths;
118
- if (cached !== undefined) {
119
- return cached;
120
- }
121
-
122
- const buildInfosDir = path.join(this._artifactsPath, BUILD_INFO_DIR_NAME);
123
-
124
- const paths = await getAllFilesMatching(
125
- this._artifactsPath,
126
- (f) =>
127
- f.endsWith(".json") &&
128
- !f.startsWith(buildInfosDir) &&
129
- !f.endsWith(".dbg.json")
130
- );
131
-
132
- const result = paths.sort();
133
-
134
- if (this._cache !== undefined) {
135
- this._cache.artifactPaths = result;
136
- }
137
-
138
- return result;
139
- }
140
-
141
- public async getBuildInfoPaths(): Promise<string[]> {
142
- const cached = this._cache?.buildInfoPaths;
143
- if (cached !== undefined) {
144
- return cached;
145
- }
146
-
147
- const paths = await getAllFilesMatching(
148
- path.join(this._artifactsPath, BUILD_INFO_DIR_NAME),
149
- (f) => f.endsWith(".json")
150
- );
151
-
152
- const result = paths.sort();
153
-
154
- if (this._cache !== undefined) {
155
- this._cache.buildInfoPaths = result;
156
- }
157
-
158
- return result;
159
- }
160
-
161
- public async getDebugFilePaths(): Promise<string[]> {
162
- const cached = this._cache?.debugFilePaths;
163
- if (cached !== undefined) {
164
- return cached;
165
- }
166
-
167
- const paths = await getAllFilesMatching(
168
- path.join(this._artifactsPath),
169
- (f) => f.endsWith(".dbg.json")
170
- );
171
-
172
- const result = paths.sort();
173
-
174
- if (this._cache !== undefined) {
175
- this._cache.debugFilePaths = result;
176
- }
177
-
178
- return result;
179
- }
180
-
181
- public async saveArtifactAndDebugFile(
182
- artifact: Artifact,
183
- pathToBuildInfo?: string
184
- ) {
185
- try {
186
- // artifact
187
- const fullyQualifiedName = getFullyQualifiedName(
188
- artifact.sourceName,
189
- artifact.contractName
190
- );
191
-
192
- const artifactPath =
193
- this.formArtifactPathFromFullyQualifiedName(fullyQualifiedName);
194
-
195
- await fsExtra.ensureDir(path.dirname(artifactPath));
196
-
197
- await Promise.all([
198
- fsExtra.writeJSON(artifactPath, artifact, {
199
- spaces: 2,
200
- }),
201
- (async () => {
202
- if (pathToBuildInfo === undefined) {
203
- return;
204
- }
205
-
206
- // save debug file
207
- const debugFilePath = this._getDebugFilePath(artifactPath);
208
- const debugFile = this._createDebugFile(
209
- artifactPath,
210
- pathToBuildInfo
211
- );
212
-
213
- await fsExtra.writeJSON(debugFilePath, debugFile, {
214
- spaces: 2,
215
- });
216
- })(),
217
- ]);
218
- } finally {
219
- this.clearCache();
220
- }
221
- }
222
-
223
- public async saveBuildInfo(
224
- solcVersion: string,
225
- solcLongVersion: string,
226
- input: CompilerInput,
227
- output: CompilerOutput
228
- ): Promise<string> {
229
- try {
230
- const buildInfoDir = path.join(this._artifactsPath, BUILD_INFO_DIR_NAME);
231
- await fsExtra.ensureDir(buildInfoDir);
232
-
233
- const buildInfoName = this._getBuildInfoName(
234
- solcVersion,
235
- solcLongVersion,
236
- input
237
- );
238
-
239
- const buildInfo = this._createBuildInfo(
240
- buildInfoName,
241
- solcVersion,
242
- solcLongVersion,
243
- input,
244
- output
245
- );
246
-
247
- const buildInfoPath = path.join(buildInfoDir, `${buildInfoName}.json`);
248
-
249
- // JSON.stringify of the entire build info can be really slow
250
- // in larger projects, so we stringify per part and incrementally create
251
- // the JSON in the file.
252
- //
253
- // We split this code into different curly-brace-enclosed scopes so that
254
- // partial JSON strings get out of scope sooner and hence can be reclaimed
255
- // by the GC if needed.
256
- const file = await fsPromises.open(buildInfoPath, "w");
257
- try {
258
- {
259
- const withoutOutput = JSON.stringify({
260
- ...buildInfo,
261
- output: undefined,
262
- });
263
-
264
- // We write the JSON (without output) except the last }
265
- await file.write(withoutOutput.slice(0, -1));
266
- }
267
-
268
- {
269
- const outputWithoutSourcesAndContracts = JSON.stringify({
270
- ...buildInfo.output,
271
- sources: undefined,
272
- contracts: undefined,
273
- });
274
-
275
- // We start writing the output
276
- await file.write(',"output":');
277
-
278
- // Write the output object except for the last }
279
- await file.write(outputWithoutSourcesAndContracts.slice(0, -1));
280
-
281
- // If there were other field apart from sources and contracts we need
282
- // a comma
283
- if (outputWithoutSourcesAndContracts.length > 2) {
284
- await file.write(",");
285
- }
286
- }
287
-
288
- // Writing the sources
289
- await file.write('"sources":{');
290
-
291
- let isFirst = true;
292
- for (const [name, value] of Object.entries(
293
- buildInfo.output.sources ?? {}
294
- )) {
295
- if (isFirst) {
296
- isFirst = false;
297
- } else {
298
- await file.write(",");
299
- }
300
-
301
- await file.write(`${JSON.stringify(name)}:${JSON.stringify(value)}`);
302
- }
303
-
304
- // Close sources object
305
- await file.write("}");
306
-
307
- // Writing the contracts
308
- await file.write(',"contracts":{');
309
-
310
- isFirst = true;
311
- for (const [name, value] of Object.entries(
312
- buildInfo.output.contracts ?? {}
313
- )) {
314
- if (isFirst) {
315
- isFirst = false;
316
- } else {
317
- await file.write(",");
318
- }
319
-
320
- await file.write(`${JSON.stringify(name)}:${JSON.stringify(value)}`);
321
- }
322
-
323
- // close contracts object
324
- await file.write("}");
325
- // close output object
326
- await file.write("}");
327
- // close build info object
328
- await file.write("}");
329
- } finally {
330
- await file.close();
331
- }
332
-
333
- return buildInfoPath;
334
- } finally {
335
- this.clearCache();
336
- }
337
- }
338
-
339
- /**
340
- * Remove all artifacts that don't correspond to the current solidity files
341
- */
342
- public async removeObsoleteArtifacts() {
343
- // We clear the cache here, as we want to be sure this runs correctly
344
- this.clearCache();
345
-
346
- try {
347
- const validArtifactPaths = await Promise.all(
348
- this._validArtifacts.flatMap(({ sourceName, artifacts }) =>
349
- artifacts.map((artifactName) =>
350
- this._getArtifactPath(
351
- getFullyQualifiedName(sourceName, artifactName)
352
- )
353
- )
354
- )
355
- );
356
-
357
- const validArtifactsPathsSet = new Set<string>(validArtifactPaths);
358
-
359
- for (const { sourceName, artifacts } of this._validArtifacts) {
360
- for (const artifactName of artifacts) {
361
- validArtifactsPathsSet.add(
362
- this.formArtifactPathFromFullyQualifiedName(
363
- getFullyQualifiedName(sourceName, artifactName)
364
- )
365
- );
366
- }
367
- }
368
-
369
- const existingArtifactsPaths = await this.getArtifactPaths();
370
-
371
- await Promise.all(
372
- existingArtifactsPaths
373
- .filter((artifactPath) => !validArtifactsPathsSet.has(artifactPath))
374
- .map((artifactPath) => this._removeArtifactFiles(artifactPath))
375
- );
376
-
377
- await this._removeObsoleteBuildInfos();
378
- } finally {
379
- // We clear the cache here, as this may have non-existent paths now
380
- this.clearCache();
381
- }
382
- }
383
-
384
- /**
385
- * Returns the absolute path to the given artifact
386
- */
387
- public formArtifactPathFromFullyQualifiedName(
388
- fullyQualifiedName: string
389
- ): string {
390
- const { sourceName, contractName } =
391
- parseFullyQualifiedName(fullyQualifiedName);
392
-
393
- return path.join(this._artifactsPath, sourceName, `${contractName}.json`);
394
- }
395
-
396
- public clearCache() {
397
- // Avoid accidentally re-enabling the cache
398
- if (this._cache === undefined) {
399
- return;
400
- }
401
-
402
- this._cache = {
403
- artifactFQNToBuildInfoPathCache: new Map(),
404
- artifactNameToArtifactPathCache: new Map(),
405
- };
406
- }
407
-
408
- public disableCache() {
409
- this._cache = undefined;
410
- }
411
-
412
- /**
413
- * Remove all build infos that aren't used by any debug file
414
- */
415
- private async _removeObsoleteBuildInfos() {
416
- const debugFiles = await this.getDebugFilePaths();
417
-
418
- const buildInfos = await Promise.all(
419
- debugFiles.map(async (debugFile) => {
420
- const buildInfoFile = await this._getBuildInfoFromDebugFile(debugFile);
421
- if (buildInfoFile !== undefined) {
422
- return path.resolve(path.dirname(debugFile), buildInfoFile);
423
- } else {
424
- return undefined;
425
- }
426
- })
427
- );
428
-
429
- const filteredBuildInfos: string[] = buildInfos.filter(
430
- (bf): bf is string => typeof bf === "string"
431
- );
432
-
433
- const validBuildInfos = new Set<string>(filteredBuildInfos);
434
-
435
- const buildInfoFiles = await this.getBuildInfoPaths();
436
-
437
- await Promise.all(
438
- buildInfoFiles
439
- .filter((buildInfoFile) => !validBuildInfos.has(buildInfoFile))
440
- .map(async (buildInfoFile) => {
441
- log(`Removing buildInfo '${buildInfoFile}'`);
442
- await fsExtra.unlink(buildInfoFile);
443
- })
444
- );
445
- }
446
-
447
- private _getBuildInfoName(
448
- solcVersion: string,
449
- solcLongVersion: string,
450
- input: CompilerInput
451
- ): string {
452
- const json = JSON.stringify({
453
- _format: BUILD_INFO_FORMAT_VERSION,
454
- solcVersion,
455
- solcLongVersion,
456
- input,
457
- });
458
-
459
- return createNonCryptographicHashBasedIdentifier(
460
- Buffer.from(json)
461
- ).toString("hex");
462
- }
463
-
464
- /**
465
- * Returns the absolute path to the artifact that corresponds to the given
466
- * name.
467
- *
468
- * If the name is fully qualified, the path is computed from it. If not, an
469
- * artifact that matches the given name is searched in the existing artifacts.
470
- * If there is an ambiguity, an error is thrown.
471
- */
472
- private async _getArtifactPath(name: string): Promise<string> {
473
- const cached = this._cache?.artifactNameToArtifactPathCache.get(name);
474
- if (cached !== undefined) {
475
- return cached;
476
- }
477
-
478
- let result: string;
479
- if (isFullyQualifiedName(name)) {
480
- result = await this._getValidArtifactPathFromFullyQualifiedName(name);
481
- } else {
482
- const files = await this.getArtifactPaths();
483
- result = this._getArtifactPathFromFiles(name, files);
484
- }
485
-
486
- this._cache?.artifactNameToArtifactPathCache.set(name, result);
487
- return result;
488
- }
489
-
490
- private _createBuildInfo(
491
- id: string,
492
- solcVersion: string,
493
- solcLongVersion: string,
494
- input: CompilerInput,
495
- output: CompilerOutput
496
- ): BuildInfo {
497
- return {
498
- id,
499
- _format: BUILD_INFO_FORMAT_VERSION,
500
- solcVersion,
501
- solcLongVersion,
502
- input,
503
- output,
504
- };
505
- }
506
-
507
- private _createDebugFile(artifactPath: string, pathToBuildInfo: string) {
508
- const relativePathToBuildInfo = path.relative(
509
- path.dirname(artifactPath),
510
- pathToBuildInfo
511
- );
512
-
513
- const debugFile: DebugFile = {
514
- _format: DEBUG_FILE_FORMAT_VERSION,
515
- buildInfo: relativePathToBuildInfo,
516
- };
517
-
518
- return debugFile;
519
- }
520
-
521
- private _getArtifactPathsSync(): string[] {
522
- const cached = this._cache?.artifactPaths;
523
- if (cached !== undefined) {
524
- return cached;
525
- }
526
-
527
- const buildInfosDir = path.join(this._artifactsPath, BUILD_INFO_DIR_NAME);
528
-
529
- const paths = getAllFilesMatchingSync(
530
- this._artifactsPath,
531
- (f) =>
532
- f.endsWith(".json") &&
533
- !f.startsWith(buildInfosDir) &&
534
- !f.endsWith(".dbg.json")
535
- );
536
-
537
- const result = paths.sort();
538
-
539
- if (this._cache !== undefined) {
540
- this._cache.artifactPaths = result;
541
- }
542
-
543
- return result;
544
- }
545
-
546
- /**
547
- * Sync version of _getArtifactPath
548
- */
549
- private _getArtifactPathSync(name: string): string {
550
- const cached = this._cache?.artifactNameToArtifactPathCache.get(name);
551
- if (cached !== undefined) {
552
- return cached;
553
- }
554
-
555
- let result: string;
556
-
557
- if (isFullyQualifiedName(name)) {
558
- result = this._getValidArtifactPathFromFullyQualifiedNameSync(name);
559
- } else {
560
- const files = this._getArtifactPathsSync();
561
- result = this._getArtifactPathFromFiles(name, files);
562
- }
563
-
564
- this._cache?.artifactNameToArtifactPathCache.set(name, result);
565
- return result;
566
- }
567
-
568
- /**
569
- * DO NOT DELETE OR CHANGE
570
- *
571
- * use this.formArtifactPathFromFullyQualifiedName instead
572
- * @deprecated until typechain migrates to public version
573
- * @see https://github.com/dethcrypto/TypeChain/issues/544
574
- */
575
- private _getArtifactPathFromFullyQualifiedName(
576
- fullyQualifiedName: string
577
- ): string {
578
- const { sourceName, contractName } =
579
- parseFullyQualifiedName(fullyQualifiedName);
580
-
581
- return path.join(this._artifactsPath, sourceName, `${contractName}.json`);
582
- }
583
-
584
- private async _getValidArtifactPathFromFullyQualifiedName(
585
- fullyQualifiedName: string
586
- ): Promise<string> {
587
- const artifactPath =
588
- this.formArtifactPathFromFullyQualifiedName(fullyQualifiedName);
589
-
590
- try {
591
- const trueCasePath = path.join(
592
- this._artifactsPath,
593
- await getFileTrueCase(
594
- this._artifactsPath,
595
- path.relative(this._artifactsPath, artifactPath)
596
- )
597
- );
598
-
599
- if (artifactPath !== trueCasePath) {
600
- throw new HardhatError(ERRORS.ARTIFACTS.WRONG_CASING, {
601
- correct: this._getFullyQualifiedNameFromPath(trueCasePath),
602
- incorrect: fullyQualifiedName,
603
- });
604
- }
605
-
606
- return trueCasePath;
607
- } catch (e) {
608
- if (e instanceof FileNotFoundError) {
609
- return this._handleWrongArtifactForFullyQualifiedName(
610
- fullyQualifiedName
611
- );
612
- }
613
-
614
- // eslint-disable-next-line @nomiclabs/hardhat-internal-rules/only-hardhat-error
615
- throw e;
616
- }
617
- }
618
-
619
- private _getAllContractNamesFromFiles(files: string[]): string[] {
620
- return files.map((file) => {
621
- const fqn = this._getFullyQualifiedNameFromPath(file);
622
- return parseFullyQualifiedName(fqn).contractName;
623
- });
624
- }
625
-
626
- private _getAllFullyQualifiedNamesSync(): string[] {
627
- const paths = this._getArtifactPathsSync();
628
- return paths.map((p) => this._getFullyQualifiedNameFromPath(p)).sort();
629
- }
630
-
631
- private _formatSuggestions(names: string[], contractName: string): string {
632
- switch (names.length) {
633
- case 0:
634
- return "";
635
- case 1:
636
- return `Did you mean "${names[0]}"?`;
637
- default:
638
- return `We found some that were similar:
639
-
640
- ${names.map((n) => ` * ${n}`).join(os.EOL)}
641
-
642
- Please replace "${contractName}" for the correct contract name wherever you are trying to read its artifact.
643
- `;
644
- }
645
- }
646
-
647
- private _handleWrongArtifactForFullyQualifiedName(
648
- fullyQualifiedName: string
649
- ): never {
650
- const names = this._getAllFullyQualifiedNamesSync();
651
-
652
- const similarNames = this._getSimilarContractNames(
653
- fullyQualifiedName,
654
- names
655
- );
656
-
657
- throw new HardhatError(ERRORS.ARTIFACTS.NOT_FOUND, {
658
- contractName: fullyQualifiedName,
659
- suggestion: this._formatSuggestions(similarNames, fullyQualifiedName),
660
- });
661
- }
662
-
663
- private _handleWrongArtifactForContractName(
664
- contractName: string,
665
- files: string[]
666
- ): never {
667
- const names = this._getAllContractNamesFromFiles(files);
668
-
669
- let similarNames = this._getSimilarContractNames(contractName, names);
670
-
671
- if (similarNames.length > 1) {
672
- similarNames = this._filterDuplicatesAsFullyQualifiedNames(
673
- files,
674
- similarNames
675
- );
676
- }
677
-
678
- throw new HardhatError(ERRORS.ARTIFACTS.NOT_FOUND, {
679
- contractName,
680
- suggestion: this._formatSuggestions(similarNames, contractName),
681
- });
682
- }
683
-
684
- /**
685
- * If the project has these contracts:
686
- * - 'contracts/Greeter.sol:Greeter'
687
- * - 'contracts/Meeter.sol:Greeter'
688
- * - 'contracts/Greater.sol:Greater'
689
- * And the user tries to get an artifact with the name 'Greter', then
690
- * the suggestions will be 'Greeter', 'Greeter', and 'Greater'.
691
- *
692
- * We don't want to show duplicates here, so we use FQNs for those. The
693
- * suggestions will then be:
694
- * - 'contracts/Greeter.sol:Greeter'
695
- * - 'contracts/Meeter.sol:Greeter'
696
- * - 'Greater'
697
- */
698
- private _filterDuplicatesAsFullyQualifiedNames(
699
- files: string[],
700
- similarNames: string[]
701
- ): string[] {
702
- const outputNames = [];
703
- const groups = similarNames.reduce((obj, cur) => {
704
- // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
705
- obj[cur] = obj[cur] ? obj[cur] + 1 : 1;
706
- return obj;
707
- }, {} as { [k: string]: number });
708
-
709
- for (const [name, occurrences] of Object.entries(groups)) {
710
- if (occurrences > 1) {
711
- for (const file of files) {
712
- if (path.basename(file) === `${name}.json`) {
713
- outputNames.push(this._getFullyQualifiedNameFromPath(file));
714
- }
715
- }
716
- continue;
717
- }
718
-
719
- outputNames.push(name);
720
- }
721
-
722
- return outputNames;
723
- }
724
-
725
- /**
726
- *
727
- * @param givenName can be FQN or contract name
728
- * @param names MUST match type of givenName (i.e. array of FQN's if givenName is FQN)
729
- * @returns
730
- */
731
- private _getSimilarContractNames(
732
- givenName: string,
733
- names: string[]
734
- ): string[] {
735
- let shortestDistance = EDIT_DISTANCE_THRESHOLD;
736
- let mostSimilarNames: string[] = [];
737
- for (const name of names) {
738
- const distance = findDistance(givenName, name);
739
-
740
- if (distance < shortestDistance) {
741
- shortestDistance = distance;
742
- mostSimilarNames = [name];
743
- continue;
744
- }
745
-
746
- if (distance === shortestDistance) {
747
- mostSimilarNames.push(name);
748
- continue;
749
- }
750
- }
751
-
752
- return mostSimilarNames;
753
- }
754
-
755
- private _getValidArtifactPathFromFullyQualifiedNameSync(
756
- fullyQualifiedName: string
757
- ): string {
758
- const artifactPath =
759
- this.formArtifactPathFromFullyQualifiedName(fullyQualifiedName);
760
-
761
- try {
762
- const trueCasePath = path.join(
763
- this._artifactsPath,
764
- getFileTrueCaseSync(
765
- this._artifactsPath,
766
- path.relative(this._artifactsPath, artifactPath)
767
- )
768
- );
769
-
770
- if (artifactPath !== trueCasePath) {
771
- throw new HardhatError(ERRORS.ARTIFACTS.WRONG_CASING, {
772
- correct: this._getFullyQualifiedNameFromPath(trueCasePath),
773
- incorrect: fullyQualifiedName,
774
- });
775
- }
776
-
777
- return trueCasePath;
778
- } catch (e) {
779
- if (e instanceof FileNotFoundError) {
780
- return this._handleWrongArtifactForFullyQualifiedName(
781
- fullyQualifiedName
782
- );
783
- }
784
-
785
- // eslint-disable-next-line @nomiclabs/hardhat-internal-rules/only-hardhat-error
786
- throw e;
787
- }
788
- }
789
-
790
- private _getDebugFilePath(artifactPath: string): string {
791
- return artifactPath.replace(/\.json$/, ".dbg.json");
792
- }
793
-
794
- private _getArtifactPathFromFiles(
795
- contractName: string,
796
- files: string[]
797
- ): string {
798
- const matchingFiles = files.filter((file) => {
799
- return path.basename(file) === `${contractName}.json`;
800
- });
801
-
802
- if (matchingFiles.length === 0) {
803
- return this._handleWrongArtifactForContractName(contractName, files);
804
- }
805
-
806
- if (matchingFiles.length > 1) {
807
- const candidates = matchingFiles.map((file) =>
808
- this._getFullyQualifiedNameFromPath(file)
809
- );
810
-
811
- throw new HardhatError(ERRORS.ARTIFACTS.MULTIPLE_FOUND, {
812
- contractName,
813
- candidates: candidates.join(os.EOL),
814
- });
815
- }
816
-
817
- return matchingFiles[0];
818
- }
819
-
820
- /**
821
- * Returns the FQN of a contract giving the absolute path to its artifact.
822
- *
823
- * For example, given a path like
824
- * `/path/to/project/artifacts/contracts/Foo.sol/Bar.json`, it'll return the
825
- * FQN `contracts/Foo.sol:Bar`
826
- */
827
- private _getFullyQualifiedNameFromPath(absolutePath: string): string {
828
- const sourceName = replaceBackslashes(
829
- path.relative(this._artifactsPath, path.dirname(absolutePath))
830
- );
831
-
832
- const contractName = path.basename(absolutePath).replace(".json", "");
833
-
834
- return getFullyQualifiedName(sourceName, contractName);
835
- }
836
-
837
- /**
838
- * Remove the artifact file, its debug file and, if it exists, its build
839
- * info file.
840
- */
841
- private async _removeArtifactFiles(artifactPath: string) {
842
- await fsExtra.remove(artifactPath);
843
-
844
- const debugFilePath = this._getDebugFilePath(artifactPath);
845
- const buildInfoPath = await this._getBuildInfoFromDebugFile(debugFilePath);
846
-
847
- await fsExtra.remove(debugFilePath);
848
-
849
- if (buildInfoPath !== undefined) {
850
- await fsExtra.remove(buildInfoPath);
851
- }
852
- }
853
-
854
- /**
855
- * Given the path to a debug file, returns the absolute path to its
856
- * corresponding build info file if it exists, or undefined otherwise.
857
- */
858
- private async _getBuildInfoFromDebugFile(
859
- debugFilePath: string
860
- ): Promise<string | undefined> {
861
- if (await fsExtra.pathExists(debugFilePath)) {
862
- const { buildInfo } = await fsExtra.readJson(debugFilePath);
863
- return path.resolve(path.dirname(debugFilePath), buildInfo);
864
- }
865
-
866
- return undefined;
867
- }
868
- }
869
-
870
- /**
871
- * Retrieves an artifact for the given `contractName` from the compilation output.
872
- *
873
- * @param sourceName The contract's source name.
874
- * @param contractName the contract's name.
875
- * @param contractOutput the contract's compilation output as emitted by `solc`.
876
- */
877
- export function getArtifactFromContractOutput(
878
- sourceName: string,
879
- contractName: string,
880
- contractOutput: any
881
- ): Artifact {
882
- const evmBytecode = contractOutput.evm && contractOutput.evm.bytecode;
883
- let bytecode: string =
884
- evmBytecode && evmBytecode.object ? evmBytecode.object : "";
885
-
886
- if (bytecode.slice(0, 2).toLowerCase() !== "0x") {
887
- bytecode = `0x${bytecode}`;
888
- }
889
-
890
- const evmDeployedBytecode =
891
- contractOutput.evm && contractOutput.evm.deployedBytecode;
892
- let deployedBytecode: string =
893
- evmDeployedBytecode && evmDeployedBytecode.object
894
- ? evmDeployedBytecode.object
895
- : "";
896
-
897
- if (deployedBytecode.slice(0, 2).toLowerCase() !== "0x") {
898
- deployedBytecode = `0x${deployedBytecode}`;
899
- }
900
-
901
- const linkReferences =
902
- evmBytecode && evmBytecode.linkReferences ? evmBytecode.linkReferences : {};
903
- const deployedLinkReferences =
904
- evmDeployedBytecode && evmDeployedBytecode.linkReferences
905
- ? evmDeployedBytecode.linkReferences
906
- : {};
907
-
908
- return {
909
- _format: ARTIFACT_FORMAT_VERSION,
910
- contractName,
911
- sourceName,
912
- abi: contractOutput.abi,
913
- bytecode,
914
- deployedBytecode,
915
- linkReferences,
916
- deployedLinkReferences,
917
- };
918
- }