@arkade-os/boltz-swap 0.3.0 → 0.3.1

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
@@ -26,286 +26,214 @@ npm install @arkade-os/sdk @arkade-os/boltz-swap
26
26
  ### Initializing
27
27
 
28
28
  ```typescript
29
- import { Wallet, SingleKey } from '@arkade-os/sdk';
30
- import { ArkadeSwaps, BoltzSwapProvider } from '@arkade-os/boltz-swap';
29
+ import { Wallet, MnemonicIdentity } from '@arkade-os/sdk';
30
+ import { ArkadeSwaps } from '@arkade-os/boltz-swap';
31
31
 
32
32
  // Create an identity
33
- const identity = SingleKey.fromHex('your_private_key_in_hex');
33
+ const identity = MnemonicIdentity.fromMnemonic('your twelve word mnemonic phrase ...', { isMainnet: true });
34
34
 
35
35
  // Initialize your Arkade wallet
36
36
  const wallet = await Wallet.create({
37
37
  identity,
38
- arkServerUrl: 'https://mutinynet.arkade.sh',
38
+ arkServerUrl: 'https://arkade.computer',
39
39
  });
40
40
 
41
- // Initialize the swap provider
42
- const swapProvider = new BoltzSwapProvider({
43
- apiUrl: 'https://api.boltz.mutinynet.arkade.sh',
44
- network: 'mutinynet',
45
- referralId: 'arkade', // optional
46
- });
47
-
48
- // Create the ArkadeSwaps instance
49
- const swaps = new ArkadeSwaps({
50
- wallet,
51
- swapProvider,
52
- // Optional: enable SwapManager for background monitoring
53
- // swapManager: true,
54
- });
41
+ // Initialize swaps (network auto-detected from wallet, SwapManager enabled by default)
42
+ const swaps = await ArkadeSwaps.create({ wallet });
55
43
  ```
56
44
 
