wb3-provider 1.0.0-beta.55

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,917 @@
1
+ import { w3cwebsocket } from 'websocket';
2
+ import { XMLHttpRequest as XMLHttpRequest$1 } from 'xhr2-cookies';
3
+ import URL from 'url-parse';
4
+ import isFunction from 'lodash/isFunction';
5
+ import isObject from 'lodash/isObject';
6
+ import EventEmitter from 'eventemitter3';
7
+ import isArray from 'lodash/isArray';
8
+ import http from 'http';
9
+ import https from 'https';
10
+
11
+ const global = function () {
12
+ return this || typeof self === 'object' && self;
13
+ }() || new Function('return this')();
14
+ class ProviderResolver {
15
+ constructor(providersModuleFactory) {
16
+ this.providersModuleFactory = providersModuleFactory;
17
+ }
18
+ resolve(provider, net) {
19
+ if (!provider) {
20
+ return provider;
21
+ }
22
+ if (typeof provider === 'string') {
23
+ if (/^http(s)?:\/\//i.test(provider)) {
24
+ return this.providersModuleFactory.createHttpProvider(provider);
25
+ }
26
+ if (/^ws(s)?:\/\//i.test(provider)) {
27
+ return this.providersModuleFactory.createWebsocketProvider(provider);
28
+ }
29
+ if (provider && isObject(net) && isFunction(net.connect)) {
30
+ return this.providersModuleFactory.createIpcProvider(provider, net);
31
+ }
32
+ }
33
+ if (provider.sendPayload && provider.subscribe) {
34
+ return provider;
35
+ }
36
+ if (typeof global.mist !== 'undefined' && provider.constructor.name === 'EthereumProvider') {
37
+ return this.providersModuleFactory.createMistEthereumProvider(provider);
38
+ }
39
+ if (provider.isEIP1193) {
40
+ return this.providersModuleFactory.createWeb3EthereumProvider(provider);
41
+ }
42
+ if (this.isMetamaskInpageProvider(provider)) {
43
+ return this.providersModuleFactory.createMetamaskProvider(provider);
44
+ }
45
+ return this.providersModuleFactory.createCustomProvider(provider);
46
+ }
47
+ isMetamaskInpageProvider(provider) {
48
+ return provider.constructor.name === 'MetamaskInpageProvider';
49
+ }
50
+ }
51
+
52
+ let messageId = 0;
53
+ class JsonRpcMapper {
54
+ static toPayload(method, params) {
55
+ if (!method) {
56
+ throw new Error(`JSONRPC method should be specified for params: "${JSON.stringify(params)}"!`);
57
+ }
58
+ const id = messageId;
59
+ messageId++;
60
+ return {
61
+ jsonrpc: '2.0',
62
+ id,
63
+ method,
64
+ params: params || []
65
+ };
66
+ }
67
+ }
68
+
69
+ class JsonRpcResponseValidator {
70
+ static validate(response, payload = false) {
71
+ if (isObject(response)) {
72
+ if (response.error) {
73
+ if (response.error instanceof Error) {
74
+ return new Error(`Node error: ${response.error.message}`);
75
+ }
76
+ return new Error(`Node error: ${JSON.stringify(response.error)}`);
77
+ }
78
+ if (payload && response.id !== payload.id) {
79
+ return new Error(`Validation error: Invalid JSON-RPC response ID (request: ${payload.id} / response: ${response.id})`);
80
+ }
81
+ if (response.result === undefined) {
82
+ return new Error('Validation error: Undefined JSON-RPC result');
83
+ }
84
+ return true;
85
+ }
86
+ return new Error('Validation error: Response should be of type Object');
87
+ }
88
+ }
89
+
90
+ class AbstractSocketProvider extends EventEmitter {
91
+ constructor(connection, timeout) {
92
+ super();
93
+ this.connection = connection;
94
+ this.timeout = timeout;
95
+ this.subscriptions = {};
96
+ this.registerEventListeners();
97
+ this.READY = 'ready';
98
+ this.CONNECT = 'connect';
99
+ this.ERROR = 'error';
100
+ this.CLOSE = 'close';
101
+ this.SOCKET_MESSAGE = 'socket_message';
102
+ this.SOCKET_READY = 'socket_ready';
103
+ this.SOCKET_CLOSE = 'socket_close';
104
+ this.SOCKET_ERROR = 'socket_error';
105
+ this.SOCKET_CONNECT = 'socket_connect';
106
+ this.SOCKET_NETWORK_CHANGED = 'socket_networkChanged';
107
+ this.SOCKET_ACCOUNTS_CHANGED = 'socket_accountsChanged';
108
+ }
109
+ supportsSubscriptions() {
110
+ return true;
111
+ }
112
+ registerEventListeners() {}
113
+ removeAllSocketListeners() {
114
+ this.removeAllListeners(this.SOCKET_MESSAGE);
115
+ this.removeAllListeners(this.SOCKET_READY);
116
+ this.removeAllListeners(this.SOCKET_CLOSE);
117
+ this.removeAllListeners(this.SOCKET_ERROR);
118
+ this.removeAllListeners(this.SOCKET_CONNECT);
119
+ }
120
+ disconnect(code, reason) {}
121
+ get connected() {}
122
+ async send(method, parameters) {
123
+ const response = await this.sendPayload(JsonRpcMapper.toPayload(method, parameters));
124
+ const validationResult = JsonRpcResponseValidator.validate(response);
125
+ if (validationResult instanceof Error) {
126
+ throw validationResult;
127
+ }
128
+ return response.result;
129
+ }
130
+ sendBatch(methods, moduleInstance) {
131
+ let payload = [];
132
+ methods.forEach(method => {
133
+ method.beforeExecution(moduleInstance);
134
+ payload.push(JsonRpcMapper.toPayload(method.rpcMethod, method.parameters));
135
+ });
136
+ return this.sendPayload(payload);
137
+ }
138
+ onReady(event) {
139
+ this.emit(this.READY, event);
140
+ this.emit(this.SOCKET_READY, event);
141
+ }
142
+ onError(error) {
143
+ this.emit(this.ERROR, error);
144
+ this.emit(this.SOCKET_ERROR, error);
145
+ this.removeAllSocketListeners();
146
+ this.removeAllListeners();
147
+ }
148
+ onClose(error = null) {
149
+ this.emit(this.CLOSE, error);
150
+ this.emit(this.SOCKET_CLOSE, error);
151
+ this.removeAllSocketListeners();
152
+ this.removeAllListeners();
153
+ }
154
+ async onConnect() {
155
+ const subscriptionKeys = Object.keys(this.subscriptions);
156
+ if (subscriptionKeys.length > 0) {
157
+ let subscriptionId;
158
+ for (let key of subscriptionKeys) {
159
+ subscriptionId = await this.subscribe(this.subscriptions[key].subscribeMethod, this.subscriptions[key].parameters[0], this.subscriptions[key].parameters.slice(1));
160
+ delete this.subscriptions[subscriptionId];
161
+ this.subscriptions[key].id = subscriptionId;
162
+ }
163
+ }
164
+ this.emit(this.SOCKET_CONNECT);
165
+ this.emit(this.CONNECT);
166
+ }
167
+ onMessage(response) {
168
+ let event;
169
+ if (!isObject(response)) {
170
+ response = JSON.parse(response);
171
+ }
172
+ if (isArray(response)) {
173
+ event = response[0].id;
174
+ } else if (typeof response.id === 'undefined') {
175
+ event = this.getSubscriptionEvent(response.params.subscription);
176
+ response = response.params;
177
+ } else {
178
+ event = response.id;
179
+ }
180
+ this.emit(this.SOCKET_MESSAGE, response);
181
+ this.emit(event, response);
182
+ }
183
+ reset() {
184
+ this.removeAllListeners();
185
+ this.registerEventListeners();
186
+ }
187
+ subscribe(subscribeMethod = 'eth_subscribe', subscriptionMethod, parameters) {
188
+ parameters.unshift(subscriptionMethod);
189
+ return this.send(subscribeMethod, parameters).then(subscriptionId => {
190
+ this.subscriptions[subscriptionId] = {
191
+ id: subscriptionId,
192
+ subscribeMethod: subscribeMethod,
193
+ parameters: parameters
194
+ };
195
+ return subscriptionId;
196
+ }).catch(error => {
197
+ throw new Error(`Provider error: ${error}`);
198
+ });
199
+ }
200
+ unsubscribe(subscriptionId, unsubscribeMethod = 'eth_unsubscribe') {
201
+ if (this.hasSubscription(subscriptionId)) {
202
+ return this.send(unsubscribeMethod, [subscriptionId]).then(response => {
203
+ if (response) {
204
+ this.removeAllListeners(this.getSubscriptionEvent(subscriptionId));
205
+ delete this.subscriptions[subscriptionId];
206
+ }
207
+ return response;
208
+ });
209
+ }
210
+ return Promise.reject(new Error(`Provider error: Subscription with ID ${subscriptionId} does not exist.`));
211
+ }
212
+ clearSubscriptions(unsubscribeMethod = 'eth_unsubscribe') {
213
+ let unsubscribePromises = [];
214
+ Object.keys(this.subscriptions).forEach(key => {
215
+ this.removeAllListeners(key);
216
+ unsubscribePromises.push(this.unsubscribe(this.subscriptions[key].id, unsubscribeMethod));
217
+ });
218
+ return Promise.all(unsubscribePromises).then(results => {
219
+ if (results.includes(false)) {
220
+ throw new Error(`Could not unsubscribe all subscriptions: ${JSON.stringify(results)}`);
221
+ }
222
+ return true;
223
+ });
224
+ }
225
+ hasSubscription(subscriptionId) {
226
+ return typeof this.getSubscriptionEvent(subscriptionId) !== 'undefined';
227
+ }
228
+ getSubscriptionEvent(subscriptionId) {
229
+ if (this.subscriptions[subscriptionId]) {
230
+ return subscriptionId;
231
+ }
232
+ let event;
233
+ Object.keys(this.subscriptions).forEach(key => {
234
+ if (this.subscriptions[key].id === subscriptionId) {
235
+ event = key;
236
+ }
237
+ });
238
+ return event;
239
+ }
240
+ }
241
+
242
+ class WebsocketProvider extends AbstractSocketProvider {
243
+ constructor(connection, timeout) {
244
+ super(connection, timeout);
245
+ this.host = this.connection.url;
246
+ }
247
+ onMessage(messageEvent) {
248
+ super.onMessage(messageEvent.data);
249
+ }
250
+ onError(event) {
251
+ if (event.code === 'ECONNREFUSED') {
252
+ this.reconnect();
253
+ return;
254
+ }
255
+ super.onError(event);
256
+ }
257
+ onClose(closeEvent) {
258
+ if (closeEvent.code !== 1000 || closeEvent.wasClean === false) {
259
+ this.reconnect();
260
+ return;
261
+ }
262
+ super.onClose();
263
+ }
264
+ reconnect() {
265
+ setTimeout(() => {
266
+ this.removeAllSocketListeners();
267
+ let connection = [];
268
+ if (this.connection.constructor.name === 'W3CWebsocket') {
269
+ connection = new this.connection.constructor(this.host, this.connection._client.protocol, null, this.connection._client.headers, this.connection._client.requestOptions, this.connection._client.config);
270
+ } else {
271
+ connection = new this.connection.constructor(this.host, this.connection.protocol || undefined);
272
+ }
273
+ this.connection = connection;
274
+ this.registerEventListeners();
275
+ }, 5000);
276
+ }
277
+ disconnect(code = null, reason = null) {
278
+ this.connection.close(code, reason);
279
+ }
280
+ registerEventListeners() {
281
+ this.connection.addEventListener('message', this.onMessage.bind(this));
282
+ this.connection.addEventListener('open', this.onReady.bind(this));
283
+ this.connection.addEventListener('open', this.onConnect.bind(this));
284
+ this.connection.addEventListener('close', this.onClose.bind(this));
285
+ this.connection.addEventListener('error', this.onError.bind(this));
286
+ }
287
+ removeAllListeners(event) {
288
+ switch (event) {
289
+ case this.SOCKET_MESSAGE:
290
+ this.connection.removeEventListener('message', this.onMessage);
291
+ break;
292
+ case this.SOCKET_READY:
293
+ this.connection.removeEventListener('open', this.onReady);
294
+ break;
295
+ case this.SOCKET_CLOSE:
296
+ this.connection.removeEventListener('close', this.onClose);
297
+ break;
298
+ case this.SOCKET_ERROR:
299
+ this.connection.removeEventListener('error', this.onError);
300
+ break;
301
+ case this.SOCKET_CONNECT:
302
+ this.connection.removeEventListener('connect', this.onConnect);
303
+ break;
304
+ }
305
+ super.removeAllListeners(event);
306
+ }
307
+ get connected() {
308
+ return this.connection.readyState === this.connection.OPEN;
309
+ }
310
+ isConnecting() {
311
+ return this.connection.readyState === this.connection.CONNECTING;
312
+ }
313
+ sendPayload(payload) {
314
+ return new Promise((resolve, reject) => {
315
+ this.once('error', reject);
316
+ if (!this.isConnecting()) {
317
+ let timeout, id;
318
+ if (this.connection.readyState !== this.connection.OPEN) {
319
+ return reject(new Error('Connection error: Connection is not open on send()'));
320
+ }
321
+ try {
322
+ this.connection.send(JSON.stringify(payload));
323
+ } catch (error) {
324
+ reject(error);
325
+ }
326
+ if (this.timeout) {
327
+ timeout = setTimeout(() => {
328
+ reject(new Error('Connection error: Timeout exceeded'));
329
+ }, this.timeout);
330
+ }
331
+ if (isArray(payload)) {
332
+ id = payload[0].id;
333
+ } else {
334
+ id = payload.id;
335
+ }
336
+ this.once(id, response => {
337
+ if (timeout) {
338
+ clearTimeout(timeout);
339
+ }
340
+ return resolve(response);
341
+ });
342
+ return;
343
+ }
344
+ this.once('connect', () => {
345
+ this.sendPayload(payload).then(resolve).catch(reject);
346
+ });
347
+ });
348
+ }
349
+ }
350
+
351
+ class IpcProvider extends AbstractSocketProvider {
352
+ constructor(connection, path) {
353
+ super(connection, null);
354
+ this.host = path;
355
+ this.lastChunk = '';
356
+ }
357
+ disconnect() {
358
+ this.connection.destroy();
359
+ }
360
+ get connected() {
361
+ return !this.connection.pending;
362
+ }
363
+ reconnect() {
364
+ this.connection.connect({
365
+ path: this.path
366
+ });
367
+ }
368
+ onMessage(message) {
369
+ let result = null;
370
+ let returnValues = [];
371
+ let dechunkedData = message.toString().replace(/\}[\n\r]?\{/g, '}|--|{')
372
+ .replace(/\}\][\n\r]?\[\{/g, '}]|--|[{')
373
+ .replace(/\}[\n\r]?\[\{/g, '}|--|[{')
374
+ .replace(/\}\][\n\r]?\{/g, '}]|--|{')
375
+ .split('|--|');
376
+ dechunkedData.forEach(data => {
377
+ result = null;
378
+ if (this.lastChunk) {
379
+ data = this.lastChunk + data;
380
+ }
381
+ try {
382
+ result = JSON.parse(data);
383
+ } catch (error) {
384
+ this.lastChunk = data;
385
+ return;
386
+ }
387
+ this.lastChunk = null;
388
+ returnValues.push(result);
389
+ });
390
+ returnValues.forEach(chunk => {
391
+ super.onMessage(chunk);
392
+ });
393
+ }
394
+ registerEventListeners() {
395
+ this.connection.on('data', this.onMessage.bind(this));
396
+ this.connection.on('connect', this.onConnect.bind(this));
397
+ this.connection.on('error', this.onError.bind(this));
398
+ this.connection.on('close', this.onClose.bind(this));
399
+ this.connection.on('timeout', this.onClose.bind(this));
400
+ this.connection.on('ready', this.onReady.bind(this));
401
+ }
402
+ removeAllListeners(event) {
403
+ switch (event) {
404
+ case this.SOCKET_MESSAGE:
405
+ this.connection.removeListener('data', this.onMessage);
406
+ break;
407
+ case this.SOCKET_READY:
408
+ this.connection.removeListener('ready', this.onReady);
409
+ break;
410
+ case this.SOCKET_CLOSE:
411
+ this.connection.removeListener('close', this.onClose);
412
+ break;
413
+ case this.SOCKET_ERROR:
414
+ this.connection.removeListener('error', this.onError);
415
+ break;
416
+ case this.SOCKET_CONNECT:
417
+ this.connection.removeListener('connect', this.onConnect);
418
+ break;
419
+ }
420
+ super.removeAllListeners(event);
421
+ }
422
+ sendPayload(payload) {
423
+ return new Promise((resolve, reject) => {
424
+ this.once('error', reject);
425
+ if (!this.connection.writable) {
426
+ this.connection.connect({
427
+ path: this.path
428
+ });
429
+ }
430
+ if (this.connection.write(JSON.stringify(payload))) {
431
+ let id;
432
+ if (isArray(payload)) {
433
+ id = payload[0].id;
434
+ } else {
435
+ id = payload.id;
436
+ }
437
+ this.once(id, resolve);
438
+ return;
439
+ }
440
+ return reject(new Error("Connection error: Couldn't write on the socket with Socket.write(payload)"));
441
+ });
442
+ }
443
+ }
444
+
445
+ class HttpProvider {
446
+ constructor(host = 'http://localhost:8545', options = {}, providersModuleFactory) {
447
+ this.host = host;
448
+ this.timeout = options.timeout || 0;
449
+ this.headers = options.headers;
450
+ this.withCredentials = options.withCredentials || false;
451
+ this.connected = true;
452
+ this.providersModuleFactory = providersModuleFactory;
453
+ this.agent = {};
454
+ let keepAlive = false;
455
+ if (options.keepAlive === true || options.keepAlive !== false) {
456
+ keepAlive = true;
457
+ }
458
+ if (host.substring(0, 5) === 'https') {
459
+ this.agent['httpsAgent'] = new https.Agent({
460
+ keepAlive
461
+ });
462
+ } else {
463
+ this.agent['httpAgent'] = new http.Agent({
464
+ keepAlive
465
+ });
466
+ }
467
+ }
468
+ supportsSubscriptions() {
469
+ return false;
470
+ }
471
+ subscribe() {
472
+ throw new Error('Subscriptions are not supported with the HttpProvider.');
473
+ }
474
+ unsubscribe() {
475
+ throw new Error('Subscriptions are not supported with the HttpProvider.');
476
+ }
477
+ disconnect() {
478
+ return true;
479
+ }
480
+ async send(method, parameters) {
481
+ const response = await this.sendPayload(JsonRpcMapper.toPayload(method, parameters));
482
+ const validationResult = JsonRpcResponseValidator.validate(response);
483
+ if (validationResult instanceof Error) {
484
+ throw validationResult;
485
+ }
486
+ return response.result;
487
+ }
488
+ sendBatch(methods, moduleInstance) {
489
+ let payload = [];
490
+ methods.forEach(method => {
491
+ method.beforeExecution(moduleInstance);
492
+ payload.push(JsonRpcMapper.toPayload(method.rpcMethod, method.parameters));
493
+ });
494
+ return this.sendPayload(payload);
495
+ }
496
+ sendPayload(payload) {
497
+ return new Promise((resolve, reject) => {
498
+ const request = this.providersModuleFactory.createXMLHttpRequest(this.host, this.timeout, this.headers, this.agent, this.withCredentials);
499
+ request.onreadystatechange = () => {
500
+ if (request.readyState !== 0 && request.readyState !== 1) {
501
+ this.connected = true;
502
+ }
503
+ if (request.readyState === 4) {
504
+ if (request.status === 200) {
505
+ try {
506
+ return resolve(JSON.parse(request.responseText));
507
+ } catch (error) {
508
+ reject(new Error(`Invalid JSON as response: ${request.responseText}`));
509
+ }
510
+ }
511
+ if (this.isInvalidHttpEndpoint(request)) {
512
+ reject(new Error(`Connection refused or URL couldn't be resolved: ${this.host}`));
513
+ }
514
+ if (request.status >= 400 && request.status <= 499) {
515
+ reject(new Error(`HttpProvider ERROR: ${request.responseText} (code: ${request.status})`));
516
+ }
517
+ }
518
+ };
519
+ request.ontimeout = () => {
520
+ this.connected = false;
521
+ reject(new Error(`Connection error: Timeout exceeded after ${this.timeout}ms`));
522
+ };
523
+ try {
524
+ request.send(JSON.stringify(payload));
525
+ } catch (error) {
526
+ this.connected = false;
527
+ reject(error);
528
+ }
529
+ });
530
+ }
531
+ isInvalidHttpEndpoint(request) {
532
+ return request.response === null && request.status === 0;
533
+ }
534
+ }
535
+
536
+ class BatchRequest {
537
+ constructor(moduleInstance) {
538
+ this.moduleInstance = moduleInstance;
539
+ this.methods = [];
540
+ }
541
+ add(method) {
542
+ if (!isObject(method) && method) {
543
+ throw new Error('Please provide a object of type AbstractMethod.');
544
+ }
545
+ this.methods.push(method);
546
+ }
547
+ execute() {
548
+ return this.moduleInstance.currentProvider.sendBatch(this.methods, this.moduleInstance).then(response => {
549
+ let errors = [];
550
+ this.methods.forEach((method, index) => {
551
+ if (!isArray(response)) {
552
+ method.callback(new Error(`BatchRequest error: Response should be of type Array but is: ${typeof response}`), null);
553
+ errors.push(`Response should be of type Array but is: ${typeof response}`);
554
+ return;
555
+ }
556
+ const responseItem = response[index] || null;
557
+ const validationResult = JsonRpcResponseValidator.validate(responseItem);
558
+ if (validationResult) {
559
+ try {
560
+ const mappedResult = method.afterExecution(responseItem.result);
561
+ response[index] = mappedResult;
562
+ method.callback(false, mappedResult);
563
+ } catch (error) {
564
+ errors.push(error);
565
+ method.callback(error, null);
566
+ }
567
+ return;
568
+ }
569
+ errors.push(validationResult);
570
+ method.callback(validationResult, null);
571
+ });
572
+ if (errors.length > 0) {
573
+ throw new Error(`BatchRequest error: ${JSON.stringify(errors)}`);
574
+ }
575
+ return {
576
+ methods: this.methods,
577
+ response
578
+ };
579
+ });
580
+ }
581
+ }
582
+
583
+ class Web3EthereumProvider extends AbstractSocketProvider {
584
+ constructor(connection) {
585
+ super(connection, null);
586
+ this.host = 'Web3EthereumProvider';
587
+ }
588
+ registerEventListeners() {
589
+ this.connection.on('notification', this.onMessage.bind(this));
590
+ this.connection.on('connect', this.onConnect.bind(this));
591
+ this.connection.on('connect', this.onReady.bind(this));
592
+ this.connection.on('close', this.onClose.bind(this));
593
+ this.connection.on('networkChanged', this.onNetworkChanged.bind(this));
594
+ this.connection.on('accountsChanged', this.onAccountsChanged.bind(this));
595
+ }
596
+ removeAllListeners(event) {
597
+ switch (event) {
598
+ case this.SOCKET_NETWORK_CHANGED:
599
+ this.connection.removeListener('networkChanged', this.onNetworkChanged);
600
+ break;
601
+ case this.SOCKET_ACCOUNTS_CHANGED:
602
+ this.connection.removeListener('accountsChanged', this.onAccountsChanged);
603
+ break;
604
+ case this.SOCKET_MESSAGE:
605
+ this.connection.removeListener('notification', this.onMessage);
606
+ break;
607
+ case this.SOCKET_READY:
608
+ this.connection.removeListener('connect', this.onReady);
609
+ break;
610
+ case this.SOCKET_CLOSE:
611
+ this.connection.removeListener('close', this.onClose);
612
+ break;
613
+ case this.SOCKET_ERROR:
614
+ this.connection.removeListener('close', this.onError);
615
+ break;
616
+ case this.SOCKET_CONNECT:
617
+ this.connection.removeListener('connect', this.onConnect);
618
+ break;
619
+ }
620
+ super.removeAllListeners(event);
621
+ }
622
+ removeAllSocketListeners() {
623
+ this.connection.removeAllListeners();
624
+ }
625
+ onNetworkChanged(networkId) {
626
+ this.emit('networkChanged', networkId);
627
+ }
628
+ onAccountsChanged(accounts) {
629
+ this.emit('accountsChanged', accounts);
630
+ }
631
+ onMessage(response) {
632
+ this.emit(this.getSubscriptionEvent(response.subscription), response);
633
+ }
634
+ async send(method, parameters) {
635
+ const response = this.connection.send(method, parameters);
636
+ const validationResult = JsonRpcResponseValidator.validate(response);
637
+ if (validationResult instanceof Error) {
638
+ throw validationResult;
639
+ }
640
+ return response;
641
+ }
642
+ sendBatch(methods, moduleInstance) {
643
+ let methodCalls = [];
644
+ methods.forEach(method => {
645
+ method.beforeExecution(moduleInstance);
646
+ methodCalls.push(this.connection.send(method.rpcMethod, method.parameters));
647
+ });
648
+ return Promise.all(methodCalls);
649
+ }
650
+ }
651
+
652
+ class MetamaskProvider extends AbstractSocketProvider {
653
+ constructor(inpageProvider) {
654
+ super(inpageProvider, null);
655
+ this.host = 'metamask';
656
+ }
657
+ registerEventListeners() {
658
+ this.connection.on('accountsChanged', this.onAccountsChanged.bind(this));
659
+ this.connection.on('networkChanged', this.onReady.bind(this));
660
+ this.connection.on('networkChanged', this.onNetworkChanged.bind(this));
661
+ this.connection.on('data', this.onMessage.bind(this));
662
+ this.connection.on('error', this.onError.bind(this));
663
+ }
664
+ onMessage(metamaskParam, payload) {
665
+ super.onMessage(payload);
666
+ }
667
+ removeAllListeners(event) {
668
+ switch (event) {
669
+ case this.SOCKET_NETWORK_CHANGED:
670
+ this.connection.removeListener('networkChanged', this.onNetworkChanged);
671
+ break;
672
+ case this.SOCKET_ACCOUNTS_CHANGED:
673
+ this.connection.removeListener('accountsChanged', this.onAccountsChanged);
674
+ break;
675
+ case this.SOCKET_MESSAGE:
676
+ this.connection.removeListener('data', this.onMessage);
677
+ break;
678
+ case this.SOCKET_ERROR:
679
+ this.connection.removeListener('error', this.onError);
680
+ break;
681
+ }
682
+ super.removeAllListeners(event);
683
+ }
684
+ removeAllSocketListeners() {
685
+ this.connection.removeListener(this.SOCKET_NETWORK_CHANGED, this.onNetworkChanged);
686
+ this.connection.removeListener(this.SOCKET_ACCOUNTS_CHANGED, this.onAccountsChanged);
687
+ super.removeAllSocketListeners();
688
+ }
689
+ onNetworkChanged(networkId) {
690
+ this.emit('networkChanged', networkId);
691
+ }
692
+ onAccountsChanged(accounts) {
693
+ this.emit('accountsChanged', accounts);
694
+ }
695
+ disconnect() {
696
+ return true;
697
+ }
698
+ get connected() {
699
+ return this.connection.isConnected();
700
+ }
701
+ sendPayload(payload) {
702
+ return new Promise((resolve, reject) => {
703
+ this.connection.send(payload, (error, response) => {
704
+ this.removeAllListeners(payload.id);
705
+ if (!error) {
706
+ return resolve(response);
707
+ }
708
+ reject(error);
709
+ });
710
+ });
711
+ }
712
+ }
713
+
714
+ class MistEthereumProvider extends AbstractSocketProvider {
715
+ constructor(connection) {
716
+ super(connection, null);
717
+ this.host = 'mist';
718
+ }
719
+ registerEventListeners() {
720
+ this.connection.on('data', this.onMessage.bind(this));
721
+ this.connection.on('error', this.onError.bind(this));
722
+ this.connection.on('connect', this.onConnect.bind(this));
723
+ this.connection.on('connect', this.onReady.bind(this));
724
+ this.connection.on('end', this.onClose.bind(this));
725
+ }
726
+ removeAllListeners(event) {
727
+ switch (event) {
728
+ case this.SOCKET_MESSAGE:
729
+ this.connection.removeListener('data', this.onMessage);
730
+ break;
731
+ case this.SOCKET_ERROR:
732
+ this.connection.removeListener('error', this.onError);
733
+ break;
734
+ case this.SOCKET_CONNECT:
735
+ this.connection.removeListener('connect', this.onConnect);
736
+ break;
737
+ case this.SOCKET_READY:
738
+ this.connection.removeListener('connect', this.onConnect);
739
+ break;
740
+ case this.SOCKET_CLOSE:
741
+ this.connection.removeListener('end', this.onClose);
742
+ break;
743
+ }
744
+ super.removeAllListeners(event);
745
+ }
746
+ disconnect() {
747
+ return true;
748
+ }
749
+ get connected() {
750
+ return this.connection.isConnected();
751
+ }
752
+ sendPayload(payload) {
753
+ return new Promise((resolve, reject) => {
754
+ this.connection.send(payload, (error, response) => {
755
+ this.removeAllListeners(payload.id);
756
+ if (!error) {
757
+ return resolve(response);
758
+ }
759
+ reject(error);
760
+ });
761
+ });
762
+ }
763
+ }
764
+
765
+ class CustomProvider {
766
+ constructor(connection) {
767
+ this.host = 'CustomProvider';
768
+ this.connection = connection;
769
+ this.checkConnectionMethods();
770
+ }
771
+ supportsSubscriptions() {
772
+ return false;
773
+ }
774
+ checkConnectionMethods() {
775
+ if (this.connection.send || this.connection.sendAsync) {
776
+ return true;
777
+ }
778
+ throw new Error('Invalid provider injected!');
779
+ }
780
+ subscribe() {
781
+ throw new Error('Subscriptions are not supported with the CustomProvider.');
782
+ }
783
+ unsubscribe() {
784
+ throw new Error('Subscriptions are not supported with the CustomProvider.');
785
+ }
786
+ async send(method, parameters) {
787
+ const response = await this.sendPayload(JsonRpcMapper.toPayload(method, parameters));
788
+ const validationResult = JsonRpcResponseValidator.validate(response);
789
+ if (validationResult instanceof Error) {
790
+ throw validationResult;
791
+ }
792
+ return response.result;
793
+ }
794
+ sendBatch(methods, moduleInstance) {
795
+ let payload = [];
796
+ methods.forEach(method => {
797
+ method.beforeExecution(moduleInstance);
798
+ payload.push(JsonRpcMapper.toPayload(method.rpcMethod, method.parameters));
799
+ });
800
+ return this.sendPayload(payload);
801
+ }
802
+ sendPayload(payload) {
803
+ return new Promise((resolve, reject) => {
804
+ if (this.connection.sendAsync) {
805
+ this.connection.sendAsync(payload, (error, response) => {
806
+ if (!error) {
807
+ resolve(response);
808
+ }
809
+ reject(error);
810
+ });
811
+ return;
812
+ }
813
+ this.connection.send(payload, (error, response) => {
814
+ if (!error) {
815
+ resolve(response);
816
+ }
817
+ reject(error);
818
+ });
819
+ });
820
+ }
821
+ }
822
+
823
+ class ProvidersModuleFactory {
824
+ createBatchRequest(moduleInstance) {
825
+ return new BatchRequest(moduleInstance);
826
+ }
827
+ createProviderResolver() {
828
+ return new ProviderResolver(this);
829
+ }
830
+ createHttpProvider(url, options = {}) {
831
+ return new HttpProvider(url, options, this);
832
+ }
833
+ createXMLHttpRequest(host, timeout, headers, agent, withCredentials) {
834
+ let request;
835
+ if (typeof process !== 'undefined' && process.versions != null && process.versions.node != null) {
836
+ request = new XMLHttpRequest$1();
837
+ request.nodejsSet(agent);
838
+ } else {
839
+ request = new XMLHttpRequest();
840
+ }
841
+ request.open('POST', host, true);
842
+ request.setRequestHeader('Content-Type', 'application/json');
843
+ request.timeout = timeout;
844
+ request.withCredentials = withCredentials;
845
+ if (headers) {
846
+ headers.forEach(header => {
847
+ request.setRequestHeader(header.name, header.value);
848
+ });
849
+ }
850
+ return request;
851
+ }
852
+ createWebsocketProvider(url, options = {}) {
853
+ let connection = '';
854
+ if (typeof process !== 'undefined' && process.versions != null && process.versions.node != null) {
855
+ let headers = options.headers || {};
856
+ const urlObject = new URL(url);
857
+ if (!headers.authorization && urlObject.username && urlObject.password) {
858
+ const authToken = Buffer.from(`${urlObject.username}:${urlObject.password}`).toString('base64');
859
+ headers.authorization = `Basic ${authToken}`;
860
+ }
861
+ connection = new w3cwebsocket(url, options.protocol, null, headers, null, options.clientConfig);
862
+ } else {
863
+ connection = new window.WebSocket(url, options.protocol);
864
+ }
865
+ return new WebsocketProvider(connection, options.timeout);
866
+ }
867
+ createIpcProvider(path, net) {
868
+ return new IpcProvider(net.connect({
869
+ path: path
870
+ }), path);
871
+ }
872
+ createWeb3EthereumProvider(connection) {
873
+ return new Web3EthereumProvider(connection);
874
+ }
875
+ createMetamaskProvider(inpageProvider) {
876
+ return new MetamaskProvider(inpageProvider);
877
+ }
878
+ createMistEthereumProvider(mistEthereumProvider) {
879
+ return new MistEthereumProvider(mistEthereumProvider);
880
+ }
881
+ createCustomProvider(connection) {
882
+ return new CustomProvider(connection);
883
+ }
884
+ }
885
+
886
+ const global$1 = function () {
887
+ return this || typeof self === 'object' && self;
888
+ }() || new Function('return this')();
889
+ class ProviderDetector {
890
+ static detect() {
891
+ if (typeof global$1.ethereumProvider !== 'undefined' && global$1.ethereumProvider.constructor.name === 'EthereumProvider') {
892
+ return global$1.ethereumProvider;
893
+ }
894
+ if (typeof global$1.web3 !== 'undefined' && global$1.web3.currentProvider) {
895
+ return global$1.web3.currentProvider;
896
+ }
897
+ return null;
898
+ }
899
+ }
900
+
901
+ function HttpProvider$1(url, options = {}) {
902
+ return new ProvidersModuleFactory().createHttpProvider(url, options);
903
+ }
904
+ function WebsocketProvider$1(url, options = {}) {
905
+ return new ProvidersModuleFactory().createWebsocketProvider(url, options);
906
+ }
907
+ function IpcProvider$1(path, net) {
908
+ return new ProvidersModuleFactory().createIpcProvider(path, net);
909
+ }
910
+ function BatchRequest$1(moduleInstance) {
911
+ return new ProvidersModuleFactory().createBatchRequest(moduleInstance);
912
+ }
913
+ function ProviderResolver$1() {
914
+ return new ProvidersModuleFactory().createProviderResolver();
915
+ }
916
+
917
+ export { BatchRequest$1 as BatchRequest, HttpProvider$1 as HttpProvider, IpcProvider$1 as IpcProvider, ProviderDetector, ProviderResolver$1 as ProviderResolver, ProvidersModuleFactory, Web3EthereumProvider, WebsocketProvider$1 as WebsocketProvider };