@arkade-os/boltz-swap 0.1.4 → 0.1.8

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/README.md CHANGED
@@ -25,7 +25,7 @@ npm install @arkade-os/sdk @arkade-os/boltz-swap
25
25
 
26
26
  ```typescript
27
27
  import { Wallet } from '@arkade-os/sdk';
28
- import { ArkadeLightning, BoltzSwapProvider } from '@arkade-os/boltz-swap';
28
+ import { ArkadeLightning, BoltzSwapProvider, StorageProvider } from '@arkade-os/boltz-swap';
29
29
 
30
30
  // Initialize your Arkade wallet
31
31
  const wallet = await Wallet.create({
@@ -39,8 +39,8 @@ const swapProvider = new BoltzSwapProvider({
39
39
  network: 'mutinynet',
40
40
  });
41
41
 
42
- // Optionaly: initialize a storage provider
43
- const storageProvider = StorageProvider.create();
42
+ // Optionally: initialize a storage provider
43
+ const storageProvider = await StorageProvider.create();
44
44
 
45
45
  // Create the ArkadeLightning instance
46
46
  const arkadeLightning = new ArkadeLightning({
@@ -50,6 +50,49 @@ const arkadeLightning = new ArkadeLightning({
50
50
  });
51
51
  ```
52
52
 
53
+ ## Wallet class Compatibility
54
+
55
+ This library supports both wallet interface patterns:
56
+
57
+ ### Wallet (with optional nested identity and providers)
58
+
59
+ ```typescript
60
+ import { Wallet } from '@arkade-os/sdk';
61
+
62
+ const wallet = await Wallet.create({
63
+ identity,
64
+ arkServerUrl: 'https://mutinynet.arkade.sh',
65
+ });
66
+
67
+ // Wallet may have built-in providers
68
+ const arkadeLightning = new ArkadeLightning({
69
+ wallet,
70
+ swapProvider,
71
+ // arkProvider and indexerProvider can be provided here if wallet doesn't have them
72
+ });
73
+ ```
74
+
75
+ ### ServiceWorkerWallet (legacy interface)
76
+
77
+ ```typescript
78
+ import { RestArkProvider, RestIndexerProvider } from '@arkade-os/sdk';
79
+
80
+ // ServiceWorkerWallet has identity methods spread directly (no nested identity)
81
+ const serviceWorkerWallet = new ServiceWorkerWallet(serviceWorker);
82
+ await serviceWorkerWallet.init({
83
+ privateKey: 'your_private_key_hex',
84
+ arkServerUrl: 'https://ark.example.com'
85
+ });
86
+
87
+ // Must provide external providers for ServiceWorkerWallet (it doesn't have them)
88
+ const arkadeLightning = new ArkadeLightning({
89
+ wallet: serviceWorkerWallet,
90
+ arkProvider: new RestArkProvider('https://ark.example.com'),
91
+ indexerProvider: new RestIndexerProvider('https://indexer.example.com'),
92
+ swapProvider,
93
+ });
94
+ ```
95
+
53
96
  ## Storage
54
97
 
55
98
  By default this library doesn't store pending swaps.
@@ -57,7 +100,7 @@ By default this library doesn't store pending swaps.
57
100
  If you need it you must initialize a storageProvider:
58
101
 
59
102
  ```typescript
60
- const storageProvider = StorageProvider.create({ storagePath: './storage.json' });
103
+ const storageProvider = await StorageProvider.create({ storagePath: './storage.json' });
61
104
 
62
105
  const arkadeLightning = new ArkadeLightning({
63
106
  wallet,
@@ -109,14 +152,16 @@ console.log('Transaction ID:', receivalResult.txid);
109
152
  To send a payment from your Arkade wallet to a Lightning invoice:
110
153
 
111
154
  ```typescript
155
+ import { decodeInvoice } from '@arkade-os/boltz-swap';
156
+
112
157
  // Parse a Lightning invoice
