hardhat 3.2.0 → 3.3.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 (248) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/dist/src/internal/builtin-global-options.d.ts.map +1 -1
  3. package/dist/src/internal/builtin-global-options.js +14 -1
  4. package/dist/src/internal/builtin-global-options.js.map +1 -1
  5. package/dist/src/internal/builtin-plugins/gas-analytics/helpers.d.ts +0 -5
  6. package/dist/src/internal/builtin-plugins/gas-analytics/helpers.d.ts.map +1 -1
  7. package/dist/src/internal/builtin-plugins/gas-analytics/helpers.js +12 -3
  8. package/dist/src/internal/builtin-plugins/gas-analytics/helpers.js.map +1 -1
  9. package/dist/src/internal/builtin-plugins/network-manager/accounts/derive-private-keys.d.ts.map +1 -1
  10. package/dist/src/internal/builtin-plugins/network-manager/accounts/derive-private-keys.js +12 -2
  11. package/dist/src/internal/builtin-plugins/network-manager/accounts/derive-private-keys.js.map +1 -1
  12. package/dist/src/internal/builtin-plugins/network-manager/edr/edr-provider.d.ts +9 -3
  13. package/dist/src/internal/builtin-plugins/network-manager/edr/edr-provider.d.ts.map +1 -1
  14. package/dist/src/internal/builtin-plugins/network-manager/edr/edr-provider.js +65 -42
  15. package/dist/src/internal/builtin-plugins/network-manager/edr/edr-provider.js.map +1 -1
  16. package/dist/src/internal/builtin-plugins/network-manager/edr/genesis-state.d.ts +11 -0
  17. package/dist/src/internal/builtin-plugins/network-manager/edr/genesis-state.d.ts.map +1 -0
  18. package/dist/src/internal/builtin-plugins/network-manager/edr/genesis-state.js +104 -0
  19. package/dist/src/internal/builtin-plugins/network-manager/edr/genesis-state.js.map +1 -0
  20. package/dist/src/internal/builtin-plugins/network-manager/edr/utils/trace-formatters.d.ts +6 -0
  21. package/dist/src/internal/builtin-plugins/network-manager/edr/utils/trace-formatters.d.ts.map +1 -0
  22. package/dist/src/internal/builtin-plugins/network-manager/edr/utils/trace-formatters.js +152 -0
  23. package/dist/src/internal/builtin-plugins/network-manager/edr/utils/trace-formatters.js.map +1 -0
  24. package/dist/src/internal/builtin-plugins/network-manager/edr/utils/trace-output.d.ts +19 -0
  25. package/dist/src/internal/builtin-plugins/network-manager/edr/utils/trace-output.d.ts.map +1 -0
  26. package/dist/src/internal/builtin-plugins/network-manager/edr/utils/trace-output.js +104 -0
  27. package/dist/src/internal/builtin-plugins/network-manager/edr/utils/trace-output.js.map +1 -0
  28. package/dist/src/internal/builtin-plugins/network-manager/hook-handlers/hre.js +1 -1
  29. package/dist/src/internal/builtin-plugins/network-manager/hook-handlers/hre.js.map +1 -1
  30. package/dist/src/internal/builtin-plugins/network-manager/hook-handlers/network.d.ts.map +1 -1
  31. package/dist/src/internal/builtin-plugins/network-manager/hook-handlers/network.js +8 -8
  32. package/dist/src/internal/builtin-plugins/network-manager/hook-handlers/network.js.map +1 -1
  33. package/dist/src/internal/builtin-plugins/network-manager/http-provider.d.ts.map +1 -1
  34. package/dist/src/internal/builtin-plugins/network-manager/http-provider.js +1 -0
  35. package/dist/src/internal/builtin-plugins/network-manager/http-provider.js.map +1 -1
  36. package/dist/src/internal/builtin-plugins/network-manager/network-manager.d.ts +1 -1
  37. package/dist/src/internal/builtin-plugins/network-manager/network-manager.d.ts.map +1 -1
  38. package/dist/src/internal/builtin-plugins/network-manager/network-manager.js +63 -7
  39. package/dist/src/internal/builtin-plugins/network-manager/network-manager.js.map +1 -1
  40. package/dist/src/internal/builtin-plugins/network-manager/request-handlers/handlers/accounts/local-accounts.d.ts.map +1 -1
  41. package/dist/src/internal/builtin-plugins/network-manager/request-handlers/handlers/accounts/local-accounts.js +56 -33
  42. package/dist/src/internal/builtin-plugins/network-manager/request-handlers/handlers/accounts/local-accounts.js.map +1 -1
  43. package/dist/src/internal/builtin-plugins/network-manager/request-handlers/handlers-array.d.ts +0 -3
  44. package/dist/src/internal/builtin-plugins/network-manager/request-handlers/handlers-array.d.ts.map +1 -1
  45. package/dist/src/internal/builtin-plugins/network-manager/request-handlers/handlers-array.js +9 -12
  46. package/dist/src/internal/builtin-plugins/network-manager/request-handlers/handlers-array.js.map +1 -1
  47. package/dist/src/internal/builtin-plugins/node/artifacts/build-info-watcher.d.ts.map +1 -1
  48. package/dist/src/internal/builtin-plugins/node/artifacts/build-info-watcher.js +1 -1
  49. package/dist/src/internal/builtin-plugins/node/artifacts/build-info-watcher.js.map +1 -1
  50. package/dist/src/internal/builtin-plugins/node/helpers.d.ts.map +1 -1
  51. package/dist/src/internal/builtin-plugins/node/helpers.js +6 -2
  52. package/dist/src/internal/builtin-plugins/node/helpers.js.map +1 -1
  53. package/dist/src/internal/builtin-plugins/solidity/build-system/artifacts.d.ts.map +1 -1
  54. package/dist/src/internal/builtin-plugins/solidity/build-system/artifacts.js +4 -0
  55. package/dist/src/internal/builtin-plugins/solidity/build-system/artifacts.js.map +1 -1
  56. package/dist/src/internal/builtin-plugins/solidity/build-system/build-system.d.ts +5 -1
  57. package/dist/src/internal/builtin-plugins/solidity/build-system/build-system.d.ts.map +1 -1
  58. package/dist/src/internal/builtin-plugins/solidity/build-system/build-system.js +86 -47
  59. package/dist/src/internal/builtin-plugins/solidity/build-system/build-system.js.map +1 -1
  60. package/dist/src/internal/builtin-plugins/solidity/build-system/cache.d.ts +1 -0
  61. package/dist/src/internal/builtin-plugins/solidity/build-system/cache.d.ts.map +1 -1
  62. package/dist/src/internal/builtin-plugins/solidity/build-system/cache.js.map +1 -1
  63. package/dist/src/internal/builtin-plugins/solidity/build-system/compilation-job.d.ts +3 -3
  64. package/dist/src/internal/builtin-plugins/solidity/build-system/compilation-job.d.ts.map +1 -1
  65. package/dist/src/internal/builtin-plugins/solidity/build-system/compilation-job.js +24 -4
  66. package/dist/src/internal/builtin-plugins/solidity/build-system/compilation-job.js.map +1 -1
  67. package/dist/src/internal/builtin-plugins/solidity/build-system/compiler/compiler.d.ts +16 -0
  68. package/dist/src/internal/builtin-plugins/solidity/build-system/compiler/compiler.d.ts.map +1 -1
  69. package/dist/src/internal/builtin-plugins/solidity/build-system/compiler/compiler.js +1 -1
  70. package/dist/src/internal/builtin-plugins/solidity/build-system/compiler/compiler.js.map +1 -1
  71. package/dist/src/internal/builtin-plugins/solidity/build-system/compiler/downloader.d.ts.map +1 -1
  72. package/dist/src/internal/builtin-plugins/solidity/build-system/compiler/downloader.js +1 -1
  73. package/dist/src/internal/builtin-plugins/solidity/build-system/compiler/downloader.js.map +1 -1
  74. package/dist/src/internal/builtin-plugins/solidity/build-system/solc-config-selection.d.ts +2 -2
  75. package/dist/src/internal/builtin-plugins/solidity/build-system/solc-config-selection.d.ts.map +1 -1
  76. package/dist/src/internal/builtin-plugins/solidity/build-system/solc-config-selection.js.map +1 -1
  77. package/dist/src/internal/builtin-plugins/solidity/config.d.ts +4 -2
  78. package/dist/src/internal/builtin-plugins/solidity/config.d.ts.map +1 -1
  79. package/dist/src/internal/builtin-plugins/solidity/config.js +247 -68
  80. package/dist/src/internal/builtin-plugins/solidity/config.js.map +1 -1
  81. package/dist/src/internal/builtin-plugins/solidity/exports.d.ts +3 -0
  82. package/dist/src/internal/builtin-plugins/solidity/exports.d.ts.map +1 -0
  83. package/dist/src/internal/builtin-plugins/solidity/exports.js +3 -0
  84. package/dist/src/internal/builtin-plugins/solidity/exports.js.map +1 -0
  85. package/dist/src/internal/builtin-plugins/solidity/hook-handlers/config.d.ts.map +1 -1
  86. package/dist/src/internal/builtin-plugins/solidity/hook-handlers/config.js +2 -1
  87. package/dist/src/internal/builtin-plugins/solidity/hook-handlers/config.js.map +1 -1
  88. package/dist/src/internal/builtin-plugins/solidity/hook-handlers/solidity.d.ts +4 -0
  89. package/dist/src/internal/builtin-plugins/solidity/hook-handlers/solidity.d.ts.map +1 -0
  90. package/dist/src/internal/builtin-plugins/solidity/hook-handlers/solidity.js +7 -0
  91. package/dist/src/internal/builtin-plugins/solidity/hook-handlers/solidity.js.map +1 -0
  92. package/dist/src/internal/builtin-plugins/solidity/index.d.ts.map +1 -1
  93. package/dist/src/internal/builtin-plugins/solidity/index.js +1 -0
  94. package/dist/src/internal/builtin-plugins/solidity/index.js.map +1 -1
  95. package/dist/src/internal/builtin-plugins/solidity/solidity-hooks.d.ts +18 -0
  96. package/dist/src/internal/builtin-plugins/solidity/solidity-hooks.d.ts.map +1 -0
  97. package/dist/src/internal/builtin-plugins/solidity/solidity-hooks.js +33 -0
  98. package/dist/src/internal/builtin-plugins/solidity/solidity-hooks.js.map +1 -0
  99. package/dist/src/internal/builtin-plugins/solidity/type-extensions.d.ts +201 -28
  100. package/dist/src/internal/builtin-plugins/solidity/type-extensions.d.ts.map +1 -1
  101. package/dist/src/internal/builtin-plugins/solidity/type-extensions.js.map +1 -1
  102. package/dist/src/internal/builtin-plugins/solidity-test/edr-artifacts.d.ts +12 -6
  103. package/dist/src/internal/builtin-plugins/solidity-test/edr-artifacts.d.ts.map +1 -1
  104. package/dist/src/internal/builtin-plugins/solidity-test/edr-artifacts.js +9 -7
  105. package/dist/src/internal/builtin-plugins/solidity-test/edr-artifacts.js.map +1 -1
  106. package/dist/src/internal/builtin-plugins/solidity-test/formatters.d.ts +1 -12
  107. package/dist/src/internal/builtin-plugins/solidity-test/formatters.d.ts.map +1 -1
  108. package/dist/src/internal/builtin-plugins/solidity-test/formatters.js +0 -150
  109. package/dist/src/internal/builtin-plugins/solidity-test/formatters.js.map +1 -1
  110. package/dist/src/internal/builtin-plugins/solidity-test/helpers.d.ts +4 -3
  111. package/dist/src/internal/builtin-plugins/solidity-test/helpers.d.ts.map +1 -1
  112. package/dist/src/internal/builtin-plugins/solidity-test/helpers.js +5 -9
  113. package/dist/src/internal/builtin-plugins/solidity-test/helpers.js.map +1 -1
  114. package/dist/src/internal/builtin-plugins/solidity-test/index.d.ts.map +1 -1
  115. package/dist/src/internal/builtin-plugins/solidity-test/index.js +0 -7
  116. package/dist/src/internal/builtin-plugins/solidity-test/index.js.map +1 -1
  117. package/dist/src/internal/builtin-plugins/solidity-test/inline-config/constants.d.ts +7 -0
  118. package/dist/src/internal/builtin-plugins/solidity-test/inline-config/constants.d.ts.map +1 -0
  119. package/dist/src/internal/builtin-plugins/solidity-test/inline-config/constants.js +20 -0
  120. package/dist/src/internal/builtin-plugins/solidity-test/inline-config/constants.js.map +1 -0
  121. package/dist/src/internal/builtin-plugins/solidity-test/inline-config/helpers.d.ts +24 -0
  122. package/dist/src/internal/builtin-plugins/solidity-test/inline-config/helpers.d.ts.map +1 -0
  123. package/dist/src/internal/builtin-plugins/solidity-test/inline-config/helpers.js +68 -0
  124. package/dist/src/internal/builtin-plugins/solidity-test/inline-config/helpers.js.map +1 -0
  125. package/dist/src/internal/builtin-plugins/solidity-test/inline-config/index.d.ts +13 -0
  126. package/dist/src/internal/builtin-plugins/solidity-test/inline-config/index.d.ts.map +1 -0
  127. package/dist/src/internal/builtin-plugins/solidity-test/inline-config/index.js +136 -0
  128. package/dist/src/internal/builtin-plugins/solidity-test/inline-config/index.js.map +1 -0
  129. package/dist/src/internal/builtin-plugins/solidity-test/inline-config/parsing.d.ts +19 -0
  130. package/dist/src/internal/builtin-plugins/solidity-test/inline-config/parsing.d.ts.map +1 -0
  131. package/dist/src/internal/builtin-plugins/solidity-test/inline-config/parsing.js +133 -0
  132. package/dist/src/internal/builtin-plugins/solidity-test/inline-config/parsing.js.map +1 -0
  133. package/dist/src/internal/builtin-plugins/solidity-test/inline-config/types.d.ts +10 -0
  134. package/dist/src/internal/builtin-plugins/solidity-test/inline-config/types.d.ts.map +1 -0
  135. package/dist/src/internal/builtin-plugins/solidity-test/inline-config/types.js +2 -0
  136. package/dist/src/internal/builtin-plugins/solidity-test/inline-config/types.js.map +1 -0
  137. package/dist/src/internal/builtin-plugins/solidity-test/inline-config/validation.d.ts +12 -0
  138. package/dist/src/internal/builtin-plugins/solidity-test/inline-config/validation.d.ts.map +1 -0
  139. package/dist/src/internal/builtin-plugins/solidity-test/inline-config/validation.js +81 -0
  140. package/dist/src/internal/builtin-plugins/solidity-test/inline-config/validation.js.map +1 -0
  141. package/dist/src/internal/builtin-plugins/solidity-test/reporter.d.ts +1 -1
  142. package/dist/src/internal/builtin-plugins/solidity-test/reporter.d.ts.map +1 -1
  143. package/dist/src/internal/builtin-plugins/solidity-test/reporter.js +5 -2
  144. package/dist/src/internal/builtin-plugins/solidity-test/reporter.js.map +1 -1
  145. package/dist/src/internal/builtin-plugins/solidity-test/task-action.d.ts +0 -1
  146. package/dist/src/internal/builtin-plugins/solidity-test/task-action.d.ts.map +1 -1
  147. package/dist/src/internal/builtin-plugins/solidity-test/task-action.js +21 -14
  148. package/dist/src/internal/builtin-plugins/solidity-test/task-action.js.map +1 -1
  149. package/dist/src/internal/builtin-plugins/test/index.d.ts.map +1 -1
  150. package/dist/src/internal/builtin-plugins/test/index.js +0 -7
  151. package/dist/src/internal/builtin-plugins/test/index.js.map +1 -1
  152. package/dist/src/internal/builtin-plugins/test/task-action.d.ts +0 -1
  153. package/dist/src/internal/builtin-plugins/test/task-action.d.ts.map +1 -1
  154. package/dist/src/internal/builtin-plugins/test/task-action.js +1 -4
  155. package/dist/src/internal/builtin-plugins/test/task-action.js.map +1 -1
  156. package/dist/src/internal/cli/help/get-help-string.d.ts.map +1 -1
  157. package/dist/src/internal/cli/help/get-help-string.js +1 -1
  158. package/dist/src/internal/cli/help/get-help-string.js.map +1 -1
  159. package/dist/src/internal/cli/init/init.d.ts.map +1 -1
  160. package/dist/src/internal/cli/init/init.js +1 -1
  161. package/dist/src/internal/cli/init/init.js.map +1 -1
  162. package/dist/src/internal/cli/init/prompt.d.ts.map +1 -1
  163. package/dist/src/internal/cli/init/prompt.js +1 -7
  164. package/dist/src/internal/cli/init/prompt.js.map +1 -1
  165. package/dist/src/internal/core/hre.d.ts +2 -1
  166. package/dist/src/internal/core/hre.d.ts.map +1 -1
  167. package/dist/src/internal/core/hre.js +18 -0
  168. package/dist/src/internal/core/hre.js.map +1 -1
  169. package/dist/src/internal/core/plugins/detect-plugin-npm-dependency-problems.d.ts.map +1 -1
  170. package/dist/src/internal/core/plugins/detect-plugin-npm-dependency-problems.js +6 -1
  171. package/dist/src/internal/core/plugins/detect-plugin-npm-dependency-problems.js.map +1 -1
  172. package/dist/src/internal/core/user-interruptions.d.ts.map +1 -1
  173. package/dist/src/internal/core/user-interruptions.js +2 -5
  174. package/dist/src/internal/core/user-interruptions.js.map +1 -1
  175. package/dist/src/internal/utils/colorizer.d.ts +10 -0
  176. package/dist/src/internal/utils/colorizer.d.ts.map +1 -0
  177. package/dist/src/internal/utils/colorizer.js +2 -0
  178. package/dist/src/internal/utils/colorizer.js.map +1 -0
  179. package/dist/src/internal/utils/package.d.ts.map +1 -1
  180. package/dist/src/internal/utils/package.js +1 -1
  181. package/dist/src/internal/utils/package.js.map +1 -1
  182. package/dist/src/types/global-options.d.ts +1 -0
  183. package/dist/src/types/global-options.d.ts.map +1 -1
  184. package/dist/src/types/hooks.d.ts +32 -0
  185. package/dist/src/types/hooks.d.ts.map +1 -1
  186. package/dist/src/types/solidity/compilation-job.d.ts +5 -5
  187. package/dist/src/types/solidity/compilation-job.d.ts.map +1 -1
  188. package/dist/src/types/solidity/solidity-artifacts.d.ts +15 -0
  189. package/dist/src/types/solidity/solidity-artifacts.d.ts.map +1 -1
  190. package/package.json +6 -5
  191. package/src/internal/builtin-global-options.ts +15 -1
  192. package/src/internal/builtin-plugins/gas-analytics/helpers.ts +13 -3
  193. package/src/internal/builtin-plugins/network-manager/accounts/derive-private-keys.ts +25 -3
  194. package/src/internal/builtin-plugins/network-manager/edr/edr-provider.ts +107 -56
  195. package/src/internal/builtin-plugins/network-manager/edr/genesis-state.ts +179 -0
  196. package/src/internal/builtin-plugins/network-manager/edr/utils/trace-formatters.ts +197 -0
  197. package/src/internal/builtin-plugins/network-manager/edr/utils/trace-output.ts +137 -0
  198. package/src/internal/builtin-plugins/network-manager/hook-handlers/hre.ts +1 -0
  199. package/src/internal/builtin-plugins/network-manager/hook-handlers/network.ts +8 -11
  200. package/src/internal/builtin-plugins/network-manager/http-provider.ts +1 -0
  201. package/src/internal/builtin-plugins/network-manager/network-manager.ts +83 -10
  202. package/src/internal/builtin-plugins/network-manager/request-handlers/handlers/accounts/local-accounts.ts +98 -34
  203. package/src/internal/builtin-plugins/network-manager/request-handlers/handlers-array.ts +10 -30
  204. package/src/internal/builtin-plugins/node/artifacts/build-info-watcher.ts +1 -2
  205. package/src/internal/builtin-plugins/node/helpers.ts +9 -2
  206. package/src/internal/builtin-plugins/solidity/build-system/artifacts.ts +7 -2
  207. package/src/internal/builtin-plugins/solidity/build-system/build-system.ts +141 -65
  208. package/src/internal/builtin-plugins/solidity/build-system/cache.ts +1 -0
  209. package/src/internal/builtin-plugins/solidity/build-system/compilation-job.ts +34 -7
  210. package/src/internal/builtin-plugins/solidity/build-system/compiler/compiler.ts +1 -1
  211. package/src/internal/builtin-plugins/solidity/build-system/compiler/downloader.ts +1 -2
  212. package/src/internal/builtin-plugins/solidity/build-system/solc-config-selection.ts +4 -2
  213. package/src/internal/builtin-plugins/solidity/config.ts +335 -110
  214. package/src/internal/builtin-plugins/solidity/exports.ts +2 -0
  215. package/src/internal/builtin-plugins/solidity/hook-handlers/config.ts +3 -0
  216. package/src/internal/builtin-plugins/solidity/hook-handlers/solidity.ts +9 -0
  217. package/src/internal/builtin-plugins/solidity/index.ts +1 -0
  218. package/src/internal/builtin-plugins/solidity/solidity-hooks.ts +53 -0
  219. package/src/internal/builtin-plugins/solidity/type-extensions.ts +258 -31
  220. package/src/internal/builtin-plugins/solidity-test/edr-artifacts.ts +22 -10
  221. package/src/internal/builtin-plugins/solidity-test/formatters.ts +1 -213
  222. package/src/internal/builtin-plugins/solidity-test/helpers.ts +8 -8
  223. package/src/internal/builtin-plugins/solidity-test/index.ts +0 -7
  224. package/src/internal/builtin-plugins/solidity-test/inline-config/constants.ts +21 -0
  225. package/src/internal/builtin-plugins/solidity-test/inline-config/helpers.ts +99 -0
  226. package/src/internal/builtin-plugins/solidity-test/inline-config/index.ts +272 -0
  227. package/src/internal/builtin-plugins/solidity-test/inline-config/parsing.ts +186 -0
  228. package/src/internal/builtin-plugins/solidity-test/inline-config/types.ts +9 -0
  229. package/src/internal/builtin-plugins/solidity-test/inline-config/validation.ts +122 -0
  230. package/src/internal/builtin-plugins/solidity-test/reporter.ts +6 -6
  231. package/src/internal/builtin-plugins/solidity-test/task-action.ts +42 -25
  232. package/src/internal/builtin-plugins/test/index.ts +0 -7
  233. package/src/internal/builtin-plugins/test/task-action.ts +1 -6
  234. package/src/internal/cli/help/get-help-string.ts +2 -2
  235. package/src/internal/cli/init/init.ts +1 -1
  236. package/src/internal/cli/init/prompt.ts +1 -14
  237. package/src/internal/core/hre.ts +33 -0
  238. package/src/internal/core/plugins/detect-plugin-npm-dependency-problems.ts +8 -1
  239. package/src/internal/core/user-interruptions.ts +3 -5
  240. package/src/internal/utils/colorizer.ts +9 -0
  241. package/src/internal/utils/package.ts +1 -2
  242. package/src/types/global-options.ts +1 -0
  243. package/src/types/hooks.ts +37 -0
  244. package/src/types/solidity/compilation-job.ts +5 -5
  245. package/src/types/solidity/solidity-artifacts.ts +16 -0
  246. package/templates/hardhat-3/01-node-test-runner-viem/package.json +5 -5
  247. package/templates/hardhat-3/02-mocha-ethers/package.json +11 -11
  248. package/templates/hardhat-3/03-minimal/package.json +1 -1
