hardhat 3.9.0 → 3.9.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 (161) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/src/config.d.ts.map +1 -1
  3. package/dist/src/config.js +6 -5
  4. package/dist/src/config.js.map +1 -1
  5. package/dist/src/hhu.d.ts +3 -0
  6. package/dist/src/hhu.d.ts.map +1 -0
  7. package/dist/src/hhu.js +14 -0
  8. package/dist/src/hhu.js.map +1 -0
  9. package/dist/src/internal/builtin-plugins/artifacts/hook-handlers/hre.d.ts.map +1 -1
  10. package/dist/src/internal/builtin-plugins/artifacts/hook-handlers/hre.js +4 -1
  11. package/dist/src/internal/builtin-plugins/artifacts/hook-handlers/hre.js.map +1 -1
  12. package/dist/src/internal/builtin-plugins/gas-analytics/function-gas-snapshots.d.ts +2 -2
  13. package/dist/src/internal/builtin-plugins/gas-analytics/function-gas-snapshots.d.ts.map +1 -1
  14. package/dist/src/internal/builtin-plugins/gas-analytics/function-gas-snapshots.js +21 -23
  15. package/dist/src/internal/builtin-plugins/gas-analytics/function-gas-snapshots.js.map +1 -1
  16. package/dist/src/internal/builtin-plugins/gas-analytics/snapshot-cheatcodes.d.ts +2 -2
  17. package/dist/src/internal/builtin-plugins/gas-analytics/snapshot-cheatcodes.d.ts.map +1 -1
  18. package/dist/src/internal/builtin-plugins/gas-analytics/snapshot-cheatcodes.js +21 -27
  19. package/dist/src/internal/builtin-plugins/gas-analytics/snapshot-cheatcodes.js.map +1 -1
  20. package/dist/src/internal/builtin-plugins/gas-analytics/tasks/solidity-test/task-action.d.ts +3 -1
  21. package/dist/src/internal/builtin-plugins/gas-analytics/tasks/solidity-test/task-action.d.ts.map +1 -1
  22. package/dist/src/internal/builtin-plugins/gas-analytics/tasks/solidity-test/task-action.js +18 -10
  23. package/dist/src/internal/builtin-plugins/gas-analytics/tasks/solidity-test/task-action.js.map +1 -1
  24. package/dist/src/internal/builtin-plugins/hhu/index.d.ts +4 -0
  25. package/dist/src/internal/builtin-plugins/hhu/index.d.ts.map +1 -0
  26. package/dist/src/internal/builtin-plugins/hhu/index.js +9 -0
  27. package/dist/src/internal/builtin-plugins/hhu/index.js.map +1 -0
  28. package/dist/src/internal/builtin-plugins/hhu/tasks/constants/index.d.ts +3 -0
  29. package/dist/src/internal/builtin-plugins/hhu/tasks/constants/index.d.ts.map +1 -0
  30. package/dist/src/internal/builtin-plugins/hhu/tasks/constants/index.js +8 -0
  31. package/dist/src/internal/builtin-plugins/hhu/tasks/constants/index.js.map +1 -0
  32. package/dist/src/internal/builtin-plugins/hhu/tasks/constants/zero-address.d.ts +4 -0
  33. package/dist/src/internal/builtin-plugins/hhu/tasks/constants/zero-address.d.ts.map +1 -0
  34. package/dist/src/internal/builtin-plugins/hhu/tasks/constants/zero-address.js +6 -0
  35. package/dist/src/internal/builtin-plugins/hhu/tasks/constants/zero-address.js.map +1 -0
  36. package/dist/src/internal/builtin-plugins/hhu/tasks/convert/index.d.ts +3 -0
  37. package/dist/src/internal/builtin-plugins/hhu/tasks/convert/index.d.ts.map +1 -0
  38. package/dist/src/internal/builtin-plugins/hhu/tasks/convert/index.js +27 -0
  39. package/dist/src/internal/builtin-plugins/hhu/tasks/convert/index.js.map +1 -0
  40. package/dist/src/internal/builtin-plugins/hhu/tasks/convert/pad.d.ts +10 -0
  41. package/dist/src/internal/builtin-plugins/hhu/tasks/convert/pad.d.ts.map +1 -0
  42. package/dist/src/internal/builtin-plugins/hhu/tasks/convert/pad.js +31 -0
  43. package/dist/src/internal/builtin-plugins/hhu/tasks/convert/pad.js.map +1 -0
  44. package/dist/src/internal/builtin-plugins/hhu/tasks/fetch/block-number.d.ts +4 -0
  45. package/dist/src/internal/builtin-plugins/hhu/tasks/fetch/block-number.d.ts.map +1 -0
  46. package/dist/src/internal/builtin-plugins/hhu/tasks/fetch/block-number.js +17 -0
  47. package/dist/src/internal/builtin-plugins/hhu/tasks/fetch/block-number.js.map +1 -0
  48. package/dist/src/internal/builtin-plugins/hhu/tasks/fetch/index.d.ts +3 -0
  49. package/dist/src/internal/builtin-plugins/hhu/tasks/fetch/index.d.ts.map +1 -0
  50. package/dist/src/internal/builtin-plugins/hhu/tasks/fetch/index.js +8 -0
  51. package/dist/src/internal/builtin-plugins/hhu/tasks/fetch/index.js.map +1 -0
  52. package/dist/src/internal/builtin-plugins/hhu/tasks/index.d.ts +11 -0
  53. package/dist/src/internal/builtin-plugins/hhu/tasks/index.d.ts.map +1 -0
  54. package/dist/src/internal/builtin-plugins/hhu/tasks/index.js +20 -0
  55. package/dist/src/internal/builtin-plugins/hhu/tasks/index.js.map +1 -0
  56. package/dist/src/internal/builtin-plugins/hhu/tasks/utils-task.d.ts +13 -0
  57. package/dist/src/internal/builtin-plugins/hhu/tasks/utils-task.d.ts.map +1 -0
  58. package/dist/src/internal/builtin-plugins/hhu/tasks/utils-task.js +17 -0
  59. package/dist/src/internal/builtin-plugins/hhu/tasks/utils-task.js.map +1 -0
  60. package/dist/src/internal/builtin-plugins/hhu/types.d.ts +45 -0
  61. package/dist/src/internal/builtin-plugins/hhu/types.d.ts.map +1 -0
  62. package/dist/src/internal/builtin-plugins/hhu/types.js +2 -0
  63. package/dist/src/internal/builtin-plugins/hhu/types.js.map +1 -0
  64. package/dist/src/internal/builtin-plugins/index.d.ts.map +1 -1
  65. package/dist/src/internal/builtin-plugins/index.js +5 -0
  66. package/dist/src/internal/builtin-plugins/index.js.map +1 -1
  67. package/dist/src/internal/builtin-plugins/network-manager/edr/stack-traces/stack-trace-solidity-errors.d.ts +1 -0
  68. package/dist/src/internal/builtin-plugins/network-manager/edr/stack-traces/stack-trace-solidity-errors.d.ts.map +1 -1
  69. package/dist/src/internal/builtin-plugins/network-manager/edr/stack-traces/stack-trace-solidity-errors.js +17 -0
  70. package/dist/src/internal/builtin-plugins/network-manager/edr/stack-traces/stack-trace-solidity-errors.js.map +1 -1
  71. package/dist/src/internal/builtin-plugins/network-manager/index.d.ts.map +1 -1
  72. package/dist/src/internal/builtin-plugins/network-manager/index.js +2 -10
  73. package/dist/src/internal/builtin-plugins/network-manager/index.js.map +1 -1
  74. package/dist/src/internal/builtin-plugins/network-manager/network-option.d.ts +9 -0
  75. package/dist/src/internal/builtin-plugins/network-manager/network-option.d.ts.map +1 -0
  76. package/dist/src/internal/builtin-plugins/network-manager/network-option.js +15 -0
  77. package/dist/src/internal/builtin-plugins/network-manager/network-option.js.map +1 -0
  78. package/dist/src/internal/builtin-plugins/network-manager/request-handlers/handlers/accounts/automatic-sender-handler.d.ts +4 -2
  79. package/dist/src/internal/builtin-plugins/network-manager/request-handlers/handlers/accounts/automatic-sender-handler.d.ts.map +1 -1
  80. package/dist/src/internal/builtin-plugins/network-manager/request-handlers/handlers/accounts/automatic-sender-handler.js +28 -6
  81. package/dist/src/internal/builtin-plugins/network-manager/request-handlers/handlers/accounts/automatic-sender-handler.js.map +1 -1
  82. package/dist/src/internal/builtin-plugins/solidity-test/config.d.ts.map +1 -1
  83. package/dist/src/internal/builtin-plugins/solidity-test/config.js +1 -4
  84. package/dist/src/internal/builtin-plugins/solidity-test/config.js.map +1 -1
  85. package/dist/src/internal/builtin-plugins/solidity-test/stack-trace-solidity-errors.d.ts.map +1 -1
  86. package/dist/src/internal/builtin-plugins/solidity-test/stack-trace-solidity-errors.js +3 -1
  87. package/dist/src/internal/builtin-plugins/solidity-test/stack-trace-solidity-errors.js.map +1 -1
  88. package/dist/src/internal/cli/help/get-global-help-string.d.ts +3 -1
  89. package/dist/src/internal/cli/help/get-global-help-string.d.ts.map +1 -1
  90. package/dist/src/internal/cli/help/get-global-help-string.js +3 -3
  91. package/dist/src/internal/cli/help/get-global-help-string.js.map +1 -1
  92. package/dist/src/internal/cli/help/get-help-string.d.ts +3 -1
  93. package/dist/src/internal/cli/help/get-help-string.d.ts.map +1 -1
  94. package/dist/src/internal/cli/help/get-help-string.js +4 -4
  95. package/dist/src/internal/cli/help/get-help-string.js.map +1 -1
  96. package/dist/src/internal/cli/help/utils.d.ts +3 -1
  97. package/dist/src/internal/cli/help/utils.d.ts.map +1 -1
  98. package/dist/src/internal/cli/help/utils.js +2 -2
  99. package/dist/src/internal/cli/help/utils.js.map +1 -1
  100. package/dist/src/internal/cli/hhu.d.ts +14 -0
  101. package/dist/src/internal/cli/hhu.d.ts.map +1 -0
  102. package/dist/src/internal/cli/hhu.js +184 -0
  103. package/dist/src/internal/cli/hhu.js.map +1 -0
  104. package/dist/src/internal/cli/main.d.ts +0 -25
  105. package/dist/src/internal/cli/main.d.ts.map +1 -1
  106. package/dist/src/internal/cli/main.js +23 -303
  107. package/dist/src/internal/cli/main.js.map +1 -1
  108. package/dist/src/internal/cli/parser.d.ts +25 -0
  109. package/dist/src/internal/cli/parser.d.ts.map +1 -0
  110. package/dist/src/internal/cli/parser.js +282 -0
  111. package/dist/src/internal/cli/parser.js.map +1 -0
  112. package/dist/src/internal/cli/telemetry/analytics/analytics.d.ts +1 -1
  113. package/dist/src/internal/cli/telemetry/analytics/analytics.d.ts.map +1 -1
  114. package/dist/src/internal/cli/telemetry/analytics/analytics.js +2 -1
  115. package/dist/src/internal/cli/telemetry/analytics/analytics.js.map +1 -1
  116. package/dist/src/internal/cli/telemetry/analytics/types.d.ts +1 -0
  117. package/dist/src/internal/cli/telemetry/analytics/types.d.ts.map +1 -1
  118. package/dist/src/internal/using-hardhat2-plugin-errors.d.ts +2 -2
  119. package/dist/src/internal/using-hardhat2-plugin-errors.d.ts.map +1 -1
  120. package/dist/src/internal/using-hardhat2-plugin-errors.js +7 -3
  121. package/dist/src/internal/using-hardhat2-plugin-errors.js.map +1 -1
  122. package/dist/src/plugins.d.ts.map +1 -1
  123. package/dist/src/plugins.js +3 -2
  124. package/dist/src/plugins.js.map +1 -1
  125. package/package.json +4 -4
  126. package/src/config.ts +17 -5
  127. package/src/hhu.ts +18 -0
  128. package/src/internal/builtin-plugins/artifacts/hook-handlers/hre.ts +11 -3
  129. package/src/internal/builtin-plugins/gas-analytics/function-gas-snapshots.ts +32 -32
  130. package/src/internal/builtin-plugins/gas-analytics/snapshot-cheatcodes.ts +32 -36
  131. package/src/internal/builtin-plugins/gas-analytics/tasks/solidity-test/task-action.ts +22 -9
  132. package/src/internal/builtin-plugins/hhu/index.ts +13 -0
  133. package/src/internal/builtin-plugins/hhu/tasks/constants/index.ts +18 -0
  134. package/src/internal/builtin-plugins/hhu/tasks/constants/zero-address.ts +9 -0
  135. package/src/internal/builtin-plugins/hhu/tasks/convert/index.ts +40 -0
  136. package/src/internal/builtin-plugins/hhu/tasks/convert/pad.ts +61 -0
  137. package/src/internal/builtin-plugins/hhu/tasks/fetch/block-number.ts +28 -0
  138. package/src/internal/builtin-plugins/hhu/tasks/fetch/index.ts +18 -0
  139. package/src/internal/builtin-plugins/hhu/tasks/index.ts +36 -0
  140. package/src/internal/builtin-plugins/hhu/tasks/utils-task.ts +29 -0
  141. package/src/internal/builtin-plugins/hhu/types.ts +57 -0
  142. package/src/internal/builtin-plugins/index.ts +6 -0
  143. package/src/internal/builtin-plugins/network-manager/edr/stack-traces/stack-trace-solidity-errors.ts +33 -0
  144. package/src/internal/builtin-plugins/network-manager/index.ts +3 -10
  145. package/src/internal/builtin-plugins/network-manager/network-option.ts +17 -0
  146. package/src/internal/builtin-plugins/network-manager/request-handlers/handlers/accounts/automatic-sender-handler.ts +39 -9
  147. package/src/internal/builtin-plugins/solidity-test/config.ts +1 -4
  148. package/src/internal/builtin-plugins/solidity-test/stack-trace-solidity-errors.ts +6 -1
  149. package/src/internal/cli/help/get-global-help-string.ts +3 -2
  150. package/src/internal/cli/help/get-help-string.ts +4 -3
  151. package/src/internal/cli/help/utils.ts +2 -1
  152. package/src/internal/cli/hhu.ts +298 -0
  153. package/src/internal/cli/main.ts +41 -495
  154. package/src/internal/cli/parser.ts +472 -0
  155. package/src/internal/cli/telemetry/analytics/analytics.ts +5 -1
  156. package/src/internal/cli/telemetry/analytics/types.ts +3 -0
  157. package/src/internal/using-hardhat2-plugin-errors.ts +12 -3
  158. package/src/plugins.ts +5 -2
  159. package/templates/hardhat-3/01-node-test-runner-viem/package.json +6 -6
  160. package/templates/hardhat-3/02-mocha-ethers/package.json +9 -9
  161. package/templates/hardhat-3/03-minimal/package.json +1 -1
