hardhat 3.4.5 → 3.5.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 (215) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/dist/src/config.d.ts +0 -1
  3. package/dist/src/config.d.ts.map +1 -1
  4. package/dist/src/config.js.map +1 -1
  5. package/dist/src/hre.d.ts +0 -1
  6. package/dist/src/hre.d.ts.map +1 -1
  7. package/dist/src/hre.js.map +1 -1
  8. package/dist/src/index.d.ts +0 -1
  9. package/dist/src/index.d.ts.map +1 -1
  10. package/dist/src/index.js.map +1 -1
  11. package/dist/src/internal/builtin-global-options.d.ts.map +1 -1
  12. package/dist/src/internal/builtin-global-options.js +1 -1
  13. package/dist/src/internal/builtin-global-options.js.map +1 -1
  14. package/dist/src/internal/builtin-plugins/gas-analytics/snapshot-cheatcodes.d.ts +21 -0
  15. package/dist/src/internal/builtin-plugins/gas-analytics/snapshot-cheatcodes.d.ts.map +1 -1
  16. package/dist/src/internal/builtin-plugins/gas-analytics/snapshot-cheatcodes.js +49 -1
  17. package/dist/src/internal/builtin-plugins/gas-analytics/snapshot-cheatcodes.js.map +1 -1
  18. package/dist/src/internal/builtin-plugins/gas-analytics/tasks/solidity-test/task-action.d.ts +2 -1
  19. package/dist/src/internal/builtin-plugins/gas-analytics/tasks/solidity-test/task-action.d.ts.map +1 -1
  20. package/dist/src/internal/builtin-plugins/gas-analytics/tasks/solidity-test/task-action.js +12 -2
  21. package/dist/src/internal/builtin-plugins/gas-analytics/tasks/solidity-test/task-action.js.map +1 -1
  22. package/dist/src/internal/builtin-plugins/network-manager/config-resolution.d.ts.map +1 -1
  23. package/dist/src/internal/builtin-plugins/network-manager/config-resolution.js +9 -2
  24. package/dist/src/internal/builtin-plugins/network-manager/config-resolution.js.map +1 -1
  25. package/dist/src/internal/builtin-plugins/network-manager/edr/edr-constants.d.ts +1 -0
  26. package/dist/src/internal/builtin-plugins/network-manager/edr/edr-constants.d.ts.map +1 -1
  27. package/dist/src/internal/builtin-plugins/network-manager/edr/edr-constants.js +1 -0
  28. package/dist/src/internal/builtin-plugins/network-manager/edr/edr-constants.js.map +1 -1
  29. package/dist/src/internal/builtin-plugins/network-manager/edr/edr-provider.d.ts.map +1 -1
  30. package/dist/src/internal/builtin-plugins/network-manager/edr/edr-provider.js +25 -5
  31. package/dist/src/internal/builtin-plugins/network-manager/edr/edr-provider.js.map +1 -1
  32. package/dist/src/internal/builtin-plugins/network-manager/edr/utils/convert-to-edr.d.ts +16 -0
  33. package/dist/src/internal/builtin-plugins/network-manager/edr/utils/convert-to-edr.d.ts.map +1 -1
  34. package/dist/src/internal/builtin-plugins/network-manager/edr/utils/convert-to-edr.js +28 -1
  35. package/dist/src/internal/builtin-plugins/network-manager/edr/utils/convert-to-edr.js.map +1 -1
  36. package/dist/src/internal/builtin-plugins/network-manager/network-manager.d.ts.map +1 -1
  37. package/dist/src/internal/builtin-plugins/network-manager/network-manager.js +2 -6
  38. package/dist/src/internal/builtin-plugins/network-manager/network-manager.js.map +1 -1
  39. package/dist/src/internal/builtin-plugins/network-manager/type-extensions/config.d.ts +5 -3
  40. package/dist/src/internal/builtin-plugins/network-manager/type-extensions/config.d.ts.map +1 -1
  41. package/dist/src/internal/builtin-plugins/network-manager/type-validation.d.ts.map +1 -1
  42. package/dist/src/internal/builtin-plugins/network-manager/type-validation.js +3 -1
  43. package/dist/src/internal/builtin-plugins/network-manager/type-validation.js.map +1 -1
  44. package/dist/src/internal/builtin-plugins/network-manager/utils/apply-coverage-network-overrides.d.ts +18 -0
  45. package/dist/src/internal/builtin-plugins/network-manager/utils/apply-coverage-network-overrides.d.ts.map +1 -0
  46. package/dist/src/internal/builtin-plugins/network-manager/utils/apply-coverage-network-overrides.js +27 -0
  47. package/dist/src/internal/builtin-plugins/network-manager/utils/apply-coverage-network-overrides.js.map +1 -0
  48. package/dist/src/internal/builtin-plugins/node/json-rpc/handler.js +6 -5
  49. package/dist/src/internal/builtin-plugins/node/json-rpc/handler.js.map +1 -1
  50. package/dist/src/internal/builtin-plugins/solidity/build-system/resolver/remapped-npm-packages-graph.d.ts.map +1 -1
  51. package/dist/src/internal/builtin-plugins/solidity/build-system/resolver/remapped-npm-packages-graph.js +1 -1
  52. package/dist/src/internal/builtin-plugins/solidity/build-system/resolver/remapped-npm-packages-graph.js.map +1 -1
  53. package/dist/src/internal/builtin-plugins/solidity/constants.d.ts +10 -0
  54. package/dist/src/internal/builtin-plugins/solidity/constants.d.ts.map +1 -1
  55. package/dist/src/internal/builtin-plugins/solidity/constants.js +10 -0
  56. package/dist/src/internal/builtin-plugins/solidity/constants.js.map +1 -1
  57. package/dist/src/internal/builtin-plugins/solidity/index.d.ts.map +1 -1
  58. package/dist/src/internal/builtin-plugins/solidity/index.js +1 -0
  59. package/dist/src/internal/builtin-plugins/solidity/index.js.map +1 -1
  60. package/dist/src/internal/builtin-plugins/solidity/tasks/compile.d.ts +9 -0
  61. package/dist/src/internal/builtin-plugins/solidity/tasks/compile.d.ts.map +1 -0
  62. package/dist/src/internal/builtin-plugins/solidity/tasks/compile.js +10 -0
  63. package/dist/src/internal/builtin-plugins/solidity/tasks/compile.js.map +1 -0
  64. package/dist/src/internal/builtin-plugins/solidity-test/config.d.ts +4 -3
  65. package/dist/src/internal/builtin-plugins/solidity-test/config.d.ts.map +1 -1
  66. package/dist/src/internal/builtin-plugins/solidity-test/config.js +55 -8
  67. package/dist/src/internal/builtin-plugins/solidity-test/config.js.map +1 -1
  68. package/dist/src/internal/builtin-plugins/solidity-test/eip712/ast-walker.d.ts +58 -0
  69. package/dist/src/internal/builtin-plugins/solidity-test/eip712/ast-walker.d.ts.map +1 -0
  70. package/dist/src/internal/builtin-plugins/solidity-test/eip712/ast-walker.js +226 -0
  71. package/dist/src/internal/builtin-plugins/solidity-test/eip712/ast-walker.js.map +1 -0
  72. package/dist/src/internal/builtin-plugins/solidity-test/eip712/canonicalize.d.ts +29 -0
  73. package/dist/src/internal/builtin-plugins/solidity-test/eip712/canonicalize.d.ts.map +1 -0
  74. package/dist/src/internal/builtin-plugins/solidity-test/eip712/canonicalize.js +244 -0
  75. package/dist/src/internal/builtin-plugins/solidity-test/eip712/canonicalize.js.map +1 -0
  76. package/dist/src/internal/builtin-plugins/solidity-test/eip712/glob.d.ts +7 -0
  77. package/dist/src/internal/builtin-plugins/solidity-test/eip712/glob.d.ts.map +1 -0
  78. package/dist/src/internal/builtin-plugins/solidity-test/eip712/glob.js +204 -0
  79. package/dist/src/internal/builtin-plugins/solidity-test/eip712/glob.js.map +1 -0
  80. package/dist/src/internal/builtin-plugins/solidity-test/eip712/index.d.ts +21 -0
  81. package/dist/src/internal/builtin-plugins/solidity-test/eip712/index.d.ts.map +1 -0
  82. package/dist/src/internal/builtin-plugins/solidity-test/eip712/index.js +77 -0
  83. package/dist/src/internal/builtin-plugins/solidity-test/eip712/index.js.map +1 -0
  84. package/dist/src/internal/builtin-plugins/solidity-test/helpers.d.ts +4 -3
  85. package/dist/src/internal/builtin-plugins/solidity-test/helpers.d.ts.map +1 -1
  86. package/dist/src/internal/builtin-plugins/solidity-test/helpers.js +20 -3
  87. package/dist/src/internal/builtin-plugins/solidity-test/helpers.js.map +1 -1
  88. package/dist/src/internal/builtin-plugins/solidity-test/task-action.d.ts.map +1 -1
  89. package/dist/src/internal/builtin-plugins/solidity-test/task-action.js +5 -1
  90. package/dist/src/internal/builtin-plugins/solidity-test/task-action.js.map +1 -1
  91. package/dist/src/internal/builtin-plugins/solidity-test/test-profiles.d.ts +2 -0
  92. package/dist/src/internal/builtin-plugins/solidity-test/test-profiles.d.ts.map +1 -0
  93. package/dist/src/internal/builtin-plugins/solidity-test/test-profiles.js +2 -0
  94. package/dist/src/internal/builtin-plugins/solidity-test/test-profiles.js.map +1 -0
  95. package/dist/src/internal/builtin-plugins/solidity-test/type-extensions.d.ts +91 -32
  96. package/dist/src/internal/builtin-plugins/solidity-test/type-extensions.d.ts.map +1 -1
  97. package/dist/src/internal/cli/init/init.d.ts +31 -6
  98. package/dist/src/internal/cli/init/init.d.ts.map +1 -1
  99. package/dist/src/internal/cli/init/init.js +121 -10
  100. package/dist/src/internal/cli/init/init.js.map +1 -1
  101. package/dist/src/internal/cli/main.d.ts.map +1 -1
  102. package/dist/src/internal/cli/main.js +41 -1
  103. package/dist/src/internal/cli/main.js.map +1 -1
  104. package/dist/src/types/arguments.d.ts +1 -0
  105. package/dist/src/types/arguments.d.ts.map +1 -1
  106. package/dist/src/types/arguments.js +1 -0
  107. package/dist/src/types/arguments.js.map +1 -1
  108. package/dist/src/types/artifacts.d.ts +1 -0
  109. package/dist/src/types/artifacts.d.ts.map +1 -1
  110. package/dist/src/types/artifacts.js +1 -1
  111. package/dist/src/types/artifacts.js.map +1 -1
  112. package/dist/src/types/builtin-plugin-type-extensions.d.ts +2 -0
  113. package/dist/src/types/builtin-plugin-type-extensions.d.ts.map +1 -0
  114. package/dist/src/types/builtin-plugin-type-extensions.js +2 -0
  115. package/dist/src/types/builtin-plugin-type-extensions.js.map +1 -0
  116. package/dist/src/types/config.d.ts +1 -0
  117. package/dist/src/types/config.d.ts.map +1 -1
  118. package/dist/src/types/config.js +1 -1
  119. package/dist/src/types/config.js.map +1 -1
  120. package/dist/src/types/global-options.d.ts +1 -0
  121. package/dist/src/types/global-options.d.ts.map +1 -1
  122. package/dist/src/types/global-options.js +1 -1
  123. package/dist/src/types/global-options.js.map +1 -1
  124. package/dist/src/types/hooks.d.ts +1 -0
  125. package/dist/src/types/hooks.d.ts.map +1 -1
  126. package/dist/src/types/hooks.js +1 -1
  127. package/dist/src/types/hooks.js.map +1 -1
  128. package/dist/src/types/hre.d.ts +1 -0
  129. package/dist/src/types/hre.d.ts.map +1 -1
  130. package/dist/src/types/hre.js +1 -1
  131. package/dist/src/types/hre.js.map +1 -1
  132. package/dist/src/types/index.d.ts +1 -0
  133. package/dist/src/types/index.d.ts.map +1 -1
  134. package/dist/src/types/index.js +1 -0
  135. package/dist/src/types/index.js.map +1 -1
  136. package/dist/src/types/network.d.ts +1 -0
  137. package/dist/src/types/network.d.ts.map +1 -1
  138. package/dist/src/types/network.js +1 -1
  139. package/dist/src/types/network.js.map +1 -1
  140. package/dist/src/types/plugins.d.ts +1 -1
  141. package/dist/src/types/plugins.d.ts.map +1 -1
  142. package/dist/src/types/plugins.js +1 -1
  143. package/dist/src/types/plugins.js.map +1 -1
  144. package/dist/src/types/providers.d.ts +1 -0
  145. package/dist/src/types/providers.d.ts.map +1 -1
  146. package/dist/src/types/providers.js +1 -1
  147. package/dist/src/types/providers.js.map +1 -1
  148. package/dist/src/types/solidity.d.ts +1 -0
  149. package/dist/src/types/solidity.d.ts.map +1 -1
  150. package/dist/src/types/solidity.js +1 -0
  151. package/dist/src/types/solidity.js.map +1 -1
  152. package/dist/src/types/tasks.d.ts +1 -0
  153. package/dist/src/types/tasks.d.ts.map +1 -1
  154. package/dist/src/types/tasks.js +1 -0
  155. package/dist/src/types/tasks.js.map +1 -1
  156. package/dist/src/types/test.d.ts +1 -0
  157. package/dist/src/types/test.d.ts.map +1 -1
  158. package/dist/src/types/test.js +1 -1
  159. package/dist/src/types/test.js.map +1 -1
  160. package/dist/src/types/user-interruptions.d.ts +1 -0
  161. package/dist/src/types/user-interruptions.d.ts.map +1 -1
  162. package/dist/src/types/user-interruptions.js +1 -1
  163. package/dist/src/types/user-interruptions.js.map +1 -1
  164. package/package.json +12 -11
  165. package/src/config.ts +0 -2
  166. package/src/hre.ts +0 -3
  167. package/src/index.ts +0 -3
  168. package/src/internal/builtin-global-options.ts +2 -1
  169. package/src/internal/builtin-plugins/gas-analytics/snapshot-cheatcodes.ts +90 -1
  170. package/src/internal/builtin-plugins/gas-analytics/tasks/solidity-test/task-action.ts +24 -2
  171. package/src/internal/builtin-plugins/network-manager/config-resolution.ts +11 -3
  172. package/src/internal/builtin-plugins/network-manager/edr/edr-constants.ts +2 -0
  173. package/src/internal/builtin-plugins/network-manager/edr/edr-provider.ts +38 -8
  174. package/src/internal/builtin-plugins/network-manager/edr/utils/convert-to-edr.ts +43 -1
  175. package/src/internal/builtin-plugins/network-manager/network-manager.ts +5 -6
  176. package/src/internal/builtin-plugins/network-manager/type-extensions/config.ts +5 -3
  177. package/src/internal/builtin-plugins/network-manager/type-validation.ts +7 -1
  178. package/src/internal/builtin-plugins/network-manager/utils/apply-coverage-network-overrides.ts +32 -0
  179. package/src/internal/builtin-plugins/node/json-rpc/handler.ts +7 -5
  180. package/src/internal/builtin-plugins/solidity/build-system/resolver/remapped-npm-packages-graph.ts +1 -2
  181. package/src/internal/builtin-plugins/solidity/constants.ts +11 -0
  182. package/src/internal/builtin-plugins/solidity/index.ts +1 -0
  183. package/src/internal/builtin-plugins/solidity/tasks/compile.ts +12 -0
  184. package/src/internal/builtin-plugins/solidity-test/config.ts +85 -12
  185. package/src/internal/builtin-plugins/solidity-test/eip712/ast-walker.ts +324 -0
  186. package/src/internal/builtin-plugins/solidity-test/eip712/canonicalize.ts +317 -0
  187. package/src/internal/builtin-plugins/solidity-test/eip712/glob.ts +225 -0
  188. package/src/internal/builtin-plugins/solidity-test/eip712/index.ts +120 -0
  189. package/src/internal/builtin-plugins/solidity-test/helpers.ts +28 -4
  190. package/src/internal/builtin-plugins/solidity-test/task-action.ts +12 -1
  191. package/src/internal/builtin-plugins/solidity-test/test-profiles.ts +1 -0
  192. package/src/internal/builtin-plugins/solidity-test/type-extensions.ts +100 -33
  193. package/src/internal/cli/init/init.ts +198 -16
  194. package/src/internal/cli/main.ts +64 -1
  195. package/src/types/arguments.ts +2 -0
  196. package/src/types/artifacts.ts +2 -0
  197. package/src/types/builtin-plugin-type-extensions.ts +15 -0
  198. package/src/types/config.ts +2 -0
  199. package/src/types/global-options.ts +2 -0
  200. package/src/types/hooks.ts +2 -0
  201. package/src/types/hre.ts +2 -0
  202. package/src/types/index.ts +2 -0
  203. package/src/types/network.ts +2 -0
  204. package/src/types/plugins.ts +1 -2
  205. package/src/types/providers.ts +2 -0
  206. package/src/types/solidity.ts +2 -0
  207. package/src/types/tasks.ts +2 -0
  208. package/src/types/test.ts +2 -0
  209. package/src/types/user-interruptions.ts +2 -0
  210. package/templates/hardhat-3/01-node-test-runner-viem/package.json +11 -11
  211. package/templates/hardhat-3/01-node-test-runner-viem/tsconfig.json +4 -7
  212. package/templates/hardhat-3/02-mocha-ethers/package.json +13 -13
  213. package/templates/hardhat-3/02-mocha-ethers/tsconfig.json +4 -7
  214. package/templates/hardhat-3/03-minimal/package.json +2 -2
  215. package/templates/hardhat-3/03-minimal/tsconfig.json +4 -7
