hardhat 2.17.3 → 2.18.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 (84) hide show
  1. package/README.md +1 -1
  2. package/builtin-tasks/help.js +36 -5
  3. package/builtin-tasks/help.js.map +1 -1
  4. package/internal/cli/ArgumentsParser.d.ts +7 -2
  5. package/internal/cli/ArgumentsParser.d.ts.map +1 -1
  6. package/internal/cli/ArgumentsParser.js +72 -11
  7. package/internal/cli/ArgumentsParser.js.map +1 -1
  8. package/internal/cli/HelpPrinter.d.ts +7 -3
  9. package/internal/cli/HelpPrinter.d.ts.map +1 -1
  10. package/internal/cli/HelpPrinter.js +53 -22
  11. package/internal/cli/HelpPrinter.js.map +1 -1
  12. package/internal/cli/cli.js +69 -27
  13. package/internal/cli/cli.js.map +1 -1
  14. package/internal/core/config/config-env.d.ts +2 -1
  15. package/internal/core/config/config-env.d.ts.map +1 -1
  16. package/internal/core/config/config-env.js +7 -1
  17. package/internal/core/config/config-env.js.map +1 -1
  18. package/internal/core/errors-list.d.ts +42 -0
  19. package/internal/core/errors-list.d.ts.map +1 -1
  20. package/internal/core/errors-list.js +52 -2
  21. package/internal/core/errors-list.js.map +1 -1
  22. package/internal/core/jsonrpc/types/input/blockTag.d.ts +3 -3
  23. package/internal/core/jsonrpc/types/input/filterRequest.d.ts +6 -6
  24. package/internal/core/runtime-environment.d.ts +5 -3
  25. package/internal/core/runtime-environment.d.ts.map +1 -1
  26. package/internal/core/runtime-environment.js +30 -7
  27. package/internal/core/runtime-environment.js.map +1 -1
  28. package/internal/core/tasks/dsl.d.ts +10 -1
  29. package/internal/core/tasks/dsl.d.ts.map +1 -1
  30. package/internal/core/tasks/dsl.js +64 -4
  31. package/internal/core/tasks/dsl.js.map +1 -1
  32. package/internal/core/tasks/task-definitions.d.ts +31 -4
  33. package/internal/core/tasks/task-definitions.d.ts.map +1 -1
  34. package/internal/core/tasks/task-definitions.js +51 -5
  35. package/internal/core/tasks/task-definitions.js.map +1 -1
  36. package/internal/core/tasks/util.d.ts +6 -0
  37. package/internal/core/tasks/util.d.ts.map +1 -0
  38. package/internal/core/tasks/util.js +19 -0
  39. package/internal/core/tasks/util.js.map +1 -0
  40. package/internal/hardhat-network/provider/modules/base.d.ts +17 -0
  41. package/internal/hardhat-network/provider/modules/base.d.ts.map +1 -0
  42. package/internal/hardhat-network/provider/modules/base.js +127 -0
  43. package/internal/hardhat-network/provider/modules/base.js.map +1 -0
  44. package/internal/hardhat-network/provider/modules/debug.d.ts +5 -3
  45. package/internal/hardhat-network/provider/modules/debug.d.ts.map +1 -1
  46. package/internal/hardhat-network/provider/modules/debug.js +21 -5
  47. package/internal/hardhat-network/provider/modules/debug.js.map +1 -1
  48. package/internal/hardhat-network/provider/modules/eth.d.ts +2 -7
  49. package/internal/hardhat-network/provider/modules/eth.d.ts.map +1 -1
  50. package/internal/hardhat-network/provider/modules/eth.js +12 -60
  51. package/internal/hardhat-network/provider/modules/eth.js.map +1 -1
  52. package/internal/hardhat-network/provider/node.d.ts +1 -0
  53. package/internal/hardhat-network/provider/node.d.ts.map +1 -1
  54. package/internal/hardhat-network/provider/node.js +6 -0
  55. package/internal/hardhat-network/provider/node.js.map +1 -1
  56. package/internal/lib/hardhat-lib.d.ts.map +1 -1
  57. package/internal/lib/hardhat-lib.js +1 -1
  58. package/internal/lib/hardhat-lib.js.map +1 -1
  59. package/internal/sentry/anonymizer.d.ts.map +1 -1
  60. package/internal/sentry/anonymizer.js +3 -1
  61. package/internal/sentry/anonymizer.js.map +1 -1
  62. package/package.json +1 -1
  63. package/register.js +1 -1
  64. package/register.js.map +1 -1
  65. package/src/builtin-tasks/help.ts +47 -5
  66. package/src/internal/cli/ArgumentsParser.ts +79 -13
  67. package/src/internal/cli/HelpPrinter.ts +89 -24
  68. package/src/internal/cli/cli.ts +106 -38
  69. package/src/internal/core/config/config-env.ts +11 -0
  70. package/src/internal/core/errors-list.ts +56 -2
  71. package/src/internal/core/runtime-environment.ts +32 -7
  72. package/src/internal/core/tasks/dsl.ts +99 -4
  73. package/src/internal/core/tasks/task-definitions.ts +97 -3
  74. package/src/internal/core/tasks/util.ts +18 -0
  75. package/src/internal/hardhat-network/provider/modules/base.ts +156 -0
  76. package/src/internal/hardhat-network/provider/modules/debug.ts +50 -9
  77. package/src/internal/hardhat-network/provider/modules/eth.ts +16 -91
  78. package/src/internal/hardhat-network/provider/node.ts +12 -0
  79. package/src/internal/lib/hardhat-lib.ts +1 -0
  80. package/src/internal/sentry/anonymizer.ts +3 -1
  81. package/src/register.ts +1 -0
  82. package/src/types/runtime.ts +35 -1
  83. package/types/runtime.d.ts +24 -1
  84. package/types/runtime.d.ts.map +1 -1
