hardhat 2.17.3 → 2.17.4

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 (31) hide show
  1. package/internal/cli/cli.js +42 -14
  2. package/internal/cli/cli.js.map +1 -1
  3. package/internal/core/errors-list.d.ts +14 -0
  4. package/internal/core/errors-list.d.ts.map +1 -1
  5. package/internal/core/errors-list.js +16 -0
  6. package/internal/core/errors-list.js.map +1 -1
  7. package/internal/core/jsonrpc/types/input/blockTag.d.ts +3 -3
  8. package/internal/core/jsonrpc/types/input/filterRequest.d.ts +6 -6
  9. package/internal/hardhat-network/provider/modules/base.d.ts +17 -0
  10. package/internal/hardhat-network/provider/modules/base.d.ts.map +1 -0
  11. package/internal/hardhat-network/provider/modules/base.js +127 -0
  12. package/internal/hardhat-network/provider/modules/base.js.map +1 -0
  13. package/internal/hardhat-network/provider/modules/debug.d.ts +5 -3
  14. package/internal/hardhat-network/provider/modules/debug.d.ts.map +1 -1
  15. package/internal/hardhat-network/provider/modules/debug.js +21 -5
  16. package/internal/hardhat-network/provider/modules/debug.js.map +1 -1
  17. package/internal/hardhat-network/provider/modules/eth.d.ts +2 -7
  18. package/internal/hardhat-network/provider/modules/eth.d.ts.map +1 -1
  19. package/internal/hardhat-network/provider/modules/eth.js +12 -60
  20. package/internal/hardhat-network/provider/modules/eth.js.map +1 -1
  21. package/internal/hardhat-network/provider/node.d.ts +1 -0
  22. package/internal/hardhat-network/provider/node.d.ts.map +1 -1
  23. package/internal/hardhat-network/provider/node.js +6 -0
  24. package/internal/hardhat-network/provider/node.js.map +1 -1
  25. package/package.json +1 -1
  26. package/src/internal/cli/cli.ts +65 -15
  27. package/src/internal/core/errors-list.ts +18 -0
  28. package/src/internal/hardhat-network/provider/modules/base.ts +156 -0
  29. package/src/internal/hardhat-network/provider/modules/debug.ts +50 -9
  30. package/src/internal/hardhat-network/provider/modules/eth.ts +16 -91
  31. package/src/internal/hardhat-network/provider/node.ts +12 -0
@@ -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
  }
@@ -5,18 +5,10 @@ import {
5
5
  TransactionFactory,
6
6
  TypedTransaction,
7
7
  } from "@nomicfoundation/ethereumjs-tx";
8
- import {
9
- Address,
10
- bufferToHex,
11
- toBuffer,
12
- toRpcSig,
13
- zeroAddress,
14
- } from "@nomicfoundation/ethereumjs-util";
8
+ import { Address, toBuffer, toRpcSig } from "@nomicfoundation/ethereumjs-util";
15
9
  import * as t from "io-ts";
16
10
  import cloneDeep from "lodash/cloneDeep";
17
-
18
11
  import { BoundExperimentalHardhatNetworkMessageTraceHook } from "../../../../types";