@@ -6,6 +6,10 @@ import console from "./console/index.js";
6
6
  import coverage from "./coverage/index.js";
7
7
  import flatten from "./flatten/index.js";
8
8
  import gasAnalytics from "./gas-analytics/index.js";
9
+ // The hhu / `utils` feature is unreleased and intentionally not wired up yet.
10
+ // To enable it, uncomment the three `hhu` lines (this import, the type re-export
11
+ // below, and the `builtinPlugins` entry) and re-add `bin.hhu` in package.json.
12
+ // import hhu from "./hhu/index.js";
9
13
  import networkManager from "./network-manager/index.js";
10
14
  import node from "./node/index.js";
11
15
  import run from "./run/index.js";
@@ -22,6 +26,7 @@ export type * from "./console/index.js";
22
26
  export type * from "./coverage/index.js";
23
27
  export type * from "./flatten/index.js";
24
28
  export type * from "./gas-analytics/index.js";
29
+ // export type * from "./hhu/index.js";
25
30
  export type * from "./network-manager/index.js";
26
31
  export type * from "./node/index.js";
27
32
  export type * from "./run/index.js";
@@ -46,4 +51,5 @@ export const builtinPlugins: HardhatPlugin[] = [
46
51
  node,
47
52
  flatten,
48
53
  telemetry,
54
+ // hhu,
49
55
  ];