57
- **SwapRepository**: Swap storage is pluggable via `SwapRepository`. By default, `ArkadeSwaps` uses an IndexedDB-backed repository in browser contexts. You can inject your own repository (for tests, Node.js, or custom storage) via the `swapRepository` option. Custom implementations must set `readonly version = 1` to match the interface — TypeScript will error when the version is bumped, signaling a required update.
45
+ > [!NOTE]
46
+ > Upgrading from v1 `StorageAdapter`? See [SwapRepository migration](#swaprepository).
58
47
 
59
- Platform-specific repositories are available as subpath exports:
48
+ ### Receive Lightning
60
49
 
61
50
  ```typescript
62
- // SQLite (React Native / Node.js)
63
- import { SQLiteSwapRepository } from '@arkade-os/boltz-swap/repositories/sqlite';
64
-
65
- // Realm (React Native)
66
- import { RealmSwapRepository, BoltzRealmSchemas } from '@arkade-os/boltz-swap/repositories/realm';
51
+ const result = await swaps.createLightningInvoice({ amount: 50000 });
52
+ console.log('Invoice:', result.invoice);
53
+ // SwapManager auto-claims when paid
67
54
  ```
68
55
 
69
- > [!WARNING]
70
- > If you previously used the v1 `StorageAdapter`-based repositories, migrate
71
- > data into the new IndexedDB repositories before use. You can use
72
- > `getMigrationStatus` from `@arkade-os/sdk` to check whether migration is
73
- > needed before running it:
74
- >
75
- > ```typescript
76
- > import {
77
- > IndexedDbSwapRepository,
78
- > migrateToSwapRepository
79
- > } from '@arkade-os/boltz-swap'
80
- > import { getMigrationStatus } from '@arkade-os/sdk'
81
- > import { IndexedDBStorageAdapter } from '@arkade-os/sdk/adapters/indexedDB'
82
- >
83
- > // if you used a different name for the DB, use your own here
84
- > const oldStorage = new IndexedDBStorageAdapter('arkade-service-worker', 1)
85
- >
86
- > const status = await getMigrationStatus('wallet', oldStorage)
87
- > if (status !== 'not-needed') {
88
- > await migrateToSwapRepository(oldStorage, new IndexedDbSwapRepository())
89
- > }
90
- > ```
56
+ ### Send Lightning
91
57
 
92
- Existing data stays in the old DB (e.g. `arkade-service-worker`) until you run the migration once.
93
- After `migrateToSwapRepository`, the IndexedDB-backed SwapRepository is used going forward.
58
+ ```typescript
59
+ const result = await swaps.sendLightningPayment({ invoice: 'lnbc500u1pj...' });
60
+ console.log('Paid:', result.txid);
61
+ // SwapManager auto-refunds if payment fails
62
+ ```
94
63
 
95
- ## Background Swap Monitoring (SwapManager)
64
+ ### ARK to BTC
96
65
 
97
- By default, you must manually monitor each swap and act on their state. **SwapManager** enables autonomous background processing - swaps complete automatically while the app is running. When the app reopens, it automatically resumes pending swaps.
66
+ ```typescript
67
+ const result = await swaps.arkToBtc({
68
+ btcAddress: 'bc1q...',
69
+ senderLockAmount: 100000,
70
+ });
71
+ // SwapManager auto-claims BTC when ready
72
+ ```
98
73
 
99
- ### Enable SwapManager
74
+ ### BTC to ARK
100
75
 
101
76
  ```typescript
102
- // Option 1: Enable with defaults
103
- const swaps = new ArkadeSwaps({
104
- wallet,
105
- swapProvider,
106
- swapManager: true, // Simple boolean to enable with defaults
107
- });
77
+ const result = await swaps.btcToArk({ receiverLockAmount: 100000 });
78
+ console.log('Pay to:', result.btcAddress, 'Amount:', result.amountToPay);
79
+ // SwapManager auto-claims ARK when ready
80
+ ```
108
81
 
109
- // Option 2: Enable with custom config
110
- const swaps = new ArkadeSwaps({
111
- wallet,
112
- swapProvider,
113
- swapManager: {
114
- autoStart: false, // Set to false to manually call startSwapManager() later
115
- // Events for UI updates (optional, can also use on/off methods)
116
- events: {
117
- onSwapCompleted: (swap) => {
118
- console.log(`Swap ${swap.id} completed!`);
119
- },
120
- onSwapUpdate: (swap, oldStatus) => {
121
- console.log(`${swap.id}: ${oldStatus} → ${swap.status}`);
122
- },
123
- },
124
- },
125
- });
82
+ ### Listening for Updates
126
83
 
127
- // If autoStart is false, manually start monitoring
128
- await swaps.startSwapManager();
84
+ ```typescript
85
+ const manager = swaps.getSwapManager();
129
86
 
130
- // Create swaps - they're automatically monitored!
131
- const invoice = await swaps.createLightningInvoice({ amount: 50000 });
132
- // User can navigate to other pages - swap completes in background
133
- ```
87
+ // Global listeners
88
+ manager.onSwapCompleted((swap) => console.log(`${swap.id} completed`));
89
+ manager.onSwapFailed((swap, error) => console.error(`${swap.id} failed`, error));
90
+ manager.onSwapUpdate((swap, oldStatus) => console.log(`${swap.id}: ${oldStatus} → ${swap.status}`));
134
91
 
135
- ### How It Works
92
+ // Wait for a specific swap
93
+ const result = await swaps.createLightningInvoice({ amount: 50000 });
94
+ const unsubscribe = manager.subscribeToSwapUpdates(result.pendingSwap.id, (swap, oldStatus) => {
95
+ console.log(`${oldStatus} → ${swap.status}`);
96
+ });
136
97
 
137
- - **Single WebSocket** monitors all swaps (not one per swap)
138
- - **Automatic polling** after WebSocket connects/reconnects
139
- - **Fallback polling** with exponential backoff if WebSocket fails
140
- - **Auto-claim/refund** executes when status allows
141
- - **Resumes on app reopen** - loads pending swaps, polls latest status, executes refunds if expired
142
- - **Default `ArkadeSwaps` requires the app running** - monitoring stops when the app/tab closes
143
- - For browser background monitoring, use `ServiceWorkerArkadeSwaps`
144
- - If swaps expire while closed, refunds execute automatically on next app launch (unless claimed/refunded by your background runtime)
98
+ // Or block until a specific swap completes
99
+ const { txid } = await manager.waitForSwapCompletion(result.pendingSwap.id);
100
+ ```
145
101
 
146
- ### Configuration Options
102
+ ### Fees and Limits
147
103
 
148
104
  ```typescript
149
- // Simple boolean to enable with defaults
150
- swapManager: true,
105
+ // Lightning
106
+ const fees = await swaps.getFees();
107
+ const limits = await swaps.getLimits();
151
108
 
152
- // OR custom configuration
153
- swapManager: {
154
- enableAutoActions: true, // Auto claim/refund (default: true)
155
- autoStart: true, // Auto-start on init (default: true)
156
- pollInterval: 30000, // Failsafe poll every 30s when WS active (default)
157
- reconnectDelayMs: 1000, // Initial WS reconnect delay (default)
158
- maxReconnectDelayMs: 60000, // Max WS reconnect delay (default)
159
- pollRetryDelayMs: 5000, // Initial fallback poll delay (default)
160
- maxPollRetryDelayMs: 300000, // Max fallback poll delay (default)
161
-
162
- // Optional: provide event listeners in config
163
- // (can also use on/off methods dynamically - see Event Subscription section)
164
- events: {
165
- onSwapUpdate: (swap, oldStatus) => {},
166
- onSwapCompleted: (swap) => {},
167
- onSwapFailed: (swap, error) => {},
168
- onActionExecuted: (swap, action) => {}, // 'claim', 'refund', 'claimArk', 'claimBtc', 'refundArk', 'signServerClaim'
169
- onWebSocketConnected: () => {},
170
- onWebSocketDisconnected: (error?) => {},
171
- }
172
- }
109
+ // Chain swaps
110
+ const chainFees = await swaps.getFees('ARK', 'BTC');
111
+ const chainLimits = await swaps.getLimits('ARK', 'BTC');
173
112
  ```
174
113
 
175
- ### Event Subscription
176
-
177
- SwapManager supports flexible event subscription - you can add/remove listeners dynamically:
114
+ ### Swap History
178
115
 
179
116
  ```typescript
180
- const swaps = new ArkadeSwaps({
181
- wallet,
182
- swapProvider,
183
- swapManager: true,
184
- });
185
-
186
- const manager = swaps.getSwapManager();
117
+ const history = await swaps.getSwapHistory();
118
+ const pending = await swaps.getPendingReverseSwaps();
119
+ ```
187
120
 
188
- // Subscribe to events using on* methods (returns unsubscribe function)
189
- const unsubscribe = manager.onSwapUpdate((swap, oldStatus) => {
190
- console.log(`Swap ${swap.id}: ${oldStatus} → ${swap.status}`);
191
- });
121
+ ---
192
122
 
193
- // Subscribe to completed events
194
- manager.onSwapCompleted((swap) => {
195
- console.log(`Swap ${swap.id} completed!`);
196
- });
123
+ ## Advanced Usage
197
124
 
198
- // Subscribe to failures
199
- manager.onSwapFailed((swap, error) => {
200
- console.error(`Swap ${swap.id} failed:`, error);
201
- });
125
+ ### Chain Swap Amounts
202
126
 
203
- // Subscribe to actions (claim/refund/claimArk/claimBtc/refundArk/signServerClaim)
204
- manager.onActionExecuted((swap, action) => {
205
- console.log(`Executed ${action} for swap ${swap.id}`);
206
- });
127
+ When creating a chain swap, specify exactly one:
128
+ - `senderLockAmount`: sender sends this exact amount, receiver gets less (amount - fees)
129
+ - `receiverLockAmount`: receiver gets this exact amount, sender pays more (amount + fees)
207
130
 
208
- // WebSocket events
209
- manager.onWebSocketConnected(() => console.log('Connected'));
210
- manager.onWebSocketDisconnected((error) => console.log('Disconnected', error));
131
+ ### Renegotiating Quotes
211
132
 
212
- // Unsubscribe when no longer needed (e.g., component unmount)
213
- unsubscribe();
133
+ If the amount sent differs from expected:
214
134
 
215
- // Or use off* methods to remove a specific listener
216
- manager.offSwapUpdate(myListener);
135
+ ```typescript
136
+ const newAmount = await swaps.quoteSwap(pendingSwap.id);
217
137
  ```
218
138
 
219
- ### Cleanup (Disposable Pattern)
139
+ ### Blocking on a Swap
220
140
 
221
- ArkadeSwaps implements the Disposable pattern for automatic cleanup:
141
+ Even with SwapManager, you can block until a specific swap completes:
222
142
 
223
143
  ```typescript
224
- // Option 1: Manual cleanup
225
- const swaps = new ArkadeSwaps({ wallet, swapProvider });
226
- // ... use it
227
- await swaps.dispose(); // Stops SwapManager and cleans up
144
+ const result = await swaps.createLightningInvoice({ amount: 50000 });
145
+ const { txid } = await swaps.waitAndClaim(result.pendingSwap);
146
+ ```
228
147
 
229
- // Option 2: Automatic cleanup with `await using` (TypeScript 5.2+)
230
- {
231
- await using swaps = new ArkadeSwaps({
232
- wallet,
233
- swapProvider,
234
- swapManager: { autoStart: true },
235
- });
148
+ ### Without SwapManager (Manual Mode)
236
149
 
237
- // Use swaps...
150
+ If you disable SwapManager, you must manually monitor and act on swaps:
151
+
152
+ ```typescript
153
+ const swaps = await ArkadeSwaps.create({ wallet, swapManager: false });
238
154
 
239
- } // SwapManager automatically stopped when scope exits
155
+ const result = await swaps.createLightningInvoice({ amount: 50000 });
156
+ await swaps.waitAndClaim(result.pendingSwap); // blocks until complete
240
157
  ```
241
158
 
242
- ### Manual Control
159
+ ### SwapManager Configuration
243
160
 
244
161
  ```typescript
