@buildonspark/spark-sdk 0.3.5 → 0.3.7

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 (113) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/bare/index.cjs +4079 -4662
  3. package/dist/bare/index.d.cts +689 -89
  4. package/dist/bare/index.d.ts +689 -89
  5. package/dist/bare/index.js +5565 -5972
  6. package/dist/{chunk-JE73HB26.js → chunk-KDEVNW7C.js} +12671 -13161
  7. package/dist/chunk-P4HYYSMU.js +7 -0
  8. package/dist/chunk-SRPKOCG4.js +139 -0
  9. package/dist/chunk-UYTT3C6H.js +605 -0
  10. package/dist/{client-DWml6sjL.d.cts → client-Bcb7TUIp.d.cts} +12 -10
  11. package/dist/{client-DBZ43pJT.d.ts → client-D9T58OY8.d.ts} +12 -10
  12. package/dist/debug.cjs +9248 -9782
  13. package/dist/debug.d.cts +8 -8
  14. package/dist/debug.d.ts +8 -8
  15. package/dist/debug.js +5 -3
  16. package/dist/graphql/objects/index.d.cts +3 -3
  17. package/dist/graphql/objects/index.d.ts +3 -3
  18. package/dist/index.cjs +695 -1286
  19. package/dist/index.d.cts +7 -18
  20. package/dist/index.d.ts +7 -18
  21. package/dist/index.js +5 -4
  22. package/dist/index.node.cjs +1365 -1496
  23. package/dist/index.node.d.cts +6 -7
  24. package/dist/index.node.d.ts +6 -7
  25. package/dist/index.node.js +7 -66
  26. package/dist/{logging-Dt2ooQiP.d.ts → logging-JIaZZIbR.d.ts} +3 -3
  27. package/dist/{logging-BUpzk4Z6.d.cts → logging-zkr4UlOi.d.cts} +3 -3
  28. package/dist/native/{chunk-D3SZRO65.js → chunk-X2QXUON7.js} +15 -0
  29. package/dist/native/{index.cjs → index.react-native.cjs} +875 -1274
  30. package/dist/native/{index.d.cts → index.react-native.d.cts} +1124 -520
  31. package/dist/native/{index.d.ts → index.react-native.d.ts} +1124 -520
  32. package/dist/native/{index.js → index.react-native.js} +870 -1100
  33. package/dist/native/{wasm-KT5NZXRN.js → wasm-GKEDPGTM.js} +1 -2
  34. package/dist/proto/spark.d.cts +1 -1
  35. package/dist/proto/spark.d.ts +1 -1
  36. package/dist/proto/spark_token.d.cts +1 -1
  37. package/dist/proto/spark_token.d.ts +1 -1
  38. package/dist/{spark-DasxuVfm.d.cts → spark-WA_4wcBr.d.cts} +1 -1
  39. package/dist/{spark-DasxuVfm.d.ts → spark-WA_4wcBr.d.ts} +1 -1
  40. package/dist/{spark-wallet-jlC0XN5f.d.ts → spark-wallet-BuFrUWeE.d.cts} +107 -75
  41. package/dist/{spark-wallet-BoMIOPWW.d.cts → spark-wallet-CE5PYiIb.d.ts} +107 -75
  42. package/dist/spark-wallet.browser-BwYkkOBU.d.ts +26 -0
  43. package/dist/spark-wallet.browser-DC3jdQPW.d.cts +26 -0
  44. package/dist/spark-wallet.node-C9d2W-Nb.d.ts +90 -0
  45. package/dist/spark-wallet.node-CR_zNxmy.d.cts +90 -0
  46. package/dist/tests/test-utils.cjs +17563 -7501
  47. package/dist/tests/test-utils.d.cts +8 -22
  48. package/dist/tests/test-utils.d.ts +8 -22
  49. package/dist/tests/test-utils.js +30 -4
  50. package/dist/{token-transactions-DscJaJOE.d.ts → token-transactions-BZoJuvuE.d.ts} +2 -2
  51. package/dist/{token-transactions-BDzCrQSk.d.cts → token-transactions-I_OFIoNH.d.cts} +2 -2
  52. package/dist/types/index.d.cts +2 -2
  53. package/dist/types/index.d.ts +2 -2
  54. package/package.json +20 -16
  55. package/src/bare/index.ts +1 -1
  56. package/src/debug.ts +1 -1
  57. package/src/graphql/client.ts +6 -9
  58. package/src/graphql/mutations/CompleteCoopExit.ts +1 -1
  59. package/src/graphql/mutations/RequestCoopExit.ts +3 -1
  60. package/src/graphql/mutations/RequestLightningSend.ts +3 -1
  61. package/src/graphql/objects/CompleteCoopExitInput.ts +22 -33
  62. package/src/graphql/objects/RequestCoopExitInput.ts +39 -45
  63. package/src/graphql/objects/RequestLightningSendInput.ts +31 -39
  64. package/src/index.node.ts +2 -1
  65. package/src/index.react-native.ts +21 -0
  66. package/src/index.ts +2 -1
  67. package/src/services/config.ts +2 -2
  68. package/src/services/connection/connection.browser.ts +130 -0
  69. package/src/services/connection/connection.node.ts +158 -0
  70. package/src/services/{connection.ts → connection/connection.ts} +58 -259
  71. package/src/services/coop-exit.ts +8 -4
  72. package/src/services/deposit.ts +1 -1
  73. package/src/services/index.ts +1 -1
  74. package/src/services/lightning.ts +1 -1
  75. package/src/services/token-transactions.ts +9 -9
  76. package/src/services/transfer.ts +1 -1
  77. package/src/spark-wallet/spark-wallet.bare.ts +12 -0
  78. package/src/spark-wallet/spark-wallet.browser.ts +9 -24
  79. package/src/spark-wallet/spark-wallet.node.ts +4 -24
  80. package/src/spark-wallet/spark-wallet.react-native.ts +17 -0
  81. package/src/spark-wallet/spark-wallet.ts +130 -82
  82. package/src/spark-wallet/types.ts +4 -2
  83. package/src/tests/integration/coop-exit.test.ts +5 -3
  84. package/src/tests/integration/lightning.test.ts +9 -5
  85. package/src/tests/integration/ssp/coop-exit-validation.test.ts +8 -11
  86. package/src/tests/integration/ssp/coop-exit.test.ts +3 -5
  87. package/src/tests/integration/ssp/lightning.test.ts +1 -1
  88. package/src/tests/integration/ssp/static-deposit-validation.test.ts +2 -2
  89. package/src/tests/integration/ssp/static_deposit.test.ts +94 -101
  90. package/src/tests/integration/ssp/swap.test.ts +4 -5
  91. package/src/tests/integration/ssp/transfers.test.ts +10 -11
  92. package/src/tests/integration/static_deposit.test.ts +4 -4
  93. package/src/tests/integration/token-output.test.ts +2 -2
  94. package/src/tests/integration/transfer.test.ts +30 -26
  95. package/src/tests/integration/watchtower.test.ts +3 -3
  96. package/src/tests/optimize.test.ts +45 -0
  97. package/src/tests/spark-wallet/queryNodes.test.ts +1 -2
  98. package/src/tests/test-utils.ts +3 -3
  99. package/src/tests/token-outputs.test.ts +61 -2
  100. package/src/tests/utils/spark-testing-wallet.ts +18 -58
  101. package/src/tests/utils/test-faucet.ts +12 -8
  102. package/src/tests/utils/utils.ts +63 -0
  103. package/src/tests/wrapWithOtelSpan.test.ts +7 -0
  104. package/src/utils/network.ts +11 -10
  105. package/src/utils/optimize.ts +226 -0
  106. package/dist/bare/xhr-transport-EEEC7FYA.js +0 -165
  107. package/dist/chunk-DIXXHATX.js +0 -70
  108. package/dist/native/chunk-C3WN3D4O.js +0 -19
  109. package/dist/native/xhr-transport-TNCG4HTW.js +0 -168
  110. package/dist/spark-wallet.node-07PksUHH.d.cts +0 -12
  111. package/dist/spark-wallet.node-CdWkKMSq.d.ts +0 -12
  112. package/dist/xhr-transport-IWJPYF7F.js +0 -167
  113. package/src/native/index.ts +0 -20
