mainnet-js 3.1.7 → 4.0.0-next.2

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.
Files changed (83) hide show
  1. package/dist/index.html +1 -1
  2. package/dist/{mainnet-3.1.7.js → mainnet-4.0.0-next.2.js} +66 -166
  3. package/dist/module/cache/walletCache.d.ts +16 -6
  4. package/dist/module/cache/walletCache.d.ts.map +1 -1
  5. package/dist/module/cache/walletCache.js +92 -34
  6. package/dist/module/cache/walletCache.js.map +1 -1
  7. package/dist/module/mine/mine.d.ts.map +1 -1
  8. package/dist/module/mine/mine.js +14 -19
  9. package/dist/module/mine/mine.js.map +1 -1
  10. package/dist/module/network/Connection.d.ts +1 -12
  11. package/dist/module/network/Connection.d.ts.map +1 -1
  12. package/dist/module/network/Connection.js +12 -33
  13. package/dist/module/network/Connection.js.map +1 -1
  14. package/dist/module/network/ElectrumNetworkProvider.d.ts +4 -7
  15. package/dist/module/network/ElectrumNetworkProvider.d.ts.map +1 -1
  16. package/dist/module/network/ElectrumNetworkProvider.js +43 -70
  17. package/dist/module/network/ElectrumNetworkProvider.js.map +1 -1
  18. package/dist/module/network/configuration.d.ts +2 -4
  19. package/dist/module/network/configuration.d.ts.map +1 -1
  20. package/dist/module/network/configuration.js +25 -50
  21. package/dist/module/network/configuration.js.map +1 -1
  22. package/dist/module/network/constant.d.ts +7 -7
  23. package/dist/module/network/constant.d.ts.map +1 -1
  24. package/dist/module/network/constant.js +20 -24
  25. package/dist/module/network/constant.js.map +1 -1
  26. package/dist/module/network/default.d.ts +3 -2
  27. package/dist/module/network/default.d.ts.map +1 -1
  28. package/dist/module/network/default.js +19 -51
  29. package/dist/module/network/default.js.map +1 -1
  30. package/dist/module/network/index.d.ts +2 -2
  31. package/dist/module/network/index.d.ts.map +1 -1
  32. package/dist/module/network/index.js +2 -2
  33. package/dist/module/network/index.js.map +1 -1
  34. package/dist/module/network/interface.d.ts +0 -6
  35. package/dist/module/network/interface.d.ts.map +1 -1
  36. package/dist/module/wallet/Base.d.ts.map +1 -1
  37. package/dist/module/wallet/Base.js +33 -12
  38. package/dist/module/wallet/Base.js.map +1 -1
  39. package/dist/module/wallet/HDWallet.d.ts.map +1 -1
  40. package/dist/module/wallet/HDWallet.js +16 -35
  41. package/dist/module/wallet/HDWallet.js.map +1 -1
  42. package/dist/module/wallet/Watch.d.ts +22 -1
  43. package/dist/module/wallet/Watch.d.ts.map +1 -1
  44. package/dist/module/wallet/Watch.js +137 -6
  45. package/dist/module/wallet/Watch.js.map +1 -1
  46. package/dist/module/wallet/Wif.d.ts +1 -1
  47. package/dist/module/wallet/Wif.d.ts.map +1 -1
  48. package/dist/module/wallet/Wif.js +0 -4
  49. package/dist/module/wallet/Wif.js.map +1 -1
  50. package/dist/tsconfig.tsbuildinfo +1 -1
  51. package/package.json +5 -3
  52. package/src/cache/walletCache.ts +122 -57
  53. package/src/mine/mine.ts +18 -22
  54. package/src/network/Connection.test.ts +8 -7
  55. package/src/network/Connection.ts +16 -42
  56. package/src/network/ElectrumNetworkProvider.ts +54 -88
  57. package/src/network/Rpc.test.ts +6 -5
  58. package/src/network/configuration.test.ts +23 -25
  59. package/src/network/configuration.ts +29 -55
  60. package/src/network/constant.ts +20 -25
  61. package/src/network/default.ts +25 -87
  62. package/src/network/electrum.test.ts +47 -11
  63. package/src/network/index.ts +7 -2
  64. package/src/network/interface.ts +0 -7
  65. package/src/network/subscription.test.ts +268 -0
  66. package/src/wallet/Base.ts +39 -17
  67. package/src/wallet/Cashtokens.test.headless.js +6 -0
  68. package/src/wallet/Cashtokens.test.ts +13 -0
  69. package/src/wallet/HDWallet.test.ts +4 -4
  70. package/src/wallet/HDWallet.ts +19 -35
  71. package/src/wallet/WalletCache.test.ts +6 -2
  72. package/src/wallet/Watch.ts +199 -7
  73. package/src/wallet/Wif.test.ts +6 -0
  74. package/src/wallet/Wif.ts +2 -9
  75. package/tsconfig.browser.json +10 -1
  76. package/tsconfig.json +12 -1
  77. package/webpack.config.cjs +1 -0
  78. package/dist/module/network/util.d.ts +0 -3
  79. package/dist/module/network/util.d.ts.map +0 -1
  80. package/dist/module/network/util.js +0 -27
  81. package/dist/module/network/util.js.map +0 -1
  82. package/src/network/util.test.ts +0 -24
  83. package/src/network/util.ts +0 -30