@@ -15,23 +15,17 @@ import type {
15
15
  import type { RequireField } from "../../../../types/utils.js";
16
16
  import type { DefaultHDAccountsConfigParams } from "../accounts/constants.js";
17
17
  import type { JsonRpcRequestWrapperFunction } from "../network-manager.js";
18
+ import type { TraceOutputManager } from "./utils/trace-output.js";
18
19
  import type {
19
20
  SubscriptionEvent,
20
21
  Response,
21
22
  Provider,
22
23
  ProviderConfig,
23
24
  TracingConfigWithBuffers,
24
- AccountOverride,
25
25
  GasReportConfig,
26
26
  } from "@nomicfoundation/edr";
27
27
 
28
- import {
29
- opGenesisState,
30
- opHardforkFromString,
31
- l1GenesisState,
32
- l1HardforkFromString,
33
- ContractDecoder,
34
- } from "@nomicfoundation/edr";
28
+ import { ContractDecoder, IncludeTraces } from "@nomicfoundation/edr";
35
29
  import {
36
30
  assertHardhatInvariant,
37
31
  HardhatError,
@@ -41,14 +35,9 @@ import { ensureError } from "@nomicfoundation/hardhat-utils/error";
41
35
  import { numberToHexString } from "@nomicfoundation/hardhat-utils/hex";
42
36
  import { deepEqual } from "@nomicfoundation/hardhat-utils/lang";
43
37
  import debug from "debug";
44
- import { hexToBytes } from "ethereum-cryptography/utils";
45
- import { addr } from "micro-eth-signer";
46
38
 
47
39
  import { sendErrorTelemetry } from "../../../cli/telemetry/sentry/reporter.js";
48
- import {
49
- EDR_NETWORK_REVERT_SNAPSHOT_EVENT,
50
- OPTIMISM_CHAIN_TYPE,
51
- } from "../../../constants.js";
40
+ import { EDR_NETWORK_REVERT_SNAPSHOT_EVENT } from "../../../constants.js";
52
41
  import { hardhatChainTypeToEdrChainType } from "../../../edr/chain-type.js";
53
42
  import { getGlobalEdrContext } from "../../../edr/context.js";
54
43
  import { DEFAULT_HD_ACCOUNTS_CONFIG_PARAMS } from "../accounts/constants.js";
@@ -60,6 +49,7 @@ import {
60
49
  UnknownError,
61
50
  } from "../provider-errors.js";
62
51
 
52
+ import { getGenesisStateAndOwnedAccounts } from "./genesis-state.js";
63
53
  import { EdrProviderStackTraceGenerationError } from "./stack-traces/stack-trace-generation-errors.js";
64
54
  import { createSolidityErrorWithStackTrace } from "./stack-traces/stack-trace-solidity-errors.js";
65
55
  import { isEdrProviderErrorData } from "./type-validation.js";
@@ -69,7 +59,6 @@ import {
69
59
  hardhatMiningIntervalToEdrMiningInterval,
70
60
  hardhatMempoolOrderToEdrMineOrdering,
71
61
  hardhatHardforkToEdrSpecId,
72
- hardhatAccountsToEdrOwnedAccounts,
73
62
  hardhatForkingConfigToEdrForkConfig,
74
63
  } from "./utils/convert-to-edr.js";
75
64
  import { printLine, replaceLastLine } from "./utils/logger.js";
@@ -135,10 +124,14 @@ interface EdrProviderConfig {
135
124
  chainDescriptors: ChainDescriptorsConfig;
136
125
  networkConfig: RequireField<EdrNetworkConfig, "chainType">;
137
126
  loggerConfig?: LoggerConfig;
138
- tracingConfig?: TracingConfigWithBuffers;
127
+ contractDecoder: ContractDecoder;
139
128
  jsonRpcRequestWrapper?: JsonRpcRequestWrapperFunction;
140
129
  coverageConfig?: CoverageConfig;
141
130
  gasReportConfig?: GasReportConfig;
131
+ includeCallTraces?: IncludeTraces;
132
+ connectionId: number;
133
+ networkName: string;
134
+ verbosity: number;
142
135
  }
143
136
 
144
137
  export class EdrProvider extends BaseProvider {
@@ -146,6 +139,13 @@ export class EdrProvider extends BaseProvider {
146
139
 
147
140
  #provider: Provider | undefined;
148
141
  #nextRequestId = 1;
142
+ readonly #traceOutput: TraceOutputManager | undefined;
143
+
144
+ public static async createContractDecoder(
145
+ tracingConfig: TracingConfigWithBuffers,
146
+ ): Promise<ContractDecoder> {
147
+ return ContractDecoder.withContracts(tracingConfig);
148
+ }
149
149
 
150
150
  /**
151
151
  * Creates a new instance of `EdrProvider`.
@@ -154,10 +154,14 @@ export class EdrProvider extends BaseProvider {
154
154
  chainDescriptors,
155
155
  networkConfig,
156
156
  loggerConfig = { enabled: false },
157
- tracingConfig = {},
157
+ contractDecoder,
158
158
  jsonRpcRequestWrapper,
159
159
  coverageConfig,
160
160
  gasReportConfig,
161
+ includeCallTraces,
162
+ verbosity,
163
+ connectionId,
164
+ networkName,
161
165
  }: EdrProviderConfig): Promise<EdrProvider> {
162
166
  const printLineFn = loggerConfig.printLineFn ?? printLine;
163
167
  const replaceLastLineFn = loggerConfig.replaceLastLineFn ?? replaceLastLine;
@@ -167,15 +171,18 @@ export class EdrProvider extends BaseProvider {
167
171
  coverageConfig,
168
172
  gasReportConfig,
169
173
  chainDescriptors,
174
+ includeCallTraces,
170
175
  );
171
176
 
172
177
  let edrProvider: EdrProvider;
173
178
 
179
+ // We use a WeakRef to the provider to prevent the subscriptionCallback
180
+ // below from creating a cycle and leaking the provider.
181
+ let edrProviderWeakRef: WeakRef<EdrProvider> | undefined;
182
+
174
183
  // We need to catch errors here, as the provider creation can panic unexpectedly,
175
184
  // and we want to make sure such a crash is propagated as a ProviderError.
176
185
  try {
177
- const contractDecoder = ContractDecoder.withContracts(tracingConfig);
178
-
179
186
  const context = await getGlobalEdrContext();
180
187
  const provider = await context.createProvider(
181
188
  hardhatChainTypeToEdrChainType(networkConfig.chainType),
@@ -199,13 +206,38 @@ export class EdrProvider extends BaseProvider {
199
206
  },
200
207
  {
201
208
  subscriptionCallback: (event: SubscriptionEvent) => {
202
- edrProvider.onSubscriptionEvent(event);
209
+ const deferredProvider = edrProviderWeakRef?.deref();
210
+ if (deferredProvider !== undefined) {
211
+ deferredProvider.onSubscriptionEvent(event);
212
+ }
203
213
  },
204
214
  },
205
215
  contractDecoder,
206
216
  );
207
217
 
208
- edrProvider = new EdrProvider(provider, jsonRpcRequestWrapper);
218
+ const tracesEnabled =
219
+ includeCallTraces !== undefined &&
220
+ includeCallTraces !== IncludeTraces.None;
221
+
222
+ let traceOutput: TraceOutputManager | undefined;
223
+ if (tracesEnabled) {
224
+ const { TraceOutputManager: TraceOutputManagerImpl } = await import(
225
+ "./utils/trace-output.js"
226
+ );
227
+ traceOutput = new TraceOutputManagerImpl(
228
+ printLineFn,
229
+ connectionId,
230
+ networkName,
231
+ verbosity,
232
+ );
233
+ }
234
+
235
+ edrProvider = new EdrProvider(
236
+ provider,
237
+ traceOutput,
238
+ jsonRpcRequestWrapper,
239
+ );
240
+ edrProviderWeakRef = new WeakRef(edrProvider);
209
241
  } catch (error) {
210
242
  ensureError(error);
211
243
 
@@ -225,12 +257,22 @@ export class EdrProvider extends BaseProvider {
225
257
  */
226
258
  private constructor(
227
259
  provider: Provider,
260
+ traceOutput: TraceOutputManager | undefined,
228
261
  jsonRpcRequestWrapper?: JsonRpcRequestWrapperFunction,
229
262
  ) {
230
263
  super();
231
264
 
232
265
  this.#provider = provider;
266
+ this.#traceOutput = traceOutput;
233
267
  this.#jsonRpcRequestWrapper = jsonRpcRequestWrapper;
268
+
269
+ // After a snapshot revert, the same transactions may run again.
270
+ // Reset traced hashes so their traces are printed a second time.
271
+ if (this.#traceOutput !== undefined) {
272
+ this.on(EDR_NETWORK_REVERT_SNAPSHOT_EVENT, () => {
273
+ this.#traceOutput?.clearTracedHashes();
274
+ });
275
+ }
234
276
  }
235
277
 
236
278
  public async request(
@@ -290,8 +332,10 @@ export class EdrProvider extends BaseProvider {
290
332
  }
291
333
 
292
334
  public async close(): Promise<void> {
335
+ this.removeAllListeners();
293
336
  // Clear the provider reference to help with garbage collection
294
337
  this.#provider = undefined;
338
+ this.#traceOutput?.clearTracedHashes();
295
339
  }
296
340
 
297
341
  public async addCompilationResult(
@@ -312,8 +356,11 @@ export class EdrProvider extends BaseProvider {
312
356
 
313
357
  async #handleEdrResponse(
314
358
  edrResponse: Response,
359
+ method: string,
360
+ params?: unknown[],
315
361
  ): Promise<SuccessfulJsonRpcResponse> {
316
362
  let jsonRpcResponse: JsonRpcResponse;
363
+ let txHash: string | undefined;
317
364
 
318
365
  if (typeof edrResponse.data === "string") {
319
366
  jsonRpcResponse = JSON.parse(edrResponse.data);
@@ -325,6 +372,12 @@ export class EdrProvider extends BaseProvider {
325
372
  const responseError = jsonRpcResponse.error;
326
373
  let error;
327
374
 
375
+ // Grab the tx hash so trace deduplication can recognize this transaction later
376
+ const errorData = responseError.data;
377
+ if (isEdrProviderErrorData(errorData)) {
378
+ txHash = errorData.transactionHash;
379
+ }
380
+
328
381
  const stackTrace = edrResponse.stackTrace();
329
382
 
330
383
  if (stackTrace?.kind === "StackTrace") {
@@ -365,11 +418,33 @@ export class EdrProvider extends BaseProvider {
365
418
  error.data = responseError.data;
366
419
  }
367
420
 
421
+ this.#traceOutput?.outputCallTraces(edrResponse, method, txHash, true);
422
+
368
423
  /* eslint-disable-next-line no-restricted-syntax -- we may throw
369
424
  non-Hardhat errors inside of an EthereumProvider */
370
425
  throw error;
371
426
  }
372
427
 
428
+ if (this.#traceOutput !== undefined) {
429
+ // Output call traces for successful responses. The tx hash is resolved
430
+ // from the response/params so the trace manager can deduplicate.
431
+
432
+ if (
433
+ method === "eth_sendTransaction" ||
434
+ method === "eth_sendRawTransaction"
435
+ ) {
436
+ txHash =
437
+ typeof jsonRpcResponse.result === "string"
438
+ ? jsonRpcResponse.result
439
+ : undefined;
440
+ } else if (method === "eth_getTransactionReceipt") {
441
+ // params[0] is the tx hash being queried — used to dedup receipt polling
442
+ txHash = typeof params?.[0] === "string" ? params[0] : undefined;
443
+ }
444
+
445
+ this.#traceOutput.outputCallTraces(edrResponse, method, txHash, false);
446
+ }
447
+
373
448
  return jsonRpcResponse;
374
449
  }
375
450
 
@@ -421,7 +496,11 @@ export class EdrProvider extends BaseProvider {
421
496
  throw new UnknownError(error.message, error);
422
497
  }
423
498
 
424
- return this.#handleEdrResponse(edrResponse);
499
+ return this.#handleEdrResponse(
500
+ edrResponse,
501
+ request.method,
502
+ Array.isArray(request.params) ? request.params : undefined,
503
+ );
425
504
  }
426
505
  }
427
506
 
@@ -430,49 +509,20 @@ export async function getProviderConfig(
430
509
  coverageConfig: CoverageConfig | undefined,
431
510
  gasReportConfig: GasReportConfig | undefined,
432
511
  chainDescriptors: ChainDescriptorsConfig,
512
+ includeCallTraces?: IncludeTraces,
433
513
  ): Promise<ProviderConfig> {
434
514
  const specId = hardhatHardforkToEdrSpecId(
435
515
  networkConfig.hardfork,
436
516
  networkConfig.chainType,
437
517
  );
438
518
 
439
- const ownedAccounts = await hardhatAccountsToEdrOwnedAccounts(
519
+ const { genesisState, ownedAccounts } = await getGenesisStateAndOwnedAccounts(
440
520
  networkConfig.accounts,
521
+ networkConfig.forking,
522
+ networkConfig.chainType,
523
+ specId,
441
524
  );
442
525
 
443
- const genesisState: Map<Uint8Array, AccountOverride> = new Map(
444
- ownedAccounts.map(({ secretKey, balance }) => {
445
- const address = hexToBytes(addr.fromPrivateKey(secretKey));
446
- const accountOverride: AccountOverride = {
447
- address,
448
- balance: BigInt(balance),
449
- code: new Uint8Array(), // Empty account code, removing potential delegation code when forking
450
- };
451
-
452
- return [address, accountOverride];
453
- }),
454
- );
455
-
456
- const chainGenesisState =
457
- networkConfig.forking !== undefined
458
- ? [] // TODO: Add support for overriding remote fork state when the local fork is different
459
- : networkConfig.chainType === OPTIMISM_CHAIN_TYPE
460
- ? opGenesisState(opHardforkFromString(specId))
461
- : l1GenesisState(l1HardforkFromString(specId));
462
-
463
- for (const account of chainGenesisState) {
464
- const existingOverride = genesisState.get(account.address);
465
- if (existingOverride !== undefined) {
466
- // Favor the genesis state specified by the user
467
- account.balance = account.balance ?? existingOverride.balance;
468
- account.nonce = account.nonce ?? existingOverride.nonce;
469
- account.code = account.code ?? existingOverride.code;
470
- account.storage = account.storage ?? existingOverride.storage;
471
- } else {
472
- genesisState.set(account.address, account);
473
- }
474
- }
475
-
476
526
  return {
477
527
  allowBlocksWithSameTimestamp: networkConfig.allowBlocksWithSameTimestamp,
478
528
  allowUnlimitedContractSize: networkConfig.allowUnlimitedContractSize,
@@ -506,6 +556,7 @@ export async function getProviderConfig(
506
556
  observability: {
507
557
  codeCoverage: coverageConfig,
508
558
  gasReport: gasReportConfig,
559
+ includeCallTraces,
509
560
  },
510
561
  ownedAccounts: ownedAccounts.map((account) => account.secretKey),
511
562
  precompileOverrides: [],
@@ -0,0 +1,179 @@
1
+ import type {
2
+ EdrNetworkAccountsConfig,
3
+ EdrNetworkForkingConfig,
4
+ } from "../../../../types/config.js";
5
+ import type { ChainType } from "../../../../types/network.js";
6
+ import type * as MicroEthSignerAddressT from "micro-eth-signer/address";
7
+
8
+ import {
9
+ l1GenesisState,
10
+ l1HardforkFromString,
11
+ opGenesisState,
12
+ opHardforkFromString,
13
+ type AccountOverride,
14
+ } from "@nomicfoundation/edr";
15
+ import { AsyncMutex } from "@nomicfoundation/hardhat-utils/synchronization";
16
+ import { hexToBytes } from "ethereum-cryptography/utils";
17
+
18
+ import { OPTIMISM_CHAIN_TYPE } from "../../../constants.js";
19
+
20
+ import { hardhatAccountsToEdrOwnedAccounts } from "./utils/convert-to-edr.js";
21
+
22
+ // micro-eth-signer is known to be slow to load, so we lazy load it
23
+ let microEthSignerAddress: typeof MicroEthSignerAddressT | undefined;
24
+
25
+ const noForkingConfigCacheMarkerObject = {};
26
+
27
+ /**
28
+ * We cache the genesis state and owned accounts because computing them can be
29
+ * expensive, especially when run multiple times for the same configuration
30
+ * (e.g. when creating many EDR connections to the same network config).
31
+ *
32
+ * We use mostly references as cache keys, which means that we can miss some
33
+ * cache hits if an equivalent config is used with a different reference, but
34
+ * in practice this should rarely happen, except when using network config
35
+ * overrides that generate the same config. These cases should be the minority
36
+ * within a test suite.
37
+ *
38
+ * Note: the main reason that we don't use the entire NetworkConfig as cache
39
+ * key is that EDR initialization path recreates the NetworkConfig object to
40
+ * override some properties like `allowUnlimitedContractSize`, leading to a
41
+ * different NetworkConfig reference, despite keeping the references of most
42
+ * of its properties (including the accounts and forking config) the same.
43
+ */
44
+ const genesisStateAndAccountsCache: WeakMap<
45
+ EdrNetworkAccountsConfig,
46
+ WeakMap<
47
+ EdrNetworkForkingConfig | typeof noForkingConfigCacheMarkerObject,
48
+ Map<
49
+ ChainType,
50
+ Map<
51
+ string,
52
+ {
53
+ genesisState: Map<Uint8Array, AccountOverride>;
54
+ ownedAccounts: Array<{ secretKey: string; balance: bigint }>;
55
+ }
56
+ >
57
+ >
58
+ >
59
+ > = new WeakMap();
60
+
61
+ const genesisStateAndAccountsCacheMutex = new AsyncMutex();
62
+
63
+ export async function getGenesisStateAndOwnedAccounts(
64
+ accountsConfig: EdrNetworkAccountsConfig,
65
+ forkingConfig: EdrNetworkForkingConfig | undefined,
66
+ chainType: ChainType,
67
+ specId: string,
68
+ ): Promise<{
69
+ genesisState: Map<Uint8Array, AccountOverride>;
70
+ ownedAccounts: Array<{ secretKey: string; balance: bigint }>;
71
+ }> {
72
+ const cached = genesisStateAndAccountsCache
73
+ .get(accountsConfig)
74
+ ?.get(forkingConfig ?? noForkingConfigCacheMarkerObject)
75
+ ?.get(chainType)
76
+ ?.get(specId);
77
+
78
+ if (cached !== undefined) {
79
+ return cached;
80
+ }
81
+
82
+ return genesisStateAndAccountsCacheMutex.exclusiveRun(async () => {
83
+ // We need to check again inside the mutex callback in case another async
84
+ // operation initialized it while we were waiting to acquire the mutex
85
+ const cachedAfterWaiting = genesisStateAndAccountsCache
86
+ .get(accountsConfig)
87
+ ?.get(forkingConfig ?? noForkingConfigCacheMarkerObject)
88
+ ?.get(chainType)
89
+ ?.get(specId);
90
+
91
+ if (cachedAfterWaiting !== undefined) {
92
+ return cachedAfterWaiting;
93
+ }
94
+
95
+ const result = await createGenesisStateAndOwnedAccounts(
96
+ accountsConfig,
97
+ forkingConfig,
98
+ chainType,
99
+ specId,
100
+ );
101
+
102
+ let secondLevelCacheMap = genesisStateAndAccountsCache.get(accountsConfig);
103
+ if (secondLevelCacheMap === undefined) {
104
+ secondLevelCacheMap = new WeakMap();
105
+ genesisStateAndAccountsCache.set(accountsConfig, secondLevelCacheMap);
106
+ }
107
+
108
+ const forkingConfigCacheKey =
109
+ forkingConfig ?? noForkingConfigCacheMarkerObject;
110
+ let thirdLevelCacheMap = secondLevelCacheMap.get(forkingConfigCacheKey);
111
+ if (thirdLevelCacheMap === undefined) {
112
+ thirdLevelCacheMap = new Map();
113
+ secondLevelCacheMap.set(forkingConfigCacheKey, thirdLevelCacheMap);
114
+ }
115
+
116
+ let fourthLevelCacheMap = thirdLevelCacheMap.get(chainType);
117
+ if (fourthLevelCacheMap === undefined) {
118
+ fourthLevelCacheMap = new Map();
119
+ thirdLevelCacheMap.set(chainType, fourthLevelCacheMap);
120
+ }
121
+
122
+ fourthLevelCacheMap.set(specId, result);
123
+
124
+ return result;
125
+ });
126
+ }
127
+
128
+ async function createGenesisStateAndOwnedAccounts(
129
+ accountsConfig: EdrNetworkAccountsConfig,
130
+ forkingConfig: EdrNetworkForkingConfig | undefined,
131
+ chainType: ChainType,
132
+ specId: string,
133
+ ): Promise<{
134
+ genesisState: Map<Uint8Array, AccountOverride>;
135
+ ownedAccounts: Array<{ secretKey: string; balance: bigint }>;
136
+ }> {
137
+ if (microEthSignerAddress === undefined) {
138
+ microEthSignerAddress = await import("micro-eth-signer/address");
139
+ }
140
+
141
+ const { addr } = microEthSignerAddress;
142
+
143
+ const ownedAccounts = await hardhatAccountsToEdrOwnedAccounts(accountsConfig);
144
+
145
+ const genesisState: Map<Uint8Array, AccountOverride> = new Map(
146
+ ownedAccounts.map(({ secretKey, balance }) => {
147
+ const address = hexToBytes(addr.fromPrivateKey(secretKey));
148
+ const accountOverride: AccountOverride = {
149
+ address,
150
+ balance: BigInt(balance),
151
+ code: new Uint8Array(), // Empty account code, removing potential delegation code when forking
152
+ };
153
+
154
+ return [address, accountOverride];
155
+ }),
156
+ );
157
+
158
+ const chainGenesisState =
159
+ forkingConfig !== undefined
160
+ ? [] // TODO: Add support for overriding remote fork state when the local fork is different
161
+ : chainType === OPTIMISM_CHAIN_TYPE
162
+ ? opGenesisState(opHardforkFromString(specId))
163
+ : l1GenesisState(l1HardforkFromString(specId));
164
+
165
+ for (const account of chainGenesisState) {
166
+ const existingOverride = genesisState.get(account.address);
167
+ if (existingOverride !== undefined) {
168
+ // Favor the genesis state specified by the user
169
+ account.balance = account.balance ?? existingOverride.balance;
170
+ account.nonce = account.nonce ?? existingOverride.nonce;
171
+ account.code = account.code ?? existingOverride.code;
172
+ account.storage = account.storage ?? existingOverride.storage;
173
+ } else {
174
+ genesisState.set(account.address, account);
175
+ }
176
+ }
177
+
178
+ return { genesisState, ownedAccounts };
179
+ }
@@ -0,0 +1,197 @@
1
+ import type { Colorizer } from "../../../../utils/colorizer.js";
2
+ import type {
3
+ LogTrace,
4
+ CallTrace,
5
+ DecodedTraceParameters,
6
+ } from "@nomicfoundation/edr";
7
+
8
+ import { LogKind, CallKind, IncludeTraces } from "@nomicfoundation/edr";
9
+ import { bytesToHexString } from "@nomicfoundation/hardhat-utils/hex";
10
+
11
+ type NestedArray<T> = Array<T | NestedArray<T>>;
12
+
13
+ export function verbosityToIncludeTraces(verbosity: number): IncludeTraces {
14
+ if (verbosity >= 4) {
15
+ return IncludeTraces.All;
16
+ } else if (verbosity >= 3) {
17
+ return IncludeTraces.Failing;
18
+ }
19
+
20
+ return IncludeTraces.None;
21
+ }
22
+
23
+ export function formatTraces(
24
+ traces: CallTrace[],
25
+ prefix: string,
26
+ colorizer: Colorizer,
27
+ ): string {
28
+ const lines = traces.map((trace) => formatTrace(trace, colorizer));
29
+ const formattedTraces = formatNestedArray(lines, prefix);
30
+ // Remove the trailing newline
31
+ return formattedTraces.slice(0, -1);
32
+ }
33
+
34
+ function formatInputs(
35
+ inputs: DecodedTraceParameters | Uint8Array,
36
+ color?: (text: string) => string,
37
+ ): string | undefined {
38
+ if (inputs instanceof Uint8Array) {
39
+ return inputs.length > 0 ? bytesToHexString(inputs) : undefined;
40
+ } else {
41
+ const formattedName =
42
+ color !== undefined ? color(inputs.name) : inputs.name;
43
+ return `${formattedName}(${inputs.arguments.join(", ")})`;
44
+ }
45
+ }
46
+
47
+ function formatOutputs(outputs: string | Uint8Array): string | undefined {
48
+ if (outputs instanceof Uint8Array) {
49
+ return outputs.length > 0 ? bytesToHexString(outputs) : undefined;
50
+ } else {
51
+ return outputs;
52
+ }
53
+ }
54
+
55
+ function formatLog(log: LogTrace, colorizer: Colorizer): string[] {
56
+ const { parameters } = log;
57
+ const tag = colorizer.yellow("[event]");
58
+ const lines = [];
59
+
60
+ if (Array.isArray(parameters)) {
61
+ const hexValues = parameters.map((bytes) => bytesToHexString(bytes));
62
+ const topicCount = hexValues.length - 1;
63
+
64
+ for (let i = 0; i < topicCount; i++) {
65
+ const prefix = i === 0 ? `${tag} topic 0` : ` topic ${i}`;
66
+ lines.push(`${prefix}: ${colorizer.cyan(hexValues[i])}`);
67
+ }
68
+
69
+ if (hexValues.length > 0) {
70
+ const dataPrefix = topicCount > 0 ? " data" : `${tag} data`;
71
+ lines.push(
72
+ `${dataPrefix}: ${colorizer.cyan(hexValues[hexValues.length - 1])}`,
73
+ );
74
+ }
75
+ } else {
76
+ lines.push(
77
+ `${tag} ${parameters.name}(${colorizer.cyan(parameters.arguments.join(", "))})`,
78
+ );
79
+ }
80
+ return lines;
81
+ }
82
+
83
+ function formatTrace(
84
+ trace: CallTrace,
85
+ colorizer: Colorizer,
86
+ ): NestedArray<string> {
87
+ const {
88
+ success,
89
+ address,
90
+ contract,
91
+ inputs,
92
+ gasUsed,
93
+ value,
94
+ kind,
95
+ isCheatcode,
96
+ outputs,
97
+ } = trace;
98
+ let color;
99
+ if (isCheatcode) {
100
+ color = colorizer.blue;
101
+ } else if (success) {
102
+ color = colorizer.green;
103
+ } else {
104
+ color = colorizer.red;
105
+ }
106
+
107
+ const formattedInputs = formatInputs(inputs, color);
108
+ const formattedOutputs = formatOutputs(outputs);
109
+
110
+ let openingLine: string;
111
+ let closingLine: string | undefined;
112
+ if (kind === CallKind.Create) {
113
+ openingLine = `[${gasUsed}] ${colorizer.yellow("→ new")} ${contract ?? "<unknown>"}@${address}`;
114
+ // TODO: Uncomment this when the formattedInputs starts containing
115
+ // the address of where the contract was deployed instead of the code.
116
+ // if (formattedInputs !== undefined) {
117
+ // openingLine = `${openingLine}@${formattedInputs}`;
118
+ // }
119
+ } else {
120
+ openingLine = `[${gasUsed}] ${color(contract ?? address)}`;
121
+ if (formattedInputs !== undefined) {
122
+ openingLine = `${openingLine}::${formattedInputs}`;
123
+ }
124
+ if (value !== 0n) {
125
+ openingLine = `${openingLine} {value: ${value}}`;
126
+ }
127
+ if (kind === CallKind.StaticCall) {
128
+ openingLine = `${openingLine} ${colorizer.yellow("[staticcall]")}`;
129
+ } else if (kind === CallKind.DelegateCall) {
130
+ openingLine = `${openingLine} ${colorizer.yellow("[delegatecall]")}`;
131
+ } else if (kind === CallKind.CallCode) {
132
+ openingLine = `${openingLine} ${colorizer.yellow("[callcode]")}`;
133
+ }
134
+ }
135
+ if (formattedOutputs !== undefined) {
136
+ if (
137
+ formattedOutputs === "EvmError: Revert" ||
138
+ formattedOutputs.startsWith("revert:")
139
+ ) {
140
+ closingLine = `${color("←")} ${color("[Revert]")} ${formattedOutputs}`;
141
+ } else {
142
+ closingLine = `${color("←")} ${formattedOutputs}`;
143
+ }
144
+ }
145
+
146
+ const lines = [];
147
+ lines.push(openingLine);
148
+ for (const child of trace.children) {
149
+ if (child.kind === LogKind.Log) {
150
+ lines.push(formatLog(child, colorizer));
151
+ } else {
152
+ lines.push(formatTrace(child, colorizer));
153
+ }
154
+ }
155
+ if (closingLine !== undefined) {
156
+ lines.push([closingLine]);
157
+ }
158
+ return lines;
159
+ }
160
+
161
+ function formatNestedArray(
162
+ data: NestedArray<string>,
163
+ prefix = "",
164
+ isTopLevel = true,
165
+ ): string {
166
+ let output = "";
167
+
168
+ for (let i = 0; i < data.length; i++) {
169
+ const item = data[i];
170
+
171
+ if (Array.isArray(item) && typeof item[0] === "string") {
172
+ const [label, ...children] = item;
173
+
174
+ if (isTopLevel) {
175
+ // Blank line between top-level traces
176
+ if (i > 0) {
177
+ output += "\n";
178
+ }
179
+
180
+ output += `${prefix}${label}\n`;
181
+ output += formatNestedArray(children, prefix, false);
182
+ } else {
183
+ const isLast = i === data.length - 1;
184
+ const connector = isLast ? " └─ " : " ├─ ";
185
+ const childPrefix = isLast ? " " : " │ ";
186
+ output += `${prefix}${connector}${label}\n`;
187
+ output += formatNestedArray(children, prefix + childPrefix, false);
188
+ }
189
+ } else if (typeof item === "string") {
190
+ const isLast = i === data.length - 1;
191
+ const connector = isLast ? " └─ " : " ├─ ";
192
+ output += `${prefix}${connector}${item}\n`;
193
+ }
194
+ }
195
+
196
+ return output;
197
+ }