0
# Argument Matching Utilities
1
2
Helper functions for flexible argument matching in event and error testing scenarios, allowing partial validation of complex arguments.
3
4
## Import
5
6
```typescript
7
import { anyValue, anyUint } from "@nomicfoundation/hardhat-chai-matchers/withArgs";
8
```
9
10
## Capabilities
11
12
### Any Value Matcher
13
14
A predicate function that accepts any value as a positive match, useful when you want to ignore specific arguments in event or error validation.
15
16
```typescript { .api }
17
/**
18
* Predicate that matches any argument value
19
* @returns boolean - always returns true for any input
20
*/
21
function anyValue(): boolean;
22
```
23
24
**Usage Examples:**
25
26
```typescript
27
import { expect } from "chai";
28
import { anyValue } from "@nomicfoundation/hardhat-chai-matchers/withArgs";
29
30
// Test event emission ignoring specific arguments
31
await expect(contract.mint(user, 1000, metadata))
32
.to.emit(contract, "Mint")
33
.withArgs(user.address, 1000, anyValue); // Ignore metadata argument
34
35
// Test custom error with partial argument matching
36
await expect(contract.complexOperation(data))
37
.to.be.revertedWithCustomError(contract, "OperationFailed")
38
.withArgs(anyValue, 404, "Invalid data"); // Ignore first argument
39
40
// Multiple anyValue uses
41
await expect(contract.multiParamEvent())
42
.to.emit(contract, "ComplexEvent")
43
.withArgs(anyValue, anyValue, "important", anyValue); // Only validate 3rd argument
44
45
// Mixed with specific values
46
await expect(token.transfer(recipient, amount))
47
.to.emit(token, "Transfer")
48
.withArgs(anyValue, recipient.address, anyValue); // Only care about recipient
49
```
50
51
### Any Unsigned Integer Matcher
52
53
A predicate function that validates the argument is a valid unsigned integer (positive number or zero), while accepting any specific value within that constraint.
54
55
```typescript { .api }
56
/**
57
* Predicate that matches any unsigned integer value
58
* @param i - The value to validate as unsigned integer
59
* @returns boolean - true if value is valid unsigned integer
60
* @throws AssertionError if value is negative or not a number
61
*/
62
function anyUint(i: any): boolean;
63
```
64
65
**Usage Examples:**
66
67
```typescript
68
import { anyUint } from "@nomicfoundation/hardhat-chai-matchers/withArgs";
69
70
// Test event with any positive amount
71
await expect(contract.deposit({ value: ethers.parseEther("1") }))
72
.to.emit(contract, "Deposit")
73
.withArgs(user.address, anyUint); // Any positive deposit amount
74
75
// Test token transfer with amount validation
76
await expect(token.mint(recipient, 1000))
77
.to.emit(token, "Mint")
78
.withArgs(recipient.address, anyUint); // Validates amount is positive
79
80
// Combined with other matchers
81
await expect(contract.updateBalance(user, newBalance))
82
.to.emit(contract, "BalanceUpdated")
83
.withArgs(user.address, anyUint, anyValue); // Balance positive, timestamp ignored
84
85
// Works with BigInt values
86
const largeAmount = ethers.parseEther("1000000");
87
await expect(contract.largeTransfer(recipient, largeAmount))
88
.to.emit(contract, "Transfer")
89
.withArgs(anyValue, recipient.address, anyUint); // Validates BigInt amount
90
```
91
92
### Type Validation Behavior
93
94
```typescript
95
// anyUint accepts regular numbers (>= 0)
96
anyUint(0); // ✅ true
97
anyUint(42); // ✅ true
98
anyUint(1000); // ✅ true
99
100
// anyUint accepts BigInt values (>= 0n)
101
anyUint(0n); // ✅ true
102
anyUint(42n); // ✅ true
103
anyUint(ethers.parseEther("1")); // ✅ true
104
105
// anyUint rejects negative values
106
anyUint(-1); // ❌ throws AssertionError
107
anyUint(-42n); // ❌ throws AssertionError
108
109
// anyUint rejects non-numeric values
110
anyUint("123"); // ❌ throws AssertionError
111
anyUint(null); // ❌ throws AssertionError
112
anyUint({}); // ❌ throws AssertionError
113
```
114
115
## Advanced Usage Patterns
116
117
### Complex Event Validation
118
119
```typescript
120
// Validate multi-parameter events with mixed requirements
121
await expect(dex.swap(tokenA, tokenB, amountIn))
122
.to.emit(dex, "Swap")
123
.withArgs(
124
user.address, // Specific user
125
tokenA.address, // Specific input token
126
tokenB.address, // Specific output token
127
anyUint, // Any valid input amount
128
anyUint, // Any valid output amount
129
anyValue // Ignore price/slippage data
130
);
131
132
// Validate fee distribution events
133
await expect(protocol.distributeFees())
134
.to.emit(protocol, "FeesDistributed")
135
.withArgs(
136
anyUint, // Treasury fee (any positive amount)
137
anyUint, // Dev fee (any positive amount)
138
anyUint, // Staking rewards (any positive amount)
139
anyValue // Ignore timestamp
140
);
141
```
142
143
### Error Argument Validation
144
145
```typescript
146
// Test custom errors with flexible argument matching
147
await expect(lending.borrow(amount, collateral))
148
.to.be.revertedWithCustomError(lending, "InsufficientCollateral")
149
.withArgs(
150
user.address, // Specific borrower
151
anyUint, // Any requested amount
152
anyUint, // Any collateral value
153
anyValue // Ignore collateral ratio calculation
154
);
155
156
// Validate access control errors
157
await expect(contract.adminFunction())
158
.to.be.revertedWithCustomError(contract, "AccessDenied")
159
.withArgs(user.address, "ADMIN_ROLE", anyValue); // Ignore additional context
160
```
161
162
### Combining Multiple Utilities
163
164
```typescript
165
// Complex validation combining both utilities
166
await expect(marketplace.createListing(nft, price, duration))
167
.to.emit(marketplace, "ListingCreated")
168
.withArgs(
169
anyUint, // Listing ID (any positive ID)
170
user.address, // Specific seller
171
nft.address, // Specific NFT contract
172
anyUint, // Token ID (any valid token)
173
anyUint, // Price (any positive price)
174
anyValue // Ignore expiration timestamp
175
);
176
177
// Batch operation validation
178
await expect(contract.batchProcess(items))
179
.to.emit(contract, "BatchProcessed")
180
.withArgs(
181
anyUint, // Batch ID
182
anyUint, // Items processed count
183
anyUint, // Success count
184
anyValue, // Ignore failure details
185
anyValue // Ignore processing metadata
186
);
187
```
188
189
## Error Messages
190
191
The utilities provide clear error messages when validation fails:
192
193
```typescript
194
// anyUint with negative number:
195
// "anyUint expected its argument to be an unsigned integer, but it was negative, with value -42"
196
197
// anyUint with non-numeric type:
198
// "anyUint expected its argument to be an integer, but its type was 'string'"
199
200
// anyUint with negative BigInt:
201
// "anyUint expected its argument to be an unsigned integer, but it was negative, with value -42n"
202
```
203
204
## Integration with Other Matchers
205
206
### Event Emission
207
208
```typescript
209
// Use with event emission testing
210
await expect(contract.complexFunction())
211
.to.emit(contract, "Event1")
212
.withArgs(specificValue, anyValue, anyUint)
213
.and.to.emit(contract, "Event2")
214
.withArgs(anyValue, anyUint, specificValue);
215
```
216
217
### Custom Error Testing
218
219
```typescript
220
// Use with custom error validation
221
await expect(contract.restrictedFunction())
222
.to.be.revertedWithCustomError(contract, "ValidationError")
223
.withArgs(anyValue, anyUint, "Required field missing");
224
```
225
226
## Best Practices
227
228
### When to Use anyValue
229
230
- Ignore timestamp arguments that change between test runs
231
- Skip complex computed values that are tested elsewhere
232
- Focus tests on specific arguments of interest
233
- Ignore metadata or auxiliary information
234
235
### When to Use anyUint
236
237
- Validate amounts are positive without caring about exact values
238
- Test fee calculations where any positive fee is acceptable
239
- Verify ID generation produces valid positive identifiers
240
- Ensure counters increment correctly
241
242
### Combining with Specific Values
243
244
```typescript
245
// Good: Mix specific requirements with flexible matching
246
await expect(contract.operation())
247
.to.emit(contract, "Operation")
248
.withArgs(
249
user.address, // Specific - who performed operation
250
"CREATE", // Specific - what operation type
251
anyUint, // Flexible - any valid item ID
252
anyValue // Flexible - ignore metadata
253
);
254
255
// Avoid: Using anyValue for everything (not very useful)
256
await expect(contract.operation())
257
.to.emit(contract, "Operation")
258
.withArgs(anyValue, anyValue, anyValue, anyValue); // Too permissive
259
```