@@ -1,14 +1,21 @@
1
1
  import {
2
2
  ActionType,
3
+ ScopeDefinition,
4
+ ScopesMap,
3
5
  TaskArguments,
4
6
  TaskDefinition,
7
+ TaskIdentifier,
5
8
  TasksMap,
6
9
  } from "../../../types";
10
+ import { HardhatError, assertHardhatInvariant } from "../errors";
11
+ import { ERRORS } from "../errors-list";
7
12
 
8
13
  import {
9
14
  OverriddenTaskDefinition,
15
+ SimpleScopeDefinition,
10
16
  SimpleTaskDefinition,
11
17
  } from "./task-definitions";
18
+ import { parseTaskIdentifier } from "./util";
12
19
 
13
20
  /**
14
21
  * This class defines the DSL used in Hardhat config files
@@ -18,6 +25,7 @@ export class TasksDSL {
18
25
  public readonly internalTask = this.subtask;
19
26
 
20
27
  private readonly _tasks: TasksMap = {};
28
+ private readonly _scopes: ScopesMap = {};
21
29
 
22
30
  /**
23
31
  * Creates a task, overriding any previous task with the same name.
@@ -56,6 +64,8 @@ export class TasksDSL {
56
64
  descriptionOrAction?: string | ActionType<TaskArgumentsT>,
57
65
  action?: ActionType<TaskArgumentsT>
58
66
  ): TaskDefinition {
67
+ // if this function is updated, update the corresponding callback
68
+ // passed to `new SimpleScopeDefinition`
59
69
  return this._addTask(name, descriptionOrAction, action, false);
60
70
  }
61
71
 
@@ -96,9 +106,56 @@ export class TasksDSL {
96
106
  descriptionOrAction?: string | ActionType<TaskArgumentsT>,
97
107
  action?: ActionType<TaskArgumentsT>
98
108
  ): TaskDefinition {
109
+ // if this function is updated, update the corresponding callback
110
+ // passed to `new SimpleScopeDefinition`
99
111
  return this._addTask(name, descriptionOrAction, action, true);
100
112
  }
101
113
 
114
+ public scope(name: string, description?: string): ScopeDefinition {
115
+ if (this._tasks[name] !== undefined) {
116
+ throw new HardhatError(ERRORS.TASK_DEFINITIONS.TASK_SCOPE_CLASH, {
117
+ scopeName: name,
118
+ });
119
+ }
120
+
121
+ const scopeDefinition = this._scopes[name];
122
+
123
+ if (scopeDefinition !== undefined) {
124
+ // if the scope already exists, the only thing we might
125
+ // do is to update its description
126
+ if (description !== undefined) {
127
+ scopeDefinition.setDescription(description);
128
+ }
129
+
130
+ return scopeDefinition;
131
+ }
132
+
133
+ const scope = new SimpleScopeDefinition(
134
+ name,
135
+ description,
136
+ (taskName, descriptionOrAction, action) =>
137
+ // if this function is updated, update the dsl.task function too
138
+ this._addTask(
139
+ { scope: name, task: taskName },
140
+ descriptionOrAction,
141
+ action,
142
+ false
143
+ ),
144
+ (subtaskName, descriptionOrAction, action) =>
145
+ // if this function is updated, update the dsl.subtask function too
146
+ this._addTask(
147
+ { scope: name, task: subtaskName },
148
+ descriptionOrAction,
149
+ action,
150
+ true
151
+ )
152
+ );
153
+
154
+ this._scopes[name] = scope;
155
+
156
+ return scope;
157
+ }
158
+
102
159
  /**
103
160
  * Retrieves the task definitions.
104
161
  *
@@ -108,13 +165,41 @@ export class TasksDSL {
108
165
  return this._tasks;
109
166
  }
110
167
 
168
+ /**
169
+ * Retrieves the scoped task definitions.
170
+ *
171
+ * @returns The scoped tasks container.
172
+ */
173
+ public getScopesDefinitions(): ScopesMap {
174
+ return this._scopes;
175
+ }
176
+
177
+ public getTaskDefinition(
178
+ scope: string | undefined,
179
+ name: string
180
+ ): TaskDefinition | undefined {
181
+ if (scope === undefined) {
182
+ return this._tasks[name];
183
+ } else {
184
+ return this._scopes[scope]?.tasks?.[name];
185
+ }
186
+ }
187
+
111
188
  private _addTask<TaskArgumentsT extends TaskArguments>(
112
- name: string,
189
+ taskIdentifier: TaskIdentifier,
113
190
  descriptionOrAction?: string | ActionType<TaskArgumentsT>,
114
191
  action?: ActionType<TaskArgumentsT>,
115
192
  isSubtask?: boolean
116
193
  ) {
117
- const parentTaskDefinition = this._tasks[name];
194
+ const { scope, task } = parseTaskIdentifier(taskIdentifier);
195
+
196
+ if (scope === undefined && this._scopes[task] !== undefined) {
197
+ throw new HardhatError(ERRORS.TASK_DEFINITIONS.SCOPE_TASK_CLASH, {
198
+ taskName: task,
199
+ });
200
+ }
201
+
202
+ const parentTaskDefinition = this.getTaskDefinition(scope, task);
118
203
 
119
204
  let taskDefinition: TaskDefinition;
120
205
 
@@ -124,7 +209,7 @@ export class TasksDSL {
124
209
  isSubtask
125
210
  );
126
211
  } else {
127
- taskDefinition = new SimpleTaskDefinition(name, isSubtask);
212
+ taskDefinition = new SimpleTaskDefinition(taskIdentifier, isSubtask);
128
213
  }
