mainnet-js 2.6.7 → 2.7.0
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.
- package/dist/index.html +1 -1
- package/dist/{mainnet-2.6.7.js → mainnet-2.7.0.js} +446 -156
- package/dist/module/cli.js +0 -4
- package/dist/module/cli.js.map +1 -1
- package/dist/module/index.d.ts +1 -3
- package/dist/module/index.d.ts.map +1 -1
- package/dist/module/index.js +1 -3
- package/dist/module/index.js.map +1 -1
- package/dist/module/network/ElectrumNetworkProvider.d.ts +21 -27
- package/dist/module/network/ElectrumNetworkProvider.d.ts.map +1 -1
- package/dist/module/network/ElectrumNetworkProvider.js +92 -102
- package/dist/module/network/ElectrumNetworkProvider.js.map +1 -1
- package/dist/module/network/NetworkProvider.d.ts +9 -22
- package/dist/module/network/NetworkProvider.d.ts.map +1 -1
- package/dist/module/network/constant.d.ts +0 -21
- package/dist/module/network/constant.d.ts.map +1 -1
- package/dist/module/network/constant.js +0 -21
- package/dist/module/network/constant.js.map +1 -1
- package/dist/module/network/default.d.ts +2 -2
- package/dist/module/network/default.d.ts.map +1 -1
- package/dist/module/network/default.js +15 -45
- package/dist/module/network/default.js.map +1 -1
- package/dist/module/network/interface.d.ts +2 -8
- package/dist/module/network/interface.d.ts.map +1 -1
- package/dist/module/network/util.d.ts.map +1 -1
- package/dist/module/network/util.js +4 -5
- package/dist/module/network/util.js.map +1 -1
- package/dist/module/rate/ExchangeRate.js +2 -1
- package/dist/module/rate/ExchangeRate.js.map +1 -1
- package/dist/module/transaction/Wif.d.ts.map +1 -1
- package/dist/module/transaction/Wif.js +1 -1
- package/dist/module/transaction/Wif.js.map +1 -1
- package/dist/module/wallet/Base.d.ts +282 -88
- package/dist/module/wallet/Base.d.ts.map +1 -1
- package/dist/module/wallet/Base.js +1058 -215
- package/dist/module/wallet/Base.js.map +1 -1
- package/dist/module/wallet/Util.d.ts +7 -54
- package/dist/module/wallet/Util.d.ts.map +1 -1
- package/dist/module/wallet/Util.js +12 -79
- package/dist/module/wallet/Util.js.map +1 -1
- package/dist/module/wallet/Wif.d.ts +46 -251
- package/dist/module/wallet/Wif.d.ts.map +1 -1
- package/dist/module/wallet/Wif.js +126 -1026
- package/dist/module/wallet/Wif.js.map +1 -1
- package/dist/module/wallet/createWallet.d.ts +2 -1
- package/dist/module/wallet/createWallet.d.ts.map +1 -1
- package/dist/module/wallet/createWallet.js +2 -3
- package/dist/module/wallet/createWallet.js.map +1 -1
- package/dist/module/wallet/interface.d.ts +2 -4
- package/dist/module/wallet/interface.d.ts.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +6 -12
- package/src/cli.ts +0 -4
- package/src/index.ts +1 -5
- package/src/network/ElectrumNetworkProvider.ts +133 -188
- package/src/network/NetworkProvider.ts +9 -30
- package/src/network/Rpc.test.ts +14 -5
- package/src/network/constant.ts +0 -23
- package/src/network/default.ts +26 -66
- package/src/network/electrum.test.ts +2 -4
- package/src/network/interface.ts +2 -9
- package/src/network/util.ts +6 -7
- package/src/rate/ExchangeRate.test.ts +1 -1
- package/src/rate/ExchangeRate.ts +2 -1
- package/{polyfill/json.js → src/test/json.test.ts} +7 -1
- package/src/transaction/Wif.ts +2 -1
- package/src/wallet/Base.ts +1520 -273
- package/src/wallet/Cashtokens.test.headless.js +1 -1
- package/src/wallet/Cashtokens.test.ts +7 -8
- package/src/wallet/Util.ts +20 -102
- package/src/wallet/Wif.bip39.test.ts +3 -3
- package/src/wallet/Wif.test.ts +31 -25
- package/src/wallet/Wif.ts +174 -1493
- package/src/wallet/Wif.watchOnly.test.ts +5 -5
- package/src/wallet/createWallet.ts +11 -10
- package/src/wallet/interface.ts +3 -4
- package/webpack.config.cjs +4 -55
- package/dist/module/qr/Qr.d.ts +0 -9
- package/dist/module/qr/Qr.d.ts.map +0 -1
- package/dist/module/qr/Qr.js +0 -22
- package/dist/module/qr/Qr.js.map +0 -1
- package/dist/module/qr/interface.d.ts +0 -6
- package/dist/module/qr/interface.d.ts.map +0 -1
- package/dist/module/qr/interface.js +0 -2
- package/dist/module/qr/interface.js.map +0 -1
- package/dist/module/util/eventsource.d.ts +0 -3
- package/dist/module/util/eventsource.d.ts.map +0 -1
- package/dist/module/util/eventsource.js +0 -11
- package/dist/module/util/eventsource.js.map +0 -1
- package/polyfill/README.md +0 -1
- package/polyfill/eventsource.js +0 -6
- package/polyfill/support/types.js +0 -286
- package/polyfill/util.cjs +0 -249
- package/src/network/default.test.ts +0 -37
- package/src/qr/Qr.test.ts +0 -14
- package/src/qr/Qr.ts +0 -24
- package/src/qr/interface.ts +0 -5
- package/src/util/eventsource.ts +0 -12
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
|
-
ElectrumCluster,
|
|
3
2
|
ElectrumClient,
|
|
4
3
|
RequestResponse,
|
|
4
|
+
ElectrumClientEvents,
|
|
5
|
+
RPCNotification,
|
|
5
6
|
ConnectionStatus,
|
|
6
|
-
} from "electrum-cash";
|
|
7
|
+
} from "@electrum-cash/network";
|
|
7
8
|
import { default as NetworkProvider } from "./NetworkProvider.js";
|
|
8
9
|
import {
|
|
9
10
|
HexHeaderI,
|
|
@@ -16,7 +17,7 @@ import { Network } from "../interface.js";
|
|
|
16
17
|
import { delay } from "../util/delay.js";
|
|
17
18
|
import { ElectrumRawTransaction, ElectrumUtxo } from "./interface.js";
|
|
18
19
|
|
|
19
|
-
import {
|
|
20
|
+
import { CancelFn } from "../wallet/interface.js";
|
|
20
21
|
import { getTransactionHash } from "../util/transaction.js";
|
|
21
22
|
import { Config } from "../config.js";
|
|
22
23
|
import { decodeHeader } from "../util/header.js";
|
|
@@ -26,10 +27,12 @@ import { WebStorageCache } from "../cache/WebStorageCache.js";
|
|
|
26
27
|
import { MemoryCache } from "../cache/MemoryCache.js";
|
|
27
28
|
|
|
28
29
|
export default class ElectrumNetworkProvider implements NetworkProvider {
|
|
29
|
-
public electrum:
|
|
30
|
+
public electrum: ElectrumClient<ElectrumClientEvents>;
|
|
30
31
|
public subscriptions: number = 0;
|
|
31
32
|
public version;
|
|
32
33
|
private connectPromise;
|
|
34
|
+
private subscribedToHeaders: boolean = false;
|
|
35
|
+
private subscriptionMap: Record<string, number> = {};
|
|
33
36
|
|
|
34
37
|
private _cache: CacheProvider | undefined;
|
|
35
38
|
|
|
@@ -65,20 +68,16 @@ export default class ElectrumNetworkProvider implements NetworkProvider {
|
|
|
65
68
|
}
|
|
66
69
|
|
|
67
70
|
constructor(
|
|
68
|
-
electrum:
|
|
71
|
+
electrum: ElectrumClient<ElectrumClientEvents>,
|
|
69
72
|
public network: Network = Network.MAINNET,
|
|
70
73
|
private manualConnectionManagement?: boolean
|
|
71
74
|
) {
|
|
72
75
|
if (electrum) {
|
|
73
76
|
this.electrum = electrum;
|
|
74
77
|
this.connectPromise = this.getConnectPromise();
|
|
75
|
-
|
|
76
|
-
this.version = (this.electrum as ElectrumCluster).version;
|
|
77
|
-
} else {
|
|
78
|
-
this.version = (this.electrum as ElectrumClient).connection.version;
|
|
79
|
-
}
|
|
78
|
+
this.version = this.electrum.version;
|
|
80
79
|
} else {
|
|
81
|
-
throw new Error(`A electrum-cash
|
|
80
|
+
throw new Error(`A electrum-cash client is required.`);
|
|
82
81
|
}
|
|
83
82
|
}
|
|
84
83
|
|
|
@@ -89,40 +88,18 @@ export default class ElectrumNetworkProvider implements NetworkProvider {
|
|
|
89
88
|
await Promise.race([
|
|
90
89
|
new Promise(async (resolve) => {
|
|
91
90
|
this.connectPromise = undefined;
|
|
92
|
-
|
|
93
|
-
if (this.electrum instanceof ElectrumCluster) {
|
|
94
|
-
try {
|
|
95
|
-
await this.connectCluster();
|
|
96
|
-
} catch (e) {
|
|
97
|
-
console.warn(
|
|
98
|
-
`Unable to connect to one or more electrum-cash hosts: ${JSON.stringify(
|
|
99
|
-
e
|
|
100
|
-
)}`
|
|
101
|
-
);
|
|
102
|
-
}
|
|
103
|
-
resolve(await this.readyCluster());
|
|
104
|
-
} else {
|
|
105
|
-
resolve(await this.connectClient());
|
|
106
|
-
}
|
|
91
|
+
resolve(await this.connectClient());
|
|
107
92
|
}),
|
|
108
|
-
// new Promise(
|
|
109
|
-
// (_resolve, reject) =>
|
|
110
|
-
// (timeoutHandle = setTimeout(() => {
|
|
111
|
-
// reject(
|
|
112
|
-
// new Error(`Timeout connecting to electrum network: ${this.network}`)
|
|
113
|
-
// );
|
|
114
|
-
// }, _timeout))
|
|
115
|
-
// ),
|
|
116
93
|
]);
|
|
117
94
|
clearTimeout(timeoutHandle);
|
|
118
95
|
}
|
|
119
96
|
|
|
120
97
|
async getUtxos(cashaddr: string): Promise<UtxoI[]> {
|
|
121
|
-
const result =
|
|
98
|
+
const result = await this.performRequest<ElectrumUtxo[]>(
|
|
122
99
|
"blockchain.address.listunspent",
|
|
123
100
|
cashaddr,
|
|
124
101
|
"include_tokens"
|
|
125
|
-
)
|
|
102
|
+
);
|
|
126
103
|
return result.map((utxo) => ({
|
|
127
104
|
txid: utxo.tx_hash,
|
|
128
105
|
vout: utxo.tx_pos,
|
|
@@ -140,10 +117,10 @@ export default class ElectrumNetworkProvider implements NetworkProvider {
|
|
|
140
117
|
}
|
|
141
118
|
|
|
142
119
|
async getBalance(cashaddr: string): Promise<number> {
|
|
143
|
-
const result =
|
|
120
|
+
const result = await this.performRequest<ElectrumBalanceI>(
|
|
144
121
|
"blockchain.address.get_balance",
|
|
145
122
|
cashaddr
|
|
146
|
-
)
|
|
123
|
+
);
|
|
147
124
|
|
|
148
125
|
return result.confirmed + result.unconfirmed;
|
|
149
126
|
}
|
|
@@ -161,10 +138,10 @@ export default class ElectrumNetworkProvider implements NetworkProvider {
|
|
|
161
138
|
}
|
|
162
139
|
}
|
|
163
140
|
|
|
164
|
-
const result =
|
|
141
|
+
const result = await this.performRequest<HexHeaderI>(
|
|
165
142
|
"blockchain.header.get",
|
|
166
143
|
height
|
|
167
|
-
)
|
|
144
|
+
);
|
|
168
145
|
if (this.cache) {
|
|
169
146
|
await this.cache.setItem(key, JSON.stringify(result));
|
|
170
147
|
}
|
|
@@ -173,7 +150,7 @@ export default class ElectrumNetworkProvider implements NetworkProvider {
|
|
|
173
150
|
}
|
|
174
151
|
|
|
175
152
|
async getBlockHeight(): Promise<number> {
|
|
176
|
-
return (
|
|
153
|
+
return (await this.performRequest<HexHeaderI>("blockchain.headers.get_tip"))
|
|
177
154
|
.height;
|
|
178
155
|
}
|
|
179
156
|
|
|
@@ -262,17 +239,22 @@ export default class ElectrumNetworkProvider implements NetworkProvider {
|
|
|
262
239
|
this.performRequest("blockchain.transaction.broadcast", txHex);
|
|
263
240
|
resolve(txHash);
|
|
264
241
|
} else {
|
|
242
|
+
let cancel: CancelFn;
|
|
243
|
+
|
|
265
244
|
const waitForTransactionCallback = async (data) => {
|
|
266
|
-
if (data && data[0] === txHash) {
|
|
267
|
-
|
|
245
|
+
if (data && data[0] === txHash && data[1] !== null) {
|
|
246
|
+
await cancel?.();
|
|
268
247
|
resolve(txHash);
|
|
269
248
|
}
|
|
270
249
|
};
|
|
271
|
-
this.subscribeToTransaction(
|
|
250
|
+
cancel = await this.subscribeToTransaction(
|
|
251
|
+
txHash,
|
|
252
|
+
waitForTransactionCallback
|
|
253
|
+
);
|
|
272
254
|
|
|
273
255
|
this.performRequest("blockchain.transaction.broadcast", txHex).catch(
|
|
274
|
-
(error) => {
|
|
275
|
-
|
|
256
|
+
async (error) => {
|
|
257
|
+
await cancel?.();
|
|
276
258
|
reject(error);
|
|
277
259
|
}
|
|
278
260
|
);
|
|
@@ -286,12 +268,12 @@ export default class ElectrumNetworkProvider implements NetworkProvider {
|
|
|
286
268
|
fromHeight: number = 0,
|
|
287
269
|
toHeight: number = -1
|
|
288
270
|
): Promise<TxI[]> {
|
|
289
|
-
const result =
|
|
271
|
+
const result = await this.performRequest<TxI[]>(
|
|
290
272
|
"blockchain.address.get_history",
|
|
291
273
|
cashaddr,
|
|
292
274
|
fromHeight,
|
|
293
275
|
toHeight
|
|
294
|
-
)
|
|
276
|
+
);
|
|
295
277
|
|
|
296
278
|
return result;
|
|
297
279
|
}
|
|
@@ -303,10 +285,10 @@ export default class ElectrumNetworkProvider implements NetworkProvider {
|
|
|
303
285
|
return result;
|
|
304
286
|
}
|
|
305
287
|
|
|
306
|
-
public watchAddressStatus(
|
|
288
|
+
public async watchAddressStatus(
|
|
307
289
|
cashaddr: string,
|
|
308
290
|
callback: (status: string) => void
|
|
309
|
-
):
|
|
291
|
+
): Promise<CancelFn> {
|
|
310
292
|
const watchAddressStatusCallback = async (data) => {
|
|
311
293
|
// subscription acknowledgement is the latest known status or null if no status is known
|
|
312
294
|
// status is an array: [ cashaddr, statusHash ]
|
|
@@ -321,17 +303,13 @@ export default class ElectrumNetworkProvider implements NetworkProvider {
|
|
|
321
303
|
}
|
|
322
304
|
};
|
|
323
305
|
|
|
324
|
-
this.subscribeToAddress(cashaddr, watchAddressStatusCallback);
|
|
325
|
-
|
|
326
|
-
return async () => {
|
|
327
|
-
await this.unsubscribeFromAddress(cashaddr, watchAddressStatusCallback);
|
|
328
|
-
};
|
|
306
|
+
return this.subscribeToAddress(cashaddr, watchAddressStatusCallback);
|
|
329
307
|
}
|
|
330
308
|
|
|
331
|
-
public watchAddress(
|
|
309
|
+
public async watchAddress(
|
|
332
310
|
cashaddr: string,
|
|
333
311
|
callback: (txHash: string) => void
|
|
334
|
-
):
|
|
312
|
+
): Promise<CancelFn> {
|
|
335
313
|
const historyMap: { [txid: string]: boolean } = {};
|
|
336
314
|
|
|
337
315
|
this.getHistory(cashaddr).then((history) =>
|
|
@@ -359,20 +337,20 @@ export default class ElectrumNetworkProvider implements NetworkProvider {
|
|
|
359
337
|
return this.watchAddressStatus(cashaddr, watchAddressStatusCallback);
|
|
360
338
|
}
|
|
361
339
|
|
|
362
|
-
public watchAddressTransactions(
|
|
340
|
+
public async watchAddressTransactions(
|
|
363
341
|
cashaddr: string,
|
|
364
342
|
callback: (tx: ElectrumRawTransaction) => void
|
|
365
|
-
):
|
|
343
|
+
): Promise<CancelFn> {
|
|
366
344
|
return this.watchAddress(cashaddr, async (txHash: string) => {
|
|
367
345
|
const tx = await this.getRawTransactionObject(txHash);
|
|
368
346
|
callback(tx);
|
|
369
347
|
});
|
|
370
348
|
}
|
|
371
349
|
|
|
372
|
-
public watchAddressTokenTransactions(
|
|
350
|
+
public async watchAddressTokenTransactions(
|
|
373
351
|
cashaddr: string,
|
|
374
352
|
callback: (tx: ElectrumRawTransaction) => void
|
|
375
|
-
):
|
|
353
|
+
): Promise<CancelFn> {
|
|
376
354
|
return this.watchAddress(cashaddr, async (txHash: string) => {
|
|
377
355
|
const tx = await this.getRawTransactionObject(txHash, true);
|
|
378
356
|
if (
|
|
@@ -385,10 +363,10 @@ export default class ElectrumNetworkProvider implements NetworkProvider {
|
|
|
385
363
|
}
|
|
386
364
|
|
|
387
365
|
// watch for block headers and block height, if `skipCurrentHeight` is set, the notification about current block will not arrive
|
|
388
|
-
public watchBlocks(
|
|
366
|
+
public async watchBlocks(
|
|
389
367
|
callback: (header: HexHeaderI) => void,
|
|
390
368
|
skipCurrentHeight: boolean = true
|
|
391
|
-
):
|
|
369
|
+
): Promise<CancelFn> {
|
|
392
370
|
let acknowledged = !skipCurrentHeight;
|
|
393
371
|
const waitForBlockCallback = (_header: HexHeaderI | HexHeaderI[]) => {
|
|
394
372
|
if (!acknowledged) {
|
|
@@ -399,20 +377,27 @@ export default class ElectrumNetworkProvider implements NetworkProvider {
|
|
|
399
377
|
_header = _header instanceof Array ? _header[0] : _header;
|
|
400
378
|
callback(_header);
|
|
401
379
|
};
|
|
402
|
-
this.subscribeToHeaders(waitForBlockCallback);
|
|
403
|
-
|
|
404
|
-
return async () => {
|
|
405
|
-
this.unsubscribeFromHeaders(waitForBlockCallback);
|
|
406
|
-
};
|
|
380
|
+
return this.subscribeToHeaders(waitForBlockCallback);
|
|
407
381
|
}
|
|
408
382
|
|
|
409
383
|
// Wait for the next block or a block at given blockchain height.
|
|
410
384
|
public async waitForBlock(height?: number): Promise<HexHeaderI> {
|
|
411
385
|
return new Promise(async (resolve) => {
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
386
|
+
let cancelWatch: CancelFn;
|
|
387
|
+
if (this.electrum.chainHeight && !height) {
|
|
388
|
+
height = this.electrum.chainHeight + 1;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
cancelWatch = await this.watchBlocks(async (header) => {
|
|
392
|
+
if (!height) {
|
|
393
|
+
height = header.height + 1;
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
if (header.height >= height) {
|
|
398
|
+
await cancelWatch?.();
|
|
415
399
|
resolve(header);
|
|
400
|
+
return;
|
|
416
401
|
}
|
|
417
402
|
});
|
|
418
403
|
});
|
|
@@ -421,87 +406,36 @@ export default class ElectrumNetworkProvider implements NetworkProvider {
|
|
|
421
406
|
// subscribe to notifications sent when new block is found, the block header is sent to callback
|
|
422
407
|
async subscribeToHeaders(
|
|
423
408
|
callback: (header: HexHeaderI) => void
|
|
424
|
-
): Promise<
|
|
425
|
-
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
// unsubscribe to notifications sent when new block is found
|
|
429
|
-
async unsubscribeFromHeaders(
|
|
430
|
-
callback: (header: HexHeaderI) => void
|
|
431
|
-
): Promise<void> {
|
|
432
|
-
await this.unsubscribeRequest("blockchain.headers.subscribe", callback);
|
|
409
|
+
): Promise<CancelFn> {
|
|
410
|
+
return this.subscribeRequest("blockchain.headers.subscribe", callback);
|
|
433
411
|
}
|
|
434
412
|
|
|
435
413
|
async subscribeToAddress(
|
|
436
414
|
cashaddr: string,
|
|
437
415
|
callback: (data: any) => void
|
|
438
|
-
): Promise<
|
|
439
|
-
|
|
416
|
+
): Promise<CancelFn> {
|
|
417
|
+
return this.subscribeRequest(
|
|
440
418
|
"blockchain.address.subscribe",
|
|
441
419
|
callback,
|
|
442
420
|
cashaddr
|
|
443
421
|
);
|
|
444
422
|
}
|
|
445
423
|
|
|
446
|
-
async unsubscribeFromAddress(
|
|
447
|
-
cashaddr: string,
|
|
448
|
-
callback: (data: any) => void
|
|
449
|
-
): Promise<void> {
|
|
450
|
-
await this.unsubscribeRequest(
|
|
451
|
-
"blockchain.address.subscribe",
|
|
452
|
-
callback,
|
|
453
|
-
cashaddr
|
|
454
|
-
);
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
async subscribeToAddressTransactions(
|
|
458
|
-
cashaddr: string,
|
|
459
|
-
callback: (data: any) => void
|
|
460
|
-
): Promise<void> {
|
|
461
|
-
await this.subscribeRequest(
|
|
462
|
-
"blockchain.address.transactions.subscribe",
|
|
463
|
-
callback,
|
|
464
|
-
cashaddr
|
|
465
|
-
);
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
async unsubscribeFromAddressTransactions(
|
|
469
|
-
cashaddr: string,
|
|
470
|
-
callback: (data: any) => void
|
|
471
|
-
): Promise<void> {
|
|
472
|
-
await this.unsubscribeRequest(
|
|
473
|
-
"blockchain.address.transactions.subscribe",
|
|
474
|
-
callback,
|
|
475
|
-
cashaddr
|
|
476
|
-
);
|
|
477
|
-
}
|
|
478
|
-
|
|
479
424
|
async subscribeToTransaction(
|
|
480
425
|
txHash: string,
|
|
481
426
|
callback: (data: any) => void
|
|
482
|
-
): Promise<
|
|
483
|
-
|
|
427
|
+
): Promise<CancelFn> {
|
|
428
|
+
return this.subscribeRequest(
|
|
484
429
|
"blockchain.transaction.subscribe",
|
|
485
430
|
callback,
|
|
486
431
|
txHash
|
|
487
432
|
);
|
|
488
433
|
}
|
|
489
434
|
|
|
490
|
-
async
|
|
491
|
-
txHash: string,
|
|
492
|
-
callback: (data: any) => void
|
|
493
|
-
): Promise<void> {
|
|
494
|
-
await this.unsubscribeRequest(
|
|
495
|
-
"blockchain.transaction.subscribe",
|
|
496
|
-
callback,
|
|
497
|
-
txHash
|
|
498
|
-
);
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
private async performRequest(
|
|
435
|
+
private async performRequest<T>(
|
|
502
436
|
name: string,
|
|
503
437
|
...parameters: (string | number | boolean)[]
|
|
504
|
-
): Promise<
|
|
438
|
+
): Promise<T> {
|
|
505
439
|
await this.ready();
|
|
506
440
|
|
|
507
441
|
const requestTimeout = new Promise(function (_resolve, reject) {
|
|
@@ -518,7 +452,7 @@ export default class ElectrumNetworkProvider implements NetworkProvider {
|
|
|
518
452
|
.then((value) => {
|
|
519
453
|
if (value instanceof Error) throw value;
|
|
520
454
|
let result = value as RequestResponse;
|
|
521
|
-
return result;
|
|
455
|
+
return result as T;
|
|
522
456
|
})
|
|
523
457
|
.catch(async () => {
|
|
524
458
|
// console.warn(
|
|
@@ -528,7 +462,7 @@ export default class ElectrumNetworkProvider implements NetworkProvider {
|
|
|
528
462
|
.then((value) => {
|
|
529
463
|
if (value instanceof Error) throw value;
|
|
530
464
|
let result = value as RequestResponse;
|
|
531
|
-
return result;
|
|
465
|
+
return result as T;
|
|
532
466
|
})
|
|
533
467
|
.catch(function (e) {
|
|
534
468
|
throw e;
|
|
@@ -536,74 +470,100 @@ export default class ElectrumNetworkProvider implements NetworkProvider {
|
|
|
536
470
|
});
|
|
537
471
|
}
|
|
538
472
|
|
|
539
|
-
private async
|
|
473
|
+
private async trackSubscription(
|
|
540
474
|
methodName: string,
|
|
541
|
-
callback: (data) => void,
|
|
542
475
|
...parameters: (string | number | boolean)[]
|
|
543
|
-
): Promise<
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
);
|
|
476
|
+
): Promise<void> {
|
|
477
|
+
const key = `${methodName}-${this.network}-${JSON.stringify(parameters)}`;
|
|
478
|
+
if (this.subscriptionMap[key]) {
|
|
479
|
+
this.subscriptionMap[key]++;
|
|
480
|
+
} else {
|
|
481
|
+
this.subscriptionMap[key] = 1;
|
|
482
|
+
}
|
|
551
483
|
|
|
552
|
-
this.
|
|
484
|
+
await this.electrum.subscribe(methodName, ...parameters);
|
|
485
|
+
}
|
|
553
486
|
|
|
554
|
-
|
|
487
|
+
private async untrackSubscription(
|
|
488
|
+
methodName: string,
|
|
489
|
+
...parameters: (string | number | boolean)[]
|
|
490
|
+
): Promise<void> {
|
|
491
|
+
const key = `${methodName}-${this.network}-${JSON.stringify(parameters)}`;
|
|
492
|
+
if (this.subscriptionMap[key]) {
|
|
493
|
+
this.subscriptionMap[key]--;
|
|
494
|
+
if (this.subscriptionMap[key] <= 0) {
|
|
495
|
+
// only really unsubscribe if there are no more subscriptions for this `key`
|
|
496
|
+
delete this.subscriptionMap[key];
|
|
497
|
+
|
|
498
|
+
try {
|
|
499
|
+
await this.electrum.unsubscribe(methodName, ...parameters);
|
|
500
|
+
} catch {}
|
|
501
|
+
}
|
|
502
|
+
}
|
|
555
503
|
}
|
|
556
504
|
|
|
557
|
-
|
|
505
|
+
public async subscribeRequest(
|
|
558
506
|
methodName: string,
|
|
559
507
|
callback: (data) => void,
|
|
560
508
|
...parameters: (string | number | boolean)[]
|
|
561
|
-
): Promise<
|
|
509
|
+
): Promise<CancelFn> {
|
|
562
510
|
await this.ready();
|
|
563
511
|
|
|
564
|
-
const
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
512
|
+
const handler = (data: RPCNotification) => {
|
|
513
|
+
if (data.method === methodName) {
|
|
514
|
+
callback(data.params);
|
|
515
|
+
}
|
|
516
|
+
};
|
|
569
517
|
|
|
570
|
-
this.
|
|
518
|
+
this.electrum.on("notification", handler);
|
|
571
519
|
|
|
572
|
-
|
|
520
|
+
// safeguard against multiple subscriptions to headers
|
|
521
|
+
if (methodName === "blockhain.headers.subscribe") {
|
|
522
|
+
if (!this.subscribedToHeaders) {
|
|
523
|
+
this.subscribedToHeaders = true;
|
|
524
|
+
|
|
525
|
+
await this.trackSubscription(methodName, ...parameters);
|
|
526
|
+
}
|
|
527
|
+
} else {
|
|
528
|
+
await this.trackSubscription(methodName, ...parameters);
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
this.subscriptions++;
|
|
532
|
+
|
|
533
|
+
return async () => {
|
|
534
|
+
this.electrum.off("notification", handler);
|
|
535
|
+
this.subscriptions--;
|
|
536
|
+
|
|
537
|
+
// there are no blockchain.headers.unsubscribe method, so let's safeguard against it
|
|
538
|
+
if (methodName !== "blockchain.headers.subscribe") {
|
|
539
|
+
await this.untrackSubscription(methodName, ...parameters);
|
|
540
|
+
}
|
|
541
|
+
};
|
|
573
542
|
}
|
|
574
543
|
|
|
575
544
|
async ready(): Promise<boolean | unknown> {
|
|
576
|
-
return
|
|
545
|
+
return this.connect();
|
|
577
546
|
}
|
|
578
547
|
|
|
579
|
-
async connect(): Promise<void
|
|
548
|
+
async connect(): Promise<void> {
|
|
580
549
|
await this.cache?.init();
|
|
581
550
|
return await this.connectPromise;
|
|
582
551
|
}
|
|
583
552
|
|
|
584
|
-
disconnect(): Promise<boolean
|
|
553
|
+
disconnect(): Promise<boolean> {
|
|
585
554
|
if (this.subscriptions > 0) {
|
|
586
555
|
// console.warn(
|
|
587
556
|
// `Trying to disconnect a network provider with ${this.subscriptions} active subscriptions. This is in most cases a bad idea.`
|
|
588
557
|
// );
|
|
589
558
|
}
|
|
590
|
-
return this.
|
|
591
|
-
? this.disconnectClient()
|
|
592
|
-
: this.disconnectCluster();
|
|
593
|
-
}
|
|
594
|
-
|
|
595
|
-
isElectrumClient(): boolean {
|
|
596
|
-
return this.electrum.hasOwnProperty("connection");
|
|
559
|
+
return this.disconnectClient();
|
|
597
560
|
}
|
|
598
561
|
|
|
599
562
|
async readyClient(timeout?: number): Promise<boolean | unknown> {
|
|
600
563
|
timeout = typeof timeout !== "undefined" ? timeout : 3000;
|
|
601
564
|
|
|
602
565
|
let connectPromise = async () => {
|
|
603
|
-
while (
|
|
604
|
-
(this.electrum as ElectrumClient).connection.status !==
|
|
605
|
-
ConnectionStatus.CONNECTED
|
|
606
|
-
) {
|
|
566
|
+
while (this.electrum.status !== ConnectionStatus.CONNECTED) {
|
|
607
567
|
await delay(100);
|
|
608
568
|
}
|
|
609
569
|
return true;
|
|
@@ -611,37 +571,22 @@ export default class ElectrumNetworkProvider implements NetworkProvider {
|
|
|
611
571
|
return connectPromise;
|
|
612
572
|
}
|
|
613
573
|
|
|
614
|
-
async
|
|
615
|
-
timeout;
|
|
616
|
-
return (this.electrum as ElectrumCluster).ready();
|
|
617
|
-
}
|
|
618
|
-
|
|
619
|
-
async connectCluster(): Promise<void[]> {
|
|
620
|
-
return (this.electrum as ElectrumCluster).startup();
|
|
621
|
-
}
|
|
622
|
-
|
|
623
|
-
async connectClient(): Promise<void[]> {
|
|
574
|
+
async connectClient(): Promise<void> {
|
|
624
575
|
let connectionPromise = async () => {
|
|
625
576
|
try {
|
|
626
|
-
return await
|
|
577
|
+
return await this.electrum.connect();
|
|
627
578
|
} catch (e) {
|
|
628
579
|
console.warn(
|
|
629
|
-
`Warning: Failed to connect to client on ${this.network} at ${
|
|
630
|
-
(this.electrum as ElectrumClient).connection.host
|
|
631
|
-
}.`,
|
|
580
|
+
`Warning: Failed to connect to client on ${this.network} at ${this.electrum.hostIdentifier}.`,
|
|
632
581
|
e
|
|
633
582
|
);
|
|
634
583
|
return;
|
|
635
584
|
}
|
|
636
585
|
};
|
|
637
|
-
return
|
|
638
|
-
}
|
|
639
|
-
|
|
640
|
-
async disconnectCluster(): Promise<boolean[]> {
|
|
641
|
-
return (this.electrum as ElectrumCluster).shutdown();
|
|
586
|
+
return connectionPromise();
|
|
642
587
|
}
|
|
643
588
|
|
|
644
|
-
async disconnectClient(): Promise<boolean
|
|
645
|
-
return
|
|
589
|
+
async disconnectClient(): Promise<boolean> {
|
|
590
|
+
return this.electrum.disconnect(true, false);
|
|
646
591
|
}
|
|
647
592
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { TxI, UtxoI, Network, HexHeaderI, HeaderI } from "../interface.js";
|
|
2
|
+
import { CancelFn } from "../wallet/interface.js";
|
|
2
3
|
|
|
3
4
|
export default interface NetworkProvider {
|
|
4
5
|
/**
|
|
@@ -93,18 +94,7 @@ export default interface NetworkProvider {
|
|
|
93
94
|
subscribeToAddress(
|
|
94
95
|
cashaddr: string,
|
|
95
96
|
callback: (data: any) => void
|
|
96
|
-
): Promise<
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* Unsubscribe from the address change events
|
|
100
|
-
* @param cashaddr The CashAddress for which we wish to retrieve history.
|
|
101
|
-
* @throws {Error} If the unsubscription failed.
|
|
102
|
-
* @returns nothing.
|
|
103
|
-
*/
|
|
104
|
-
unsubscribeFromAddress(
|
|
105
|
-
cashaddr: string,
|
|
106
|
-
callback: (data: any) => void
|
|
107
|
-
): Promise<void>;
|
|
97
|
+
): Promise<CancelFn>;
|
|
108
98
|
|
|
109
99
|
/**
|
|
110
100
|
* Subscribe to a transaction in order to receive future notifications if its confirmation status changes.
|
|
@@ -115,18 +105,7 @@ export default interface NetworkProvider {
|
|
|
115
105
|
subscribeToTransaction(
|
|
116
106
|
txHash: string,
|
|
117
107
|
callback: (data: any) => void
|
|
118
|
-
): Promise<
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* Unsubscribe from a transaction, preventing future notifications if its confirmation status changes.
|
|
122
|
-
* @param txHash The transaction hash as a hexadecimal string.
|
|
123
|
-
* @throws {Error} If the subscription failed.
|
|
124
|
-
* @returns nothing.
|
|
125
|
-
*/
|
|
126
|
-
unsubscribeFromTransaction(
|
|
127
|
-
txHash: string,
|
|
128
|
-
callback: (data: any) => void
|
|
129
|
-
): Promise<void>;
|
|
108
|
+
): Promise<CancelFn>;
|
|
130
109
|
|
|
131
110
|
/**
|
|
132
111
|
* Function to wait for connection to be ready
|
|
@@ -136,14 +115,14 @@ export default interface NetworkProvider {
|
|
|
136
115
|
ready(timeout?: number): Promise<boolean | unknown>;
|
|
137
116
|
|
|
138
117
|
/**
|
|
139
|
-
* Function to connect manually if using persistent
|
|
140
|
-
* @returns
|
|
118
|
+
* Function to connect manually if using persistent connection
|
|
119
|
+
* @returns a promise resolving when the connection is established.
|
|
141
120
|
*/
|
|
142
|
-
connect(): Promise<void
|
|
121
|
+
connect(): Promise<void>;
|
|
143
122
|
|
|
144
123
|
/**
|
|
145
|
-
* Function to disconnect manually if using persistent
|
|
146
|
-
* @returns
|
|
124
|
+
* Function to disconnect manually if using persistent connection
|
|
125
|
+
* @returns true if successfully disconnected, or false if there was no connection
|
|
147
126
|
*/
|
|
148
|
-
disconnect(): Promise<boolean
|
|
127
|
+
disconnect(): Promise<boolean>;
|
|
149
128
|
}
|
package/src/network/Rpc.test.ts
CHANGED
|
@@ -15,11 +15,20 @@ afterAll(async () => {
|
|
|
15
15
|
});
|
|
16
16
|
|
|
17
17
|
describe("Rpc tests", () => {
|
|
18
|
+
test("get utxos", async () => {
|
|
19
|
+
const provider = getNetworkProvider(Network.REGTEST);
|
|
20
|
+
expect(
|
|
21
|
+
await provider.getUtxos(
|
|
22
|
+
"bchreg:qpttdv3qg2usm4nm7talhxhl05mlhms3ys43u76rn0"
|
|
23
|
+
)
|
|
24
|
+
).not.toHaveLength(0);
|
|
25
|
+
});
|
|
26
|
+
|
|
18
27
|
test("subcribe to address", async () => {
|
|
19
28
|
const provider = getNetworkProvider(Network.REGTEST);
|
|
20
29
|
try {
|
|
21
30
|
await provider.subscribeToAddress(
|
|
22
|
-
"
|
|
31
|
+
"bchreg:qpttdv3qg2usm4nm7talhxhl05mlhms3ys43u76rn0",
|
|
23
32
|
async (data) => {
|
|
24
33
|
expect(data).not.toBe("");
|
|
25
34
|
}
|
|
@@ -36,7 +45,7 @@ describe("Rpc tests", () => {
|
|
|
36
45
|
|
|
37
46
|
try {
|
|
38
47
|
await provider.subscribeToAddress(
|
|
39
|
-
"
|
|
48
|
+
"bchreg:qpttdv3qg2usm4nm7talhxhl05mlhms3ys43u76rn0",
|
|
40
49
|
async (data) => {
|
|
41
50
|
// console.log("First", data);
|
|
42
51
|
expect(data).not.toBe("");
|
|
@@ -45,7 +54,7 @@ describe("Rpc tests", () => {
|
|
|
45
54
|
);
|
|
46
55
|
|
|
47
56
|
await provider.subscribeToAddress(
|
|
48
|
-
"
|
|
57
|
+
"bchreg:qpttdv3qg2usm4nm7talhxhl05mlhms3ys43u76rn0",
|
|
49
58
|
async (data) => {
|
|
50
59
|
// console.log("Second", data);
|
|
51
60
|
expect(data).not.toBe("");
|
|
@@ -71,7 +80,7 @@ describe("Rpc tests", () => {
|
|
|
71
80
|
});
|
|
72
81
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
73
82
|
// we do not trigger the callback upon subscription anymore
|
|
74
|
-
expect(result).toBe(
|
|
83
|
+
expect(result).toBe(true);
|
|
75
84
|
});
|
|
76
85
|
|
|
77
86
|
test("Wait for block timeout", async () => {
|
|
@@ -118,5 +127,5 @@ describe("Rpc tests", () => {
|
|
|
118
127
|
|
|
119
128
|
header = await provider.waitForBlock(height + 2);
|
|
120
129
|
expect(header.height).toBe(height + 2);
|
|
121
|
-
});
|
|
130
|
+
}, 20000);
|
|
122
131
|
});
|