0
# BigNumber Support
1
2
Enhanced comparison operators that support ethers BigInt and other BigNumber types alongside regular JavaScript numbers, enabling seamless testing of blockchain values.
3
4
## Capabilities
5
6
### Enhanced Numeric Comparisons
7
8
All standard Chai comparison operators are automatically enhanced to support BigInt, ethers BigNumber, and other numeric types commonly used in Ethereum development.
9
10
```typescript { .api }
11
// All these methods are enhanced to support BigNumber comparisons:
12
// equal, eq, equals - equality comparison
13
// above, gt, greaterThan - greater than comparison
14
// below, lt, lessThan - less than comparison
15
// least, gte, greaterThanOrEqual - greater than or equal comparison
16
// most, lte, lessThanOrEqual - less than or equal comparison
17
// within - range comparison
18
// closeTo, approximately - approximate equality with delta
19
// length, lengthOf - length comparison with BigNumber values
20
```
21
22
### Within Range Testing
23
24
Tests if a value falls within a specified numeric range, supporting BigNumber types.
25
26
```typescript { .api }
27
/**
28
* Tests if value is within specified range (inclusive)
29
* @param start - Lower bound of range
30
* @param finish - Upper bound of range
31
* @param message - Optional custom error message
32
* @returns Assertion for chaining
33
*/
34
within(start: any, finish: any, message?: string): Assertion;
35
```
36
37
**Usage Examples:**
38
39
```typescript
40
import { expect } from "chai";
41
import { ethers } from "hardhat";
42
43
// Test BigInt values within range
44
const balance = await ethers.provider.getBalance(address);
45
expect(balance).to.be.within(
46
ethers.parseEther("1"),
47
ethers.parseEther("10")
48
);
49
50
// Test token amounts
51
const tokenBalance = await token.balanceOf(user);
52
expect(tokenBalance).to.be.within(1000n, 5000n);
53
54
// Mixed type comparisons work seamlessly
55
expect(ethers.parseEther("2.5")).to.be.within(
56
ethers.parseEther("2"),
57
ethers.parseEther("3")
58
);
59
60
// Regular numbers still work
61
expect(42).to.be.within(40, 50);
62
```
63
64
## Enhanced Operators
65
66
### Equality Comparisons
67
68
```typescript
69
// All these methods support BigNumber comparisons
70
expect(ethers.parseEther("1")).to.equal(ethers.parseEther("1"));
71
expect(1000n).to.eq(1000n);
72
expect(tokenAmount).to.equals(expectedAmount);
73
74
// Cross-type comparisons
75
expect(ethers.parseEther("1")).to.equal(1000000000000000000n);
76
expect(BigInt(42)).to.equal(42);
77
```
78
79
### Relational Comparisons
80
81
```typescript
82
const largeAmount = ethers.parseEther("100");
83
const smallAmount = ethers.parseEther("1");
84
85
// Greater than comparisons
86
expect(largeAmount).to.be.above(smallAmount);
87
expect(largeAmount).to.be.gt(smallAmount);
88
expect(largeAmount).to.be.greaterThan(smallAmount);
89
90
// Less than comparisons
91
expect(smallAmount).to.be.below(largeAmount);
92
expect(smallAmount).to.be.lt(largeAmount);
93
expect(smallAmount).to.be.lessThan(largeAmount);
94
95
// Greater than or equal
96
expect(largeAmount).to.be.at.least(smallAmount);
97
expect(largeAmount).to.be.gte(smallAmount);
98
expect(largeAmount).to.be.greaterThanOrEqual(smallAmount);
99
100
// Less than or equal
101
expect(smallAmount).to.be.at.most(largeAmount);
102
expect(smallAmount).to.be.lte(largeAmount);
103
expect(smallAmount).to.be.lessThanOrEqual(largeAmount);
104
```
105
106
### Approximate Comparisons
107
108
```typescript
109
// Test values that are close but not exactly equal
110
const calculatedValue = ethers.parseEther("1.999");
111
const expectedValue = ethers.parseEther("2");
112
const delta = ethers.parseEther("0.01");
113
114
expect(calculatedValue).to.be.closeTo(expectedValue, delta);
115
expect(calculatedValue).to.be.approximately(expectedValue, delta);
116
117
// Works with regular numbers too
118
expect(1.999).to.be.closeTo(2, 0.01);
119
```
120
121
### Length Comparisons
122
123
```typescript
124
// Length comparisons with BigNumber values
125
const arrayLength = BigInt(items.length);
126
expect(items).to.have.length(arrayLength);
127
expect(items).to.have.lengthOf(arrayLength);
128
129
// Useful for testing array operations
130
expect(results).to.have.length(ethers.toBigInt(expectedCount));
131
```
132
133
## Smart Contract Testing Examples
134
135
### Token Balance Testing
136
137
```typescript
138
describe("Token operations", function() {
139
it("should handle large token amounts", async function() {
140
const totalSupply = ethers.parseUnits("1000000", 18); // 1M tokens
141
const userBalance = await token.balanceOf(user.address);
142
143
// Test balance is within expected range
144
expect(userBalance).to.be.within(
145
ethers.parseUnits("1000", 18),
146
ethers.parseUnits("10000", 18)
147
);
148
149
// Test balance is less than total supply
150
expect(userBalance).to.be.below(totalSupply);
151
152
// Test approximate equality after calculations
153
const calculated = userBalance * 2n;
154
const expected = ethers.parseUnits("2000", 18);
155
const tolerance = ethers.parseUnits("1", 18);
156
157
expect(calculated).to.be.closeTo(expected, tolerance);
158
});
159
});
160
```
161
162
### Gas Cost Analysis
163
164
```typescript
165
describe("Gas optimization", function() {
166
it("should stay within gas limits", async function() {
167
const tx = await contract.expensiveOperation();
168
const receipt = await tx.wait();
169
170
const gasUsed = receipt.gasUsed;
171
const gasLimit = 500000n;
172
const minGas = 100000n;
173
174
// Test gas usage is within acceptable range
175
expect(gasUsed).to.be.within(minGas, gasLimit);
176
expect(gasUsed).to.be.below(gasLimit);
177
});
178
});
179
```
180
181
### ETH Value Testing
182
183
```typescript
184
describe("ETH transactions", function() {
185
it("should handle ETH transfers correctly", async function() {
186
const sendAmount = ethers.parseEther("1.5");
187
const initialBalance = await ethers.provider.getBalance(recipient.address);
188
189
await sender.sendTransaction({
190
to: recipient.address,
191
value: sendAmount
192
});
193
194
const finalBalance = await ethers.provider.getBalance(recipient.address);
195
const expectedBalance = initialBalance + sendAmount;
196
197
// Account for potential gas refunds or small discrepancies
198
const tolerance = ethers.parseEther("0.001");
199
expect(finalBalance).to.be.closeTo(expectedBalance, tolerance);
200
expect(finalBalance).to.be.above(initialBalance);
201
});
202
});
203
```
204
205
## Mixed Type Support
206
207
The enhanced operators seamlessly handle different numeric types:
208
209
```typescript
210
// These all work correctly due to automatic type conversion
211
expect(ethers.parseEther("1")).to.equal(1000000000000000000n);
212
expect(BigInt(42)).to.equal(42);
213
expect(ethers.toBigInt(100)).to.be.above(99);
214
expect(ethers.parseUnits("1", 6)).to.be.within(999999n, 1000001n);
215
216
// Useful for testing conversions
217
const weiValue = ethers.parseEther("2.5");
218
const etherValue = 2.5;
219
expect(weiValue).to.equal(ethers.parseEther(etherValue.toString()));
220
```
221
222
## Error Messages
223
224
Enhanced error messages provide clear information about BigNumber comparisons:
225
226
```typescript
227
// Clear error messages for failed BigNumber comparisons:
228
// "expected 1000000000000000000n to equal 2000000000000000000n"
229
// "expected 500000000000000000n to be above 1000000000000000000n"
230
// "expected 1500000000000000000n to be within 1000000000000000000n..1200000000000000000n"
231
```
232
233
## Important Notes
234
235
### Automatic Enhancement
236
237
All standard Chai numeric comparison methods are automatically enhanced when the hardhat-chai-matchers plugin is imported. No additional imports or setup is required.
238
239
### Type Conversion
240
241
The enhanced operators automatically handle type conversion between:
242
- Regular JavaScript numbers
243
- BigInt values
244
- ethers BigInt values
245
- Other BigNumber-like objects with appropriate conversion methods
246
247
### Performance
248
249
The enhanced comparisons maintain good performance by using efficient type detection and conversion only when necessary.