245
- // Stop background monitoring
246
- await swaps.stopSwapManager();
247
-
248
- // Check manager stats
249
- const manager = swaps.getSwapManager();
250
- const stats = await manager?.getStats();
251
- console.log(`Monitoring ${stats.monitoredSwaps} swaps`);
252
- console.log(`WebSocket connected: ${stats.websocketConnected}`);
162
+ const swaps = await ArkadeSwaps.create({
163
+ wallet,
164
+ swapManager: {
165
+ enableAutoActions: true, // Auto claim/refund (default: true)
166
+ autoStart: true, // Auto-start on init (default: true)
167
+ pollInterval: 30000, // Failsafe poll interval (default)
168
+ events: {
169
+ onSwapCompleted: (swap) => {},
170
+ onSwapFailed: (swap, error) => {},
171
+ onSwapUpdate: (swap, oldStatus) => {},
172
+ onActionExecuted: (swap, action) => {},
173
+ onWebSocketConnected: () => {},
174
+ onWebSocketDisconnected: (error?) => {},
175
+ }
176
+ },
177
+ });
253
178
  ```
254
179
 
255
180
  ### Per-Swap UI Hooks
256
181
 
257
- When SwapManager is enabled, you can subscribe to updates for specific swaps to show progress in your UI:
258
-
259
182
  ```typescript
