0
# Time Manipulation
1
2
Blockchain time and block manipulation utilities for testing time-dependent contract behavior in development networks. Essential for testing time locks, vesting schedules, and other temporal smart contract logic.
3
4
## Capabilities
5
6
### Block Advancement
7
8
Mine new blocks to advance the blockchain state.
9
10
```javascript { .api }
11
/**
12
* Mine one block on the blockchain
13
* @returns {Promise<void>}
14
*/
15
function time.advanceBlock();
16
17
/**
18
* Advance blockchain to a specific block number
19
* @param {BN|number|string} target - Target block number
20
* @returns {Promise<void>}
21
*/
22
async function time.advanceBlockTo(target);
23
```
24
25
**Usage Examples:**
26
27
```javascript
28
const { time, BN } = require('@openzeppelin/test-helpers');
29
30
// Mine a single block
31
await time.advanceBlock();
32
33
// Advance to specific block (careful with large jumps!)
34
const targetBlock = await time.latestBlock().add(new BN('10'));
35
await time.advanceBlockTo(targetBlock);
36
```
37
38
### Time Queries
39
40
Get current blockchain time and block information.
41
42
```javascript { .api }
43
/**
44
* Get the timestamp of the latest block in seconds
45
* @returns {Promise<BN>} - Block timestamp as BigNumber
46
*/
47
async function time.latest();
48
49
/**
50
* Get the latest block number
51
* @returns {Promise<BN>} - Block number as BigNumber
52
*/
53
async function time.latestBlock();
54
```
55
56
**Usage Examples:**
57
58
```javascript
59
// Get current block timestamp
60
const now = await time.latest();
61
console.log('Current time:', now.toString());
62
63
// Get current block number
64
const blockNumber = await time.latestBlock();
65
console.log('Current block:', blockNumber.toString());
66
67
// Compare timestamps
68
const deadline = now.add(time.duration.days(7));
69
expect(deadline).to.be.bignumber.greaterThan(now);
70
```
71
72
### Time Advancement
73
74
Manipulate blockchain time for testing time-dependent functionality.
75
76
```javascript { .api }
77
/**
78
* Increase blockchain time by a specific duration
79
* @param {BN|number|string} duration - Duration in seconds to increase
80
* @returns {Promise<void>}
81
*/
82
async function time.increase(duration);
83
84
/**
85
* Increase blockchain time to a specific target timestamp
86
* @param {BN|number|string} target - Target timestamp in seconds
87
* @returns {Promise<void>}
88
*/
89
async function time.increaseTo(target);
90
```
91
92
**Usage Examples:**
93
94
```javascript
95
const { time } = require('@openzeppelin/test-helpers');
96
97
// Increase time by 1 hour
98
await time.increase(time.duration.hours(1));
99
100
// Jump to specific future time
101
const futureTime = (await time.latest()).add(time.duration.days(30));
102
await time.increaseTo(futureTime);
103
104
// Test time-locked function
105
it('should allow withdrawal after lock period', async function () {
106
// Lock funds for 1 week
107
await this.contract.lockFunds({ from: user });
108
109
// Try to withdraw immediately (should fail)
110
await expectRevert(
111
this.contract.withdraw({ from: user }),
112
'Funds are still locked'
113
);
114
115
// Advance time by 1 week
116
await time.increase(time.duration.weeks(1));
117
118
// Now withdrawal should succeed
119
await this.contract.withdraw({ from: user });
120
});
121
```
122
123
### Duration Utilities
124
125
Convenient time duration conversion utilities.
126
127
```javascript { .api }
128
const time.duration = {
129
/**
130
* Convert seconds to BigNumber
131
* @param {number|string} val - Value in seconds
132
* @returns {BN} - Duration as BigNumber
133
*/
134
seconds: (val) => BN,
135
136
/**
137
* Convert minutes to seconds as BigNumber
138
* @param {number|string} val - Value in minutes
139
* @returns {BN} - Duration in seconds as BigNumber
140
*/
141
minutes: (val) => BN,
142
143
/**
144
* Convert hours to seconds as BigNumber
145
* @param {number|string} val - Value in hours
146
* @returns {BN} - Duration in seconds as BigNumber
147
*/
148
hours: (val) => BN,
149
150
/**
151
* Convert days to seconds as BigNumber
152
* @param {number|string} val - Value in days
153
* @returns {BN} - Duration in seconds as BigNumber
154
*/
155
days: (val) => BN,
156
157
/**
158
* Convert weeks to seconds as BigNumber
159
* @param {number|string} val - Value in weeks
160
* @returns {BN} - Duration in seconds as BigNumber
161
*/
162
weeks: (val) => BN,
163
164
/**
165
* Convert years to seconds as BigNumber (365 days)
166
* @param {number|string} val - Value in years
167
* @returns {BN} - Duration in seconds as BigNumber
168
*/
169
years: (val) => BN,
170
};
171
```
172
173
**Usage Examples:**
174
175
```javascript
176
// Duration calculations
177
const oneHour = time.duration.hours(1);
178
const oneDay = time.duration.days(1);
179
const oneWeek = time.duration.weeks(1);
180
const oneYear = time.duration.years(1);
181
182
console.log('1 hour =', oneHour.toString(), 'seconds');
183
console.log('1 day =', oneDay.toString(), 'seconds');
184
console.log('1 week =', oneWeek.toString(), 'seconds');
185
console.log('1 year =', oneYear.toString(), 'seconds');
186
187
// Combining durations
188
const lockPeriod = time.duration.days(30).add(time.duration.hours(12));
189
await time.increase(lockPeriod);
190
```
191
192
## Comprehensive Testing Example
193
194
```javascript
195
const { time, expectRevert, BN } = require('@openzeppelin/test-helpers');
196
197
contract('TimeLock', function ([owner, beneficiary]) {
198
beforeEach(async function () {
199
this.lockDuration = time.duration.days(30);
200
this.releaseTime = (await time.latest()).add(this.lockDuration);
201
202
this.timeLock = await TimeLock.new(
203
beneficiary,
204
this.releaseTime,
205
{ from: owner }
206
);
207
});
208
209
it('should not allow release before time', async function () {
210
await expectRevert(
211
this.timeLock.release(),
212
'TimeLock: current time is before release time'
213
);
214
});
215
216
it('should allow release after time', async function () {
217
// Fast forward to release time
218
await time.increaseTo(this.releaseTime);
219
220
// Should now be able to release
221
await this.timeLock.release();
222
});
223
224
it('should handle gradual vesting', async function () {
225
const vestingStart = await time.latest();
226
const vestingDuration = time.duration.days(100);
227
228
// Check vesting at different points
229
await time.increaseTo(vestingStart.add(time.duration.days(25)));
230
let vestedAmount = await this.vestingContract.vestedAmount(beneficiary);
231
expect(vestedAmount).to.be.bignumber.equal(new BN('25')); // 25% vested
232
233
await time.increaseTo(vestingStart.add(time.duration.days(50)));
234
vestedAmount = await this.vestingContract.vestedAmount(beneficiary);
235
expect(vestedAmount).to.be.bignumber.equal(new BN('50')); // 50% vested
236
237
await time.increaseTo(vestingStart.add(vestingDuration));
238
vestedAmount = await this.vestingContract.vestedAmount(beneficiary);
239
expect(vestedAmount).to.be.bignumber.equal(new BN('100')); // 100% vested
240
});
241
});
242
```
243
244
## Important Notes
245
246
### Performance Warning
247
248
The `advanceBlockTo` function will show a warning when advancing many blocks (5+ seconds), as this can slow down tests significantly.
249
250
### Precision Limitations
251
252
Time manipulation is subject to blockchain precision limitations. Design tests to tolerate small time fluctuations when using `increaseTo`.
253
254
### Provider Compatibility
255
256
Time manipulation requires a development blockchain that supports:
257
- `evm_increaseTime` RPC method
258
- `evm_mine` RPC method
259
260
Compatible with:
261
- Ganache
262
- Hardhat Network
263
- Truffle Develop
264
265
### Block vs Time
266
267
Remember that advancing time also mines a block. Some contracts may depend on block numbers rather than timestamps.
268
269
```javascript
270
// Advance time without mining extra blocks
271
await time.increase(time.duration.hours(1));
272
273
// This will mine one additional block after time increase
274
// Current block number = previous + 1
275
```