@buildonspark/spark-sdk 0.0.11 → 0.0.13

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 (61) hide show
  1. package/dist/graphql/objects/LeavesSwapRequest.d.ts +8 -8
  2. package/dist/graphql/objects/LeavesSwapRequest.js +21 -12
  3. package/dist/graphql/objects/LeavesSwapRequest.js.map +1 -1
  4. package/dist/graphql/objects/SparkTransferToLeavesConnection.d.ts +5 -5
  5. package/dist/graphql/objects/SparkTransferToLeavesConnection.js +6 -5
  6. package/dist/graphql/objects/SparkTransferToLeavesConnection.js.map +1 -1
  7. package/dist/graphql/objects/Transfer.d.ts +1 -1
  8. package/dist/services/config.d.ts +2 -16
  9. package/dist/services/config.js +8 -8
  10. package/dist/services/config.js.map +1 -1
  11. package/dist/services/connection.js +25 -11
  12. package/dist/services/connection.js.map +1 -1
  13. package/dist/services/coop-exit.js +1 -2
  14. package/dist/services/coop-exit.js.map +1 -1
  15. package/dist/services/deposit.js +1 -1
  16. package/dist/services/deposit.js.map +1 -1
  17. package/dist/services/lightning.js +1 -0
  18. package/dist/services/lightning.js.map +1 -1
  19. package/dist/services/transfer.d.ts +4 -4
  20. package/dist/services/transfer.js +6 -6
  21. package/dist/services/transfer.js.map +1 -1
  22. package/dist/services/wallet-config.d.ts +22 -0
  23. package/dist/services/wallet-config.js +100 -0
  24. package/dist/services/wallet-config.js.map +1 -0
  25. package/dist/signer/signer.d.ts +8 -4
  26. package/dist/signer/signer.js +45 -36
  27. package/dist/signer/signer.js.map +1 -1
  28. package/dist/spark-sdk.d.ts +49 -47
  29. package/dist/spark-sdk.js +73 -145
  30. package/dist/spark-sdk.js.map +1 -1
  31. package/dist/tests/adaptor-signature.test.js +5 -2
  32. package/dist/tests/adaptor-signature.test.js.map +1 -1
  33. package/dist/tests/coop-exit.test.js +10 -9
  34. package/dist/tests/coop-exit.test.js.map +1 -1
  35. package/dist/tests/deposit.test.js +10 -4
  36. package/dist/tests/deposit.test.js.map +1 -1
  37. package/dist/tests/lightning.test.js +16 -12
  38. package/dist/tests/lightning.test.js.map +1 -1
  39. package/dist/tests/swap.test.js +16 -11
  40. package/dist/tests/swap.test.js.map +1 -1
  41. package/dist/tests/test-util.d.ts +1 -8
  42. package/dist/tests/test-util.js +5 -117
  43. package/dist/tests/test-util.js.map +1 -1
  44. package/dist/tests/transfer.test.js +41 -36
  45. package/dist/tests/transfer.test.js.map +1 -1
  46. package/dist/tests/utils/spark-testing-wallet.d.ts +5 -1
  47. package/dist/tests/utils/spark-testing-wallet.js +8 -0
  48. package/dist/tests/utils/spark-testing-wallet.js.map +1 -1
  49. package/dist/utils/index.d.ts +2 -1
  50. package/dist/utils/index.js +2 -1
  51. package/dist/utils/index.js.map +1 -1
  52. package/dist/utils/mempool.d.ts +1 -0
  53. package/dist/utils/mempool.js +29 -0
  54. package/dist/utils/mempool.js.map +1 -0
  55. package/dist/utils/network.d.ts +14 -6
  56. package/dist/utils/network.js +29 -6
  57. package/dist/utils/network.js.map +1 -1
  58. package/dist/utils/signing.d.ts +1 -1
  59. package/dist/utils/wasm-wrapper.js +23 -13
  60. package/dist/utils/wasm-wrapper.js.map +1 -1
  61. package/package.json +21 -5
@@ -1,9 +1,11 @@
1
+ import { CoopExitFeeEstimateInput, CoopExitFeeEstimateOutput, LeavesSwapRequest, LightningReceiveFeeEstimateInput, LightningReceiveFeeEstimateOutput, LightningSendFeeEstimateInput, LightningSendFeeEstimateOutput } from "./graphql/objects/index.js";
1
2
  import { LeafWithPreviousTransactionData, QueryAllTransfersResponse, Transfer, TreeNode } from "./proto/spark.js";