113
- const invoiceDetails = await arkadeLightning.decodeInvoice(
158
+ const invoiceDetails = decodeInvoice(
114
159
  'lnbc500u1pj...' // Lightning invoice string
115
160
  );
116
161
 
117
162
  console.log('Invoice amount:', invoiceDetails.amountSats, 'sats');
118
163
  console.log('Description:', invoiceDetails.description);
119
- console.log('Destination:', invoiceDetails.destination);
164
+ console.log('Payment Hash:', invoiceDetails.paymentHash);
120
165
 
121
166
  // Pay the Lightning invoice from your Arkade wallet
122
167
  const paymentResult = await arkadeLightning.sendLightningPayment({
package/dist/index.cjs CHANGED
@@ -34,9 +34,13 @@ __export(index_exports, {
34
34
  BoltzSwapProvider: () => BoltzSwapProvider,
35
35
  InsufficientFundsError: () => InsufficientFundsError,
36
36
  InvoiceExpiredError: () => InvoiceExpiredError,
37
+ InvoiceFailedToPayError: () => InvoiceFailedToPayError,
37
38
  NetworkError: () => NetworkError,
39
+ SchemaError: () => SchemaError,
38
40
  StorageProvider: () => StorageProvider,
39
41
  SwapError: () => SwapError,
42
+ SwapExpiredError: () => SwapExpiredError,
43
+ TransactionFailedError: () => TransactionFailedError,
40
44
  decodeInvoice: () => decodeInvoice,
41
45
  getInvoicePaymentHash: () => getInvoicePaymentHash,
42
46
  getInvoiceSatoshis: () => getInvoiceSatoshis
@@ -115,6 +119,11 @@ var TransactionRefundedError = class extends SwapError {
115
119
  var import_sdk = require("@arkade-os/sdk");
116
120
  var import_sha2 = require("@noble/hashes/sha2");
117
121
  var import_base = require("@scure/base");
122
+
123
+ // src/types.ts
124
+ var isWalletWithNestedIdentity = (w) => !!w.identity && typeof w.identity?.xOnlyPublicKey === "function";
125
+
126
+ // src/arkade-lightning.ts
118
127
  var import_utils = require("@noble/hashes/utils");
119
128
  var import_btc_signer = require("@scure/btc-signer");
120
129
  var import_legacy = require("@noble/hashes/legacy");
@@ -139,6 +148,26 @@ var getInvoicePaymentHash = (invoice) => {
139
148
  };
140
149
 
141
150
  // src/arkade-lightning.ts
151
+ function getIdentity(wallet) {
152
+ if (isWalletWithNestedIdentity(wallet)) {
153
+ return wallet.identity;
154
+ }
155
+ return wallet;
156
+ }
157
+ function getXOnlyPublicKey(wallet) {
158
+ return getIdentity(wallet).xOnlyPublicKey();
159
+ }
160
+ function getSignerSession(wallet) {
161
+ const identity = getIdentity(wallet);
162
+ const signerSession = identity?.signerSession;
163
+ if (typeof signerSession === "function") {
164
+ return signerSession();
165
+ }
166
+ return signerSession;
167
+ }
168
+ async function signTransaction(wallet, tx, inputIndexes) {
169
+ return getIdentity(wallet).sign(tx, inputIndexes);
170
+ }
142
171
  var ArkadeLightning = class {
143
172
  wallet;
144
173
  arkProvider;
@@ -147,14 +176,16 @@ var ArkadeLightning = class {
147
176
  indexerProvider;
148
177
  constructor(config) {
149
178
  if (!config.wallet) throw new Error("Wallet is required.");
150
- if (!config.arkProvider) throw new Error("Ark provider is required.");
151
179
  if (!config.swapProvider) throw new Error("Swap provider is required.");
152
- if (!config.indexerProvider) throw new Error("Indexer provider is required.");
153
180
  this.wallet = config.wallet;
154
- this.arkProvider = config.arkProvider;
181
+ const arkProvider = config.wallet.arkProvider ?? config.arkProvider;
182
+ if (!arkProvider) throw new Error("Ark provider is required either in wallet or config.");
183
+ this.arkProvider = arkProvider;
184
+ const indexerProvider = config.wallet.indexerProvider ?? config.indexerProvider;
185
+ if (!indexerProvider) throw new Error("Indexer provider is required either in wallet or config.");
186
+ this.indexerProvider = indexerProvider;
155
187
  this.swapProvider = config.swapProvider;
156
188
  this.storageProvider = config.storageProvider ?? null;
157
- this.indexerProvider = config.indexerProvider;
158
189
  }
159
190
  // receive from lightning = reverse submarine swap
160
191
  //
@@ -189,10 +220,10 @@ var ArkadeLightning = class {
189
220
  async sendLightningPayment(args) {
190
221
  return new Promise((resolve, reject) => {
191
222
  this.createSubmarineSwap(args).then((pendingSwap) => {
192
- if (args.maxFeeSats) {
193
- const invoiceAmount = decodeInvoice(args.invoice).amountSats;
223
+ if (args.maxFeeSats != null) {
224
+ const invoiceAmount = decodeInvoice(args.invoice).amountSats ?? 0;
194
225
  const fees = pendingSwap.response.expectedAmount - invoiceAmount;
195
- if (fees > args.maxFeeSats) {
226
+ if (invoiceAmount > 0 && fees > args.maxFeeSats) {
196
227
  reject(new SwapError({ message: `Swap fees ${fees} exceed max allowed ${args.maxFeeSats}` }));
197
228
  }
198
229
  }
@@ -218,7 +249,7 @@ var ArkadeLightning = class {
218
249
  }
219
250
  // create submarine swap
220
251
  async createSubmarineSwap(args) {
221
- const refundPublicKey = import_base.hex.encode(this.wallet.xOnlyPublicKey());
252
+ const refundPublicKey = import_base.hex.encode(getXOnlyPublicKey(this.wallet));
222
253
  if (!refundPublicKey) throw new SwapError({ message: "Failed to get refund public key from wallet" });
223
254
  const invoice = args.invoice;
224
255
  if (!invoice) throw new SwapError({ message: "Invoice is required" });
@@ -240,7 +271,7 @@ var ArkadeLightning = class {
240
271
  // create reverse submarine swap
241
272
  async createReverseSwap(args) {
242
273
  if (args.amount <= 0) throw new SwapError({ message: "Amount must be greater than 0" });
243
- const claimPublicKey = import_base.hex.encode(this.wallet.xOnlyPublicKey());
274
+ const claimPublicKey = import_base.hex.encode(getXOnlyPublicKey(this.wallet));
244
275
  if (!claimPublicKey) throw new SwapError({ message: "Failed to get claim public key from wallet" });
245
276
  const preimage = (0, import_utils.randomBytes)(32);
246
277
  const preimageHash = import_base.hex.encode((0, import_sha2.sha256)(preimage));
@@ -267,7 +298,7 @@ var ArkadeLightning = class {
267
298
  const preimage = import_base.hex.decode(pendingSwap.preimage);
268
299
  const aspInfo = await this.arkProvider.getInfo();
269
300
  const address = await this.wallet.getAddress();
270
- let receiverXOnlyPublicKey = this.wallet.xOnlyPublicKey();
301
+ let receiverXOnlyPublicKey = getXOnlyPublicKey(this.wallet);
271
302
  if (receiverXOnlyPublicKey.length == 33) {
272
303
  receiverXOnlyPublicKey = receiverXOnlyPublicKey.slice(1);
273
304
  } else if (receiverXOnlyPublicKey.length !== 32) {
@@ -298,13 +329,13 @@ var ArkadeLightning = class {
298
329
  const vhtlcIdentity = {
299
330
  sign: async (tx, inputIndexes) => {
300
331
  const cpy = tx.clone();
301
- let signedTx = await this.wallet.sign(cpy, inputIndexes);
332
+ let signedTx = await signTransaction(this.wallet, cpy, inputIndexes);
302
333
  signedTx = import_btc_signer.Transaction.fromPSBT(signedTx.toPSBT(), { allowUnknown: true });
303
334
  (0, import_sdk.setArkPsbtField)(signedTx, 0, import_sdk.ConditionWitness, [preimage]);
304
335
  return signedTx;
305
336
  },
306
337
  xOnlyPublicKey: receiverXOnlyPublicKey,
307
- signerSession: this.wallet.signerSession
338
+ signerSession: getSignerSession(this.wallet)
308
339
  };
309
340
  const serverUnrollScript = import_sdk.CSVMultisigTapscript.encode({
310
341
  pubkeys: [serverXOnlyPublicKey],
@@ -356,7 +387,7 @@ var ArkadeLightning = class {
356
387
  const aspInfo = await this.arkProvider.getInfo();
357
388
  const address = await this.wallet.getAddress();
358
389
  if (!address) throw new Error("Failed to get ark address from service worker wallet");
359
- let receiverXOnlyPublicKey = this.wallet.xOnlyPublicKey();
390
+ let receiverXOnlyPublicKey = getXOnlyPublicKey(this.wallet);
360
391
  if (receiverXOnlyPublicKey.length == 33) {
361
392
  receiverXOnlyPublicKey = receiverXOnlyPublicKey.slice(1);
362
393
  } else if (receiverXOnlyPublicKey.length !== 32) {
@@ -372,7 +403,7 @@ var ArkadeLightning = class {
372
403
  network: aspInfo.network,
373
404
  preimageHash: import_base.hex.decode(getInvoicePaymentHash(pendingSwap.request.invoice)),
374
405
  receiverPubkey: pendingSwap.response.claimPublicKey,
375
- senderPubkey: import_base.hex.encode(this.wallet.xOnlyPublicKey()),
406
+ senderPubkey: import_base.hex.encode(getXOnlyPublicKey(this.wallet)),
376
407
  serverPubkey: aspInfo.signerPubkey,
377
408
  timeoutBlockHeights: pendingSwap.response.timeoutBlockHeights
378
409
  });
@@ -388,11 +419,11 @@ var ArkadeLightning = class {
388
419
  const vhtlcIdentity = {
389
420
  sign: async (tx, inputIndexes) => {
390
421
  const cpy = tx.clone();
391
- let signedTx = await this.wallet.sign(cpy, inputIndexes);
422
+ let signedTx = await signTransaction(this.wallet, cpy, inputIndexes);
392
423
  return import_btc_signer.Transaction.fromPSBT(signedTx.toPSBT(), { allowUnknown: true });
393
424
  },
394
425
  xOnlyPublicKey: receiverXOnlyPublicKey,
395
- signerSession: this.wallet.signerSession
426
+ signerSession: getSignerSession(this.wallet)
396
427
  };
397
428
  const serverUnrollScript = import_sdk.CSVMultisigTapscript.encode({
398
429
  pubkeys: [serverXOnlyPublicKey],
@@ -486,23 +517,28 @@ var ArkadeLightning = class {
486
517
  */
487
518
  async waitForSwapSettlement(pendingSwap) {
488
519
  return new Promise((resolve, reject) => {
520
+ let isResolved = false;
489
521
  const onStatusUpdate = async (status) => {
522
+ if (isResolved) return;
490
523
  switch (status) {
491
524
  case "swap.expired":
525
+ isResolved = true;
492
526
  this.storageProvider?.savePendingSubmarineSwap({ ...pendingSwap, status });
493
527
  reject(new SwapExpiredError({ isRefundable: true, pendingSwap }));
494
528
  break;
495
529
  case "invoice.failedToPay":
530
+ isResolved = true;
496
531
  this.storageProvider?.savePendingSubmarineSwap({ ...pendingSwap, status });
497
532
  reject(new InvoiceFailedToPayError({ isRefundable: true, pendingSwap }));
498
533
  break;
499
534
  case "transaction.lockupFailed":
535
+ isResolved = true;
500
536
  this.storageProvider?.savePendingSubmarineSwap({ ...pendingSwap, status });
501
537
  reject(new TransactionLockupFailedError({ isRefundable: true, pendingSwap }));
502
538
  break;
503
539
  case "transaction.claimed": {
540
+ isResolved = true;
504
541
  const { preimage } = await this.swapProvider.getSwapPreimage(pendingSwap.response.id);
505
- console.log("preimage returned", { preimage });
506
542
  this.storageProvider?.savePendingSubmarineSwap({ ...pendingSwap, preimage, status });
507
543
  resolve({ preimage });
508
544
  break;
@@ -512,7 +548,12 @@ var ArkadeLightning = class {
512
548
  break;
513
549
  }
514
550
  };
515
- this.swapProvider.monitorSwap(pendingSwap.response.id, onStatusUpdate);
551
+ this.swapProvider.monitorSwap(pendingSwap.response.id, onStatusUpdate).catch((error) => {
552
+ if (!isResolved) {
553
+ isResolved = true;
554
+ reject(error);
555
+ }
556
+ });
516
557
  });
517
558
  }
518
559
  // validators
@@ -1002,9 +1043,13 @@ var BoltzSwapProvider = class {
1002
1043
  BoltzSwapProvider,
1003
1044
  InsufficientFundsError,
1004
1045
  InvoiceExpiredError,
1046
+ InvoiceFailedToPayError,
1005
1047
  NetworkError,
1048
+ SchemaError,
1006
1049
  StorageProvider,
1007
1050
  SwapError,
1051
+ SwapExpiredError,
1052
+ TransactionFailedError,
1008
1053
  decodeInvoice,
1009
1054
  getInvoicePaymentHash,
1010
1055
  getInvoiceSatoshis
package/dist/index.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { IWallet, Identity, RestArkProvider, RestIndexerProvider, VHTLC } from '@arkade-os/sdk';
1
+ import { IWallet, ArkProvider, IndexerProvider, Identity, VHTLC } from '@arkade-os/sdk';
2
2
 
3
3
  interface StorageOptions {
4
4
  storagePath?: string;
@@ -119,13 +119,20 @@ interface Vtxo {
119
119
  locktime: number;
120
120
  };
121
121
  }
122
- type Wallet = IWallet & Identity;
122
+ type WalletWithNestedIdentity = IWallet & {
123
+ arkProvider?: ArkProvider;
124
+ indexerProvider?: IndexerProvider;
125
+ identity: Identity;
126
+ };
127
+ type ServiceWorkerWallet = IWallet & Identity;
128
+ type Wallet = WalletWithNestedIdentity | ServiceWorkerWallet;
123
129
  type Network = 'bitcoin' | 'mutinynet' | 'regtest' | 'testnet';
124
130
  interface CreateLightningInvoiceRequest {
125
131
  amount: number;
126
132
  description?: string;
127
133
  }
128
134
  interface CreateLightningInvoiceResponse {
135
+ amount: number;
129
136
  expiry: number;
130
137
  invoice: string;
131
138
  paymentHash: string;
@@ -162,9 +169,9 @@ interface RefundHandler {
162
169
  }
163
170
  interface ArkadeLightningConfig {
164
171
  wallet: Wallet;
165
- arkProvider: RestArkProvider;
172
+ arkProvider?: ArkProvider;
166
173
  swapProvider: BoltzSwapProvider;
167
- indexerProvider: RestIndexerProvider;
174
+ indexerProvider?: IndexerProvider;
168
175
  feeConfig?: Partial<FeeConfig>;
169
176
  refundHandler?: RefundHandler;
170
177
  storageProvider?: StorageProvider | null;
@@ -316,12 +323,24 @@ declare class SwapError extends Error {
316
323
  declare class InvoiceExpiredError extends SwapError {
317
324
  constructor(options: ErrorOptions);
318
325
  }
326
+ declare class InvoiceFailedToPayError extends SwapError {
327
+ constructor(options: ErrorOptions);
328
+ }
319
329
  declare class InsufficientFundsError extends SwapError {
320
330
  constructor(options?: ErrorOptions);
321
331
  }
322
332
  declare class NetworkError extends Error {
323
333
  constructor(message: string);
324
334
  }
335
+ declare class SchemaError extends SwapError {
336
+ constructor(options?: ErrorOptions);
337
+ }
338
+ declare class SwapExpiredError extends SwapError {
339
+ constructor(options: ErrorOptions);
340
+ }
341
+ declare class TransactionFailedError extends SwapError {
342
+ constructor(options?: ErrorOptions);
343
+ }
325
344
 
326
345
  /**
327
346
  * Decodes a Lightning invoice.
@@ -332,4 +351,4 @@ declare const decodeInvoice: (invoice: string) => DecodedInvoice;
332
351
  declare const getInvoiceSatoshis: (invoice: string) => number;
333
352
  declare const getInvoicePaymentHash: (invoice: string) => string;
334
353
 
335
- export { ArkadeLightning, type ArkadeLightningConfig, BoltzSwapProvider, type BoltzSwapStatus, type CreateLightningInvoiceResponse, type DecodedInvoice, type FeeConfig, type IncomingPaymentSubscription, InsufficientFundsError, InvoiceExpiredError, type LimitsResponse, type Network, NetworkError, type PendingReverseSwap, type PendingSubmarineSwap, type RefundHandler, type RetryConfig, type SendLightningPaymentRequest, type SendLightningPaymentResponse, StorageProvider, SwapError, type TimeoutConfig, type Vtxo, type Wallet, decodeInvoice, getInvoicePaymentHash, getInvoiceSatoshis };
354
+ export { ArkadeLightning, type ArkadeLightningConfig, BoltzSwapProvider, type BoltzSwapStatus, type CreateLightningInvoiceResponse, type DecodedInvoice, type FeeConfig, type IncomingPaymentSubscription, InsufficientFundsError, InvoiceExpiredError, InvoiceFailedToPayError, type LimitsResponse, type Network, NetworkError, type PendingReverseSwap, type PendingSubmarineSwap, type RefundHandler, type RetryConfig, SchemaError, type SendLightningPaymentRequest, type SendLightningPaymentResponse, StorageProvider, SwapError, SwapExpiredError, type TimeoutConfig, TransactionFailedError, type Vtxo, type Wallet, decodeInvoice, getInvoicePaymentHash, getInvoiceSatoshis };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { IWallet, Identity, RestArkProvider, RestIndexerProvider, VHTLC } from '@arkade-os/sdk';
1
+ import { IWallet, ArkProvider, IndexerProvider, Identity, VHTLC } from '@arkade-os/sdk';
2
2
 
3
3
  interface StorageOptions {
4
4
  storagePath?: string;
@@ -119,13 +119,20 @@ interface Vtxo {
119
119
  locktime: number;
120
120
  };
121
121
  }
122
- type Wallet = IWallet & Identity;
122
+ type WalletWithNestedIdentity = IWallet & {
123
+ arkProvider?: ArkProvider;
124
+ indexerProvider?: IndexerProvider;
125
+ identity: Identity;
126
+ };
127
+ type ServiceWorkerWallet = IWallet & Identity;
128
+ type Wallet = WalletWithNestedIdentity | ServiceWorkerWallet;
123
129
  type Network = 'bitcoin' | 'mutinynet' | 'regtest' | 'testnet';
124
130
  interface CreateLightningInvoiceRequest {
125
131
  amount: number;
126
132
  description?: string;
127
133
  }
128
134
  interface CreateLightningInvoiceResponse {
135
+ amount: number;
129
136
  expiry: number;
130
137
  invoice: string;
131
138
  paymentHash: string;
@@ -162,9 +169,9 @@ interface RefundHandler {
162
169
  }
163
170
  interface ArkadeLightningConfig {
164
171
  wallet: Wallet;
165
- arkProvider: RestArkProvider;
172
+ arkProvider?: ArkProvider;
166
173
  swapProvider: BoltzSwapProvider;
167
- indexerProvider: RestIndexerProvider;
174
+ indexerProvider?: IndexerProvider;
168
175
  feeConfig?: Partial<FeeConfig>;
169
176
  refundHandler?: RefundHandler;
170
177
  storageProvider?: StorageProvider | null;
@@ -316,12 +323,24 @@ declare class SwapError extends Error {
316
323
  declare class InvoiceExpiredError extends SwapError {
317
324
  constructor(options: ErrorOptions);
318
325
  }
326
+ declare class InvoiceFailedToPayError extends SwapError {
327
+ constructor(options: ErrorOptions);
328
+ }
319
329
  declare class InsufficientFundsError extends SwapError {
320
330
  constructor(options?: ErrorOptions);
321
331
  }
322
332
  declare class NetworkError extends Error {
323
333
  constructor(message: string);
324
334
  }
335
+ declare class SchemaError extends SwapError {
336
+ constructor(options?: ErrorOptions);
337
+ }
338
+ declare class SwapExpiredError extends SwapError {
339
+ constructor(options: ErrorOptions);
340
+ }
341
+ declare class TransactionFailedError extends SwapError {
342
+ constructor(options?: ErrorOptions);
343
+ }
325
344
 
326
345
  /**
327
346
  * Decodes a Lightning invoice.
@@ -332,4 +351,4 @@ declare const decodeInvoice: (invoice: string) => DecodedInvoice;
332
351
  declare const getInvoiceSatoshis: (invoice: string) => number;
333
352
  declare const getInvoicePaymentHash: (invoice: string) => string;
334
353
 
335
- export { ArkadeLightning, type ArkadeLightningConfig, BoltzSwapProvider, type BoltzSwapStatus, type CreateLightningInvoiceResponse, type DecodedInvoice, type FeeConfig, type IncomingPaymentSubscription, InsufficientFundsError, InvoiceExpiredError, type LimitsResponse, type Network, NetworkError, type PendingReverseSwap, type PendingSubmarineSwap, type RefundHandler, type RetryConfig, type SendLightningPaymentRequest, type SendLightningPaymentResponse, StorageProvider, SwapError, type TimeoutConfig, type Vtxo, type Wallet, decodeInvoice, getInvoicePaymentHash, getInvoiceSatoshis };
354
+ export { ArkadeLightning, type ArkadeLightningConfig, BoltzSwapProvider, type BoltzSwapStatus, type CreateLightningInvoiceResponse, type DecodedInvoice, type FeeConfig, type IncomingPaymentSubscription, InsufficientFundsError, InvoiceExpiredError, InvoiceFailedToPayError, type LimitsResponse, type Network, NetworkError, type PendingReverseSwap, type PendingSubmarineSwap, type RefundHandler, type RetryConfig, SchemaError, type SendLightningPaymentRequest, type SendLightningPaymentResponse, StorageProvider, SwapError, SwapExpiredError, type TimeoutConfig, TransactionFailedError, type Vtxo, type Wallet, decodeInvoice, getInvoicePaymentHash, getInvoiceSatoshis };
package/dist/index.js CHANGED
@@ -77,6 +77,11 @@ import {
77
77
  } from "@arkade-os/sdk";
78
78
  import { sha256 } from "@noble/hashes/sha2";
79
79
  import { base64, hex } from "@scure/base";
80
+
81
+ // src/types.ts
82
+ var isWalletWithNestedIdentity = (w) => !!w.identity && typeof w.identity?.xOnlyPublicKey === "function";
83
+
84
+ // src/arkade-lightning.ts
80
85
  import { randomBytes } from "@noble/hashes/utils";
81
86
  import { Transaction } from "@scure/btc-signer";
82
87
  import { ripemd160 } from "@noble/hashes/legacy";
@@ -101,6 +106,26 @@ var getInvoicePaymentHash = (invoice) => {
101
106
  };
102
107
 
103
108
  // src/arkade-lightning.ts
109
+ function getIdentity(wallet) {
110
+ if (isWalletWithNestedIdentity(wallet)) {
111
+ return wallet.identity;
112
+ }
113
+ return wallet;
114
+ }
115
+ function getXOnlyPublicKey(wallet) {
116
+ return getIdentity(wallet).xOnlyPublicKey();
117
+ }
118
+ function getSignerSession(wallet) {
119
+ const identity = getIdentity(wallet);
120
+ const signerSession = identity?.signerSession;
121
+ if (typeof signerSession === "function") {
122
+ return signerSession();
123
+ }
124
+ return signerSession;
125
+ }
126
+ async function signTransaction(wallet, tx, inputIndexes) {
127
+ return getIdentity(wallet).sign(tx, inputIndexes);
128
+ }
104
129
  var ArkadeLightning = class {
105
130
  wallet;
106
131
  arkProvider;
@@ -109,14 +134,16 @@ var ArkadeLightning = class {
109
134
  indexerProvider;
110
135
  constructor(config) {
111
136
  if (!config.wallet) throw new Error("Wallet is required.");
112
- if (!config.arkProvider) throw new Error("Ark provider is required.");
113
137
  if (!config.swapProvider) throw new Error("Swap provider is required.");
114
- if (!config.indexerProvider) throw new Error("Indexer provider is required.");
115
138
  this.wallet = config.wallet;
116
- this.arkProvider = config.arkProvider;
139
+ const arkProvider = config.wallet.arkProvider ?? config.arkProvider;
140
+ if (!arkProvider) throw new Error("Ark provider is required either in wallet or config.");
141
+ this.arkProvider = arkProvider;
142
+ const indexerProvider = config.wallet.indexerProvider ?? config.indexerProvider;
143
+ if (!indexerProvider) throw new Error("Indexer provider is required either in wallet or config.");
144
+ this.indexerProvider = indexerProvider;
117
145
  this.swapProvider = config.swapProvider;
118
146
  this.storageProvider = config.storageProvider ?? null;
119
- this.indexerProvider = config.indexerProvider;
120
147
  }
121
148
  // receive from lightning = reverse submarine swap
122
149
  //
@@ -151,10 +178,10 @@ var ArkadeLightning = class {
151
178
  async sendLightningPayment(args) {
152
179
  return new Promise((resolve, reject) => {
153
180
  this.createSubmarineSwap(args).then((pendingSwap) => {
154
- if (args.maxFeeSats) {
155
- const invoiceAmount = decodeInvoice(args.invoice).amountSats;
181
+ if (args.maxFeeSats != null) {
182
+ const invoiceAmount = decodeInvoice(args.invoice).amountSats ?? 0;
156
183
  const fees = pendingSwap.response.expectedAmount - invoiceAmount;
157
- if (fees > args.maxFeeSats) {
184
+ if (invoiceAmount > 0 && fees > args.maxFeeSats) {
158
185
  reject(new SwapError({ message: `Swap fees ${fees} exceed max allowed ${args.maxFeeSats}` }));
159
186
  }
160
187
  }
@@ -180,7 +207,7 @@ var ArkadeLightning = class {
180
207
  }
181
208
  // create submarine swap
182
209
  async createSubmarineSwap(args) {
183
- const refundPublicKey = hex.encode(this.wallet.xOnlyPublicKey());
210
+ const refundPublicKey = hex.encode(getXOnlyPublicKey(this.wallet));
184
211
  if (!refundPublicKey) throw new SwapError({ message: "Failed to get refund public key from wallet" });
185
212
  const invoice = args.invoice;
186
213
  if (!invoice) throw new SwapError({ message: "Invoice is required" });
@@ -202,7 +229,7 @@ var ArkadeLightning = class {
202
229
  // create reverse submarine swap
203
230
  async createReverseSwap(args) {
204
231
  if (args.amount <= 0) throw new SwapError({ message: "Amount must be greater than 0" });
205
- const claimPublicKey = hex.encode(this.wallet.xOnlyPublicKey());
232
+ const claimPublicKey = hex.encode(getXOnlyPublicKey(this.wallet));
206
233
  if (!claimPublicKey) throw new SwapError({ message: "Failed to get claim public key from wallet" });
207
234
  const preimage = randomBytes(32);
208
235
  const preimageHash = hex.encode(sha256(preimage));
@@ -229,7 +256,7 @@ var ArkadeLightning = class {
229
256
  const preimage = hex.decode(pendingSwap.preimage);
230
257
  const aspInfo = await this.arkProvider.getInfo();
231
258
  const address = await this.wallet.getAddress();
232
- let receiverXOnlyPublicKey = this.wallet.xOnlyPublicKey();
259
+ let receiverXOnlyPublicKey = getXOnlyPublicKey(this.wallet);
233
260
  if (receiverXOnlyPublicKey.length == 33) {
234
261
  receiverXOnlyPublicKey = receiverXOnlyPublicKey.slice(1);
235
262
  } else if (receiverXOnlyPublicKey.length !== 32) {
@@ -260,13 +287,13 @@ var ArkadeLightning = class {
260
287
  const vhtlcIdentity = {
261
288
  sign: async (tx, inputIndexes) => {
262
289
  const cpy = tx.clone();
263
- let signedTx = await this.wallet.sign(cpy, inputIndexes);
290
+ let signedTx = await signTransaction(this.wallet, cpy, inputIndexes);
264
291
  signedTx = Transaction.fromPSBT(signedTx.toPSBT(), { allowUnknown: true });
265
292
  setArkPsbtField(signedTx, 0, ConditionWitness, [preimage]);
266
293
  return signedTx;
267
294
  },
268
295
  xOnlyPublicKey: receiverXOnlyPublicKey,
269
- signerSession: this.wallet.signerSession
296
+ signerSession: getSignerSession(this.wallet)
270
297
  };
271
298
  const serverUnrollScript = CSVMultisigTapscript.encode({
272
299
  pubkeys: [serverXOnlyPublicKey],
@@ -318,7 +345,7 @@ var ArkadeLightning = class {
318
345
  const aspInfo = await this.arkProvider.getInfo();
319
346
  const address = await this.wallet.getAddress();
320
347
  if (!address) throw new Error("Failed to get ark address from service worker wallet");
321
- let receiverXOnlyPublicKey = this.wallet.xOnlyPublicKey();
348
+ let receiverXOnlyPublicKey = getXOnlyPublicKey(this.wallet);
322
349
  if (receiverXOnlyPublicKey.length == 33) {
323
350
  receiverXOnlyPublicKey = receiverXOnlyPublicKey.slice(1);
324
351
  } else if (receiverXOnlyPublicKey.length !== 32) {
@@ -334,7 +361,7 @@ var ArkadeLightning = class {
334
361
  network: aspInfo.network,
335
362
  preimageHash: hex.decode(getInvoicePaymentHash(pendingSwap.request.invoice)),
336
363
  receiverPubkey: pendingSwap.response.claimPublicKey,
337
- senderPubkey: hex.encode(this.wallet.xOnlyPublicKey()),
364
+ senderPubkey: hex.encode(getXOnlyPublicKey(this.wallet)),
338
365
  serverPubkey: aspInfo.signerPubkey,
339
366
  timeoutBlockHeights: pendingSwap.response.timeoutBlockHeights
340
367
  });
@@ -350,11 +377,11 @@ var ArkadeLightning = class {
350
377
  const vhtlcIdentity = {
351
378
  sign: async (tx, inputIndexes) => {
352
379
  const cpy = tx.clone();
353
- let signedTx = await this.wallet.sign(cpy, inputIndexes);
380
+ let signedTx = await signTransaction(this.wallet, cpy, inputIndexes);
354
381
  return Transaction.fromPSBT(signedTx.toPSBT(), { allowUnknown: true });
355
382
  },
356
383
  xOnlyPublicKey: receiverXOnlyPublicKey,
357
- signerSession: this.wallet.signerSession
384
+ signerSession: getSignerSession(this.wallet)
358
385
  };
359
386
  const serverUnrollScript = CSVMultisigTapscript.encode({
360
387
  pubkeys: [serverXOnlyPublicKey],
@@ -448,23 +475,28 @@ var ArkadeLightning = class {
448
475
  */
449
476
  async waitForSwapSettlement(pendingSwap) {
450
477
  return new Promise((resolve, reject) => {
478
+ let isResolved = false;
451
479
  const onStatusUpdate = async (status) => {
480
+ if (isResolved) return;
452
481
  switch (status) {
453
482
  case "swap.expired":
483
+ isResolved = true;
454
484
  this.storageProvider?.savePendingSubmarineSwap({ ...pendingSwap, status });
455
485
  reject(new SwapExpiredError({ isRefundable: true, pendingSwap }));
456
486
  break;
457
487
  case "invoice.failedToPay":
488
+ isResolved = true;
458
489
  this.storageProvider?.savePendingSubmarineSwap({ ...pendingSwap, status });
459
490
  reject(new InvoiceFailedToPayError({ isRefundable: true, pendingSwap }));
460
491
  break;
461
492
  case "transaction.lockupFailed":
493
+ isResolved = true;
462
494
  this.storageProvider?.savePendingSubmarineSwap({ ...pendingSwap, status });
463
495
  reject(new TransactionLockupFailedError({ isRefundable: true, pendingSwap }));
464
496
  break;
465
497
  case "transaction.claimed": {
498
+ isResolved = true;
466
499
  const { preimage } = await this.swapProvider.getSwapPreimage(pendingSwap.response.id);
467
- console.log("preimage returned", { preimage });
468
500
  this.storageProvider?.savePendingSubmarineSwap({ ...pendingSwap, preimage, status });
469
501
  resolve({ preimage });
470
502
  break;
@@ -474,7 +506,12 @@ var ArkadeLightning = class {
474
506
  break;
475
507
  }
476
508
  };
477
- this.swapProvider.monitorSwap(pendingSwap.response.id, onStatusUpdate);
509
+ this.swapProvider.monitorSwap(pendingSwap.response.id, onStatusUpdate).catch((error) => {
510
+ if (!isResolved) {
511
+ isResolved = true;
512
+ reject(error);
513
+ }
514
+ });
478
515
  });
479
516
  }
480
517
  // validators
@@ -963,9 +1000,13 @@ export {
963
1000
  BoltzSwapProvider,
964
1001
  InsufficientFundsError,
965
1002
  InvoiceExpiredError,
1003
+ InvoiceFailedToPayError,
966
1004
  NetworkError,
1005
+ SchemaError,
967
1006
  StorageProvider,
968
1007
  SwapError,
1008
+ SwapExpiredError,
1009
+ TransactionFailedError,
969
1010
  decodeInvoice,
970
1011
  getInvoicePaymentHash,
971
1012
  getInvoiceSatoshis
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arkade-os/boltz-swap",
3
- "version": "0.1.4",
3
+ "version": "0.1.8",
4
4
  "type": "module",
5
5
  "description": "A production-ready TypeScript package that brings Boltz submarine-swaps to Arkade.",
6
6
  "main": "./dist/index.js",
@@ -31,7 +31,7 @@
31
31
  "license": "MIT",
32
32
  "dependencies": {
33
33
  "@arkade-os/sdk": "^0.2.1",
34
- "@noble/hashes": "^1.3.3",
34
+ "@noble/hashes": "1.8.0",
35
35
  "@scure/base": "^1.2.6",
36
36
  "@scure/btc-signer": "^1.2.1",
37
37
  "light-bolt11-decoder": "^3.2.0"