0
# Network Helpers
1
2
Network helpers provide comprehensive blockchain testing utilities for fixture management, time manipulation, account impersonation, and network state control. These utilities are re-exported from `@nomicfoundation/hardhat-network-helpers` for convenient access.
3
4
## Capabilities
5
6
### Fixture Management
7
8
Efficient test setup using blockchain snapshots for consistent test environments.
9
10
```typescript { .api }
11
/**
12
* Executes fixture function and creates blockchain snapshots for efficient test setup
13
* Subsequent calls with the same fixture restore the blockchain to the snapshot
14
* @param fixture - Named function that returns a promise with test setup data
15
* @returns Promise resolving to the fixture data
16
* @throws FixtureAnonymousFunctionError if fixture is an anonymous function
17
* @throws FixtureSnapshotError if snapshot restoration fails
18
*/
19
function loadFixture<T>(fixture: Fixture<T>): Promise<T>;
20
21
/**
22
* Clears all existing snapshots from memory
23
* Use when you need to reset all cached fixture states
24
*/
25
function clearSnapshots(): Promise<void>;
26
27
type Fixture<T> = () => Promise<T>;
28
```
29
30
**Usage Examples:**
31
32
```typescript
33
import { loadFixture } from "@nomicfoundation/hardhat-toolbox/network-helpers";
34
import { ethers } from "hardhat";
35
36
describe("Token Contract", function () {
37
// ✅ Correct: Named function
38
async function deployTokenFixture() {
39
const [owner, addr1, addr2] = await ethers.getSigners();
40
const Token = await ethers.getContractFactory("Token");
41
const token = await Token.deploy();
42
return { token, owner, addr1, addr2 };
43
}
44
45
it("should transfer tokens between accounts", async function () {
46
// First call executes fixture and takes snapshot
47
const { token, owner, addr1 } = await loadFixture(deployTokenFixture);
48
49
await token.transfer(addr1.address, 50);
50
expect(await token.balanceOf(addr1.address)).to.equal(50);
51
});
52
53
it("should handle multiple transfers", async function () {
54
// Second call restores blockchain to snapshot, no re-execution
55
const { token, owner, addr1, addr2 } = await loadFixture(deployTokenFixture);
56
57
await token.transfer(addr1.address, 30);
58
await token.transfer(addr2.address, 20);
59
expect(await token.balanceOf(addr1.address)).to.equal(30);
60
});
61
});
62
63
// ❌ Incorrect: Anonymous function will execute every time
64
// await loadFixture(async () => { ... });
65
```
66
67
### Time Manipulation
68
69
Control blockchain time and block progression for testing time-dependent contracts.
70
71
```typescript { .api }
72
namespace time {
73
/**
74
* Get the timestamp of the latest block
75
* @returns Promise resolving to the latest block timestamp in seconds
76
*/
77
function latest(): Promise<number>;
78
79
/**
80
* Get the block number of the latest block
81
* @returns Promise resolving to the latest block number
82
*/
83
function latestBlock(): Promise<number>;
84
85
/**
86
* Increase the time of the next block by the given number of seconds
87
* Does not mine a new block - use mine() to apply the time change
88
* @param seconds - Number of seconds to increase time by
89
*/
90
function increase(seconds: number): Promise<void>;
91
92
/**
93
* Set the time of the next block to the given timestamp
94
* Does not mine a new block - use mine() to apply the time change
95
* @param timestamp - Target timestamp in seconds since epoch
96
*/
97
function increaseTo(timestamp: number): Promise<void>;
98
99
/**
100
* Mine a single block, advancing the block number by 1
101
* Applies any pending time changes from increase() or increaseTo()
102
*/
103
function advanceBlock(): Promise<void>;
104
105
/**
106
* Mine blocks until reaching the target block number
107
* @param blockNumber - Target block number to reach
108
*/
109
function advanceBlockTo(blockNumber: number): Promise<void>;
110
111
/**
112
* Set the timestamp for the next block that will be mined
113
* @param timestamp - Target timestamp in seconds since epoch
114
*/
115
function setNextBlockTimestamp(timestamp: number): Promise<void>;
116
}
117
```
118
119
**Time Duration Helpers:**
120
121
```typescript { .api }
122
namespace time.duration {
123
/** Convert milliseconds to duration value */
124
function millis(amount: number): number;
125
/** Convert seconds to duration value */
126
function seconds(amount: number): number;
127
/** Convert minutes to duration value */
128
function minutes(amount: number): number;
129
/** Convert hours to duration value */
130
function hours(amount: number): number;
131
/** Convert days to duration value */
132
function days(amount: number): number;
133
/** Convert weeks to duration value */
134
function weeks(amount: number): number;
135
/** Convert years to duration value */
136
function years(amount: number): number;
137
}
138
```
139
140
**Usage Examples:**
141
142
```typescript
143
import { time, mine } from "@nomicfoundation/hardhat-toolbox/network-helpers";
144
145
describe("TimeLock Contract", function () {
146
it("should unlock after time period", async function () {
147
const { timeLock } = await loadFixture(deployTimeLockFixture);
148
149
// Get current time and set unlock time
150
const currentTime = await time.latest();
151
const unlockTime = currentTime + time.duration.days(30);
152
153
// Try to unlock immediately (should fail)
154
await expect(timeLock.unlock()).to.be.revertedWith("Still locked");
155
156
// Advance time to unlock period
157
await time.increaseTo(unlockTime);
158
await mine(); // Apply the time change
159
160
// Now unlock should work
161
await expect(timeLock.unlock()).not.to.be.reverted;
162
});
163
164
it("should handle multiple time advances", async function () {
165
const { timeLock } = await loadFixture(deployTimeLockFixture);
166
167
// Advance time in steps
168
await time.increase(time.duration.days(10));
169
await mine();
170
171
await time.increase(time.duration.days(15));
172
await mine();
173
174
await time.increase(time.duration.days(10)); // Total: 35 days
175
await mine();
176
177
await expect(timeLock.unlock()).not.to.be.reverted;
178
});
179
});
180
```
181
182
### Block Mining
183
184
Control block mining and transaction processing for testing block-dependent logic.
185
186
```typescript { .api }
187
/**
188
* Mine one or more blocks
189
* @param blocks - Number of blocks to mine (default: 1)
190
*/
191
function mine(blocks?: number): Promise<void>;
192
193
/**
194
* Mine blocks until reaching the target block number
195
* @param blockNumber - Target block number to reach
196
*/
197
function mineUpTo(blockNumber: number): Promise<void>;
198
199
/**
200
* Drop a pending transaction from the mempool
201
* Useful for testing transaction failure scenarios
202
* @param txHash - Hash of the transaction to drop
203
*/
204
function dropTransaction(txHash: string): Promise<void>;
205
```
206
207
**Usage Examples:**
208
209
```typescript
210
import { mine, mineUpTo, time } from "@nomicfoundation/hardhat-toolbox/network-helpers";
211
212
describe("Auction Contract", function () {
213
it("should end auction after block deadline", async function () {
214
const { auction } = await loadFixture(deployAuctionFixture);
215
216
const currentBlock = await time.latestBlock();
217
const endBlock = currentBlock + 100;
218
219
// Place some bids
220
await auction.placeBid({ value: ethers.parseEther("1") });
221
222
// Mine to just before end
223
await mineUpTo(endBlock - 1);
224
await expect(auction.placeBid({ value: ethers.parseEther("2") })).not.to.be.reverted;
225
226
// Mine past end block
227
await mine(2);
228
await expect(auction.placeBid({ value: ethers.parseEther("3") }))
229
.to.be.revertedWith("Auction ended");
230
});
231
});
232
```
233
234
### Account Impersonation
235
236
Impersonate any account for testing interactions with existing contracts and accounts.
237
238
```typescript { .api }
239
/**
240
* Start impersonating an account
241
* Allows sending transactions from that account without private key
242
* @param address - Address of the account to impersonate
243
*/
244
function impersonateAccount(address: string): Promise<void>;
245
246
/**
247
* Stop impersonating an account
248
* @param address - Address of the account to stop impersonating
249
*/
250
function stopImpersonatingAccount(address: string): Promise<void>;
251
252
/**
253
* Set the balance of an account
254
* @param address - Account address
255
* @param balance - New balance in wei (use ethers.parseEther for ether amounts)
256
*/
257
function setBalance(address: string, balance: bigint): Promise<void>;
258
259
/**
260
* Set the nonce of an account
261
* @param address - Account address
262
* @param nonce - New nonce value
263
*/
264
function setNonce(address: string, nonce: number): Promise<void>;
265
```
266
267
**Usage Examples:**
268
269
```typescript
270
import {
271
impersonateAccount,
272
stopImpersonatingAccount,
273
setBalance
274
} from "@nomicfoundation/hardhat-toolbox/network-helpers";
275
import { ethers } from "hardhat";
276
277
describe("DAO Governance", function () {
278
it("should allow whale to vote", async function () {
279
const { dao, governanceToken } = await loadFixture(deployDAOFixture);
280
281
// Impersonate a large token holder
282
const whaleAddress = "0x742d35Cc6635C0532925a3b8D7389b18A68Ff0cd";
283
await impersonateAccount(whaleAddress);
284
285
// Give the whale some ETH for gas fees
286
await setBalance(whaleAddress, ethers.parseEther("10"));
287
288
// Get signer for the impersonated account
289
const whaleSigner = await ethers.getSigner(whaleAddress);
290
291
// Vote using the whale's tokens
292
await dao.connect(whaleSigner).vote(1, true);
293
294
// Verify the vote was counted
295
const proposal = await dao.proposals(1);
296
expect(proposal.votesFor).to.be.gt(0);
297
298
// Stop impersonating
299
await stopImpersonatingAccount(whaleAddress);
300
});
301
});
302
```
303
304
### State Manipulation
305
306
Directly manipulate blockchain state for testing edge cases and complex scenarios.
307
308
```typescript { .api }
309
/**
310
* Get storage value at a specific slot for a contract
311
* @param address - Contract address
312
* @param position - Storage slot position (hex string)
313
* @returns Storage value as hex string
314
*/
315
function getStorageAt(address: string, position: string): Promise<string>;
316
317
/**
318
* Set storage value at a specific slot for a contract
319
* @param address - Contract address
320
* @param position - Storage slot position (hex string)
321
* @param value - New storage value (hex string)
322
*/
323
function setStorageAt(address: string, position: string, value: string): Promise<void>;
324
325
/**
326
* Set the contract code at an address
327
* @param address - Address to set code at
328
* @param code - Contract bytecode (hex string)
329
*/
330
function setCode(address: string, code: string): Promise<void>;
331
```
332
333
**Usage Examples:**
334
335
```typescript
336
import { setStorageAt, getStorageAt } from "@nomicfoundation/hardhat-toolbox/network-helpers";
337
338
describe("Storage Manipulation", function () {
339
it("should modify contract storage directly", async function () {
340
const { token } = await loadFixture(deployTokenFixture);
341
342
// Modify total supply directly (assuming it's at slot 0)
343
const newSupply = ethers.parseEther("1000000");
344
await setStorageAt(
345
token.target,
346
"0x0", // Storage slot 0
347
ethers.toBeHex(newSupply, 32) // Convert to 32-byte hex
348
);
349
350
// Verify the change
351
expect(await token.totalSupply()).to.equal(newSupply);
352
});
353
});
354
```
355
356
### Network Configuration
357
358
Control network-level settings and behavior.
359
360
```typescript { .api }
361
/**
362
* Set the block gas limit for subsequent blocks
363
* @param gasLimit - New gas limit for blocks
364
*/
365
function setBlockGasLimit(gasLimit: number): Promise<void>;
366
367
/**
368
* Set the coinbase address (block miner address)
369
* @param address - New coinbase address
370
*/
371
function setCoinbase(address: string): Promise<void>;
372
373
/**
374
* Set the prevRandao value for the next block
375
* @param randao - New prevRandao value (hex string)
376
*/
377
function setPrevRandao(randao: string): Promise<void>;
378
379
/**
380
* Set the base fee per gas for the next block
381
* @param baseFee - New base fee in wei
382
*/
383
function setNextBlockBaseFeePerGas(baseFee: bigint): Promise<void>;
384
```
385
386
### Snapshot Management
387
388
Advanced snapshot functionality for complex test scenarios.
389
390
```typescript { .api }
391
/**
392
* Take a snapshot of the current blockchain state
393
* @returns SnapshotRestorer object with restore capability
394
*/
395
function takeSnapshot(): Promise<SnapshotRestorer>;
396
397
/**
398
* Reset the blockchain to a clean state
399
* @param forking - Optional forking configuration to reset to a specific block
400
*/
401
function reset(forking?: {
402
jsonRpcUrl: string;
403
blockNumber?: number;
404
}): Promise<void>;
405
406
interface SnapshotRestorer {
407
/** Unique identifier for this snapshot */
408
snapshotId: string;
409
/** Restore blockchain state to this snapshot */
410
restore(): Promise<void>;
411
}
412
```
413
414
**Usage Examples:**
415
416
```typescript
417
import { takeSnapshot, reset } from "@nomicfoundation/hardhat-toolbox/network-helpers";
418
419
describe("Complex Test Suite", function () {
420
let snapshot: SnapshotRestorer;
421
422
beforeEach(async function () {
423
// Take snapshot before each test
424
snapshot = await takeSnapshot();
425
});
426
427
afterEach(async function () {
428
// Restore to snapshot after each test
429
await snapshot.restore();
430
});
431
432
it("should handle complex interactions", async function () {
433
// Test implementation that modifies state
434
// State will be restored automatically
435
});
436
});
437
```
438
439
## Error Types
440
441
```typescript { .api }
442
/** Thrown when loadFixture is called with an anonymous function */
443
class FixtureAnonymousFunctionError extends Error {
444
constructor();
445
}
446
447
/** Thrown when snapshot restoration fails */
448
class FixtureSnapshotError extends Error {
449
constructor(cause: InvalidSnapshotError);
450
}
451
452
/** Thrown when trying to restore an invalid snapshot */
453
class InvalidSnapshotError extends Error {
454
constructor(snapshotId: string);
455
}
456
```