2
- import { ConfigOptions, WalletConfigService } from "./services/config.js";
3
+ import { WalletConfigService } from "./services/config.js";
3
4
  import { ConnectionManager } from "./services/connection.js";
4
5
  import { TransferService } from "./services/transfer.js";
5
- import { NetworkType } from "./utils/network.js";
6
+ import { ConfigOptions } from "./services/wallet-config.js";
6
7
  import { LRC20WalletApiConfig, LRCWallet } from "@buildonspark/lrc20-sdk";
8
+ import { SparkSigner } from "./signer/signer.js";
7
9
  export type CreateLightningInvoiceParams = {
8
10
  amountSats: number;
9
11
  memo: string;
@@ -12,19 +14,19 @@ export type CreateLightningInvoiceParams = {
12
14
  export type PayLightningInvoiceParams = {
13
15
  invoice: string;
14
16
  };
15
- export type SendTransferParams = {
16
- amount?: number;
17
- leaves?: TreeNode[];
18
- receiverPubKey: string;
19
- expiryTime?: Date;
17
+ export type TransferParams = {
18
+ amountSats: number;
19
+ receiverSparkAddress: string;
20
20
  };
21
21
  export type InitWalletResponse = {
22
- balance: bigint;
23
- tokenBalance: Map<string, {
24
- balance: bigint;
25
- }>;
26
22
  mnemonic?: string | undefined;
27
23
  };
24
+ export interface SparkWalletProps {
25
+ mnemonicOrSeed?: Uint8Array | string;
26
+ signer?: SparkSigner;
27
+ options?: ConfigOptions;
28
+ lrc20WalletApiConfig?: LRC20WalletApiConfig;
29
+ }
28
30
  /**
29
31
  * The SparkWallet class is the primary interface for interacting with the Spark network.
30
32
  * It provides methods for creating and managing wallets, handling deposits, executing transfers,
@@ -47,7 +49,11 @@ export declare class SparkWallet {
47
49
  private wasmModule;
48
50
  protected leaves: TreeNode[];
49
51
  protected tokenLeaves: Map<string, LeafWithPreviousTransactionData[]>;
50
- constructor(network: NetworkType, configOptions?: ConfigOptions);
52
+ protected constructor(options?: ConfigOptions, signer?: SparkSigner);
53
+ static create({ mnemonicOrSeed, signer, options, lrc20WalletApiConfig, }: SparkWalletProps): Promise<{
54
+ mnemonic?: string | undefined;
55
+ wallet: SparkWallet;
56
+ }>;
51
57
  private initWasm;
52
58
  private initializeWallet;
53
59
  private getLeaves;
@@ -57,7 +63,6 @@ export declare class SparkWallet {
57
63
  private optimizeLeaves;
58
64
  private syncWallet;
59
65
  private withLeaves;
60
- private isInitialized;
61
66
  /**
62
67
  * Gets the identity public key of the wallet.
63
68
  *
@@ -84,9 +89,9 @@ export declare class SparkWallet {
84
89
  * - mnemonic: The mnemonic if one was generated (undefined for raw seed)
85
90
  * - balance: The wallet's initial balance in satoshis
86
91
  * - tokenBalance: Map of token balances and leaf counts
92
+ * @private
87
93
  */
88
- initWallet(mnemonicOrSeed?: Uint8Array | string, enableLRC20Wallet?: boolean, lrc20WalletApiConfig?: LRC20WalletApiConfig): Promise<InitWalletResponse>;
89
- private initWalletFromMnemonic;
94
+ protected initWallet(mnemonicOrSeed?: Uint8Array | string, lrc20WalletApiConfig?: LRC20WalletApiConfig): Promise<InitWalletResponse | undefined>;
90
95
  /**
91
96
  * Initializes a wallet from a seed.
92
97
  *
@@ -102,9 +107,11 @@ export declare class SparkWallet {
102
107
  * @param {number} [params.targetAmount] - Target amount for the swap
103
108
  * @param {TreeNode[]} [params.leaves] - Specific leaves to swap
104
109
  * @returns {Promise<Object>} The completed swap response
105
- * @private
106
110
  */
107
- private requestLeavesSwap;
111
+ requestLeavesSwap({ targetAmount, leaves, }: {
112
+ targetAmount?: number;
113
+ leaves?: TreeNode[];
114
+ }): Promise<LeavesSwapRequest>;
108
115
  /**
109
116
  * Gets all transfers for the wallet.
110
117
  *
@@ -112,7 +119,7 @@ export declare class SparkWallet {
112
119
  * @param {number} [offset=0] - Offset for pagination
113
120
  * @returns {Promise<QueryAllTransfersResponse>} Response containing the list of transfers
114
121
  */
115
- getAllTransfers(limit?: number, offset?: number): Promise<QueryAllTransfersResponse>;
122
+ getTransfers(limit?: number, offset?: number): Promise<QueryAllTransfersResponse>;
116
123
  /**
117
124
  * Gets the current balance of the wallet.
118
125
  * You can use the forceRefetch option to synchronize your wallet and claim any
@@ -153,15 +160,19 @@ export declare class SparkWallet {
153
160
  * @private
154
161
  */
155
162
  private finalizeDeposit;
156
- claimDeposit(txid: string): Promise<TreeNode[] | undefined>;
157
163
  /**
158
- * Queries the mempool for transactions associated with an address.
164
+ * Gets all unused deposit addresses for the wallet.
159
165
  *
160
- * @param {string} address - The address to query
161
- * @returns {Promise<{depositTx: Transaction, vout: number} | null>} Transaction details or null if none found
162
- * @private
166
+ * @returns {Promise<string[]>} The unused deposit addresses
167
+ */
168
+ getUnusedDepositAddresses(): Promise<string[]>;
169
+ /**
170
+ * Claims a deposit to the wallet.
171
+ *
172
+ * @param {string} txid - The transaction ID of the deposit
173
+ * @returns {Promise<TreeNode[] | undefined>} The nodes resulting from the deposit
163
174
  */
164
- private queryMempoolTxs;
175
+ claimDeposit(txid: string): Promise<TreeNode[] | undefined>;
165
176
  /**
166
177
  * Transfers deposit to self to claim ownership.
167
178
  *
@@ -174,45 +185,39 @@ export declare class SparkWallet {
174
185
  /**
175
186
  * Sends a transfer to another Spark user.
176
187
  *
177
- * @param {Object} params - Parameters for the transfer
188
+ * @param {TransferParams} params - Parameters for the transfer
178
189
  * @param {string} params.receiverSparkAddress - The recipient's Spark address
179
190
  * @param {number} params.amountSats - Amount to send in satoshis
180
191
  * @returns {Promise<Transfer>} The completed transfer details
181
192
  */
182
- sendSparkTransfer({ receiverSparkAddress, amountSats, }: {
183
- receiverSparkAddress: string;
184
- amountSats: number;
185
- }): Promise<Transfer>;
193
+ transfer({ amountSats, receiverSparkAddress }: TransferParams): Promise<Transfer>;
186
194
  /**
187
- * Internal method to send a transfer.
195
+ * Internal method to refresh timelock nodes.
188
196
  *
189
- * @param {SendTransferParams} params - Parameters for the transfer
190
- * @returns {Promise<Transfer>} The completed transfer details
197
+ * @param {string} nodeId - The optional ID of the node to refresh. If not provided, all nodes will be checked.
198
+ * @returns {Promise<void>}
191
199
  * @private
192
200
  */
193
- private _sendTransfer;
201
+ private refreshTimelockNodes;
194
202
  /**
195
- * Internal method to refresh timelock nodes.
203
+ * Gets all pending transfers.
196
204
  *
197
- * @param {string} nodeId - The optional ID of the node to refresh. If not provided, all nodes will be checked.
198
- * @returns {Promise<void>}
205
+ * @returns {Promise<Transfer[]>} The pending transfers
199
206
  */
200
- refreshTimelockNodes(nodeId?: string): Promise<void>;
207
+ getPendingTransfers(): Promise<Transfer[]>;
201
208
  /**
202
209
  * Claims a specific transfer.
203
210
  *
204
211
  * @param {Transfer} transfer - The transfer to claim
205
212
  * @returns {Promise<Object>} The claim result
206
- * @private
207
213
  */
208
- private claimTransfer;
214
+ claimTransfer(transfer: Transfer): Promise<TreeNode[]>;
209
215
  /**
210
216
  * Claims all pending transfers.
211
217
  *
212
218
  * @returns {Promise<boolean>} True if any transfers were claimed
213
- * @private
214
219
  */
215
- private claimTransfers;
220
+ claimTransfers(): Promise<boolean>;
216
221
  /**
217
222
  * Cancels all sender-initiated transfers.
218
223
  *
@@ -243,17 +248,15 @@ export declare class SparkWallet {
243
248
  *
244
249
  * @param {LightningReceiveFeeEstimateInput} params - Input parameters for fee estimation
245
250
  * @returns {Promise<LightningReceiveFeeEstimateOutput | null>} Fee estimate for receiving Lightning payments
246
- * @private
247
251
  */
248
- private getLightningReceiveFeeEstimate;
252
+ getLightningReceiveFeeEstimate({ amountSats, network, }: LightningReceiveFeeEstimateInput): Promise<LightningReceiveFeeEstimateOutput | null>;
249
253
  /**
250
254
  * Gets fee estimate for sending Lightning payments.
251
255
  *
252
256
  * @param {LightningSendFeeEstimateInput} params - Input parameters for fee estimation
253
257
  * @returns {Promise<LightningSendFeeEstimateOutput | null>} Fee estimate for sending Lightning payments
254
- * @private
255
258
  */
256
- private getLightningSendFeeEstimate;
259
+ getLightningSendFeeEstimate({ encodedInvoice, }: LightningSendFeeEstimateInput): Promise<LightningSendFeeEstimateOutput | null>;
257
260
  /**
258
261
  * Generates a deposit address for a tree.
259
262
  *
@@ -303,9 +306,8 @@ export declare class SparkWallet {
303
306
  *
304
307
  * @param {CoopExitFeeEstimateInput} params - Input parameters for fee estimation
305
308
  * @returns {Promise<CoopExitFeeEstimateOutput | null>} Fee estimate for the withdrawal
306
- * @private
307
309
  */
308
- private getCoopExitFeeEstimate;
310
+ getCoopExitFeeEstimate({ leafExternalIds, withdrawalAddress, }: CoopExitFeeEstimateInput): Promise<CoopExitFeeEstimateOutput | null>;
309
311
  /**
310
312
  * Synchronizes token leaves for the wallet.
311
313
  *
package/dist/spark-sdk.js CHANGED
@@ -13,7 +13,6 @@ import { DepositService } from "./services/deposit.js";
13
13
  import { LightningService } from "./services/lightning.js";
14
14
  import { TokenTransactionService } from "./services/token-transactions.js";
15
15
  import { TransferService } from "./services/transfer.js";
16
- import * as bip39 from "@scure/bip39";
17
16
  import { validateMnemonic } from "@scure/bip39";
18
17
  import { wordlist } from "@scure/bip39/wordlists/english";
19
18
  import { Mutex } from "async-mutex";
@@ -30,20 +29,6 @@ import { broadcastL1Withdrawal } from "./services/lrc20.js";
30
29
  import { getMasterHDKeyFromSeed } from "./utils/index.js";
31
30
  // Add this constant at the file level
32
31
  const MAX_TOKEN_LEAVES = 100;
33
- class LeafOperationError extends Error {
34
- cause;
35
- constructor(message, cause) {
36
- super(message);
37
- this.cause = cause;
38
- this.name = "LeafOperationError";
39
- }
40
- }
41
- class LeafOperationTimeoutError extends LeafOperationError {
42
- constructor(message) {
43
- super(message);
44
- this.name = "LeafOperationTimeoutError";
45
- }
46
- }
47
32
  /**
48
33
  * The SparkWallet class is the primary interface for interacting with the Spark network.
49
34
  * It provides methods for creating and managing wallets, handling deposits, executing transfers,
@@ -66,8 +51,8 @@ export class SparkWallet {
66
51
  wasmModule = null;
67
52
  leaves = [];
68
53
  tokenLeaves = new Map();
69
- constructor(network, configOptions) {
70
- this.config = new WalletConfigService(Network[network], configOptions);
54
+ constructor(options, signer) {
55
+ this.config = new WalletConfigService(options, signer);
71
56
  this.connectionManager = new ConnectionManager(this.config);
72
57
  this.depositService = new DepositService(this.config, this.connectionManager);
73
58
  this.transferService = new TransferService(this.config, this.connectionManager);
@@ -76,6 +61,14 @@ export class SparkWallet {
76
61
  this.lightningService = new LightningService(this.config, this.connectionManager);
77
62
  this.coopExitService = new CoopExitService(this.config, this.connectionManager);
78
63
  }
64
+ static async create({ mnemonicOrSeed, signer, options, lrc20WalletApiConfig, }) {
65
+ const wallet = new SparkWallet(options, signer);
66
+ const initResponse = await wallet.initWallet(mnemonicOrSeed, lrc20WalletApiConfig);
67
+ return {
68
+ wallet,
69
+ ...initResponse,
70
+ };
71
+ }
79
72
  async initWasm() {
80
73
  try {
81
74
  this.wasmModule = await initWasm();
@@ -85,13 +78,9 @@ export class SparkWallet {
85
78
  }
86
79
  }
87
80
  async initializeWallet(identityPublicKey) {
88
- await this.connectionManager.createClients();
89
81
  this.sspClient = new SspClient(identityPublicKey);
90
- await Promise.all([
91
- this.initWasm(),
92
- // Hacky but do this to store the deposit signing key in the signer
93
- this.config.signer.getDepositSigningKey(),
94
- ]);
82
+ await this.connectionManager.createClients();
83
+ await this.initWasm();
95
84
  await this.syncWallet();
96
85
  }
97
86
  async getLeaves() {
@@ -195,8 +184,8 @@ export class SparkWallet {
195
184
  async syncWallet() {
196
185
  await Promise.all([this.claimTransfers(), this.syncTokenLeaves()]);
197
186
  this.leaves = await this.getLeaves();
198
- await this.refreshTimelockNodes();
199
187
  await this.config.signer.restoreSigningKeysFromLeafs(this.leaves);
188
+ await this.refreshTimelockNodes();
200
189
  this.optimizeLeaves().catch((e) => {
201
190
  console.error("Failed to optimize leaves", e);
202
191
  });
@@ -210,9 +199,6 @@ export class SparkWallet {
210
199
  release();
211
200
  }
212
201
  }
213
- isInitialized() {
214
- return this.sspClient !== null && this.wasmModule !== null;
215
- }
216
202
  /**
217
203
  * Gets the identity public key of the wallet.
218
204
  *
@@ -243,33 +229,28 @@ export class SparkWallet {
243
229
  * - mnemonic: The mnemonic if one was generated (undefined for raw seed)
244
230
  * - balance: The wallet's initial balance in satoshis
245
231
  * - tokenBalance: Map of token balances and leaf counts
232
+ * @private
246
233
  */
247
- async initWallet(mnemonicOrSeed, enableLRC20Wallet = true, lrc20WalletApiConfig) {
234
+ async initWallet(mnemonicOrSeed, lrc20WalletApiConfig) {
248
235
  const returnMnemonic = !mnemonicOrSeed;
236
+ let mnemonic;
249
237
  if (!mnemonicOrSeed) {
250
238
  mnemonicOrSeed = await this.config.signer.generateMnemonic();
251
239
  }
240
+ let seed;
252
241
  if (typeof mnemonicOrSeed !== "string") {
253
- mnemonicOrSeed = bytesToHex(mnemonicOrSeed);
254
- }
255
- let mnemonic;
256
- if (validateMnemonic(mnemonicOrSeed, wordlist)) {
257
- mnemonic = mnemonicOrSeed;
258
- await this.initWalletFromMnemonic(mnemonicOrSeed);
242
+ seed = mnemonicOrSeed;
259
243
  }
260
244
  else {
261
- await this.initWalletFromSeed(mnemonicOrSeed);
262
- }
263
- const balance = this.leaves.reduce((acc, leaf) => acc + BigInt(leaf.value), 0n);
264
- const tokenBalance = await this.getAllTokenBalances();
265
- if (enableLRC20Wallet) {
266
- let seed;
267
- if (typeof mnemonicOrSeed === "string") {
268
- seed = await bip39.mnemonicToSeed(mnemonicOrSeed);
245
+ if (validateMnemonic(mnemonicOrSeed, wordlist)) {
246
+ seed = await this.config.signer.mnemonicToSeed(mnemonicOrSeed);
269
247
  }
270
248
  else {
271
- seed = mnemonicOrSeed;
249
+ seed = hexToBytes(mnemonicOrSeed);
272
250
  }
251
+ }
252
+ await this.initWalletFromSeed(seed);
253
+ if (lrc20WalletApiConfig) {
273
254
  const network = this.config.getNetwork();
274
255
  const masterPrivateKey = getMasterHDKeyFromSeed(seed, network == Network.REGTEST ? 0 : 1).privateKey;
275
256
  this.lrc20Wallet = new LRCWallet(bytesToHex(masterPrivateKey), LRC_WALLET_NETWORK[network], LRC_WALLET_NETWORK_TYPE[network], lrc20WalletApiConfig);
@@ -277,19 +258,9 @@ export class SparkWallet {
277
258
  if (returnMnemonic) {
278
259
  return {
279
260
  mnemonic,
280
- balance,
281
- tokenBalance,
282
261
  };
283
262
  }
284
- return {
285
- balance,
286
- tokenBalance,
287
- };
288
- }
289
- async initWalletFromMnemonic(mnemonic) {
290
- const identityPublicKey = await this.config.signer.createSparkWalletFromMnemonic(mnemonic, this.config.getNetwork());
291
- await this.initializeWallet(identityPublicKey);
292
- return identityPublicKey;
263
+ return;
293
264
  }
294
265
  /**
295
266
  * Initializes a wallet from a seed.
@@ -310,7 +281,6 @@ export class SparkWallet {
310
281
  * @param {number} [params.targetAmount] - Target amount for the swap
311
282
  * @param {TreeNode[]} [params.leaves] - Specific leaves to swap
312
283
  * @returns {Promise<Object>} The completed swap response
313
- * @private
314
284
  */
315
285
  async requestLeavesSwap({ targetAmount, leaves, }) {
316
286
  if (targetAmount && targetAmount <= 0) {
@@ -338,7 +308,7 @@ export class SparkWallet {
338
308
  signingPubKey: await this.config.signer.generatePublicKey(sha256(leaf.id)),
339
309
  newSigningPubKey: await this.config.signer.generatePublicKey(),
340
310
  })));
341
- const { transfer, signatureMap } = await this.transferService.sendTransferSignRefund(leafKeyTweaks, await this.config.signer.getSspIdentityPublicKey(this.config.getNetwork()), new Date(Date.now() + 10 * 60 * 1000));
311
+ const { transfer, signatureMap } = await this.transferService.sendTransferSignRefund(leafKeyTweaks, await this.config.signer.getSspIdentityPublicKey(this.config.getNetwork()), new Date(Date.now() + 2 * 60 * 1000));
342
312
  try {
343
313
  if (!transfer.leaves[0]?.leaf) {
344
314
  throw new Error("Failed to get leaf");
@@ -445,7 +415,7 @@ export class SparkWallet {
445
415
  * @param {number} [offset=0] - Offset for pagination
446
416
  * @returns {Promise<QueryAllTransfersResponse>} Response containing the list of transfers
447
417
  */
448
- async getAllTransfers(limit = 20, offset = 0) {
418
+ async getTransfers(limit = 20, offset = 0) {
449
419
  return await this.transferService.queryAllTransfers(limit, offset);
450
420
  }
451
421
  /**
@@ -518,6 +488,23 @@ export class SparkWallet {
518
488
  });
519
489
  return await this.transferDepositToSelf(response.nodes, signingPubKey);
520
490
  }
491
+ /**
492
+ * Gets all unused deposit addresses for the wallet.
493
+ *
494
+ * @returns {Promise<string[]>} The unused deposit addresses
495
+ */
496
+ async getUnusedDepositAddresses() {
497
+ const sparkClient = await this.connectionManager.createSparkClient(this.config.getCoordinatorAddress());
498
+ return (await sparkClient.query_unused_deposit_addresses({
499
+ identityPublicKey: await this.config.signer.getIdentityPublicKey(),
500
+ })).depositAddresses.map((addr) => addr.depositAddress);
501
+ }
502
+ /**
503
+ * Claims a deposit to the wallet.
504
+ *
505
+ * @param {string} txid - The transaction ID of the deposit
506
+ * @returns {Promise<TreeNode[] | undefined>} The nodes resulting from the deposit
507
+ */
521
508
  async claimDeposit(txid) {
522
509
  const baseUrl = this.config.getNetwork() === Network.REGTEST
523
510
  ? "https://regtest-mempool.dev.dev.sparkinfra.net/api"
@@ -567,47 +554,6 @@ export class SparkWallet {
567
554
  });
568
555
  return nodes;
569
556
  }
570
- /**
571
- * Queries the mempool for transactions associated with an address.
572
- *
573
- * @param {string} address - The address to query
574
- * @returns {Promise<{depositTx: Transaction, vout: number} | null>} Transaction details or null if none found
575
- * @private
576
- */
577
- async queryMempoolTxs(address) {
578
- const network = getNetworkFromAddress(address) || this.config.getNetwork();
579
- const baseUrl = network === BitcoinNetwork.REGTEST
580
- ? "https://regtest-mempool.dev.dev.sparkinfra.net/api"
581
- : "https://mempool.space/docs/api";
582
- const auth = btoa("spark-sdk:mCMk1JqlBNtetUNy");
583
- const headers = {
584
- "Content-Type": "application/json",
585
- };
586
- if (network === BitcoinNetwork.REGTEST) {
587
- headers["Authorization"] = `Basic ${auth}`;
588
- }
589
- const response = await fetch(`${baseUrl}/address/${address}/txs`, {
590
- headers,
591
- });
592
- const addressTxs = await response.json();
593
- if (addressTxs && addressTxs.length > 0) {
594
- const latestTx = addressTxs[0];
595
- const outputIndex = latestTx.vout.findIndex((output) => output.scriptpubkey_address === address);
596
- if (outputIndex === -1) {
597
- return null;
598
- }
599
- const txResponse = await fetch(`${baseUrl}/tx/${latestTx.txid}/hex`, {
600
- headers,
601
- });
602
- const txHex = await txResponse.text();
603
- const depositTx = getTxFromRawTxHex(txHex);
604
- return {
605
- depositTx,
606
- vout: outputIndex,
607
- };
608
- }
609
- return null;
610
- }
611
557
  /**
612
558
  * Transfers deposit to self to claim ownership.
613
559
  *
@@ -622,7 +568,7 @@ export class SparkWallet {
622
568
  signingPubKey,
623
569
  newSigningPubKey: await this.config.signer.generatePublicKey(),
624
570
  })));
625
- await this.transferService.sendTransfer(leafKeyTweaks, await this.config.signer.getIdentityPublicKey(), new Date(Date.now() + 10 * 60 * 1000));
571
+ await this.transferService.sendTransfer(leafKeyTweaks, await this.config.signer.getIdentityPublicKey());
626
572
  const pendingTransfers = await this.transferService.queryPendingTransfers();
627
573
  if (pendingTransfers.transfers.length > 0) {
628
574
  // @ts-ignore - We check the length, so the first element is guaranteed to exist
@@ -634,55 +580,32 @@ export class SparkWallet {
634
580
  /**
635
581
  * Sends a transfer to another Spark user.
636
582
  *
637
- * @param {Object} params - Parameters for the transfer
583
+ * @param {TransferParams} params - Parameters for the transfer
638
584
  * @param {string} params.receiverSparkAddress - The recipient's Spark address
639
585
  * @param {number} params.amountSats - Amount to send in satoshis
640
586
  * @returns {Promise<Transfer>} The completed transfer details
641
587
  */
642
- async sendSparkTransfer({ receiverSparkAddress, amountSats, }) {
588
+ async transfer({ amountSats, receiverSparkAddress }) {
643
589
  return await this.withLeaves(async () => {
644
- return await this._sendTransfer({
645
- receiverPubKey: receiverSparkAddress,
646
- amount: amountSats,
647
- });
590
+ const leavesToSend = await this.selectLeaves(amountSats);
591
+ await this.refreshTimelockNodes();
592
+ const leafKeyTweaks = await Promise.all(leavesToSend.map(async (leaf) => ({
593
+ leaf,
594
+ signingPubKey: await this.config.signer.generatePublicKey(sha256(leaf.id)),
595
+ newSigningPubKey: await this.config.signer.generatePublicKey(),
596
+ })));
597
+ const transfer = await this.transferService.sendTransfer(leafKeyTweaks, hexToBytes(receiverSparkAddress));
598
+ const leavesToRemove = new Set(leavesToSend.map((leaf) => leaf.id));
599
+ this.leaves = this.leaves.filter((leaf) => !leavesToRemove.has(leaf.id));
600
+ return transfer;
648
601
  });
649
602
  }
650
- /**
651
- * Internal method to send a transfer.
652
- *
653
- * @param {SendTransferParams} params - Parameters for the transfer
654
- * @returns {Promise<Transfer>} The completed transfer details
655
- * @private
656
- */
657
- async _sendTransfer({ amount, receiverPubKey, leaves, expiryTime = new Date(Date.now() + 10 * 60 * 1000), }) {
658
- let leavesToSend = [];
659
- if (leaves) {
660
- leavesToSend = leaves.map((leaf) => ({
661
- ...leaf,
662
- }));
663
- }
664
- else if (amount) {
665
- leavesToSend = await this.selectLeaves(amount);
666
- }
667
- else {
668
- throw new Error("Must provide amount or leaves");
669
- }
670
- await this.refreshTimelockNodes();
671
- const leafKeyTweaks = await Promise.all(leavesToSend.map(async (leaf) => ({
672
- leaf,
673
- signingPubKey: await this.config.signer.generatePublicKey(sha256(leaf.id)),
674
- newSigningPubKey: await this.config.signer.generatePublicKey(),
675
- })));
676
- const transfer = await this.transferService.sendTransfer(leafKeyTweaks, hexToBytes(receiverPubKey), expiryTime);
677
- const leavesToRemove = new Set(leavesToSend.map((leaf) => leaf.id));
678
- this.leaves = this.leaves.filter((leaf) => !leavesToRemove.has(leaf.id));
679
- return transfer;
680
- }
681
603
  /**
682
604
  * Internal method to refresh timelock nodes.
683
605
  *
684
606
  * @param {string} nodeId - The optional ID of the node to refresh. If not provided, all nodes will be checked.
685
607
  * @returns {Promise<void>}
608
+ * @private
686
609
  */
687
610
  async refreshTimelockNodes(nodeId) {
688
611
  const nodesToRefresh = [];
@@ -747,12 +670,19 @@ export class SparkWallet {
747
670
  this.leaves.push(newNode);
748
671
  }
749
672
  }
673
+ /**
674
+ * Gets all pending transfers.
675
+ *
676
+ * @returns {Promise<Transfer[]>} The pending transfers
677
+ */
678
+ async getPendingTransfers() {
679
+ return (await this.transferService.queryPendingTransfers()).transfers;
680
+ }
750
681
  /**
751
682
  * Claims a specific transfer.
752
683
  *
753
684
  * @param {Transfer} transfer - The transfer to claim
754
685
  * @returns {Promise<Object>} The claim result
755
- * @private
756
686
  */
757
687
  async claimTransfer(transfer) {
758
688
  return await this.claimTransferMutex.runExclusive(async () => {
@@ -780,7 +710,6 @@ export class SparkWallet {
780
710
  * Claims all pending transfers.
781
711
  *
782
712
  * @returns {Promise<boolean>} True if any transfers were claimed
783
- * @private
784
713
  */
785
714
  async claimTransfers() {
786
715
  const transfers = await this.transferService.queryPendingTransfers();
@@ -805,10 +734,12 @@ export class SparkWallet {
805
734
  * @private
806
735
  */
807
736
  async cancelAllSenderInitiatedTransfers() {
808
- const transfers = await this.transferService.queryPendingTransfersBySender();
809
- for (const transfer of transfers.transfers) {
810
- if (transfer.status === TransferStatus.TRANSFER_STATUS_SENDER_INITIATED) {
811
- await this.transferService.cancelSendTransfer(transfer);
737
+ for (const operator of Object.values(this.config.getSigningOperators())) {
738
+ const transfers = await this.transferService.queryPendingTransfersBySender(operator.address);
739
+ for (const transfer of transfers.transfers) {
740
+ if (transfer.status === TransferStatus.TRANSFER_STATUS_SENDER_INITIATED) {
741
+ await this.transferService.cancelSendTransfer(transfer, operator.address);
742
+ }
812
743
  }
813
744
  }
814
745
  }
@@ -908,7 +839,6 @@ export class SparkWallet {
908
839
  *
909
840
  * @param {LightningReceiveFeeEstimateInput} params - Input parameters for fee estimation
910
841
  * @returns {Promise<LightningReceiveFeeEstimateOutput | null>} Fee estimate for receiving Lightning payments
911
- * @private
912
842
  */
913
843
  async getLightningReceiveFeeEstimate({ amountSats, network, }) {
914
844
  if (!this.sspClient) {
@@ -921,7 +851,6 @@ export class SparkWallet {
921
851
  *
922
852
  * @param {LightningSendFeeEstimateInput} params - Input parameters for fee estimation
923
853
  * @returns {Promise<LightningSendFeeEstimateOutput | null>} Fee estimate for sending Lightning payments
924
- * @private
925
854
  */
926
855
  async getLightningSendFeeEstimate({ encodedInvoice, }) {
927
856
  if (!this.sspClient) {
@@ -1032,7 +961,6 @@ export class SparkWallet {
1032
961
  *
1033
962
  * @param {CoopExitFeeEstimateInput} params - Input parameters for fee estimation
1034
963
  * @returns {Promise<CoopExitFeeEstimateOutput | null>} Fee estimate for the withdrawal
1035
- * @private
1036
964
  */
1037
965
  async getCoopExitFeeEstimate({ leafExternalIds, withdrawalAddress, }) {
1038
966
  if (!this.sspClient) {