@@ -21,6 +21,32 @@ import {
21
21
  UNRECOGNIZED_FUNCTION_NAME,
22
22
  } from "./solidity-stack-trace.js";
23
23
 
24
+ interface CheatcodeSuggestion {
25
+ message: string;
26
+ docsUrl?: string;
27
+ }
28
+
29
+ const CHEATCODE_SUGGESTIONS: Record<string, CheatcodeSuggestion> = {
30
+ "eip712HashType(string,string)": {
31
+ message:
32
+ "Providing a path to a bindings file is not supported, please use the eip712HashType(string calldata typeNameOrDefinition) cheatcode instead.",
33
+ docsUrl:
34
+ "https://hardhat.org/docs/reference/cheatcodes/utilities/eip712-hash-type",
35
+ },
36
+ };
37
+
38
+ export function getCheatcodeSuggestion(cheatcode: string): string {
39
+ const suggestion = CHEATCODE_SUGGESTIONS[cheatcode];
40
+
41
+ if (suggestion === undefined) {
42
+ return "";
43
+ }
44
+
45
+ return suggestion.docsUrl !== undefined
46
+ ? `${suggestion.message} See ${suggestion.docsUrl} for more information.`
47
+ : suggestion.message;
48
+ }
49
+
24
50
  export function createSolidityErrorWithStackTrace(
25
51
  fallbackMessage: string,
26
52
  stackTrace: SolidityStackTrace,
@@ -277,6 +303,13 @@ function getMessageFromLastStackTraceEntry(
277
303
  switch (stackTraceEntry.details.code) {
278
304
  case CheatcodeErrorCode.UnsupportedCheatcode:
279
305
  message = `Cheatcode '${stackTraceEntry.details.cheatcode}' is not supported by Hardhat.`;
306
+
307
+ const suggestion = getCheatcodeSuggestion(
308
+ stackTraceEntry.details.cheatcode,
309
+ );
310
+
311
+ message += suggestion.length > 0 ? " " + suggestion : "";
312
+
280
313
  break;
281
314
  case CheatcodeErrorCode.MissingCheatcode:
282
315
  message = `Cheatcode '${stackTraceEntry.details.cheatcode}' is not yet available in this version of Hardhat.`;
@@ -1,8 +1,8 @@
1
1
  import type { HardhatPlugin } from "../../../types/plugins.js";
2
2
 
3
3
  import { definePlugin } from "../../../plugins.js";
4
- import { ArgumentType } from "../../../types/arguments.js";
5
- import { globalOption } from "../../core/config.js";
4
+
5
+ import { NETWORK_GLOBAL_OPTION } from "./network-option.js";
6
6
 
7
7
  export type * from "./type-extensions/config.js";
8
8
  export type * from "./type-extensions/global-options.js";
@@ -16,14 +16,7 @@ const hardhatPlugin: HardhatPlugin = definePlugin({
16
16
  hre: () => import("./hook-handlers/hre.js"),
17
17
  network: () => import("./hook-handlers/network.js"),
18
18
  },
19
- globalOptions: [
20
- globalOption({
21
- name: "network",
22
- description: "The network to connect to",
23
- type: ArgumentType.STRING_WITHOUT_DEFAULT,
24
- defaultValue: undefined,
25
- }),
26
- ],
19
+ globalOptions: [NETWORK_GLOBAL_OPTION],
27
20
  npmPackage: "hardhat",
28
21
  dependencies: () => [import("../artifacts/index.js")],
29
22
  });
@@ -0,0 +1,17 @@
1
+ import type { GlobalOptionDefinition } from "../../../types/arguments.js";
2
+
3
+ import { ArgumentType } from "../../../types/arguments.js";
4
+ import { globalOption } from "../../core/config.js";
5
+
6
+ /**
7
+ * The `--network` global option, contributed by the network-manager plugin.
8
+ *
9
+ * Exported so the standalone hhu binary, which doesn't load the plugin, can
10
+ * reuse the exact same definition instead of duplicating it.
11
+ */
12
+ export const NETWORK_GLOBAL_OPTION: GlobalOptionDefinition = globalOption({
13
+ name: "network",
14
+ description: "The network to connect to",
15
+ type: ArgumentType.STRING_WITHOUT_DEFAULT,
16
+ defaultValue: undefined,
17
+ });
@@ -1,32 +1,62 @@
1
- import { assertHardhatInvariant } from "@nomicfoundation/hardhat-errors";
1
+ import type {
2
+ JsonRpcRequest,
3
+ JsonRpcResponse,
4
+ } from "../../../../../../types/providers.js";
5
+
6
+ import { isObject } from "@nomicfoundation/hardhat-utils/lang";
7
+
8
+ import { getRequestParams } from "../../../json-rpc.js";
9
+ import { InternalError } from "../../../provider-errors.js";
2
10
 
3
11
  import { SenderHandler } from "./sender.js";
4
12
 
5
13
  /**
6
14
  * This class automatically retrieves and caches the first available account from the connected provider.
7
- * It overrides the getSender method of the base class to request the list of accounts if the first account has not been fetched yet,
8
- * ensuring dynamic selection of the sender for all JSON-RPC requests without requiring manual input.
15
+ * On the first supported request, fetches and caches `eth_accounts` so callers don't need to set `from` manually.
16
+ * If `eth_accounts` responds with a non-array, it returns a JSON-RPC error.
9
17
  */
10
18
  export class AutomaticSenderHandler extends SenderHandler {
11
19
  #alreadyFetchedAccounts = false;
12
20
  #firstAccount: string | undefined;
13
21
 
14
- protected async getSender(): Promise<string | undefined> {
22
+ public override async handle(
23
+ jsonRpcRequest: JsonRpcRequest,
24
+ ): Promise<JsonRpcRequest | JsonRpcResponse> {
25
+ if (!this.isSupportedMethod(jsonRpcRequest)) {
26
+ return jsonRpcRequest;
27
+ }
28
+
29
+ const [tx] = getRequestParams(jsonRpcRequest);
30
+ if (!isObject(tx) || tx.from !== undefined) {
31
+ // Skip the eth_accounts fetch when we won't need a sender anyway:
32
+ // the tx isn't an object, or it already carries a `from`.
33
+ return await super.handle(jsonRpcRequest);
34
+ }
35
+
15
36
  if (this.#alreadyFetchedAccounts === false) {
16
37
  const accounts = await this.provider.request({
17
38
  method: "eth_accounts",
18
39
  });
19
40
 
20
- // TODO: This shouldn't be an exception but a failed JSON response!
21
- assertHardhatInvariant(
22
- Array.isArray(accounts),
23
- "eth_accounts response should be an array",
24
- );
41
+ if (!Array.isArray(accounts)) {
42
+ return {
43
+ jsonrpc: "2.0",
44
+ id: jsonRpcRequest.id,
45
+ error: {
46
+ code: InternalError.CODE,
47
+ message: "eth_accounts did not return an array of accounts",
48
+ },
49
+ };
50
+ }
25
51
 
26
52
  this.#firstAccount = accounts[0];
27
53
  this.#alreadyFetchedAccounts = true;
28
54
  }
29
55
 
56
+ return await super.handle(jsonRpcRequest);
57
+ }
58
+
59
+ protected async getSender(): Promise<string | undefined> {
30
60
  return this.#firstAccount;
31
61
  }
32
62
  }
@@ -55,10 +55,7 @@ const solidityTestProfileUserConfigType = z.object({
55
55
  prevRandao: z.bigint().optional(),
56
56
  gasLimit: z.bigint().optional(),
57
57
  blockGasLimit: z.number().or(z.bigint()).or(z.literal(false)).optional(),
58
- // TODO: widen back to .number().or(z.bigint()).or(z.literal(false))
59
- // once Solidity test runner no longer breaks setUp() when
60
- // disableTransactionGasCap is false. See PR #8301.
61
- transactionGasCap: z.literal(false).optional(),
58
+ transactionGasCap: z.number().or(z.bigint()).or(z.literal(false)).optional(),
62
59
  fuzz: z
63
60
  .object({
64
61
  failurePersistDir: z.string().optional(),
@@ -6,6 +6,7 @@ import {
6
6
  StackTraceEntryType,
7
7
  CheatcodeErrorCode,
8
8
  } from "../network-manager/edr/stack-traces/solidity-stack-trace.js";
9
+ import { getCheatcodeSuggestion } from "../network-manager/edr/stack-traces/stack-trace-solidity-errors.js";
9
10
 
10
11
  export function getMessageFromLastStackTraceEntry(
11
12
  stackTraceEntry: SolidityStackTraceEntry,
@@ -71,7 +72,11 @@ export function getMessageFromLastStackTraceEntry(
71
72
  if (stackTraceEntry.details !== undefined) {
72
73
  switch (stackTraceEntry.details.code) {
73
74
  case CheatcodeErrorCode.UnsupportedCheatcode:
74
- return `Cheatcode '${stackTraceEntry.details.cheatcode}' is not supported by Hardhat.`;
75
+ const suggestion = getCheatcodeSuggestion(
76
+ stackTraceEntry.details.cheatcode,
77
+ );
78
+
79
+ return `Cheatcode '${stackTraceEntry.details.cheatcode}' is not supported by Hardhat.${suggestion.length > 0 ? " " + suggestion : ""}`;
75
80
  case CheatcodeErrorCode.MissingCheatcode:
76
81
  return `Cheatcode '${stackTraceEntry.details.cheatcode}' is not yet available in this version of Hardhat.`;
77
82
  }
@@ -14,6 +14,7 @@ import {
14
14
  export async function getGlobalHelpString(
15
15
  rootTasks: Map<string, Task>,
16
16
  globalOptionDefinitions: GlobalOptionDefinitions,
17
+ { command = "hardhat" }: { command?: "hardhat" | "hhu" } = {},
17
18
  ): Promise<string> {
18
19
  const version = await getHardhatVersion();
19
20
 
@@ -27,7 +28,7 @@ export async function getGlobalHelpString(
27
28
 
28
29
  let output = `Hardhat version ${version}
29
30
 
30
- Usage: hardhat [GLOBAL OPTIONS] <TASK> [SUBTASK] [TASK OPTIONS] [--] [TASK ARGUMENTS]
31
+ Usage: ${command} [GLOBAL OPTIONS] <TASK> [SUBTASK] [TASK OPTIONS] [--] [TASK ARGUMENTS]
31
32
  `;
32
33
 
33
34
  if (tasks.length > 0) {
@@ -40,7 +41,7 @@ Usage: hardhat [GLOBAL OPTIONS] <TASK> [SUBTASK] [TASK OPTIONS] [--] [TASK ARGUM
40
41
 
41
42
  output += getSection("GLOBAL OPTIONS", globalOptions, namePadding);
42
43
 
43
- output += `\nTo get help for a specific task run: npx hardhat <TASK> [SUBTASK] --help`;
44
+ output += `\nTo get help for a specific task run: npx ${command} <TASK> [SUBTASK] --help`;
44
45
 
45
46
  return output;
46
47
  }
@@ -16,6 +16,7 @@ import {
16
16
  export async function getHelpString(
17
17
  task: Task,
18
18
  globalOptionDefinitions: GlobalOptionDefinitions,
19
+ { command = "hardhat" }: { command?: "hardhat" | "hhu" } = {},
19
20
  ): Promise<string> {
20
21
  const { options, positionalArguments } = parseOptions(task);
21
22
 
@@ -34,20 +35,20 @@ export async function getHelpString(
34
35
  let output = `${styleText("bold", task.description)}`;
35
36
 
36
37
  if (task.isEmpty) {
37
- output += `\n\nUsage: hardhat [GLOBAL OPTIONS] ${task.id.join(" ")} <SUBTASK> [SUBTASK OPTIONS] [--] [SUBTASK POSITIONAL ARGUMENTS]\n`;
38
+ output += `\n\nUsage: ${command} [GLOBAL OPTIONS] ${task.id.join(" ")} <SUBTASK> [SUBTASK OPTIONS] [--] [SUBTASK POSITIONAL ARGUMENTS]\n`;
38
39
 
39
40
  if (subtasks.length > 0) {
40
41
  output += getSection("AVAILABLE SUBTASKS", subtasks, namePadding);
41
42
 
42
43
  output += getSection("GLOBAL OPTIONS", globalOptions, namePadding);
43
44
 
44
- output += `\nTo get help for a specific task run: npx hardhat ${task.id.join(" ")} <SUBTASK> --help`;
45
+ output += `\nTo get help for a specific task run: npx ${command} ${task.id.join(" ")} <SUBTASK> --help`;
45
46
  }
46
47
 
47
48
  return output;
48
49
  }
49
50
 
50
- const usage = getUsageString(task, options, positionalArguments);
51
+ const usage = getUsageString(task, options, positionalArguments, { command });
51
52
 
52
53
  output += `\n\n${usage}\n`;
53
54
 
@@ -172,8 +172,9 @@ export function getUsageString(
172
172
  task: Task,
173
173
  options: ReturnType<typeof parseOptions>["options"],
174
174
  positionalArguments: ReturnType<typeof parseOptions>["positionalArguments"],
175
+ { command = "hardhat" }: { command?: "hardhat" | "hhu" } = {},
175
176
  ): string {
176
- let output = `Usage: hardhat [GLOBAL OPTIONS] ${task.id.join(" ")}`;
177
+ let output = `Usage: ${command} [GLOBAL OPTIONS] ${task.id.join(" ")}`;
177
178
 
178
179
  if (options.length > 0) {
179
180
  output += ` ${options
@@ -0,0 +1,298 @@
1
+ import type { GlobalOptionDefinitions } from "../../types/global-options.js";
2
+ import type { HardhatRuntimeEnvironment } from "../../types/hre.js";
3
+ import type { Task, TaskDefinition } from "../../types/tasks.js";
4
+ import type { FakeHhuHardhatRuntimeEnvironment } from "../builtin-plugins/hhu/types.js";
5
+
6
+ import {
7
+ assertHardhatInvariant,
8
+ HardhatError,
9
+ } from "@nomicfoundation/hardhat-errors";
10
+ import { isCi } from "@nomicfoundation/hardhat-utils/ci";
11
+ import { createDebug } from "@nomicfoundation/hardhat-utils/debug";
12
+ import { setGlobalOptionsAsEnvVariables } from "@nomicfoundation/hardhat-utils/env";
13
+ import { ensureError } from "@nomicfoundation/hardhat-utils/error";
14
+
15
+ import { isResult } from "../../utils/result.js";
16
+ import { generateTasks } from "../builtin-plugins/hhu/tasks/index.js";
17
+ import { NETWORK_GLOBAL_OPTION } from "../builtin-plugins/network-manager/network-option.js";
18
+ import { globalFlag } from "../core/config.js";
19
+ import { TaskManagerImplementation } from "../core/tasks/task-manager.js";
20
+ import { getHardhatVersion } from "../utils/package.js";
21
+
22
+ import { printErrorMessages } from "./error-handler.js";
23
+ import { getGlobalHelpString } from "./help/get-global-help-string.js";
24
+ import { getHelpString } from "./help/get-help-string.js";
25
+ import {
26
+ parseGlobalOptions,
27
+ parseRawArguments,
28
+ parseTask,
29
+ parseTaskArguments,
30
+ } from "./parser.js";
31
+ import { sendTaskAnalytics } from "./telemetry/analytics/analytics.js";
32
+ import { setupGlobalUnhandledErrorHandlers } from "./telemetry/error-reporter/global-error-handlers.js";
33
+ import { sendErrorTelemetry } from "./telemetry/error-reporter/reporter.js";
34
+
35
+ interface MainOptions {
36
+ print?: (message: string) => void;
37
+ rethrowErrors?: true;
38
+ }
39
+
40
+ export async function main(
41
+ rawArguments: string[],
42
+ options: MainOptions = {},
43
+ ): Promise<void> {
44
+ // We set up the global unhandled errors before running any functionality
45
+ setupGlobalUnhandledErrorHandlers();
46
+
47
+ const print = options.print ?? console.log;
48
+
49
+ const log = createDebug("hardhat:core:hhu:main");
50
+
51
+ let hhuGlobalOptions;
52
+
53
+ log("hhu started");
54
+
55
+ try {
56
+ const cliArguments = parseRawArguments(rawArguments);
57
+
58
+ const usedCliArguments: boolean[] = new Array(cliArguments.length).fill(
59
+ false,
60
+ );
61
+
62
+ hhuGlobalOptions = await parseHhuGlobalOptions(
63
+ cliArguments,
64
+ usedCliArguments,
65
+ );
66
+
67
+ // We forward `network` as an env variable so it's available when we lazily
68
+ // import the real HRE in utils that need it. We explicitly whitelist it
69
+ // (rather than forwarding every hhu global option) so that hhu-only options
70
+ // never leak into the real HRE's global-option namespace.
71
+ setGlobalOptionsAsEnvVariables({ network: hhuGlobalOptions.network });
72
+
73
+ log("Parsed hhu global options");
74
+
75
+ if (hhuGlobalOptions.version) {
76
+ return await printHhuVersionMessage(print);
77
+ }
78
+
79
+ const globalOptionDefinitions: GlobalOptionDefinitions = new Map(
80
+ HHU_GLOBAL_OPTIONS_DEFINITIONS,
81
+ );
82
+
83
+ const rootTasks = taskDefinitionsToTasksMap(
84
+ generateTasks({ prefixWithUtils: false }),
85
+ );
86
+
87
+ const taskOrId = parseTask(cliArguments, usedCliArguments, rootTasks);
88
+
89
+ if (Array.isArray(taskOrId)) {
90
+ if (taskOrId.length === 0) {
91
+ const globalHelp = await getGlobalHelpString(
92
+ rootTasks,
93
+ globalOptionDefinitions,
94
+ { command: "hhu" },
95
+ );
96
+
97
+ print(globalHelp);
98
+ return;
99
+ }
100
+
101
+ throw new HardhatError(
102
+ HardhatError.ERRORS.CORE.TASK_DEFINITIONS.TASK_NOT_FOUND,
103
+ { task: taskOrId.join(" ") },
104
+ );
105
+ }
106
+
107
+ const task = taskOrId;
108
+
109
+ if (task.isEmpty && usedCliArguments.includes(false)) {
110
+ const invalidSubtask = cliArguments[usedCliArguments.indexOf(false)];
111
+
112
+ throw new HardhatError(
113
+ HardhatError.ERRORS.CORE.TASK_DEFINITIONS.UNRECOGNIZED_SUBTASK,
114
+ {
115
+ task: task.id.join(" "),
116
+ invalidSubtask,
117
+ },
118
+ );
119
+ }
120
+
121
+ if (hhuGlobalOptions.help || task.isEmpty) {
122
+ const taskHelp = await getHelpString(task, globalOptionDefinitions, {
123
+ command: "hhu",
124
+ });
125
+
126
+ print(taskHelp);
127
+ return;
128
+ }
129
+
130
+ const taskArguments = parseTaskArguments(
131
+ cliArguments,
132
+ usedCliArguments,
133
+ task,
134
+ );
135
+
136
+ log(`Running task "${task.id.join(" ")}"`);
137
+
138
+ const [taskResult] = await Promise.all([
139
+ task.run(taskArguments),
140
+ sendTaskAnalytics(task.id, "hhu"),
141
+ ]);
142
+
143
+ if (isResult(taskResult) && !taskResult.success) {
144
+ process.exitCode = 1;
145
+ }
146
+ } catch (error) {
147
+ ensureError(error);
148
+ await printErrorMessages(error, hhuGlobalOptions?.showStackTraces);
149
+
150
+ try {
151
+ await sendErrorTelemetry(error);
152
+ } catch (e) {
153
+ log("Couldn't report error to sentry: %O", e);
154
+ }
155
+
156
+ if (options.rethrowErrors) {
157
+ throw error;
158
+ }
159
+
160
+ process.exitCode = 1;
161
+ }
162
+ }
163
+
164
+ const HHU_GLOBAL_OPTIONS_DEFINITIONS: GlobalOptionDefinitions = new Map([
165
+ [
166
+ "help",
167
+ {
168
+ pluginId: "builtin",
169
+ option: globalFlag({
170
+ name: "help",
171
+ shortName: "h",
172
+ description:
173
+ "Show this message, or a task's help if its name is provided.",
174
+ }),
175
+ },
176
+ ],
177
+ [
178
+ "showStackTraces",
179
+ {
180
+ pluginId: "builtin",
181
+ option: globalFlag({
182
+ name: "showStackTraces",
183
+ description: "Show stack traces (always enabled on CI servers).",
184
+ }),
185
+ },
186
+ ],
187
+ [
188
+ "version",
189
+ {
190
+ pluginId: "builtin",
191
+ option: globalFlag({
192
+ name: "version",
193
+ description: "Show the version of hhu.",
194
+ }),
195
+ },
196
+ ],
197
+ [
198
+ "network",
199
+ {
200
+ pluginId: "builtin",
201
+ option: NETWORK_GLOBAL_OPTION,
202
+ },
203
+ ],
204
+ ]);
205
+
206
+ export async function parseHhuGlobalOptions(
207
+ cliArguments: string[],
208
+ usedCliArguments: boolean[],
209
+ ): Promise<{
210
+ help: boolean;
211
+ showStackTraces: boolean;
212
+ version: boolean;
213
+ network: string | undefined;
214
+ }> {
215
+ const hhuGlobalOptions = await parseGlobalOptions(
216
+ HHU_GLOBAL_OPTIONS_DEFINITIONS,
217
+ cliArguments,
218
+ usedCliArguments,
219
+ );
220
+
221
+ return {
222
+ help: hhuGlobalOptions.help ?? false,
223
+ showStackTraces: hhuGlobalOptions.showStackTraces ?? isCi(),
224
+ version: hhuGlobalOptions.version ?? false,
225
+ network: hhuGlobalOptions.network,
226
+ };
227
+ }
228
+
229
+ export async function printHhuVersionMessage(
230
+ print: (message: string) => void = console.log,
231
+ ): Promise<void> {
232
+ print(await getHardhatVersion());
233
+ }
234
+
235
+ function makeStrictProxy<T extends object>(
236
+ name: string,
237
+ object: Partial<T>,
238
+ ): T {
239
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- inaccessible properties will throw an assertion error
240
+ return new Proxy(object as T, {
241
+ get(target, property) {
242
+ assertHardhatInvariant(
243
+ Object.hasOwn(object, property),
244
+ `Unexpected access of property "${String(property)}" in ${name}.`,
245
+ );
246
+
247
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- we know this is safe because of the assertion above
248
+ return target[property as keyof T];
249
+ },
250
+ });
251
+ }
252
+
253
+ function taskDefinitionsToTasksMap(tasks: TaskDefinition[]): Map<string, Task> {
254
+ // To be able to parse the hhu arguments, we need to create a tasks map from
255
+ // the task definitions. The easiest way to do that is by using
256
+ // `TaskManagerImplementation`, but this needs an HRE and we don't want to
257
+ // create one just for this. So we use a fake HRE that has the minimum
258
+ // properties needed.
259
+ //
260
+ // The exception is `network.create`: utils that need a network get the real
261
+ // implementation, which lazily loads Hardhat (and thus creates the project's
262
+ // HRE) only when such a util actually runs.
263
+ //
264
+ // One downside of this approach is that we _won't_ get a compilation error
265
+ // if `TaskManagerImplementation` tries to access a property that doesn't exist in the
266
+ // fake HRE, but tests should catch that.
267
+ //
268
+ // The `satisfies FakeHhuHardhatRuntimeEnvironment` keeps this fake HRE in sync
269
+ // with the surface utils actions rely on.
270
+ const fakeHre = makeStrictProxy<HardhatRuntimeEnvironment>(
271
+ "hhu's proxied HRE",
272
+ {
273
+ config: makeStrictProxy<HardhatRuntimeEnvironment["config"]>(
274
+ "hhu's proxied config",
275
+ {
276
+ tasks,
277
+ plugins: [],
278
+ },
279
+ ),
280
+ network: makeStrictProxy<HardhatRuntimeEnvironment["network"]>(
281
+ "hhu's proxied network",
282
+ {
283
+ create: async (networkOrParams) => {
284
+ const hre = await import("../../index.js");
285
+ return await hre.network.create(networkOrParams);
286
+ },
287
+ },
288
+ ),
289
+ } satisfies FakeHhuHardhatRuntimeEnvironment,
290
+ );
291
+
292
+ const taskManager = new TaskManagerImplementation(
293
+ fakeHre,
294
+ new Map(HHU_GLOBAL_OPTIONS_DEFINITIONS),
295
+ );
296
+
297
+ return taskManager.rootTasks;
298
+ }