@arkade-os/boltz-swap 0.3.32 → 0.3.33

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 (31) hide show
  1. package/README.md +22 -26
  2. package/dist/{arkade-swaps-CS8FZSVL.d.cts → arkade-swaps-9M7FRuq1.d.cts} +57 -5
  3. package/dist/{arkade-swaps-WiKCanCL.d.ts → arkade-swaps-DNsyWeFr.d.ts} +57 -5
  4. package/dist/{chunk-NHBWNN6H.js → chunk-HNQDJOLM.js} +8 -27
  5. package/dist/{chunk-B3Q4TFWT.js → chunk-SJ5SYSMK.js} +551 -779
  6. package/dist/chunk-SJQJQO7P.js +25 -0
  7. package/dist/expo/background.cjs +573 -805
  8. package/dist/expo/background.d.cts +3 -3
  9. package/dist/expo/background.d.ts +3 -3
  10. package/dist/expo/background.js +8 -20
  11. package/dist/expo/index.cjs +574 -783
  12. package/dist/expo/index.d.cts +7 -5
  13. package/dist/expo/index.d.ts +7 -5
  14. package/dist/expo/index.js +17 -20
  15. package/dist/index.cjs +732 -931
  16. package/dist/index.d.cts +80 -10
  17. package/dist/index.d.ts +80 -10
  18. package/dist/index.js +126 -115
  19. package/dist/repositories/realm/index.cjs +10 -22
  20. package/dist/repositories/realm/index.d.cts +7 -5
  21. package/dist/repositories/realm/index.d.ts +7 -5
  22. package/dist/repositories/realm/index.js +8 -22
  23. package/dist/repositories/sqlite/index.cjs +12 -23
  24. package/dist/repositories/sqlite/index.d.cts +1 -1
  25. package/dist/repositories/sqlite/index.d.ts +1 -1
  26. package/dist/repositories/sqlite/index.js +10 -23
  27. package/dist/{swapsPollProcessor-wYOMzldd.d.ts → swapsPollProcessor-CEgeGlbP.d.ts} +3 -3
  28. package/dist/{swapsPollProcessor-BF3uTFae.d.cts → swapsPollProcessor-CuITxZie.d.cts} +3 -3
  29. package/dist/{types-BBI7-KJ0.d.cts → types-CrKkVzBB.d.cts} +9 -3
  30. package/dist/{types-BBI7-KJ0.d.ts → types-CrKkVzBB.d.ts} +9 -3
  31. package/package.json +10 -25
package/README.md CHANGED
@@ -242,18 +242,18 @@ Custom implementations must set `readonly version = 1` — TypeScript will error
242
242
 
243
243
  > [!WARNING]
244
244
  > If you previously used the v1 `StorageAdapter`-based repositories, migrate
245
- > data before use:
245
+ > data before use. `migrateToSwapRepository` copies legacy `reverseSwaps` and
246
+ > `submarineSwaps` collections from the old `ContractRepository` into the new
247
+ > `SwapRepository`. It writes its own swap-specific migration flag, so it is
248
+ > idempotent and safe to call on every startup — do not gate it on the
249
+ > wallet-side `getMigrationStatus`.
246
250
  >
247
251
  > ```typescript
248
252
  > import { IndexedDbSwapRepository, migrateToSwapRepository } from '@arkade-os/boltz-swap'
249
- > import { getMigrationStatus } from '@arkade-os/sdk'
250
253
  > import { IndexedDBStorageAdapter } from '@arkade-os/sdk/adapters/indexedDB'
251
254
  >
252
255
  > const oldStorage = new IndexedDBStorageAdapter('arkade-service-worker', 1)
253
- > const status = await getMigrationStatus('wallet', oldStorage)
254
- > if (status !== 'not-needed') {
255
- > await migrateToSwapRepository(oldStorage, new IndexedDbSwapRepository())
256
- > }
256
+ > await migrateToSwapRepository(oldStorage, new IndexedDbSwapRepository())
257
257
  > ```
258
258
 
259
259
  ## Expo / React Native
@@ -283,16 +283,14 @@ Expo/React Native cannot run a long-lived Service Worker, and background work is
283
283
  npx expo install expo-task-manager expo-background-task
