hardhat 3.9.0 → 3.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (224) hide show
  1. package/CHANGELOG.md +44 -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/accounts/derive-private-keys.js +1 -1
  68. package/dist/src/internal/builtin-plugins/network-manager/edr/edr-provider.d.ts.map +1 -1
  69. package/dist/src/internal/builtin-plugins/network-manager/edr/edr-provider.js +2 -0
  70. package/dist/src/internal/builtin-plugins/network-manager/edr/edr-provider.js.map +1 -1
  71. package/dist/src/internal/builtin-plugins/network-manager/edr/stack-traces/solidity-stack-trace.d.ts +2 -2
  72. package/dist/src/internal/builtin-plugins/network-manager/edr/stack-traces/solidity-stack-trace.d.ts.map +1 -1
  73. package/dist/src/internal/builtin-plugins/network-manager/edr/stack-traces/solidity-stack-trace.js.map +1 -1
  74. package/dist/src/internal/builtin-plugins/network-manager/edr/stack-traces/stack-trace-solidity-errors.d.ts +1 -0
  75. package/dist/src/internal/builtin-plugins/network-manager/edr/stack-traces/stack-trace-solidity-errors.d.ts.map +1 -1
  76. package/dist/src/internal/builtin-plugins/network-manager/edr/stack-traces/stack-trace-solidity-errors.js +17 -0
  77. package/dist/src/internal/builtin-plugins/network-manager/edr/stack-traces/stack-trace-solidity-errors.js.map +1 -1
  78. package/dist/src/internal/builtin-plugins/network-manager/edr/types/hardfork.d.ts +17 -1
  79. package/dist/src/internal/builtin-plugins/network-manager/edr/types/hardfork.d.ts.map +1 -1
  80. package/dist/src/internal/builtin-plugins/network-manager/edr/types/hardfork.js +19 -2
  81. package/dist/src/internal/builtin-plugins/network-manager/edr/types/hardfork.js.map +1 -1
  82. package/dist/src/internal/builtin-plugins/network-manager/edr/utils/convert-to-edr.d.ts.map +1 -1
  83. package/dist/src/internal/builtin-plugins/network-manager/edr/utils/convert-to-edr.js +5 -1
  84. package/dist/src/internal/builtin-plugins/network-manager/edr/utils/convert-to-edr.js.map +1 -1
  85. package/dist/src/internal/builtin-plugins/network-manager/edr/utils/hardfork.d.ts +8 -0
  86. package/dist/src/internal/builtin-plugins/network-manager/edr/utils/hardfork.d.ts.map +1 -1
  87. package/dist/src/internal/builtin-plugins/network-manager/edr/utils/hardfork.js +30 -1
  88. package/dist/src/internal/builtin-plugins/network-manager/edr/utils/hardfork.js.map +1 -1
  89. package/dist/src/internal/builtin-plugins/network-manager/index.d.ts.map +1 -1
  90. package/dist/src/internal/builtin-plugins/network-manager/index.js +2 -10
  91. package/dist/src/internal/builtin-plugins/network-manager/index.js.map +1 -1
  92. package/dist/src/internal/builtin-plugins/network-manager/network-option.d.ts +9 -0
  93. package/dist/src/internal/builtin-plugins/network-manager/network-option.d.ts.map +1 -0
  94. package/dist/src/internal/builtin-plugins/network-manager/network-option.js +15 -0
  95. package/dist/src/internal/builtin-plugins/network-manager/network-option.js.map +1 -0
  96. package/dist/src/internal/builtin-plugins/network-manager/request-handlers/handlers/accounts/automatic-sender-handler.d.ts +4 -2
  97. package/dist/src/internal/builtin-plugins/network-manager/request-handlers/handlers/accounts/automatic-sender-handler.d.ts.map +1 -1
  98. package/dist/src/internal/builtin-plugins/network-manager/request-handlers/handlers/accounts/automatic-sender-handler.js +28 -6
  99. package/dist/src/internal/builtin-plugins/network-manager/request-handlers/handlers/accounts/automatic-sender-handler.js.map +1 -1
  100. package/dist/src/internal/builtin-plugins/node/task-action.d.ts.map +1 -1
  101. package/dist/src/internal/builtin-plugins/node/task-action.js +2 -37
  102. package/dist/src/internal/builtin-plugins/node/task-action.js.map +1 -1
  103. package/dist/src/internal/builtin-plugins/node/utils/resolve-node-connection-params.d.ts +19 -0
  104. package/dist/src/internal/builtin-plugins/node/utils/resolve-node-connection-params.d.ts.map +1 -0
  105. package/dist/src/internal/builtin-plugins/node/utils/resolve-node-connection-params.js +47 -0
  106. package/dist/src/internal/builtin-plugins/node/utils/resolve-node-connection-params.js.map +1 -0
  107. package/dist/src/internal/builtin-plugins/solidity/build-system/build-system.d.ts.map +1 -1
  108. package/dist/src/internal/builtin-plugins/solidity/build-system/build-system.js +34 -7
  109. package/dist/src/internal/builtin-plugins/solidity/build-system/build-system.js.map +1 -1
  110. package/dist/src/internal/builtin-plugins/solidity-test/config.d.ts +1 -0
  111. package/dist/src/internal/builtin-plugins/solidity-test/config.d.ts.map +1 -1
  112. package/dist/src/internal/builtin-plugins/solidity-test/config.js +32 -9
  113. package/dist/src/internal/builtin-plugins/solidity-test/config.js.map +1 -1
  114. package/dist/src/internal/builtin-plugins/solidity-test/eip712/canonicalize.d.ts +9 -3
  115. package/dist/src/internal/builtin-plugins/solidity-test/eip712/canonicalize.d.ts.map +1 -1
  116. package/dist/src/internal/builtin-plugins/solidity-test/eip712/canonicalize.js +60 -27
  117. package/dist/src/internal/builtin-plugins/solidity-test/eip712/canonicalize.js.map +1 -1
  118. package/dist/src/internal/builtin-plugins/solidity-test/eip712/index.d.ts +1 -1
  119. package/dist/src/internal/builtin-plugins/solidity-test/eip712/index.d.ts.map +1 -1
  120. package/dist/src/internal/builtin-plugins/solidity-test/eip712/index.js +19 -10
  121. package/dist/src/internal/builtin-plugins/solidity-test/eip712/index.js.map +1 -1
  122. package/dist/src/internal/builtin-plugins/solidity-test/helpers.d.ts.map +1 -1
  123. package/dist/src/internal/builtin-plugins/solidity-test/helpers.js +4 -1
  124. package/dist/src/internal/builtin-plugins/solidity-test/helpers.js.map +1 -1
  125. package/dist/src/internal/builtin-plugins/solidity-test/inline-config/index.d.ts +1 -1
  126. package/dist/src/internal/builtin-plugins/solidity-test/inline-config/index.d.ts.map +1 -1
  127. package/dist/src/internal/builtin-plugins/solidity-test/inline-config/index.js +13 -5
  128. package/dist/src/internal/builtin-plugins/solidity-test/inline-config/index.js.map +1 -1
  129. package/dist/src/internal/builtin-plugins/solidity-test/stack-trace-solidity-errors.d.ts.map +1 -1
  130. package/dist/src/internal/builtin-plugins/solidity-test/stack-trace-solidity-errors.js +3 -1
  131. package/dist/src/internal/builtin-plugins/solidity-test/stack-trace-solidity-errors.js.map +1 -1
  132. package/dist/src/internal/builtin-plugins/solidity-test/task-action.js +2 -2
  133. package/dist/src/internal/builtin-plugins/solidity-test/task-action.js.map +1 -1
  134. package/dist/src/internal/builtin-plugins/solidity-test/type-extensions.d.ts +6 -0
  135. package/dist/src/internal/builtin-plugins/solidity-test/type-extensions.d.ts.map +1 -1
  136. package/dist/src/internal/cli/help/get-global-help-string.d.ts +3 -1
  137. package/dist/src/internal/cli/help/get-global-help-string.d.ts.map +1 -1
  138. package/dist/src/internal/cli/help/get-global-help-string.js +3 -3
  139. package/dist/src/internal/cli/help/get-global-help-string.js.map +1 -1
  140. package/dist/src/internal/cli/help/get-help-string.d.ts +3 -1
  141. package/dist/src/internal/cli/help/get-help-string.d.ts.map +1 -1
  142. package/dist/src/internal/cli/help/get-help-string.js +4 -4
  143. package/dist/src/internal/cli/help/get-help-string.js.map +1 -1
  144. package/dist/src/internal/cli/help/utils.d.ts +3 -1
  145. package/dist/src/internal/cli/help/utils.d.ts.map +1 -1
  146. package/dist/src/internal/cli/help/utils.js +2 -2
  147. package/dist/src/internal/cli/help/utils.js.map +1 -1
  148. package/dist/src/internal/cli/hhu.d.ts +14 -0
  149. package/dist/src/internal/cli/hhu.d.ts.map +1 -0
  150. package/dist/src/internal/cli/hhu.js +184 -0
  151. package/dist/src/internal/cli/hhu.js.map +1 -0
  152. package/dist/src/internal/cli/main.d.ts +0 -25
  153. package/dist/src/internal/cli/main.d.ts.map +1 -1
  154. package/dist/src/internal/cli/main.js +23 -303
  155. package/dist/src/internal/cli/main.js.map +1 -1
  156. package/dist/src/internal/cli/parser.d.ts +25 -0
  157. package/dist/src/internal/cli/parser.d.ts.map +1 -0
  158. package/dist/src/internal/cli/parser.js +282 -0
  159. package/dist/src/internal/cli/parser.js.map +1 -0
  160. package/dist/src/internal/cli/telemetry/analytics/analytics.d.ts +1 -1
  161. package/dist/src/internal/cli/telemetry/analytics/analytics.d.ts.map +1 -1
  162. package/dist/src/internal/cli/telemetry/analytics/analytics.js +2 -1
  163. package/dist/src/internal/cli/telemetry/analytics/analytics.js.map +1 -1
  164. package/dist/src/internal/cli/telemetry/analytics/types.d.ts +1 -0
  165. package/dist/src/internal/cli/telemetry/analytics/types.d.ts.map +1 -1
  166. package/dist/src/internal/using-hardhat2-plugin-errors.d.ts +2 -2
  167. package/dist/src/internal/using-hardhat2-plugin-errors.d.ts.map +1 -1
  168. package/dist/src/internal/using-hardhat2-plugin-errors.js +7 -3
  169. package/dist/src/internal/using-hardhat2-plugin-errors.js.map +1 -1
  170. package/dist/src/plugins.d.ts.map +1 -1
  171. package/dist/src/plugins.js +3 -2
  172. package/dist/src/plugins.js.map +1 -1
  173. package/package.json +4 -4
  174. package/src/config.ts +17 -5
  175. package/src/hhu.ts +18 -0
  176. package/src/internal/builtin-plugins/artifacts/hook-handlers/hre.ts +11 -3
  177. package/src/internal/builtin-plugins/gas-analytics/function-gas-snapshots.ts +32 -32
  178. package/src/internal/builtin-plugins/gas-analytics/snapshot-cheatcodes.ts +32 -36
  179. package/src/internal/builtin-plugins/gas-analytics/tasks/solidity-test/task-action.ts +22 -9
  180. package/src/internal/builtin-plugins/hhu/index.ts +13 -0
  181. package/src/internal/builtin-plugins/hhu/tasks/constants/index.ts +18 -0
  182. package/src/internal/builtin-plugins/hhu/tasks/constants/zero-address.ts +9 -0
  183. package/src/internal/builtin-plugins/hhu/tasks/convert/index.ts +40 -0
  184. package/src/internal/builtin-plugins/hhu/tasks/convert/pad.ts +61 -0
  185. package/src/internal/builtin-plugins/hhu/tasks/fetch/block-number.ts +28 -0
  186. package/src/internal/builtin-plugins/hhu/tasks/fetch/index.ts +18 -0
  187. package/src/internal/builtin-plugins/hhu/tasks/index.ts +36 -0
  188. package/src/internal/builtin-plugins/hhu/tasks/utils-task.ts +29 -0
  189. package/src/internal/builtin-plugins/hhu/types.ts +57 -0
  190. package/src/internal/builtin-plugins/index.ts +6 -0
  191. package/src/internal/builtin-plugins/network-manager/accounts/derive-private-keys.ts +1 -1
  192. package/src/internal/builtin-plugins/network-manager/edr/edr-provider.ts +3 -0
  193. package/src/internal/builtin-plugins/network-manager/edr/stack-traces/solidity-stack-trace.ts +1 -1
  194. package/src/internal/builtin-plugins/network-manager/edr/stack-traces/stack-trace-solidity-errors.ts +33 -0
  195. package/src/internal/builtin-plugins/network-manager/edr/types/hardfork.ts +20 -3
  196. package/src/internal/builtin-plugins/network-manager/edr/utils/convert-to-edr.ts +5 -0
  197. package/src/internal/builtin-plugins/network-manager/edr/utils/hardfork.ts +53 -1
  198. package/src/internal/builtin-plugins/network-manager/index.ts +3 -10
  199. package/src/internal/builtin-plugins/network-manager/network-option.ts +17 -0
  200. package/src/internal/builtin-plugins/network-manager/request-handlers/handlers/accounts/automatic-sender-handler.ts +39 -9
  201. package/src/internal/builtin-plugins/node/task-action.ts +2 -52
  202. package/src/internal/builtin-plugins/node/utils/resolve-node-connection-params.ts +79 -0
  203. package/src/internal/builtin-plugins/solidity/build-system/build-system.ts +51 -8
  204. package/src/internal/builtin-plugins/solidity-test/config.ts +53 -9
  205. package/src/internal/builtin-plugins/solidity-test/eip712/canonicalize.ts +64 -25
  206. package/src/internal/builtin-plugins/solidity-test/eip712/index.ts +23 -13
  207. package/src/internal/builtin-plugins/solidity-test/helpers.ts +5 -1
  208. package/src/internal/builtin-plugins/solidity-test/inline-config/index.ts +20 -9
  209. package/src/internal/builtin-plugins/solidity-test/stack-trace-solidity-errors.ts +6 -1
  210. package/src/internal/builtin-plugins/solidity-test/task-action.ts +2 -2
  211. package/src/internal/builtin-plugins/solidity-test/type-extensions.ts +6 -0
  212. package/src/internal/cli/help/get-global-help-string.ts +3 -2
  213. package/src/internal/cli/help/get-help-string.ts +4 -3
  214. package/src/internal/cli/help/utils.ts +2 -1
  215. package/src/internal/cli/hhu.ts +298 -0
  216. package/src/internal/cli/main.ts +41 -495
  217. package/src/internal/cli/parser.ts +472 -0
  218. package/src/internal/cli/telemetry/analytics/analytics.ts +5 -1
  219. package/src/internal/cli/telemetry/analytics/types.ts +3 -0
  220. package/src/internal/using-hardhat2-plugin-errors.ts +12 -3
  221. package/src/plugins.ts +5 -2
  222. package/templates/hardhat-3/01-node-test-runner-viem/package.json +6 -6
  223. package/templates/hardhat-3/02-mocha-ethers/package.json +9 -9
  224. package/templates/hardhat-3/03-minimal/package.json +1 -1