@@ -1,5 +1,16 @@
1
1
  import type { CompilerInput } from "../../../types/solidity.js";
2
2
 
3
+ /**
4
+ * The input source name prefix used for files belonging to the Hardhat
5
+ * project (as opposed to npm packages, which use `npm/<pkg>@<version>`).
6
+ *
7
+ * For example, a project file at `<root>/contracts/Foo.sol` has input
8
+ * source name `project/contracts/Foo.sol`. Part of the build-info format
9
+ * contract: changing this value would require a new build-info format
10
+ * version.
11
+ */
12
+ export const HARDHAT_PROJECT_INPUT_SOURCE_NAME_ROOT = "project";
13
+
3
14
  export const DEFAULT_OUTPUT_SELECTION: CompilerInput["settings"]["outputSelection"] =
4
15
  {
5
16
  "*": {
@@ -53,6 +53,7 @@ const hardhatPlugin: HardhatPlugin = {
53
53
  ...buildTask,
54
54
  id: ["compile"],
55
55
  description: "Build project (alias for build)",
56
+ action: async () => await import("./tasks/compile.js"),
56
57
  },
57
58
  ],
58
59
  globalOptions: [
@@ -0,0 +1,12 @@
1
+ import type { NewTaskActionFunction } from "../../../../types/tasks.js";
2
+
3
+ /**
4
+ * Compile task action is an alias of the build task action, it invokes
5
+ * the build task to ensure any build overrides are properly executed when
6
+ * compile is run.
7
+ */
8
+ const compileAction: NewTaskActionFunction = async (args, hre) => {
9
+ return await hre.tasks.getTask("build").run(args);
10
+ };
11
+
12
+ export default compileAction;
@@ -6,17 +6,19 @@ import type {
6
6
  } from "../../../types/config.js";
7
7
  import type { HardhatUserConfigValidationError } from "../../../types/hooks.js";
8
8
  import type {
9
- SolidityTestConfig,
10
9
  SolidityTestForkingConfig,
11
- SolidityTestUserConfig,
10
+ SolidityTestProfileConfig,
11
+ SolidityTestProfileUserConfig,
12
12
  } from "../../../types/test.js";
13
13
 
14
14
  import path from "node:path";
15
15
 
16
+ import { assertHardhatInvariant } from "@nomicfoundation/hardhat-errors";
16
17
  import { isObject } from "@nomicfoundation/hardhat-utils/lang";
17
18
  import { resolveFromRoot } from "@nomicfoundation/hardhat-utils/path";
18
19
  import {
19
20
  conditionalUnionType,
21
+ incompatibleFieldType,
20
22
  sensitiveStringSchema,
21
23
  sensitiveUrlSchema,
22
24
  unionType,
@@ -24,11 +26,13 @@ import {
24
26
  } from "@nomicfoundation/hardhat-zod-utils";
25
27
  import { z } from "zod";
26
28
 
29
+ import { DEFAULT_TEST_PROFILE } from "./test-profiles.js";
30
+
27
31
  // the keccak256 of "built for ethereum"
28
32
  export const DEFAULT_FUZZ_SEED =
29
33
  "0x7727ea51af0441c20da14dcd68a15dac8c9ebd589c5be8fa8c87c1d3720450bc";
30
34
 
31
- const solidityTestUserConfigType = z.object({
35
+ const solidityTestProfileUserConfigType = z.object({
32
36
  fsPermissions: z
33
37
  .object({
34
38
  readWriteFile: z.array(z.string()).optional(),
@@ -50,7 +54,11 @@ const solidityTestUserConfigType = z.object({
50
54
  blockTimestamp: z.bigint().optional(),
51
55
  prevRandao: z.bigint().optional(),
52
56
  gasLimit: z.bigint().optional(),
53
- blockGasLimit: z.bigint().or(z.literal(false)).optional(),
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(),
54
62
  fuzz: z
55
63
  .object({
56
64
  failurePersistDir: z.string().optional(),
@@ -89,8 +97,49 @@ const solidityTestUserConfigType = z.object({
89
97
  shrinkRunLimit: z.number().optional(),
90
98
  })
91
99
  .optional(),
100
+ eip712Types: z
101
+ .object({
102
+ include: z.array(z.string()).optional(),
103
+ exclude: z.array(z.string()).optional(),
104
+ })
105
+ .optional(),
92
106
  });
93
107
 
108
+ const solidityTestFlatUserConfigType = solidityTestProfileUserConfigType.extend(
109
+ {
110
+ profiles: incompatibleFieldType(
111
+ "This field is incompatible with the flat solidity test config",
112
+ ),
113
+ },
114
+ );
115
+
116
+ const solidityTestProfilesUserConfigType = z.object({
117
+ profiles: z
118
+ .record(z.string(), solidityTestProfileUserConfigType)
119
+ .refine(
120
+ (profiles) => DEFAULT_TEST_PROFILE in profiles,
121
+ "A `default` profile is required when using `profiles`",
122
+ )
123
+ .refine(
124
+ (profiles) =>
125
+ !(DEFAULT_TEST_PROFILE in profiles) ||
126
+ Object.keys(profiles).every((name) => name === DEFAULT_TEST_PROFILE),
127
+ "Only the `default` profile is supported. Other profile names will be supported in a future release.",
128
+ ),
129
+ });
130
+
131
+ const solidityTestUserConfigType = conditionalUnionType(
132
+ [
133
+ [
134
+ (data) =>
135
+ isObject(data) && "profiles" in data && Object.keys(data).length === 1,
136
+ solidityTestProfilesUserConfigType,
137
+ ],
138
+ [isObject, solidityTestFlatUserConfigType],
139
+ ],
140
+ "Expected a Solidity test config or a `{ profiles: { ... } }` wrapper",
141
+ );
142
+
94
143
  const userConfigType = z.object({
95
144
  paths: z
96
145
  .object({
@@ -111,7 +160,7 @@ const userConfigType = z.object({
111
160
  });
112
161
 
113
162
  export function resolveSolidityTestForkingConfig(
114
- forkingUserConfig: SolidityTestUserConfig["forking"],
163
+ forkingUserConfig: SolidityTestProfileUserConfig["forking"],
115
164
  resolveConfigurationVariable: ConfigurationVariableResolver,
116
165
  ): SolidityTestForkingConfig | undefined {
117
166
  if (forkingUserConfig === undefined) {
@@ -159,16 +208,29 @@ export async function resolveSolidityTestUserConfig(
159
208
 
160
209
  const defaultRpcCachePath = path.join(resolvedConfig.paths.cache, "edr");
161
210
 
211
+ const solidityUserConfig = userConfig.test?.solidity;
212
+ let profileUserConfig: SolidityTestProfileUserConfig | undefined;
213
+ if (solidityUserConfig !== undefined && "profiles" in solidityUserConfig) {
214
+ profileUserConfig = solidityUserConfig.profiles[DEFAULT_TEST_PROFILE];
215
+ assertHardhatInvariant(
216
+ profileUserConfig !== undefined,
217
+ "default profile must be present when the profiles wrapper user config is supplied",
218
+ );
219
+ } else {
220
+ profileUserConfig = solidityUserConfig;
221
+ }
222
+
162
223
  const resolvedForking = resolveSolidityTestForkingConfig(
163
- userConfig.test?.solidity?.forking,
224
+ profileUserConfig?.forking,
164
225
  resolveConfigurationVariable,
165
226
  );
166
227
 
167
- const solidityTest = {
228
+ const resolvedDefaultProfile = {
168
229
  rpcCachePath: defaultRpcCachePath,
169
- ...userConfig.test?.solidity,
170
- fuzz: resolveFuzzConfig(userConfig.test?.solidity?.fuzz),
230
+ ...profileUserConfig,
231
+ fuzz: resolveFuzzConfig(profileUserConfig?.fuzz),
171
232
  forking: resolvedForking,
233
+ eip712Types: resolveEip712TypesConfig(profileUserConfig?.eip712Types),
172
234
  };
173
235
 
174
236
  return {
@@ -182,16 +244,27 @@ export async function resolveSolidityTestUserConfig(
182
244
  },
183
245
  test: {
184
246
  ...resolvedConfig.test,
185
- solidity: solidityTest,
247
+ solidity: {
248
+ profiles: { [DEFAULT_TEST_PROFILE]: resolvedDefaultProfile },
249
+ },
186
250
  },
187
251
  };
188
252
  }
189
253
 
190
254
  export function resolveFuzzConfig(
191
- fuzzUserConfig: SolidityTestUserConfig["fuzz"] = {},
192
- ): SolidityTestConfig["fuzz"] {
255
+ fuzzUserConfig: SolidityTestProfileUserConfig["fuzz"] = {},
256
+ ): SolidityTestProfileConfig["fuzz"] {
193
257
  return {
194
258
  ...fuzzUserConfig,
195
259
  seed: fuzzUserConfig.seed ?? DEFAULT_FUZZ_SEED,
196
260
  };
197
261
  }
262
+
263
+ export function resolveEip712TypesConfig(
264
+ eip712TypesUserConfig: SolidityTestProfileUserConfig["eip712Types"] = {},
265
+ ): SolidityTestProfileConfig["eip712Types"] {
266
+ return {
267
+ include: eip712TypesUserConfig.include ?? [],
268
+ exclude: eip712TypesUserConfig.exclude ?? [],
269
+ };
270
+ }
@@ -0,0 +1,324 @@
1
+ import { isObject } from "@nomicfoundation/hardhat-utils/lang";
2
+
3
+ /**
4
+ * A single field of a Solidity struct
5
+ */
6
+ export interface StructMember {
7
+ name: string;
8
+ /**
9
+ * EIP-712 type string, or `undefined` if the type can't be encoded (e.g. mappings).
10
+ */
11
+ type: string | undefined;
12
+ }
13
+
14
+ /**
15
+ * A Solidity struct extracted from a source AST (Abstract Syntax Tree).
16
+ */
17
+ export interface CollectedStruct {
18
+ name: string;
19
+ members: StructMember[];
20
+ /**
21
+ * Project-relative source path. Used for diagnostics only.
22
+ */
23
+ sourcePath: string;
24
+ }
25
+
26
+ /**
27
+ * A user-defined value type (`type Foo is bytes32;`) resolves to its
28
+ * underlying elementary type for EIP-712 encoding.
29
+ * The map is keyed by the user-defined value type definition's solc node id,
30
+ * which is what `referencedDeclaration` on a `UserDefinedTypeName` reference
31
+ * points to.
32
+ */
33
+ export type UserDefinedValueTypeIndex = Map<number, Record<string, unknown>>;
34
+
35
+ /**
36
+ * Walks every AST in the build and indexes every `UserDefinedValueTypeDefinition`
37
+ * by its node `id`, mapping to its `underlyingType` (an `ElementaryTypeName`).
38
+ *
39
+ * User-defined value types can sit at file scope or inside a contract, and a
40
+ * struct in one source may reference a user-defined value type defined in
41
+ * another, so this must run across every AST in the build — not just the ones
42
+ * matched by the user's include globs.
43
+ */
44
+ export function buildUserDefinedValueTypeIndex(
45
+ asts: unknown[],
46
+ ): UserDefinedValueTypeIndex {
47
+ const index: UserDefinedValueTypeIndex = new Map();
48
+
49
+ for (const ast of asts) {
50
+ if (!isObject(ast) || ast.nodeType !== "SourceUnit") {
51
+ continue;
52
+ }
53
+
54
+ const topLevelNodes: unknown[] = Array.isArray(ast.nodes) ? ast.nodes : [];
55
+ for (const node of topLevelNodes) {
56
+ if (!isObject(node)) {
57
+ continue;
58
+ }
59
+
60
+ if (node.nodeType === "UserDefinedValueTypeDefinition") {
61
+ recordUserDefinedValueType(node, index);
62
+ } else if (node.nodeType === "ContractDefinition") {
63
+ const members: unknown[] = Array.isArray(node.nodes) ? node.nodes : [];
64
+ for (const member of members) {
65
+ if (
66
+ isObject(member) &&
67
+ member.nodeType === "UserDefinedValueTypeDefinition"
68
+ ) {
69
+ recordUserDefinedValueType(member, index);
70
+ }
71
+ }
72
+ }
73
+ }
74
+ }
75
+
76
+ return index;
77
+ }
78
+
79
+ function recordUserDefinedValueType(
80
+ node: Record<string, unknown>,
81
+ index: UserDefinedValueTypeIndex,
82
+ ): void {
83
+ if (
84
+ typeof node.id === "number" &&
85
+ isObject(node.underlyingType) &&
86
+ node.underlyingType.nodeType === "ElementaryTypeName"
87
+ ) {
88
+ index.set(node.id, node.underlyingType);
89
+ }
90
+ }
91
+
92
+ /**
93
+ * Returns every struct definition reachable from a solc source AST (Abstract Syntax Tree),
94
+ * including structs nested inside contracts.
95
+ */
96
+ export function extractStructsFromAst(
97
+ ast: unknown,
98
+ sourcePath: string,
99
+ userDefinedValueTypeI: UserDefinedValueTypeIndex = new Map(),
100
+ ): CollectedStruct[] {
101
+ if (!isObject(ast) || ast.nodeType !== "SourceUnit") {
102
+ return [];
103
+ }
104
+
105
+ const results: CollectedStruct[] = [];
106
+ const topLevelNodes: unknown[] = Array.isArray(ast.nodes) ? ast.nodes : [];
107
+
108
+ for (const node of topLevelNodes) {
109
+ if (!isObject(node)) {
110
+ continue;
111
+ }
112
+
113
+ if (node.nodeType === "StructDefinition") {
114
+ const collected = collectStruct(node, sourcePath, userDefinedValueTypeI);
115
+ if (collected !== undefined) {
116
+ results.push(collected);
117
+ }
118
+ } else if (node.nodeType === "ContractDefinition") {
119
+ const members: unknown[] = Array.isArray(node.nodes) ? node.nodes : [];
120
+ for (const member of members) {
121
+ if (isObject(member) && member.nodeType === "StructDefinition") {
122
+ const collected = collectStruct(
123
+ member,
124
+ sourcePath,
125
+ userDefinedValueTypeI,
126
+ );
127
+ if (collected !== undefined) {
128
+ results.push(collected);
129
+ }
130
+ }
131
+ }
132
+ }
133
+ }
134
+
135
+ return results;
136
+ }
137
+
138
+ function collectStruct(
139
+ node: Record<string, unknown>,
140
+ sourcePath: string,
141
+ userDefinedValueTypeI: UserDefinedValueTypeIndex,
142
+ ): CollectedStruct | undefined {
143
+ if (typeof node.name !== "string") {
144
+ return undefined;
145
+ }
146
+
147
+ const memberNodes: unknown[] = Array.isArray(node.members)
148
+ ? node.members
149
+ : [];
150
+ const members: StructMember[] = [];
151
+
152
+ for (const memberNode of memberNodes) {
153
+ if (
154
+ !isObject(memberNode) ||
155
+ memberNode.nodeType !== "VariableDeclaration"
156
+ ) {
157
+ continue;
158
+ }
159
+
160
+ if (typeof memberNode.name !== "string") {
161
+ continue;
162
+ }
163
+
164
+ members.push({
165
+ name: memberNode.name,
166
+ type: encodeMemberType(memberNode.typeName, userDefinedValueTypeI),
167
+ });
168
+ }
169
+
170
+ return {
171
+ name: node.name,
172
+ members,
173
+ sourcePath,
174
+ };
175
+ }
176
+
177
+ /**
178
+ * Converts a solc `typeName` AST node into its EIP-712 type string, following
179
+ * the same conventions as `forge bind-json`:
180
+ *
181
+ * - elementary types pass through (`address`, `uint256`, `string`, ...)
182
+ * - enums → `uint8`
183
+ * - contracts / interfaces → `address`
184
+ * - structs → bare name (`Wallet.Person` → `Person`)
185
+ * - user-defined value types → underlying elementary type (`type Foo is bytes32` → `bytes32`)
186
+ * - arrays → `T[]` (dynamic) or `T[N]` (fixed)
187
+ * - mappings / functions → `undefined` (not EIP-712 encodable)
188
+ */
189
+ export function encodeMemberType(
190
+ typeName: unknown,
191
+ userDefinedValueTypeI: UserDefinedValueTypeIndex = new Map(),
192
+ ): string | undefined {
193
+ if (!isObject(typeName)) {
194
+ return undefined;
195
+ }
196
+
197
+ switch (typeName.nodeType) {
198
+ case "ElementaryTypeName": {
199
+ // Prefer `typeDescriptions.typeString` over `name`: solc emits the
200
+ // unresolved alias in `name` (`uint`, `int`, `byte`), but the canonical
201
+ // EIP-712 type is in `typeString` (`uint256`, `int256`, `bytes1`).
202
+ // `address payable` is the exception — `typeString` is `"address payable"`
203
+ // while the canonical EIP-712 type is just `address`.
204
+ const desc = isObject(typeName.typeDescriptions)
205
+ ? typeName.typeDescriptions
206
+ : undefined;
207
+ const typeString =
208
+ typeof desc?.typeString === "string" ? desc.typeString : undefined;
209
+ if (typeString !== undefined) {
210
+ return typeString.endsWith(" payable")
211
+ ? typeString.slice(0, -" payable".length)
212
+ : typeString;
213
+ }
214
+
215
+ return typeof typeName.name === "string" ? typeName.name : undefined;
216
+ }
217
+
218
+ case "UserDefinedTypeName": {
219
+ // `typeDescriptions.typeString` is the only reliable way to tell what
220
+ // kind of user-defined type this is — e.g. "struct Foo", "enum Bar",
221
+ // "contract Token". The AST node itself doesn't say. Note that solc
222
+ // emits the "contract " prefix for interface references as well.
223
+ const desc = isObject(typeName.typeDescriptions)
224
+ ? typeName.typeDescriptions
225
+ : undefined;
226
+ const typeString =
227
+ typeof desc?.typeString === "string" ? desc.typeString : "";
228
+
229
+ if (typeString.startsWith("enum ")) {
230
+ return "uint8";
231
+ }
232
+
233
+ if (typeString.startsWith("contract ")) {
234
+ return "address";
235
+ }
236
+
237
+ if (typeString.startsWith("struct ")) {
238
+ // EIP-712 references structs by their bare name, so strip both the
239
+ // "struct " prefix, any storage-location suffix solc may append
240
+ // ("memory", "storage", ...), and any qualifier ("Wallet.Person").
241
+ const remainder = typeString.slice("struct ".length).trim();
242
+ const namePart = remainder.split(/\s+/)[0];
243
+ const segments = namePart.split(".");
244
+ return segments[segments.length - 1];
245
+ }
246
+
247
+ // User-defined value types (`type Foo is bytes32;`, solc 0.8.8+).
248
+ // Resolve via `referencedDeclaration` against the build-wide
249
+ // user-defined value type index
250
+ // and recurse on the underlying elementary type — matching forge's
251
+ // `Resolver::resolve_type` so `Foo h` encodes as `bytes32 h`, not `Foo h`.
252
+ const refId =
253
+ typeof typeName.referencedDeclaration === "number"
254
+ ? typeName.referencedDeclaration
255
+ : isObject(typeName.pathNode) &&
256
+ typeof typeName.pathNode.referencedDeclaration === "number"
257
+ ? typeName.pathNode.referencedDeclaration
258
+ : undefined;
259
+
260
+ if (refId !== undefined) {
261
+ const underlying = userDefinedValueTypeI.get(refId);
262
+ if (underlying !== undefined) {
263
+ return encodeMemberType(underlying, userDefinedValueTypeI);
264
+ }
265
+ }
266
+
267
+ // Fallback when the reference can't be resolved (missing
268
+ // `referencedDeclaration`, or its definition wasn't in the build).
269
+ // Emitting the name lets the downstream encoder produce a clear error
270
+ // rather than failing silently here.
271
+ if (typeof typeName.name === "string") {
272
+ return typeName.name;
273
+ }
274
+
275
+ if (
276
+ isObject(typeName.pathNode) &&
277
+ typeof typeName.pathNode.name === "string"
278
+ ) {
279
+ const segments = typeName.pathNode.name.split(".");
280
+ return segments[segments.length - 1];
281
+ }
282
+
283
+ return undefined;
284
+ }
285
+
286
+ case "ArrayTypeName": {
287
+ const base = encodeMemberType(typeName.baseType, userDefinedValueTypeI);
288
+ if (base === undefined) {
289
+ return undefined;
290
+ }
291
+
292
+ // solc omits `length` entirely for dynamic arrays; it isn't emitted as `null`.
293
+ const length = typeName.length;
294
+ if (length === null || length === undefined) {
295
+ return `${base}[]`;
296
+ }
297
+
298
+ // Always read from typeString: `Literal.value` preserves source text
299
+ // (`0x100`, `1_000`) but typeString canonicalizes to decimal.
300
+ const desc = isObject(typeName.typeDescriptions)
301
+ ? typeName.typeDescriptions
302
+ : undefined;
303
+ const typeString =
304
+ typeof desc?.typeString === "string" ? desc.typeString : "";
305
+ const match = /\[(\d+)\]$/.exec(typeString);
306
+
307
+ if (match !== null) {
308
+ return `${base}[${match[1]}]`;
309
+ }
310
+
311
+ return undefined;
312
+ }
313
+
314
+ case "Mapping":
315
+ return undefined;
316
+
317
+ case "FunctionTypeName":
318
+ // EIP-712 can't encode function types.
319
+ return undefined;
320
+
321
+ default:
322
+ return undefined;
323
+ }
324
+ }