hardhat 2.17.1 → 2.17.2

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 (87) hide show
  1. package/builtin-tasks/compile.js +28 -4
  2. package/builtin-tasks/compile.js.map +1 -1
  3. package/builtin-tasks/task-names.d.ts +1 -0
  4. package/builtin-tasks/task-names.d.ts.map +1 -1
  5. package/builtin-tasks/task-names.js +3 -2
  6. package/builtin-tasks/task-names.js.map +1 -1
  7. package/internal/artifacts.d.ts +28 -0
  8. package/internal/artifacts.d.ts.map +1 -1
  9. package/internal/artifacts.js +39 -1
  10. package/internal/artifacts.js.map +1 -1
  11. package/internal/cli/project-creation.js +1 -1
  12. package/internal/core/errors-list.d.ts +28 -0
  13. package/internal/core/errors-list.d.ts.map +1 -1
  14. package/internal/core/errors-list.js +34 -0
  15. package/internal/core/errors-list.js.map +1 -1
  16. package/internal/core/jsonrpc/types/base-types.d.ts +1 -0
  17. package/internal/core/jsonrpc/types/base-types.d.ts.map +1 -1
  18. package/internal/core/jsonrpc/types/base-types.js +8 -1
  19. package/internal/core/jsonrpc/types/base-types.js.map +1 -1
  20. package/internal/core/jsonrpc/types/input/callRequest.d.ts +60 -0
  21. package/internal/core/jsonrpc/types/input/callRequest.d.ts.map +1 -1
  22. package/internal/core/jsonrpc/types/input/callRequest.js +13 -1
  23. package/internal/core/jsonrpc/types/input/callRequest.js.map +1 -1
  24. package/internal/core/providers/construction.d.ts.map +1 -1
  25. package/internal/core/providers/construction.js +1 -0
  26. package/internal/core/providers/construction.js.map +1 -1
  27. package/internal/hardhat-network/provider/fork/ForkBlockchain.d.ts.map +1 -1
  28. package/internal/hardhat-network/provider/fork/ForkBlockchain.js +13 -1
  29. package/internal/hardhat-network/provider/fork/ForkBlockchain.js.map +1 -1
  30. package/internal/hardhat-network/provider/modules/eth.d.ts.map +1 -1
  31. package/internal/hardhat-network/provider/modules/eth.js +3 -3
  32. package/internal/hardhat-network/provider/modules/eth.js.map +1 -1
  33. package/internal/hardhat-network/provider/node-types.d.ts +1 -0
  34. package/internal/hardhat-network/provider/node-types.d.ts.map +1 -1
  35. package/internal/hardhat-network/provider/node.d.ts +8 -1
  36. package/internal/hardhat-network/provider/node.d.ts.map +1 -1
  37. package/internal/hardhat-network/provider/node.js +65 -6
  38. package/internal/hardhat-network/provider/node.js.map +1 -1
  39. package/internal/hardhat-network/provider/provider.d.ts +1 -0
  40. package/internal/hardhat-network/provider/provider.d.ts.map +1 -1
  41. package/internal/hardhat-network/provider/provider.js +1 -0
  42. package/internal/hardhat-network/provider/provider.js.map +1 -1
  43. package/internal/hardhat-network/provider/utils/makeCommon.d.ts +1 -1
  44. package/internal/hardhat-network/provider/utils/makeCommon.d.ts.map +1 -1
  45. package/internal/hardhat-network/provider/utils/makeCommon.js +3 -1
  46. package/internal/hardhat-network/provider/utils/makeCommon.js.map +1 -1
  47. package/internal/hardhat-network/stack-traces/vm-debug-tracer.d.ts.map +1 -1
  48. package/internal/hardhat-network/stack-traces/vm-debug-tracer.js +8 -8
  49. package/internal/hardhat-network/stack-traces/vm-debug-tracer.js.map +1 -1
  50. package/internal/solidity/dependencyGraph.d.ts.map +1 -1
  51. package/internal/solidity/dependencyGraph.js +13 -3
  52. package/internal/solidity/dependencyGraph.js.map +1 -1
  53. package/internal/solidity/resolver.d.ts +2 -1
  54. package/internal/solidity/resolver.d.ts.map +1 -1
  55. package/internal/solidity/resolver.js +31 -17
  56. package/internal/solidity/resolver.js.map +1 -1
  57. package/package.json +12 -11
  58. package/src/builtin-tasks/compile.ts +33 -4
  59. package/src/builtin-tasks/task-names.ts +1 -0
  60. package/src/internal/artifacts.ts +40 -1
  61. package/src/internal/cli/project-creation.ts +1 -1
  62. package/src/internal/core/errors-list.ts +38 -0
  63. package/src/internal/core/jsonrpc/types/base-types.ts +15 -0
  64. package/src/internal/core/jsonrpc/types/input/callRequest.ts +35 -1
  65. package/src/internal/core/providers/construction.ts +2 -0
  66. package/src/internal/hardhat-network/provider/fork/ForkBlockchain.ts +24 -4
  67. package/src/internal/hardhat-network/provider/modules/eth.ts +18 -4
  68. package/src/internal/hardhat-network/provider/node-types.ts +1 -0
  69. package/src/internal/hardhat-network/provider/node.ts +110 -6
  70. package/src/internal/hardhat-network/provider/provider.ts +2 -0
  71. package/src/internal/hardhat-network/provider/utils/makeCommon.ts +9 -1
  72. package/src/internal/hardhat-network/stack-traces/vm-debug-tracer.ts +12 -10
  73. package/src/internal/solidity/dependencyGraph.ts +15 -3
  74. package/src/internal/solidity/resolver.ts +58 -16
  75. package/src/types/config.ts +2 -0
  76. package/src/utils/contract-names.ts +1 -0
  77. package/src/utils/remappings.ts +17 -0
  78. package/types/config.d.ts +2 -0
  79. package/types/config.d.ts.map +1 -1
  80. package/utils/contract-names.d.ts +1 -0
  81. package/utils/contract-names.d.ts.map +1 -1
  82. package/utils/contract-names.js +1 -0
  83. package/utils/contract-names.js.map +1 -1
  84. package/utils/remappings.d.ts +2 -0
  85. package/utils/remappings.d.ts.map +1 -0
  86. package/utils/remappings.js +15 -0
  87. package/utils/remappings.js.map +1 -0