@@ -32,6 +32,22 @@ import { DEFAULT_TEST_PROFILE } from "./test-profiles.js";
32
32
  export const DEFAULT_FUZZ_SEED =
33
33
  "0x7727ea51af0441c20da14dcd68a15dac8c9ebd589c5be8fa8c87c1d3720450bc";
34
34
 
35
+ const nonnegativeSafeIntOrBigInt = unionType(
36
+ [z.number().int().nonnegative().safe(), z.bigint().nonnegative()],
37
+ "Expected a nonnegative safe int or a nonnegative bigint",
38
+ );
39
+
40
+ const nonnegativeSafeIntOrSafeBigInt = unionType(
41
+ [
42
+ z.number().int().nonnegative().safe(),
43
+ z
44
+ .bigint()
45
+ .nonnegative()
46
+ .refine((value) => value <= BigInt(Number.MAX_SAFE_INTEGER)),
47
+ ],
48
+ "Expected a nonnegative safe int or a nonnegative safe bigint",
49
+ );
50
+
35
51
  const solidityTestProfileUserConfigType = z.object({
36
52
  fsPermissions: z
37
53
  .object({
@@ -54,11 +70,9 @@ const solidityTestProfileUserConfigType = z.object({
54
70
  blockTimestamp: z.bigint().optional(),
55
71
  prevRandao: z.bigint().optional(),
56
72
  gasLimit: z.bigint().optional(),
73
+ memoryLimit: nonnegativeSafeIntOrBigInt.optional(),
57
74
  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(),
75
+ transactionGasCap: z.number().or(z.bigint()).or(z.literal(false)).optional(),
62
76
  fuzz: z
63
77
  .object({
64
78
  failurePersistDir: z.string().optional(),
@@ -70,6 +84,7 @@ const solidityTestProfileUserConfigType = z.object({
70
84
  includeStorage: z.boolean().optional(),
71
85
  includePushBytes: z.boolean().optional(),
72
86
  showLogs: z.boolean().optional(),
87
+ timeout: nonnegativeSafeIntOrSafeBigInt.optional(),
73
88
  })
74
89
  .optional(),
75
90
  forking: z
@@ -95,6 +110,7 @@ const solidityTestProfileUserConfigType = z.object({
95
110
  includeStorage: z.boolean().optional(),
96
111
  includePushBytes: z.boolean().optional(),
97
112
  shrinkRunLimit: z.number().optional(),
113
+ timeout: nonnegativeSafeIntOrSafeBigInt.optional(),
98
114
  })
99
115
  .optional(),
100
116
  eip712Types: z
@@ -225,12 +241,22 @@ export async function resolveSolidityTestUserConfig(
225
241
  resolveConfigurationVariable,
226
242
  );
227
243
 
244
+ const {
245
+ memoryLimit,
246
+ fuzz,
247
+ invariant,
248
+ eip712Types,
249
+ ...otherProfileUserConfig
250
+ } = profileUserConfig ?? {};
251
+
228
252
  const resolvedDefaultProfile = {
229
253
  rpcCachePath: defaultRpcCachePath,
230
- ...profileUserConfig,
231
- fuzz: resolveFuzzConfig(profileUserConfig?.fuzz),
254
+ ...otherProfileUserConfig,
255
+ memoryLimit: memoryLimit !== undefined ? BigInt(memoryLimit) : undefined,
256
+ fuzz: resolveFuzzConfig(fuzz),
257
+ invariant: resolveInvariantConfig(invariant),
232
258
  forking: resolvedForking,
233
- eip712Types: resolveEip712TypesConfig(profileUserConfig?.eip712Types),
259
+ eip712Types: resolveEip712TypesConfig(eip712Types),
234
260
  };
235
261
 
236
262
  return {
@@ -254,9 +280,27 @@ export async function resolveSolidityTestUserConfig(
254
280
  export function resolveFuzzConfig(
255
281
  fuzzUserConfig: SolidityTestProfileUserConfig["fuzz"] = {},
256
282
  ): SolidityTestProfileConfig["fuzz"] {
283
+ const { seed, timeout, ...otherFuzzUserConfig } = fuzzUserConfig;
284
+
285
+ return {
286
+ ...otherFuzzUserConfig,
287
+ seed: seed ?? DEFAULT_FUZZ_SEED,
288
+ ...(timeout !== undefined ? { timeout: Number(timeout) } : {}),
289
+ };
290
+ }
291
+
292
+ export function resolveInvariantConfig(
293
+ invariantUserConfig: SolidityTestProfileUserConfig["invariant"],
294
+ ): SolidityTestProfileConfig["invariant"] {
295
+ if (invariantUserConfig === undefined) {
296
+ return undefined;
297
+ }
298
+
299
+ const { timeout, ...otherInvariantUserConfig } = invariantUserConfig;
300
+
257
301
  return {
258
- ...fuzzUserConfig,
259
- seed: fuzzUserConfig.seed ?? DEFAULT_FUZZ_SEED,
302
+ ...otherInvariantUserConfig,
303
+ ...(timeout !== undefined ? { timeout: Number(timeout) } : {}),
260
304
  };
261
305
  }
262
306
 
@@ -2,6 +2,12 @@ import type { CollectedStruct } from "./ast-walker.js";
2
2
 
3
3
  import { HardhatError } from "@nomicfoundation/hardhat-errors";
4
4
 
5
+ export const SELECTED_CONFLICT_REMEDIATION =
6
+ "Rename one of the structs, or scope your `test.solidity.eip712Types.include` / `exclude` globs in `hardhat.config.ts` so that only one of them is selected.";
7
+
8
+ export const DEPENDENCY_CONFLICT_REMEDIATION =
9
+ "Rename one of the structs so the name has a single definition. The clashing name is pulled in as a dependency of a selected struct, so if you don't need that selected struct, deselecting it with your `test.solidity.eip712Types.include` / `exclude` globs in `hardhat.config.ts` also resolves the conflict.";
10
+
5
11
  /**
6
12
  * Produces the flat list of canonical EIP-712 type strings expected by EDR.
7
13
  *
@@ -25,14 +31,28 @@ import { HardhatError } from "@nomicfoundation/hardhat-errors";
25
31
  * constructs and propagates `None` through the dep graph so dependents are
26
32
  * also dropped.
27
33
  *
28
- * Only names in `selectedNames` are emitted; non-selected structs still
29
- * participate in dep resolution so cross-file deps inline correctly.
34
+ * Selection is scoped by source, not by struct name: `selectedSources` holds
35
+ * the project-relative paths matched by the user's include/exclude globs. Only
36
+ * structs from those sources are emitted, but structs elsewhere still feed dep
37
+ * resolution so cross-file deps inline correctly. Scoping by source is what
38
+ * lets a non-selected file define a same-named struct without it being mistaken
39
+ * for selected.
30
40
  */
31
41
  export function canonicalizeStructs(
32
42
  structs: CollectedStruct[],
33
- selectedNames: Set<string>,
43
+ selectedSources: Set<string>,
34
44
  ): string[] {
35
- const byName = indexByName(structs, selectedNames);
45
+ // A name is "selected" if any of its definitions lives in a selected source.
46
+ // Drives what's emitted and, in `indexByName`, whether a selected definition
47
+ // exists to win a name collision.
48
+ const selectedNames = new Set<string>();
49
+ for (const struct of structs) {
50
+ if (selectedSources.has(struct.sourcePath)) {
51
+ selectedNames.add(struct.name);
52
+ }
53
+ }
54
+
55
+ const byName = indexByName(structs, selectedSources, selectedNames);
36
56
  const knownNames = new Set(byName.keys());
37
57
  const encodable = computeEncodable(byName, knownNames);
38
58
  const result: string[] = [];
@@ -189,15 +209,27 @@ function transitiveDeps(
189
209
  * non decodable definition silently win over an encodable one, dropping the
190
210
  * struct from the canonical output.
191
211
  *
192
- * Conflicts on a name reachable from any selected struct (selected roots plus
193
- * their transitive deps) throw, since the selected struct's inlined dep head
194
- * would otherwise depend on which conflicting copy happened to be seen first.
195
- * Conflicts on names truly unreachable from the selected set are silently
196
- * deduped (first wins). Selected structs are processed first so they win over
197
- * non-selected copies.
212
+ * A name clash aborts the run only when it could change the output; otherwise
213
+ * the first definition wins silently. Selection is scoped by source
214
+ * (`selectedSources`), not by name, so a non-selected source whose struct name
215
+ * collides with a selected one stays non-selected. `selectedNames` is the
216
+ * derived set of names with at least one selected definition. Selected structs
217
+ * are processed first, so the already-stored definition in any collision is
218
+ * selected when one exists. Two rules resolve conflicts:
219
+ *
220
+ * - Both sides selected: throw immediately — genuinely ambiguous which to
221
+ * emit.
222
+ * - Current side non-selected: defer; the stored definition keeps the name.
223
+ * Throw only if the name is reachable from a selected struct (its
224
+ * transitive deps), since then which copy got inlined would depend on
225
+ * iteration order. Names unreachable from the selected set are silently
226
+ * deduped (first wins), so a non-selected struct that merely shares a
227
+ * name with a selected root or an unreferenced struct never aborts the
228
+ * run.
198
229
  */
199
230
  function indexByName(
200
231
  structs: CollectedStruct[],
232
+ selectedSources: Set<string>,
201
233
  selectedNames: Set<string>,
202
234
  ): Map<string, CollectedStruct> {
203
235
  const byName = new Map<string, CollectedStruct>();
@@ -209,8 +241,8 @@ function indexByName(
209
241
  >();
210
242
 
211
243
  const ordered = [
212
- ...structs.filter((s) => selectedNames.has(s.name)),
213
- ...structs.filter((s) => !selectedNames.has(s.name)),
244
+ ...structs.filter((s) => selectedSources.has(s.sourcePath)),
245
+ ...structs.filter((s) => !selectedSources.has(s.sourcePath)),
214
246
  ];
215
247
 
216
248
  for (const struct of ordered) {
@@ -228,24 +260,31 @@ function indexByName(
228
260
  continue;
229
261
  }
230
262
 
231
- if (!selectedNames.has(struct.name)) {
232
- if (!deferredConflicts.has(struct.name)) {
233
- deferredConflicts.set(struct.name, {
263
+ if (selectedSources.has(struct.sourcePath)) {
264
+ // Selected-vs-selected conflict: both this and the stored definition are
265
+ // selected (selected structs come first), so it's ambiguous which to emit.
266
+ throw new HardhatError(
267
+ HardhatError.ERRORS.CORE.SOLIDITY_TESTS.EIP712_DUPLICATE_STRUCT_NAME,
268
+ {
269
+ name: struct.name,
234
270
  firstSource: sourceByName.get(struct.name) ?? "<unknown>",
235
271
  secondSource: struct.sourcePath,
236
- });
237
- }
238
- continue;
272
+ remediation: SELECTED_CONFLICT_REMEDIATION,
273
+ },
274
+ );
239
275
  }
240
276
 
241
- throw new HardhatError(
242
- HardhatError.ERRORS.CORE.SOLIDITY_TESTS.EIP712_DUPLICATE_STRUCT_NAME,
243
- {
244
- name: struct.name,
277
+ // Non-selected side, so the stored definition (selected if the name has
278
+ // one, since selected sources come first) keeps the name. Defer: throw
279
+ // later only if the name is reachable from a selected struct. Sharing a
280
+ // name with a selected root or an unreferenced struct is harmless and
281
+ // must not abort.
282
+ if (!deferredConflicts.has(struct.name)) {
283
+ deferredConflicts.set(struct.name, {
245
284
  firstSource: sourceByName.get(struct.name) ?? "<unknown>",
246
285
  secondSource: struct.sourcePath,
247
- },
248
- );
286
+ });
287
+ }
249
288
  }
250
289
 
251
290
  if (deferredConflicts.size > 0) {
@@ -254,7 +293,7 @@ function indexByName(
254
293
  if (reachable.has(name)) {
255
294
  throw new HardhatError(
256
295
  HardhatError.ERRORS.CORE.SOLIDITY_TESTS.EIP712_DUPLICATE_STRUCT_NAME,
257
- { name, ...sources },
296
+ { name, ...sources, remediation: DEPENDENCY_CONFLICT_REMEDIATION },
258
297
  );
259
298
  }
260
299
  }
@@ -2,10 +2,12 @@ import type { CollectedStruct } from "./ast-walker.js";
2
2
  import type { SolidityBuildInfoOutput } from "../../../../types/solidity/solidity-artifacts.js";
3
3
  import type { BuildInfoAndOutput } from "../edr-artifacts.js";
4
4
 
5
+ import { HardhatError } from "@nomicfoundation/hardhat-errors";
5
6
  import {
6
7
  bytesIncludesUtf8String,
7
- bytesToUtf8String,
8
+ parseJsonBytes,
8
9
  } from "@nomicfoundation/hardhat-utils/bytes";
10
+ import { ensureError } from "@nomicfoundation/hardhat-utils/error";
9
11
 
10
12
  import { isPathSelected } from "../../../utils/glob.js";
11
13
  import { toUserSourceName } from "../../solidity/source-names.js";
@@ -35,11 +37,11 @@ export interface Eip712TypesConfig {
35
37
  * When `include` is empty/unset the feature is off: collection short-circuits
36
38
  * and returns an empty list without parsing any build info.
37
39
  */
38
- export function collectEip712CanonicalTypes(
40
+ export async function collectEip712CanonicalTypes(
39
41
  buildInfosAndOutputs: BuildInfoAndOutput[],
40
42
  inputToUserSource: ReadonlyMap<string, string>,
41
43
  config: Eip712TypesConfig,
42
- ): string[] {
44
+ ): Promise<string[]> {
43
45
  const { include, exclude } = config;
44
46
 
45
47
  if (include.length === 0) {
@@ -47,18 +49,26 @@ export function collectEip712CanonicalTypes(
47
49
  }
48
50
 
49
51
  const collected: CollectedStruct[] = [];
50
- const selectedNames = new Set<string>();
52
+ const selectedSources = new Set<string>();
51
53
 
52
- for (const { buildInfo, output } of buildInfosAndOutputs) {
54
+ for (const { buildInfoId, buildInfo, output } of buildInfosAndOutputs) {
53
55
  // Byte-level fast path: a build info whose source bytes don't contain
54
56
  // `struct ` can't define any EIP-712 type, so skip JSON-parsing its output.
55
57
  if (!bytesIncludesUtf8String(buildInfo, "struct ")) {
56
58
  continue;
57
59
  }
58
60
 
59
- const parsedOutput: SolidityBuildInfoOutput = JSON.parse(
60
- bytesToUtf8String(output),
61
- );
61
+ let parsedOutput: SolidityBuildInfoOutput;
62
+ try {
63
+ parsedOutput = await parseJsonBytes<SolidityBuildInfoOutput>(output);
64
+ } catch (error) {
65
+ ensureError(error);
66
+ throw new HardhatError(
67
+ HardhatError.ERRORS.CORE.SOLIDITY.BUILD_INFO_OUTPUT_PARSE_ERROR,
68
+ { buildInfoId },
69
+ error,
70
+ );
71
+ }
62
72
 
63
73
  const sources = parsedOutput.output.sources;
64
74
  if (sources === undefined) {
@@ -92,7 +102,9 @@ export function collectEip712CanonicalTypes(
92
102
  toUserSourceName(inputSourceName);
93
103
 
94
104
  // Collect every source so non-selected files can serve as dep targets;
95
- // selection is enforced at emit time via `selectedNames`.
105
+ // `selectedSources` enforces selection at emit time. Tracked per source,
106
+ // not per struct name, so a non-selected source defining a same-named
107
+ // struct isn't treated as selected (see `canonicalizeStructs`).
96
108
  const structs = extractStructsFromAst(
97
109
  source.ast,
98
110
  userSourceName,
@@ -101,12 +113,10 @@ export function collectEip712CanonicalTypes(
101
113
  collected.push(...structs);
102
114
 
103
115
  if (isPathSelected(userSourceName, include, exclude)) {
104
- for (const s of structs) {
105
- selectedNames.add(s.name);
106
- }
116
+ selectedSources.add(userSourceName);
107
117
  }
108
118
  }
109
119
  }
110
120
 
111
- return canonicalizeStructs(collected, selectedNames);
121
+ return canonicalizeStructs(collected, selectedSources);
112
122
  }
@@ -25,6 +25,7 @@ import { hexStringToBytes } from "@nomicfoundation/hardhat-utils/hex";
25
25
  import { DEFAULT_VERBOSITY, OPTIMISM_CHAIN_TYPE } from "../../constants.js";
26
26
  import { resolveHardfork } from "../network-manager/config-resolution.js";
27
27
  import { hardhatHardforkToEdrSpecId } from "../network-manager/edr/utils/convert-to-edr.js";
28
+ import { warnIfExperimentalHardfork } from "../network-manager/edr/utils/hardfork.js";
28
29
  import { verbosityToIncludeTraces } from "../network-manager/edr/utils/trace-formatters.js";
29
30
 
30
31
  import { formatArtifactId } from "./formatters.js";
@@ -88,8 +89,11 @@ export async function solidityTestConfigToSolidityTestRunnerConfigArgs({
88
89
  const txOrigin = hexToBytes(config.txOrigin);
89
90
  const blockCoinbase = hexToBytes(config.coinbase);
90
91
 
92
+ const resolvedHardforkName = resolveHardfork(hardfork, chainType);
93
+ warnIfExperimentalHardfork(resolvedHardforkName, chainType);
94
+
91
95
  const resolvedHardfork = hardhatHardforkToEdrSpecId(
92
- resolveHardfork(hardfork, chainType),
96
+ resolvedHardforkName,
93
97
  chainType,
94
98
  );
95
99
 
@@ -10,7 +10,8 @@ import {
10
10
  HardhatError,
11
11
  assertHardhatInvariant,
12
12
  } from "@nomicfoundation/hardhat-errors";
13
- import { bytesToUtf8String } from "@nomicfoundation/hardhat-utils/bytes";
13
+ import { parseJsonBytes } from "@nomicfoundation/hardhat-utils/bytes";
14
+ import { ensureError } from "@nomicfoundation/hardhat-utils/error";
14
15
 
15
16
  import { getFullyQualifiedName } from "../../../../utils/contract-names.js";
16
17
 
@@ -48,11 +49,11 @@ interface CollectedOverrides {
48
49
  * in the solc AST. It only extracts them from the build info where each
49
50
  * test artifact's file was compiled as a root file.
50
51
  */
51
- export function getTestFunctionOverrides(
52
+ export async function getTestFunctionOverrides(
52
53
  testSuiteArtifacts: EdrArtifactWithMetadata[],
53
54
  buildInfosAndOutputs: BuildInfoAndOutput[],
54
- ): TestFunctionOverride[] {
55
- const allRawOverrides = collectRawOverrides(
55
+ ): Promise<TestFunctionOverride[]> {
56
+ const allRawOverrides = await collectRawOverrides(
56
57
  testSuiteArtifacts,
57
58
  buildInfosAndOutputs,
58
59
  );
@@ -62,10 +63,10 @@ export function getTestFunctionOverrides(
62
63
  return buildTestFunctionOverrides(allRawOverrides);
63
64
  }
64
65
 
65
- function collectRawOverrides(
66
+ async function collectRawOverrides(
66
67
  testSuiteArtifacts: EdrArtifactWithMetadata[],
67
68
  buildInfosAndOutputs: BuildInfoAndOutput[],
68
- ): CollectedOverrides {
69
+ ): Promise<CollectedOverrides> {
69
70
  const overrides: RawInlineOverride[] = [];
70
71
  const methodIdentifiersByContract = new Map<string, Record<string, string>>();
71
72
 
@@ -153,9 +154,19 @@ function collectRawOverrides(
153
154
  continue;
154
155
  }
155
156
 
156
- const buildInfoOutput: SolidityBuildInfoOutput = JSON.parse(
157
- bytesToUtf8String(buildInfoAndOutput.output),
158
- );
157
+ let buildInfoOutput: SolidityBuildInfoOutput;
158
+ try {
159
+ buildInfoOutput = await parseJsonBytes<SolidityBuildInfoOutput>(
160
+ buildInfoAndOutput.output,
161
+ );
162
+ } catch (error) {
163
+ ensureError(error);
164
+ throw new HardhatError(
165
+ HardhatError.ERRORS.CORE.SOLIDITY.BUILD_INFO_OUTPUT_PARSE_ERROR,
166
+ { buildInfoId },
167
+ error,
168
+ );
169
+ }
159
170
 
160
171
  for (const [
161
172
  inputSourceName,
@@ -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
  }
@@ -231,12 +231,12 @@ const runSolidityTests: NewTaskActionFunction<TestActionArguments> = async (
231
231
  }
232
232
  }
233
233
 
234
- const testFunctionOverrides = getTestFunctionOverrides(
234
+ const testFunctionOverrides = await getTestFunctionOverrides(
235
235
  testSuiteArtifacts,
236
236
  allBuildInfosAndOutputs,
237
237
  );
238
238
 
239
- const eip712CanonicalTypes = collectEip712CanonicalTypes(
239
+ const eip712CanonicalTypes = await collectEip712CanonicalTypes(
240
240
  allBuildInfosAndOutputs,
241
241
  sourceNameToUserSourceName,
242
242
  eip712Types,
@@ -33,6 +33,7 @@ declare module "../../../types/test.js" {
33
33
  includeStorage?: boolean;
34
34
  includePushBytes?: boolean;
35
35
  shrinkRunLimit?: number;
36
+ timeout?: number | bigint;
36
37
  }
37
38
 
38
39
  export interface SolidityTestFuzzUserConfig {
@@ -45,6 +46,7 @@ declare module "../../../types/test.js" {
45
46
  includeStorage?: boolean;
46
47
  includePushBytes?: boolean;
47
48
  showLogs?: boolean;
49
+ timeout?: number | bigint;
48
50
  }
49
51
 
50
52
  export interface SolidityTestForkingUserConfig {
@@ -66,6 +68,7 @@ declare module "../../../types/test.js" {
66
68
  blockTimestamp?: bigint;
67
69
  prevRandao?: bigint;
68
70
  gasLimit?: bigint;
71
+ memoryLimit?: number | bigint;
69
72
  blockGasLimit?: number | bigint | false;
70
73
  transactionGasCap?: number | bigint | false;
71
74
  fuzz?: SolidityTestFuzzUserConfig;
@@ -108,6 +111,7 @@ declare module "../../../types/test.js" {
108
111
  includeStorage?: boolean;
109
112
  includePushBytes?: boolean;
110
113
  shrinkRunLimit?: number;
114
+ timeout?: number;
111
115
  }
112
116
 
113
117
  export interface SolidityTestFuzzConfig {
@@ -120,6 +124,7 @@ declare module "../../../types/test.js" {
120
124
  includeStorage?: boolean;
121
125
  includePushBytes?: boolean;
122
126
  showLogs?: boolean;
127
+ timeout?: number;
123
128
  }
124
129
 
125
130
  export interface SolidityTestForkingConfig {
@@ -142,6 +147,7 @@ declare module "../../../types/test.js" {
142
147
  blockTimestamp?: bigint;
143
148
  prevRandao?: bigint;
144
149
  gasLimit?: bigint;
150
+ memoryLimit?: bigint;
145
151
  blockGasLimit?: number | bigint | false;
146
152
  transactionGasCap?: number | bigint | false;
147
153
  fuzz: SolidityTestFuzzConfig;
@@ -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