129
214
 
130
215
  if (descriptionOrAction instanceof Function) {
@@ -140,7 +225,17 @@ export class TasksDSL {
140
225
  taskDefinition.setAction(action);
141
226
  }
142
227
 
143
- this._tasks[name] = taskDefinition;
228
+ if (scope === undefined) {
229
+ this._tasks[task] = taskDefinition;
230
+ } else {
231
+ const scopeDefinition = this._scopes[scope];
232
+ assertHardhatInvariant(
233
+ scopeDefinition !== undefined,
234
+ "It shouldn't be possible to create a task in a scope that doesn't exist"
235
+ );
236
+ scopeDefinition.tasks[task] = taskDefinition;
237
+ }
238
+
144
239
  return taskDefinition;
145
240
  }
146
241
  }
@@ -4,13 +4,17 @@ import {
4
4
  CLIArgumentType,
5
5
  ParamDefinition,
6
6
  ParamDefinitionsMap,
7
+ ScopeDefinition,
7
8
  TaskArguments,
8
9
  TaskDefinition,
10
+ TaskIdentifier,
11
+ TasksMap,
9
12
  } from "../../../types";
10
13
  import { HardhatError } from "../errors";
11
14
  import { ErrorDescriptor, ERRORS } from "../errors-list";
12
15
  import * as types from "../params/argumentTypes";