@@ -1,4 +1,5 @@
1
1
  import { Network } from "../interface";
2
+ import { Wallet } from "../wallet/Wif";
2
3
  import * as config from "./configuration";
3
4
  import * as primary from "./constant";
4
5
 
@@ -15,11 +16,11 @@ test("Should get electrum settings from defaults", async () => {
15
16
  });
16
17
 
17
18
  test("Should get electrum settings from DefaultProvider", async () => {
18
- config.DefaultProvider.servers.mainnet = ["wss://example.com:777"];
19
+ config.DefaultProvider.servers.mainnet = "wss://example.com:777";
19
20
 
20
- expect(config.getDefaultServers(Network.MAINNET)).toStrictEqual([
21
- "wss://example.com:777",
22
- ]);
21
+ expect(config.getDefaultServers(Network.MAINNET)).toBe(
22
+ "wss://example.com:777"
23
+ );
23
24
  expect(config.getDefaultServers(Network.TESTNET)).toBe(
24
25
  primary.testnetServers
25
26
  );
@@ -27,33 +28,30 @@ test("Should get electrum settings from DefaultProvider", async () => {
27
28
  primary.regtestServers
28
29
  );
29
30
 
30
- config.DefaultProvider.servers.mainnet = [];
31
+ config.DefaultProvider.servers.mainnet = "";
31
32
  });
32
33
 
33
34
  test("Should get electrum settings from env", async () => {
34
- process.env.ELECTRUM = "https://example.com:1234";
35
+ process.env.ELECTRUM = "wss://example.com:1234";
35
36
  process.env.ELECTRUM_TESTNET =
36
- "https://test.example.com:1234,https://test.example.dk:1234";
37
+ "fallback(wss://test.example.com:1234,wss://test.example.dk:1234)";
37
38
  process.env.ELECTRUM_REGTEST = "ws://reg.example.com:1234";
38
- expect(config.getDefaultServers(Network.MAINNET)).toStrictEqual([
39
- "https://example.com:1234",
40
- ]);
41
- expect(config.getDefaultServers(Network.TESTNET)).toStrictEqual([
42
- "https://test.example.com:1234",
43
- "https://test.example.dk:1234",
44
- ]);
45
- expect(config.getDefaultServers(Network.REGTEST)).toStrictEqual([
46
- "ws://reg.example.com:1234",
47
- ]);
39
+ expect(config.getDefaultServers(Network.MAINNET)).toBe(
40
+ "wss://example.com:1234"
41
+ );
42
+ expect(config.getDefaultServers(Network.TESTNET)).toBe(
43
+ "fallback(wss://test.example.com:1234,wss://test.example.dk:1234)"
44
+ );
45
+ expect(config.getDefaultServers(Network.REGTEST)).toBe(
46
+ "ws://reg.example.com:1234"
47
+ );
48
48
  });
49
49
 
50
- test("Should get electrum cluster confidence from defaults", async () => {
51
- let c = config.getConfidence();
52
- expect(c).toStrictEqual(1);
53
- });
50
+ test("Should get electrum settings from env, comma separated", async () => {
51
+ process.env.ELECTRUM =
52
+ "wss://bch.imaginary.cash:50004,wss://electrum.imaginary.cash:50004";
54
53
 
55
- test("Should get electrum cluster confidence from env", async () => {
56
- process.env.ELECTRUM_CONFIDENCE = "2";
57
- let c = config.getConfidence();
58
- expect(c).toStrictEqual(2);
54
+ const wallet = await Wallet.newRandom();
55
+ expect(await wallet.getBalance()).toBe(0n);
56
+ await wallet.provider!.disconnect();
59
57
  });
@@ -2,19 +2,24 @@ import { Network } from "../interface.js";
2
2
  import { getRuntimePlatform } from "../util/index.js";
3
3
  import * as primary from "./constant.js";
4
4
 
5
- let mainnetServers: string[],
6
- testnetServers: string[],
7
- regtestServers: string[];
8
-
9
5
  export class DefaultProvider {
10
- static servers: { [name: string]: string[] } = {
11
- mainnet: [] as string[],
12
- testnet: [] as string[],
13
- regtest: [] as string[],
6
+ static servers: { [name: string]: string } = {
7
+ mainnet: "",
8
+ testnet: "",
9
+ regtest: "",
14
10
  };
15
11
  }
16
12
 
17
- export function getDefaultServers(network: Network) {
13
+ // Detect plain comma-separated URLs (not already in parse notation like "fallback(...)") and convert
14
+ function normalizeServers(value: string): string {
15
+ if (!value) return value;
16
+ // Already parse notation (contains parens) or a single URL — pass through
17
+ if (value.includes("(") || !value.includes(",")) return value;
18
+ // Plain comma-separated URLs: convert to parse notation with fallback
19
+ return primary.toParseNotation(value.split(",").map((s) => s.trim()));
20
+ }
21
+
22
+ export function getDefaultServers(network: Network): string {
18
23
  let env: any;
19
24
  if (getRuntimePlatform() == "node") {
20
25
  env = process.env;
@@ -22,51 +27,20 @@ export function getDefaultServers(network: Network) {
22
27
  env = {};
23
28
  }
24
29
 
25
- mainnetServers = DefaultProvider.servers.mainnet.length
26
- ? DefaultProvider.servers.mainnet
27
- : env.ELECTRUM
28
- ? env.ELECTRUM.split(",")
29
- : primary.mainnetServers;
30
- testnetServers = DefaultProvider.servers.testnet.length
31
- ? DefaultProvider.servers.testnet
32
- : env.ELECTRUM_TESTNET
33
- ? env.ELECTRUM_TESTNET.split(",")
34
- : primary.testnetServers;
35
- regtestServers = DefaultProvider.servers.regtest.length
36
- ? DefaultProvider.servers.regtest
37
- : env.ELECTRUM_REGTEST
38
- ? env.ELECTRUM_REGTEST.split(",")
39
- : primary.regtestServers;
40
-
41
- return {
42
- mainnet: mainnetServers,
43
- testnet: testnetServers,
44
- regtest: regtestServers,
45
- }[network];
46
- }
47
-
48
- export function getUserAgent() {
49
- // Allow users to configure the cluster confidence
50
- let ua;
51
- if (getRuntimePlatform() === "node") {
52
- ua = process.env.ELECTRUM_USER_AGENT
53
- ? process.env.ELECTRUM_USER_AGENT
54
- : "mainnet-js-" + getRuntimePlatform();
55
- } else {
56
- ua = "mainnet-js-" + getRuntimePlatform();
57
- }
58
- return ua;
59
- }
30
+ const servers = {
31
+ mainnet:
32
+ DefaultProvider.servers.mainnet ||
33
+ normalizeServers(env.ELECTRUM) ||
34
+ primary.mainnetServers,
35
+ testnet:
36
+ DefaultProvider.servers.testnet ||
37
+ normalizeServers(env.ELECTRUM_TESTNET) ||
38
+ primary.testnetServers,
39
+ regtest:
40
+ DefaultProvider.servers.regtest ||
41
+ normalizeServers(env.ELECTRUM_REGTEST) ||
42
+ primary.regtestServers,
43
+ };
60
44
 
61
- export function getConfidence() {
62
- // Allow users to configure the cluster confidence
63
- let confidence;
64
- if (getRuntimePlatform() === "node") {
65
- confidence = process.env.ELECTRUM_CONFIDENCE
66
- ? parseInt(process.env.ELECTRUM_CONFIDENCE)
67
- : 1;
68
- } else {
69
- confidence = 1;
70
- }
71
- return confidence;
45
+ return servers[network];
72
46
  }
@@ -1,40 +1,35 @@
1
- export const ELECTRUM_CASH_PROTOCOL_VERSION = "1.5";
2
-
3
1
  export const networkTickerMap = {
4
2
  mainnet: "BCH",
5
3
  testnet: "tBCH",
6
4
  regtest: "rBCH",
7
5
  };
8
6
 
9
- export const mainnetServers = [
10
- // "wss://bch.imaginary.cash:50004",
11
- "wss://blackie.c3-soft.com:50004",
12
- // "wss://electrum.imaginary.cash:50004",
13
- // "wss://fulcrum.fountainhead.cash",
14
- ];
7
+ const opts =
8
+ "connectTimeout=5000&timeout=5000&keepAlive=60000&protocolVersion=1.6&batchSize=5";
15
9
 
16
- // export const testnetServers = [
17
- // // "wss://tbch.loping.net:60004",
18
- // "wss://blackie.c3-soft.com:60004",
19
- // // "wss://testnet.bitcoincash.network:60004",
20
- // //,"wss://unavailable.invalid:50004"
21
- // ];
10
+ export function toParseNotation(urls: string[]): string {
11
+ const withOpts = urls.map((u) => `${u}?${opts}`);
12
+ if (withOpts.length === 1) return withOpts[0];
13
+ return `fallback(${withOpts.join(",")})?eagerConnect=true&rank=true`;
14
+ }
22
15
 
23
- // testnet4
24
- // export const testnetServers = [
25
- // //"wss://t4fork.c3-soft.com:61004",
26
- // "wss://testnet4.imaginary.cash:50004",
27
- // //,"wss://unavailable.invalid:50004"
28
- // ];
16
+ export const mainnetServers = toParseNotation([
17
+ "wss://bch.imaginary.cash:50004",
18
+ "wss://electrum.imaginary.cash:50004",
19
+ "wss://fulcrum.pat.mn:50004",
20
+ ]);
29
21
 
30
22
  // chipnet
31
- export const testnetServers = [
23
+ export const testnetServers = toParseNotation([
24
+ "wss://chipnet.bch.ninja:50004",
32
25
  "wss://chipnet.imaginary.cash:50004",
33
- //"wss://blackie.c3-soft.com:64004", // chipnet with protocol 1.5.0
34
- // "wss://chipnet.bch.ninja:50004",
35
- ];
26
+ "wss://chipnet.c3-soft.com:64004",
27
+ ]);
36
28
 
37
- export const regtestServers = ["ws://127.0.0.1:60003"];
29
+ export const regtestServers = toParseNotation([
30
+ "ws://127.0.0.1:60003",
31
+ "ws://host.docker.internal:60003",
32
+ ]);
38
33
 
39
34
  export const defaultServers = {
40
35
  mainnet: mainnetServers,
@@ -1,15 +1,14 @@
1
1
  import { default as ElectrumNetworkProvider } from "./ElectrumNetworkProvider.js";
2
- import { ElectrumClient } from "@electrum-cash/network";
3
- import { ElectrumWebSocket } from "@electrum-cash/web-socket";
4
2
  import { default as NetworkProvider } from "./NetworkProvider.js";
5
- import { getDefaultServers, getUserAgent } from "./configuration.js";
6
- import { parseElectrumUrl } from "./util.js";
7
- import { ElectrumHostParams } from "./interface.js";
3
+ import { getDefaultServers } from "./configuration.js";
8
4
  import { Network } from "../interface.js";
9
- import {
10
- networkTickerMap,
11
- ELECTRUM_CASH_PROTOCOL_VERSION,
12
- } from "./constant.js";
5
+ import { networkTickerMap } from "./constant.js";
6
+ import type { ElectrumCashSchema } from "@rpckit/core/electrum-cash";
7
+ import { createParseSync } from "@rpckit/core";
8
+ import { webSocket } from "@rpckit/websocket/electrum-cash";
9
+ import { fallback } from "@rpckit/fallback/electrum-cash";
10
+
11
+ const parseSync = createParseSync({ webSocket, fallback });
13
12
 
14
13
  export function setGlobalProvider(
15
14
  network: Network,
@@ -34,87 +33,26 @@ export function removeGlobalProvider(network: Network): void {
34
33
  }
35
34
  }
36
35
 
37
- export function getNetworkProvider(
36
+ export async function createProvider(
38
37
  network: Network = Network.MAINNET,
39
- servers?: string[] | string,
40
- manualConnectionManagement?: boolean,
41
- options?: ElectrumHostParams
42
- ): NetworkProvider {
43
- const globalContext =
44
- servers === undefined &&
45
- manualConnectionManagement === undefined &&
46
- options === undefined;
47
- if (globalContext) {
48
- const globalProvider = getGlobalProvider(network);
49
- if (globalProvider) {
50
- return globalProvider;
51
- }
52
- }
53
-
54
- manualConnectionManagement = manualConnectionManagement
55
- ? manualConnectionManagement
56
- : false;
57
- servers = servers ? servers : getDefaultServers(network);
58
- // If the user has passed a single string, assume a single client connection
59
- if (typeof servers === "string") {
60
- servers = [servers as string];
61
- }
62
-
63
- // There were server(s)
64
- if (servers) {
65
- const client = getClient(servers[0], network, options);
66
- let provider = new ElectrumNetworkProvider(
67
- client,
68
- network,
69
- manualConnectionManagement
70
- );
71
-
72
- if (globalContext) {
73
- return setGlobalProvider(network, provider);
74
- }
75
-
76
- return provider;
77
- } else {
78
- throw Error("No servers provided, defaults not available.");
79
- }
80
- }
81
-
82
- // create a client with a server
83
- function getClient(
84
- server: string,
85
- network: Network,
86
- options?: ElectrumHostParams
87
- ) {
88
- let url = parseElectrumUrl(server);
89
- return getElectrumClient(url, options?.timeout ?? 120000, network);
38
+ servers?: string
39
+ ): Promise<ElectrumNetworkProvider> {
40
+ const serverStr = servers ?? getDefaultServers(network);
41
+ const transport = parseSync<ElectrumCashSchema>(serverStr);
42
+ return new ElectrumNetworkProvider(transport, network);
90
43
  }
91
44
 
92
- function getElectrumClient(
93
- params: ElectrumHostParams,
94
- timeout: number,
95
- network: Network
96
- ) {
97
- if (params.scheme?.includes("tcp")) {
98
- throw Error("TCP connections are not supported.");
45
+ export function getNetworkProvider(
46
+ network: Network = Network.MAINNET
47
+ ): NetworkProvider {
48
+ const globalProvider = getGlobalProvider(network);
49
+ if (globalProvider) {
50
+ return globalProvider;
99
51
  }
100
52
 
101
- const webSocket = new ElectrumWebSocket(
102
- params.host,
103
- params.port,
104
- params.scheme === "wss",
105
- timeout,
106
- {
107
- disableBrowserConnectivityHandling: true,
108
- disableBrowserVisibilityHandling: true,
109
- }
110
- );
111
- return new ElectrumClient(
112
- getUserAgent(),
113
- ELECTRUM_CASH_PROTOCOL_VERSION,
114
- webSocket,
115
- {
116
- disableBrowserConnectivityHandling: true,
117
- disableBrowserVisibilityHandling: true,
118
- }
119
- );
53
+ const serverStr = getDefaultServers(network);
54
+ const transport = parseSync<ElectrumCashSchema>(serverStr);
55
+ const provider = new ElectrumNetworkProvider(transport, network);
56
+ setGlobalProvider(network, provider);
57
+ return provider;
120
58
  }
@@ -1,21 +1,19 @@
1
- import { ElectrumClient } from "@electrum-cash/network";
2
- import { getNetworkProvider } from ".";
1
+ import { webSocket } from "@rpckit/websocket/electrum-cash";
2
+ import { getNetworkProvider, createProvider } from ".";
3
3
  import { Network } from "../interface";
4
4
 
5
- test("Should get a transaction with bare electrum", async () => {
6
- const electrum = new ElectrumClient(
7
- "Electrum client example",
8
- "1.4.1",
9
- "bch.imaginary.cash"
10
- );
11
- await electrum.connect();
5
+ test("Should get a transaction with bare rpckit transport", async () => {
6
+ const transport = webSocket("wss://fulcrum.pat.mn:50004");
7
+ await transport.connect();
12
8
  const transactionID =
13
9
  "4db095f34d632a4daf942142c291f1f2abb5ba2e1ccac919d85bdc2f671fb251";
14
- const transactionHex = await electrum.request(
10
+ const transactionHex = await transport.request(
15
11
  "blockchain.transaction.get",
16
12
  transactionID
17
13
  );
18
- await electrum.disconnect();
14
+ expect(typeof transactionHex).toBe("string");
15
+ expect((transactionHex as string).length).toBeGreaterThan(0);
16
+ await transport.close();
19
17
  });
20
18
 
21
19
  test("Should get a transaction with provider", async () => {
@@ -26,3 +24,41 @@ test("Should get a transaction with provider", async () => {
26
24
  //console.log(transactionHex);
27
25
  await provider.disconnect();
28
26
  });
27
+
28
+ test("Should propagate electrum error for non-existent transaction", async () => {
29
+ const zeroTxId =
30
+ "0000000000000000000000000000000000000000000000000000000000000000";
31
+
32
+ // rpckit rejects with a plain object { code, message }, not an Error instance
33
+ const transport = webSocket("wss://fulcrum.pat.mn:50004");
34
+ await transport.connect();
35
+ try {
36
+ await transport.request("blockchain.transaction.get", zeroTxId);
37
+ fail("Expected request to throw");
38
+ } catch (error: any) {
39
+ expect(error.message).toContain(
40
+ "No such mempool or blockchain transaction"
41
+ );
42
+ } finally {
43
+ await transport.close();
44
+ }
45
+ });
46
+
47
+ test("Should throw user-friendly error for non-existent transaction via provider", async () => {
48
+ const zeroTxId =
49
+ "0000000000000000000000000000000000000000000000000000000000000000";
50
+ const provider = await createProvider(
51
+ Network.MAINNET,
52
+ "wss://fulcrum.pat.mn:50004"
53
+ );
54
+ try {
55
+ await provider.getRawTransaction(zeroTxId);
56
+ fail("Expected getRawTransaction to throw");
57
+ } catch (error: any) {
58
+ expect(error).toBeInstanceOf(Error);
59
+ expect(error.message).toContain("Could not decode transaction");
60
+ expect(error.message).toContain("might not exist");
61
+ } finally {
62
+ await provider.disconnect();
63
+ }
64
+ });
@@ -1,6 +1,11 @@
1
- export { getNetworkProvider } from "./default.js";
2
1
  export {
3
- Connection,
2
+ getNetworkProvider,
3
+ createProvider,
4
+ setGlobalProvider,
5
+ getGlobalProvider,
6
+ removeGlobalProvider,
7
+ } from "./default.js";
8
+ export {
4
9
  initProviders,
5
10
  initProvider,
6
11
  disconnectProviders,
@@ -5,13 +5,6 @@ export interface BlockHeader {
5
5
  hex: string;
6
6
  }
7
7
 
8
- export interface ElectrumHostParams {
9
- host: string;
10
- port: number;
11
- timeout?: number;
12
- scheme: "tcp" | "tcp_tls" | "ws" | "wss";
13
- }
14
-
15
8
  export interface ElectrumTokenData {
16
9
  amount: string;
17
10
  category: string;