0
# Provider Abstractions
1
2
Abstract base classes for implementing EIP-1193 compatible providers and socket-based connections with automatic reconnection support. These classes provide the foundation for building Web3 providers.
3
4
## Capabilities
5
6
### EIP-1193 Provider
7
8
Abstract implementation of the EIP-1193 provider standard.
9
10
```typescript { .api }
11
/**
12
* Abstract EIP-1193 provider implementation
13
* Extends Web3BaseProvider with EIP-1193 specific functionality
14
*/
15
abstract class Eip1193Provider<API extends Web3APISpec = EthExecutionAPI> extends Web3BaseProvider<API> {
16
/**
17
* Called when provider connects
18
* Should be implemented by concrete providers
19
*/
20
protected _onConnect(): void;
21
22
/**
23
* Called when provider disconnects
24
* Should be implemented by concrete providers
25
* @param code - Disconnection code
26
* @param data - Optional disconnection data
27
*/
28
protected _onDisconnect(code: number, data?: unknown): void;
29
}
30
```
31
32
### Socket Provider
33
34
Abstract socket-based provider with reconnection capabilities.
35
36
```typescript { .api }
37
/**
38
* Abstract socket-based provider for WebSocket, IPC, etc.
39
* Provides reconnection logic and socket management
40
*/
41
abstract class SocketProvider<
42
MessageEvent,
43
CloseEvent,
44
ErrorEvent,
45
API extends Web3APISpec = EthExecutionAPI
46
> extends Eip1193Provider<API> {
47
/**
48
* Socket connection accessor
49
* @returns Current socket connection
50
*/
51
get SocketConnection(): unknown;
52
53
/**
54
* Creates new socket provider
55
* @param socketPath - Path or URL for socket connection
56
* @param socketOptions - Socket-specific options
57
* @param reconnectOptions - Reconnection configuration
58
*/
59
constructor(
60
socketPath: string,
61
socketOptions?: unknown,
62
reconnectOptions?: Partial<ReconnectOptions>
63
);
64
65
/**
66
* Establishes socket connection
67
*/
68
connect(): void;
69
70
/**
71
* Closes socket connection
72
* @param code - Close code
73
* @param data - Close reason
74
*/
75
disconnect(code?: number, data?: string): void;
76
77
/**
78
* Safely disconnects with timeout
79
* @param code - Close code
80
* @param data - Close reason
81
* @param forceDisconnect - Force disconnect after timeout
82
* @param ms - Timeout in milliseconds
83
* @returns Promise that resolves when disconnected
84
*/
85
safeDisconnect(code?: number, data?: string, forceDisconnect?: boolean, ms?: number): Promise<void>;
86
87
/**
88
* Resets provider state and connection
89
*/
90
reset(): void;
91
92
/**
93
* Gets pending request queue size
94
* @returns Number of pending requests
95
*/
96
getPendingRequestQueueSize(): number;
97
98
/**
99
* Gets sent requests queue size
100
* @returns Number of sent requests awaiting response
101
*/
102
getSentRequestsQueueSize(): number;
103
104
/**
105
* Checks if provider supports subscriptions
106
* @returns true if subscriptions are supported
107
*/
108
supportsSubscriptions(): boolean;
109
110
/**
111
* Clears request queues
112
* @param event - Optional connection event context
113
*/
114
clearQueues(event?: ConnectionEvent): void;
115
116
/**
117
* Sends JSON-RPC request
118
* @param request - Web3 API payload
119
* @returns Promise resolving to JSON-RPC response
120
*/
121
request<Method, ResultType>(
122
request: Web3APIPayload<API, Method>
123
): Promise<JsonRpcResponseWithResult<ResultType>>;
124
125
// Event listener methods inherited from EventEmitter
126
on(event: string, listener: Function): this;
127
once(event: string, listener: Function): this;
128
removeListener(event: string, listener: Function): this;
129
removeAllListeners(event?: string): this;
130
}
131
```
132
133
### Reconnection Options
134
135
```typescript { .api }
136
/**
137
* Configuration for automatic reconnection
138
*/
139
type ReconnectOptions = {
140
/**
141
* Whether to automatically reconnect on connection loss
142
*/
143
autoReconnect: boolean;
144
145
/**
146
* Delay between reconnection attempts in milliseconds
147
*/
148
delay: number;
149
150
/**
151
* Maximum number of reconnection attempts
152
*/
153
maxAttempts: number;
154
};
155
```
156
157
## Usage Examples
158
159
### Custom WebSocket Provider
160
161
```typescript
162
import { SocketProvider, ReconnectOptions } from "web3-utils";
163
164
class CustomWebSocketProvider extends SocketProvider<MessageEvent, CloseEvent, ErrorEvent> {
165
private ws: WebSocket | null = null;
166
167
constructor(url: string, options?: WebSocketOptions, reconnectOptions?: Partial<ReconnectOptions>) {
168
super(url, options, reconnectOptions);
169
}
170
171
// Implement required abstract methods
172
get SocketConnection() {
173
return this.ws;
174
}
175
176
connect(): void {
177
if (this.ws?.readyState === WebSocket.OPEN) {
178
return;
179
}
180
181
this.ws = new WebSocket(this.socketPath);
182
183
this.ws.onopen = (event) => {
184
this._onConnect();
185
this.emit('connect');
186
};
187
188
this.ws.onmessage = (event) => {
189
try {
190
const data = JSON.parse(event.data);
191
this.emit('message', data);
192
} catch (error) {
193
this.emit('error', error);
194
}
195
};
196
197
this.ws.onclose = (event) => {
198
this._onDisconnect(event.code, event.reason);
199
this.emit('disconnect', event.code, event.reason);
200
};
201
202
this.ws.onerror = (event) => {
203
this.emit('error', new Error('WebSocket error'));
204
};
205
}
206
207
disconnect(code?: number, data?: string): void {
208
if (this.ws) {
209
this.ws.close(code, data);
210
this.ws = null;
211
}
212
}
213
214
// Implement request sending
215
protected sendRequest(request: any): void {
216
if (this.ws?.readyState === WebSocket.OPEN) {
217
this.ws.send(JSON.stringify(request));
218
} else {
219
throw new Error('WebSocket not connected');
220
}
221
}
222
}
223
224
// Usage
225
const provider = new CustomWebSocketProvider('ws://localhost:8546', {}, {
226
autoReconnect: true,
227
delay: 5000,
228
maxAttempts: 5
229
});
230
231
provider.on('connect', () => {
232
console.log('Connected to WebSocket');
233
});
234
235
provider.on('disconnect', (code, reason) => {
236
console.log(`Disconnected: ${code} - ${reason}`);
237
});
238
239
provider.on('error', (error) => {
240
console.error('Provider error:', error);
241
});
242
243
provider.connect();
244
```
245
246
### Custom HTTP Provider
247
248
```typescript
249
import { Eip1193Provider } from "web3-utils";
250
251
class CustomHttpProvider extends Eip1193Provider {
252
private url: string;
253
private headers: Record<string, string>;
254
255
constructor(url: string, options?: { headers?: Record<string, string> }) {
256
super();
257
this.url = url;
258
this.headers = options?.headers || {};
259
}
260
261
protected _onConnect(): void {
262
// HTTP providers are always "connected"
263
this.emit('connect');
264
}
265
266
protected _onDisconnect(code: number, data?: unknown): void {
267
// HTTP providers don't really disconnect
268
this.emit('disconnect', code, data);
269
}
270
271
async request<Method, ResultType>(
272
request: Web3APIPayload<any, Method>
273
): Promise<JsonRpcResponseWithResult<ResultType>> {
274
try {
275
const response = await fetch(this.url, {
276
method: 'POST',
277
headers: {
278
'Content-Type': 'application/json',
279
...this.headers
280
},
281
body: JSON.stringify(request)
282
});
283
284
if (!response.ok) {
285
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
286
}
287
288
const jsonResponse = await response.json();
289
290
if (jsonResponse.error) {
291
throw new Error(`RPC Error ${jsonResponse.error.code}: ${jsonResponse.error.message}`);
292
}
293
294
return jsonResponse;
295
} catch (error) {
296
this.emit('error', error);
297
throw error;
298
}
299
}
300
301
supportsSubscriptions(): boolean {
302
return false; // HTTP doesn't support subscriptions
303
}
304
}
305
306
// Usage
307
const httpProvider = new CustomHttpProvider('https://mainnet.infura.io/v3/YOUR_PROJECT_ID', {
308
headers: {
309
'Authorization': 'Bearer your-token'
310
}
311
});
312
313
// Make requests
314
const result = await httpProvider.request({
315
method: 'eth_getBalance',
316
params: ['0x742E4C5b469F50A4a8b399D4915C1fc93d15651B', 'latest']
317
});
318
```
319
320
### Provider with Queue Management
321
322
```typescript
323
import { SocketProvider } from "web3-utils";
324
325
class ManagedSocketProvider extends SocketProvider<MessageEvent, CloseEvent, ErrorEvent> {
326
constructor(socketPath: string) {
327
super(socketPath, {}, {
328
autoReconnect: true,
329
delay: 2000,
330
maxAttempts: 10
331
});
332
333
// Monitor queue sizes
334
setInterval(() => {
335
const pending = this.getPendingRequestQueueSize();
336
const sent = this.getSentRequestsQueueSize();
337
338
if (pending > 100 || sent > 50) {
339
console.warn(`High queue sizes: pending=${pending}, sent=${sent}`);
340
}
341
}, 10000);
342
}
343
344
// Override to add queue management
345
async request<Method, ResultType>(
346
request: Web3APIPayload<any, Method>
347
): Promise<JsonRpcResponseWithResult<ResultType>> {
348
// Check queue size before adding request
349
if (this.getPendingRequestQueueSize() > 1000) {
350
throw new Error('Request queue full');
351
}
352
353
return super.request(request);
354
}
355
356
// Custom method to clear queues when needed
357
emergencyClearQueues(): void {
358
console.log('Emergency queue clear initiated');
359
this.clearQueues();
360
}
361
362
// Graceful shutdown
363
async shutdown(): Promise<void> {
364
console.log('Shutting down provider...');
365
366
// Wait for queues to empty or timeout
367
const maxWait = 30000; // 30 seconds
368
const startTime = Date.now();
369
370
while (
371
(this.getPendingRequestQueueSize() > 0 || this.getSentRequestsQueueSize() > 0) &&
372
(Date.now() - startTime) < maxWait
373
) {
374
await new Promise(resolve => setTimeout(resolve, 100));
375
}
376
377
await this.safeDisconnect(1000, 'Normal shutdown', true, 5000);
378
console.log('Provider shutdown complete');
379
}
380
}
381
```
382
383
## Common Usage Patterns
384
385
### Provider Factory
386
387
```typescript
388
import { SocketProvider, Eip1193Provider } from "web3-utils";
389
390
type ProviderConfig = {
391
type: 'http' | 'websocket' | 'ipc';
392
url: string;
393
options?: any;
394
reconnectOptions?: Partial<ReconnectOptions>;
395
};
396
397
function createProvider(config: ProviderConfig): Eip1193Provider {
398
switch (config.type) {
399
case 'http':
400
return new CustomHttpProvider(config.url, config.options);
401
case 'websocket':
402
return new CustomWebSocketProvider(config.url, config.options, config.reconnectOptions);
403
case 'ipc':
404
return new CustomIPCProvider(config.url, config.options, config.reconnectOptions);
405
default:
406
throw new Error(`Unsupported provider type: ${config.type}`);
407
}
408
}
409
410
// Usage
411
const provider = createProvider({
412
type: 'websocket',
413
url: 'ws://localhost:8546',
414
reconnectOptions: {
415
autoReconnect: true,
416
delay: 3000,
417
maxAttempts: 5
418
}
419
});
420
```
421
422
## Types
423
424
```typescript { .api }
425
// Provider-related types
426
type ConnectionEvent = 'connect' | 'disconnect' | 'error';
427
428
interface Web3APISpec {
429
[method: string]: {
430
Parameters: any[];
431
ReturnType: any;
432
};
433
}
434
435
interface Web3APIPayload<API extends Web3APISpec, Method extends keyof API> {
436
method: Method;
437
params: API[Method]['Parameters'];
438
}
439
440
interface Web3BaseProvider<API extends Web3APISpec> {
441
request<Method extends keyof API>(
442
request: Web3APIPayload<API, Method>
443
): Promise<API[Method]['ReturnType']>;
444
}
445
```