13
16
  import { HARDHAT_PARAM_DEFINITIONS } from "../params/hardhat-params";
17
+ import { parseTaskIdentifier } from "./util";
14
18
 
15
19
  function isCLIArgumentType(
16
20
  type: ArgumentType<any>
@@ -26,6 +30,12 @@ function isCLIArgumentType(
26
30
  *
27
31
  */
28
32
  export class SimpleTaskDefinition implements TaskDefinition {
33
+ public get name() {
34
+ return this._task;
35
+ }
36
+ public get scope() {
37
+ return this._scope;
38
+ }
29
39
  public get description() {
30
40
  return this._description;
31
41
  }
@@ -36,6 +46,8 @@ export class SimpleTaskDefinition implements TaskDefinition {
36
46
  private _positionalParamNames: Set<string>;
37
47
  private _hasVariadicParam: boolean;
38
48
  private _hasOptionalPositionalParam: boolean;
49
+ private _scope?: string;
50
+ private _task: string;
39
51
  private _description?: string;
40
52
 
41
53
  /**
@@ -43,19 +55,22 @@ export class SimpleTaskDefinition implements TaskDefinition {
43
55
  *
44
56
  * This definition will have no params, and will throw a HH205 if executed.
45
57
  *
46
- * @param name The task's name.
58
+ * @param taskIdentifier The task's identifier.
47
59
  * @param isSubtask `true` if the task is a subtask, `false` otherwise.
48
60
  */
49
61
  constructor(
50
- public readonly name: string,
62
+ taskIdentifier: TaskIdentifier,
51
63
  public readonly isSubtask: boolean = false
52
64
  ) {
53
65
  this._positionalParamNames = new Set();
54
66
  this._hasVariadicParam = false;
55
67
  this._hasOptionalPositionalParam = false;
68
+ const { scope, task } = parseTaskIdentifier(taskIdentifier);
69
+ this._scope = scope;
70
+ this._task = task;
56
71
  this.action = () => {
57
72
  throw new HardhatError(ERRORS.TASK_DEFINITIONS.ACTION_NOT_SET, {
58
- taskName: name,
73
+ taskName: this._task,
59
74
  });
60
75
  };
61
76
  }
@@ -562,6 +577,10 @@ export class OverriddenTaskDefinition implements TaskDefinition {
562
577
  this.parentTaskDefinition = parentTaskDefinition;
563
578
  }
564
579
 
580
+ /**
581
+ * Sets the task's description.
582
+ * @param description The description.
583
+ */
565
584
  public setDescription(description: string) {
566
585
  this._description = description;
567
586
  return this;
@@ -579,6 +598,13 @@ export class OverriddenTaskDefinition implements TaskDefinition {
579
598
  return this;
580
599
  }
581
600
 
601
+ /**
602
+ * Retrieves the parent task's scope.
603
+ */
604
+ public get scope() {
605
+ return this.parentTaskDefinition.scope;
606
+ }
607
+
582
608
  /**
583
609
  * Retrieves the parent task's name.
584
610
  */
@@ -734,3 +760,71 @@ export class OverriddenTaskDefinition implements TaskDefinition {
734
760
  });
735
761
  }
736
762
  }
763
+
764
+ type AddTaskFunction = <TaskArgumentsT extends TaskArguments>(
765
+ name: string,
766
+ descriptionOrAction?: string | ActionType<TaskArgumentsT>,
767
+ action?: ActionType<TaskArgumentsT>
768
+ ) => TaskDefinition;
769
+
770
+ export class SimpleScopeDefinition implements ScopeDefinition {
771
+ public tasks: TasksMap = {};
772
+
773
+ constructor(
774
+ public readonly name: string,
775
+ private _description: string | undefined,
776
+ private _addTask: AddTaskFunction,
777
+ private _addSubtask: AddTaskFunction
778
+ ) {}
779
+
780
+ public get description() {
781
+ return this._description;
782
+ }
783
+
784
+ public setDescription(description: string): this {
785
+ this._description = description;
786
+ return this;
787
+ }
788
+
789
+ public task<TaskArgumentsT extends TaskArguments>(
790
+ name: string,
791
+ description?: string,
792
+ action?: ActionType<TaskArgumentsT>
793
+ ): TaskDefinition;
794
+ public task<TaskArgumentsT extends TaskArguments>(
795
+ name: string,
796
+ action: ActionType<TaskArgumentsT>
797
+ ): TaskDefinition;
798
+ public task<TaskArgumentsT extends TaskArguments>(
799
+ name: string,
800
+ descriptionOrAction?: string | ActionType<TaskArgumentsT>,
801
+ action?: ActionType<TaskArgumentsT>
802
+ ) {
803
+ const task = this._addTask(name, descriptionOrAction, action);
804
+
805
+ this.tasks[name] = task;
806
+
807
+ return task;
808
+ }
809
+
810
+ public subtask<TaskArgumentsT extends TaskArguments>(
811
+ name: string,
812
+ description?: string,
813
+ action?: ActionType<TaskArgumentsT>
814
+ ): TaskDefinition;
815
+ public subtask<TaskArgumentsT extends TaskArguments>(
816
+ name: string,
817
+ action: ActionType<TaskArgumentsT>
818
+ ): TaskDefinition;
819
+ public subtask<TaskArgumentsT extends TaskArguments>(
820
+ name: string,
821
+ descriptionOrAction?: string | ActionType<TaskArgumentsT>,
822
+ action?: ActionType<TaskArgumentsT>
823
+ ) {
824
+ const subtask = this._addSubtask(name, descriptionOrAction, action);
825
+
826
+ this.tasks[name] = subtask;
827
+
828
+ return subtask;
829
+ }
830
+ }
@@ -0,0 +1,18 @@
1
+ import { TaskIdentifier } from "../../../types";
2
+
3
+ export function parseTaskIdentifier(taskIdentifier: TaskIdentifier): {
4
+ scope: string | undefined;
5
+ task: string;
6
+ } {
7
+ if (typeof taskIdentifier === "string") {
8
+ return {
9
+ scope: undefined,
10
+ task: taskIdentifier,
11
+ };
12
+ } else {
13
+ return {
14
+ scope: taskIdentifier.scope,
15
+ task: taskIdentifier.task,
16
+ };
17
+ }
18
+ }
@@ -0,0 +1,156 @@
1
+ import { Block } from "@nomicfoundation/ethereumjs-block";
2
+ import {
3
+ bufferToHex,
4
+ toBuffer,
5
+ zeroAddress,
6
+ } from "@nomicfoundation/ethereumjs-util";
7
+ import {
8
+ OptionalRpcNewBlockTag,
9
+ RpcNewBlockTag,
10
+ } from "../../../core/jsonrpc/types/input/blockTag";
11
+ import { HardhatNode } from "../node";
12
+ import * as BigIntUtils from "../../../util/bigint";
13
+ import {
14
+ InvalidArgumentsError,
15
+ InvalidInputError,
16
+ } from "../../../core/providers/errors";
17
+ import { RpcCallRequest } from "../../../core/jsonrpc/types/input/callRequest";
18
+ import { CallParams } from "../node-types";
19
+ import { RpcAccessList } from "../../../core/jsonrpc/types/access-list";
20
+
21
+ /* eslint-disable @nomicfoundation/hardhat-internal-rules/only-hardhat-error */
22
+
23
+ export class Base {
24
+ constructor(protected readonly _node: HardhatNode) {}
25
+
26
+ public async resolveNewBlockTag(
27
+ newBlockTag: OptionalRpcNewBlockTag,
28
+ defaultValue: RpcNewBlockTag = "latest"
29
+ ): Promise<bigint | "pending"> {
30
+ if (newBlockTag === undefined) {
31
+ newBlockTag = defaultValue;
32
+ }
33
+
34
+ if (newBlockTag === "pending") {
35
+ return "pending";
36
+ }
37
+
38
+ if (newBlockTag === "latest") {
39
+ return this._node.getLatestBlockNumber();
40
+ }
41
+
42
+ if (newBlockTag === "earliest") {
43
+ return 0n;
44
+ }
45
+
46
+ if (newBlockTag === "safe" || newBlockTag === "finalized") {
47
+ this._checkPostMergeBlockTags(newBlockTag);
48
+
49
+ return this._node.getLatestBlockNumber();
50
+ }
51
+
52
+ if (!BigIntUtils.isBigInt(newBlockTag)) {
53
+ if ("blockNumber" in newBlockTag && "blockHash" in newBlockTag) {
54
+ throw new InvalidArgumentsError(
55
+ "Invalid block tag received. Only one of hash or block number can be used."
56
+ );
57
+ }
58
+
59
+ if ("blockNumber" in newBlockTag && "requireCanonical" in newBlockTag) {
60
+ throw new InvalidArgumentsError(
61
+ "Invalid block tag received. requireCanonical only works with hashes."
62
+ );
63
+ }
64
+ }
65
+
66
+ let block: Block | undefined;
67
+ if (BigIntUtils.isBigInt(newBlockTag)) {
68
+ block = await this._node.getBlockByNumber(newBlockTag);
69
+ } else if ("blockNumber" in newBlockTag) {
70
+ block = await this._node.getBlockByNumber(newBlockTag.blockNumber);
71
+ } else {
72
+ block = await this._node.getBlockByHash(newBlockTag.blockHash);
73
+ }
74
+
75
+ if (block === undefined) {
76
+ const latestBlock = this._node.getLatestBlockNumber();
77
+
78
+ throw new InvalidInputError(
79
+ `Received invalid block tag ${this._newBlockTagToString(
80
+ newBlockTag
81
+ )}. Latest block number is ${latestBlock.toString()}`
82
+ );
83
+ }
84
+
85
+ return block.header.number;
86
+ }
87
+
88
+ public async rpcCallRequestToNodeCallParams(
89
+ rpcCall: RpcCallRequest
90
+ ): Promise<CallParams> {
91
+ return {
92
+ to: rpcCall.to,
93
+ from:
94
+ rpcCall.from !== undefined
95
+ ? rpcCall.from
96
+ : await this._getDefaultCallFrom(),
97
+ data: rpcCall.data !== undefined ? rpcCall.data : toBuffer([]),
98
+ gasLimit:
99
+ rpcCall.gas !== undefined ? rpcCall.gas : this._node.getBlockGasLimit(),
100
+ value: rpcCall.value !== undefined ? rpcCall.value : 0n,
101
+ accessList:
102
+ rpcCall.accessList !== undefined
103
+ ? this._rpcAccessListToNodeAccessList(rpcCall.accessList)
104
+ : undefined,
105
+ gasPrice: rpcCall.gasPrice,
106
+ maxFeePerGas: rpcCall.maxFeePerGas,
107
+ maxPriorityFeePerGas: rpcCall.maxPriorityFeePerGas,
108
+ };
109
+ }
110
+
111
+ protected _rpcAccessListToNodeAccessList(
112
+ rpcAccessList: RpcAccessList
113
+ ): Array<[Buffer, Buffer[]]> {
114
+ return rpcAccessList.map((tuple) => [
115
+ tuple.address,
116
+ tuple.storageKeys ?? [],
117
+ ]);
118
+ }
119
+
120
+ protected _checkPostMergeBlockTags(blockTag: "safe" | "finalized") {
121
+ const isPostMerge = this._node.isPostMergeHardfork();
122
+ const hardfork = this._node.hardfork;
123
+
124
+ if (!isPostMerge) {
125
+ throw new InvalidArgumentsError(
126
+ `The '${blockTag}' block tag is not allowed in pre-merge hardforks. You are using the '${hardfork}' hardfork.`
127
+ );
128
+ }
129
+ }
130
+
131
+ protected _newBlockTagToString(tag: RpcNewBlockTag): string {
132
+ if (typeof tag === "string") {
133
+ return tag;
134
+ }
135
+
136
+ if (BigIntUtils.isBigInt(tag)) {
137
+ return tag.toString();
138
+ }
139
+
140
+ if ("blockNumber" in tag) {
141
+ return tag.blockNumber.toString();
142
+ }
143
+
144
+ return bufferToHex(tag.blockHash);
145
+ }
146
+
147
+ private async _getDefaultCallFrom(): Promise<Buffer> {
148
+ const localAccounts = await this._node.getLocalAccountAddresses();
149
+
150
+ if (localAccounts.length === 0) {
151
+ return toBuffer(zeroAddress());
152
+ }
153
+
154
+ return toBuffer(localAccounts[0]);
155
+ }
156
+ }
@@ -1,4 +1,12 @@
1
1
  import { rpcHash } from "../../../core/jsonrpc/types/base-types";
2
+ import {
3
+ OptionalRpcNewBlockTag,
4
+ optionalRpcNewBlockTag,
5
+ } from "../../../core/jsonrpc/types/input/blockTag";
6
+ import {
7
+ RpcCallRequest,
8
+ rpcCallRequest,
9
+ } from "../../../core/jsonrpc/types/input/callRequest";
2
10
  import {
3
11
  rpcDebugTracingConfig,
4
12
  RpcDebugTracingConfig,
@@ -10,17 +18,22 @@ import {
10
18
  } from "../../../core/providers/errors";
11
19
  import { HardhatNode } from "../node";
12
20
  import { RpcDebugTraceOutput } from "../output";
21
+ import { Base } from "./base";
13
22
 
14
23
  /* eslint-disable @nomicfoundation/hardhat-internal-rules/only-hardhat-error */
15
24
 
16
- export class DebugModule {
17
- constructor(private readonly _node: HardhatNode) {}
25
+ export class DebugModule extends Base {
26
+ constructor(_node: HardhatNode) {
27
+ super(_node);
28
+ }
18
29
 
19
30
  public async processRequest(
20
31
  method: string,
21
32
  params: any[] = []
22
33
  ): Promise<any> {
23
34
  switch (method) {
35
+ case "debug_traceCall":
36
+ return this._traceCallAction(...this._traceCallParams(params));
24
37
  case "debug_traceTransaction":
25
38
  return this._traceTransactionAction(
26
39
  ...this._traceTransactionParams(params)
@@ -30,6 +43,34 @@ export class DebugModule {
30
43
  throw new MethodNotFoundError(`Method ${method} not found`);
31
44
  }
32
45
 
46
+ // debug_traceCall
47
+
48
+ private _traceCallParams(
49
+ params: any[]
50
+ ): [RpcCallRequest, OptionalRpcNewBlockTag, RpcDebugTracingConfig] {
51
+ const validatedParams = validateParams(
52
+ params,
53
+ rpcCallRequest,
54
+ optionalRpcNewBlockTag,
55
+ rpcDebugTracingConfig
56
+ );
57
+
58
+ this._validateTracerParam(validatedParams[2]);
59
+
60
+ return validatedParams;
61
+ }
62
+
63
+ private async _traceCallAction(
64
+ callConfig: RpcCallRequest,
65
+ block: OptionalRpcNewBlockTag,
66
+ traceConfig: RpcDebugTracingConfig
67
+ ): Promise<RpcDebugTraceOutput> {
68
+ const callParams = await this.rpcCallRequestToNodeCallParams(callConfig);
69
+ const blockNumber = await this.resolveNewBlockTag(block);
70
+
71
+ return this._node.traceCall(callParams, blockNumber, traceConfig);
72
+ }
73
+
33
74
  // debug_traceTransaction
34
75
 
35
76
  private _traceTransactionParams(
@@ -46,6 +87,13 @@ export class DebugModule {
46
87
  return validatedParams;
47
88
  }
48
89
 
90
+ private async _traceTransactionAction(
91
+ hash: Buffer,
92
+ config: RpcDebugTracingConfig
93
+ ): Promise<RpcDebugTraceOutput> {
94
+ return this._node.traceTransaction(hash, config);
95
+ }
96
+
49
97
  private _validateTracerParam(config: RpcDebugTracingConfig) {
50
98
  if (config?.tracer !== undefined) {
51
99
  throw new InvalidArgumentsError(
@@ -53,11 +101,4 @@ export class DebugModule {
53
101
  );
54
102
  }
55
103
  }
56
-
57
- private async _traceTransactionAction(
58
- hash: Buffer,
59
- config: RpcDebugTracingConfig
60
- ): Promise<RpcDebugTraceOutput> {
61
- return this._node.traceTransaction(hash, config);
62
- }
63
104
  }