@@ -13,7 +13,7 @@ import {
13
13
  } from "../../index.js";
14
14
  import { InvoiceStatus, TransferStatus } from "../../proto/spark.js";
15
15
  import { WalletConfigService } from "../../services/config.js";
16
- import { ConnectionManager } from "../../services/connection.js";
16
+ import { ConnectionManagerNodeJS } from "../../services/connection/connection.node.js";
17
17
  import { SigningService } from "../../services/signing.js";
18
18
  import type { LeafKeyTweak } from "../../services/transfer.js";
19
19
  import { TransferService } from "../../services/transfer.js";
@@ -24,7 +24,10 @@ import {
24
24
  } from "../../services/wallet-config.js";
25
25
  import { NetworkType } from "../../utils/network.js";
26
26
  import { walletTypes } from "../test-utils.js";
27
- import { SparkWalletTesting } from "../utils/spark-testing-wallet.js";
27
+ import {
28
+ SparkWalletTesting,
29
+ SparkWalletTestingWithStream,
30
+ } from "../utils/spark-testing-wallet.js";
28
31
  import { BitcoinFaucet } from "../utils/test-faucet.js";
29
32
 
30
33
  const testLocalOnly = process.env.GITHUB_ACTIONS ? it.skip : it;
@@ -49,7 +52,7 @@ describe.each(walletTypes)(
49
52
  options,
50
53
  senderWallet.getSigner(),
51
54
  );