260
183
  const result = await swaps.createLightningInvoice({ amount: 50000 });
261
-
262
- // Subscribe to this specific swap's updates
263
184
  const manager = swaps.getSwapManager();
185
+
264
186
  const unsubscribe = manager.subscribeToSwapUpdates(
265
187
  result.pendingSwap.id,
266
188
  (swap, oldStatus) => {
267
- console.log(`Swap ${swap.id}: ${oldStatus} → ${swap.status}`);
268
- if (swap.status === 'transaction.mempool') {
269
- showNotification('Payment detected in mempool!');
270
- } else if (swap.status === 'invoice.settled') {
271
- showNotification('Payment received!');
272
- }
189
+ if (swap.status === 'invoice.settled') showNotification('Payment received!');
273
190
  }
274
191
  );
275
-
276
- // Clean up when component unmounts
277
- // unsubscribe();
278
192
  ```
279
193
 
280
- ### Blocking with SwapManager
281
-
282
- Even with SwapManager enabled, you can still wait for specific swaps to complete:
194
+ ### Cleanup
283
195
 
284
196
  ```typescript
285
- const result = await swaps.createLightningInvoice({ amount: 50000 });
197
+ // Manual
198
+ await swaps.dispose();
286
199
 
287
- // This blocks until the swap completes, but SwapManager handles the monitoring
288
- try {
289
- const { txid } = await swaps.waitAndClaim(result.pendingSwap);
290
- console.log('Payment claimed successfully:', txid);
291
- } catch (error) {
292
- console.error('Payment failed:', error);
293
- }
200
+ // Automatic (TypeScript 5.2+)
201
+ {
202
+ await using swaps = await ArkadeSwaps.create({ wallet });
203
+ // ...
204
+ } // auto-disposed
294
205
  ```
295
206
 
296
- ### Without SwapManager (Manual Mode)
207
+ ### SwapRepository
297
208
 
298
- If SwapManager is not enabled, you must manually monitor swaps:
209
+ Swap storage defaults to IndexedDB in browsers. For other platforms:
299
210
 
300
211
  ```typescript