19
- import { RpcAccessList } from "../../../core/jsonrpc/types/access-list";
20
12
  import {
21
13
  bufferToRpcData,
22
14
  numberToRpcQuantity,
@@ -69,7 +61,6 @@ import { MessageTrace } from "../../stack-traces/message-trace";
69
61
  import { LATEST_BLOCK } from "../filter";
70
62
  import { HardhatNode } from "../node";
71
63
  import {
72
- CallParams,
73
64
  FilterParams,
74
65
  GatherTracesResult,
75
66
  MineBlockResult,
@@ -90,6 +81,7 @@ import { optional } from "../../../util/io-ts";
90
81
  import * as BigIntUtils from "../../../util/bigint";
91
82
  import { HardforkName } from "../../../util/hardforks";
92
83
  import { ModulesLogger } from "./logger";
84
+ import { Base } from "./base";
93
85
 
94
86
  const EIP1559_MIN_HARDFORK = HardforkName.LONDON;
95
87
  const ACCESS_LIST_MIN_HARDFORK = HardforkName.BERLIN;
@@ -97,15 +89,17 @@ const EIP155_MIN_HARDFORK = HardforkName.SPURIOUS_DRAGON;
97
89
  const EIP3860_MIN_HARDFORK = HardforkName.SHANGHAI;
98
90
 
99
91
  /* eslint-disable @nomicfoundation/hardhat-internal-rules/only-hardhat-error */
100
- export class EthModule {
92
+ export class EthModule extends Base {
101
93
  constructor(
102
94
  private readonly _common: Common,
103
- private readonly _node: HardhatNode,
95
+ _node: HardhatNode,
104
96
  private readonly _throwOnTransactionFailures: boolean,
105
97
  private readonly _throwOnCallFailures: boolean,
106
98
  private readonly _logger: ModulesLogger,
107
99
  private readonly _experimentalHardhatNetworkMessageTraceHooks: BoundExperimentalHardhatNetworkMessageTraceHook[] = []
108
- ) {}
100
+ ) {
101
+ super(_node);
102
+ }
109
103
 
110
104
  public async processRequest(
111
105
  method: string,
@@ -354,9 +348,9 @@ export class EthModule {
354
348
  ): Promise<string> {
355
349
  this._validateTransactionAndCallRequest(rpcCall);
356
350
 
357
- const blockNumberOrPending = await this._resolveNewBlockTag(blockTag);
351
+ const blockNumberOrPending = await this.resolveNewBlockTag(blockTag);
358
352
 
359
- const callParams = await this._rpcCallRequestToNodeCallParams(rpcCall);
353
+ const callParams = await this.rpcCallRequestToNodeCallParams(rpcCall);
360
354
 
361
355
  const {
362
356
  result: returnData,
@@ -434,12 +428,12 @@ export class EthModule {
434
428
 
435
429
  // estimateGas behaves differently when there's no blockTag
436
430
  // it uses "pending" as default instead of "latest"
437
- const blockNumberOrPending = await this._resolveNewBlockTag(
431
+ const blockNumberOrPending = await this.resolveNewBlockTag(
438
432
  blockTag,
439
433
  "pending"
440
434
  );
441
435
 
442
- const callParams = await this._rpcCallRequestToNodeCallParams(callRequest);
436
+ const callParams = await this.rpcCallRequestToNodeCallParams(callRequest);
443
437
 
444
438
  const { estimation, error, trace, consoleLogMessages } =
445
439
  await this._node.estimateGas(callParams, blockNumberOrPending);
@@ -487,7 +481,7 @@ export class EthModule {
487
481
  address: Buffer,
488
482
  blockTag: OptionalRpcNewBlockTag
489
483
  ): Promise<string> {
490
- const blockNumberOrPending = await this._resolveNewBlockTag(blockTag);
484
+ const blockNumberOrPending = await this.resolveNewBlockTag(blockTag);
491
485
 
492
486
  return numberToRpcQuantity(
493
487
  await this._node.getAccountBalance(
@@ -612,7 +606,7 @@ export class EthModule {
612
606
  address: Buffer,
613
607
  blockTag: OptionalRpcNewBlockTag
614
608
  ): Promise<string> {
615
- const blockNumberOrPending = await this._resolveNewBlockTag(blockTag);
609
+ const blockNumberOrPending = await this.resolveNewBlockTag(blockTag);
616
610
 
617
611
  return bufferToRpcData(
618
612
  await this._node.getCode(new Address(address), blockNumberOrPending)
@@ -721,7 +715,7 @@ export class EthModule {
721
715
  slot: bigint,
722
716
  blockTag: OptionalRpcNewBlockTag
723
717
  ): Promise<string> {
724
- const blockNumberOrPending = await this._resolveNewBlockTag(blockTag);
718
+ const blockNumberOrPending = await this.resolveNewBlockTag(blockTag);
725
719
 
726
720
  const data = await this._node.getStorageAt(
727
721
  new Address(address),
@@ -854,7 +848,7 @@ export class EthModule {
854
848
  address: Buffer,
855
849
  blockTag: OptionalRpcNewBlockTag
856
850
  ): Promise<string> {
857
- const blockNumberOrPending = await this._resolveNewBlockTag(blockTag);
851
+ const blockNumberOrPending = await this.resolveNewBlockTag(blockTag);
858
852
 
859
853
  return numberToRpcQuantity(
860
854
  await this._node.getNextConfirmedNonce(
@@ -1240,7 +1234,7 @@ export class EthModule {
1240
1234
  );
1241
1235
  }
1242
1236
 
1243
- const resolvedNewestBlock = await this._resolveNewBlockTag(newestBlock);
1237
+ const resolvedNewestBlock = await this.resolveNewBlockTag(newestBlock);
1244
1238
 
1245
1239
  const feeHistory = await this._node.getFeeHistory(
1246
1240
  blockCount,
@@ -1263,29 +1257,6 @@ export class EthModule {
1263
1257
 
1264
1258
  // Utility methods
1265
1259
 
1266
- private async _rpcCallRequestToNodeCallParams(
1267
- rpcCall: RpcCallRequest
1268
- ): Promise<CallParams> {
1269
- return {
1270
- to: rpcCall.to,
1271
- from:
1272
- rpcCall.from !== undefined
1273
- ? rpcCall.from
1274
- : await this._getDefaultCallFrom(),
1275
- data: rpcCall.data !== undefined ? rpcCall.data : toBuffer([]),
1276
- gasLimit:
1277
- rpcCall.gas !== undefined ? rpcCall.gas : this._node.getBlockGasLimit(),
1278
- value: rpcCall.value !== undefined ? rpcCall.value : 0n,
1279
- accessList:
1280
- rpcCall.accessList !== undefined
1281
- ? this._rpcAccessListToNodeAccessList(rpcCall.accessList)
1282
- : undefined,
1283
- gasPrice: rpcCall.gasPrice,
1284
- maxFeePerGas: rpcCall.maxFeePerGas,
1285
- maxPriorityFeePerGas: rpcCall.maxPriorityFeePerGas,
1286
- };
1287
- }
1288
-
1289
1260
  private async _rpcTransactionRequestToNodeTransactionParams(
1290
1261
  rpcTx: RpcTransactionRequest
1291
1262
  ): Promise<TransactionParams> {
@@ -1365,15 +1336,6 @@ export class EthModule {
1365
1336
  };
1366
1337
  }
1367
1338
 
1368
- private _rpcAccessListToNodeAccessList(
1369
- rpcAccessList: RpcAccessList
1370
- ): Array<[Buffer, Buffer[]]> {
1371
- return rpcAccessList.map((tuple) => [
1372
- tuple.address,
1373
- tuple.storageKeys ?? [],
1374
- ]);
1375
- }
1376
-
1377
1339
  private async _resolveOldBlockTag(
1378
1340
  oldBlockTag: RpcOldBlockTag
1379
1341
  ): Promise<bigint | "pending" | undefined> {
@@ -1485,22 +1447,6 @@ export class EthModule {
1485
1447
  return blockTag;
1486
1448
  }
1487
1449
 
1488
- private _newBlockTagToString(tag: RpcNewBlockTag): string {
1489
- if (typeof tag === "string") {
1490
- return tag;
1491
- }
1492
-
1493
- if (BigIntUtils.isBigInt(tag)) {
1494
- return tag.toString();
1495
- }
1496
-
1497
- if ("blockNumber" in tag) {
1498
- return tag.blockNumber.toString();
1499
- }
1500
-
1501
- return bufferToHex(tag.blockHash);
1502
- }
1503
-
1504
1450
  private _extractNormalizedLogTopics(
1505
1451
  topics: OptionalRpcLogTopics
1506
1452
  ): Array<Array<Buffer | null> | null> {
@@ -1532,16 +1478,6 @@ export class EthModule {
1532
1478
  return address;
1533
1479
  }
1534
1480
 
1535
- private async _getDefaultCallFrom(): Promise<Buffer> {
1536
- const localAccounts = await this._node.getLocalAccountAddresses();
1537
-
1538
- if (localAccounts.length === 0) {
1539
- return toBuffer(zeroAddress());
1540
- }
1541
-
1542
- return toBuffer(localAccounts[0]);
1543
- }
1544
-
1545
1481
  private async _sendTransactionAndReturnHash(tx: TypedTransaction) {
1546
1482
  let result = await this._node.sendTransaction(tx);
1547
1483
 
@@ -1816,15 +1752,4 @@ You can use them by running Hardhat Network with 'hardfork' ${EIP1559_MIN_HARDFO
1816
1752
  );
1817
1753
  }
1818
1754
  }
1819
-
1820
- private _checkPostMergeBlockTags(blockTag: "safe" | "finalized") {
1821
- const isPostMerge = this._node.isPostMergeHardfork();
1822
- const hardfork = this._node.hardfork;
1823
-
1824
- if (!isPostMerge) {
1825
- throw new InvalidArgumentsError(
1826
- `The '${blockTag}' block tag is not allowed in pre-merge hardforks. You are using the '${hardfork}' hardfork.`
1827
- );
1828
- }
1829
- }
1830
1755
  }
@@ -1377,6 +1377,18 @@ Hardhat Network's forking functionality only works with blocks from at least spu
1377
1377
  await this._persistIrregularWorldState();
1378
1378
  }
1379
1379
 
1380
+ public async traceCall(
1381
+ callParams: CallParams,
1382
+ block: bigint | "pending",
1383
+ traceConfig: RpcDebugTracingConfig
1384
+ ) {
1385
+ const vmDebugTracer = new VMDebugTracer(this._vm);
1386
+
1387
+ return vmDebugTracer.trace(async () => {
1388
+ await this.runCall(callParams, block);
1389
+ }, traceConfig);
1390
+ }
1391
+
1380
1392
  public async traceTransaction(hash: Buffer, config: RpcDebugTracingConfig) {
1381
1393
  const block = await this.getBlockByTransactionHash(hash);
1382
1394
  if (block === undefined) {