mainnet-js 2.3.15 → 2.4.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.3.15.js → mainnet-2.4.0.js} +15 -5
- package/dist/module/history/electrumTransformer.d.ts +11 -3
- package/dist/module/history/electrumTransformer.d.ts.map +1 -1
- package/dist/module/history/electrumTransformer.js +199 -195
- package/dist/module/history/electrumTransformer.js.map +1 -1
- package/dist/module/history/interface.d.ts +19 -13
- package/dist/module/history/interface.d.ts.map +1 -1
- package/dist/module/interface.d.ts +10 -1
- package/dist/module/interface.d.ts.map +1 -1
- package/dist/module/interface.js.map +1 -1
- package/dist/module/network/ElectrumNetworkProvider.d.ts +8 -6
- package/dist/module/network/ElectrumNetworkProvider.d.ts.map +1 -1
- package/dist/module/network/ElectrumNetworkProvider.js +28 -6
- package/dist/module/network/ElectrumNetworkProvider.js.map +1 -1
- package/dist/module/network/NetworkProvider.d.ts +8 -3
- package/dist/module/network/NetworkProvider.d.ts.map +1 -1
- package/dist/module/util/header.d.ts +3 -0
- package/dist/module/util/header.d.ts.map +1 -0
- package/dist/module/util/header.js +13 -0
- package/dist/module/util/header.js.map +1 -0
- package/dist/module/util/index.d.ts +1 -0
- package/dist/module/util/index.d.ts.map +1 -1
- package/dist/module/util/index.js +1 -0
- package/dist/module/util/index.js.map +1 -1
- package/dist/module/wallet/Wif.d.ts +27 -6
- package/dist/module/wallet/Wif.d.ts.map +1 -1
- package/dist/module/wallet/Wif.js +29 -7
- package/dist/module/wallet/Wif.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/history/electrumTransformer.test.ts +112 -55
- package/src/history/electrumTransformer.ts +279 -284
- package/src/history/interface.ts +19 -13
- package/src/interface.ts +11 -1
- package/src/network/ElectrumNetworkProvider.ts +58 -11
- package/src/network/NetworkProvider.ts +13 -3
- package/src/util/header.test.ts +34 -0
- package/src/util/header.ts +16 -0
- package/src/util/index.ts +1 -0
- package/src/wallet/Wif.ts +55 -21
|
@@ -5,7 +5,13 @@ import {
|
|
|
5
5
|
ConnectionStatus,
|
|
6
6
|
} from "electrum-cash";
|
|
7
7
|
import { default as NetworkProvider } from "./NetworkProvider.js";
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
HexHeaderI,
|
|
10
|
+
TxI,
|
|
11
|
+
UtxoI,
|
|
12
|
+
ElectrumBalanceI,
|
|
13
|
+
HeaderI,
|
|
14
|
+
} from "../interface.js";
|
|
9
15
|
import { Network } from "../interface.js";
|
|
10
16
|
import { delay } from "../util/delay.js";
|
|
11
17
|
import { ElectrumRawTransaction, ElectrumUtxo } from "./interface.js";
|
|
@@ -13,6 +19,7 @@ import { ElectrumRawTransaction, ElectrumUtxo } from "./interface.js";
|
|
|
13
19
|
import { CancelWatchFn } from "../wallet/interface.js";
|
|
14
20
|
import { getTransactionHash } from "../util/transaction.js";
|
|
15
21
|
import { Config } from "../config.js";
|
|
22
|
+
import { decodeHeader } from "../util/header.js";
|
|
16
23
|
|
|
17
24
|
export default class ElectrumNetworkProvider implements NetworkProvider {
|
|
18
25
|
public electrum: ElectrumCluster | ElectrumClient;
|
|
@@ -105,6 +112,35 @@ export default class ElectrumNetworkProvider implements NetworkProvider {
|
|
|
105
112
|
return result.confirmed + result.unconfirmed;
|
|
106
113
|
}
|
|
107
114
|
|
|
115
|
+
static rawHeaderCache = {};
|
|
116
|
+
async getHeader(
|
|
117
|
+
height: number,
|
|
118
|
+
verbose: boolean = false
|
|
119
|
+
): Promise<HeaderI | HexHeaderI> {
|
|
120
|
+
const key = `header-${this.network}-${height}-${verbose}`;
|
|
121
|
+
|
|
122
|
+
if (Config.UseLocalStorageCache) {
|
|
123
|
+
const cached = localStorage.getItem(key);
|
|
124
|
+
if (cached) {
|
|
125
|
+
return verbose ? decodeHeader(JSON.parse(cached)) : JSON.parse(cached);
|
|
126
|
+
}
|
|
127
|
+
} else {
|
|
128
|
+
ElectrumNetworkProvider.rawTransactionCache[key];
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const result = (await this.performRequest(
|
|
132
|
+
"blockchain.header.get",
|
|
133
|
+
height
|
|
134
|
+
)) as HexHeaderI;
|
|
135
|
+
if (Config.UseLocalStorageCache) {
|
|
136
|
+
localStorage.setItem(key, JSON.stringify(result));
|
|
137
|
+
} else {
|
|
138
|
+
ElectrumNetworkProvider.rawTransactionCache[key] = result;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return verbose ? decodeHeader(result) : result;
|
|
142
|
+
}
|
|
143
|
+
|
|
108
144
|
async getBlockHeight(): Promise<number> {
|
|
109
145
|
return ((await this.performRequest("blockchain.headers.get_tip")) as any)
|
|
110
146
|
.height;
|
|
@@ -116,7 +152,7 @@ export default class ElectrumNetworkProvider implements NetworkProvider {
|
|
|
116
152
|
verbose: boolean = false,
|
|
117
153
|
loadInputValues: boolean = false
|
|
118
154
|
): Promise<string> {
|
|
119
|
-
const key =
|
|
155
|
+
const key = `tx-${this.network}-${txHash}-${verbose}-${loadInputValues}`;
|
|
120
156
|
|
|
121
157
|
if (Config.UseLocalStorageCache) {
|
|
122
158
|
const cached = localStorage.getItem(key);
|
|
@@ -219,10 +255,16 @@ export default class ElectrumNetworkProvider implements NetworkProvider {
|
|
|
219
255
|
}
|
|
220
256
|
|
|
221
257
|
// Get transaction history of a given cashaddr
|
|
222
|
-
async getHistory(
|
|
258
|
+
async getHistory(
|
|
259
|
+
cashaddr: string,
|
|
260
|
+
fromHeight: number = 0,
|
|
261
|
+
toHeight: number = -1
|
|
262
|
+
): Promise<TxI[]> {
|
|
223
263
|
const result = (await this.performRequest(
|
|
224
264
|
"blockchain.address.get_history",
|
|
225
|
-
cashaddr
|
|
265
|
+
cashaddr,
|
|
266
|
+
fromHeight,
|
|
267
|
+
toHeight
|
|
226
268
|
)) as TxI[];
|
|
227
269
|
|
|
228
270
|
return result;
|
|
@@ -316,10 +358,13 @@ export default class ElectrumNetworkProvider implements NetworkProvider {
|
|
|
316
358
|
});
|
|
317
359
|
}
|
|
318
360
|
|
|
319
|
-
//
|
|
320
|
-
public watchBlocks(
|
|
321
|
-
|
|
322
|
-
|
|
361
|
+
// watch for block headers and block height, if `skipCurrentHeight` is set, the notification about current block will not arrive
|
|
362
|
+
public watchBlocks(
|
|
363
|
+
callback: (header: HexHeaderI) => void,
|
|
364
|
+
skipCurrentHeight: boolean = true
|
|
365
|
+
): CancelWatchFn {
|
|
366
|
+
let acknowledged = !skipCurrentHeight;
|
|
367
|
+
const waitForBlockCallback = (_header: HexHeaderI | HexHeaderI[]) => {
|
|
323
368
|
if (!acknowledged) {
|
|
324
369
|
acknowledged = true;
|
|
325
370
|
return;
|
|
@@ -336,7 +381,7 @@ export default class ElectrumNetworkProvider implements NetworkProvider {
|
|
|
336
381
|
}
|
|
337
382
|
|
|
338
383
|
// Wait for the next block or a block at given blockchain height.
|
|
339
|
-
public async waitForBlock(height?: number): Promise<
|
|
384
|
+
public async waitForBlock(height?: number): Promise<HexHeaderI> {
|
|
340
385
|
return new Promise(async (resolve) => {
|
|
341
386
|
const cancelWatch = this.watchBlocks(async (header) => {
|
|
342
387
|
if (height === undefined || header.height >= height!) {
|
|
@@ -348,13 +393,15 @@ export default class ElectrumNetworkProvider implements NetworkProvider {
|
|
|
348
393
|
}
|
|
349
394
|
|
|
350
395
|
// subscribe to notifications sent when new block is found, the block header is sent to callback
|
|
351
|
-
async subscribeToHeaders(
|
|
396
|
+
async subscribeToHeaders(
|
|
397
|
+
callback: (header: HexHeaderI) => void
|
|
398
|
+
): Promise<void> {
|
|
352
399
|
await this.subscribeRequest("blockchain.headers.subscribe", callback);
|
|
353
400
|
}
|
|
354
401
|
|
|
355
402
|
// unsubscribe to notifications sent when new block is found
|
|
356
403
|
async unsubscribeFromHeaders(
|
|
357
|
-
callback: (header:
|
|
404
|
+
callback: (header: HexHeaderI) => void
|
|
358
405
|
): Promise<void> {
|
|
359
406
|
await this.unsubscribeRequest("blockchain.headers.subscribe", callback);
|
|
360
407
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { TxI, UtxoI, Network, HeaderI } from "../interface.js";
|
|
1
|
+
import { TxI, UtxoI, Network, HexHeaderI, HeaderI } from "../interface.js";
|
|
2
2
|
|
|
3
3
|
export default interface NetworkProvider {
|
|
4
4
|
/**
|
|
@@ -20,6 +20,12 @@ export default interface NetworkProvider {
|
|
|
20
20
|
*/
|
|
21
21
|
getBalance(cashaddr: string): Promise<number>;
|
|
22
22
|
|
|
23
|
+
/**
|
|
24
|
+
* @returns The block header fetched at blockheight @param height.
|
|
25
|
+
* @param verbose steers the response type. If true, a verbose response is returned.
|
|
26
|
+
*/
|
|
27
|
+
getHeader(height: number, verbose: boolean): Promise<HeaderI | HexHeaderI>;
|
|
28
|
+
|
|
23
29
|
/**
|
|
24
30
|
* @returns The current block height.
|
|
25
31
|
*/
|
|
@@ -65,14 +71,18 @@ export default interface NetworkProvider {
|
|
|
65
71
|
* @throws {Error} When failing to get history.
|
|
66
72
|
* @returns Array of transactions.
|
|
67
73
|
*/
|
|
68
|
-
getHistory(
|
|
74
|
+
getHistory(
|
|
75
|
+
cashaddr: string,
|
|
76
|
+
fromHeight?: number,
|
|
77
|
+
toHeight?: number
|
|
78
|
+
): Promise<TxI[]>;
|
|
69
79
|
|
|
70
80
|
/**
|
|
71
81
|
* Wait for the next block or a block at given blockchain height.
|
|
72
82
|
* @param height If specified, waits for blockchain to reach this height.
|
|
73
83
|
* @returns Block header.
|
|
74
84
|
*/
|
|
75
|
-
waitForBlock(height?: number): Promise<
|
|
85
|
+
waitForBlock(height?: number): Promise<HexHeaderI>;
|
|
76
86
|
|
|
77
87
|
/**
|
|
78
88
|
* Subscribe to the address change events
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { HeaderI, HexHeaderI } from "../interface";
|
|
2
|
+
import { disconnectProviders, initProviders } from "../network";
|
|
3
|
+
import { Wallet } from "../wallet/Wif";
|
|
4
|
+
|
|
5
|
+
beforeAll(async () => {
|
|
6
|
+
await initProviders();
|
|
7
|
+
});
|
|
8
|
+
afterAll(async () => {
|
|
9
|
+
await disconnectProviders();
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
describe("header tests", () => {
|
|
13
|
+
it("decodeHeader", async () => {
|
|
14
|
+
const wallet = await Wallet.newRandom();
|
|
15
|
+
const hexHeader = (await wallet.provider!.getHeader(854724)) as HexHeaderI;
|
|
16
|
+
expect(hexHeader.height).toBe(854724);
|
|
17
|
+
expect(hexHeader.hex).toBe(
|
|
18
|
+
"0080c4339674a81d4e35a5b590b15a6b69f93b7b22bd14845b3517000000000000000000128a8b776c82fda87f60c6fdb0de26f021cdf39ffd835dc309eb1fc6bbfaac343e2f96662d5202184db2428f"
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
const header = (await wallet.provider!.getHeader(854724, true)) as HeaderI;
|
|
22
|
+
expect(header.version).toBe(868515840);
|
|
23
|
+
expect(header.previousBlockHash).toBe(
|
|
24
|
+
"00000000000000000017355b8414bd227b3bf9696b5ab190b5a5354e1da87496"
|
|
25
|
+
);
|
|
26
|
+
expect(header.merkleRoot).toBe(
|
|
27
|
+
"34acfabbc61feb09c35d83fd9ff3cd21f026deb0fdc6607fa8fd826c778b8a12"
|
|
28
|
+
);
|
|
29
|
+
expect(header.timestamp).toBe(1721118526);
|
|
30
|
+
expect(header.bits).toBe(402805293);
|
|
31
|
+
expect(header.nonce).toBe(2403512909);
|
|
32
|
+
expect(header.height).toBe(854724);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { HeaderI, HexHeaderI } from "../interface";
|
|
2
|
+
|
|
3
|
+
export const decodeHeader = (hexHeader: HexHeaderI): HeaderI => {
|
|
4
|
+
const result = {} as HeaderI;
|
|
5
|
+
|
|
6
|
+
const header = Buffer.from(hexHeader.hex, "hex");
|
|
7
|
+
result.version = header.readUInt32LE(0);
|
|
8
|
+
result.previousBlockHash = header.subarray(4, 36).reverse().toString("hex");
|
|
9
|
+
result.merkleRoot = header.subarray(36, 68).reverse().toString("hex");
|
|
10
|
+
result.timestamp = header.readUInt32LE(68);
|
|
11
|
+
result.bits = header.readUInt32LE(72);
|
|
12
|
+
result.nonce = header.readUInt32LE(76);
|
|
13
|
+
result.height = hexHeader.height;
|
|
14
|
+
|
|
15
|
+
return result;
|
|
16
|
+
};
|
package/src/util/index.ts
CHANGED
package/src/wallet/Wif.ts
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
// Stable
|
|
3
3
|
import {
|
|
4
4
|
decodeCashAddress,
|
|
5
|
-
decodeCashAddressVersionByte,
|
|
6
5
|
encodeHdPublicKey,
|
|
7
6
|
HdKeyNetwork,
|
|
8
7
|
secp256k1,
|
|
@@ -25,7 +24,7 @@ import {
|
|
|
25
24
|
import { mnemonicToSeedSync, generateMnemonic } from "@scure/bip39";
|
|
26
25
|
import { NetworkType, prefixFromNetworkMap, UnitEnum } from "../enum.js";
|
|
27
26
|
|
|
28
|
-
import { Network,
|
|
27
|
+
import { Network, HexHeaderI, TxI, NFTCapability } from "../interface.js";
|
|
29
28
|
|
|
30
29
|
import { networkPrefixMap } from "../enum.js";
|
|
31
30
|
import { PrivateKeyI, UtxoI } from "../interface.js";
|
|
@@ -104,14 +103,14 @@ import { amountInSatoshi } from "../util/amountInSatoshi.js";
|
|
|
104
103
|
import { getXPubKey } from "../util/getXPubKey.js";
|
|
105
104
|
import { DERIVATION_PATHS, DUST_UTXO_THRESHOLD } from "../constant.js";
|
|
106
105
|
|
|
107
|
-
import { TransactionHistoryI } from "../history/interface.js";
|
|
108
106
|
import { getAddressHistory } from "../history/electrumTransformer.js";
|
|
109
|
-
import { IdentitySnapshot
|
|
107
|
+
import { IdentitySnapshot } from "./bcmr-v2.schema.js";
|
|
110
108
|
import { BCMR } from "./Bcmr.js";
|
|
111
109
|
import { qrAddress } from "../qr/Qr.js";
|
|
112
110
|
import { ImageI } from "../qr/interface.js";
|
|
113
111
|
import { Config } from "../config.js";
|
|
114
112
|
import { checkUtxos } from "../util/checkUtxos.js";
|
|
113
|
+
import { TransactionHistoryItem } from "../history/interface.js";
|
|
115
114
|
|
|
116
115
|
//#endregion Imports
|
|
117
116
|
|
|
@@ -1282,25 +1281,53 @@ export class Wallet extends BaseWallet {
|
|
|
1282
1281
|
}
|
|
1283
1282
|
|
|
1284
1283
|
// gets transaction history of this wallet
|
|
1285
|
-
public async getRawHistory(
|
|
1286
|
-
|
|
1284
|
+
public async getRawHistory(
|
|
1285
|
+
fromHeight: number = 0,
|
|
1286
|
+
toHeight: number = -1
|
|
1287
|
+
): Promise<TxI[]> {
|
|
1288
|
+
return await this.provider!.getHistory(
|
|
1289
|
+
this.cashaddr!,
|
|
1290
|
+
fromHeight,
|
|
1291
|
+
toHeight
|
|
1292
|
+
);
|
|
1287
1293
|
}
|
|
1288
1294
|
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1295
|
+
/**
|
|
1296
|
+
* getHistory gets transaction history of this wallet with most data decoded and ready to present to user
|
|
1297
|
+
* @note balance calculations are valid only if querying to the blockchain tip (`toHeight` === -1, `count` === -1)
|
|
1298
|
+
* @note this method is heavy on network calls, if invoked in browser use of cache is advised, @see `Config.UseLocalStorageCache`
|
|
1299
|
+
* @note this method tries to recreate the history tab view of Electron Cash wallet, however, it may not be 100% accurate if the tnransaction value changes are the same in the same block (ordering)
|
|
1300
|
+
*
|
|
1301
|
+
* @param unit optional, BCH or currency unit to present balance and balance changes. If unit is currency like USD or EUR, balances will be subject to possible rounding errors. Default 0
|
|
1302
|
+
* @param fromHeight optional, if set, history will be limited. Default 0
|
|
1303
|
+
* @param toHeight optional, if set, history will be limited. Default -1, meaning that all history items will be returned, including mempool
|
|
1304
|
+
* @param start optional, if set, the result set will be paginated with offset `start`
|
|
1305
|
+
* @param count optional, if set, the result set will be paginated with `count`. Default -1, meaning that all history items will be returned
|
|
1306
|
+
*
|
|
1307
|
+
* @returns an array of transaction history items, with input values and addresses encoded in cashaddress format. @see `TransactionHistoryItem` type
|
|
1308
|
+
*/
|
|
1309
|
+
public async getHistory({
|
|
1310
|
+
unit = "sat",
|
|
1311
|
+
fromHeight = 0,
|
|
1312
|
+
toHeight = -1,
|
|
1313
|
+
start = 0,
|
|
1314
|
+
count = -1,
|
|
1315
|
+
}: {
|
|
1316
|
+
unit?: UnitEnum;
|
|
1317
|
+
fromHeight?: number;
|
|
1318
|
+
toHeight?: number;
|
|
1319
|
+
start?: number;
|
|
1320
|
+
count?: number;
|
|
1321
|
+
}): Promise<TransactionHistoryItem[]> {
|
|
1322
|
+
return getAddressHistory({
|
|
1323
|
+
address: this.cashaddr!,
|
|
1324
|
+
provider: this.provider!,
|
|
1299
1325
|
unit,
|
|
1326
|
+
fromHeight,
|
|
1327
|
+
toHeight,
|
|
1300
1328
|
start,
|
|
1301
1329
|
count,
|
|
1302
|
-
|
|
1303
|
-
);
|
|
1330
|
+
});
|
|
1304
1331
|
}
|
|
1305
1332
|
|
|
1306
1333
|
// gets last transaction of this wallet
|
|
@@ -1393,11 +1420,18 @@ export class Wallet extends BaseWallet {
|
|
|
1393
1420
|
* watchBlocks Watch network blocks
|
|
1394
1421
|
*
|
|
1395
1422
|
* @param callback callback with a block header object
|
|
1423
|
+
* @param skipCurrentHeight if set, the notification about current block will not arrive
|
|
1396
1424
|
*
|
|
1397
1425
|
* @returns a function which will cancel watching upon evaluation
|
|
1398
1426
|
*/
|
|
1399
|
-
public watchBlocks(
|
|
1400
|
-
|
|
1427
|
+
public watchBlocks(
|
|
1428
|
+
callback: (header: HexHeaderI) => void,
|
|
1429
|
+
skipCurrentHeight: boolean = true
|
|
1430
|
+
): CancelWatchFn {
|
|
1431
|
+
return (this.provider! as ElectrumNetworkProvider).watchBlocks(
|
|
1432
|
+
callback,
|
|
1433
|
+
skipCurrentHeight
|
|
1434
|
+
);
|
|
1401
1435
|
}
|
|
1402
1436
|
|
|
1403
1437
|
/**
|
|
@@ -1406,7 +1440,7 @@ export class Wallet extends BaseWallet {
|
|
|
1406
1440
|
* @param height if specified waits for this exact blockchain height, otherwise resolves with the next block
|
|
1407
1441
|
*
|
|
1408
1442
|
*/
|
|
1409
|
-
public async waitForBlock(height?: number): Promise<
|
|
1443
|
+
public async waitForBlock(height?: number): Promise<HexHeaderI> {
|
|
1410
1444
|
return (this.provider! as ElectrumNetworkProvider).waitForBlock(height);
|
|
1411
1445
|
}
|
|
1412
1446
|
//#endregion Funds
|