284
284
  npx expo install @react-native-async-storage/async-storage expo-secure-store
285
285
  npx expo install expo-crypto
286
- npx expo install expo-sqlite && npm install indexeddbshim
286
+ npx expo install expo-sqlite
287
287
  ```
288
288
 
289
- - If you rely on the default IndexedDB-backed repositories in Expo, call `setupExpoDb()` **before any SDK/boltz-swap import**:
290
-
291
- ```ts
292
- import { setupExpoDb } from "@arkade-os/sdk/adapters/expo-db";
293
-
294
- setupExpoDb();
295
- ```
289
+ - For persistence on Expo, prefer the SQLite-backed repositories
290
+ (`@arkade-os/boltz-swap/repositories/sqlite` and
291
+ `@arkade-os/sdk/repositories/sqlite`) on top of `expo-sqlite`, or the Realm
292
+ repositories on top of `realm`. There is no SDK-shipped IndexedDB helper
293
+ for Expo.
296
294
 
297
295
  - Expo requires a `crypto.getRandomValues()` polyfill for cryptographic operations:
298
296
 
@@ -310,13 +308,20 @@ global.crypto.getRandomValues = Crypto.getRandomValues;
310
308
  // App entry point (e.g., _layout.tsx) — GLOBAL SCOPE
311
309
  import AsyncStorage from "@react-native-async-storage/async-storage";
312
310
  import * as SecureStore from "expo-secure-store";
311
+ import * as SQLite from "expo-sqlite";
313
312
  import { SingleKey } from "@arkade-os/sdk";
314
313
  import { AsyncStorageTaskQueue } from "@arkade-os/sdk/worker/expo";
315
- import { IndexedDbSwapRepository } from "@arkade-os/boltz-swap";
314
+ import { SQLiteSwapRepository } from "@arkade-os/boltz-swap/repositories/sqlite";
316
315
  import { defineExpoSwapBackgroundTask } from "@arkade-os/boltz-swap/expo/background";
317
316
 
318
317
  const swapTaskQueue = new AsyncStorageTaskQueue(AsyncStorage, "ark:swap-queue");
319
- const swapRepository = new IndexedDbSwapRepository();
318
+
319
+ const swapDb = SQLite.openDatabaseSync("ark-swaps.db");
320
+ const swapRepository = new SQLiteSwapRepository({
321
+ run: (sql, params) => swapDb.runAsync(sql, params ?? []),
322
+ get: (sql, params) => swapDb.getFirstAsync(sql, params ?? []),
323
+ all: (sql, params) => swapDb.getAllAsync(sql, params ?? []),
324
+ });
320
325
 
321
326
  defineExpoSwapBackgroundTask("ark-swap-poll", {
322
327
  taskQueue: swapTaskQueue,
@@ -424,16 +429,7 @@ import {
424
429
 
425
430
  ### Releasing
426
431
 
427
- ```bash
428
- # Release new version (will prompt for version patch, minor, major)
429
- pnpm release
430
-
431
- # You can test release process without making changes
432
- pnpm release:dry-run
433
-
434
- # Cleanup: checkout version commit and remove release branch
435
- pnpm release:cleanup
436
- ```
432
+ Package-local releases are disabled. Releases run from the monorepo root and are package-scoped: `pnpm run release -- boltz-swap patch` bumps and publishes just `@arkade-os/boltz-swap` with a `@arkade-os/boltz-swap/<version>` tag, against the currently published `@arkade-os/sdk` version. See the [root README](../../README.md#releasing) for full flags and `pnpm run release -- --help`.
437
433
 
438
434
  ## License
439
435
 
@@ -1,5 +1,5 @@
1
1
  import { IWallet, ArkProvider, IndexerProvider, ArkInfo, Identity, ArkTxInput, VHTLC } from '@arkade-os/sdk';
2
- import { p as BoltzSwapProvider, Y as SwapManager, m as SwapRepository, _ as ArkadeSwapsCreateConfig, A as ArkadeSwapsConfig, n as SwapManagerClient, C as CreateLightningInvoiceRequest, e as CreateLightningInvoiceResponse, b as BoltzReverseSwap, S as SendLightningPaymentRequest, f as SendLightningPaymentResponse, c as BoltzSubmarineSwap, g as SubmarineRefundOutcome, h as SubmarineRecoveryInfo, i as SubmarineRecoveryResult, k as ArkToBtcResponse, a as BoltzChainSwap, l as BtcToArkResponse, d as Chain, F as FeesResponse, j as ChainFeesResponse, L as LimitsResponse, G as GetSwapStatusResponse, B as BoltzSwap } from './types-BBI7-KJ0.cjs';
2
+ import { q as BoltzSwapProvider, w as SwapManager, m as SwapRepository, p as ArkadeSwapsCreateConfig, A as ArkadeSwapsConfig, n as SwapManagerClient, C as CreateLightningInvoiceRequest, e as CreateLightningInvoiceResponse, b as BoltzReverseSwap, S as SendLightningPaymentRequest, f as SendLightningPaymentResponse, c as BoltzSubmarineSwap, g as SubmarineRefundOutcome, h as SubmarineRecoveryInfo, i as SubmarineRecoveryResult, k as ArkToBtcResponse, a as BoltzChainSwap, l as BtcToArkResponse, d as Chain, F as FeesResponse, j as ChainFeesResponse, L as LimitsResponse, G as GetSwapStatusResponse, B as BoltzSwap } from './types-CrKkVzBB.cjs';
3
3
  import { TransactionOutput } from '@scure/btc-signer/psbt.js';
4
4
 
5
5
  /**
@@ -337,11 +337,46 @@ declare class ArkadeSwaps {
337
337
  arkInfo: ArkInfo;
338
338
  }): Promise<boolean>;
339
339
  /**
340
- * Renegotiates the quote for an existing swap.
340
+ * Renegotiates the quote for an existing chain swap. Convenience wrapper
341
+ * over `getSwapQuote` + `acceptSwapQuote` with a safety floor.
342
+ *
343
+ * The floor is resolved in order:
344
+ * 1. `options.minAcceptableAmount` if provided.
345
+ * 2. The original `response.claimDetails.amount` of the stored
346
+ * pending swap (Boltz-confirmed server-lock amount at creation).
347
+ * 3. Otherwise throws `QuoteRejectedError({ reason: "no_baseline" })`.
348
+ *
349
+ * `options.maxSlippageBps` (default 0) relaxes the floor by basis points.
350
+ * Quotes ≤ 0 are always rejected. On rejection the acceptance is NOT
351
+ * posted to Boltz.
352
+ *
353
+ * Prefer `getSwapQuote` / `acceptSwapQuote` for callers that want to
354
+ * inspect the quote before committing.
355
+ *
341
356
  * @param swapId - The ID of the swap.
357
+ * @param options - Optional floor and slippage configuration.
342
358
  * @returns The accepted quote amount.
359
+ * @throws QuoteRejectedError if the quote is non-positive, below the
360
+ * effective floor, or no baseline is available.
361
+ */
362
+ quoteSwap(swapId: string, options?: QuoteSwapOptions): Promise<number>;
363
+ /**
364
+ * Fetches a renegotiated quote from Boltz without accepting it.
365
+ * Pair with `acceptSwapQuote` to commit a specific value.
366
+ */
367
+ getSwapQuote(swapId: string): Promise<number>;
368
+ /**
369
+ * Accepts a quote amount for an existing chain swap, after validating it
370
+ * against the configured floor. See `quoteSwap` for floor-resolution rules.
371
+ *
372
+ * @throws QuoteRejectedError if `amount` ≤ 0, below the effective floor,
373
+ * or no baseline is available.
343
374
  */
344
- quoteSwap(swapId: string): Promise<number>;
375
+ acceptSwapQuote(swapId: string, amount: number, options?: QuoteSwapOptions): Promise<number>;
376
+ private resolveEffectiveFloor;
377
+ private resolveQuoteFloor;
378
+ private validateQuoteOptions;
379
+ private validateQuote;
345
380
  /**
346
381
  * Joins a batch to spend the vtxo via commitment transaction.
347
382
  * @param identity - The identity to use for signing.
@@ -429,6 +464,21 @@ declare class ArkadeSwaps {
429
464
  */
430
465
  enrichSubmarineSwapInvoice(swap: BoltzSubmarineSwap, invoice: string): BoltzSubmarineSwap;
431
466
  }
467
+ /** Options controlling acceptance of a renegotiated chain-swap quote. */
468
+ type QuoteSwapOptions = {
469
+ /**
470
+ * Hard floor on the accepted quote (in sats). When provided, skips the
471
+ * repository lookup. Pass the original `response.claimDetails.amount`
472
+ * to require the renegotiated amount to be no worse than what Boltz
473
+ * confirmed at swap creation.
474
+ */
475
+ minAcceptableAmount?: number;
476
+ /**
477
+ * Slippage tolerance in basis points, applied to the floor. Default 0
478
+ * (strict). E.g. 100 allows accepting quotes within 1% below the floor.
479
+ */
480
+ maxSlippageBps?: number;
481
+ };
432
482
  /** Public interface for ArkadeSwaps, defining all swap operations available to consumers. */
433
483
  interface IArkadeSwaps extends AsyncDisposable {
434
484
  startSwapManager(): Promise<void>;
@@ -493,7 +543,9 @@ interface IArkadeSwaps extends AsyncDisposable {
493
543
  swap: BoltzChainSwap;
494
544
  arkInfo: ArkInfo;
495
545
  }): Promise<boolean>;
496
- quoteSwap(swapId: string): Promise<number>;
546
+ quoteSwap(swapId: string, options?: QuoteSwapOptions): Promise<number>;
547
+ getSwapQuote(swapId: string): Promise<number>;
548
+ acceptSwapQuote(swapId: string, amount: number, options?: QuoteSwapOptions): Promise<number>;
497
549
  joinBatch(identity: Identity, input: ArkTxInput, output: TransactionOutput, arkInfo: ArkInfo, isRecoverable?: boolean): Promise<string>;
498
550
  createVHTLCScript(args: {
499
551
  network: string;
@@ -528,4 +580,4 @@ interface IArkadeSwaps extends AsyncDisposable {
528
580
  dispose(): Promise<void>;
529
581
  }
530
582
 
531
- export { ArkadeSwaps as A, type IArkadeSwaps as I, type VhtlcTimeouts as V };
583
+ export { ArkadeSwaps as A, type IArkadeSwaps as I, type QuoteSwapOptions as Q, type VhtlcTimeouts as V };
@@ -1,5 +1,5 @@
1
1
  import { IWallet, ArkProvider, IndexerProvider, ArkInfo, Identity, ArkTxInput, VHTLC } from '@arkade-os/sdk';
2
- import { p as BoltzSwapProvider, Y as SwapManager, m as SwapRepository, _ as ArkadeSwapsCreateConfig, A as ArkadeSwapsConfig, n as SwapManagerClient, C as CreateLightningInvoiceRequest, e as CreateLightningInvoiceResponse, b as BoltzReverseSwap, S as SendLightningPaymentRequest, f as SendLightningPaymentResponse, c as BoltzSubmarineSwap, g as SubmarineRefundOutcome, h as SubmarineRecoveryInfo, i as SubmarineRecoveryResult, k as ArkToBtcResponse, a as BoltzChainSwap, l as BtcToArkResponse, d as Chain, F as FeesResponse, j as ChainFeesResponse, L as LimitsResponse, G as GetSwapStatusResponse, B as BoltzSwap } from './types-BBI7-KJ0.js';
2
+ import { q as BoltzSwapProvider, w as SwapManager, m as SwapRepository, p as ArkadeSwapsCreateConfig, A as ArkadeSwapsConfig, n as SwapManagerClient, C as CreateLightningInvoiceRequest, e as CreateLightningInvoiceResponse, b as BoltzReverseSwap, S as SendLightningPaymentRequest, f as SendLightningPaymentResponse, c as BoltzSubmarineSwap, g as SubmarineRefundOutcome, h as SubmarineRecoveryInfo, i as SubmarineRecoveryResult, k as ArkToBtcResponse, a as BoltzChainSwap, l as BtcToArkResponse, d as Chain, F as FeesResponse, j as ChainFeesResponse, L as LimitsResponse, G as GetSwapStatusResponse, B as BoltzSwap } from './types-CrKkVzBB.js';
3
3
  import { TransactionOutput } from '@scure/btc-signer/psbt.js';
4
4
 
5
5
  /**
@@ -337,11 +337,46 @@ declare class ArkadeSwaps {
337
337
  arkInfo: ArkInfo;
338
338
  }): Promise<boolean>;
339
339
  /**
340
- * Renegotiates the quote for an existing swap.
340
+ * Renegotiates the quote for an existing chain swap. Convenience wrapper
341
+ * over `getSwapQuote` + `acceptSwapQuote` with a safety floor.
342
+ *
343
+ * The floor is resolved in order:
344
+ * 1. `options.minAcceptableAmount` if provided.
345
+ * 2. The original `response.claimDetails.amount` of the stored
346
+ * pending swap (Boltz-confirmed server-lock amount at creation).
347
+ * 3. Otherwise throws `QuoteRejectedError({ reason: "no_baseline" })`.
348
+ *
349
+ * `options.maxSlippageBps` (default 0) relaxes the floor by basis points.
350
+ * Quotes ≤ 0 are always rejected. On rejection the acceptance is NOT
351
+ * posted to Boltz.
352
+ *
353
+ * Prefer `getSwapQuote` / `acceptSwapQuote` for callers that want to
354
+ * inspect the quote before committing.
355
+ *
341
356
  * @param swapId - The ID of the swap.
357
+ * @param options - Optional floor and slippage configuration.
342
358
  * @returns The accepted quote amount.
359
+ * @throws QuoteRejectedError if the quote is non-positive, below the
360
+ * effective floor, or no baseline is available.
361
+ */
362
+ quoteSwap(swapId: string, options?: QuoteSwapOptions): Promise<number>;
363
+ /**
364
+ * Fetches a renegotiated quote from Boltz without accepting it.
365
+ * Pair with `acceptSwapQuote` to commit a specific value.
366
+ */
367
+ getSwapQuote(swapId: string): Promise<number>;
368
+ /**
369
+ * Accepts a quote amount for an existing chain swap, after validating it
370
+ * against the configured floor. See `quoteSwap` for floor-resolution rules.
371
+ *
372
+ * @throws QuoteRejectedError if `amount` ≤ 0, below the effective floor,
373
+ * or no baseline is available.
343
374
  */
344
- quoteSwap(swapId: string): Promise<number>;
375
+ acceptSwapQuote(swapId: string, amount: number, options?: QuoteSwapOptions): Promise<number>;
376
+ private resolveEffectiveFloor;
377
+ private resolveQuoteFloor;
378
+ private validateQuoteOptions;
379
+ private validateQuote;
345
380
  /**
346
381
  * Joins a batch to spend the vtxo via commitment transaction.
347
382
  * @param identity - The identity to use for signing.
@@ -429,6 +464,21 @@ declare class ArkadeSwaps {
429
464
  */
430
465
  enrichSubmarineSwapInvoice(swap: BoltzSubmarineSwap, invoice: string): BoltzSubmarineSwap;
431
466
  }
467
+ /** Options controlling acceptance of a renegotiated chain-swap quote. */
468
+ type QuoteSwapOptions = {
469
+ /**
470
+ * Hard floor on the accepted quote (in sats). When provided, skips the
471
+ * repository lookup. Pass the original `response.claimDetails.amount`
472
+ * to require the renegotiated amount to be no worse than what Boltz
473
+ * confirmed at swap creation.
474
+ */
475
+ minAcceptableAmount?: number;
476
+ /**
477
+ * Slippage tolerance in basis points, applied to the floor. Default 0
478
+ * (strict). E.g. 100 allows accepting quotes within 1% below the floor.
479
+ */
480
+ maxSlippageBps?: number;
481
+ };
432
482
  /** Public interface for ArkadeSwaps, defining all swap operations available to consumers. */
433
483
  interface IArkadeSwaps extends AsyncDisposable {
434
484
  startSwapManager(): Promise<void>;
@@ -493,7 +543,9 @@ interface IArkadeSwaps extends AsyncDisposable {
493
543
  swap: BoltzChainSwap;
494
544
  arkInfo: ArkInfo;
495
545
  }): Promise<boolean>;
496
- quoteSwap(swapId: string): Promise<number>;
546
+ quoteSwap(swapId: string, options?: QuoteSwapOptions): Promise<number>;
547
+ getSwapQuote(swapId: string): Promise<number>;
548
+ acceptSwapQuote(swapId: string, amount: number, options?: QuoteSwapOptions): Promise<number>;
497
549
  joinBatch(identity: Identity, input: ArkTxInput, output: TransactionOutput, arkInfo: ArkInfo, isRecoverable?: boolean): Promise<string>;
498
550
  createVHTLCScript(args: {
499
551
  network: string;
@@ -528,4 +580,4 @@ interface IArkadeSwaps extends AsyncDisposable {
528
580
  dispose(): Promise<void>;
529
581
  }
530
582
 
531
- export { ArkadeSwaps as A, type IArkadeSwaps as I, type VhtlcTimeouts as V };
583
+ export { ArkadeSwaps as A, type IArkadeSwaps as I, type QuoteSwapOptions as Q, type VhtlcTimeouts as V };
@@ -7,26 +7,18 @@ import {
7
7
  isSubmarineFinalStatus,
8
8
  isSubmarineSwapRefundable,
9
9
  logger
10
- } from "./chunk-B3Q4TFWT.js";
10
+ } from "./chunk-SJ5SYSMK.js";
11
11
 
12
12
  // src/expo/swapsPollProcessor.ts
13
13
  var SWAP_POLL_TASK_TYPE = "swap-poll";
14
14
  var swapsPollProcessor = {
15
15
  taskType: SWAP_POLL_TASK_TYPE,
16
16
  async execute(item, deps) {
17
- const {
18
- swapRepository,
19
- swapProvider,
20
- wallet,
21
- arkProvider,
22
- indexerProvider
23
- } = deps;
17
+ const { swapRepository, swapProvider, wallet, arkProvider, indexerProvider } = deps;
24
18
  const allSwaps = await swapRepository.getAllSwaps();
25
19
  const pendingSwaps = allSwaps.filter((swap) => {
26
- if (isPendingReverseSwap(swap))
27
- return !isReverseFinalStatus(swap.status);
28
- if (isPendingSubmarineSwap(swap))
29
- return !isSubmarineFinalStatus(swap.status);
20
+ if (isPendingReverseSwap(swap)) return !isReverseFinalStatus(swap.status);
21
+ if (isPendingSubmarineSwap(swap)) return !isSubmarineFinalStatus(swap.status);
30
22
  return false;
31
23
  });
32
24
  let polled = 0;
@@ -56,19 +48,14 @@ var swapsPollProcessor = {
56
48
  }
57
49
  if (isPendingReverseSwap(swap) && isReverseClaimableStatus(currentStatus)) {
58
50
  if (!swap.preimage) {
59
- logger.warn(
60
- `[swap-poll] Skipping claim for ${swap.id}: no preimage`
61
- );
51
+ logger.warn(`[swap-poll] Skipping claim for ${swap.id}: no preimage`);
62
52
  continue;
63
53
  }
64
54
  try {
65
55
  await tempSwaps.claimVHTLC(swap);
66
56
  claimed++;
67
57
  } catch (claimError) {
68
- logger.error(
69
- `[swap-poll] Claim failed for ${swap.id}:`,
70
- claimError
71
- );
58
+ logger.error(`[swap-poll] Claim failed for ${swap.id}:`, claimError);
72
59
  errors++;
73
60
  }
74
61
  }
@@ -84,18 +71,12 @@ var swapsPollProcessor = {
84
71
  await tempSwaps.refundVHTLC(swapWithStatus);
85
72
  refunded++;
86
73
  } catch (refundError) {
87
- logger.error(
88
- `[swap-poll] Refund failed for ${swap.id}:`,
89
- refundError
90
- );
74
+ logger.error(`[swap-poll] Refund failed for ${swap.id}:`, refundError);
91
75
  errors++;
92
76
  }
93
77
  }
94
78
  } catch (swapError) {
95
- logger.error(
96
- `[swap-poll] Error processing swap ${swap.id}:`,
97
- swapError
98
- );
79
+ logger.error(`[swap-poll] Error processing swap ${swap.id}:`, swapError);
99
80
  errors++;
100
81
  }
101
82
  }