301
- // Create invoice
302
- const result = await swaps.createLightningInvoice({ amount: 50000 });
212
+ // SQLite (React Native / Node.js)
213
+ import { SQLiteSwapRepository } from '@arkade-os/boltz-swap/repositories/sqlite';
303
214
 
304
- // MUST manually monitor - blocks until complete
305
- await swaps.waitAndClaim(result.pendingSwap);
306
- // User must stay on this page - navigating away stops monitoring
215
+ // Realm (React Native)
216
+ import { RealmSwapRepository, BoltzRealmSchemas } from '@arkade-os/boltz-swap/repositories/realm';
307
217
  ```
308
218
 
219
+ Custom implementations must set `readonly version = 1` — TypeScript will error when bumped, signaling a required update.
220
+
221
+ > [!WARNING]
222
+ > If you previously used the v1 `StorageAdapter`-based repositories, migrate
223
+ > data before use:
224
+ >
225
+ > ```typescript
226
+ > import { IndexedDbSwapRepository, migrateToSwapRepository } from '@arkade-os/boltz-swap'
227
+ > import { getMigrationStatus } from '@arkade-os/sdk'
228
+ > import { IndexedDBStorageAdapter } from '@arkade-os/sdk/adapters/indexedDB'
229
+ >
230
+ > const oldStorage = new IndexedDBStorageAdapter('arkade-service-worker', 1)
231
+ > const status = await getMigrationStatus('wallet', oldStorage)
232
+ > if (status !== 'not-needed') {
233
+ > await migrateToSwapRepository(oldStorage, new IndexedDbSwapRepository())
234
+ > }
235
+ > ```
236
+
309
237
  ## Expo / React Native
310
238
 
311
239
  Expo/React Native cannot run a long-lived Service Worker, and background work is executed by the OS for a short window (typically every ~15+ minutes). To enable best-effort background claim/refund for swaps, use `ExpoArkadeLightning` plus a background task defined at global scope.
@@ -410,271 +338,16 @@ const arkLn = await ExpoArkadeLightning.setup({
410
338
  await arkLn.createLightningInvoice({ amount: 1000 });
411
339
  ```
412
340
 
