@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
@@ -41,6 +41,7 @@ var TaskManager = __toESM(require("expo-task-manager"), 1);
41
41
  var BackgroundTask = __toESM(require("expo-background-task"), 1);
42
42
  var import_expo = require("@arkade-os/sdk/worker/expo");
43
43
  var import_expo2 = require("@arkade-os/sdk/adapters/expo");
44
+ var import_sdk9 = require("@arkade-os/sdk");
44
45
 
45
46
  // src/boltz-swap-provider.ts
46
47
  var import_sdk = require("@arkade-os/sdk");
@@ -54,7 +55,10 @@ var SwapError = class extends Error {
54
55
  /** The pending swap associated with this error, if available. */
55
56
  pendingSwap;
56
57
  constructor(options = {}) {
57
- super(options.message ?? "Error during swap.");
58
+ super(
59
+ options.message ?? "Error during swap.",
60
+ options.cause !== void 0 ? { cause: options.cause } : void 0
61
+ );
58
62
  this.name = "SwapError";
59
63
  this.isClaimable = options.isClaimable ?? false;
60
64
  this.isRefundable = options.isRefundable ?? false;
@@ -131,6 +135,96 @@ var TransactionRefundedError = class extends SwapError {
131
135
  this.name = "TransactionRefundedError";
132
136
  }
133
137
  };
138
+ var QuoteRejectedError = class _QuoteRejectedError extends SwapError {
139
+ reason;
140
+ quotedAmount;
141
+ floor;
142
+ constructor(options) {
143
+ super({
144
+ message: options.message ?? _QuoteRejectedError.defaultMessage(options),
145
+ ...options
146
+ });
147
+ this.name = "QuoteRejectedError";
148
+ this.reason = options.reason;
149
+ this.quotedAmount = "quotedAmount" in options ? options.quotedAmount : void 0;
150
+ this.floor = "floor" in options ? options.floor : void 0;
151
+ }
152
+ static defaultMessage(options) {
153
+ switch (options.reason) {
154
+ case "below_floor":
155
+ return `Boltz quote ${options.quotedAmount} is below acceptable floor ${options.floor}`;
156
+ case "non_positive":
157
+ return `Boltz quote ${options.quotedAmount} is not positive`;
158
+ case "no_baseline":
159
+ return "Cannot accept quote: no minAcceptableAmount and no stored pending swap";
160
+ }
161
+ }
162
+ /**
163
+ * Serialize into a plain `Error` whose `.message` carries the full
164
+ * rejection payload as JSON behind a marker prefix. Structured clone
165
+ * (used by `postMessage` between page and service worker) preserves
166
+ * `Error.message` reliably but strips custom `.name` and own properties,
167
+ * so we move the typed data into the message field for transport.
168
+ */
169
+ toTransportError() {
170
+ return new Error(
171
+ QUOTE_REJECTION_TRANSPORT_PREFIX + JSON.stringify({
172
+ reason: this.reason,
173
+ message: this.message,
174
+ quotedAmount: this.quotedAmount,
175
+ floor: this.floor
176
+ })
177
+ );
178
+ }
179
+ /**
180
+ * Inverse of `toTransportError`. Returns a real `QuoteRejectedError` if
181
+ * `error` carries the transport prefix, else `null`.
182
+ */
183
+ static fromTransportError(error) {
184
+ if (!(error instanceof Error) || !error.message.startsWith(QUOTE_REJECTION_TRANSPORT_PREFIX)) {
185
+ return null;
186
+ }
187
+ const payload = error.message.slice(QUOTE_REJECTION_TRANSPORT_PREFIX.length);
188
+ let data;
189
+ try {
190
+ data = JSON.parse(payload);
191
+ } catch {
192
+ return null;
193
+ }
194
+ if (typeof data.reason !== "string" || !QUOTE_REJECTION_REASONS.has(data.reason)) {
195
+ return null;
196
+ }
197
+ const message = typeof data.message === "string" ? data.message : void 0;
198
+ const reason = data.reason;
199
+ const quotedAmount = typeof data.quotedAmount === "number" ? data.quotedAmount : null;
200
+ const floor = typeof data.floor === "number" ? data.floor : null;
201
+ switch (reason) {
202
+ case "below_floor":
203
+ if (quotedAmount === null || floor === null) return null;
204
+ return new _QuoteRejectedError({
205
+ reason,
206
+ quotedAmount,
207
+ floor,
208
+ message
209
+ });
210
+ case "non_positive":
211
+ if (quotedAmount === null) return null;
212
+ return new _QuoteRejectedError({
213
+ reason,
214
+ quotedAmount,
215
+ message
216
+ });
217
+ case "no_baseline":
218
+ return new _QuoteRejectedError({ reason, message });
219
+ }
220
+ }
221
+ };
222
+ var QUOTE_REJECTION_TRANSPORT_PREFIX = "QUOTE_REJECTED::";
223
+ var QUOTE_REJECTION_REASONS = /* @__PURE__ */ new Set([
224
+ "below_floor",
225
+ "non_positive",
226
+ "no_baseline"
227
+ ]);
134
228
  var BoltzRefundError = class extends Error {
135
229
  constructor(message, cause) {
136
230
  super(message);
@@ -142,18 +236,10 @@ var BoltzRefundError = class extends Error {
142
236
  // src/boltz-swap-provider.ts
143
237
  var import_base = require("@scure/base");
144
238
  var isSubmarineFinalStatus = (status) => {
145
- return [
146
- "invoice.failedToPay",
147
- "transaction.claimed",
148
- "swap.expired"
149
- ].includes(status);
239
+ return ["invoice.failedToPay", "transaction.claimed", "swap.expired"].includes(status);
150
240
  };
151
241
  var isSubmarineRefundableStatus = (status) => {
152
- return [
153
- "invoice.failedToPay",
154
- "transaction.lockupFailed",
155
- "swap.expired"
156
- ].includes(status);
242
+ return ["invoice.failedToPay", "transaction.lockupFailed", "swap.expired"].includes(status);
157
243
  };
158
244
  var isSubmarineSuccessStatus = (status) => {
159
245
  return status === "transaction.claimed";
@@ -172,10 +258,7 @@ var isReverseClaimableStatus = (status) => {
172
258
  return ["transaction.mempool", "transaction.confirmed"].includes(status);
173
259
  };
174
260
  var isChainClaimableStatus = (status) => {
175
- return [
176
- "transaction.server.mempool",
177
- "transaction.server.confirmed"
178
- ].includes(status);
261
+ return ["transaction.server.mempool", "transaction.server.confirmed"].includes(status);
179
262
  };
180
263
  var isChainFinalStatus = (status) => {
181
264
  return [
@@ -292,8 +375,7 @@ var BASE_URLS = {
292
375
  var isSwapNotFoundBody = (error) => {
293
376
  const needle = "could not find swap";
294
377
  const fromJson = error.errorData?.error;
295
- if (typeof fromJson === "string" && fromJson.toLowerCase().includes(needle))
296
- return true;
378
+ if (typeof fromJson === "string" && fromJson.toLowerCase().includes(needle)) return true;
297
379
  return error.message.toLowerCase().includes(needle);
298
380
  };
299
381
  var BoltzSwapProvider = class {
@@ -307,10 +389,7 @@ var BoltzSwapProvider = class {
307
389
  this.network = config.network;
308
390
  this.referralId = config.referralId ?? "arkade-ts-sdk";
309
391
  const apiUrl = config.apiUrl || BASE_URLS[config.network];
310
- if (!apiUrl)
311
- throw new Error(
312
- `API URL is required for network: ${config.network}`
313
- );
392
+ if (!apiUrl) throw new Error(`API URL is required for network: ${config.network}`);
314
393
  this.apiUrl = apiUrl;
315
394
  this.wsUrl = this.apiUrl.replace(/^http(s)?:\/\//, "ws$1://").replace("9069", "9004") + "/v2/ws";
316
395
  }
@@ -329,10 +408,7 @@ var BoltzSwapProvider = class {
329
408
  /** Returns current Lightning swap fees (submarine + reverse) from Boltz. */
330
409
  async getFees() {
331
410
  const [submarine, reverse] = await Promise.all([
332
- this.request(
333
- "/v2/swap/submarine",
334
- "GET"
335
- ),
411
+ this.request("/v2/swap/submarine", "GET"),
336
412
  this.request("/v2/swap/reverse", "GET")
337
413
  ]);
338
414
  if (!isGetSubmarinePairsResponse(submarine))
@@ -352,10 +428,7 @@ var BoltzSwapProvider = class {
352
428
  }
353
429
  /** Returns current Lightning swap min/max limits from Boltz. */
354
430
  async getLimits() {
355
- const response = await this.request(
356
- "/v2/swap/submarine",
357
- "GET"
358
- );
431
+ const response = await this.request("/v2/swap/submarine", "GET");
359
432
  if (!isGetSubmarinePairsResponse(response))
360
433
  throw new SchemaError({ message: "error fetching limits" });
361
434
  return {
@@ -365,10 +438,7 @@ var BoltzSwapProvider = class {
365
438
  }
366
439
  /** Returns the current BTC chain tip height from Boltz. */
367
440
  async getChainHeight() {
368
- const response = await this.request(
369
- "/v2/chain/heights",
370
- "GET"
371
- );
441
+ const response = await this.request("/v2/chain/heights", "GET");
372
442
  if (typeof response?.BTC !== "number")
373
443
  throw new SchemaError({
374
444
  message: "error fetching chain heights"
@@ -398,10 +468,7 @@ var BoltzSwapProvider = class {
398
468
  async getSwapStatus(id) {
399
469
  let response;
400
470
  try {
401
- response = await this.request(
402
- `/v2/swap/${id}`,
403
- "GET"
404
- );
471
+ response = await this.request(`/v2/swap/${id}`, "GET");
405
472
  } catch (error) {
406
473
  if (error instanceof NetworkError && error.statusCode === 404 && isSwapNotFoundBody(error)) {
407
474
  throw new SwapNotFoundError(id, error.errorData);
@@ -497,12 +564,10 @@ var BoltzSwapProvider = class {
497
564
  throw new SwapError({ message: "Invalid 'to' chain" });
498
565
  if (["BTC", "ARK"].indexOf(from) === -1)
499
566
  throw new SwapError({ message: "Invalid 'from' chain" });
500
- if (to === from)
501
- throw new SwapError({ message: "Invalid swap direction" });
567
+ if (to === from) throw new SwapError({ message: "Invalid swap direction" });
502
568
  if (!preimageHash || preimageHash.length != 64)
503
569
  throw new SwapError({ message: "Invalid preimageHash" });
504
- if (feeSatsPerByte <= 0)
505
- throw new SwapError({ message: "Invalid feeSatsPerByte" });
570
+ if (feeSatsPerByte <= 0) throw new SwapError({ message: "Invalid feeSatsPerByte" });
506
571
  if (serverLockAmount !== void 0 && userLockAmount !== void 0 || serverLockAmount === void 0 && userLockAmount === void 0)
507
572
  throw new SwapError({
508
573
  message: "Either serverLockAmount or userLockAmount must be provided"
@@ -557,12 +622,8 @@ var BoltzSwapProvider = class {
557
622
  message: "Error refunding submarine swap"
558
623
  });
559
624
  return {
560
- transaction: import_sdk.Transaction.fromPSBT(
561
- import_base.base64.decode(response.transaction)
562
- ),
563
- checkpoint: import_sdk.Transaction.fromPSBT(
564
- import_base.base64.decode(response.checkpoint)
565
- )
625
+ transaction: import_sdk.Transaction.fromPSBT(import_base.base64.decode(response.transaction)),
626
+ checkpoint: import_sdk.Transaction.fromPSBT(import_base.base64.decode(response.checkpoint))
566
627
  };
567
628
  }
568
629
  /** Requests Boltz co-signature for a chain swap refund. Returns signed transaction + checkpoint. */
@@ -581,53 +642,53 @@ var BoltzSwapProvider = class {
581
642
  message: "Error refunding chain swap"
582
643
  });
583
644
  return {
584
- transaction: import_sdk.Transaction.fromPSBT(
585
- import_base.base64.decode(response.transaction)
586
- ),
587
- checkpoint: import_sdk.Transaction.fromPSBT(
588
- import_base.base64.decode(response.checkpoint)
589
- )
645
+ transaction: import_sdk.Transaction.fromPSBT(import_base.base64.decode(response.transaction)),
646
+ checkpoint: import_sdk.Transaction.fromPSBT(import_base.base64.decode(response.checkpoint))
590
647
  };
591
648
  }
592
- /** Monitors swap status updates via WebSocket. Calls update callback on each status change. Resolves when terminal. */
649
+ /**
650
+ * Monitors swap status updates and forwards them to the update callback.
651
+ * Prefers a WebSocket subscription; on connection error or premature close
652
+ * it falls back to REST polling so callers don't fail when the WS endpoint
653
+ * is flaky (observed in CI). Resolves when the swap reaches a terminal
654
+ * status.
655
+ */
593
656
  async monitorSwap(swapId, update) {
594
657
  return new Promise((resolve, reject) => {
595
- const webSocket = new globalThis.WebSocket(this.wsUrl);
596
- const connectionTimeout = setTimeout(() => {
597
- webSocket.close();
598
- reject(new NetworkError("WebSocket connection timeout"));
599
- }, 3e4);
600
- webSocket.onerror = (error) => {
601
- clearTimeout(connectionTimeout);
602
- reject(
603
- new NetworkError(
604
- `WebSocket error: ${error.message}`
605
- )
606
- );
607
- };
608
- webSocket.onopen = () => {
609
- clearTimeout(connectionTimeout);
610
- webSocket.send(
611
- JSON.stringify({
612
- op: "subscribe",
613
- channel: "swap.update",
614
- args: [swapId]
615
- })
616
- );
658
+ let settled = false;
659
+ let lastStatus = null;
660
+ let pollTimer = null;
661
+ let webSocket = null;
662
+ let connectionTimeout = null;
663
+ const cleanup = () => {
664
+ if (connectionTimeout) {
665
+ clearTimeout(connectionTimeout);
666
+ connectionTimeout = null;
667
+ }
668
+ if (pollTimer) {
669
+ clearInterval(pollTimer);
670
+ pollTimer = null;
671
+ }
672
+ if (webSocket) {
673
+ try {
674
+ webSocket.close();
675
+ } catch {
676
+ }
677
+ webSocket = null;
678
+ }
617
679
  };
618
- webSocket.onclose = () => {
619
- clearTimeout(connectionTimeout);
620
- resolve();
680
+ const finish = (err) => {
681
+ if (settled) return;
682
+ settled = true;
683
+ cleanup();
684
+ if (err) reject(err);
685
+ else resolve();
621
686
  };
622
- webSocket.onmessage = async (rawMsg) => {
623
- const msg = JSON.parse(rawMsg.data);
624
- if (msg.event !== "update" || msg.args[0].id !== swapId) return;
625
- if (msg.args[0].error) {
626
- webSocket.close();
627
- reject(new SwapError({ message: msg.args[0].error }));
628
- }
629
- const status = msg.args[0].status;
630
- const negotiable = status === "transaction.lockupFailed" && msg.args[0].failureDetails?.actual !== void 0 && msg.args[0].failureDetails?.expected !== void 0;
687
+ const handleStatus = (status, data) => {
688
+ if (settled) return;
689
+ if (status === lastStatus) return;
690
+ lastStatus = status;
691
+ const negotiable = status === "transaction.lockupFailed" && data?.failureDetails?.actual !== void 0 && data?.failureDetails?.expected !== void 0;
631
692
  switch (status) {
632
693
  case "invoice.settled":
633
694
  case "transaction.claimed":
@@ -636,13 +697,13 @@ var BoltzSwapProvider = class {
636
697
  case "invoice.failedToPay":
637
698
  case "transaction.failed":
638
699
  case "swap.expired":
639
- webSocket.close();
640
- update(status, msg.args[0]);
641
- break;
700
+ update(status, data);
701
+ finish();
702
+ return;
642
703
  case "transaction.lockupFailed":
643
- if (!negotiable) webSocket.close();
644
- update(status, msg.args[0]);
645
- break;
704
+ update(status, data);
705
+ if (!negotiable) finish();
706
+ return;
646
707
  case "invoice.paid":
647
708
  case "invoice.pending":
648
709
  case "invoice.set":
@@ -652,9 +713,77 @@ var BoltzSwapProvider = class {
652
713
  case "transaction.claim.pending":
653
714
  case "transaction.server.mempool":
654
715
  case "transaction.server.confirmed":
655
- update(status, msg.args[0]);
716
+ update(status, data);
717
+ return;
656
718
  }
657
719
  };
720
+ const startPolling = () => {
721
+ if (settled || pollTimer) return;
722
+ const poll = async () => {
723
+ if (settled) return;
724
+ try {
725
+ const result = await this.getSwapStatus(swapId);
726
+ handleStatus(result.status, { ...result, id: swapId });
727
+ } catch {
728
+ }
729
+ };
730
+ pollTimer = setInterval(poll, 1e3);
731
+ poll();
732
+ };
733
+ try {
734
+ webSocket = new globalThis.WebSocket(this.wsUrl);
735
+ connectionTimeout = setTimeout(() => {
736
+ try {
737
+ webSocket?.close();
738
+ } catch {
739
+ }
740
+ webSocket = null;
741
+ startPolling();
742
+ }, 5e3);
743
+ webSocket.onerror = () => {
744
+ if (connectionTimeout) {
745
+ clearTimeout(connectionTimeout);
746
+ connectionTimeout = null;
747
+ }
748
+ webSocket = null;
749
+ startPolling();
750
+ };
751
+ webSocket.onopen = () => {
752
+ if (connectionTimeout) {
753
+ clearTimeout(connectionTimeout);
754
+ connectionTimeout = null;
755
+ }
756
+ webSocket?.send(
757
+ JSON.stringify({
758
+ op: "subscribe",
759
+ channel: "swap.update",
760
+ args: [swapId]
761
+ })
762
+ );
763
+ };
764
+ webSocket.onclose = () => {
765
+ if (connectionTimeout) {
766
+ clearTimeout(connectionTimeout);
767
+ connectionTimeout = null;
768
+ }
769
+ if (!settled && !pollTimer) startPolling();
770
+ };
771
+ webSocket.onmessage = (rawMsg) => {
772
+ try {
773
+ const msg = JSON.parse(rawMsg.data);
774
+ if (msg.event !== "update" || msg.args?.[0]?.id !== swapId) return;
775
+ if (msg.args[0].error) {
776
+ finish(new SwapError({ message: msg.args[0].error }));
777
+ return;
778
+ }
779
+ handleStatus(msg.args[0].status, msg.args[0]);
780
+ } catch {
781
+ }
782
+ };
783
+ } catch {
784
+ webSocket = null;
785
+ startPolling();
786
+ }
658
787
  });
659
788
  }
660
789
  /** Returns current chain swap fees for a given pair (e.g. ARK→BTC). */
@@ -662,10 +791,7 @@ var BoltzSwapProvider = class {
662
791
  if (from === to) {
663
792
  throw new SwapError({ message: "Invalid chain pair" });
664
793
  }
665
- const response = await this.request(
666
- "/v2/swap/chain",
667
- "GET"
668
- );
794
+ const response = await this.request("/v2/swap/chain", "GET");
669
795
  if (!isGetChainPairsResponse(response))
670
796
  throw new SchemaError({ message: "error fetching fees" });
671
797
  if (!response[from]?.[to]) {
@@ -680,10 +806,7 @@ var BoltzSwapProvider = class {
680
806
  if (from === to) {
681
807
  throw new SwapError({ message: "Invalid chain pair" });
682
808
  }
683
- const response = await this.request(
684
- "/v2/swap/chain",
685
- "GET"
686
- );
809
+ const response = await this.request("/v2/swap/chain", "GET");
687
810
  if (!isGetChainPairsResponse(response))
688
811
  throw new SchemaError({ message: "error fetching limits" });
689
812
  if (!response[from]?.[to]) {
@@ -812,9 +935,7 @@ var BoltzSwapProvider = class {
812
935
  return await response.json();
813
936
  } catch (error) {
814
937
  if (error instanceof NetworkError) throw error;
815
- throw new NetworkError(
816
- `Request to ${url} failed: ${error.message}`
817
- );
938
+ throw new NetworkError(`Request to ${url} failed: ${error.message}`);
818
939
  }
819
940
  }
820
941
  };
@@ -837,8 +958,7 @@ var findKeyIndex = (keys, target) => keys.findIndex((k) => (0, import_utils.equa
837
958
  var assertPublicKeys = (keys) => {
838
959
  const seen = /* @__PURE__ */ new Set();
839
960
  for (const key of keys) {
840
- if (key.length !== 33)
841
- throw new Error(`public key must be 33 bytes, got ${key.length}`);
961
+ if (key.length !== 33) throw new Error(`public key must be 33 bytes, got ${key.length}`);
842
962
  const enc = import_base2.hex.encode(key);
843
963
  if (seen.has(enc)) throw new Error(`duplicate public key ${enc}`);
844
964
  seen.add(enc);
@@ -846,9 +966,7 @@ var assertPublicKeys = (keys) => {
846
966
  };
847
967
  var aggregateKeys = (publicKeys, tweak) => {
848
968
  assertPublicKeys([...publicKeys]);
849
- return (0, import_musig2.keyAggExport)(
850
- (0, import_musig2.keyAggregate)([...publicKeys], tweak ? [tweak] : [], tweak ? [true] : [])
851
- );
969
+ return (0, import_musig2.keyAggExport)((0, import_musig2.keyAggregate)([...publicKeys], tweak ? [tweak] : [], tweak ? [true] : []));
852
970
  };
853
971
  var MusigKeyAgg = class _MusigKeyAgg {
854
972
  constructor(privateKey, myPublicKey, publicKeys, myIndex, aggPubkey, internalKey, _tweak) {
@@ -895,18 +1013,12 @@ var MusigWithMessage = class {
895
1013
  this.msg = msg;
896
1014
  }
897
1015
  generateNonce() {
898
- const nonce = (0, import_musig2.nonceGen)(
899
- this.myPublicKey,
900
- this.privateKey,
901
- this.aggPubkey,
902
- this.msg
903
- );
1016
+ const nonce = (0, import_musig2.nonceGen)(this.myPublicKey, this.privateKey, this.aggPubkey, this.msg);
904
1017
  return new MusigWithNonce(
905
1018
  this.privateKey,
906
1019
  this.myPublicKey,
907
1020
  this.publicKeys,
908
1021
  this.myIndex,
909
- this.aggPubkey,
910
1022
  this.tweak,
911
1023
  this.msg,
912
1024
  nonce
@@ -914,12 +1026,11 @@ var MusigWithMessage = class {
914
1026
  }
915
1027
  };
916
1028
  var MusigWithNonce = class {
917
- constructor(privateKey, myPublicKey, publicKeys, myIndex, aggPubkey, tweak, msg, nonce) {
1029
+ constructor(privateKey, myPublicKey, publicKeys, myIndex, tweak, msg, nonce) {
918
1030
  this.privateKey = privateKey;
919
1031
  this.myPublicKey = myPublicKey;
920
1032
  this.publicKeys = publicKeys;
921
1033
  this.myIndex = myIndex;
922
- this.aggPubkey = aggPubkey;
923
1034
  this.tweak = tweak;
924
1035
  this.msg = msg;
925
1036
  this.nonce = nonce;
@@ -951,10 +1062,8 @@ var MusigWithNonce = class {
951
1062
  const aggregatedNonce = (0, import_musig2.nonceAggregate)([...ordered]);
952
1063
  return new MusigNoncesAggregated(
953
1064
  this.privateKey,
954
- this.myPublicKey,
955
1065
  this.publicKeys,
956
1066
  this.myIndex,
957
- this.aggPubkey,
958
1067
  this.tweak,
959
1068
  this.msg,
960
1069
  this.nonce,
@@ -964,12 +1073,10 @@ var MusigWithNonce = class {
964
1073
  }
965
1074
  };
966
1075
  var MusigNoncesAggregated = class {
967
- constructor(privateKey, myPublicKey, publicKeys, myIndex, aggPubkey, tweak, msg, nonce, pubNonces, aggregatedNonce) {
1076
+ constructor(privateKey, publicKeys, myIndex, tweak, msg, nonce, pubNonces, aggregatedNonce) {
968
1077
  this.privateKey = privateKey;
969
- this.myPublicKey = myPublicKey;
970
1078
  this.publicKeys = publicKeys;
971
1079
  this.myIndex = myIndex;
972
- this.aggPubkey = aggPubkey;
973
1080
  this.tweak = tweak;
974
1081
  this.msg = msg;
975
1082
  this.nonce = nonce;
@@ -1015,11 +1122,7 @@ var MusigSession = class {
1015
1122
  const index = typeof publicKeyOrIndex === "number" ? publicKeyOrIndex : findKeyIndex(this.publicKeys, publicKeyOrIndex);
1016
1123
  if (index < 0 || index >= this.publicKeys.length)
1017
1124
  throw new Error("public key not found or index out of range");
1018
- if (!this.session.partialSigVerify(
1019
- signature,
1020
- [...this.pubNonces],
1021
- index
1022
- )) {
1125
+ if (!this.session.partialSigVerify(signature, [...this.pubNonces], index)) {
1023
1126
  throw new Error("invalid partial signature");
1024
1127
  }
1025
1128
  this.partialSignatures[index] = signature;
@@ -1028,12 +1131,7 @@ var MusigSession = class {
1028
1131
  signPartial() {
1029
1132
  const sig = this.session.sign(this.nonce.secret, this.privateKey, true);
1030
1133
  this.partialSignatures[this.myIndex] = sig;
1031
- return new MusigSigned(
1032
- this.session,
1033
- [...this.partialSignatures],
1034
- sig,
1035
- this.nonce.public
1036
- );
1134
+ return new MusigSigned(this.session, [...this.partialSignatures], sig, this.nonce.public);
1037
1135
  }
1038
1136
  };
1039
1137
  var MusigSigned = class {
@@ -1047,14 +1145,11 @@ var MusigSigned = class {
1047
1145
  if (this.partialSignatures.some((s) => s === null)) {
1048
1146
  throw new Error("not all partial signatures are set");
1049
1147
  }
1050
- return this.session.partialSigAgg(
1051
- this.partialSignatures
1052
- );
1148
+ return this.session.partialSigAgg(this.partialSignatures);
1053
1149
  }
1054
1150
  };
1055
1151
  var create = (privateKey, publicKeys) => {
1056
- if (publicKeys.length < 2)
1057
- throw new Error("need at least 2 keys to aggregate");
1152
+ if (publicKeys.length < 2) throw new Error("need at least 2 keys to aggregate");
1058
1153
  const keys = [...publicKeys];
1059
1154
  assertPublicKeys(keys);
1060
1155
  Object.freeze(keys);
@@ -1062,14 +1157,7 @@ var create = (privateKey, publicKeys) => {
1062
1157
  const myIndex = findKeyIndex(keys, myPublicKey);
1063
1158
  if (myIndex === -1) throw new Error("our key is not in publicKeys");
1064
1159
  const aggPubkey = aggregateKeys(keys);
1065
- return new MusigKeyAgg(
1066
- privateKey,
1067
- myPublicKey,
1068
- keys,
1069
- myIndex,
1070
- aggPubkey,
1071
- aggPubkey
1072
- );
1160
+ return new MusigKeyAgg(privateKey, myPublicKey, keys, myIndex, aggPubkey, aggPubkey);
1073
1161
  };
1074
1162
 
1075
1163
  // src/utils/boltz-swap-tx.ts
@@ -1145,9 +1233,7 @@ var taprootHashTree = (tree) => {
1145
1233
  };
1146
1234
  var tweakMusig = (musig, tree) => {
1147
1235
  const tweak = taprootHashTree(tree).hash;
1148
- return musig.xonlyTweakAdd(
1149
- import_secp256k12.schnorr.utils.taggedHash("TapTweak", musig.aggPubkey, tweak)
1150
- );
1236
+ return musig.xonlyTweakAdd(import_secp256k12.schnorr.utils.taggedHash("TapTweak", musig.aggPubkey, tweak));
1151
1237
  };
1152
1238
  var toXOnly = (pubKey) => {
1153
1239
  if (pubKey.length === 32) return pubKey;
@@ -1159,9 +1245,7 @@ var toXOnly = (pubKey) => {
1159
1245
  }
1160
1246
  return pubKey.subarray(1, 33);
1161
1247
  }
1162
- throw new Error(
1163
- `Invalid public key length: expected 32 or 33 bytes, got ${pubKey.length}`
1164
- );
1248
+ throw new Error(`Invalid public key length: expected 32 or 33 bytes, got ${pubKey.length}`);
1165
1249
  };
1166
1250
  var p2trScript = (publicKey) => import_btc_signer.Script.encode(["OP_1", toXOnly(publicKey)]);
1167
1251
  var detectSwapOutput = (tweakedKey, transaction) => {
@@ -1176,8 +1260,7 @@ var detectSwapOutput = (tweakedKey, transaction) => {
1176
1260
  };
1177
1261
  var DUMMY_TAPROOT_SIGNATURE = new Uint8Array(64);
1178
1262
  var constructClaimTransaction = (utxo, destinationScript, fee) => {
1179
- if (fee < BigInt(0) || fee >= utxo.amount)
1180
- throw new Error("fee exceeds utxo amount");
1263
+ if (fee < BigInt(0) || fee >= utxo.amount) throw new Error("fee exceeds utxo amount");
1181
1264
  const tx = new import_btc_signer.Transaction({ version: 2 });
1182
1265
  tx.addOutput({
1183
1266
  amount: utxo.amount - fee,
@@ -1196,9 +1279,7 @@ var constructClaimTransaction = (utxo, destinationScript, fee) => {
1196
1279
  };
1197
1280
  var targetFee = (satPerVbyte, constructTx) => {
1198
1281
  const tx = constructTx(BigInt(1));
1199
- return constructTx(
1200
- BigInt(Math.ceil((tx.vsize + tx.inputsLength) * satPerVbyte))
1201
- );
1282
+ return constructTx(BigInt(Math.ceil((tx.vsize + tx.inputsLength) * satPerVbyte)));
1202
1283
  };
1203
1284
 
1204
1285
  // src/utils/decoding.ts
@@ -1206,9 +1287,7 @@ var import_light_bolt11_decoder = __toESM(require("light-bolt11-decoder"), 1);
1206
1287
  var import_sdk2 = require("@arkade-os/sdk");
1207
1288
  var decodeInvoice = (invoice) => {
1208
1289
  const decoded = import_light_bolt11_decoder.default.decode(invoice);
1209
- const millisats = Number(
1210
- decoded.sections.find((s) => s.name === "amount")?.value ?? "0"
1211
- );
1290
+ const millisats = Number(decoded.sections.find((s) => s.name === "amount")?.value ?? "0");
1212
1291
  return {
1213
1292
  expiry: decoded.expiry ?? 3600,
1214
1293
  amountSats: Math.floor(millisats / 1e3),
@@ -1271,10 +1350,7 @@ function extractTimeLockFromLeafOutput(scriptHex) {
1271
1350
  const data = opcodes[hasCSV - 1];
1272
1351
  if (data instanceof Uint8Array) {
1273
1352
  const dataBytes = new Uint8Array(data).reverse();
1274
- const {
1275
- blocks,
1276
- seconds
1277
- } = import_bip68.default.decode(
1353
+ const { blocks, seconds } = import_bip68.default.decode(
1278
1354
  parseInt(import_base5.hex.encode(dataBytes), 16)
1279
1355
  );
1280
1356
  return blocks ?? seconds ?? 0;
@@ -1378,9 +1454,7 @@ var SwapManager = class _SwapManager {
1378
1454
  this.wsConnectedListeners.add(config.events.onWebSocketConnected);
1379
1455
  }
1380
1456
  if (config.events?.onWebSocketDisconnected) {
1381
- this.wsDisconnectedListeners.add(
1382
- config.events.onWebSocketDisconnected
1383
- );
1457
+ this.wsDisconnectedListeners.add(config.events.onWebSocketDisconnected);
1384
1458
  }
1385
1459
  this.currentReconnectDelay = this.config.reconnectDelayMs;
1386
1460
  this.currentPollRetryDelay = this.config.pollRetryDelayMs;
@@ -1531,9 +1605,7 @@ var SwapManager = class _SwapManager {
1531
1605
  */
1532
1606
  setPollInterval(ms) {
1533
1607
  if (ms <= 0) {
1534
- throw new RangeError(
1535
- `setPollInterval: ms must be a positive number, got ${ms}`
1536
- );
1608
+ throw new RangeError(`setPollInterval: ms must be a positive number, got ${ms}`);
1537
1609
  }
1538
1610
  const cappedInterval = Math.min(ms, this.config.maxPollIntervalMs);
1539
1611
  if (cappedInterval !== ms) {
@@ -1542,10 +1614,7 @@ var SwapManager = class _SwapManager {
1542
1614
  );
1543
1615
  }
1544
1616
  this.config.pollInterval = cappedInterval;
1545
- this.currentPollRetryDelay = Math.min(
1546
- cappedInterval,
1547
- this.config.pollRetryDelayMs
1548
- );
1617
+ this.currentPollRetryDelay = Math.min(cappedInterval, this.config.pollRetryDelayMs);
1549
1618
  if (this.isRunning) {
1550
1619
  if (this.usePollingFallback) {
1551
1620
  this.startPollingFallback();
@@ -1630,9 +1699,7 @@ var SwapManager = class _SwapManager {
1630
1699
  }
1631
1700
  if (this.isFinalStatus(swap)) {
1632
1701
  if (isPendingReverseSwap(swap)) {
1633
- const response = await this.swapProvider.getReverseSwapTxId(
1634
- swap.id
1635
- );
1702
+ const response = await this.swapProvider.getReverseSwapTxId(swap.id);
1636
1703
  return { txid: response.id };
1637
1704
  }
1638
1705
  if (isPendingSubmarineSwap(swap)) {
@@ -1649,31 +1716,19 @@ var SwapManager = class _SwapManager {
1649
1716
  if (updatedSwap.status === "invoice.settled") {
1650
1717
  this.swapProvider.getReverseSwapTxId(updatedSwap.id).then((response) => resolve({ txid: response.id })).catch((error) => reject(error));
1651
1718
  } else {
1652
- reject(
1653
- new Error(
1654
- `Swap failed with status: ${updatedSwap.status}`
1655
- )
1656
- );
1719
+ reject(new Error(`Swap failed with status: ${updatedSwap.status}`));
1657
1720
  }
1658
1721
  } else if (isPendingSubmarineSwap(updatedSwap)) {
1659
1722
  if (updatedSwap.status === "transaction.claimed") {
1660
1723
  resolve({ txid: updatedSwap.id });
1661
1724
  } else {
1662
- reject(
1663
- new Error(
1664
- `Swap failed with status: ${updatedSwap.status}`
1665
- )
1666
- );
1725
+ reject(new Error(`Swap failed with status: ${updatedSwap.status}`));
1667
1726
  }
1668
1727
  } else if (isPendingChainSwap(updatedSwap)) {
1669
1728
  if (updatedSwap.status === "transaction.claimed") {
1670
1729
  resolve({ txid: updatedSwap.id });
1671
1730
  } else {
1672
- reject(
1673
- new Error(
1674
- `Swap failed with status: ${updatedSwap.status}`
1675
- )
1676
- );
1731
+ reject(new Error(`Swap failed with status: ${updatedSwap.status}`));
1677
1732
  }
1678
1733
  }
1679
1734
  };
@@ -1716,16 +1771,12 @@ var SwapManager = class _SwapManager {
1716
1771
  const connectionTimeout = setTimeout(() => {
1717
1772
  logger.error("WebSocket connection timeout");
1718
1773
  this.websocket?.close();
1719
- this.enterPollingFallback(
1720
- new NetworkError("WebSocket connection failed")
1721
- );
1774
+ this.enterPollingFallback(new NetworkError("WebSocket connection failed"));
1722
1775
  }, 1e4);
1723
1776
  this.websocket.onerror = (error) => {
1724
1777
  clearTimeout(connectionTimeout);
1725
1778
  logger.error("WebSocket error:", error);
1726
- this.enterPollingFallback(
1727
- new NetworkError("WebSocket connection failed")
1728
- );
1779
+ this.enterPollingFallback(new NetworkError("WebSocket connection failed"));
1729
1780
  };
1730
1781
  this.websocket.onopen = () => {
1731
1782
  clearTimeout(connectionTimeout);
@@ -1765,9 +1816,7 @@ var SwapManager = class _SwapManager {
1765
1816
  };
1766
1817
  } catch (error) {
1767
1818
  logger.error("Failed to create WebSocket:", error);
1768
- this.enterPollingFallback(
1769
- new NetworkError("WebSocket connection failed")
1770
- );
1819
+ this.enterPollingFallback(new NetworkError("WebSocket connection failed"));
1771
1820
  }
1772
1821
  }
1773
1822
  /**
@@ -1802,11 +1851,8 @@ var SwapManager = class _SwapManager {
1802
1851
  * Schedule WebSocket reconnection with exponential backoff
1803
1852
  */
1804
1853
  scheduleReconnect() {
1805
- if (this.reconnectTimer || this.webSocketUnavailable || !this.hasWebSocketSupport())
1806
- return;
1807
- logger.log(
1808
- `Scheduling WebSocket reconnect in ${this.currentReconnectDelay}ms`
1809
- );
1854
+ if (this.reconnectTimer || this.webSocketUnavailable || !this.hasWebSocketSupport()) return;
1855
+ logger.log(`Scheduling WebSocket reconnect in ${this.currentReconnectDelay}ms`);
1810
1856
  this.reconnectTimer = setTimeout(() => {
1811
1857
  this.reconnectTimer = null;
1812
1858
  this.isReconnecting = false;
@@ -1821,8 +1867,7 @@ var SwapManager = class _SwapManager {
1821
1867
  * Subscribe to a specific swap ID on the WebSocket
1822
1868
  */
1823
1869
  subscribeToSwap(swapId) {
1824
- if (!this.websocket || this.websocket.readyState !== WebSocket.OPEN)
1825
- return;
1870
+ if (!this.websocket || this.websocket.readyState !== WebSocket.OPEN) return;
1826
1871
  this.websocket.send(
1827
1872
  JSON.stringify({
1828
1873
  op: "subscribe",
@@ -1845,9 +1890,7 @@ var SwapManager = class _SwapManager {
1845
1890
  if (msg.args[0].error) {
1846
1891
  logger.error(`Swap ${swapId} error:`, msg.args[0].error);
1847
1892
  const error = new Error(msg.args[0].error);
1848
- this.swapFailedListeners.forEach(
1849
- (listener) => listener(swap, error)
1850
- );
1893
+ this.swapFailedListeners.forEach((listener) => listener(swap, error));
1851
1894
  return;
1852
1895
  }
1853
1896
  const newStatus = msg.args[0].status;
@@ -1865,19 +1908,14 @@ var SwapManager = class _SwapManager {
1865
1908
  const oldStatus = swap.status;
1866
1909
  if (oldStatus === newStatus) return;
1867
1910
  swap.status = newStatus;
1868
- this.swapUpdateListeners.forEach(
1869
- (listener) => listener(swap, oldStatus)
1870
- );
1911
+ this.swapUpdateListeners.forEach((listener) => listener(swap, oldStatus));
1871
1912
  const subscribers = this.swapSubscriptions.get(swap.id);
1872
1913
  if (subscribers) {
1873
1914
  subscribers.forEach((callback) => {
1874
1915
  try {
1875
1916
  callback(swap, oldStatus);
1876
1917
  } catch (error) {
1877
- logger.error(
1878
- `Error in swap subscription callback for ${swap.id}:`,
1879
- error
1880
- );
1918
+ logger.error(`Error in swap subscription callback for ${swap.id}:`, error);
1881
1919
  }
1882
1920
  });
1883
1921
  }
@@ -1902,9 +1940,7 @@ var SwapManager = class _SwapManager {
1902
1940
  */
1903
1941
  async executeAutonomousAction(swap) {
1904
1942
  if (this.swapsInProgress.has(swap.id)) {
1905
- logger.log(
1906
- `Swap ${swap.id} is already being processed, skipping autonomous action`
1907
- );
1943
+ logger.log(`Swap ${swap.id} is already being processed, skipping autonomous action`);
1908
1944
  return;
1909
1945
  }
1910
1946
  try {
@@ -1919,9 +1955,7 @@ var SwapManager = class _SwapManager {
1919
1955
  if (isReverseClaimableStatus(swap.status)) {
1920
1956
  logger.log(`Auto-claiming reverse swap ${swap.id}`);
1921
1957
  await this.executeClaimAction(swap);
1922
- this.actionExecutedListeners.forEach(
1923
- (listener) => listener(swap, "claim")
1924
- );
1958
+ this.actionExecutedListeners.forEach((listener) => listener(swap, "claim"));
1925
1959
  }
1926
1960
  } else if (isPendingSubmarineSwap(swap)) {
1927
1961
  if (!swap.request?.invoice || swap.request.invoice.length === 0) {
@@ -1933,9 +1967,7 @@ var SwapManager = class _SwapManager {
1933
1967
  if (isSubmarineRefundableStatus(swap.status)) {
1934
1968
  logger.log(`Auto-refunding submarine swap ${swap.id}`);
1935
1969
  await this.executeRefundAction(swap);
1936
- this.actionExecutedListeners.forEach(
1937
- (listener) => listener(swap, "refund")
1938
- );
1970
+ this.actionExecutedListeners.forEach((listener) => listener(swap, "refund"));
1939
1971
  }
1940
1972
  } else if (isPendingChainSwap(swap)) {
1941
1973
  if (isChainClaimableStatus(swap.status)) {
@@ -1985,13 +2017,8 @@ var SwapManager = class _SwapManager {
1985
2017
  }
1986
2018
  }
1987
2019
  } catch (error) {
1988
- logger.error(
1989
- `Failed to execute autonomous action for swap ${swap.id}:`,
1990
- error
1991
- );
1992
- this.swapFailedListeners.forEach(
1993
- (listener) => listener(swap, error)
1994
- );
2020
+ logger.error(`Failed to execute autonomous action for swap ${swap.id}:`, error);
2021
+ this.swapFailedListeners.forEach((listener) => listener(swap, error));
1995
2022
  } finally {
1996
2023
  this.swapsInProgress.delete(swap.id);
1997
2024
  }
@@ -2092,9 +2119,7 @@ var SwapManager = class _SwapManager {
2092
2119
  logger.log(`Resuming chain refund for swap ${swap.id}`);
2093
2120
  await this.executeAutonomousAction(swap);
2094
2121
  } else if (isPendingChainSwap(swap) && swap.request.to === "ARK" && isChainSignableStatus(swap.status)) {
2095
- logger.log(
2096
- `Resuming server claim signing for swap ${swap.id}`
2097
- );
2122
+ logger.log(`Resuming server claim signing for swap ${swap.id}`);
2098
2123
  await this.executeAutonomousAction(swap);
2099
2124
  }
2100
2125
  } catch (error) {
@@ -2153,9 +2178,7 @@ var SwapManager = class _SwapManager {
2153
2178
  }
2154
2179
  async pollSingleSwap(swap) {
2155
2180
  try {
2156
- const statusResponse = await this.swapProvider.getSwapStatus(
2157
- swap.id
2158
- );
2181
+ const statusResponse = await this.swapProvider.getSwapStatus(swap.id);
2159
2182
  this.notFoundCounts.delete(swap.id);
2160
2183
  if (statusResponse.status !== swap.status) {
2161
2184
  await this.handleSwapStatusUpdate(swap, statusResponse.status);
@@ -2166,9 +2189,7 @@ var SwapManager = class _SwapManager {
2166
2189
  return;
2167
2190
  }
2168
2191
  if (error instanceof NetworkError && error.statusCode === 429) {
2169
- logger.warn(
2170
- `Rate-limited polling swap ${swap.id}, retrying in 2s`
2171
- );
2192
+ logger.warn(`Rate-limited polling swap ${swap.id}, retrying in 2s`);
2172
2193
  const existing = this.pollRetryTimers.get(swap.id);
2173
2194
  if (existing) clearTimeout(existing);
2174
2195
  this.pollRetryTimers.set(
@@ -2176,25 +2197,17 @@ var SwapManager = class _SwapManager {
2176
2197
  setTimeout(async () => {
2177
2198
  this.pollRetryTimers.delete(swap.id);
2178
2199
  try {
2179
- const retry = await this.swapProvider.getSwapStatus(
2180
- swap.id
2181
- );
2200
+ const retry = await this.swapProvider.getSwapStatus(swap.id);
2182
2201
  this.notFoundCounts.delete(swap.id);
2183
2202
  if (retry.status !== swap.status) {
2184
- await this.handleSwapStatusUpdate(
2185
- swap,
2186
- retry.status
2187
- );
2203
+ await this.handleSwapStatusUpdate(swap, retry.status);
2188
2204
  }
2189
2205
  } catch (retryError) {
2190
2206
  if (retryError instanceof SwapNotFoundError) {
2191
2207
  await this.handleSwapNotFound(swap);
2192
2208
  return;
2193
2209
  }
2194
- logger.error(
2195
- `Retry poll for swap ${swap.id} also failed:`,
2196
- retryError
2197
- );
2210
+ logger.error(`Retry poll for swap ${swap.id} also failed:`, retryError);
2198
2211
  }
2199
2212
  }, 2e3)
2200
2213
  );
@@ -2246,9 +2259,7 @@ var SwapManager = class _SwapManager {
2246
2259
  this.pollRetryTimers.delete(swap.id);
2247
2260
  }
2248
2261
  this.notFoundCounts.delete(swap.id);
2249
- this.swapUpdateListeners.forEach(
2250
- (listener) => listener(swap, oldStatus)
2251
- );
2262
+ this.swapUpdateListeners.forEach((listener) => listener(swap, oldStatus));
2252
2263
  const subscribers = this.swapSubscriptions.get(swap.id);
2253
2264
  if (subscribers) {
2254
2265
  subscribers.forEach((callback) => {
@@ -2313,9 +2324,7 @@ async function saveSwap(swap, saver) {
2313
2324
  if (saver.saveSubmarineSwap) {
2314
2325
  await saver.saveSubmarineSwap(swap);
2315
2326
  } else {
2316
- console.warn(
2317
- "No saveSubmarineSwap handler provided, swap not saved"
2318
- );
2327
+ console.warn("No saveSubmarineSwap handler provided, swap not saved");
2319
2328
  }
2320
2329
  } else if (isPendingChainSwap(swap)) {
2321
2330
  if (saver.saveChainSwap) {
@@ -2372,6 +2381,26 @@ function enrichSubmarineSwapInvoice(swap, invoice) {
2372
2381
  return swap;
2373
2382
  }
2374
2383
 
2384
+ // src/repositories/swap-repository.ts
2385
+ function hasImpossibleSwapsFilter(filter) {
2386
+ if (!filter) return false;
2387
+ return Array.isArray(filter.id) && filter.id.length === 0 || Array.isArray(filter.status) && filter.status.length === 0 || Array.isArray(filter.type) && filter.type.length === 0;
2388
+ }
2389
+ function matchesCriterion(value, criterion) {
2390
+ if (criterion === void 0) return true;
2391
+ return Array.isArray(criterion) ? criterion.includes(value) : value === criterion;
2392
+ }
2393
+ function applySwapsFilter(swaps, filter) {
2394
+ return swaps.filter(
2395
+ (swap) => !!swap && matchesCriterion(swap.id, filter.id) && matchesCriterion(swap.status, filter.status) && matchesCriterion(swap.type, filter.type)
2396
+ );
2397
+ }
2398
+ function applyCreatedAtOrder(swaps, filter) {
2399
+ if (filter?.orderBy !== "createdAt") return swaps;
2400
+ const direction = filter.orderDirection === "asc" ? 1 : -1;
2401
+ return swaps.slice().sort((a, b) => (a.createdAt - b.createdAt) * direction);
2402
+ }
2403
+
2375
2404
  // src/repositories/IndexedDb/swap-repository.ts
2376
2405
  var import_sdk4 = require("@arkade-os/sdk");
2377
2406
  var DEFAULT_DB_NAME = "arkade-boltz-swap";
@@ -2387,6 +2416,10 @@ function initDatabase(db) {
2387
2416
  swapStore.createIndex("createdAt", "createdAt", { unique: false });
2388
2417
  }
2389
2418
  }
2419
+ function asArray(v) {
2420
+ if (v === void 0) return void 0;
2421
+ return Array.isArray(v) ? v : [v];
2422
+ }
2390
2423
  var IndexedDbSwapRepository = class {
2391
2424
  constructor(dbName = DEFAULT_DB_NAME) {
2392
2425
  this.dbName = dbName;
@@ -2401,10 +2434,7 @@ var IndexedDbSwapRepository = class {
2401
2434
  async saveSwap(swap) {
2402
2435
  const db = await this.getDB();
2403
2436
  return new Promise((resolve, reject) => {
2404
- const transaction = db.transaction(
2405
- [STORE_SWAPS_STATE],
2406
- "readwrite"
2407
- );
2437
+ const transaction = db.transaction([STORE_SWAPS_STATE], "readwrite");
2408
2438
  const store = transaction.objectStore(STORE_SWAPS_STATE);
2409
2439
  const request = store.put(swap);
2410
2440
  request.onsuccess = () => resolve();
@@ -2414,10 +2444,7 @@ var IndexedDbSwapRepository = class {
2414
2444
  async deleteSwap(id) {
2415
2445
  const db = await this.getDB();
2416
2446
  return new Promise((resolve, reject) => {
2417
- const transaction = db.transaction(
2418
- [STORE_SWAPS_STATE],
2419
- "readwrite"
2420
- );
2447
+ const transaction = db.transaction([STORE_SWAPS_STATE], "readwrite");
2421
2448
  const store = transaction.objectStore(STORE_SWAPS_STATE);
2422
2449
  const request = store.delete(id);
2423
2450
  request.onsuccess = () => resolve();
@@ -2430,10 +2457,7 @@ var IndexedDbSwapRepository = class {
2430
2457
  async clear() {
2431
2458
  const db = await this.getDB();
2432
2459
  return new Promise((resolve, reject) => {
2433
- const transaction = db.transaction(
2434
- [STORE_SWAPS_STATE],
2435
- "readwrite"
2436
- );
2460
+ const transaction = db.transaction([STORE_SWAPS_STATE], "readwrite");
2437
2461
  const store = transaction.objectStore(STORE_SWAPS_STATE);
2438
2462
  const request = store.clear();
2439
2463
  request.onsuccess = () => resolve();
@@ -2450,11 +2474,10 @@ var IndexedDbSwapRepository = class {
2450
2474
  request.onsuccess = () => resolve(request.result ?? []);
2451
2475
  })
2452
2476
  );
2453
- return Promise.all(requests).then(
2454
- (results) => results.flatMap((result) => result)
2455
- );
2477
+ return Promise.all(requests).then((results) => results.flatMap((result) => result));
2456
2478
  }
2457
2479
  async getAllSwapsFromStore(filter) {
2480
+ if (hasImpossibleSwapsFilter(filter)) return [];
2458
2481
  const db = await this.getDB();
2459
2482
  const store = db.transaction([STORE_SWAPS_STATE], "readonly").objectStore(STORE_SWAPS_STATE);
2460
2483
  if (!filter || Object.keys(filter).length === 0) {
@@ -2464,9 +2487,8 @@ var IndexedDbSwapRepository = class {
2464
2487
  request.onerror = () => reject(request.error);
2465
2488
  });
2466
2489
  }
2467
- const normalizedFilter = normalizeFilter(filter);
2468
- if (normalizedFilter.has("id")) {
2469
- const ids = normalizedFilter.get("id");
2490
+ const ids = asArray(filter.id);
2491
+ if (ids) {
2470
2492
  const swaps = await Promise.all(
2471
2493
  ids.map(
2472
2494
  (id) => new Promise((resolve, reject) => {
@@ -2476,34 +2498,17 @@ var IndexedDbSwapRepository = class {
2476
2498
  })
2477
2499
  )
2478
2500
  );
2479
- return this.sortIfNeeded(
2480
- this.applySwapsFilter(swaps, normalizedFilter),
2481
- filter
2482
- );
2501
+ return applyCreatedAtOrder(applySwapsFilter(swaps, filter), filter);
2483
2502
  }
2484
- if (normalizedFilter.has("type")) {
2485
- const types = normalizedFilter.get("type");
2486
- const swaps = await this.getSwapsByIndexValues(
2487
- store,
2488
- "type",
2489
- types
2490
- );
2491
- return this.sortIfNeeded(
2492
- this.applySwapsFilter(swaps, normalizedFilter),
2493
- filter
2494
- );
2503
+ const types = asArray(filter.type);
2504
+ if (types) {
2505
+ const swaps = await this.getSwapsByIndexValues(store, "type", types);
2506
+ return applyCreatedAtOrder(applySwapsFilter(swaps, filter), filter);
2495
2507
  }
2496
- if (normalizedFilter.has("status")) {
2497
- const ids = normalizedFilter.get("status");
2498
- const swaps = await this.getSwapsByIndexValues(
2499
- store,
2500
- "status",
2501
- ids
2502
- );
2503
- return this.sortIfNeeded(
2504
- this.applySwapsFilter(swaps, normalizedFilter),
2505
- filter
2506
- );
2508
+ const statuses = asArray(filter.status);
2509
+ if (statuses) {
2510
+ const swaps = await this.getSwapsByIndexValues(store, "status", statuses);
2511
+ return applyCreatedAtOrder(applySwapsFilter(swaps, filter), filter);
2507
2512
  }
2508
2513
  if (filter.orderBy === "createdAt") {
2509
2514
  return this.getAllSwapsByCreatedAt(store, filter.orderDirection);
@@ -2513,22 +2518,7 @@ var IndexedDbSwapRepository = class {
2513
2518
  request.onsuccess = () => resolve(request.result ?? []);
2514
2519
  request.onerror = () => reject(request.error);
2515
2520
  });
2516
- return this.sortIfNeeded(
2517
- this.applySwapsFilter(allSwaps, normalizedFilter),
2518
- filter
2519
- );
2520
- }
2521
- applySwapsFilter(swaps, filter) {
2522
- return swaps.filter((swap) => {
2523
- if (swap === void 0) return false;
2524
- if (filter.has("id") && !filter.get("id")?.includes(swap.id))
2525
- return false;
2526
- if (filter.has("status") && !filter.get("status")?.includes(swap.status))
2527
- return false;
2528
- if (filter.has("type") && !filter.get("type")?.includes(swap.type))
2529
- return false;
2530
- return true;
2531
- });
2521
+ return applyCreatedAtOrder(applySwapsFilter(allSwaps, filter), filter);
2532
2522
  }
2533
2523
  async getAllSwapsByCreatedAt(store, orderDirection) {
2534
2524
  const index = store.index("createdAt");
@@ -2548,30 +2538,12 @@ var IndexedDbSwapRepository = class {
2548
2538
  };
2549
2539
  });
2550
2540
  }
2551
- sortIfNeeded(swaps, filter) {
2552
- if (filter?.orderBy !== "createdAt") return swaps;
2553
- const direction = filter.orderDirection === "asc" ? 1 : -1;
2554
- return swaps.slice().sort((a, b) => (a.createdAt - b.createdAt) * direction);
2555
- }
2556
2541
  async [Symbol.asyncDispose]() {
2557
2542
  if (!this.db) return;
2558
2543
  await (0, import_sdk4.closeDatabase)(this.dbName);
2559
2544
  this.db = null;
2560
2545
  }
2561
2546
  };
2562
- var FILTER_FIELDS = ["id", "status", "type"];
2563
- function normalizeFilter(filter) {
2564
- const res = /* @__PURE__ */ new Map();
2565
- FILTER_FIELDS.forEach((current) => {
2566
- if (!filter?.[current]) return;
2567
- if (Array.isArray(filter[current])) {
2568
- res.set(current, filter[current]);
2569
- } else {
2570
- res.set(current, [filter[current]]);
2571
- }
2572
- });
2573
- return res;
2574
- }
2575
2547
 
2576
2548
  // src/utils/identity.ts
2577
2549
  var import_sdk5 = require("@arkade-os/sdk");
@@ -2583,13 +2555,8 @@ function claimVHTLCIdentity(identity, preimage) {
2583
2555
  let signedTx = await identity.sign(cpy, inputIndexes);
2584
2556
  signedTx = import_sdk5.Transaction.fromPSBT(signedTx.toPSBT());
2585
2557
  if (preimage) {
2586
- for (const inputIndex of inputIndexes || Array.from(
2587
- { length: signedTx.inputsLength },
2588
- (_, i) => i
2589
- )) {
2590
- (0, import_sdk5.setArkPsbtField)(signedTx, inputIndex, import_sdk5.ConditionWitness, [
2591
- preimage
2592
- ]);
2558
+ for (const inputIndex of inputIndexes || Array.from({ length: signedTx.inputsLength }, (_, i) => i)) {
2559
+ (0, import_sdk5.setArkPsbtField)(signedTx, inputIndex, import_sdk5.ConditionWitness, [preimage]);
2593
2560
  }
2594
2561
  }
2595
2562
  return signedTx;
@@ -2644,17 +2611,13 @@ function createVHTLCBatchHandler(intentId, vhtlc, arkProvider, identity, session
2644
2611
  if (!sweepTapTreeRoot) {
2645
2612
  throw new Error("Sweep tap tree root not set");
2646
2613
  }
2647
- const xOnlyPublicKeys = event.cosignersPublicKeys.map(
2648
- (k) => k.slice(2)
2649
- );
2614
+ const xOnlyPublicKeys = event.cosignersPublicKeys.map((k) => k.slice(2));
2650
2615
  const signerPublicKey = await session.getPublicKey();
2651
2616
  const xonlySignerPublicKey = signerPublicKey.subarray(1);
2652
2617
  if (!xOnlyPublicKeys.includes(import_base7.hex.encode(xonlySignerPublicKey))) {
2653
2618
  return { skip: true };
2654
2619
  }
2655
- const commitmentTx = import_sdk6.Transaction.fromPSBT(
2656
- import_base7.base64.decode(event.unsignedCommitmentTx)
2657
- );
2620
+ const commitmentTx = import_sdk6.Transaction.fromPSBT(import_base7.base64.decode(event.unsignedCommitmentTx));
2658
2621
  (0, import_sdk6.validateVtxoTxGraph)(vtxoTree, commitmentTx, sweepTapTreeRoot);
2659
2622
  const sharedOutput = commitmentTx.getOutput(0);
2660
2623
  if (!sharedOutput?.amount) {
@@ -2670,18 +2633,11 @@ function createVHTLCBatchHandler(intentId, vhtlc, arkProvider, identity, session
2670
2633
  if (!session) {
2671
2634
  return { fullySigned: true };
2672
2635
  }
2673
- const { hasAllNonces } = await session.aggregatedNonces(
2674
- event.txid,
2675
- event.nonces
2676
- );
2636
+ const { hasAllNonces } = await session.aggregatedNonces(event.txid, event.nonces);
2677
2637
  if (!hasAllNonces) return { fullySigned: false };
2678
2638
  const signatures = await session.sign();
2679
2639
  const pubkey = import_base7.hex.encode(await session.getPublicKey());
2680
- await arkProvider.submitTreeSignatures(
2681
- event.id,
2682
- pubkey,
2683
- signatures
2684
- );
2640
+ await arkProvider.submitTreeSignatures(event.id, pubkey, signatures);
2685
2641
  return { fullySigned: true };
2686
2642
  },
2687
2643
  onBatchFinalization: async (event, _, connectorTree) => {
@@ -2689,9 +2645,7 @@ function createVHTLCBatchHandler(intentId, vhtlc, arkProvider, identity, session
2689
2645
  return;
2690
2646
  }
2691
2647
  if (!connectorTree) {
2692
- throw new Error(
2693
- "BatchFinalizationEvent: expected connector tree to be defined"
2694
- );
2648
+ throw new Error("BatchFinalizationEvent: expected connector tree to be defined");
2695
2649
  }
2696
2650
  (0, import_sdk6.validateConnectorsTxGraph)(event.commitmentTx, connectorTree);
2697
2651
  const connectors = connectorTree.leaves();
@@ -2706,9 +2660,7 @@ function createVHTLCBatchHandler(intentId, vhtlc, arkProvider, identity, session
2706
2660
  connectors[connectorIndex]
2707
2661
  );
2708
2662
  const signedForfeitTx = await identity.sign(forfeitTx);
2709
- await arkProvider.submitSignedForfeitTxs([
2710
- import_base7.base64.encode(signedForfeitTx.toPSBT())
2711
- ]);
2663
+ await arkProvider.submitSignedForfeitTxs([import_base7.base64.encode(signedForfeitTx.toPSBT())]);
2712
2664
  }
2713
2665
  };
2714
2666
  }
@@ -2768,36 +2720,22 @@ var createVHTLCScript = (args) => {
2768
2720
  serverPubkey,
2769
2721
  timeoutBlockHeights: vhtlcTimeouts
2770
2722
  } = args;
2771
- const receiverXOnlyPublicKey = normalizeToXOnlyKey(
2772
- import_base8.hex.decode(receiverPubkey),
2773
- "receiver"
2774
- );
2775
- const senderXOnlyPublicKey = normalizeToXOnlyKey(
2776
- import_base8.hex.decode(senderPubkey),
2777
- "sender"
2778
- );
2779
- const serverXOnlyPublicKey = normalizeToXOnlyKey(
2780
- import_base8.hex.decode(serverPubkey),
2781
- "server"
2782
- );
2723
+ const receiverXOnlyPublicKey = normalizeToXOnlyKey(import_base8.hex.decode(receiverPubkey), "receiver");
2724
+ const senderXOnlyPublicKey = normalizeToXOnlyKey(import_base8.hex.decode(senderPubkey), "sender");
2725
+ const serverXOnlyPublicKey = normalizeToXOnlyKey(import_base8.hex.decode(serverPubkey), "server");
2783
2726
  const vhtlcScript = new import_sdk7.VHTLC.Script({
2784
2727
  preimageHash: (0, import_legacy.ripemd160)(preimageHash),
2785
2728
  sender: senderXOnlyPublicKey,
2786
2729
  receiver: receiverXOnlyPublicKey,
2787
2730
  server: serverXOnlyPublicKey,
2788
2731
  refundLocktime: BigInt(vhtlcTimeouts.refund),
2789
- unilateralClaimDelay: toBip68RelativeTimelock(
2790
- vhtlcTimeouts.unilateralClaim
2791
- ),
2792
- unilateralRefundDelay: toBip68RelativeTimelock(
2793
- vhtlcTimeouts.unilateralRefund
2794
- ),
2732
+ unilateralClaimDelay: toBip68RelativeTimelock(vhtlcTimeouts.unilateralClaim),
2733
+ unilateralRefundDelay: toBip68RelativeTimelock(vhtlcTimeouts.unilateralRefund),
2795
2734
  unilateralRefundWithoutReceiverDelay: toBip68RelativeTimelock(
2796
2735
  vhtlcTimeouts.unilateralRefundWithoutReceiver
2797
2736
  )
2798
2737
  });
2799
- if (!vhtlcScript.claimScript)
2800
- throw new Error("Failed to create VHTLC script");
2738
+ if (!vhtlcScript.claimScript) throw new Error("Failed to create VHTLC script");
2801
2739
  const hrp = network === "bitcoin" ? "ark" : "tark";
2802
2740
  const vhtlcAddress = vhtlcScript.address(hrp, serverXOnlyPublicKey).encode();
2803
2741
  return { vhtlcScript, vhtlcAddress };
@@ -2831,11 +2769,7 @@ var joinBatch = async (arkProvider, identity, input, output, {
2831
2769
  unknown: [import_sdk7.VtxoTaprootTree.encode(input.tapTree)],
2832
2770
  sequence: (0, import_sdk7.getSequence)(input.tapLeafScript)
2833
2771
  };
2834
- const registerIntent = import_sdk7.Intent.create(
2835
- intentMessage,
2836
- [intentInput],
2837
- [output]
2838
- );
2772
+ const registerIntent = import_sdk7.Intent.create(intentMessage, [intentInput], [output]);
2839
2773
  const deleteIntent = import_sdk7.Intent.create(deleteMessage, [intentInput]);
2840
2774
  const [signedRegisterIntent, signedDeleteIntent] = await Promise.all([
2841
2775
  identity.sign(registerIntent),
@@ -2859,14 +2793,8 @@ var joinBatch = async (arkProvider, identity, input, output, {
2859
2793
  normalizeToXOnlyKey(forfeitPubkey, "forfeit"),
2860
2794
  isRecoverable2 ? void 0 : import_btc_signer4.OutScript.encode(decodedAddress)
2861
2795
  );
2862
- const topics = [
2863
- import_base8.hex.encode(signerPublicKey),
2864
- `${input.txid}:${input.vout}`
2865
- ];
2866
- const eventStream = arkProvider.getEventStream(
2867
- abortController.signal,
2868
- topics
2869
- );
2796
+ const topics = [import_base8.hex.encode(signerPublicKey), `${input.txid}:${input.vout}`];
2797
+ const eventStream = arkProvider.getEventStream(abortController.signal, topics);
2870
2798
  const commitmentTxid = await import_sdk7.Batch.join(eventStream, handler, {
2871
2799
  abortController
2872
2800
  });
@@ -2887,14 +2815,8 @@ var joinBatch = async (arkProvider, identity, input, output, {
2887
2815
  };
2888
2816
  var claimVHTLCwithOffchainTx = async (identity, vhtlcScript, serverXOnlyPublicKey, input, output, arkInfo, arkProvider) => {
2889
2817
  const rawCheckpointTapscript = import_base8.hex.decode(arkInfo.checkpointTapscript);
2890
- const serverUnrollScript = import_sdk7.CSVMultisigTapscript.decode(
2891
- rawCheckpointTapscript
2892
- );
2893
- const { arkTx, checkpoints } = (0, import_sdk7.buildOffchainTx)(
2894
- [input],
2895
- [output],
2896
- serverUnrollScript
2897
- );
2818
+ const serverUnrollScript = import_sdk7.CSVMultisigTapscript.decode(rawCheckpointTapscript);
2819
+ const { arkTx, checkpoints } = (0, import_sdk7.buildOffchainTx)([input], [output], serverUnrollScript);
2898
2820
  const signedArkTx = await identity.sign(arkTx);
2899
2821
  const { arkTxid, finalArkTx, signedCheckpointTxs } = await arkProvider.submitTx(
2900
2822
  import_base8.base64.encode(signedArkTx.toPSBT()),
@@ -2902,9 +2824,7 @@ var claimVHTLCwithOffchainTx = async (identity, vhtlcScript, serverXOnlyPublicKe
2902
2824
  );
2903
2825
  const finalTx = import_sdk7.Transaction.fromPSBT(import_base8.base64.decode(finalArkTx));
2904
2826
  const serverPubkeyHex = import_base8.hex.encode(serverXOnlyPublicKey);
2905
- const claimLeafHash = (0, import_payment3.tapLeafHash)(
2906
- scriptFromTapLeafScript(vhtlcScript.claim())
2907
- );
2827
+ const claimLeafHash = (0, import_payment3.tapLeafHash)(scriptFromTapLeafScript(vhtlcScript.claim()));
2908
2828
  for (let i = 0; i < finalTx.inputsLength; i++) {
2909
2829
  if (!verifySignatures(finalTx, i, [serverPubkeyHex], claimLeafHash)) {
2910
2830
  throw new Error("Invalid final Ark transaction");
@@ -2914,13 +2834,9 @@ var claimVHTLCwithOffchainTx = async (identity, vhtlcScript, serverXOnlyPublicKe
2914
2834
  signedCheckpointTxs.map(async (c, idx) => {
2915
2835
  const tx = import_sdk7.Transaction.fromPSBT(import_base8.base64.decode(c));
2916
2836
  const checkpointLeaf = checkpoints[idx].getInput(0).tapLeafScript[0];
2917
- const cpLeafHash = (0, import_payment3.tapLeafHash)(
2918
- scriptFromTapLeafScript(checkpointLeaf)
2919
- );
2837
+ const cpLeafHash = (0, import_payment3.tapLeafHash)(scriptFromTapLeafScript(checkpointLeaf));
2920
2838
  if (!verifySignatures(tx, 0, [serverPubkeyHex], cpLeafHash)) {
2921
- throw new Error(
2922
- "Invalid server signature in checkpoint transaction"
2923
- );
2839
+ throw new Error("Invalid server signature in checkpoint transaction");
2924
2840
  }
2925
2841
  const signedCheckpoint = await identity.sign(tx, [0]);
2926
2842
  return import_base8.base64.encode(signedCheckpoint.toPSBT());
@@ -2930,61 +2846,37 @@ var claimVHTLCwithOffchainTx = async (identity, vhtlcScript, serverXOnlyPublicKe
2930
2846
  };
2931
2847
  var refundVHTLCwithOffchainTx = async (swapId, identity, arkProvider, boltzXOnlyPublicKey, ourXOnlyPublicKey, serverXOnlyPublicKey, input, output, arkInfo, refundFunc) => {
2932
2848
  const rawCheckpointTapscript = import_base8.hex.decode(arkInfo.checkpointTapscript);
2933
- const serverUnrollScript = import_sdk7.CSVMultisigTapscript.decode(
2934
- rawCheckpointTapscript
2849
+ const serverUnrollScript = import_sdk7.CSVMultisigTapscript.decode(rawCheckpointTapscript);
2850
+ const { arkTx: unsignedRefundTx, checkpoints: checkpointPtxs } = (0, import_sdk7.buildOffchainTx)(
2851
+ [input],
2852
+ [output],
2853
+ serverUnrollScript
2935
2854
  );
2936
- const { arkTx: unsignedRefundTx, checkpoints: checkpointPtxs } = (0, import_sdk7.buildOffchainTx)([input], [output], serverUnrollScript);
2937
2855
  if (checkpointPtxs.length !== 1)
2938
- throw new Error(
2939
- `Expected one checkpoint transaction, got ${checkpointPtxs.length}`
2940
- );
2856
+ throw new Error(`Expected one checkpoint transaction, got ${checkpointPtxs.length}`);
2941
2857
  const unsignedCheckpointTx = checkpointPtxs[0];
2942
2858
  let boltzSignedRefundTx;
2943
2859
  let boltzSignedCheckpointTx;
2944
2860
  try {
2945
- const result = await refundFunc(
2946
- swapId,
2947
- unsignedRefundTx,
2948
- unsignedCheckpointTx
2949
- );
2861
+ const result = await refundFunc(swapId, unsignedRefundTx, unsignedCheckpointTx);
2950
2862
  boltzSignedRefundTx = result.transaction;
2951
2863
  boltzSignedCheckpointTx = result.checkpoint;
2952
2864
  } catch (error) {
2953
- throw new BoltzRefundError(
2954
- `Boltz rejected refund for swap ${swapId}`,
2955
- error
2956
- );
2865
+ throw new BoltzRefundError(`Boltz rejected refund for swap ${swapId}`, error);
2957
2866
  }
2958
2867
  const boltzXOnlyPublicKeyHex = import_base8.hex.encode(boltzXOnlyPublicKey);
2959
- const refundLeafHash = (0, import_payment3.tapLeafHash)(
2960
- scriptFromTapLeafScript(input.tapLeafScript)
2961
- );
2962
- if (!verifySignatures(
2963
- boltzSignedRefundTx,
2964
- 0,
2965
- [boltzXOnlyPublicKeyHex],
2966
- refundLeafHash
2967
- )) {
2868
+ const refundLeafHash = (0, import_payment3.tapLeafHash)(scriptFromTapLeafScript(input.tapLeafScript));
2869
+ if (!verifySignatures(boltzSignedRefundTx, 0, [boltzXOnlyPublicKeyHex], refundLeafHash)) {
2968
2870
  throw new Error("Invalid Boltz signature in refund transaction");
2969
2871
  }
2970
2872
  const checkpointLeaf = unsignedCheckpointTx.getInput(0).tapLeafScript[0];
2971
- const checkpointLeafHash = (0, import_payment3.tapLeafHash)(
2972
- scriptFromTapLeafScript(checkpointLeaf)
2973
- );
2974
- if (!verifySignatures(
2975
- boltzSignedCheckpointTx,
2976
- 0,
2977
- [boltzXOnlyPublicKeyHex],
2978
- checkpointLeafHash
2979
- )) {
2873
+ const checkpointLeafHash = (0, import_payment3.tapLeafHash)(scriptFromTapLeafScript(checkpointLeaf));
2874
+ if (!verifySignatures(boltzSignedCheckpointTx, 0, [boltzXOnlyPublicKeyHex], checkpointLeafHash)) {
2980
2875
  throw new Error("Invalid Boltz signature in checkpoint transaction");
2981
2876
  }
2982
2877
  const signedRefundTx = await identity.sign(unsignedRefundTx);
2983
2878
  const signedCheckpointTx = await identity.sign(unsignedCheckpointTx);
2984
- const combinedSignedRefundTx = (0, import_sdk7.combineTapscriptSigs)(
2985
- boltzSignedRefundTx,
2986
- signedRefundTx
2987
- );
2879
+ const combinedSignedRefundTx = (0, import_sdk7.combineTapscriptSigs)(boltzSignedRefundTx, signedRefundTx);
2988
2880
  const combinedSignedCheckpointTx = (0, import_sdk7.combineTapscriptSigs)(
2989
2881
  boltzSignedCheckpointTx,
2990
2882
  signedCheckpointTx
@@ -3008,25 +2900,16 @@ var refundVHTLCwithOffchainTx = async (swapId, identity, arkProvider, boltzXOnly
3008
2900
  `Expected one signed checkpoint transaction, got ${signedCheckpointTxs.length}`
3009
2901
  );
3010
2902
  }
3011
- const serverSignedCheckpointTx = import_sdk7.Transaction.fromPSBT(
3012
- import_base8.base64.decode(signedCheckpointTxs[0])
3013
- );
2903
+ const serverSignedCheckpointTx = import_sdk7.Transaction.fromPSBT(import_base8.base64.decode(signedCheckpointTxs[0]));
3014
2904
  const serverPubkeyHex = import_base8.hex.encode(serverXOnlyPublicKey);
3015
- if (!verifySignatures(
3016
- serverSignedCheckpointTx,
3017
- 0,
3018
- [serverPubkeyHex],
3019
- checkpointLeafHash
3020
- )) {
2905
+ if (!verifySignatures(serverSignedCheckpointTx, 0, [serverPubkeyHex], checkpointLeafHash)) {
3021
2906
  throw new Error("Invalid server signature in checkpoint transaction");
3022
2907
  }
3023
2908
  const finalCheckpointTx = (0, import_sdk7.combineTapscriptSigs)(
3024
2909
  combinedSignedCheckpointTx,
3025
2910
  serverSignedCheckpointTx
3026
2911
  );
3027
- await arkProvider.finalizeTx(arkTxid, [
3028
- import_base8.base64.encode(finalCheckpointTx.toPSBT())
3029
- ]);
2912
+ await arkProvider.finalizeTx(arkTxid, [import_base8.base64.encode(finalCheckpointTx.toPSBT())]);
3030
2913
  };
3031
2914
  function scriptFromTapLeafScript(leaf) {
3032
2915
  return leaf[1].subarray(0, leaf[1].length - 1);
@@ -3034,21 +2917,21 @@ function scriptFromTapLeafScript(leaf) {
3034
2917
 
3035
2918
  // src/arkade-swaps.ts
3036
2919
  var dedupeVtxos = (vtxos) => [
3037
- ...new Map(
3038
- vtxos.map((vtxo) => [`${vtxo.txid}:${vtxo.vout}`, vtxo])
3039
- ).values()
2920
+ ...new Map(vtxos.map((vtxo) => [`${vtxo.txid}:${vtxo.vout}`, vtxo])).values()
3040
2921
  ];
3041
2922
  var hasNonEmptyString = (value) => typeof value === "string" && value.length > 0;
3042
2923
  var canRecoverViaBoltz3of3 = (refundableVtxos, swap) => {
3043
2924
  const hasRequiredSwapMetadata = hasNonEmptyString(swap.id) && hasNonEmptyString(swap.request.refundPublicKey) && hasNonEmptyString(swap.response.address) && hasNonEmptyString(swap.response.claimPublicKey) && !!swap.response.timeoutBlockHeights;
3044
2925
  if (!hasRequiredSwapMetadata) return false;
3045
- return refundableVtxos.some(
3046
- (vtxo) => !vtxo.isSpent && !(0, import_sdk8.isRecoverable)(vtxo)
3047
- );
2926
+ return refundableVtxos.some((vtxo) => !vtxo.isSpent && !(0, import_sdk8.isRecoverable)(vtxo));
3048
2927
  };
3049
2928
  var isSubmarineRefundLocktimeReached = (refundTimestamp) => Math.floor(Date.now() / 1e3) >= refundTimestamp;
3050
2929
  var CLAIM_VTXO_RETRY_ATTEMPTS = 3;
3051
2930
  var CLAIM_VTXO_RETRY_DELAY_MS = 500;
2931
+ var quoteOptionsForSwap = (swap) => {
2932
+ const amount = swap.response?.claimDetails?.amount;
2933
+ return typeof amount === "number" ? { minAcceptableAmount: amount } : void 0;
2934
+ };
3052
2935
  var ArkadeSwaps = class _ArkadeSwaps {
3053
2936
  /** The Arkade wallet instance used for signing and address generation. */
3054
2937
  wallet;
@@ -3084,10 +2967,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
3084
2967
  return new _ArkadeSwaps(config);
3085
2968
  }
3086
2969
  const arkProvider = config.arkProvider ?? config.wallet.arkProvider;
3087
- if (!arkProvider)
3088
- throw new Error(
3089
- "Ark provider is required either in wallet or config."
3090
- );
2970
+ if (!arkProvider) throw new Error("Ark provider is required either in wallet or config.");
3091
2971
  const arkInfo = await arkProvider.getInfo();
3092
2972
  const network = arkInfo.network;
3093
2973
  const swapProvider = new BoltzSwapProvider({ network });
@@ -3098,16 +2978,11 @@ var ArkadeSwaps = class _ArkadeSwaps {
3098
2978
  if (!config.swapProvider) throw new Error("Swap provider is required.");
3099
2979
  this.wallet = config.wallet;
3100
2980
  const arkProvider = config.arkProvider ?? config.wallet.arkProvider;
3101
- if (!arkProvider)
3102
- throw new Error(
3103
- "Ark provider is required either in wallet or config."
3104
- );
2981
+ if (!arkProvider) throw new Error("Ark provider is required either in wallet or config.");
3105
2982
  this.arkProvider = arkProvider;
3106
2983
  const indexerProvider = config.indexerProvider ?? config.wallet.indexerProvider;
3107
2984
  if (!indexerProvider)
3108
- throw new Error(
3109
- "Indexer provider is required either in wallet or config."
3110
- );
2985
+ throw new Error("Indexer provider is required either in wallet or config.");
3111
2986
  this.indexerProvider = indexerProvider;
3112
2987
  this.swapProvider = config.swapProvider;
3113
2988
  if (config.swapRepository) {
@@ -3118,10 +2993,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
3118
2993
  if (config.swapManager !== false) {
3119
2994
  const swapManagerConfig = !config.swapManager || config.swapManager === true ? {} : config.swapManager;
3120
2995
  const shouldAutostart = swapManagerConfig.autoStart ?? true;
3121
- this.swapManager = new SwapManager(
3122
- this.swapProvider,
3123
- swapManagerConfig
3124
- );
2996
+ this.swapManager = new SwapManager(this.swapProvider, swapManagerConfig);
3125
2997
  this.swapManager.setCallbacks({
3126
2998
  claim: async (swap) => {
3127
2999
  await this.claimVHTLC(swap);
@@ -3269,19 +3141,15 @@ var ArkadeSwaps = class _ArkadeSwaps {
3269
3141
  * @throws {SwapError} If amount is <= 0 or key retrieval fails.
3270
3142
  */
3271
3143
  async createReverseSwap(args) {
3272
- if (args.amount <= 0)
3273
- throw new SwapError({ message: "Amount must be greater than 0" });
3274
- const claimPublicKey = import_base9.hex.encode(
3275
- await this.wallet.identity.compressedPublicKey()
3276
- );
3144
+ if (args.amount <= 0) throw new SwapError({ message: "Amount must be greater than 0" });
3145
+ const claimPublicKey = import_base9.hex.encode(await this.wallet.identity.compressedPublicKey());
3277
3146
  if (!claimPublicKey)
3278
3147
  throw new SwapError({
3279
3148
  message: "Failed to get claim public key from wallet"
3280
3149
  });
3281
3150
  const preimage = (0, import_utils3.randomBytes)(32);
3282
3151
  const preimageHash = import_base9.hex.encode((0, import_sha23.sha256)(preimage));
3283
- if (!preimageHash)
3284
- throw new SwapError({ message: "Failed to get preimage hash" });
3152
+ if (!preimageHash) throw new SwapError({ message: "Failed to get preimage hash" });
3285
3153
  const swapRequest = {
3286
3154
  invoiceAmount: args.amount,
3287
3155
  claimPublicKey,
@@ -3311,18 +3179,14 @@ var ArkadeSwaps = class _ArkadeSwaps {
3311
3179
  */
3312
3180
  async claimVHTLC(pendingSwap) {
3313
3181
  if (!pendingSwap.preimage)
3314
- throw new Error(
3315
- `Swap ${pendingSwap.id}: preimage is required to claim VHTLC`
3316
- );
3182
+ throw new Error(`Swap ${pendingSwap.id}: preimage is required to claim VHTLC`);
3317
3183
  const {
3318
3184
  refundPublicKey,
3319
3185
  lockupAddress,
3320
3186
  timeoutBlockHeights: vhtlcTimeouts
3321
3187
  } = pendingSwap.response;
3322
3188
  if (!refundPublicKey || !lockupAddress || !vhtlcTimeouts)
3323
- throw new Error(
3324
- `Swap ${pendingSwap.id}: incomplete reverse swap response`
3325
- );
3189
+ throw new Error(`Swap ${pendingSwap.id}: incomplete reverse swap response`);
3326
3190
  const preimage = import_base9.hex.decode(pendingSwap.preimage);
3327
3191
  const arkInfo = await this.arkProvider.getInfo();
3328
3192
  const address = await this.wallet.getAddress();
@@ -3367,15 +3231,11 @@ var ArkadeSwaps = class _ArkadeSwaps {
3367
3231
  break;
3368
3232
  }
3369
3233
  if (attempt < CLAIM_VTXO_RETRY_ATTEMPTS) {
3370
- await new Promise(
3371
- (resolve) => setTimeout(resolve, CLAIM_VTXO_RETRY_DELAY_MS)
3372
- );
3234
+ await new Promise((resolve) => setTimeout(resolve, CLAIM_VTXO_RETRY_DELAY_MS));
3373
3235
  }
3374
3236
  }
3375
3237
  if (!vtxo) {
3376
- throw new Error(
3377
- `Swap ${pendingSwap.id}: no spendable virtual coins found`
3378
- );
3238
+ throw new Error(`Swap ${pendingSwap.id}: no spendable virtual coins found`);
3379
3239
  }
3380
3240
  if (vtxo.isSpent) {
3381
3241
  throw new Error(`Swap ${pendingSwap.id}: VHTLC is already spent`);
@@ -3389,10 +3249,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
3389
3249
  amount: BigInt(vtxo.value),
3390
3250
  script: import_sdk8.ArkAddress.decode(address).pkScript
3391
3251
  };
3392
- const vhtlcIdentity = claimVHTLCIdentity(
3393
- this.wallet.identity,
3394
- preimage
3395
- );
3252
+ const vhtlcIdentity = claimVHTLCIdentity(this.wallet.identity, preimage);
3396
3253
  let finalStatus;
3397
3254
  if ((0, import_sdk8.isRecoverable)(vtxo)) {
3398
3255
  await this.joinBatch(vhtlcIdentity, input, output, arkInfo);
@@ -3511,9 +3368,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
3511
3368
  async sendLightningPayment(args) {
3512
3369
  const pendingSwap = await this.createSubmarineSwap(args);
3513
3370
  if (!pendingSwap.response.address)
3514
- throw new Error(
3515
- `Swap ${pendingSwap.id}: missing address in submarine swap response`
3516
- );
3371
+ throw new Error(`Swap ${pendingSwap.id}: missing address in submarine swap response`);
3517
3372
  await this.savePendingSubmarineSwap(pendingSwap);
3518
3373
  const txid = await this.wallet.send({
3519
3374
  address: pendingSwap.response.address,
@@ -3546,9 +3401,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
3546
3401
  * @throws {SwapError} If invoice is missing or key retrieval fails.
3547
3402
  */
3548
3403
  async createSubmarineSwap(args) {
3549
- const refundPublicKey = import_base9.hex.encode(
3550
- await this.wallet.identity.compressedPublicKey()
3551
- );
3404
+ const refundPublicKey = import_base9.hex.encode(await this.wallet.identity.compressedPublicKey());
3552
3405
  if (!refundPublicKey)
3553
3406
  throw new SwapError({
3554
3407
  message: "Failed to get refund public key from wallet"
@@ -3586,9 +3439,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
3586
3439
  async buildSubmarineVHTLCContext(swap, arkInfo) {
3587
3440
  const preimageHash = swap.request.invoice ? getInvoicePaymentHash(swap.request.invoice) : swap.preimageHash;
3588
3441
  if (!preimageHash)
3589
- throw new Error(
3590
- `Swap ${swap.id}: preimage hash is required to refund VHTLC`
3591
- );
3442
+ throw new Error(`Swap ${swap.id}: preimage hash is required to refund VHTLC`);
3592
3443
  const resolvedArkInfo = arkInfo ?? await this.arkProvider.getInfo();
3593
3444
  const ourXOnlyPublicKey = normalizeToXOnlyKey(
3594
3445
  await this.wallet.identity.xOnlyPublicKey(),
@@ -3602,9 +3453,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
3602
3453
  );
3603
3454
  const { claimPublicKey, timeoutBlockHeights: vhtlcTimeouts } = swap.response;
3604
3455
  if (!claimPublicKey || !vhtlcTimeouts)
3605
- throw new Error(
3606
- `Swap ${swap.id}: incomplete submarine swap response`
3607
- );
3456
+ throw new Error(`Swap ${swap.id}: incomplete submarine swap response`);
3608
3457
  const boltzXOnlyPublicKey = normalizeToXOnlyKey(
3609
3458
  import_base9.hex.decode(claimPublicKey),
3610
3459
  "boltz",
@@ -3619,9 +3468,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
3619
3468
  timeoutBlockHeights: vhtlcTimeouts
3620
3469
  });
3621
3470
  if (!vhtlcScript.claimScript)
3622
- throw new Error(
3623
- `Swap ${swap.id}: failed to create VHTLC script for submarine swap`
3624
- );
3471
+ throw new Error(`Swap ${swap.id}: failed to create VHTLC script for submarine swap`);
3625
3472
  if (vhtlcAddress !== swap.response.address)
3626
3473
  throw new Error(
3627
3474
  `VHTLC address mismatch for swap ${swap.id}: expected ${swap.response.address}, got ${vhtlcAddress}`
@@ -3660,10 +3507,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
3660
3507
  recoverableOnly: true
3661
3508
  })
3662
3509
  ]);
3663
- const refundableVtxos = dedupeVtxos([
3664
- ...spendableResult.vtxos,
3665
- ...recoverableResult.vtxos
3666
- ]);
3510
+ const refundableVtxos = dedupeVtxos([...spendableResult.vtxos, ...recoverableResult.vtxos]);
3667
3511
  let diagnostic;
3668
3512
  if (refundableVtxos.length === 0) {
3669
3513
  const { vtxos: allVtxos } = await this.indexerProvider.getVtxos({
@@ -3683,13 +3527,8 @@ var ArkadeSwaps = class _ArkadeSwaps {
3683
3527
  submarineRecoveryInfoFromLookup(swap, lookup) {
3684
3528
  const { refundableVtxos, diagnostic, vhtlcTimeouts } = lookup;
3685
3529
  if (refundableVtxos.length > 0) {
3686
- const cltvSatisfied = isSubmarineRefundLocktimeReached(
3687
- vhtlcTimeouts.refund
3688
- );
3689
- const amountSats = refundableVtxos.reduce(
3690
- (sum, vtxo) => sum + Number(vtxo.value),
3691
- 0
3692
- );
3530
+ const cltvSatisfied = isSubmarineRefundLocktimeReached(vhtlcTimeouts.refund);
3531
+ const amountSats = refundableVtxos.reduce((sum, vtxo) => sum + Number(vtxo.value), 0);
3693
3532
  const isRecoverable2 = cltvSatisfied || canRecoverViaBoltz3of3(refundableVtxos, swap);
3694
3533
  return {
3695
3534
  swap,
@@ -3753,19 +3592,13 @@ var ArkadeSwaps = class _ArkadeSwaps {
3753
3592
  );
3754
3593
  }
3755
3594
  if (diagnostic.allSpent) {
3756
- throw new Error(
3757
- `Swap ${pendingSwap.id}: VHTLC is already spent`
3758
- );
3595
+ throw new Error(`Swap ${pendingSwap.id}: VHTLC is already spent`);
3759
3596
  }
3760
- throw new Error(
3761
- `Swap ${pendingSwap.id}: VHTLC has no refundable VTXOs yet`
3762
- );
3597
+ throw new Error(`Swap ${pendingSwap.id}: VHTLC has no refundable VTXOs yet`);
3763
3598
  }
3764
3599
  const outputScript = import_sdk8.ArkAddress.decode(address).pkScript;
3765
3600
  const refundWithoutReceiverLeaf = vhtlcScript.refundWithoutReceiver();
3766
- const cltvSatisfied = isSubmarineRefundLocktimeReached(
3767
- vhtlcTimeouts.refund
3768
- );
3601
+ const cltvSatisfied = isSubmarineRefundLocktimeReached(vhtlcTimeouts.refund);
3769
3602
  let boltzCallCount = 0;
3770
3603
  let sweptCount = 0;
3771
3604
  let skippedCount = 0;
@@ -3817,9 +3650,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
3817
3650
  input,
3818
3651
  output,
3819
3652
  arkInfo,
3820
- this.swapProvider.refundSubmarineSwap.bind(
3821
- this.swapProvider
3822
- )
3653
+ this.swapProvider.refundSubmarineSwap.bind(this.swapProvider)
3823
3654
  );
3824
3655
  boltzCallCount++;
3825
3656
  sweptCount++;
@@ -3842,13 +3673,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
3842
3673
  tapLeafScript: refundWithoutReceiverLeaf,
3843
3674
  tapTree: vhtlcScript.encode()
3844
3675
  };
3845
- await this.joinBatch(
3846
- this.wallet.identity,
3847
- fallbackInput,
3848
- output,
3849
- arkInfo,
3850
- false
3851
- );
3676
+ await this.joinBatch(this.wallet.identity, fallbackInput, output, arkInfo, false);
3852
3677
  sweptCount++;
3853
3678
  }
3854
3679
  }
@@ -3944,10 +3769,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
3944
3769
  try {
3945
3770
  return {
3946
3771
  swap,
3947
- context: await this.buildSubmarineVHTLCContext(
3948
- swap,
3949
- arkInfo
3950
- )
3772
+ context: await this.buildSubmarineVHTLCContext(swap, arkInfo)
3951
3773
  };
3952
3774
  } catch (err) {
3953
3775
  return {
@@ -3960,9 +3782,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
3960
3782
  const valid = prepared.filter(
3961
3783
  (item) => "context" in item
3962
3784
  );
3963
- const scripts = [
3964
- ...new Set(valid.map(({ context }) => context.vhtlcPkScriptHex))
3965
- ];
3785
+ const scripts = [...new Set(valid.map(({ context }) => context.vhtlcPkScriptHex))];
3966
3786
  const refundableByScript = /* @__PURE__ */ new Map();
3967
3787
  if (scripts.length > 0) {
3968
3788
  const [spendableResult, recoverableResult] = await Promise.all([
@@ -3997,9 +3817,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
3997
3817
  error: item.error
3998
3818
  };
3999
3819
  }
4000
- const refundableVtxos = refundableByScript.get(
4001
- item.context.vhtlcPkScriptHex.toLowerCase()
4002
- ) ?? [];
3820
+ const refundableVtxos = refundableByScript.get(item.context.vhtlcPkScriptHex.toLowerCase()) ?? [];
4003
3821
  return this.submarineRecoveryInfoFromLookup(item.swap, {
4004
3822
  ...item.context,
4005
3823
  refundableVtxos
@@ -4178,9 +3996,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
4178
3996
  */
4179
3997
  async waitAndClaimBtc(pendingSwap) {
4180
3998
  if (this.swapManager && await this.swapManager.hasSwap(pendingSwap.id)) {
4181
- const { txid } = await this.swapManager.waitForSwapCompletion(
4182
- pendingSwap.id
4183
- );
3999
+ const { txid } = await this.swapManager.waitForSwapCompletion(pendingSwap.id);
4184
4000
  return { txid };
4185
4001
  }
4186
4002
  return new Promise((resolve, reject) => {
@@ -4207,24 +4023,25 @@ var ArkadeSwaps = class _ArkadeSwaps {
4207
4023
  }
4208
4024
  case "transaction.claimed":
4209
4025
  await updateSwapStatus();
4210
- const claimedStatus = await this.getSwapStatus(
4211
- pendingSwap.id
4212
- );
4026
+ const claimedStatus = await this.getSwapStatus(pendingSwap.id);
4213
4027
  resolve({
4214
4028
  txid: claimedStatus.transaction?.id ?? ""
4215
4029
  });
4216
4030
  break;
4217
4031
  case "transaction.lockupFailed":
4218
4032
  await updateSwapStatus();
4219
- await this.quoteSwap(swap.response.id).catch((err) => {
4220
- reject(
4221
- new SwapError({
4222
- message: `Failed to renegotiate quote: ${err.message}`,
4223
- isRefundable: true,
4224
- pendingSwap: swap
4225
- })
4226
- );
4227
- });
4033
+ await this.quoteSwap(swap.response.id, quoteOptionsForSwap(swap)).catch(
4034
+ (err) => {
4035
+ reject(
4036
+ new SwapError({
4037
+ message: `Failed to renegotiate quote: ${err.message}`,
4038
+ isRefundable: true,
4039
+ pendingSwap: swap,
4040
+ cause: err
4041
+ })
4042
+ );
4043
+ }
4044
+ );
4228
4045
  break;
4229
4046
  case "swap.expired":
4230
4047
  await updateSwapStatus();
@@ -4262,30 +4079,18 @@ var ArkadeSwaps = class _ArkadeSwaps {
4262
4079
  */
4263
4080
  async claimBtc(pendingSwap) {
4264
4081
  if (!pendingSwap.toAddress)
4265
- throw new Error(
4266
- `Swap ${pendingSwap.id}: destination address is required`
4267
- );
4082
+ throw new Error(`Swap ${pendingSwap.id}: destination address is required`);
4268
4083
  if (!pendingSwap.response.claimDetails.swapTree)
4269
- throw new Error(
4270
- `Swap ${pendingSwap.id}: missing swap tree in claim details`
4271
- );
4084
+ throw new Error(`Swap ${pendingSwap.id}: missing swap tree in claim details`);
4272
4085
  if (!pendingSwap.response.claimDetails.serverPublicKey)
4273
- throw new Error(
4274
- `Swap ${pendingSwap.id}: missing server public key in claim details`
4275
- );
4086
+ throw new Error(`Swap ${pendingSwap.id}: missing server public key in claim details`);
4276
4087
  const swapStatus = await this.getSwapStatus(pendingSwap.id);
4277
4088
  if (!swapStatus.transaction?.hex)
4278
- throw new Error(
4279
- `Swap ${pendingSwap.id}: BTC transaction hex is required`
4280
- );
4281
- const lockupTx = import_btc_signer5.Transaction.fromRaw(
4282
- import_base9.hex.decode(swapStatus.transaction.hex)
4283
- );
4089
+ throw new Error(`Swap ${pendingSwap.id}: BTC transaction hex is required`);
4090
+ const lockupTx = import_btc_signer5.Transaction.fromRaw(import_base9.hex.decode(swapStatus.transaction.hex));
4284
4091
  const arkInfo = await this.arkProvider.getInfo();
4285
4092
  const network = arkInfo.network === "bitcoin" ? import_utils4.NETWORK : arkInfo.network === "mutinynet" ? MUTINYNET_NETWORK : REGTEST_NETWORK;
4286
- const swapTree = deserializeSwapTree(
4287
- pendingSwap.response.claimDetails.swapTree
4288
- );
4093
+ const swapTree = deserializeSwapTree(pendingSwap.response.claimDetails.swapTree);
4289
4094
  const musig = tweakMusig(
4290
4095
  create(import_base9.hex.decode(pendingSwap.ephemeralKey), [
4291
4096
  import_base9.hex.decode(pendingSwap.response.claimDetails.serverPublicKey),
@@ -4306,19 +4111,14 @@ var ArkadeSwaps = class _ArkadeSwaps {
4306
4111
  vout: swapOutput.vout,
4307
4112
  transactionId: lockupTx.id
4308
4113
  },
4309
- import_btc_signer5.OutScript.encode(
4310
- (0, import_btc_signer5.Address)(network).decode(pendingSwap.toAddress)
4311
- ),
4114
+ import_btc_signer5.OutScript.encode((0, import_btc_signer5.Address)(network).decode(pendingSwap.toAddress)),
4312
4115
  feeToDeliverExactAmount > fee ? feeToDeliverExactAmount : fee
4313
4116
  )
4314
4117
  );
4315
4118
  const musigMessage = musig.message(
4316
- claimTx.preimageWitnessV1(
4317
- 0,
4318
- [swapOutput.script],
4319
- import_btc_signer5.SigHash.DEFAULT,
4320
- [swapOutput.amount]
4321
- )
4119
+ claimTx.preimageWitnessV1(0, [swapOutput.script], import_btc_signer5.SigHash.DEFAULT, [
4120
+ swapOutput.amount
4121
+ ])
4322
4122
  ).generateNonce();
4323
4123
  const signedTxData = await this.swapProvider.postChainClaimDetails(
4324
4124
  pendingSwap.response.id,
@@ -4332,14 +4132,10 @@ var ArkadeSwaps = class _ArkadeSwaps {
4332
4132
  }
4333
4133
  );
4334
4134
  if (!signedTxData.pubNonce || !signedTxData.partialSignature)
4335
- throw new Error(
4336
- `Swap ${pendingSwap.id}: invalid signature data from server`
4337
- );
4135
+ throw new Error(`Swap ${pendingSwap.id}: invalid signature data from server`);
4338
4136
  const musigSession = musigMessage.aggregateNonces([
4339
4137
  [
4340
- import_base9.hex.decode(
4341
- pendingSwap.response.claimDetails.serverPublicKey
4342
- ),
4138
+ import_base9.hex.decode(pendingSwap.response.claimDetails.serverPublicKey),
4343
4139
  import_base9.hex.decode(signedTxData.pubNonce)
4344
4140
  ]
4345
4141
  ]).initializeSession();
@@ -4359,13 +4155,9 @@ var ArkadeSwaps = class _ArkadeSwaps {
4359
4155
  */
4360
4156
  async refundArk(pendingSwap) {
4361
4157
  if (!pendingSwap.response.lockupDetails.serverPublicKey)
4362
- throw new Error(
4363
- `Swap ${pendingSwap.id}: missing server public key in lockup details`
4364
- );
4158
+ throw new Error(`Swap ${pendingSwap.id}: missing server public key in lockup details`);
4365
4159
  if (!pendingSwap.response.lockupDetails.timeouts)
4366
- throw new Error(
4367
- `Swap ${pendingSwap.id}: missing timeouts in lockup details`
4368
- );
4160
+ throw new Error(`Swap ${pendingSwap.id}: missing timeouts in lockup details`);
4369
4161
  const arkInfo = await this.arkProvider.getInfo();
4370
4162
  const address = await this.wallet.getAddress();
4371
4163
  const ourXOnlyPublicKey = normalizeToXOnlyKey(
@@ -4407,9 +4199,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
4407
4199
  timeoutBlockHeights: pendingSwap.response.lockupDetails.timeouts
4408
4200
  });
4409
4201
  if (!vhtlcScript.refundScript)
4410
- throw new Error(
4411
- `Swap ${pendingSwap.id}: failed to create VHTLC script for chain swap`
4412
- );
4202
+ throw new Error(`Swap ${pendingSwap.id}: failed to create VHTLC script for chain swap`);
4413
4203
  if (pendingSwap.response.lockupDetails.lockupAddress !== vhtlcAddress) {
4414
4204
  throw new SwapError({
4415
4205
  message: "Unable to claim: invalid VHTLC address"
@@ -4490,9 +4280,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
4490
4280
  */
4491
4281
  async waitAndClaimArk(pendingSwap) {
4492
4282
  if (this.swapManager && await this.swapManager.hasSwap(pendingSwap.id)) {
4493
- const { txid } = await this.swapManager.waitForSwapCompletion(
4494
- pendingSwap.id
4495
- );
4283
+ const { txid } = await this.swapManager.waitForSwapCompletion(pendingSwap.id);
4496
4284
  return { txid };
4497
4285
  }
4498
4286
  return new Promise((resolve, reject) => {
@@ -4513,37 +4301,33 @@ var ArkadeSwaps = class _ArkadeSwaps {
4513
4301
  break;
4514
4302
  case "transaction.claimed":
4515
4303
  await updateSwapStatus();
4516
- const claimedStatus = await this.getSwapStatus(
4517
- pendingSwap.id
4518
- );
4304
+ const claimedStatus = await this.getSwapStatus(pendingSwap.id);
4519
4305
  resolve({
4520
4306
  txid: claimedStatus.transaction?.id ?? ""
4521
4307
  });
4522
4308
  break;
4523
4309
  case "transaction.claim.pending":
4524
4310
  await updateSwapStatus();
4525
- await this.signCooperativeClaimForServer(swap).catch(
4311
+ await this.signCooperativeClaimForServer(swap).catch((err) => {
4312
+ logger.error(`Failed to sign cooperative claim for ${swap.id}:`, err);
4313
+ });
4314
+ break;
4315
+ case "transaction.lockupFailed":
4316
+ await updateSwapStatus();
4317
+ await this.quoteSwap(swap.response.id, quoteOptionsForSwap(swap)).catch(
4526
4318
  (err) => {
4527
- logger.error(
4528
- `Failed to sign cooperative claim for ${swap.id}:`,
4529
- err
4319
+ reject(
4320
+ new SwapError({
4321
+ message: `Failed to renegotiate quote: ${err.message}`,
4322
+ isRefundable: false,
4323
+ // TODO btc refund not implemented yet
4324
+ pendingSwap: swap,
4325
+ cause: err
4326
+ })
4530
4327
  );
4531
4328
  }
4532
4329
  );
4533
4330
  break;
4534
- case "transaction.lockupFailed":
4535
- await updateSwapStatus();
4536
- await this.quoteSwap(swap.response.id).catch((err) => {
4537
- reject(
4538
- new SwapError({
4539
- message: `Failed to renegotiate quote: ${err.message}`,
4540
- isRefundable: false,
4541
- // TODO btc refund not implemented yet
4542
- pendingSwap: swap
4543
- })
4544
- );
4545
- });
4546
- break;
4547
4331
  case "swap.expired":
4548
4332
  await updateSwapStatus();
4549
4333
  reject(
@@ -4583,17 +4367,11 @@ var ArkadeSwaps = class _ArkadeSwaps {
4583
4367
  */
4584
4368
  async claimArk(pendingSwap) {
4585
4369
  if (!pendingSwap.toAddress)
4586
- throw new Error(
4587
- `Swap ${pendingSwap.id}: destination address is required`
4588
- );
4370
+ throw new Error(`Swap ${pendingSwap.id}: destination address is required`);
4589
4371
  if (!pendingSwap.response.claimDetails.serverPublicKey)
4590
- throw new Error(
4591
- `Swap ${pendingSwap.id}: missing server public key in claim details`
4592
- );
4372
+ throw new Error(`Swap ${pendingSwap.id}: missing server public key in claim details`);
4593
4373
  if (!pendingSwap.response.claimDetails.timeouts)
4594
- throw new Error(
4595
- `Swap ${pendingSwap.id}: missing timeouts in claim details`
4596
- );
4374
+ throw new Error(`Swap ${pendingSwap.id}: missing timeouts in claim details`);
4597
4375
  const arkInfo = await this.arkProvider.getInfo();
4598
4376
  const preimage = import_base9.hex.decode(pendingSwap.preimage);
4599
4377
  const address = await this.wallet.getAddress();
@@ -4605,10 +4383,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
4605
4383
  pendingSwap.response.claimDetails.serverPublicKey,
4606
4384
  "sender"
4607
4385
  );
4608
- const serverXOnlyPublicKey = normalizeToXOnlyKey(
4609
- arkInfo.signerPubkey,
4610
- "server"
4611
- );
4386
+ const serverXOnlyPublicKey = normalizeToXOnlyKey(arkInfo.signerPubkey, "server");
4612
4387
  const { vhtlcAddress, vhtlcScript } = this.createVHTLCScript({
4613
4388
  network: arkInfo.network,
4614
4389
  preimageHash: import_base9.hex.decode(pendingSwap.request.preimageHash),
@@ -4618,9 +4393,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
4618
4393
  timeoutBlockHeights: pendingSwap.response.claimDetails.timeouts
4619
4394
  });
4620
4395
  if (!vhtlcScript.claimScript)
4621
- throw new Error(
4622
- `Swap ${pendingSwap.id}: failed to create VHTLC script for chain swap`
4623
- );
4396
+ throw new Error(`Swap ${pendingSwap.id}: failed to create VHTLC script for chain swap`);
4624
4397
  if (pendingSwap.response.claimDetails.lockupAddress !== vhtlcAddress) {
4625
4398
  throw new SwapError({
4626
4399
  message: "Unable to claim: invalid VHTLC address"
@@ -4637,15 +4410,11 @@ var ArkadeSwaps = class _ArkadeSwaps {
4637
4410
  break;
4638
4411
  }
4639
4412
  if (attempt < CLAIM_VTXO_RETRY_ATTEMPTS) {
4640
- await new Promise(
4641
- (resolve) => setTimeout(resolve, CLAIM_VTXO_RETRY_DELAY_MS)
4642
- );
4413
+ await new Promise((resolve) => setTimeout(resolve, CLAIM_VTXO_RETRY_DELAY_MS));
4643
4414
  }
4644
4415
  }
4645
4416
  if (!vtxo) {
4646
- throw new Error(
4647
- `Swap ${pendingSwap.id}: no spendable virtual coins found`
4648
- );
4417
+ throw new Error(`Swap ${pendingSwap.id}: no spendable virtual coins found`);
4649
4418
  }
4650
4419
  const input = {
4651
4420
  ...vtxo,
@@ -4656,10 +4425,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
4656
4425
  amount: BigInt(vtxo.value),
4657
4426
  script: import_sdk8.ArkAddress.decode(address).pkScript
4658
4427
  };
4659
- const vhtlcIdentity = claimVHTLCIdentity(
4660
- this.wallet.identity,
4661
- preimage
4662
- );
4428
+ const vhtlcIdentity = claimVHTLCIdentity(this.wallet.identity, preimage);
4663
4429
  if ((0, import_sdk8.isRecoverable)(vtxo)) {
4664
4430
  await this.joinBatch(vhtlcIdentity, input, output, arkInfo);
4665
4431
  } else {
@@ -4685,16 +4451,10 @@ var ArkadeSwaps = class _ArkadeSwaps {
4685
4451
  */
4686
4452
  async signCooperativeClaimForServer(pendingSwap) {
4687
4453
  if (!pendingSwap.response.lockupDetails.swapTree)
4688
- throw new Error(
4689
- `Swap ${pendingSwap.id}: missing swap tree in lockup details`
4690
- );
4454
+ throw new Error(`Swap ${pendingSwap.id}: missing swap tree in lockup details`);
4691
4455
  if (!pendingSwap.response.lockupDetails.serverPublicKey)
4692
- throw new Error(
4693
- `Swap ${pendingSwap.id}: missing server public key in lockup details`
4694
- );
4695
- const claimDetails = await this.swapProvider.getChainClaimDetails(
4696
- pendingSwap.id
4697
- );
4456
+ throw new Error(`Swap ${pendingSwap.id}: missing server public key in lockup details`);
4457
+ const claimDetails = await this.swapProvider.getChainClaimDetails(pendingSwap.id);
4698
4458
  const serverPubKey = pendingSwap.response.lockupDetails.serverPublicKey;
4699
4459
  if (claimDetails.publicKey !== serverPubKey) {
4700
4460
  throw new Error(
@@ -4710,9 +4470,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
4710
4470
  );
4711
4471
  const musigNonces = musig.message(import_base9.hex.decode(claimDetails.transactionHash)).generateNonce().aggregateNonces([
4712
4472
  [
4713
- import_base9.hex.decode(
4714
- pendingSwap.response.lockupDetails.serverPublicKey
4715
- ),
4473
+ import_base9.hex.decode(pendingSwap.response.lockupDetails.serverPublicKey),
4716
4474
  import_base9.hex.decode(claimDetails.pubNonce)
4717
4475
  ]
4718
4476
  ]).initializeSession();
@@ -4731,10 +4489,8 @@ var ArkadeSwaps = class _ArkadeSwaps {
4731
4489
  * @returns The transaction ID of the claim.
4732
4490
  */
4733
4491
  async waitAndClaimChain(pendingSwap) {
4734
- if (pendingSwap.request.to === "ARK")
4735
- return this.waitAndClaimArk(pendingSwap);
4736
- if (pendingSwap.request.to === "BTC")
4737
- return this.waitAndClaimBtc(pendingSwap);
4492
+ if (pendingSwap.request.to === "ARK") return this.waitAndClaimArk(pendingSwap);
4493
+ if (pendingSwap.request.to === "BTC") return this.waitAndClaimBtc(pendingSwap);
4738
4494
  throw new SwapError({
4739
4495
  message: `Unsupported swap destination: ${pendingSwap.request.to}`
4740
4496
  });
@@ -4749,11 +4505,9 @@ var ArkadeSwaps = class _ArkadeSwaps {
4749
4505
  */
4750
4506
  async createChainSwap(args) {
4751
4507
  const { to, from, receiverLockAmount, senderLockAmount, toAddress } = args;
4752
- if (!toAddress)
4753
- throw new SwapError({ message: "Destination address is required" });
4508
+ if (!toAddress) throw new SwapError({ message: "Destination address is required" });
4754
4509
  const feeSatsPerByte = args.feeSatsPerByte ?? 1;
4755
- if (feeSatsPerByte <= 0)
4756
- throw new SwapError({ message: "Invalid feeSatsPerByte" });
4510
+ if (feeSatsPerByte <= 0) throw new SwapError({ message: "Invalid feeSatsPerByte" });
4757
4511
  let amount, serverLockAmount, userLockAmount;
4758
4512
  if (receiverLockAmount) {
4759
4513
  amount = receiverLockAmount;
@@ -4768,8 +4522,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
4768
4522
  }
4769
4523
  const preimage = (0, import_utils3.randomBytes)(32);
4770
4524
  const preimageHash = import_base9.hex.encode((0, import_sha23.sha256)(preimage));
4771
- if (!preimageHash)
4772
- throw new SwapError({ message: "Failed to get preimage hash" });
4525
+ if (!preimageHash) throw new SwapError({ message: "Failed to get preimage hash" });
4773
4526
  const ephemeralKey = import_secp256k13.secp256k1.utils.randomSecretKey();
4774
4527
  const refundPublicKey = to === "ARK" ? import_base9.hex.encode(import_secp256k13.secp256k1.getPublicKey(ephemeralKey)) : import_base9.hex.encode(await this.wallet.identity.compressedPublicKey());
4775
4528
  if (!refundPublicKey)
@@ -4818,30 +4571,20 @@ var ArkadeSwaps = class _ArkadeSwaps {
4818
4571
  const { to, from, swap, arkInfo } = args;
4819
4572
  if (from === "ARK") {
4820
4573
  if (!swap.response.lockupDetails.serverPublicKey)
4821
- throw new Error(
4822
- `Swap ${swap.id}: missing serverPublicKey in lockup details`
4823
- );
4574
+ throw new Error(`Swap ${swap.id}: missing serverPublicKey in lockup details`);
4824
4575
  if (!swap.response.lockupDetails.timeouts)
4825
- throw new Error(
4826
- `Swap ${swap.id}: missing timeouts in lockup details`
4827
- );
4576
+ throw new Error(`Swap ${swap.id}: missing timeouts in lockup details`);
4828
4577
  }
4829
4578
  if (to === "ARK") {
4830
4579
  if (!swap.response.claimDetails.serverPublicKey)
4831
- throw new Error(
4832
- `Swap ${swap.id}: missing serverPublicKey in claim details`
4833
- );
4580
+ throw new Error(`Swap ${swap.id}: missing serverPublicKey in claim details`);
4834
4581
  if (!swap.response.claimDetails.timeouts)
4835
- throw new Error(
4836
- `Swap ${swap.id}: missing timeouts in claim details`
4837
- );
4582
+ throw new Error(`Swap ${swap.id}: missing timeouts in claim details`);
4838
4583
  }
4839
4584
  const lockupAddress = to === "ARK" ? swap.response.claimDetails.lockupAddress : swap.response.lockupDetails.lockupAddress;
4840
4585
  const receiverPubkey = to === "ARK" ? swap.request.claimPublicKey : swap.response.lockupDetails.serverPublicKey;
4841
4586
  const senderPubkey = to === "ARK" ? swap.response.claimDetails.serverPublicKey : swap.request.refundPublicKey;
4842
- const serverPubkey = import_base9.hex.encode(
4843
- normalizeToXOnlyKey(arkInfo.signerPubkey, "server")
4844
- );
4587
+ const serverPubkey = import_base9.hex.encode(normalizeToXOnlyKey(arkInfo.signerPubkey, "server"));
4845
4588
  const vhtlcTimeouts = to === "ARK" ? swap.response.claimDetails.timeouts : swap.response.lockupDetails.timeouts;
4846
4589
  const { vhtlcAddress } = this.createVHTLCScript({
4847
4590
  network: arkInfo.network,
@@ -4859,15 +4602,110 @@ var ArkadeSwaps = class _ArkadeSwaps {
4859
4602
  return true;
4860
4603
  }
4861
4604
  /**
4862
- * Renegotiates the quote for an existing swap.
4605
+ * Renegotiates the quote for an existing chain swap. Convenience wrapper
4606
+ * over `getSwapQuote` + `acceptSwapQuote` with a safety floor.
4607
+ *
4608
+ * The floor is resolved in order:
4609
+ * 1. `options.minAcceptableAmount` if provided.
4610
+ * 2. The original `response.claimDetails.amount` of the stored
4611
+ * pending swap (Boltz-confirmed server-lock amount at creation).
4612
+ * 3. Otherwise throws `QuoteRejectedError({ reason: "no_baseline" })`.
4613
+ *
4614
+ * `options.maxSlippageBps` (default 0) relaxes the floor by basis points.
4615
+ * Quotes ≤ 0 are always rejected. On rejection the acceptance is NOT
4616
+ * posted to Boltz.
4617
+ *
4618
+ * Prefer `getSwapQuote` / `acceptSwapQuote` for callers that want to
4619
+ * inspect the quote before committing.
4620
+ *
4863
4621
  * @param swapId - The ID of the swap.
4622
+ * @param options - Optional floor and slippage configuration.
4864
4623
  * @returns The accepted quote amount.
4624
+ * @throws QuoteRejectedError if the quote is non-positive, below the
4625
+ * effective floor, or no baseline is available.
4865
4626
  */
4866
- async quoteSwap(swapId) {
4627
+ async quoteSwap(swapId, options) {
4628
+ const effectiveFloor = await this.resolveEffectiveFloor(swapId, options);
4629
+ const amount = await this.getSwapQuote(swapId);
4630
+ this.validateQuote(amount, effectiveFloor);
4631
+ await this.swapProvider.postChainQuote(swapId, { amount });
4632
+ return amount;
4633
+ }
4634
+ /**
4635
+ * Fetches a renegotiated quote from Boltz without accepting it.
4636
+ * Pair with `acceptSwapQuote` to commit a specific value.
4637
+ */
4638
+ async getSwapQuote(swapId) {
4867
4639
  const { amount } = await this.swapProvider.getChainQuote(swapId);
4640
+ return amount;
4641
+ }
4642
+ /**
4643
+ * Accepts a quote amount for an existing chain swap, after validating it
4644
+ * against the configured floor. See `quoteSwap` for floor-resolution rules.
4645
+ *
4646
+ * @throws QuoteRejectedError if `amount` ≤ 0, below the effective floor,
4647
+ * or no baseline is available.
4648
+ */
4649
+ async acceptSwapQuote(swapId, amount, options) {
4650
+ const effectiveFloor = await this.resolveEffectiveFloor(swapId, options);
4651
+ this.validateQuote(amount, effectiveFloor);
4868
4652
  await this.swapProvider.postChainQuote(swapId, { amount });
4869
4653
  return amount;
4870
4654
  }
4655
+ async resolveEffectiveFloor(swapId, options) {
4656
+ this.validateQuoteOptions(options);
4657
+ const floor = await this.resolveQuoteFloor(swapId, options);
4658
+ const slippageBps = options?.maxSlippageBps ?? 0;
4659
+ return Math.floor(floor - floor * slippageBps / 1e4);
4660
+ }
4661
+ async resolveQuoteFloor(swapId, options) {
4662
+ if (options?.minAcceptableAmount !== void 0) {
4663
+ return options.minAcceptableAmount;
4664
+ }
4665
+ const swaps = await this.swapRepository.getAllSwaps({
4666
+ id: swapId,
4667
+ type: "chain"
4668
+ });
4669
+ const stored = swaps[0];
4670
+ const amount = stored?.response?.claimDetails?.amount;
4671
+ if (typeof amount !== "number") {
4672
+ throw new QuoteRejectedError({ reason: "no_baseline" });
4673
+ }
4674
+ return amount;
4675
+ }
4676
+ validateQuoteOptions(options) {
4677
+ if (options?.minAcceptableAmount !== void 0) {
4678
+ const v = options.minAcceptableAmount;
4679
+ if (!Number.isInteger(v) || v <= 0) {
4680
+ throw new TypeError(
4681
+ `Invalid minAcceptableAmount: ${v} \u2014 must be a positive integer`
4682
+ );
4683
+ }
4684
+ }
4685
+ if (options?.maxSlippageBps !== void 0) {
4686
+ const v = options.maxSlippageBps;
4687
+ if (!Number.isInteger(v) || v < 0 || v > 1e4) {
4688
+ throw new TypeError(
4689
+ `Invalid maxSlippageBps: ${v} \u2014 must be an integer in [0, 10000]`
4690
+ );
4691
+ }
4692
+ }
4693
+ }
4694
+ validateQuote(amount, effectiveFloor) {
4695
+ if (!(amount > 0)) {
4696
+ throw new QuoteRejectedError({
4697
+ reason: "non_positive",
4698
+ quotedAmount: amount
4699
+ });
4700
+ }
4701
+ if (amount < effectiveFloor) {
4702
+ throw new QuoteRejectedError({
4703
+ reason: "below_floor",
4704
+ quotedAmount: amount,
4705
+ floor: effectiveFloor
4706
+ });
4707
+ }
4708
+ }
4871
4709
  // =========================================================================
4872
4710
  // Shared utilities
4873
4711
  // =========================================================================
@@ -4881,14 +4719,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
4881
4719
  * @returns The commitment transaction ID.
4882
4720
  */
4883
4721
  async joinBatch(identity, input, output, arkInfo, isRecoverable2 = true) {
4884
- return joinBatch(
4885
- this.arkProvider,
4886
- identity,
4887
- input,
4888
- output,
4889
- arkInfo,
4890
- isRecoverable2
4891
- );
4722
+ return joinBatch(this.arkProvider, identity, input, output, arkInfo, isRecoverable2);
4892
4723
  }
4893
4724
  /**
4894
4725
  * Creates a VHTLC script for the swap.
@@ -4926,9 +4757,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
4926
4757
  async getPendingSubmarineSwaps() {
4927
4758
  const swaps = await this.getPendingSubmarineSwapsFromStorage();
4928
4759
  if (!swaps) return [];
4929
- return swaps.filter(
4930
- (swap) => swap.status === "invoice.set"
4931
- );
4760
+ return swaps.filter((swap) => swap.status === "invoice.set");
4932
4761
  }
4933
4762
  /**
4934
4763
  * Returns pending reverse swaps (those with status `swap.created`).
@@ -4936,9 +4765,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
4936
4765
  async getPendingReverseSwaps() {
4937
4766
  const swaps = await this.getPendingReverseSwapsFromStorage();
4938
4767
  if (!swaps) return [];
4939
- return swaps.filter(
4940
- (swap) => swap.status === "swap.created"
4941
- );
4768
+ return swaps.filter((swap) => swap.status === "swap.created");
4942
4769
  }
4943
4770
  /**
4944
4771
  * Returns pending chain swaps (those with status `swap.created`).
@@ -4977,10 +4804,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
4977
4804
  this.savePendingReverseSwap.bind(this)
4978
4805
  )
4979
4806
  ).catch((error) => {
4980
- logger.error(
4981
- `Failed to refresh swap status for ${swap.id}:`,
4982
- error
4983
- );
4807
+ logger.error(`Failed to refresh swap status for ${swap.id}:`, error);
4984
4808
  })
4985
4809
  );
4986
4810
  }
@@ -4994,23 +4818,15 @@ var ArkadeSwaps = class _ArkadeSwaps {
4994
4818
  this.savePendingSubmarineSwap.bind(this)
4995
4819
  )
4996
4820
  ).catch((error) => {
4997
- logger.error(
4998
- `Failed to refresh swap status for ${swap.id}:`,
4999
- error
5000
- );
4821
+ logger.error(`Failed to refresh swap status for ${swap.id}:`, error);
5001
4822
  })
5002
4823
  );
5003
4824
  }
5004
4825
  for (const swap of await this.getPendingChainSwapsFromStorage()) {
5005
4826
  if (isChainFinalStatus(swap.status)) continue;
5006
4827
  promises.push(
5007
- this.getSwapStatus(swap.id).then(
5008
- ({ status }) => this.savePendingChainSwap({ ...swap, status })
5009
- ).catch((error) => {
5010
- logger.error(
5011
- `Failed to refresh swap status for ${swap.id}:`,
5012
- error
5013
- );
4828
+ this.getSwapStatus(swap.id).then(({ status }) => this.savePendingChainSwap({ ...swap, status })).catch((error) => {
4829
+ logger.error(`Failed to refresh swap status for ${swap.id}:`, error);
5014
4830
  })
5015
4831
  );
5016
4832
  }
@@ -5027,9 +4843,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
5027
4843
  * display/monitoring and are not automatically wired into the SwapManager.
5028
4844
  */
5029
4845
  async restoreSwaps(boltzFees) {
5030
- const publicKey = import_base9.hex.encode(
5031
- await this.wallet.identity.compressedPublicKey()
5032
- );
4846
+ const publicKey = import_base9.hex.encode(await this.wallet.identity.compressedPublicKey());
5033
4847
  if (!publicKey) throw new Error("Failed to get public key from wallet");
5034
4848
  const fees = boltzFees ?? await this.swapProvider.getFees();
5035
4849
  const chainSwaps = [];
@@ -5081,25 +4895,14 @@ var ArkadeSwaps = class _ArkadeSwaps {
5081
4895
  preimage: ""
5082
4896
  });
5083
4897
  } else if (isRestoredSubmarineSwap(swap)) {
5084
- const {
5085
- amount,
5086
- lockupAddress,
5087
- serverPublicKey,
5088
- tree,
5089
- timeoutBlockHeights
5090
- } = swap.refundDetails;
4898
+ const { amount, lockupAddress, serverPublicKey, tree, timeoutBlockHeights } = swap.refundDetails;
5091
4899
  let preimage = "";
5092
4900
  if (!isSubmarineFinalStatus(status)) {
5093
4901
  try {
5094
- const data = await this.swapProvider.getSwapPreimage(
5095
- swap.id
5096
- );
4902
+ const data = await this.swapProvider.getSwapPreimage(swap.id);
5097
4903
  preimage = data.preimage;
5098
4904
  } catch (error) {
5099
- logger.warn(
5100
- `Failed to restore preimage for submarine swap ${id}`,
5101
- error
5102
- );
4905
+ logger.warn(`Failed to restore preimage for submarine swap ${id}`, error);
5103
4906
  }
5104
4907
  }
5105
4908
  submarineSwaps.push({
@@ -5137,12 +4940,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
5137
4940
  } else if (isRestoredChainSwap(swap)) {
5138
4941
  const refundDetails = swap.refundDetails;
5139
4942
  if (!refundDetails) continue;
5140
- const {
5141
- amount,
5142
- lockupAddress,
5143
- serverPublicKey,
5144
- timeoutBlockHeight
5145
- } = refundDetails;
4943
+ const { amount, lockupAddress, serverPublicKey, timeoutBlockHeight } = refundDetails;
5146
4944
  chainSwaps.push({
5147
4945
  id,
5148
4946
  type: "chain",
@@ -5195,19 +4993,11 @@ var SWAP_POLL_TASK_TYPE = "swap-poll";
5195
4993
  var swapsPollProcessor = {
5196
4994
  taskType: SWAP_POLL_TASK_TYPE,
5197
4995
  async execute(item, deps) {
5198
- const {
5199
- swapRepository,
5200
- swapProvider,
5201
- wallet,
5202
- arkProvider,
5203
- indexerProvider
5204
- } = deps;
4996
+ const { swapRepository, swapProvider, wallet, arkProvider, indexerProvider } = deps;
5205
4997
  const allSwaps = await swapRepository.getAllSwaps();
5206
4998
  const pendingSwaps = allSwaps.filter((swap) => {
5207
- if (isPendingReverseSwap(swap))
5208
- return !isReverseFinalStatus(swap.status);
5209
- if (isPendingSubmarineSwap(swap))
5210
- return !isSubmarineFinalStatus(swap.status);
4999
+ if (isPendingReverseSwap(swap)) return !isReverseFinalStatus(swap.status);
5000
+ if (isPendingSubmarineSwap(swap)) return !isSubmarineFinalStatus(swap.status);
5211
5001
  return false;
5212
5002
  });
5213
5003
  let polled = 0;
@@ -5237,19 +5027,14 @@ var swapsPollProcessor = {
5237
5027
  }
5238
5028
  if (isPendingReverseSwap(swap) && isReverseClaimableStatus(currentStatus)) {
5239
5029
  if (!swap.preimage) {
5240
- logger.warn(
5241
- `[swap-poll] Skipping claim for ${swap.id}: no preimage`
5242
- );
5030
+ logger.warn(`[swap-poll] Skipping claim for ${swap.id}: no preimage`);
5243
5031
  continue;
5244
5032
  }
5245
5033
  try {
5246
5034
  await tempSwaps.claimVHTLC(swap);
5247
5035
  claimed++;
5248
5036
  } catch (claimError) {
5249
- logger.error(
5250
- `[swap-poll] Claim failed for ${swap.id}:`,
5251
- claimError
5252
- );
5037
+ logger.error(`[swap-poll] Claim failed for ${swap.id}:`, claimError);
5253
5038
  errors++;
5254
5039
  }
5255
5040
  }
@@ -5265,18 +5050,12 @@ var swapsPollProcessor = {
5265
5050
  await tempSwaps.refundVHTLC(swapWithStatus);
5266
5051
  refunded++;
5267
5052
  } catch (refundError) {
5268
- logger.error(
5269
- `[swap-poll] Refund failed for ${swap.id}:`,
5270
- refundError
5271
- );
5053
+ logger.error(`[swap-poll] Refund failed for ${swap.id}:`, refundError);
5272
5054
  errors++;
5273
5055
  }
5274
5056
  }
5275
5057
  } catch (swapError) {
5276
- logger.error(
5277
- `[swap-poll] Error processing swap ${swap.id}:`,
5278
- swapError
5279
- );
5058
+ logger.error(`[swap-poll] Error processing swap ${swap.id}:`, swapError);
5280
5059
  errors++;
5281
5060
  }
5282
5061
  }
@@ -5293,9 +5072,6 @@ var swapsPollProcessor = {
5293
5072
  };
5294
5073
 
5295
5074
  // src/expo/background.ts
5296
- function getRandomId() {
5297
- return Math.random().toString(36).slice(2) + Date.now().toString(36);
5298
- }
5299
5075
  function createBackgroundWalletShim(args) {
5300
5076
  const notImplemented = (method) => {
5301
5077
  throw new Error(
@@ -5330,9 +5106,7 @@ function defineExpoSwapBackgroundTask(taskName, options) {
5330
5106
  }
5331
5107
  const identity = await identityFactory();
5332
5108
  const arkProvider = new import_expo2.ExpoArkProvider(config.arkServerUrl);
5333
- const indexerProvider = new import_expo2.ExpoIndexerProvider(
5334
- config.arkServerUrl
5335
- );
5109
+ const indexerProvider = new import_expo2.ExpoIndexerProvider(config.arkServerUrl);
5336
5110
  const swapProvider = new BoltzSwapProvider({
5337
5111
  network: config.network,
5338
5112
  apiUrl: config.boltzApiUrl
@@ -5347,11 +5121,7 @@ function defineExpoSwapBackgroundTask(taskName, options) {
5347
5121
  const serverPubKey = hex9.decode(info.signerPubkey);
5348
5122
  const xOnlyServerPubKey = serverPubKey.length === 33 ? serverPubKey.slice(1) : serverPubKey;
5349
5123
  const hrp = info.network === "bitcoin" ? "ark" : "tark";
5350
- return new ArkAddress3(
5351
- xOnlyServerPubKey,
5352
- pubkey,
5353
- hrp
5354
- ).encode();
5124
+ return new ArkAddress3(xOnlyServerPubKey, pubkey, hrp).encode();
5355
5125
  }
5356
5126
  });
5357
5127
  const deps = {
@@ -5365,14 +5135,12 @@ function defineExpoSwapBackgroundTask(taskName, options) {
5365
5135
  await (0, import_expo.runTasks)(taskQueue, [swapsPollProcessor], deps);
5366
5136
  const results = await taskQueue.getResults();
5367
5137
  if (results.length > 0) {
5368
- await taskQueue.acknowledgeResults(
5369
- results.map((r) => r.id)
5370
- );
5138
+ await taskQueue.acknowledgeResults(results.map((r) => r.id));
5371
5139
  }
5372
5140
  const existing = await taskQueue.getTasks(SWAP_POLL_TASK_TYPE);
5373
5141
  if (existing.length === 0) {
5374
5142
  const task = {
5375
- id: getRandomId(),
5143
+ id: (0, import_sdk9.getRandomId)(),
5376
5144
  type: SWAP_POLL_TASK_TYPE,
5377
5145
  data: {},
5378
5146
  createdAt: Date.now()