52
- const senderConnectionManager = new ConnectionManager(
55
+ const senderConnectionManager = new ConnectionManagerNodeJS(
53
56
  senderConfigService,
54
57
  );
55
58
  const signingService = new SigningService(senderConfigService);
@@ -77,7 +80,7 @@ describe.each(walletTypes)(
77
80
  options,
78
81
  receiverWallet.getSigner(),
79
82
  );
80
- const receiverConnectionManager = new ConnectionManager(
83
+ const receiverConnectionManager = new ConnectionManagerNodeJS(
81
84
  receiverConfigService,
82
85
  );
83
86
  const receiverSigningService = new SigningService(receiverConfigService);
@@ -165,7 +168,7 @@ describe.each(walletTypes)(
165
168
  options,
166
169
  senderWallet.getSigner(),
167
170
  );
168
- const senderConnectionManager = new ConnectionManager(
171
+ const senderConnectionManager = new ConnectionManagerNodeJS(
169
172
  senderConfigService,
170
173
  );
171
174
  const senderSigningService = new SigningService(senderConfigService);
@@ -186,7 +189,7 @@ describe.each(walletTypes)(
186
189
  options,
187
190
  receiverWallet.getSigner(),
188
191
  );
189
- const receiverConnectionManager = new ConnectionManager(
192
+ const receiverConnectionManager = new ConnectionManagerNodeJS(
190
193
  receiverConfigService,
191
194
  );
192
195
  const receiverSigningService = new SigningService(receiverConfigService);
@@ -264,7 +267,7 @@ describe.each(walletTypes)(
264
267
 
265
268
  const transferService = new TransferService(
266
269
  receiverConfigService,
267
- new ConnectionManager(receiverConfigService),
270
+ new ConnectionManagerNodeJS(receiverConfigService),
268
271
  new SigningService(receiverConfigService),
269
272
  );
270
273
 
@@ -329,7 +332,7 @@ describe.each(walletTypes)(
329
332
  options,
330
333
  senderWallet.getSigner(),
331
334
  );
332
- const senderConnectionManager = new ConnectionManager(
335
+ const senderConnectionManager = new ConnectionManagerNodeJS(
333
336
  senderConfigService,
334
337
  );
335
338
  const senderSigningService = new SigningService(senderConfigService);
@@ -372,7 +375,7 @@ describe.each(walletTypes)(
372
375
  missingOperatorOptions,
373
376
  receiverWallet.getSigner(),
374
377
  );
375
- const receiverConnectionManager = new ConnectionManager(
378
+ const receiverConnectionManager = new ConnectionManagerNodeJS(
376
379
  receiverConfigService,
377
380
  );
378
381
  const receiverSigningService = new SigningService(
@@ -457,9 +460,8 @@ describe.each(walletTypes)(
457
460
  receiverOptions,
458
461
  receiverWalletWithAllOperators.getSigner(),
459
462
  );
460
- const receiverConnectionManagerWithAllOperators = new ConnectionManager(
461
- receiverConfigServiceWithAllOperators,
462
- );
463
+ const receiverConnectionManagerWithAllOperators =
464
+ new ConnectionManagerNodeJS(receiverConfigServiceWithAllOperators);
463
465
  const receiverSigningServiceWithAllOperators = new SigningService(
464
466
  receiverConfigServiceWithAllOperators,
465
467
  );
@@ -550,12 +552,10 @@ describe.each(walletTypes)(
550
552
 
551
553
  await senderWallet.claimDeposit(signedTx.id);
552
554
 
553
- const { wallet: receiverWallet } = await SparkWalletTesting.initialize(
554
- {
555
+ const { wallet: receiverWallet } =
556
+ await SparkWalletTestingWithStream.initialize({
555
557
  options,
556
- },
557
- false,
558
- );
558
+ });
559
559
 
560
560
  expect(await receiverWallet.getSparkAddress()).not.toEqual(
561
561
  await senderWallet.getSparkAddress(),
@@ -719,7 +719,9 @@ describe.each(walletTypes)("transfer v2", ({ name, Signer, createTree }) => {
719
719
  options,
720
720
  senderWallet.getSigner(),
721
721
  );
722
- const senderConnectionManager = new ConnectionManager(senderConfigService);
722
+ const senderConnectionManager = new ConnectionManagerNodeJS(
723
+ senderConfigService,
724
+ );
723
725
  const signingService = new SigningService(senderConfigService);
724
726
  const senderTransferService = new TransferService(
725
727
  senderConfigService,
@@ -745,7 +747,7 @@ describe.each(walletTypes)("transfer v2", ({ name, Signer, createTree }) => {
745
747
  options,
746
748
  receiverWallet.getSigner(),
747
749
  );
748
- const receiverConnectionManager = new ConnectionManager(
750
+ const receiverConnectionManager = new ConnectionManagerNodeJS(
749
751
  receiverConfigService,
750
752
  );
751
753
  const receiverSigningService = new SigningService(receiverConfigService);
@@ -834,7 +836,9 @@ describe.each(walletTypes)("transfer v2", ({ name, Signer, createTree }) => {
834
836
  options,
835
837
  senderWallet.getSigner(),
836
838
  );
837
- const senderConnectionManager = new ConnectionManager(senderConfigService);
839
+ const senderConnectionManager = new ConnectionManagerNodeJS(
840
+ senderConfigService,
841
+ );
838
842
  const senderSigningService = new SigningService(senderConfigService);
839
843
  const senderTransferService = new TransferService(
840
844
  senderConfigService,
@@ -1093,7 +1097,7 @@ describe.each(walletTypes)("transfer v2", ({ name, Signer, createTree }) => {
1093
1097
  options,
1094
1098
  sdk2.getSigner(),
1095
1099
  );
1096
- const receiverConnectionManager = new ConnectionManager(
1100
+ const receiverConnectionManager = new ConnectionManagerNodeJS(
1097
1101
  receiverConfigService,
1098
1102
  );
1099
1103
  const receiverSigningService = new SigningService(receiverConfigService);
@@ -1177,7 +1181,7 @@ describe.each(walletTypes)("transfer v2", ({ name, Signer, createTree }) => {
1177
1181
  });
1178
1182
 
1179
1183
  const bobConfigService = new WalletConfigService(options, bob.getSigner());
1180
- const bobConnectionManager = new ConnectionManager(bobConfigService);
1184
+ const bobConnectionManager = new ConnectionManagerNodeJS(bobConfigService);
1181
1185
  const bobSigningService = new SigningService(bobConfigService);
1182
1186
 
1183
1187
  const bobTransferService = new TransferService(
@@ -1252,7 +1256,7 @@ describe.each(walletTypes)("transfer v2", ({ name, Signer, createTree }) => {
1252
1256
  });
1253
1257
 
1254
1258
  const bobConfigService = new WalletConfigService(options, bob.getSigner());
1255
- const bobConnectionManager = new ConnectionManager(bobConfigService);
1259
+ const bobConnectionManager = new ConnectionManagerNodeJS(bobConfigService);
1256
1260
  const bobSigningService = new SigningService(bobConfigService);
1257
1261
 
1258
1262
  const bobTransferService = new TransferService(
@@ -1365,7 +1369,7 @@ describe.skip.each(walletTypes)(
1365
1369
  options,
1366
1370
  sdk2.getSigner(),
1367
1371
  );
1368
- const receiverConnectionManager = new ConnectionManager(
1372
+ const receiverConnectionManager = new ConnectionManagerNodeJS(
1369
1373
  receiverConfigService,
1370
1374
  );
1371
1375
  const receiverSigningService = new SigningService(receiverConfigService);
@@ -1482,7 +1486,7 @@ describe.skip.each(walletTypes)(
1482
1486
  options,
1483
1487
  sdk2.getSigner(),
1484
1488
  );
1485
- const receiverConnectionManager = new ConnectionManager(
1489
+ const receiverConnectionManager = new ConnectionManagerNodeJS(
1486
1490
  receiverConfigService,
1487
1491
  );
1488
1492
  const receiverSigningService = new SigningService(receiverConfigService);
@@ -1542,7 +1546,7 @@ describe.skip.each(walletTypes)(
1542
1546
  options,
1543
1547
  sdk2.getSigner(),
1544
1548
  );
1545
- const receiverConnectionManager = new ConnectionManager(
1549
+ const receiverConnectionManager = new ConnectionManagerNodeJS(
1546
1550
  receiverConfigService,
1547
1551
  );
1548
1552
  const receiverSigningService = new SigningService(receiverConfigService);
@@ -3,7 +3,7 @@ import { bytesToHex, hexToBytes } from "@noble/curves/utils";
3
3
  import { uuidv7 } from "uuidv7";
4
4
  import { KeyDerivation, KeyDerivationType } from "../../index.js";
5
5
  import { WalletConfigService } from "../../services/config.js";
6
- import { ConnectionManager } from "../../services/connection.js";
6
+ import { ConnectionManagerNodeJS } from "../../services/connection/connection.node.js";
7
7
  import { SigningService } from "../../services/signing.js";
8
8
  import type { LeafKeyTweak } from "../../services/transfer.js";
9
9
  import { TransferService } from "../../services/transfer.js";
@@ -42,7 +42,7 @@ describe.each(walletTypes)("Node compatibility tests", ({ name, Signer }) => {
42
42
  options,
43
43
  oldWallet.getSigner(),
44
44
  );
45
- const oldConnectionManager = new ConnectionManager(oldConfigService);
45
+ const oldConnectionManager = new ConnectionManagerNodeJS(oldConfigService);
46
46
  const oldSigningService = new SigningService(oldConfigService);
47
47
  const oldTransferService = new TransferService(
48
48
  oldConfigService,
@@ -54,7 +54,7 @@ describe.each(walletTypes)("Node compatibility tests", ({ name, Signer }) => {
54
54
  options,
55
55
  newWallet.getSigner(),
56
56
  );
57
- const newConnectionManager = new ConnectionManager(newConfigService);
57
+ const newConnectionManager = new ConnectionManagerNodeJS(newConfigService);
58
58
  const newSigningService = new SigningService(newConfigService);
59
59
  const newTransferService = new TransferService(
60
60
  newConfigService,
@@ -0,0 +1,45 @@
1
+ import { describe, expect, it } from "@jest/globals";
2
+ import {
3
+ greedyLeaves,
4
+ swapMinimizingLeaves,
5
+ maximizeUnilateralExit,
6
+ minimizeTransferSwap,
7
+ Swap,
8
+ } from "../utils/optimize.js";
9
+
10
+ describe("keys", () => {
11
+ it("test greedyLeaves", () => {
12
+ expect(greedyLeaves(0)).toEqual([]);
13
+ expect(greedyLeaves(1)).toEqual([1]);
14
+ expect(greedyLeaves(100)).toEqual([4, 32, 64]);
15
+ expect(greedyLeaves(255)).toEqual([1, 2, 4, 8, 16, 32, 64, 128]);
16
+ expect(greedyLeaves(256)).toEqual([256]);
17
+ });
18
+
19
+ it("test swapMinimizingLeaves", () => {
20
+ expect(swapMinimizingLeaves(0)).toEqual([]);
21
+ expect(swapMinimizingLeaves(1)).toEqual([1]);
22
+ expect(swapMinimizingLeaves(100)).toEqual([1, 1, 2, 4, 4, 8, 16, 32, 32]);
23
+ expect(swapMinimizingLeaves(255)).toEqual([1, 2, 4, 8, 16, 32, 64, 128]);
24
+ expect(swapMinimizingLeaves(256)).toEqual([1, 1, 2, 4, 8, 16, 32, 64, 128]);
25
+ });
26
+
27
+ it("test maximizeUnilateralExit", () => {
28
+ expect(maximizeUnilateralExit([100, 64, 28, 1, 1])).toEqual([
29
+ new Swap([1, 1, 28, 64, 100], [2, 64, 128]),
30
+ ]);
31
+ expect(maximizeUnilateralExit([1, 1, 1, 1, 1, 1, 1, 1], 2)).toEqual([
32
+ new Swap([1, 1], [2]),
33
+ new Swap([1, 1], [2]),
34
+ new Swap([1, 1], [2]),
35
+ new Swap([1, 1], [2]),
36
+ ]);
37
+ });
38
+
39
+ it("test minimizeTransferSwap", () => {
40
+ expect(minimizeTransferSwap([8])).toEqual([new Swap([8], [1, 1, 2, 4])]);
41
+ expect(minimizeTransferSwap([100])).toEqual([
42
+ new Swap([100], [1, 1, 2, 4, 4, 8, 16, 32, 32]),
43
+ ]);
44
+ });
45
+ });
@@ -1,6 +1,5 @@
1
1
  import { describe, it, expect, beforeEach, jest } from "@jest/globals";
2
- import { SparkWallet } from "../../spark-wallet/spark-wallet.js";
3
- import type { ConnectionManager } from "../../services/connection.js";
2
+ import { SparkWallet } from "../../spark-wallet/spark-wallet.node.js";
4
3
 
5
4
  /** Helper subclass to expose the private `queryNodes` method for testing. */
6
5
  class TestSparkWallet extends SparkWallet {
@@ -8,7 +8,7 @@ import {
8
8
  } from "../index.js";
9
9
  import { FinalizeNodeSignaturesResponse, TreeNode } from "../proto/spark.js";
10
10
  import { WalletConfigService } from "../services/config.js";
11
- import { ConnectionManager } from "../services/connection.js";
11
+ import { ConnectionManagerNodeJS } from "../services/connection/connection.node.js";
12
12
  import { DepositService } from "../services/deposit.js";
13
13
  import { ConfigOptions, WalletConfig } from "../services/wallet-config.js";
14
14
  import { getP2TRAddressFromPublicKey } from "../utils/bitcoin.js";
@@ -17,7 +17,7 @@ import { SparkWalletTesting } from "./utils/spark-testing-wallet.js";
17
17
  import { BitcoinFaucet } from "./utils/test-faucet.js";
18
18
  import { sha256 } from "@noble/hashes/sha2";
19
19
 
20
- export { BitcoinFaucet };
20
+ export { BitcoinFaucet, SparkWalletTesting };
21
21
 
22
22
  export function getTestWalletConfig() {
23
23
  const identityPrivateKey = secp256k1.utils.randomPrivateKey();
@@ -48,7 +48,7 @@ async function createDeposit(
48
48
  },
49
49
  wallet.getSigner(),
50
50
  );
51
- const connectionManager = new ConnectionManager(configService);
51
+ const connectionManager = new ConnectionManagerNodeJS(configService);
52
52
  const depositService = new DepositService(configService, connectionManager);
53
53
 
54
54
  const pubKey = await wallet.getSigner().getPublicKeyFromDerivation({
@@ -1,8 +1,8 @@
1
- import { numberToBytesBE } from "@noble/curves/utils";
1
+ import { numberToBytesBE, bytesToNumberBE } from "@noble/curves/utils";
2
2
  import { ValidationError } from "../errors/types.js";
3
3
  import { OutputWithPreviousTransactionData } from "../proto/spark.js";
4
4
  import { WalletConfigService } from "../services/config.js";
5
- import { ConnectionManager } from "../services/connection.js";
5
+ import { ConnectionManager } from "../services/connection/connection.js";
6
6
  import { TokenTransactionService } from "../services/token-transactions.js";
7
7
 
8
8
  describe("select token outputs", () => {
@@ -17,6 +17,18 @@ describe("select token outputs", () => {
17
17
  );
18
18
  });
19
19
 
20
+ // Helper to access the private sorting method
21
+ const sortTokenOutputsByStrategy = (
22
+ tokenOutputs: OutputWithPreviousTransactionData[],
23
+ strategy: "SMALL_FIRST" | "LARGE_FIRST",
24
+ ) => {
25
+ // TypeScript bracket notation to access private method
26
+ (tokenTransactionService as any)["sortTokenOutputsByStrategy"](
27
+ tokenOutputs,
28
+ strategy,
29
+ );
30
+ };
31
+
20
32
  const createMockTokenOutput = (
21
33
  id: string,
22
34
  tokenAmount: bigint,
@@ -191,4 +203,51 @@ describe("select token outputs", () => {
191
203
  // Total: 600n >= 600n
192
204
  });
193
205
  });
206
+
207
+ describe("sorting with large amounts", () => {
208
+ it("should sort correctly when all amounts are above 2^60", () => {
209
+ const base = 2n ** 60n;
210
+ const amounts = [
211
+ base + 5000n,
212
+ base + 100n,
213
+ base + 1n,
214
+ base + 10000n,
215
+ base + 500n,
216
+ ];
217
+
218
+ const tokenOutputs = amounts.map((amount, i) =>
219
+ createMockTokenOutput(`output${i}`, amount),
220
+ );
221
+
222
+ // SMALL_FIRST
223
+ const smallFirstSorted = [...tokenOutputs];
224
+ sortTokenOutputsByStrategy(smallFirstSorted, "SMALL_FIRST");
225
+
226
+ const smallFirstAmounts = smallFirstSorted.map((o) =>
227
+ bytesToNumberBE(o.output!.tokenAmount!),
228
+ );
229
+ expect(smallFirstAmounts).toEqual([
230
+ base + 1n,
231
+ base + 100n,
232
+ base + 500n,
233
+ base + 5000n,
234
+ base + 10000n,
235
+ ]);
236
+
237
+ // LARGE_FIRST
238
+ const largeFirstSorted = [...tokenOutputs];
239
+ sortTokenOutputsByStrategy(largeFirstSorted, "LARGE_FIRST");
240
+
241
+ const largeFirstAmounts = largeFirstSorted.map((o) =>
242
+ bytesToNumberBE(o.output!.tokenAmount!),
243
+ );
244
+ expect(largeFirstAmounts).toEqual([
245
+ base + 10000n,
246
+ base + 5000n,
247
+ base + 500n,
248
+ base + 100n,
249
+ base + 1n,
250
+ ]);
251
+ });
252
+ });
194
253
  });
@@ -1,65 +1,22 @@
1
1
  import { QueryTransfersResponse, Transfer } from "../../proto/spark.js";
2
2
  import { ConfigOptions } from "../../services/wallet-config.js";
3
3
  import { SparkSigner } from "../../signer/signer.js";
4
- import { SparkWallet } from "../../spark-wallet/spark-wallet.node.js";
5
4
  import type { SparkWalletProps } from "../../spark-wallet/types.js";
6
5
  import { BitcoinFaucet } from "./test-faucet.js";
7
6
  import { Transaction } from "@scure/btc-signer";
8
7
  import { NetworkType } from "../../index.node.js";
8
+ import { SparkWalletNodeJS } from "../../spark-wallet/spark-wallet.node.js";
9
9
 
10
- interface ISparkWalletTesting extends SparkWallet {
11
- getSigner(): SparkSigner;
12
- queryPendingTransfers(): Promise<QueryTransfersResponse>;
13
- verifyPendingTransfer(transfer: Transfer): Promise<Map<string, Uint8Array>>;
14
- }
15
-
16
- export class SparkWalletTesting
17
- extends SparkWallet
18
- implements ISparkWalletTesting
19
- {
20
- private disableEvents: boolean;
21
-
22
- constructor(
23
- options?: ConfigOptions,
24
- signer?: SparkSigner,
25
- disableEvents = true,
26
- ) {
27
- super(options, signer);
28
- this.disableEvents = disableEvents;
29
- }
30
-
31
- static async initialize(props: SparkWalletProps, disableEvents = true) {
32
- const wallet = new SparkWalletTesting(
33
- props.options,
34
- props.signer,
35
- disableEvents,
36
- );
37
-
38
- if (props.options && props.options.signerWithPreExistingKeys) {
39
- await wallet.initWalletWithoutSeed();
40
-
41
- return {
42
- wallet,
43
- };
44
- } else {
45
- const initResponse = await wallet.initWallet(
46
- props.mnemonicOrSeed,
47
- props.accountNumber,
48
- );
49
- return {
50
- wallet,
51
- mnemonic: initResponse?.mnemonic,
52
- };
53
- }
54
- }
55
-
10
+ export class SparkWalletTesting extends SparkWalletNodeJS {
56
11
  protected override async setupBackgroundStream() {
57
- if (!this.disableEvents) {
58
- await super.setupBackgroundStream();
59
- }
12
+ // Background stream is disabled by default, use SparkWalletTestingWithStream to enable it
60
13
  return;
61
14
  }
62
15
 
16
+ protected async proxyParentSetupBackgroundStream() {
17
+ return super.setupBackgroundStream();
18
+ }
19
+
63
20
  public getSigner(): SparkSigner {
64
21
  return this.config.signer;
65
22
  }
@@ -75,7 +32,13 @@ export class SparkWalletTesting
75
32
  }
76
33
  }
77
34
 
78
- export async function initWallet(
35
+ export class SparkWalletTestingWithStream extends SparkWalletTesting {
36
+ protected override async setupBackgroundStream() {
37
+ return this.proxyParentSetupBackgroundStream();
38
+ }
39
+ }
40
+
41
+ export async function initTestingWallet(
79
42
  amount: bigint,
80
43
  network: NetworkType,
81
44
  ): Promise<{
@@ -86,14 +49,11 @@ export async function initWallet(
86
49
  faucet: BitcoinFaucet;
87
50
  }> {
88
51
  const faucet = BitcoinFaucet.getInstance();
89
- const { wallet: userWallet } = await SparkWalletTesting.initialize(
90
- {
91
- options: {
92
- network: network,
93
- },
52
+ const { wallet: userWallet } = await SparkWalletTestingWithStream.initialize({
53
+ options: {
54
+ network: network,
94
55
  },
95
- false,
96
- );
56
+ });
97
57
 
98
58
  const depositAddress = await userWallet.getStaticDepositAddress();
99
59
 
@@ -42,9 +42,9 @@ export class BitcoinFaucet {
42
42
  private lock: Promise<void> = Promise.resolve();
43
43
 
44
44
  private constructor(
45
- private url: string = "http://127.0.0.1:8332",
46
- private username: string = "testutil",
47
- private password: string = "testutilpassword",
45
+ private url: string,
46
+ private username: string,
47
+ private password: string,
48
48
  ) {
49
49
  this.miningAddress = getP2TRAddressFromPublicKey(
50
50
  secp256k1.getPublicKey(STATIC_MINING_KEY),
@@ -52,12 +52,16 @@ export class BitcoinFaucet {
52
52
  );
53
53
  }
54
54
 
55
- static getInstance(
56
- url: string = "http://127.0.0.1:8332",
57
- username: string = "testutil",
58
- password: string = "testutilpassword",
59
- ): BitcoinFaucet {
55
+ static getInstance(): BitcoinFaucet {
60
56
  if (!BitcoinFaucet.instance) {
57
+ const url =
58
+ process.env.BITCOIN_RPC_URL ||
59
+ (process.env.MINIKUBE_IP
60
+ ? `http://${process.env.MINIKUBE_IP}:8332`
61
+ : "http://127.0.0.1:8332");
62
+ const username = process.env.BITCOIN_RPC_USER || "testutil";
63
+ const password = process.env.BITCOIN_RPC_PASSWORD || "testutilpassword";
64
+
61
65
  BitcoinFaucet.instance = new BitcoinFaucet(url, username, password);
62
66
  }
63
67
  return BitcoinFaucet.instance;
@@ -0,0 +1,63 @@
1
+ import { SparkWalletTesting } from "./spark-testing-wallet.js";
2
+ import { SparkWalletEvent } from "../../index.js";
3
+
4
+ const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));
5
+
6
+ /**
7
+ * Retry a function until it succeeds.
8
+ * @param fn - The function to retry.
9
+ * @param maxAttempts - The maximum number of attempts.
10
+ * @param delayMs - The delay between attempts.
11
+ * @returns The result of the function.
12
+ */
13
+ export async function retryUntilSuccess<T>(
14
+ fn: () => Promise<T>,
15
+ { maxAttempts = 20, delayMs = 2000 } = {},
16
+ ): Promise<T> {
17
+ let err: unknown;
18
+ for (let i = 1; i <= maxAttempts; i++) {
19
+ try {
20
+ return await fn();
21
+ } catch (e) {
22
+ err = e;
23
+ }
24
+ await sleep(delayMs);
25
+ }
26
+ throw err;
27
+ }
28
+
29
+ /**
30
+ * Wait for a claim to be made on a wallet.
31
+ * @param wallet - The wallet to wait for a claim on.
32
+ * @param timeoutMs - The timeout in milliseconds.
33
+ * @param throwOnTimeout - Whether to throw an error if the timeout is reached.
34
+ * @returns A promise that resolves when the claim is made.
35
+ */
36
+ export async function waitForClaim({
37
+ wallet,
38
+ timeoutMs = 30000,
39
+ throwOnTimeout = false,
40
+ }: {
41
+ wallet: SparkWalletTesting;
42
+ timeoutMs?: number;
43
+ throwOnTimeout?: boolean;
44
+ }): Promise<void> {
45
+ await new Promise<void>((resolve, reject) => {
46
+ const onClaim = () => {
47
+ cleanup();
48
+ resolve();
49
+ };
50
+ const timer = setTimeout(() => {
51
+ cleanup();
52
+ if (throwOnTimeout) {
53
+ reject(new Error("claim timeout"));
54
+ } else {
55
+ resolve();
56
+ }
57
+ }, timeoutMs);
58
+ const cleanup = () => {
59
+ clearTimeout(timer);
60
+ };
61
+ wallet.once(SparkWalletEvent.TransferClaimed, onClaim);
62
+ });
63
+ }
@@ -3,9 +3,16 @@ import { SparkWalletTesting } from "./utils/spark-testing-wallet.js";
3
3
  import { getTestWalletConfig } from "./test-utils.js";
4
4
  import { BasicTracerProvider } from "@opentelemetry/sdk-trace-base";
5
5
  import { trace } from "@opentelemetry/api";
6
+ import { ConfigOptions } from "../index.node.js";
7
+ import { SparkSigner } from "../signer/signer.js";
6
8
 
7
9
  class TestableWallet extends SparkWalletTesting {
8
10
  public wrapWithOtelSpanPublic = this.wrapWithOtelSpan;
11
+
12
+ // Public constructor to allow direct instantiation in tests without init
13
+ public constructor(options?: ConfigOptions, signer?: SparkSigner) {
14
+ super(options, signer);
15
+ }
9
16
  }
10
17
 
11
18
  // Set up a real tracer provider once for all tests
@@ -1,5 +1,5 @@
1
1
  import * as btc from "@scure/btc-signer";
2
- import * as bitcoin from "bitcoinjs-lib";
2
+ import { bech32, bech32m } from "@scure/base";
3
3
  import { Network as NetworkProto } from "../proto/spark.js";
4
4
  import { BitcoinNetwork } from "../graphql/objects/BitcoinNetwork.js";
5
5
  import { ValidationError } from "../errors/index.js";
@@ -50,14 +50,6 @@ const NetworkConfig: Record<Network, typeof btc.NETWORK> = {
50
50
  export const getNetwork = (network: Network): typeof btc.NETWORK =>
51
51
  NetworkConfig[network];
52
52
 
53
- export const LRC_WALLET_NETWORK = Object.freeze({
54
- [Network.MAINNET]: bitcoin.networks.bitcoin,
55
- [Network.TESTNET]: bitcoin.networks.testnet,
56
- [Network.SIGNET]: bitcoin.networks.testnet,
57
- [Network.REGTEST]: bitcoin.networks.regtest,
58
- [Network.LOCAL]: bitcoin.networks.regtest,
59
- });
60
-
61
53
  /**
62
54
  * Utility function to determine the network from a Bitcoin address.
63
55
  *
@@ -66,7 +58,16 @@ export const LRC_WALLET_NETWORK = Object.freeze({
66
58
  */
67
59
  export function getNetworkFromAddress(address: string) {
68
60
  try {
69
- const decoded = bitcoin.address.fromBech32(address);
61
+ // Try bech32 first, then bech32m (Taproot)
62
+ const bechAddress = address as `${string}1${string}`;
63
+ const decoded = (() => {
64
+ try {
65
+ return bech32.decode(bechAddress);
66
+ } catch (_) {
67
+ return bech32m.decode(bechAddress);
68
+ }
69
+ })();
70
+
70
71
  // HRP (human-readable part) determines the network
71
72
  if (decoded.prefix === "bc") {
72
73
  return BitcoinNetwork.MAINNET;