@@ -315,7 +315,7 @@ async function createPackageJson() {
315
315
  function showStarOnGitHubMessage() {
316
316
  console.log(
317
317
  chalk.cyan("Give Hardhat a star on Github if you're enjoying it!") +
318
- emoji(" 💞✨")
318
+ emoji(" ⭐️✨")
319
319
  );
320
320
  console.log();
321
321
  console.log(chalk.cyan(" https://github.com/NomicFoundation/hardhat"));
@@ -278,6 +278,16 @@ Rename the file to use the .cjs to fix this problem.`,
278
278
  To initialize the provider, make sure you first call \`.init()\` or any method that hits a node like request, send or sendAsync.`,
279
279
  shouldBeReported: true,
280
280
  },
281
+ INVALID_READ_OF_DIRECTORY: {
282
+ number: 22,
283
+ message:
284
+ "Invalid file path %absolutePath%. Attempting to read a directory instead of a file.",
285
+ title: "Invalid read: a directory cannot be read",
286
+ description: `An attempt was made to read a file, but a path to a directory was provided.
287
+
288
+ Please double check the file path.`,
289
+ shouldBeReported: false,
290
+ },
281
291
  },
282
292
  NETWORK: {
283
293
  CONFIG_NOT_FOUND: {
@@ -585,6 +595,14 @@ Please double check your task definitions.`,
585
595
  What makes these types special is that they can be represented as strings, so you can write them down in the terminal.`,
586
596
  shouldBeReported: false,
587
597
  },
598
+ DEPRECATED_TRANSFORM_IMPORT_TASK: {
599
+ number: 213,
600
+ title: "Use of deprecated remapping task",
601
+ message:
602
+ "Task TASK_COMPILE_TRANSFORM_IMPORT_NAME is deprecated. Please update your @nomicfoundation/hardhat-foundry plugin version.",
603
+ description: `This task has been deprecated in favor of a new approach.`,
604
+ shouldBeReported: true,
605
+ },
588
606
  },