413
- ## Receiving Lightning Payments
414
-
415
- To receive a Lightning payment into your Arkade wallet:
416
-
417
- ```typescript
418
- const result = await swaps.createLightningInvoice({
419
- amount: 50000, // 50,000 sats
420
- description: 'Payment to my Arkade wallet',
421
- });
422
-
423
- console.log('Receive amount:', result.amount);
424
- console.log('Expiry (seconds):', result.expiry);
425
- console.log('Lightning Invoice:', result.invoice);
426
- console.log('Payment Hash:', result.paymentHash);
427
- console.log('Pending swap', result.pendingSwap);
428
- console.log('Preimage', result.preimage);
429
- ```
430
-
431
- ### Monitoring Incoming Lightning Payments
341
+ ### Error Handling
432
342
 
433
- **With SwapManager (recommended):**
434
- ```typescript
435
- // SwapManager handles monitoring and claiming automatically
436
- const result = await swaps.createLightningInvoice({ amount: 50000 });
437
- // Payment will be claimed automatically when received
438
- ```
439
-
440
- **Without SwapManager (manual mode):**
441
- ```typescript
442
- // You must manually monitor - blocks until payment is received
443
- const receivalResult = await swaps.waitAndClaim(result.pendingSwap);
444
- console.log('Transaction ID:', receivalResult.txid);
445
- ```
446
-
447
- ## Sending Lightning Payments
448
-
449
- **With SwapManager (recommended):**
450
- ```typescript
451
- import { decodeInvoice } from '@arkade-os/boltz-swap';
452
-
453
- // Validate invoice first
454
- const invoiceDetails = decodeInvoice('lnbc500u1pj...');
455
- console.log('Invoice amount:', invoiceDetails.amountSats, 'sats');
456
-
457
- // Send payment - returns immediately after creating swap
458
- const paymentResult = await swaps.sendLightningPayment({
459
- invoice: 'lnbc500u1pj...',
460
- });
343
+ With SwapManager, refunds are automatic — listen to `onSwapFailed` for notifications. Without it, handle errors manually:
461
344
 
462
- console.log('Payment initiated:', paymentResult.txid);
463
- // SwapManager monitors in background and handles refunds if payment fails
464
- ```
465
-
466
- **Without SwapManager (manual mode):**
467
345
  ```typescript
468
- const paymentResult = await swaps.sendLightningPayment({
469
- invoice: 'lnbc500u1pj...',
470
- });
471
-
472
- console.log('Amount:', paymentResult.amount);
473
- console.log('Preimage:', paymentResult.preimage);
474
- console.log('Transaction ID:', paymentResult.txid);
475
- ```
476
-
477
- ## Chain Swaps
478
-
479
- Chain swaps move funds between Arkade and Bitcoin on-chain via Boltz.
480
-
481
- #### Amounts
482
-
483
- When creating a swap, and because there are fees to be paid, you must define one and only one type of amount:
484
- - senderLockAmount: sender will send this exact amount, receiver will receive less (amount - fees)
485
- - receiverLockAmount: receiver will receive this exact amount, sender needs to send more (amount + fees)
486
-
487
- ### ARK to BTC
488
-
489
- Send funds from your Arkade wallet to a Bitcoin address:
490
-
491
- ```typescript
492
- // Create the swap
493
- const result = await swaps.arkToBtc({
494
- btcAddress: 'bc1q...',
495
- senderLockAmount: 100000,
496
- feeSatsPerByte: 2, // optional, defaults to 1
497
- });
498
-
499
- console.log('Pay to ARK address:', result.arkAddress);
500
- console.log('Amount to pay:', result.amountToPay, 'sats');
501
-
502
- // Wait for BTC to be claimed
503
- // If you use swapManager, this step is not needed
504
- const { txid } = await swaps.waitAndClaimBtc(result.pendingSwap);
505
- console.log('BTC claimed:', txid);
506
- ```
507
-
508
- If the swap fails, refund your ARK funds:
509
-
510
- ```typescript
511
- await swaps.refundArk(result.pendingSwap);
512
- ```
513
-
514
- ### BTC to ARK
515
-
516
- Receive funds from Bitcoin into your Arkade wallet:
517
-
518
- ```typescript
519
- // Create the swap
520
- const result = await swaps.btcToArk({
521
- receiverLockAmount: 100000,
522
- feeSatsPerByte: 2, // optional, defaults to 1
523
- });
524
-
525
- console.log('Pay to BTC address:', result.btcAddress);
526
- console.log('Amount to pay:', result.amountToPay, 'sats');
527
-
528
- // Wait for ARK to be claimed
529
- // If you use swapManager, this step is not needed
530
- const { txid } = await swaps.waitAndClaimArk(result.pendingSwap);
531
- console.log('ARK claimed:', txid);
532
- ```
533
-
534
- ### Chain Swap Fees and Limits
535
-
536
- ```typescript
537
- // Get chain swap fees
538
- const chainFees = await swaps.getFees('ARK', 'BTC');
539
- console.log('Percentage:', chainFees.percentage);
540
- console.log('Server miner fee:', chainFees.minerFees.server);
541
- console.log('User claim fee:', chainFees.minerFees.user.claim);
542
- console.log('User lockup fee:', chainFees.minerFees.user.lockup);
543
-
544
- // Get chain swap limits
545
- const chainLimits = await swaps.getLimits('ARK', 'BTC');
546
- console.log('Min:', chainLimits.min, 'sats');
547
- console.log('Max:', chainLimits.max, 'sats');
548
- ```
549
-
550
- ### Renegotiating Quotes
551
-
552
- If the amount sent to the swap is different from the expected, renegotiate it:
553
-
554
- ```typescript
555
- const newAmount = await swaps.quoteSwap(pendingSwap.id);
556
- console.log('Updated amount:', newAmount);
557
- ```
558
-
559
- ## Checking Swap Limits
560
-
561
- Before creating swaps, check the supported amount range:
562
-
563
- ```typescript
564
- // Lightning swap limits
565
- const limits = await swaps.getLimits();
566
- console.log('Min:', limits.min, 'sats');
567
- console.log('Max:', limits.max, 'sats');
568
-
569
- // Chain swap limits
570
- const chainLimits = await swaps.getLimits('ARK', 'BTC');
571
- ```
572
-
573
- ### Validating Lightning Invoice Amounts
574
-
575
- ```typescript
576
- import { decodeInvoice } from '@arkade-os/boltz-swap';
577
-
578
- const invoice = 'lnbc500u1pj...';
579
- const decoded = decodeInvoice(invoice);
580
- console.log('Invoice amount:', decoded.amountSats, 'sats');
581
-
582
- const limits = await swaps.getLimits();
583
- if (decoded.amountSats >= limits.min && decoded.amountSats <= limits.max) {
584
- await swaps.sendLightningPayment({ invoice });
585
- }
586
- ```
587
-
588
- ## Checking Swap Fees
589
-
590
- ```typescript
591
- // Lightning fees
592
- const fees = await swaps.getFees();
593
-
594
- const calcSubmarineSwapFee = (satoshis: number): number => {
595
- const { percentage, minerFees } = fees.submarine;
596
- return Math.ceil((satoshis * percentage) / 100 + minerFees);
597
- };
598
-
599
- const calcReverseSwapFee = (satoshis: number): number => {
600
- const { percentage, minerFees } = fees.reverse;
601
- return Math.ceil((satoshis * percentage) / 100 + minerFees.claim + minerFees.lockup);
602
- };
603
-
604
- // Chain fees
605
- const chainFees = await swaps.getFees('ARK', 'BTC');
606
- ```
607
-
608
- ## Checking Swap Status
609
-
610
- **With SwapManager:** Status updates are automatic via events - no manual checking needed.
611
-
612
- **Without SwapManager (manual mode):**
613
- ```typescript
614
- const response = await swaps.getSwapStatus('swap_id');
615
- console.log('swap status = ', response.status);
616
- ```
617
-
618
- ## Storage
619
-
620
- All swap data is persisted automatically and can be retrieved:
621
-
622
- ```typescript
623
- // Get pending swaps by type
624
- const pendingSubmarineSwaps = await swaps.getPendingSubmarineSwaps();
625
- const pendingReverseSwaps = await swaps.getPendingReverseSwaps();
626
- const pendingChainSwaps = await swaps.getPendingChainSwaps();
627
-
628
- // Get complete swap history (all types, sorted by creation date)
629
- const swapHistory = await swaps.getSwapHistory();
630
- ```
631
-
632
- **Note**: If IndexedDB is not available (e.g., in Node.js), provide a custom `swapRepository` implementation.
633
-
634
- ## Error Handling
635
-
636
- **With SwapManager:** Refunds are handled automatically - listen to `onSwapFailed` event for notifications.
637
-
638
- **Without SwapManager (manual mode):** You must handle errors and execute refunds manually:
639
-
640
- ```typescript
641
- import {
642
- SwapError,
643
- SchemaError,
644
- NetworkError,
645
- SwapExpiredError,
646
- InvoiceExpiredError,
647
- InvoiceFailedToPayError,
648
- InsufficientFundsError,
649
- TransactionFailedError,
650
- isPendingSubmarineSwap,
651
- isPendingChainSwap,
652
- } from '@arkade-os/boltz-swap';
346
+ import { isPendingSubmarineSwap, isPendingChainSwap } from '@arkade-os/boltz-swap';
653
347
 
654
348
  try {
655
- await swaps.sendLightningPayment({
656
- invoice: 'lnbc500u1pj...',
657
- });
349
+ await swaps.sendLightningPayment({ invoice: 'lnbc500u1pj...' });
658
350
  } catch (error) {
659
- if (error instanceof InvoiceExpiredError) {
660
- console.error('The invoice has expired.');
661
- } else if (error instanceof InvoiceFailedToPayError) {
662
- console.error('The provider failed to pay the invoice.');
663
- } else if (error instanceof InsufficientFundsError) {
664
- console.error('Not enough funds available:', error.message);
665
- } else if (error instanceof NetworkError) {
666
- console.error('Network issue:', error.message);
667
- } else if (error instanceof SchemaError) {
668
- console.error('Invalid response from API.');
669
- } else if (error instanceof SwapExpiredError) {
670
- console.error('The swap has expired.');
671
- } else if (error instanceof TransactionFailedError) {
672
- console.error('Transaction failed.');
673
- } else {
674
- console.error('Unknown error:', error);
675
- }
676
-
677
- // Manual refund (only needed without SwapManager)
678
351
  if (error.isRefundable && error.pendingSwap) {
679
352
  if (isPendingChainSwap(error.pendingSwap)) {
680
353
  await swaps.refundArk(error.pendingSwap);
@@ -685,29 +358,15 @@ try {
685
358
  }
686
359
  ```
