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