@arkade-os/boltz-swap 0.3.25 → 0.3.26

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.
@@ -1,5 +1,5 @@
1
- import { I as IArkadeSwaps, A as ArkadeSwaps, V as VhtlcTimeouts } from '../arkade-swaps-pfAgQUMP.js';
2
- import { A as ArkadeSwapsConfig, m as SwapRepository, p as BoltzSwapProvider, N as Network, n as SwapManagerClient, C as CreateLightningInvoiceRequest, e as CreateLightningInvoiceResponse, S as SendLightningPaymentRequest, f as SendLightningPaymentResponse, c as BoltzSubmarineSwap, b as BoltzReverseSwap, g as SubmarineRefundOutcome, h as SubmarineRecoveryInfo, i as SubmarineRecoveryResult, F as FeesResponse, a as BoltzChainSwap, k as ArkToBtcResponse, l as BtcToArkResponse, d as Chain, j as ChainFeesResponse, L as LimitsResponse, G as GetSwapStatusResponse, B as BoltzSwap } from '../types-LCXS1AVA.js';
1
+ import { I as IArkadeSwaps, A as ArkadeSwaps, V as VhtlcTimeouts } from '../arkade-swaps-WiKCanCL.js';
2
+ import { A as ArkadeSwapsConfig, m as SwapRepository, p as BoltzSwapProvider, N as Network, n as SwapManagerClient, C as CreateLightningInvoiceRequest, e as CreateLightningInvoiceResponse, S as SendLightningPaymentRequest, f as SendLightningPaymentResponse, c as BoltzSubmarineSwap, b as BoltzReverseSwap, g as SubmarineRefundOutcome, h as SubmarineRecoveryInfo, i as SubmarineRecoveryResult, F as FeesResponse, a as BoltzChainSwap, k as ArkToBtcResponse, l as BtcToArkResponse, d as Chain, j as ChainFeesResponse, L as LimitsResponse, G as GetSwapStatusResponse, B as BoltzSwap } from '../types-BBI7-KJ0.js';
3
3
  import { Identity, ArkProvider, IndexerProvider, IWallet, ArkInfo, ArkTxInput, VHTLC } from '@arkade-os/sdk';
4
4
  import { AsyncStorageTaskQueue, TaskProcessor } from '@arkade-os/sdk/worker/expo';
5
5
  import { TransactionOutput } from '@scure/btc-signer/psbt.js';
@@ -4,10 +4,10 @@ import {
4
4
  registerExpoSwapBackgroundTask,
5
5
  swapsPollProcessor,
6
6
  unregisterExpoSwapBackgroundTask
7
- } from "../chunk-FEXQELYZ.js";
7
+ } from "../chunk-X3JNWDAR.js";
8
8
  import {
9
9
  ArkadeSwaps
10
- } from "../chunk-XC2ARJZO.js";
10
+ } from "../chunk-LWUXSE5N.js";
11
11
  import "../chunk-3RG5ZIWI.js";
12
12
 
13
13
  // src/expo/arkade-lightning.ts