687
360
 
688
- ## Type Guards
361
+ Error types: `InvoiceExpiredError`, `InvoiceFailedToPayError`, `InsufficientFundsError`, `NetworkError`, `SchemaError`, `SwapExpiredError`, `TransactionFailedError`.
362
+
363
+ ### Type Guards
689
364
 
690
365
  ```typescript
691
366
  import {
692
- isPendingReverseSwap,
693
- isPendingSubmarineSwap,
694
- isPendingChainSwap,
695
- isSubmarineSwapRefundable,
696
- isChainSwapClaimable,
697
- isChainSwapRefundable,
698
- isSubmarineFinalStatus,
699
- isReverseFinalStatus,
700
- isChainFinalStatus,
367
+ isPendingReverseSwap, isPendingSubmarineSwap, isPendingChainSwap,
368
+ isChainSwapClaimable, isChainSwapRefundable,
701
369
  } from '@arkade-os/boltz-swap';
702
-
703
- // Discriminate swap types
704
- if (isPendingReverseSwap(swap)) { /* Lightning → Arkade */ }
705
- if (isPendingSubmarineSwap(swap)) { /* Arkade → Lightning */ }
706
- if (isPendingChainSwap(swap)) { /* ARK ↔ BTC chain */ }
707
-
708
- // Check swap state
709
- if (isChainSwapClaimable(swap)) { /* ready to claim */ }
710
- if (isChainSwapRefundable(swap)) { /* can be refunded */ }
711
370
  ```
712
371
 
713
372
  ### Releasing