@arkade-os/boltz-swap 0.3.0 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +139 -480
- package/dist/{arkade-swaps-Brpa88Fg.d.cts → arkade-swaps-DHjneVaF.d.ts} +86 -26
- package/dist/{arkade-swaps-DnvQayY0.d.ts → arkade-swaps-w-cm-cPg.d.cts} +86 -26
- package/dist/{background-OI6ONB3C.js → background-2UJPEKEU.js} +2 -2
- package/dist/{chunk-WNTQXNGX.js → chunk-LKAPZQDE.js} +1 -1
- package/dist/{chunk-XVJ47GNJ.js → chunk-Y7C7NJ5D.js} +163 -33
- package/dist/expo/index.cjs +164 -34
- package/dist/expo/index.d.cts +3 -2
- package/dist/expo/index.d.ts +3 -2
- package/dist/expo/index.js +4 -4
- package/dist/index.cjs +163 -33
- package/dist/index.d.cts +34 -4
- package/dist/index.d.ts +34 -4
- package/dist/index.js +1 -1
- package/dist/repositories/realm/index.d.cts +1 -1
- package/dist/repositories/realm/index.d.ts +1 -1
- package/dist/repositories/sqlite/index.d.cts +1 -1
- package/dist/repositories/sqlite/index.d.ts +1 -1
- package/dist/{types-BRYTZH1Z.d.cts → types-t0r41rlw.d.cts} +267 -10
- package/dist/{types-BRYTZH1Z.d.ts → types-t0r41rlw.d.ts} +267 -10
- package/package.json +2 -2
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,
|
|
30
|
-
import { ArkadeSwaps
|
|
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 =
|
|
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://
|
|
38
|
+
arkServerUrl: 'https://arkade.computer',
|
|
39
39
|
});
|
|
40
40
|
|
|
41
|
-
// Initialize
|
|
42
|
-
const
|
|
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
|
-
|
|
45
|
+
> [!NOTE]
|
|
46
|
+
> Upgrading from v1 `StorageAdapter`? See [SwapRepository migration](#swaprepository).
|
|
58
47
|
|
|
59
|
-
|
|
48
|
+
### Receive Lightning
|
|
60
49
|
|
|
61
50
|
```typescript
|
|
62
|
-
|
|
63
|
-
|
|
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
|
-
|
|
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
|
-
|
|
93
|
-
|
|
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
|
-
|
|
64
|
+
### ARK to BTC
|
|
96
65
|
|
|
97
|
-
|
|
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
|
-
###
|
|
74
|
+
### BTC to ARK
|
|
100
75
|
|
|
101
76
|
```typescript
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
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
|
-
|
|
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
|
-
|
|
128
|
-
|
|
84
|
+
```typescript
|
|
85
|
+
const manager = swaps.getSwapManager();
|
|
129
86
|
|
|
130
|
-
//
|
|
131
|
-
|
|
132
|
-
|
|
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
|
-
|
|
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
|
-
|
|
138
|
-
|
|
139
|
-
|
|
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
|
-
###
|
|
102
|
+
### Fees and Limits
|
|
147
103
|
|
|
148
104
|
```typescript
|
|
149
|
-
|
|
150
|
-
|
|
105
|
+
// Lightning
|
|
106
|
+
const fees = await swaps.getFees();
|
|
107
|
+
const limits = await swaps.getLimits();
|
|
151
108
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
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
|
-
###
|
|
176
|
-
|
|
177
|
-
SwapManager supports flexible event subscription - you can add/remove listeners dynamically:
|
|
114
|
+
### Swap History
|
|
178
115
|
|
|
179
116
|
```typescript
|
|
180
|
-
const
|
|
181
|
-
|
|
182
|
-
|
|
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
|
-
|
|
189
|
-
const unsubscribe = manager.onSwapUpdate((swap, oldStatus) => {
|
|
190
|
-
console.log(`Swap ${swap.id}: ${oldStatus} → ${swap.status}`);
|
|
191
|
-
});
|
|
121
|
+
---
|
|
192
122
|
|
|
193
|
-
|
|
194
|
-
manager.onSwapCompleted((swap) => {
|
|
195
|
-
console.log(`Swap ${swap.id} completed!`);
|
|
196
|
-
});
|
|
123
|
+
## Advanced Usage
|
|
197
124
|
|
|
198
|
-
|
|
199
|
-
manager.onSwapFailed((swap, error) => {
|
|
200
|
-
console.error(`Swap ${swap.id} failed:`, error);
|
|
201
|
-
});
|
|
125
|
+
### Chain Swap Amounts
|
|
202
126
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
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
|
-
|
|
209
|
-
manager.onWebSocketConnected(() => console.log('Connected'));
|
|
210
|
-
manager.onWebSocketDisconnected((error) => console.log('Disconnected', error));
|
|
131
|
+
### Renegotiating Quotes
|
|
211
132
|
|
|
212
|
-
|
|
213
|
-
unsubscribe();
|
|
133
|
+
If the amount sent differs from expected:
|
|
214
134
|
|
|
215
|
-
|
|
216
|
-
|
|
135
|
+
```typescript
|
|
136
|
+
const newAmount = await swaps.quoteSwap(pendingSwap.id);
|
|
217
137
|
```
|
|
218
138
|
|
|
219
|
-
###
|
|
139
|
+
### Blocking on a Swap
|
|
220
140
|
|
|
221
|
-
|
|
141
|
+
Even with SwapManager, you can block until a specific swap completes:
|
|
222
142
|
|
|
223
143
|
```typescript
|
|
224
|
-
|
|
225
|
-
const
|
|
226
|
-
|
|
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
|
-
|
|
230
|
-
{
|
|
231
|
-
await using swaps = new ArkadeSwaps({
|
|
232
|
-
wallet,
|
|
233
|
-
swapProvider,
|
|
234
|
-
swapManager: { autoStart: true },
|
|
235
|
-
});
|
|
148
|
+
### Without SwapManager (Manual Mode)
|
|
236
149
|
|
|
237
|
-
|
|
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
|
-
|
|
155
|
+
const result = await swaps.createLightningInvoice({ amount: 50000 });
|
|
156
|
+
await swaps.waitAndClaim(result.pendingSwap); // blocks until complete
|
|
240
157
|
```
|
|
241
158
|
|
|
242
|
-
###
|
|
159
|
+
### SwapManager Configuration
|
|
243
160
|
|
|
244
161
|
```typescript
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
//
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
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
|
-
|
|
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
|
-
###
|
|
281
|
-
|
|
282
|
-
Even with SwapManager enabled, you can still wait for specific swaps to complete:
|
|
194
|
+
### Cleanup
|
|
283
195
|
|
|
284
196
|
```typescript
|
|
285
|
-
|
|
197
|
+
// Manual
|
|
198
|
+
await swaps.dispose();
|
|
286
199
|
|
|
287
|
-
//
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
}
|
|
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
|
-
###
|
|
207
|
+
### SwapRepository
|
|
297
208
|
|
|
298
|
-
|
|
209
|
+
Swap storage defaults to IndexedDB in browsers. For other platforms:
|
|
299
210
|
|
|
300
211
|
```typescript
|
|
301
|
-
//
|
|
302
|
-
|
|
212
|
+
// SQLite (React Native / Node.js)
|
|
213
|
+
import { SQLiteSwapRepository } from '@arkade-os/boltz-swap/repositories/sqlite';
|
|
303
214
|
|
|
304
|
-
//
|
|
305
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|