@@ -56,7 +56,7 @@ var ExpoArkadeSwaps = class _ExpoArkadeSwaps {
56
56
  await instance.seedSwapPollTask();
57
57
  if (config.background.minimumBackgroundInterval) {
58
58
  try {
59
- const { registerExpoSwapBackgroundTask: registerExpoSwapBackgroundTask2 } = await import("../background-GCBCKLGY.js");
59
+ const { registerExpoSwapBackgroundTask: registerExpoSwapBackgroundTask2 } = await import("../background-UQDFQCGM.js");
60
60
  await registerExpoSwapBackgroundTask2(
61
61
  config.background.taskName,
62
62
  {
@@ -129,7 +129,7 @@ var ExpoArkadeSwaps = class _ExpoArkadeSwaps {
129
129
  }
130
130
  await this.inner.dispose();
131
131
  try {
132
- const { unregisterExpoSwapBackgroundTask: unregisterExpoSwapBackgroundTask2 } = await import("../background-GCBCKLGY.js");
132
+ const { unregisterExpoSwapBackgroundTask: unregisterExpoSwapBackgroundTask2 } = await import("../background-UQDFQCGM.js");
133
133
  await unregisterExpoSwapBackgroundTask2(this.taskName);
134
134
  } catch (err) {
135
135
  const message = err instanceof Error ? err.message : String(err);
package/dist/index.cjs CHANGED
@@ -47,6 +47,7 @@ __export(index_exports, {
47
47
  SwapError: () => SwapError,
48
48
  SwapExpiredError: () => SwapExpiredError,
49
49
  SwapManager: () => SwapManager,
50
+ SwapNotFoundError: () => SwapNotFoundError,
50
51
  TransactionFailedError: () => TransactionFailedError,
51
52
  decodeInvoice: () => decodeInvoice,
52
53
  enrichReverseSwapPreimage: () => enrichReverseSwapPreimage,
@@ -138,6 +139,19 @@ var NetworkError = class extends Error {
138
139
  this.errorData = errorData;
139
140
  }
140
141
  };
142
+ var SwapNotFoundError = class extends NetworkError {
143
+ /** The swap ID Boltz did not recognise. */
144
+ swapId;
145
+ constructor(swapId, errorData) {
146
+ super(
147
+ `Boltz returned 404 for swap '${swapId}': swap unknown to this Boltz instance`,
148
+ 404,
149
+ errorData
150
+ );
151
+ this.name = "SwapNotFoundError";
152
+ this.swapId = swapId;
153
+ }
154
+ };
141
155
  var SchemaError = class extends SwapError {
142
156
  constructor(options = {}) {
143
157
  super({ message: "Invalid API response", ...options });
@@ -396,10 +410,17 @@ var isCreateSwapsRestoreResponse = (data) => {
396
410
  );
397
411
  };
398
412
  var BASE_URLS = {
399
- bitcoin: "https://api.ark.boltz.exchange",
413
+ bitcoin: "https://api.boltz.exchange",
400
414
  mutinynet: "https://api.boltz.mutinynet.arkade.sh",
401
415
  regtest: "http://localhost:9069"
402
416
  };
417
+ var isSwapNotFoundBody = (error) => {
418
+ const needle = "could not find swap";
419
+ const fromJson = error.errorData?.error;
420
+ if (typeof fromJson === "string" && fromJson.toLowerCase().includes(needle))
421
+ return true;
422
+ return error.message.toLowerCase().includes(needle);
423
+ };
403
424
  var BoltzSwapProvider = class {
404
425
  wsUrl;
405
426
  apiUrl;
@@ -491,12 +512,27 @@ var BoltzSwapProvider = class {
491
512
  });
492
513
  return res;
493
514
  }
494
- /** Queries the current status of a swap by ID. */
515
+ /**
516
+ * Queries the current status of a swap by ID.
517
+ *
518
+ * @throws {SwapNotFoundError} when Boltz responds with HTTP 404 and a body
519
+ * matching the "could not find swap" pattern. Distinct from a generic 404
520
+ * so callers (e.g. SwapManager polling) can drive a per-swap unknown-to-
521
+ * provider counter without tripping on transient route or proxy errors.
522
+ */
495
523
  async getSwapStatus(id) {
496
- const response = await this.request(
497
- `/v2/swap/${id}`,
498
- "GET"
499
- );
524
+ let response;
525
+ try {
526
+ response = await this.request(
527
+ `/v2/swap/${id}`,
528
+ "GET"
529
+ );
530
+ } catch (error) {
531
+ if (error instanceof NetworkError && error.statusCode === 404 && isSwapNotFoundBody(error)) {
532
+ throw new SwapNotFoundError(id, error.errorData);
533
+ }
534
+ throw error;
535
+ }
500
536
  if (!isGetSwapStatusResponse(response))
501
537
  throw new SchemaError({
502
538
  message: `error fetching status for swap: ${id}`
@@ -1400,7 +1436,15 @@ function setLogger(customLogger) {
1400
1436
  }
1401
1437
 
1402
1438
  // src/swap-manager.ts
1403
- var SwapManager = class {
1439
+ var SwapManager = class _SwapManager {
1440
+ /**
1441
+ * Number of consecutive Boltz 404s for a single swap ID before the
1442
+ * polling loop gives up and transitions the swap to a terminal state.
1443
+ * At the default 30s poll cadence this is roughly a 5-minute grace
1444
+ * window — long enough to ride out a transient Boltz blip, short
1445
+ * enough that a real "swap unknown to this provider" surfaces quickly.
1446
+ */
1447
+ static NOT_FOUND_THRESHOLD = 10;
1404
1448
  swapProvider;
1405
1449
  config;
1406
1450
  // Event listeners storage (supports multiple listeners per event)
@@ -1419,6 +1463,13 @@ var SwapManager = class {
1419
1463
  reconnectTimer = null;
1420
1464
  initialPollTimer = null;
1421
1465
  pollRetryTimers = /* @__PURE__ */ new Map();
1466
+ // Per-swap counter of consecutive `SwapNotFoundError` responses from
1467
+ // `getSwapStatus`. Reset on any successful poll. Once a swap reaches
1468
+ // `NOT_FOUND_THRESHOLD` consecutive 404s the safety net trips and the
1469
+ // swap is transitioned to `swap.expired` (terminal) and dropped from
1470
+ // monitoring — typically the canonical failure mode after a Boltz
1471
+ // endpoint switch, where old swap IDs are unknown to the new instance.
1472
+ notFoundCounts = /* @__PURE__ */ new Map();
1422
1473
  isRunning = false;
1423
1474
  currentReconnectDelay;
1424
1475
  currentPollRetryDelay;
@@ -1610,6 +1661,7 @@ var SwapManager = class {
1610
1661
  clearTimeout(timer);
1611
1662
  }
1612
1663
  this.pollRetryTimers.clear();
1664
+ this.notFoundCounts.clear();
1613
1665
  }
1614
1666
  /**
1615
1667
  * Set the polling interval (ms).
@@ -1670,6 +1722,7 @@ var SwapManager = class {
1670
1722
  clearTimeout(retryTimer);
1671
1723
  this.pollRetryTimers.delete(swapId);
1672
1724
  }
1725
+ this.notFoundCounts.delete(swapId);
1673
1726
  logger.log(`Removed swap ${swapId} from monitoring`);
1674
1727
  }
1675
1728
  /**
@@ -1946,6 +1999,7 @@ var SwapManager = class {
1946
1999
  * This is the core logic that determines what actions to take
1947
2000
  */
1948
2001
  async handleSwapStatusUpdate(swap, newStatus) {
2002
+ this.notFoundCounts.delete(swap.id);
1949
2003
  const oldStatus = swap.status;
1950
2004
  if (oldStatus === newStatus) return;
1951
2005
  swap.status = newStatus;
@@ -2231,51 +2285,135 @@ var SwapManager = class {
2231
2285
  async pollAllSwaps() {
2232
2286
  if (this.monitoredSwaps.size === 0) return;
2233
2287
  const pollPromises = Array.from(this.monitoredSwaps.values()).map(
2234
- async (swap) => {
2288
+ (swap) => this.pollSingleSwap(swap)
2289
+ );
2290
+ await Promise.allSettled(pollPromises);
2291
+ }
2292
+ async pollSingleSwap(swap) {
2293
+ try {
2294
+ const statusResponse = await this.swapProvider.getSwapStatus(
2295
+ swap.id
2296
+ );
2297
+ this.notFoundCounts.delete(swap.id);
2298
+ if (statusResponse.status !== swap.status) {
2299
+ await this.handleSwapStatusUpdate(swap, statusResponse.status);
2300
+ }
2301
+ } catch (error) {
2302
+ if (error instanceof SwapNotFoundError) {
2303
+ await this.handleSwapNotFound(swap);
2304
+ return;
2305
+ }
2306
+ if (error instanceof NetworkError && error.statusCode === 429) {
2307
+ logger.warn(
2308
+ `Rate-limited polling swap ${swap.id}, retrying in 2s`
2309
+ );
2310
+ const existing = this.pollRetryTimers.get(swap.id);
2311
+ if (existing) clearTimeout(existing);
2312
+ this.pollRetryTimers.set(
2313
+ swap.id,
2314
+ setTimeout(async () => {
2315
+ this.pollRetryTimers.delete(swap.id);
2316
+ try {
2317
+ const retry = await this.swapProvider.getSwapStatus(
2318
+ swap.id
2319
+ );
2320
+ this.notFoundCounts.delete(swap.id);
2321
+ if (retry.status !== swap.status) {
2322
+ await this.handleSwapStatusUpdate(
2323
+ swap,
2324
+ retry.status
2325
+ );
2326
+ }
2327
+ } catch (retryError) {
2328
+ if (retryError instanceof SwapNotFoundError) {
2329
+ await this.handleSwapNotFound(swap);
2330
+ return;
2331
+ }
2332
+ logger.error(
2333
+ `Retry poll for swap ${swap.id} also failed:`,
2334
+ retryError
2335
+ );
2336
+ }
2337
+ }, 2e3)
2338
+ );
2339
+ } else {
2340
+ logger.error(`Failed to poll swap ${swap.id}:`, error);
2341
+ }
2342
+ }
2343
+ }
2344
+ /**
2345
+ * Increment the consecutive-not-found counter and, once the threshold is
2346
+ * reached, transition the swap to a terminal state and stop polling it.
2347
+ * Driven from {@link pollSingleSwap} when `getSwapStatus` throws
2348
+ * {@link SwapNotFoundError}. The threshold rides out a transient blip
2349
+ * but ensures we stop hammering Boltz with requests for swap IDs the
2350
+ * server has no record of (e.g. after switching the configured
2351
+ * Boltz endpoint).
2352
+ */
2353
+ async handleSwapNotFound(swap) {
2354
+ const count = (this.notFoundCounts.get(swap.id) ?? 0) + 1;
2355
+ this.notFoundCounts.set(swap.id, count);
2356
+ logger.warn(
2357
+ `Swap ${swap.id}: unknown to Boltz (${count}/${_SwapManager.NOT_FOUND_THRESHOLD} consecutive)`
2358
+ );
2359
+ if (count >= _SwapManager.NOT_FOUND_THRESHOLD) {
2360
+ await this.markSwapAsUnknownToProvider(swap);
2361
+ }
2362
+ }
2363
+ /**
2364
+ * Transition a swap to {@code swap.expired} (terminal for all swap types)
2365
+ * after Boltz has consistently reported it unknown for
2366
+ * {@link SwapManager.NOT_FOUND_THRESHOLD} consecutive polls. The swap is
2367
+ * persisted, removed from monitoring, and reported via `onSwapFailed`.
2368
+ * Bypasses {@link handleSwapStatusUpdate} on purpose: we don't want to
2369
+ * trigger autonomous claim/refund actions against a Boltz instance that
2370
+ * has no record of this swap — the requests would just generate more
2371
+ * 404s without recovering anything.
2372
+ */
2373
+ async markSwapAsUnknownToProvider(swap) {
2374
+ if (!this.monitoredSwaps.has(swap.id)) {
2375
+ this.notFoundCounts.delete(swap.id);
2376
+ return;
2377
+ }
2378
+ const oldStatus = swap.status;
2379
+ swap.status = "swap.expired";
2380
+ this.monitoredSwaps.delete(swap.id);
2381
+ const retryTimer = this.pollRetryTimers.get(swap.id);
2382
+ if (retryTimer) {
2383
+ clearTimeout(retryTimer);
2384
+ this.pollRetryTimers.delete(swap.id);
2385
+ }
2386
+ this.notFoundCounts.delete(swap.id);
2387
+ this.swapUpdateListeners.forEach(
2388
+ (listener) => listener(swap, oldStatus)
2389
+ );
2390
+ const subscribers = this.swapSubscriptions.get(swap.id);
2391
+ if (subscribers) {
2392
+ subscribers.forEach((callback) => {
2235
2393
  try {
2236
- const statusResponse = await this.swapProvider.getSwapStatus(swap.id);
2237
- if (statusResponse.status !== swap.status) {
2238
- await this.handleSwapStatusUpdate(
2239
- swap,
2240
- statusResponse.status
2241
- );
2242
- }
2243
- } catch (error) {
2244
- if (error instanceof NetworkError && error.statusCode === 429) {
2245
- logger.warn(
2246
- `Rate-limited polling swap ${swap.id}, retrying in 2s`
2247
- );
2248
- const existing = this.pollRetryTimers.get(swap.id);
2249
- if (existing) clearTimeout(existing);
2250
- this.pollRetryTimers.set(
2251
- swap.id,
2252
- setTimeout(async () => {
2253
- this.pollRetryTimers.delete(swap.id);
2254
- try {
2255
- const retry = await this.swapProvider.getSwapStatus(
2256
- swap.id
2257
- );
2258
- if (retry.status !== swap.status) {
2259
- await this.handleSwapStatusUpdate(
2260
- swap,
2261
- retry.status
2262
- );
2263
- }
2264
- } catch (retryError) {
2265
- logger.error(
2266
- `Retry poll for swap ${swap.id} also failed:`,
2267
- retryError
2268
- );
2269
- }
2270
- }, 2e3)
2271
- );
2272
- } else {
2273
- logger.error(`Failed to poll swap ${swap.id}:`, error);
2274
- }
2394
+ callback(swap, oldStatus);
2395
+ } catch (subscriberError) {
2396
+ logger.error(
2397
+ `Error in swap subscription callback for ${swap.id}:`,
2398
+ subscriberError
2399
+ );
2275
2400
  }
2276
- }
2401
+ });
2402
+ }
2403
+ try {
2404
+ await this.saveSwap(swap);
2405
+ } catch (saveError) {
2406
+ logger.error(
2407
+ `Failed to persist unknown-to-provider state for swap ${swap.id}:`,
2408
+ saveError
2409
+ );
2410
+ }
2411
+ logger.warn(
2412
+ `Swap ${swap.id}: marked failed after ${_SwapManager.NOT_FOUND_THRESHOLD} consecutive Boltz 404s \u2014 swap is unknown to the configured Boltz instance`
2277
2413
  );
2278
- await Promise.allSettled(pollPromises);
2414
+ const error = new SwapNotFoundError(swap.id);
2415
+ this.swapFailedListeners.forEach((listener) => listener(swap, error));
2416
+ this.swapSubscriptions.delete(swap.id);
2279
2417
  }
2280
2418
  /**
2281
2419
  * Check if a status is final (no more updates expected)
@@ -6633,6 +6771,7 @@ async function getContractCollection(storage, contractType) {
6633
6771
  SwapError,
6634
6772
  SwapExpiredError,
6635
6773
  SwapManager,
6774
+ SwapNotFoundError,
6636
6775
  TransactionFailedError,
6637
6776
  decodeInvoice,
6638
6777
  enrichReverseSwapPreimage,
package/dist/index.d.cts CHANGED
@@ -1,7 +1,7 @@
1
- import { I as IArkadeSwaps, V as VhtlcTimeouts } from './arkade-swaps-CZF9XoFR.cjs';
2
- export { A as ArkadeSwaps } from './arkade-swaps-CZF9XoFR.cjs';
3
- import { B as BoltzSwap, D as DecodedInvoice, a as BoltzChainSwap, b as BoltzReverseSwap, c as BoltzSubmarineSwap, A as ArkadeSwapsConfig, N as Network, C as CreateLightningInvoiceRequest, S as SendLightningPaymentRequest, F as FeesResponse, d as Chain, e as CreateLightningInvoiceResponse, f as SendLightningPaymentResponse, g as SubmarineRefundOutcome, h as SubmarineRecoveryInfo, i as SubmarineRecoveryResult, j as ChainFeesResponse, L as LimitsResponse, G as GetSwapStatusResponse, k as ArkToBtcResponse, l as BtcToArkResponse, m as SwapRepository, n as SwapManagerClient, o as GetSwapsFilter } from './types-LCXS1AVA.cjs';
4
- export { _ as ArkadeSwapsCreateConfig, p as BoltzSwapProvider, q as BoltzSwapStatus, Z as IncomingPaymentSubscription, a1 as PendingChainSwap, a0 as PendingReverseSwap, $ as PendingSubmarineSwap, a2 as PendingSwap, a4 as SubmarineRecoveryStatus, Y as SwapManager, a7 as SwapManagerCallbacks, a5 as SwapManagerConfig, a6 as SwapManagerEvents, a3 as Vtxo, r as isChainClaimableStatus, s as isChainFailedStatus, t as isChainFinalStatus, u as isChainPendingStatus, v as isChainRefundableStatus, w as isChainSignableStatus, x as isChainSuccessStatus, y as isChainSwapClaimable, z as isChainSwapRefundable, E as isPendingChainSwap, H as isPendingReverseSwap, I as isPendingSubmarineSwap, J as isReverseClaimableStatus, K as isReverseFailedStatus, M as isReverseFinalStatus, O as isReversePendingStatus, P as isReverseSuccessStatus, Q as isReverseSwapClaimable, R as isSubmarineFailedStatus, T as isSubmarineFinalStatus, U as isSubmarinePendingStatus, W as isSubmarineRefundableStatus, V as isSubmarineSuccessStatus, X as isSubmarineSwapRefundable } from './types-LCXS1AVA.cjs';
1
+ import { I as IArkadeSwaps, V as VhtlcTimeouts } from './arkade-swaps-CS8FZSVL.cjs';
2
+ export { A as ArkadeSwaps } from './arkade-swaps-CS8FZSVL.cjs';
3
+ import { B as BoltzSwap, D as DecodedInvoice, a as BoltzChainSwap, b as BoltzReverseSwap, c as BoltzSubmarineSwap, A as ArkadeSwapsConfig, N as Network, C as CreateLightningInvoiceRequest, S as SendLightningPaymentRequest, F as FeesResponse, d as Chain, e as CreateLightningInvoiceResponse, f as SendLightningPaymentResponse, g as SubmarineRefundOutcome, h as SubmarineRecoveryInfo, i as SubmarineRecoveryResult, j as ChainFeesResponse, L as LimitsResponse, G as GetSwapStatusResponse, k as ArkToBtcResponse, l as BtcToArkResponse, m as SwapRepository, n as SwapManagerClient, o as GetSwapsFilter } from './types-BBI7-KJ0.cjs';
4
+ export { _ as ArkadeSwapsCreateConfig, p as BoltzSwapProvider, q as BoltzSwapStatus, Z as IncomingPaymentSubscription, a1 as PendingChainSwap, a0 as PendingReverseSwap, $ as PendingSubmarineSwap, a2 as PendingSwap, a4 as SubmarineRecoveryStatus, Y as SwapManager, a7 as SwapManagerCallbacks, a5 as SwapManagerConfig, a6 as SwapManagerEvents, a3 as Vtxo, r as isChainClaimableStatus, s as isChainFailedStatus, t as isChainFinalStatus, u as isChainPendingStatus, v as isChainRefundableStatus, w as isChainSignableStatus, x as isChainSuccessStatus, y as isChainSwapClaimable, z as isChainSwapRefundable, E as isPendingChainSwap, H as isPendingReverseSwap, I as isPendingSubmarineSwap, J as isReverseClaimableStatus, K as isReverseFailedStatus, M as isReverseFinalStatus, O as isReversePendingStatus, P as isReverseSuccessStatus, Q as isReverseSwapClaimable, R as isSubmarineFailedStatus, T as isSubmarineFinalStatus, U as isSubmarinePendingStatus, W as isSubmarineRefundableStatus, V as isSubmarineSuccessStatus, X as isSubmarineSwapRefundable } from './types-BBI7-KJ0.cjs';
5
5
  import { Transaction } from '@scure/btc-signer';
6
6
  import { MessageHandler, RequestEnvelope, ArkInfo, ResponseEnvelope, IWallet, IReadonlyWallet, VHTLC, Identity, ArkTxInput } from '@arkade-os/sdk';
7
7
  import { TransactionOutput } from '@scure/btc-signer/psbt.js';
@@ -53,6 +53,20 @@ declare class NetworkError extends Error {
53
53
  errorData?: any;
54
54
  constructor(message: string, statusCode?: number, errorData?: any);
55
55
  }
56
+ /**
57
+ * Thrown when Boltz responds to `GET /v2/swap/{id}` with HTTP 404 and a body
58
+ * matching `{"error":"could not find swap with id: ..."}`. Signals that the
59
+ * configured Boltz instance has no record of this swap — typically because
60
+ * the swap was created against a different Boltz endpoint. Distinct from a
61
+ * generic 404 (route change, proxy misconfig) so the polling loop can drive
62
+ * a per-swap "unknown to provider" counter without conflating it with
63
+ * transient network errors.
64
+ */
65
+ declare class SwapNotFoundError extends NetworkError {
66
+ /** The swap ID Boltz did not recognise. */
67
+ readonly swapId: string;
68
+ constructor(swapId: string, errorData?: any);
69
+ }
56
70
  /** Thrown when the Boltz API returns a response that doesn't match the expected schema. */
57
71
  declare class SchemaError extends SwapError {
58
72
  constructor(options?: ErrorOptions);
@@ -769,4 +783,4 @@ declare class IndexedDbSwapRepository implements SwapRepository {
769
783
  [Symbol.asyncDispose](): Promise<void>;
770
784
  }
771
785
 
772
- export { ArkToBtcResponse, ArkadeSwapsMessageHandler as ArkadeLightningMessageHandler, ArkadeSwapsConfig, ArkadeSwapsMessageHandler, BoltzChainSwap, BoltzRefundError, BoltzReverseSwap, BoltzSubmarineSwap, BoltzSwap, BtcToArkResponse, Chain, ChainFeesResponse, CreateLightningInvoiceRequest, CreateLightningInvoiceResponse, DecodedInvoice, FeesResponse, IndexedDbSwapRepository, InsufficientFundsError, InvoiceExpiredError, InvoiceFailedToPayError, LimitsResponse, type Logger, Network, NetworkError, PreimageFetchError, SchemaError, SendLightningPaymentRequest, SendLightningPaymentResponse, ServiceWorkerArkadeSwaps as ServiceWorkerArkadeLightning, ServiceWorkerArkadeSwaps, SubmarineRecoveryInfo, SubmarineRecoveryResult, SubmarineRefundOutcome, SwapError, SwapExpiredError, SwapManagerClient, SwapRepository, type SwapSaver, TransactionFailedError, decodeInvoice, enrichReverseSwapPreimage, enrichSubmarineSwapInvoice, getInvoicePaymentHash, getInvoiceSatoshis, isValidArkAddress, logger, migrateToSwapRepository, saveSwap, setLogger, updateChainSwapStatus, updateReverseSwapStatus, updateSubmarineSwapStatus, verifySignatures };
786
+ export { ArkToBtcResponse, ArkadeSwapsMessageHandler as ArkadeLightningMessageHandler, ArkadeSwapsConfig, ArkadeSwapsMessageHandler, BoltzChainSwap, BoltzRefundError, BoltzReverseSwap, BoltzSubmarineSwap, BoltzSwap, BtcToArkResponse, Chain, ChainFeesResponse, CreateLightningInvoiceRequest, CreateLightningInvoiceResponse, DecodedInvoice, FeesResponse, IndexedDbSwapRepository, InsufficientFundsError, InvoiceExpiredError, InvoiceFailedToPayError, LimitsResponse, type Logger, Network, NetworkError, PreimageFetchError, SchemaError, SendLightningPaymentRequest, SendLightningPaymentResponse, ServiceWorkerArkadeSwaps as ServiceWorkerArkadeLightning, ServiceWorkerArkadeSwaps, SubmarineRecoveryInfo, SubmarineRecoveryResult, SubmarineRefundOutcome, SwapError, SwapExpiredError, SwapManagerClient, SwapNotFoundError, SwapRepository, type SwapSaver, TransactionFailedError, decodeInvoice, enrichReverseSwapPreimage, enrichSubmarineSwapInvoice, getInvoicePaymentHash, getInvoiceSatoshis, isValidArkAddress, logger, migrateToSwapRepository, saveSwap, setLogger, updateChainSwapStatus, updateReverseSwapStatus, updateSubmarineSwapStatus, verifySignatures };
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
- import { I as IArkadeSwaps, V as VhtlcTimeouts } from './arkade-swaps-pfAgQUMP.js';
2
- export { A as ArkadeSwaps } from './arkade-swaps-pfAgQUMP.js';
3
- import { B as BoltzSwap, D as DecodedInvoice, a as BoltzChainSwap, b as BoltzReverseSwap, c as BoltzSubmarineSwap, A as ArkadeSwapsConfig, N as Network, C as CreateLightningInvoiceRequest, S as SendLightningPaymentRequest, F as FeesResponse, d as Chain, e as CreateLightningInvoiceResponse, f as SendLightningPaymentResponse, g as SubmarineRefundOutcome, h as SubmarineRecoveryInfo, i as SubmarineRecoveryResult, j as ChainFeesResponse, L as LimitsResponse, G as GetSwapStatusResponse, k as ArkToBtcResponse, l as BtcToArkResponse, m as SwapRepository, n as SwapManagerClient, o as GetSwapsFilter } from './types-LCXS1AVA.js';
4
- export { _ as ArkadeSwapsCreateConfig, p as BoltzSwapProvider, q as BoltzSwapStatus, Z as IncomingPaymentSubscription, a1 as PendingChainSwap, a0 as PendingReverseSwap, $ as PendingSubmarineSwap, a2 as PendingSwap, a4 as SubmarineRecoveryStatus, Y as SwapManager, a7 as SwapManagerCallbacks, a5 as SwapManagerConfig, a6 as SwapManagerEvents, a3 as Vtxo, r as isChainClaimableStatus, s as isChainFailedStatus, t as isChainFinalStatus, u as isChainPendingStatus, v as isChainRefundableStatus, w as isChainSignableStatus, x as isChainSuccessStatus, y as isChainSwapClaimable, z as isChainSwapRefundable, E as isPendingChainSwap, H as isPendingReverseSwap, I as isPendingSubmarineSwap, J as isReverseClaimableStatus, K as isReverseFailedStatus, M as isReverseFinalStatus, O as isReversePendingStatus, P as isReverseSuccessStatus, Q as isReverseSwapClaimable, R as isSubmarineFailedStatus, T as isSubmarineFinalStatus, U as isSubmarinePendingStatus, W as isSubmarineRefundableStatus, V as isSubmarineSuccessStatus, X as isSubmarineSwapRefundable } from './types-LCXS1AVA.js';
1
+ import { I as IArkadeSwaps, V as VhtlcTimeouts } from './arkade-swaps-WiKCanCL.js';
2
+ export { A as ArkadeSwaps } from './arkade-swaps-WiKCanCL.js';
3
+ import { B as BoltzSwap, D as DecodedInvoice, a as BoltzChainSwap, b as BoltzReverseSwap, c as BoltzSubmarineSwap, A as ArkadeSwapsConfig, N as Network, C as CreateLightningInvoiceRequest, S as SendLightningPaymentRequest, F as FeesResponse, d as Chain, e as CreateLightningInvoiceResponse, f as SendLightningPaymentResponse, g as SubmarineRefundOutcome, h as SubmarineRecoveryInfo, i as SubmarineRecoveryResult, j as ChainFeesResponse, L as LimitsResponse, G as GetSwapStatusResponse, k as ArkToBtcResponse, l as BtcToArkResponse, m as SwapRepository, n as SwapManagerClient, o as GetSwapsFilter } from './types-BBI7-KJ0.js';
4
+ export { _ as ArkadeSwapsCreateConfig, p as BoltzSwapProvider, q as BoltzSwapStatus, Z as IncomingPaymentSubscription, a1 as PendingChainSwap, a0 as PendingReverseSwap, $ as PendingSubmarineSwap, a2 as PendingSwap, a4 as SubmarineRecoveryStatus, Y as SwapManager, a7 as SwapManagerCallbacks, a5 as SwapManagerConfig, a6 as SwapManagerEvents, a3 as Vtxo, r as isChainClaimableStatus, s as isChainFailedStatus, t as isChainFinalStatus, u as isChainPendingStatus, v as isChainRefundableStatus, w as isChainSignableStatus, x as isChainSuccessStatus, y as isChainSwapClaimable, z as isChainSwapRefundable, E as isPendingChainSwap, H as isPendingReverseSwap, I as isPendingSubmarineSwap, J as isReverseClaimableStatus, K as isReverseFailedStatus, M as isReverseFinalStatus, O as isReversePendingStatus, P as isReverseSuccessStatus, Q as isReverseSwapClaimable, R as isSubmarineFailedStatus, T as isSubmarineFinalStatus, U as isSubmarinePendingStatus, W as isSubmarineRefundableStatus, V as isSubmarineSuccessStatus, X as isSubmarineSwapRefundable } from './types-BBI7-KJ0.js';
5
5
  import { Transaction } from '@scure/btc-signer';
6
6
  import { MessageHandler, RequestEnvelope, ArkInfo, ResponseEnvelope, IWallet, IReadonlyWallet, VHTLC, Identity, ArkTxInput } from '@arkade-os/sdk';
7
7
  import { TransactionOutput } from '@scure/btc-signer/psbt.js';
@@ -53,6 +53,20 @@ declare class NetworkError extends Error {
53
53
  errorData?: any;
54
54
  constructor(message: string, statusCode?: number, errorData?: any);
55
55
  }
56
+ /**
57
+ * Thrown when Boltz responds to `GET /v2/swap/{id}` with HTTP 404 and a body
58
+ * matching `{"error":"could not find swap with id: ..."}`. Signals that the
59
+ * configured Boltz instance has no record of this swap — typically because
60
+ * the swap was created against a different Boltz endpoint. Distinct from a
61
+ * generic 404 (route change, proxy misconfig) so the polling loop can drive
62
+ * a per-swap "unknown to provider" counter without conflating it with
63
+ * transient network errors.
64
+ */
65
+ declare class SwapNotFoundError extends NetworkError {
66
+ /** The swap ID Boltz did not recognise. */
67
+ readonly swapId: string;
68
+ constructor(swapId: string, errorData?: any);
69
+ }
56
70
  /** Thrown when the Boltz API returns a response that doesn't match the expected schema. */
57
71
  declare class SchemaError extends SwapError {
58
72
  constructor(options?: ErrorOptions);
@@ -769,4 +783,4 @@ declare class IndexedDbSwapRepository implements SwapRepository {
769
783
  [Symbol.asyncDispose](): Promise<void>;
770
784
  }
771
785
 
772
- export { ArkToBtcResponse, ArkadeSwapsMessageHandler as ArkadeLightningMessageHandler, ArkadeSwapsConfig, ArkadeSwapsMessageHandler, BoltzChainSwap, BoltzRefundError, BoltzReverseSwap, BoltzSubmarineSwap, BoltzSwap, BtcToArkResponse, Chain, ChainFeesResponse, CreateLightningInvoiceRequest, CreateLightningInvoiceResponse, DecodedInvoice, FeesResponse, IndexedDbSwapRepository, InsufficientFundsError, InvoiceExpiredError, InvoiceFailedToPayError, LimitsResponse, type Logger, Network, NetworkError, PreimageFetchError, SchemaError, SendLightningPaymentRequest, SendLightningPaymentResponse, ServiceWorkerArkadeSwaps as ServiceWorkerArkadeLightning, ServiceWorkerArkadeSwaps, SubmarineRecoveryInfo, SubmarineRecoveryResult, SubmarineRefundOutcome, SwapError, SwapExpiredError, SwapManagerClient, SwapRepository, type SwapSaver, TransactionFailedError, decodeInvoice, enrichReverseSwapPreimage, enrichSubmarineSwapInvoice, getInvoicePaymentHash, getInvoiceSatoshis, isValidArkAddress, logger, migrateToSwapRepository, saveSwap, setLogger, updateChainSwapStatus, updateReverseSwapStatus, updateSubmarineSwapStatus, verifySignatures };
786
+ export { ArkToBtcResponse, ArkadeSwapsMessageHandler as ArkadeLightningMessageHandler, ArkadeSwapsConfig, ArkadeSwapsMessageHandler, BoltzChainSwap, BoltzRefundError, BoltzReverseSwap, BoltzSubmarineSwap, BoltzSwap, BtcToArkResponse, Chain, ChainFeesResponse, CreateLightningInvoiceRequest, CreateLightningInvoiceResponse, DecodedInvoice, FeesResponse, IndexedDbSwapRepository, InsufficientFundsError, InvoiceExpiredError, InvoiceFailedToPayError, LimitsResponse, type Logger, Network, NetworkError, PreimageFetchError, SchemaError, SendLightningPaymentRequest, SendLightningPaymentResponse, ServiceWorkerArkadeSwaps as ServiceWorkerArkadeLightning, ServiceWorkerArkadeSwaps, SubmarineRecoveryInfo, SubmarineRecoveryResult, SubmarineRefundOutcome, SwapError, SwapExpiredError, SwapManagerClient, SwapNotFoundError, SwapRepository, type SwapSaver, TransactionFailedError, decodeInvoice, enrichReverseSwapPreimage, enrichSubmarineSwapInvoice, getInvoicePaymentHash, getInvoiceSatoshis, isValidArkAddress, logger, migrateToSwapRepository, saveSwap, setLogger, updateChainSwapStatus, updateReverseSwapStatus, updateSubmarineSwapStatus, verifySignatures };
package/dist/index.js CHANGED
@@ -12,6 +12,7 @@ import {
12
12
  SwapError,
13
13
  SwapExpiredError,
14
14
  SwapManager,
15
+ SwapNotFoundError,
15
16
  TransactionFailedError,
16
17
  decodeInvoice,
17
18
  enrichReverseSwapPreimage,
@@ -50,7 +51,7 @@ import {
50
51
  updateReverseSwapStatus,
51
52
  updateSubmarineSwapStatus,
52
53
  verifySignatures
53
- } from "./chunk-XC2ARJZO.js";
54
+ } from "./chunk-LWUXSE5N.js";
54
55
  import "./chunk-3RG5ZIWI.js";
55
56
 
56
57
  // src/serviceWorker/arkade-swaps-message-handler.ts
@@ -1494,6 +1495,7 @@ export {
1494
1495
  SwapError,
1495
1496
  SwapExpiredError,
1496
1497
  SwapManager,
1498
+ SwapNotFoundError,
1497
1499
  TransactionFailedError,
1498
1500
  decodeInvoice,
1499
1501
  enrichReverseSwapPreimage,
@@ -1,4 +1,4 @@
1
- import { m as SwapRepository, B as BoltzSwap, o as GetSwapsFilter } from '../../types-LCXS1AVA.cjs';
1
+ import { m as SwapRepository, B as BoltzSwap, o as GetSwapsFilter } from '../../types-BBI7-KJ0.cjs';
2
2
  import '@arkade-os/sdk';
3
3
 
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { m as SwapRepository, B as BoltzSwap, o as GetSwapsFilter } from '../../types-LCXS1AVA.js';
1
+ import { m as SwapRepository, B as BoltzSwap, o as GetSwapsFilter } from '../../types-BBI7-KJ0.js';
2
2
  import '@arkade-os/sdk';
3
3
 
4
4
  /**
@@ -1,5 +1,5 @@
1
1
  import { SQLExecutor } from '@arkade-os/sdk/repositories/sqlite';
2
- import { m as SwapRepository, B as BoltzSwap, o as GetSwapsFilter } from '../../types-LCXS1AVA.cjs';
2
+ import { m as SwapRepository, B as BoltzSwap, o as GetSwapsFilter } from '../../types-BBI7-KJ0.cjs';
3
3
  import '@arkade-os/sdk';
4
4
 
5
5
  /**
@@ -1,5 +1,5 @@
1
1
  import { SQLExecutor } from '@arkade-os/sdk/repositories/sqlite';
2
- import { m as SwapRepository, B as BoltzSwap, o as GetSwapsFilter } from '../../types-LCXS1AVA.js';
2
+ import { m as SwapRepository, B as BoltzSwap, o as GetSwapsFilter } from '../../types-BBI7-KJ0.js';
3
3
  import '@arkade-os/sdk';
4
4
 
5
5
  /**
@@ -310,7 +310,14 @@ declare class BoltzSwapProvider {
310
310
  getChainHeight(): Promise<number>;
311
311
  /** Gets the lockup transaction ID for a reverse swap. */
312
312
  getReverseSwapTxId(id: string): Promise<GetReverseSwapTxIdResponse>;
313
- /** Queries the current status of a swap by ID. */
313
+ /**
314
+ * Queries the current status of a swap by ID.
315
+ *
316
+ * @throws {SwapNotFoundError} when Boltz responds with HTTP 404 and a body
317
+ * matching the "could not find swap" pattern. Distinct from a generic 404
318
+ * so callers (e.g. SwapManager polling) can drive a per-swap unknown-to-
319
+ * provider counter without tripping on transient route or proxy errors.
320
+ */
314
321
  getSwapStatus(id: string): Promise<GetSwapStatusResponse>;
315
322
  /** Gets the preimage for a settled submarine swap (proof of payment). */
316
323
  getSwapPreimage(id: string): Promise<GetSwapPreimageResponse>;
@@ -477,6 +484,14 @@ interface SwapManagerCallbacks {
477
484
  * for both reconnection and polling intervals.
478
485
  */
479
486
  declare class SwapManager implements SwapManagerClient {
487
+ /**
488
+ * Number of consecutive Boltz 404s for a single swap ID before the
489
+ * polling loop gives up and transitions the swap to a terminal state.
490
+ * At the default 30s poll cadence this is roughly a 5-minute grace
491
+ * window — long enough to ride out a transient Boltz blip, short
492
+ * enough that a real "swap unknown to this provider" surfaces quickly.
493
+ */
494
+ private static readonly NOT_FOUND_THRESHOLD;
480
495
  private readonly swapProvider;
481
496
  private readonly config;
482
497
  private swapUpdateListeners;
@@ -492,6 +507,7 @@ declare class SwapManager implements SwapManagerClient {
492
507
  private reconnectTimer;
493
508
  private initialPollTimer;
494
509
  private pollRetryTimers;
510
+ private notFoundCounts;
495
511
  private isRunning;
496
512
  private currentReconnectDelay;
497
513
  private currentPollRetryDelay;
@@ -706,6 +722,28 @@ declare class SwapManager implements SwapManagerClient {
706
722
  * 4. As fallback when WebSocket is unavailable
707
723
  */
708
724
  private pollAllSwaps;
725
+ private pollSingleSwap;
726
+ /**
727
+ * Increment the consecutive-not-found counter and, once the threshold is
728
+ * reached, transition the swap to a terminal state and stop polling it.
729
+ * Driven from {@link pollSingleSwap} when `getSwapStatus` throws
730
+ * {@link SwapNotFoundError}. The threshold rides out a transient blip
731
+ * but ensures we stop hammering Boltz with requests for swap IDs the
732
+ * server has no record of (e.g. after switching the configured
733
+ * Boltz endpoint).
734
+ */
735
+ private handleSwapNotFound;
736
+ /**
737
+ * Transition a swap to {@code swap.expired} (terminal for all swap types)
738
+ * after Boltz has consistently reported it unknown for
739
+ * {@link SwapManager.NOT_FOUND_THRESHOLD} consecutive polls. The swap is
740
+ * persisted, removed from monitoring, and reported via `onSwapFailed`.
741
+ * Bypasses {@link handleSwapStatusUpdate} on purpose: we don't want to
742
+ * trigger autonomous claim/refund actions against a Boltz instance that
743
+ * has no record of this swap — the requests would just generate more
744
+ * 404s without recovering anything.
745
+ */
746
+ private markSwapAsUnknownToProvider;
709
747
  /**
710
748
  * Check if a status is final (no more updates expected)
711
749
  */
@@ -310,7 +310,14 @@ declare class BoltzSwapProvider {
310
310
  getChainHeight(): Promise<number>;
311
311
  /** Gets the lockup transaction ID for a reverse swap. */
312
312
  getReverseSwapTxId(id: string): Promise<GetReverseSwapTxIdResponse>;
313
- /** Queries the current status of a swap by ID. */
313
+ /**
314
+ * Queries the current status of a swap by ID.
315
+ *
316
+ * @throws {SwapNotFoundError} when Boltz responds with HTTP 404 and a body
317
+ * matching the "could not find swap" pattern. Distinct from a generic 404
318
+ * so callers (e.g. SwapManager polling) can drive a per-swap unknown-to-
319
+ * provider counter without tripping on transient route or proxy errors.
320
+ */
314
321
  getSwapStatus(id: string): Promise<GetSwapStatusResponse>;
315
322
  /** Gets the preimage for a settled submarine swap (proof of payment). */
316
323
  getSwapPreimage(id: string): Promise<GetSwapPreimageResponse>;
@@ -477,6 +484,14 @@ interface SwapManagerCallbacks {
477
484
  * for both reconnection and polling intervals.
478
485
  */
479
486
  declare class SwapManager implements SwapManagerClient {
487
+ /**
488
+ * Number of consecutive Boltz 404s for a single swap ID before the
489
+ * polling loop gives up and transitions the swap to a terminal state.
490
+ * At the default 30s poll cadence this is roughly a 5-minute grace
491
+ * window — long enough to ride out a transient Boltz blip, short
492
+ * enough that a real "swap unknown to this provider" surfaces quickly.
493
+ */
494
+ private static readonly NOT_FOUND_THRESHOLD;
480
495
  private readonly swapProvider;
481
496
  private readonly config;
482
497
  private swapUpdateListeners;
@@ -492,6 +507,7 @@ declare class SwapManager implements SwapManagerClient {
492
507
  private reconnectTimer;
493
508
  private initialPollTimer;
494
509
  private pollRetryTimers;
510
+ private notFoundCounts;
495
511
  private isRunning;
496
512
  private currentReconnectDelay;
497
513
  private currentPollRetryDelay;
@@ -706,6 +722,28 @@ declare class SwapManager implements SwapManagerClient {
706
722
  * 4. As fallback when WebSocket is unavailable
707
723
  */
708
724
  private pollAllSwaps;
725
+ private pollSingleSwap;
726
+ /**
727
+ * Increment the consecutive-not-found counter and, once the threshold is
728
+ * reached, transition the swap to a terminal state and stop polling it.
729
+ * Driven from {@link pollSingleSwap} when `getSwapStatus` throws
730
+ * {@link SwapNotFoundError}. The threshold rides out a transient blip
731
+ * but ensures we stop hammering Boltz with requests for swap IDs the
732
+ * server has no record of (e.g. after switching the configured
733
+ * Boltz endpoint).
734
+ */
735
+ private handleSwapNotFound;
736
+ /**
737
+ * Transition a swap to {@code swap.expired} (terminal for all swap types)
738
+ * after Boltz has consistently reported it unknown for
739
+ * {@link SwapManager.NOT_FOUND_THRESHOLD} consecutive polls. The swap is
740
+ * persisted, removed from monitoring, and reported via `onSwapFailed`.
741
+ * Bypasses {@link handleSwapStatusUpdate} on purpose: we don't want to
742
+ * trigger autonomous claim/refund actions against a Boltz instance that
743
+ * has no record of this swap — the requests would just generate more
744
+ * 404s without recovering anything.
745
+ */
746
+ private markSwapAsUnknownToProvider;
709
747
  /**
710
748
  * Check if a status is final (no more updates expected)
711
749
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arkade-os/boltz-swap",
3
- "version": "0.3.25",
3
+ "version": "0.3.26",
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",