589
607
  ARGUMENTS: {
590
608
  INVALID_ENV_VAR_VALUE: {
@@ -855,6 +873,26 @@ Use a relative import instead of referencing the package's name.`,
855
873
  Please double check your imports and installed libraries.`,
856
874
  shouldBeReported: false,
857
875
  },
876
+ INVALID_IMPORT_OF_DIRECTORY: {
877
+ number: 414,
878
+ message:
879
+ "Invalid import %imported% from %from%. Attempting to import a directory. Directories cannot be imported.",
880
+ title: "Invalid import: a directory cannot be imported",
881
+ description: `A Solidity file is attempting to import a directory, which is not possible.
882
+
883
+ Please double check your imports.`,
884
+ shouldBeReported: false,
885
+ },
886
+ AMBIGUOUS_SOURCE_NAMES: {
887
+ number: 415,
888
+ message:
889
+ "Two different source names (%sourcenames%) resolve to the same file (%file%).",
890
+ title: "Ambiguous source names",
891
+ description: `Two different source names map to the same file.
892
+
893
+ This is probably caused by multiple remappings pointing to the same source file.`,
894
+ shouldBeReported: false,
895
+ },
858
896
  },
859
897
  SOLC: {
860
898
  INVALID_VERSION: {
@@ -40,6 +40,17 @@ export const rpcStorageSlot = new t.Type<bigint>(
40
40
  t.identity
41
41
  );
42
42
 
43
+ // This type is necessary because objects' keys need to be either strings or numbers to be properly handled by the 'io-ts' module.
44
+ // If they are not defined as strings or numbers, the type definition will result in an empty object without the required properties.
45
+ // For example, instead of displaying { ke1: value1 }, it will display {}
46
+ export const rpcStorageSlotHexString = new t.Type<string>(
47
+ "Storage slot hex string",
48
+ (x): x is string => typeof x === "string",
49
+ (u, c) =>
50
+ validateRpcStorageSlotHexString(u) ? t.success(u) : t.failure(u, c),
51
+ t.identity
52
+ );
53
+
43
54
  function validateStorageSlot(u: unknown, c: t.Context): t.Validation<bigint> {
44
55
  if (typeof u !== "string") {
45
56
  return t.failure(
@@ -185,6 +196,10 @@ export function rpcDataToBuffer(data: string): Buffer {
185
196
 
186
197
  // Type guards
187
198
 
199
+ function validateRpcStorageSlotHexString(u: unknown): u is string {
200
+ return typeof u === "string" && /^0x([0-9a-fA-F]){64}$/.test(u);
201
+ }
202
+
188
203
  function isRpcQuantityString(u: unknown): u is string {
189
204
  return (
190
205
  typeof u === "string" &&
@@ -2,7 +2,14 @@ import * as t from "io-ts";
2
2
 
3
3
  import { optionalOrNullable } from "../../../../util/io-ts";
4
4
  import { rpcAccessList } from "../access-list";
5
- import { rpcAddress, rpcData, rpcQuantity } from "../base-types";
5
+ import {
6
+ rpcAddress,
7
+ rpcData,
8
+ rpcQuantity,
9
+ rpcStorageSlot,
10
+ rpcStorageSlotHexString,
11
+ } from "../base-types";
12
+ import { address } from "../../../config/config-validation";
6
13
 
7
14
  // Type used by eth_call and eth_estimateGas
8
15
  export const rpcCallRequest = t.type(
@@ -21,3 +28,30 @@ export const rpcCallRequest = t.type(
21
28
  );
22
29
 
23
30
  export type RpcCallRequest = t.TypeOf<typeof rpcCallRequest>;
31
+
32
+ // Types used by eth_call to configure the state override set
33
+ export const stateProperties = t.record(
34
+ rpcStorageSlotHexString,
35
+ rpcStorageSlot
36
+ );
37
+
38
+ export const stateOverrideOptions = t.type(
39
+ {
40
+ balance: optionalOrNullable(rpcQuantity),
41
+ nonce: optionalOrNullable(rpcQuantity),
42
+ code: optionalOrNullable(rpcData),
43
+ state: optionalOrNullable(stateProperties),
44
+ stateDiff: optionalOrNullable(stateProperties),
45
+ },
46
+ "stateOverrideOptions"
47
+ );
48
+
49
+ export const stateOverrideSet = t.record(address, stateOverrideOptions);
50
+ export const optionalStateOverrideSet = optionalOrNullable(stateOverrideSet);
51
+
52
+ export type StateProperties = t.TypeOf<typeof stateProperties>;
53
+ export type StateOverrideOptions = t.TypeOf<typeof stateOverrideOptions>;
54
+ export type StateOverrideSet = t.TypeOf<typeof stateOverrideSet>;
55
+ export type OptionalStateOverrideSet = t.TypeOf<
56
+ typeof optionalStateOverrideSet
57
+ >;
@@ -116,6 +116,8 @@ export async function createProvider(
116
116
  forkConfig,
117
117
  forkCachePath:
118
118
  paths !== undefined ? getForkCacheDirPath(paths) : undefined,
119
+ enableTransientStorage:
120
+ hardhatNetConfig.enableTransientStorage ?? false,
119
121
  },
120
122
  new ModulesLogger(hardhatNetConfig.loggingEnabled),
121
123
  artifacts
@@ -348,10 +348,30 @@ export class ForkBlockchain
348
348
  return undefined;
349
349
  }
350
350
 
351
- const transaction = new ReadOnlyValidTransaction(
352
- new Address(rpcTransaction.from),
353
- rpcToTxData(rpcTransaction)
354
- );
351
+ let transaction: TypedTransaction;
352
+
353
+ if (rpcTransaction.type === undefined || rpcTransaction.type === 0n) {
354
+ transaction = new ReadOnlyValidTransaction(
355
+ new Address(rpcTransaction.from),
356
+ rpcToTxData(rpcTransaction)
357
+ );
358
+ } else if (rpcTransaction.type === 1n) {
359
+ transaction = new ReadOnlyValidEIP2930Transaction(
360
+ new Address(rpcTransaction.from),
361
+ rpcToTxData(rpcTransaction)
362
+ );
363
+ } else if (rpcTransaction.type === 2n) {
364
+ transaction = new ReadOnlyValidEIP1559Transaction(
365
+ new Address(rpcTransaction.from),
366
+ rpcToTxData(rpcTransaction) as FeeMarketEIP1559TxData
367
+ );
368
+ } else {
369
+ transaction = new ReadOnlyValidUnknownTypeTransaction(
370
+ new Address(rpcTransaction.from),
371
+ Number(rpcTransaction.type),
372
+ rpcToTxData(rpcTransaction)
373
+ );
374
+ }
355
375
 
356
376
  this._data.addTransaction(transaction);
357
377
 
@@ -37,6 +37,8 @@ import {
37
37
  RpcOldBlockTag,
38
38
  } from "../../../core/jsonrpc/types/input/blockTag";
39
39
  import {
40
+ optionalStateOverrideSet,
41
+ OptionalStateOverrideSet,
40
42
  rpcCallRequest,
41
43
  RpcCallRequest,
42
44
  } from "../../../core/jsonrpc/types/input/callRequest";
@@ -334,13 +336,21 @@ export class EthModule {
334
336
 
335
337
  // eth_call
336
338
 
337
- private _callParams(params: any[]): [RpcCallRequest, OptionalRpcNewBlockTag] {
338
- return validateParams(params, rpcCallRequest, optionalRpcNewBlockTag);
339
+ private _callParams(
340
+ params: any[]
341
+ ): [RpcCallRequest, OptionalRpcNewBlockTag, OptionalStateOverrideSet] {
342
+ return validateParams(
343
+ params,
344
+ rpcCallRequest,
345
+ optionalRpcNewBlockTag,
346
+ optionalStateOverrideSet
347
+ );
339
348
  }
340
349
 
341
350
  private async _callAction(
342
351
  rpcCall: RpcCallRequest,
343
- blockTag: OptionalRpcNewBlockTag
352
+ blockTag: OptionalRpcNewBlockTag,
353
+ stateOverrideSet: OptionalStateOverrideSet
344
354
  ): Promise<string> {
345
355
  this._validateTransactionAndCallRequest(rpcCall);
346
356
 
@@ -353,7 +363,11 @@ export class EthModule {
353
363
  trace,
354
364
  error,
355
365
  consoleLogMessages,
356
- } = await this._node.runCall(callParams, blockNumberOrPending);
366
+ } = await this._node.runCall(
367
+ callParams,
368
+ blockNumberOrPending,
369
+ stateOverrideSet
370
+ );
357
371
 
358
372
  const code = await this._node.getCodeFromTrace(trace, blockNumberOrPending);
359
373
 
@@ -32,6 +32,7 @@ interface CommonConfig {
32
32
  coinbase: string;
33
33
  chains: HardhatNetworkChainsConfig;
34
34
  allowBlocksWithSameTimestamp: boolean;
35
+ enableTransientStorage: boolean;
35
36
  }
36
37
 
37
38
  export type LocalNodeConfig = CommonConfig;
@@ -1,5 +1,5 @@
1
1
  import { Block, HeaderData } from "@nomicfoundation/ethereumjs-block";
2
- import { Common } from "@nomicfoundation/ethereumjs-common";
2
+ import { Common, CustomCommonOpts } from "@nomicfoundation/ethereumjs-common";
3
3
  import {
4
4
  AccessListEIP2930Transaction,
5
5
  FeeMarketEIP1559Transaction,
@@ -83,6 +83,10 @@ import { VMTracer } from "../stack-traces/vm-tracer";
83
83
  import "./ethereumjs-workarounds";
84
84
  import { rpcQuantityToBigInt } from "../../core/jsonrpc/types/base-types";
85
85
  import { JsonRpcClient } from "../jsonrpc/client";
86
+ import {
87
+ StateOverrideSet,
88
+ StateProperties,
89
+ } from "../../core/jsonrpc/types/input/callRequest";
86
90
  import { bloomFilter, Filter, filterLogs, LATEST_BLOCK, Type } from "./filter";
87
91
  import { ForkBlockchain } from "./fork/ForkBlockchain";
88
92
  import { ForkStateManager } from "./fork/ForkStateManager";
@@ -146,6 +150,7 @@ export class HardhatNode extends EventEmitter {
146
150
  networkId,
147
151
  chainId,
148
152
  allowBlocksWithSameTimestamp,
153
+ enableTransientStorage,
149
154
  } = config;
150
155
 
151
156
  const allowUnlimitedContractSize =
@@ -303,7 +308,8 @@ export class HardhatNode extends EventEmitter {
303
308
  forkBlockNum,
304
309
  forkBlockHash,
305
310
  nextBlockBaseFeePerGas,
306
- forkClient
311
+ forkClient,
312
+ enableTransientStorage
307
313
  );
308
314
 
309
315
  return [common, node];
@@ -390,7 +396,8 @@ Hardhat Network's forking functionality only works with blocks from at least spu
390
396
  private _forkBlockNumber?: bigint,
391
397
  private _forkBlockHash?: string,
392
398
  nextBlockBaseFee?: bigint,
393
- private _forkClient?: JsonRpcClient
399
+ private _forkClient?: JsonRpcClient,
400
+ private readonly _enableTransientStorage: boolean = false
394
401
  ) {
395
402
  super();
396
403
 
@@ -624,7 +631,8 @@ Hardhat Network's forking functionality only works with blocks from at least spu
624
631
 
625
632
  public async runCall(
626
633
  call: CallParams,
627
- blockNumberOrPending: bigint | "pending"
634
+ blockNumberOrPending: bigint | "pending",
635
+ stateOverrideSet: StateOverrideSet = {}
628
636
  ): Promise<RunCallResult> {
629
637
  let txParams: TransactionParams;
630
638
 
@@ -659,7 +667,13 @@ Hardhat Network's forking functionality only works with blocks from at least spu
659
667
 
660
668
  const result = await this._runInBlockContext(
661
669
  blockNumberOrPending,
662
- async () => this._runTxAndRevertMutations(tx, blockNumberOrPending, true)
670
+ async () =>
671
+ this._runTxAndRevertMutations(
672
+ tx,
673
+ blockNumberOrPending,
674
+ true,
675
+ stateOverrideSet
676
+ )
663
677
  );
664
678
 
665
679
  const traces = await this._gatherTraces(result.execResult);
@@ -2354,6 +2368,83 @@ Hardhat Network's forking functionality only works with blocks from at least spu
2354
2368
  );
2355
2369
  }
2356
2370
 
2371
+ private async _applyStateOverrideSet(stateOverrideSet: StateOverrideSet) {
2372
+ // Multiple state override set can be configured for different addresses, hence the loop
2373
+ for (const [addrToOverride, stateOverrideOptions] of Object.entries(
2374
+ stateOverrideSet
2375
+ )) {
2376
+ const address = new Address(toBuffer(addrToOverride));
2377
+
2378
+ const { balance, nonce, code, state, stateDiff } = stateOverrideOptions;
2379
+
2380
+ await this._overrideBalanceAndNonce(address, balance, nonce);
2381
+ await this._overrideCode(address, code);
2382
+ await this._overrideStateAndStateDiff(address, state, stateDiff);
2383
+ }
2384
+ }
2385
+
2386
+ private async _overrideBalanceAndNonce(
2387
+ address: Address,
2388
+ balance: bigint | undefined,
2389
+ nonce: bigint | undefined
2390
+ ) {
2391
+ const MAX_NONCE = 2n ** 64n - 1n;
2392
+ const MAX_BALANCE = 2n ** 256n - 1n;
2393
+
2394
+ if (nonce !== undefined && nonce > MAX_NONCE) {
2395
+ throw new InvalidInputError(
2396
+ `The 'nonce' property should occupy a maximum of 8 bytes (nonce=${nonce}).`
2397
+ );
2398
+ }
2399
+
2400
+ if (balance !== undefined && balance > MAX_BALANCE) {
2401
+ throw new InvalidInputError(
2402
+ `The 'balance' property should occupy a maximum of 32 bytes (balance=${balance}).`
2403
+ );
2404
+ }
2405
+
2406
+ await this._stateManager.modifyAccountFields(address, {
2407
+ balance,
2408
+ nonce,
2409
+ });
2410
+ }
2411
+
2412
+ private async _overrideCode(address: Address, code: Buffer | undefined) {
2413
+ if (code === undefined) return;
2414
+
2415
+ await this._stateManager.putContractCode(address, code);
2416
+ }
2417
+
2418
+ private async _overrideStateAndStateDiff(
2419
+ address: Address,
2420
+ state: StateProperties | undefined,
2421
+ stateDiff: StateProperties | undefined
2422
+ ) {
2423
+ let newState;
2424
+
2425
+ if (state !== undefined && stateDiff === undefined) {
2426
+ await this._stateManager.clearContractStorage(address);
2427
+ newState = state;
2428
+ } else if (state === undefined && stateDiff !== undefined) {
2429
+ newState = stateDiff;
2430
+ } else if (state === undefined && stateDiff === undefined) {
2431
+ // nothing to do
2432
+ return;
2433
+ } else {
2434
+ throw new InvalidInputError(
2435
+ "The properties 'state' and 'stateDiff' cannot be used simultaneously when configuring the state override set passed to the eth_call method."
2436
+ );
2437
+ }
2438
+
2439
+ for (const [storageKey, value] of Object.entries(newState)) {
2440
+ await this._stateManager.putContractStorage(
2441
+ address,
2442
+ toBuffer(storageKey),
2443
+ setLengthLeft(bigIntToBuffer(value), 32)
2444
+ );
2445
+ }
2446
+ }
2447
+
2357
2448
  /**
2358
2449
  * This function runs a transaction and reverts all the modifications that it
2359
2450
  * makes.
@@ -2361,10 +2452,13 @@ Hardhat Network's forking functionality only works with blocks from at least spu
2361
2452
  private async _runTxAndRevertMutations(
2362
2453
  tx: TypedTransaction,
2363
2454
  blockNumberOrPending: bigint | "pending",
2364
- forceBaseFeeZero = false
2455
+ forceBaseFeeZero = false,
2456
+ stateOverrideSet: StateOverrideSet = {}
2365
2457
  ): Promise<RunTxResult> {
2366
2458
  const initialStateRoot = await this._stateManager.getStateRoot();
2367
2459
 
2460
+ await this._applyStateOverrideSet(stateOverrideSet);
2461
+
2368
2462
  let blockContext: Block | undefined;
2369
2463
  let originalCommon: Common | undefined;
2370
2464
 
@@ -2400,6 +2494,7 @@ Hardhat Network's forking functionality only works with blocks from at least spu
2400
2494
  },
2401
2495
  {
2402
2496
  hardfork: this._selectHardfork(blockContext.header.number),
2497
+ ...this._getTransientStorageSettings(),
2403
2498
  }
2404
2499
  );
2405
2500
 
@@ -2740,6 +2835,7 @@ Hardhat Network's forking functionality only works with blocks from at least spu
2740
2835
  },
2741
2836
  {
2742
2837
  hardfork: this._selectHardfork(BigInt(blockNumber)),
2838
+ ...this._getTransientStorageSettings(),
2743
2839
  }
2744
2840
  );
2745
2841
 
@@ -2750,4 +2846,12 @@ Hardhat Network's forking functionality only works with blocks from at least spu
2750
2846
  );
2751
2847
  }
2752
2848
  }
2849
+
2850
+ private _getTransientStorageSettings(): Partial<CustomCommonOpts> {
2851
+ if (this._enableTransientStorage) {
2852
+ return { eips: [1153] };
2853
+ }
2854
+
2855
+ return {};
2856
+ }
2753
2857
  }
@@ -80,6 +80,7 @@ interface HardhatNetworkProviderConfig {
80
80
  experimentalHardhatNetworkMessageTraceHooks?: BoundExperimentalHardhatNetworkMessageTraceHook[];
81
81
  forkConfig?: ForkConfig;
82
82
  forkCachePath?: string;
83
+ enableTransientStorage: boolean;
83
84
  }
84
85
 
85
86
  export class HardhatNetworkProvider
@@ -253,6 +254,7 @@ export class HardhatNetworkProvider
253
254
  coinbase: this._config.coinbase ?? DEFAULT_COINBASE,
254
255
  chains: this._config.chains,
255
256
  allowBlocksWithSameTimestamp: this._config.allowBlocksWithSameTimestamp,
257
+ enableTransientStorage: this._config.enableTransientStorage,
256
258
  };
257
259
 
258
260
  const [common, node] = await HardhatNode.create(config);
@@ -2,7 +2,14 @@ import { Common } from "@nomicfoundation/ethereumjs-common";
2
2
 
3
3
  import { LocalNodeConfig } from "../node-types";
4
4
 
5
- export function makeCommon({ chainId, networkId, hardfork }: LocalNodeConfig) {
5
+ export function makeCommon({
6
+ chainId,
7
+ networkId,
8
+ hardfork,
9
+ enableTransientStorage,
10
+ }: LocalNodeConfig) {
11
+ const otherSettings = enableTransientStorage ? { eips: [1153] } : {};
12
+
6
13
  const common = Common.custom(
7
14
  {
8
15
  chainId,
@@ -10,6 +17,7 @@ export function makeCommon({ chainId, networkId, hardfork }: LocalNodeConfig) {
10
17
  },
11
18
  {
12
19
  hardfork,
20
+ ...otherSettings,
13
21
  }
14
22
  );
15
23
 
@@ -280,10 +280,12 @@ export class VMDebugTracer {
280
280
  "There shouldn't be two messages one after another"
281
281
  );
282
282
 
283
- // the increase in memory size of a revert is immediately
284
- // reflected, so we don't treat it as a memory expansion
285
- // of the previous step
286
- if (structLog.op !== "REVERT") {
283
+ // memory opcodes reflect the expanded memory in that step,
284
+ // so we correct them
285
+ if (
286
+ previousStructLog.op === "MSTORE" ||
287
+ previousStructLog.op === "MLOAD"
288
+ ) {
287
289
  const memoryLengthDifference =
288
290
  structLog.memory.length - previousStructLog.memory.length;
289
291
  for (let k = 0; k < memoryLengthDifference; k++) {
@@ -315,13 +317,13 @@ export class VMDebugTracer {
315
317
  }
316
318
 
317
319
  private _getMemory(step: InterpreterStep): string[] {
318
- const memory = Buffer.from(step.memory)
319
- .toString("hex")
320
- .match(/.{1,64}/g);
320
+ const rawMemory =
321
+ Buffer.from(step.memory)
322
+ .toString("hex")
323
+ .match(/.{1,64}/g) ?? [];
321
324
 
322
- const result = memory === null ? [] : [...memory];
323
-
324
- return result;
325
+ // Remove the additional non allocated memory
326
+ return rawMemory.slice(0, Number(step.memoryWordCount));
325
327
  }
326
328
 
327
329
  private _getStack(step: InterpreterStep): string[] {
@@ -1,4 +1,6 @@
1
1
  import * as taskTypes from "../../types/builtin-tasks";
2
+ import { HardhatError } from "../core/errors";
3
+ import { ERRORS } from "../core/errors-list";
2
4
 
3
5
  import { ResolvedFile, Resolver } from "./resolver";
4
6
 
@@ -22,7 +24,8 @@ export class DependencyGraph implements taskTypes.DependencyGraph {
22
24
  private _resolvedFiles = new Map<string, ResolvedFile>();
23
25
  private _dependenciesPerFile = new Map<string, Set<ResolvedFile>>();
24
26
 
25
- private readonly _visitedFiles = new Set<string>();
27
+ // map absolute paths to source names
28
+ private readonly _visitedFiles = new Map<string, string>();
26
29
 
27
30
  private constructor() {}
28
31
 
@@ -160,11 +163,20 @@ export class DependencyGraph implements taskTypes.DependencyGraph {
160
163
  resolver: Resolver,
161
164
  file: ResolvedFile
162
165
  ): Promise<void> {
163
- if (this._visitedFiles.has(file.absolutePath)) {
166
+ const sourceName = this._visitedFiles.get(file.absolutePath);
167
+
168
+ if (sourceName !== undefined) {
169
+ if (sourceName !== file.sourceName) {
170
+ throw new HardhatError(ERRORS.RESOLVER.AMBIGUOUS_SOURCE_NAMES, {
171
+ sourcenames: `'${sourceName}' and '${file.sourceName}'`,
172
+ file: file.absolutePath,
173
+ });
174
+ }
175
+
164
176
  return;
165
177
  }
166
178
 
167
- this._visitedFiles.add(file.absolutePath);
179
+ this._visitedFiles.set(file.absolutePath, file.sourceName);
168
180
 
169
181
  const dependencies = new Set<ResolvedFile>();
170
182
  this._resolvedFiles.set(file.sourceName, file);