0
# Event Handling
1
2
Event subscription, filtering, and log processing with typed event data based on contract ABI definitions.
3
4
## Capabilities
5
6
### Event Subscription
7
8
Subscribe to contract events using the dynamically generated `events` property.
9
10
```typescript { .api }
11
class Contract<Abi extends ContractAbi> {
12
/** Dynamically generated events based on contract ABI */
13
readonly events: ContractEventsInterface<Abi>;
14
15
/**
16
* Gets past events for this contract from blockchain history
17
* @param eventName - The event name or 'allEvents' to get all events
18
* @param filter - Filter options with fromBlock, toBlock, and indexed parameter filters
19
* @returns Array of past event objects matching the criteria
20
*/
21
getPastEvents(eventName?: keyof ContractEvents<Abi> | 'allEvents'): Promise<EventLog[]>;
22
getPastEvents(filter: Omit<Filter, 'address'>): Promise<EventLog[]>;
23
getPastEvents(
24
eventName: keyof ContractEvents<Abi> | 'allEvents',
25
filter: Omit<Filter, 'address'>
26
): Promise<EventLog[]>;
27
}
28
29
type ContractEventsInterface<Abi extends ContractAbi> = {
30
[Name in keyof ContractEvents<Abi> | 'allEvents']: ContractBoundEvent;
31
} & {
32
/** Allow access by event signature */
33
[key: string]: ContractBoundEvent;
34
};
35
36
/**
37
* Event subscription function
38
* @param options - Event filtering and subscription options
39
* @returns ContractLogsSubscription for managing the subscription
40
*/
41
type ContractBoundEvent = (options?: ContractEventOptions) => ContractLogsSubscription;
42
```
43
44
### Event Options
45
46
Options for filtering and configuring event subscriptions.
47
48
```typescript { .api }
49
interface ContractEventOptions {
50
/**
51
* Filter events by indexed parameters
52
* Example: { filter: { myNumber: [12, 13] } } means all events where myNumber is 12 or 13
53
*/
54
filter?: Record<string, unknown>;
55
56
/**
57
* The block number from which to get events on
58
* Can use 'earliest', 'latest', 'pending', 'safe', 'finalized' or specific block number
59
*/
60
fromBlock?: BlockNumberOrTag;
61
62
/**
63
* Manually set the topics for the event filter
64
* If given, the filter property and event signature (topic[0]) will not be set automatically
65
*/
66
topics?: string[];
67
}
68
```
69
70
### ContractLogsSubscription
71
72
Subscription class for managing event subscriptions with Web3 subscription interface.
73
74
```typescript { .api }
75
/**
76
* ContractLogsSubscription for contract event logs
77
*
78
* Supported events:
79
* - connected: Emitted when subscription is connected
80
* - data: Fires on each incoming event with event object
81
* - changed: Fires on each event removed from blockchain (has 'removed: true')
82
* - error: Fires on each error
83
*/
84
class ContractLogsSubscription extends Web3Subscription<
85
EventLog,
86
EthExecutionAPI
87
> {
88
constructor(
89
args: {
90
address?: Address;
91
topics?: string[];
92
abi?: ContractAbiWithSignature;
93
jsonInterface?: ContractAbiWithSignature;
94
},
95
options: {
96
subscriptionManager: Web3SubscriptionManager;
97
returnFormat?: DataFormat;
98
}
99
);
100
}
101
102
// Deprecated alias (use ContractLogsSubscription instead)
103
const LogsSubscription = ContractLogsSubscription;
104
```
105
106
### Event Log Structure
107
108
Structure of event logs returned by subscriptions and past event queries.
109
110
```typescript { .api }
111
interface EventLog {
112
/** Event name */
113
event?: string;
114
/** Event signature hash */
115
signature?: HexString;
116
/** Contract address that emitted the event */
117
address: string;
118
/** Indexed and non-indexed event parameters */
119
returnValues: Record<string, unknown>;
120
/** Array of log topics */
121
topics: string[];
122
/** Raw log data */
123
data: string;
124
/** Block number where event was emitted */
125
blockNumber: number;
126
/** Block hash where event was emitted */
127
blockHash: string;
128
/** Transaction hash that triggered the event */
129
transactionHash: string;
130
/** Transaction index in the block */
131
transactionIndex: number;
132
/** Log index in the block */
133
logIndex: number;
134
/** True if event was removed from blockchain */
135
removed?: boolean;
136
}
137
```
138
139
## Usage Examples
140
141
### Basic Event Subscription
142
143
```typescript
144
import { Contract } from "web3-eth-contract";
145
146
const abi = [
147
{
148
anonymous: false,
149
inputs: [
150
{ indexed: true, name: "from", type: "address" },
151
{ indexed: true, name: "to", type: "address" },
152
{ indexed: false, name: "value", type: "uint256" }
153
],
154
name: "Transfer",
155
type: "event"
156
},
157
{
158
anonymous: false,
159
inputs: [
160
{ indexed: false, name: "newValue", type: "uint256" }
161
],
162
name: "ValueChanged",
163
type: "event"
164
}
165
] as const;
166
167
const contract = new Contract(abi, contractAddress);
168
169
// Subscribe to specific event
170
const subscription = await contract.events.Transfer();
171
172
subscription.on('connected', (subscriptionId) => {
173
console.log('Subscription connected:', subscriptionId);
174
});
175
176
subscription.on('data', (event) => {
177
console.log('Transfer event:', {
178
from: event.returnValues.from,
179
to: event.returnValues.to,
180
value: event.returnValues.value,
181
blockNumber: event.blockNumber,
182
transactionHash: event.transactionHash
183
});
184
});
185
186
subscription.on('changed', (event) => {
187
console.log('Event removed (chain reorganization):', event);
188
});
189
190
subscription.on('error', (error) => {
191
console.error('Subscription error:', error);
192
});
193
```
194
195
### Event Filtering
196
197
```typescript
198
// Filter events by indexed parameters
199
const filteredSubscription = await contract.events.Transfer({
200
filter: {
201
from: "0x1234567890123456789012345678901234567890",
202
to: ["0xabcd...", "0xefgh..."] // Multiple values act as OR
203
},
204
fromBlock: 'latest'
205
});
206
207
filteredSubscription.on('data', (event) => {
208
console.log('Filtered transfer:', event.returnValues);
209
});
210
211
// Filter with specific block range
212
const historicalSubscription = await contract.events.ValueChanged({
213
fromBlock: 1000000,
214
// toBlock: 2000000 // Note: subscriptions don't support toBlock
215
});
216
```
217
218
### All Events Subscription
219
220
```typescript
221
// Subscribe to all contract events
222
const allEventsSubscription = await contract.events.allEvents({
223
fromBlock: 'latest'
224
});
225
226
allEventsSubscription.on('data', (event) => {
227
console.log('Event received:', {
228
eventName: event.event,
229
data: event.returnValues,
230
block: event.blockNumber
231
});
232
233
// Handle different event types
234
switch (event.event) {
235
case 'Transfer':
236
console.log('Transfer:', event.returnValues.from, '->', event.returnValues.to);
237
break;
238
case 'ValueChanged':
239
console.log('Value changed to:', event.returnValues.newValue);
240
break;
241
default:
242
console.log('Unknown event:', event.event);
243
}
244
});
245
```
246
247
### Manual Topic Filtering
248
249
```typescript
250
// Advanced filtering with manual topics
251
const manualSubscription = await contract.events.Transfer({
252
topics: [
253
null, // Event signature (automatically filled)
254
"0x1234567890123456789012345678901234567890", // from address
255
null // to address (any)
256
]
257
});
258
```
259
260
### Subscription Management
261
262
```typescript
263
// Store subscription reference
264
let transferSubscription: ContractLogsSubscription;
265
266
async function startEventListening() {
267
transferSubscription = await contract.events.Transfer();
268
269
transferSubscription.on('data', handleTransferEvent);
270
transferSubscription.on('error', handleError);
271
}
272
273
async function stopEventListening() {
274
if (transferSubscription) {
275
await transferSubscription.unsubscribe();
276
console.log('Unsubscribed from Transfer events');
277
}
278
}
279
280
function handleTransferEvent(event: EventLog) {
281
console.log('Transfer event received:', event);
282
}
283
284
function handleError(error: Error) {
285
console.error('Event subscription error:', error);
286
}
287
288
// Clean up on application exit
289
process.on('SIGINT', async () => {
290
await stopEventListening();
291
process.exit();
292
});
293
```
294
295
### Getting Past Events
296
297
```typescript
298
// Get historical events (not part of subscription)
299
// Note: This uses contract.getPastEvents() method
300
const pastEvents = await contract.getPastEvents('Transfer', {
301
filter: {
302
from: "0x1234567890123456789012345678901234567890"
303
},
304
fromBlock: 1000000,
305
toBlock: 2000000
306
});
307
308
console.log(`Found ${pastEvents.length} past Transfer events`);
309
pastEvents.forEach((event, index) => {
310
console.log(`Event ${index + 1}:`, {
311
from: event.returnValues.from,
312
to: event.returnValues.to,
313
value: event.returnValues.value,
314
block: event.blockNumber
315
});
316
});
317
```
318
319
### Error Handling
320
321
```typescript
322
async function subscribeWithErrorHandling() {
323
try {
324
const subscription = await contract.events.Transfer({
325
fromBlock: 'latest'
326
});
327
328
subscription.on('data', (event) => {
329
try {
330
processEvent(event);
331
} catch (error) {
332
console.error('Error processing event:', error);
333
}
334
});
335
336
subscription.on('error', (error) => {
337
console.error('Subscription error:', error);
338
339
// Attempt to resubscribe after delay
340
setTimeout(async () => {
341
try {
342
await subscribeWithErrorHandling();
343
} catch (reconnectError) {
344
console.error('Failed to reconnect:', reconnectError);
345
}
346
}, 5000);
347
});
348
349
} catch (error) {
350
console.error('Failed to create subscription:', error);
351
}
352
}
353
354
function processEvent(event: EventLog) {
355
// Your event processing logic
356
console.log('Processing event:', event.event);
357
}
358
```
359
360
### Multiple Event Types
361
362
```typescript
363
// Subscribe to multiple specific events
364
const events = ['Transfer', 'Approval', 'ValueChanged'] as const;
365
366
const subscriptions = await Promise.all(
367
events.map(eventName => contract.events[eventName]({
368
fromBlock: 'latest'
369
}))
370
);
371
372
subscriptions.forEach((subscription, index) => {
373
subscription.on('data', (event) => {
374
console.log(`${events[index]} event:`, event.returnValues);
375
});
376
});
377
378
// Cleanup all subscriptions
379
async function cleanup() {
380
await Promise.all(
381
subscriptions.map(sub => sub.unsubscribe())
382
);
383
}
384
```
385
386
## Constants
387
388
```typescript { .api }
389
// Special constants for event handling (re-exported from web3-eth)
390
const ALL_EVENTS: string;
391
const ALL_EVENTS_ABI: AbiEventFragment;
392
```