@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
@@ -45,7 +45,10 @@ var SwapError = class extends Error {
45
45
  /** The pending swap associated with this error, if available. */
46
46
  pendingSwap;
47
47
  constructor(options = {}) {
48
- super(options.message ?? "Error during swap.");
48
+ super(
49
+ options.message ?? "Error during swap.",
50
+ options.cause !== void 0 ? { cause: options.cause } : void 0
51
+ );
49
52
  this.name = "SwapError";
50
53
  this.isClaimable = options.isClaimable ?? false;
51
54
  this.isRefundable = options.isRefundable ?? false;
@@ -122,6 +125,96 @@ var TransactionRefundedError = class extends SwapError {
122
125
  this.name = "TransactionRefundedError";
123
126
  }
124
127
  };
128
+ var QuoteRejectedError = class _QuoteRejectedError extends SwapError {
129
+ reason;
130
+ quotedAmount;
131
+ floor;
132
+ constructor(options) {
133
+ super({
134
+ message: options.message ?? _QuoteRejectedError.defaultMessage(options),
135
+ ...options
136
+ });
137
+ this.name = "QuoteRejectedError";
138
+ this.reason = options.reason;
139
+ this.quotedAmount = "quotedAmount" in options ? options.quotedAmount : void 0;
140
+ this.floor = "floor" in options ? options.floor : void 0;
141
+ }
142
+ static defaultMessage(options) {
143
+ switch (options.reason) {
144
+ case "below_floor":
145
+ return `Boltz quote ${options.quotedAmount} is below acceptable floor ${options.floor}`;
146
+ case "non_positive":
147
+ return `Boltz quote ${options.quotedAmount} is not positive`;
148
+ case "no_baseline":
149
+ return "Cannot accept quote: no minAcceptableAmount and no stored pending swap";
150
+ }
151
+ }
152
+ /**
153
+ * Serialize into a plain `Error` whose `.message` carries the full
154
+ * rejection payload as JSON behind a marker prefix. Structured clone
155
+ * (used by `postMessage` between page and service worker) preserves
156
+ * `Error.message` reliably but strips custom `.name` and own properties,
157
+ * so we move the typed data into the message field for transport.
158
+ */
159
+ toTransportError() {
160
+ return new Error(
161
+ QUOTE_REJECTION_TRANSPORT_PREFIX + JSON.stringify({
162
+ reason: this.reason,
163
+ message: this.message,
164
+ quotedAmount: this.quotedAmount,
165
+ floor: this.floor
166
+ })
167
+ );
168
+ }
169
+ /**
170
+ * Inverse of `toTransportError`. Returns a real `QuoteRejectedError` if
171
+ * `error` carries the transport prefix, else `null`.
172
+ */
173
+ static fromTransportError(error) {
174
+ if (!(error instanceof Error) || !error.message.startsWith(QUOTE_REJECTION_TRANSPORT_PREFIX)) {
175
+ return null;
176
+ }
177
+ const payload = error.message.slice(QUOTE_REJECTION_TRANSPORT_PREFIX.length);
178
+ let data;
179
+ try {
180
+ data = JSON.parse(payload);
181
+ } catch {
182
+ return null;
183
+ }
184
+ if (typeof data.reason !== "string" || !QUOTE_REJECTION_REASONS.has(data.reason)) {
185
+ return null;
186
+ }
187
+ const message = typeof data.message === "string" ? data.message : void 0;
188
+ const reason = data.reason;
189
+ const quotedAmount = typeof data.quotedAmount === "number" ? data.quotedAmount : null;
190
+ const floor = typeof data.floor === "number" ? data.floor : null;
191
+ switch (reason) {
192
+ case "below_floor":
193
+ if (quotedAmount === null || floor === null) return null;
194
+ return new _QuoteRejectedError({
195
+ reason,
196
+ quotedAmount,
197
+ floor,
198
+ message
199
+ });
200
+ case "non_positive":
201
+ if (quotedAmount === null) return null;
202
+ return new _QuoteRejectedError({
203
+ reason,
204
+ quotedAmount,
205
+ message
206
+ });
207
+ case "no_baseline":
208
+ return new _QuoteRejectedError({ reason, message });
209
+ }
210
+ }
211
+ };
212
+ var QUOTE_REJECTION_TRANSPORT_PREFIX = "QUOTE_REJECTED::";
213
+ var QUOTE_REJECTION_REASONS = /* @__PURE__ */ new Set([
214
+ "below_floor",
215
+ "non_positive",
216
+ "no_baseline"
217
+ ]);
125
218
  var BoltzRefundError = class extends Error {
126
219
  constructor(message, cause) {
127
220
  super(message);
@@ -137,18 +230,10 @@ var import_sdk8 = require("@arkade-os/sdk");
137
230
  var import_sdk = require("@arkade-os/sdk");
138
231
  var import_base = require("@scure/base");
139
232
  var isSubmarineFinalStatus = (status) => {
140
- return [
141
- "invoice.failedToPay",
142
- "transaction.claimed",
143
- "swap.expired"
144
- ].includes(status);
233
+ return ["invoice.failedToPay", "transaction.claimed", "swap.expired"].includes(status);
145
234
  };
146
235
  var isSubmarineRefundableStatus = (status) => {
147
- return [
148
- "invoice.failedToPay",
149
- "transaction.lockupFailed",
150
- "swap.expired"
151
- ].includes(status);
236
+ return ["invoice.failedToPay", "transaction.lockupFailed", "swap.expired"].includes(status);
152
237
  };
153
238
  var isSubmarineSuccessStatus = (status) => {
154
239
  return status === "transaction.claimed";
@@ -167,10 +252,7 @@ var isReverseClaimableStatus = (status) => {
167
252
  return ["transaction.mempool", "transaction.confirmed"].includes(status);
168
253
  };
169
254
  var isChainClaimableStatus = (status) => {
170
- return [
171
- "transaction.server.mempool",
172
- "transaction.server.confirmed"
173
- ].includes(status);
255
+ return ["transaction.server.mempool", "transaction.server.confirmed"].includes(status);
174
256
  };
175
257
  var isChainFinalStatus = (status) => {
176
258
  return [
@@ -284,8 +366,7 @@ var BASE_URLS = {
284
366
  var isSwapNotFoundBody = (error) => {
285
367
  const needle = "could not find swap";
286
368
  const fromJson = error.errorData?.error;
287
- if (typeof fromJson === "string" && fromJson.toLowerCase().includes(needle))
288
- return true;
369
+ if (typeof fromJson === "string" && fromJson.toLowerCase().includes(needle)) return true;
289
370
  return error.message.toLowerCase().includes(needle);
290
371
  };
291
372
  var BoltzSwapProvider = class {
@@ -299,10 +380,7 @@ var BoltzSwapProvider = class {
299
380
  this.network = config.network;
300
381
  this.referralId = config.referralId ?? "arkade-ts-sdk";
301
382
  const apiUrl = config.apiUrl || BASE_URLS[config.network];
302
- if (!apiUrl)
303
- throw new Error(
304
- `API URL is required for network: ${config.network}`
305
- );
383
+ if (!apiUrl) throw new Error(`API URL is required for network: ${config.network}`);
306
384
  this.apiUrl = apiUrl;
307
385
  this.wsUrl = this.apiUrl.replace(/^http(s)?:\/\//, "ws$1://").replace("9069", "9004") + "/v2/ws";
308
386
  }
@@ -321,10 +399,7 @@ var BoltzSwapProvider = class {
321
399
  /** Returns current Lightning swap fees (submarine + reverse) from Boltz. */
322
400
  async getFees() {
323
401
  const [submarine, reverse] = await Promise.all([
324
- this.request(
325
- "/v2/swap/submarine",
326
- "GET"
327
- ),
402
+ this.request("/v2/swap/submarine", "GET"),
328
403
  this.request("/v2/swap/reverse", "GET")
329
404
  ]);
330
405
  if (!isGetSubmarinePairsResponse(submarine))
@@ -344,10 +419,7 @@ var BoltzSwapProvider = class {
344
419
  }
345
420
  /** Returns current Lightning swap min/max limits from Boltz. */
346
421
  async getLimits() {
347
- const response = await this.request(
348
- "/v2/swap/submarine",
349
- "GET"
350
- );
422
+ const response = await this.request("/v2/swap/submarine", "GET");
351
423
  if (!isGetSubmarinePairsResponse(response))
352
424
  throw new SchemaError({ message: "error fetching limits" });
353
425
  return {
@@ -357,10 +429,7 @@ var BoltzSwapProvider = class {
357
429
  }
358
430
  /** Returns the current BTC chain tip height from Boltz. */
359
431
  async getChainHeight() {
360
- const response = await this.request(
361
- "/v2/chain/heights",
362
- "GET"
363
- );
432
+ const response = await this.request("/v2/chain/heights", "GET");
364
433
  if (typeof response?.BTC !== "number")
365
434
  throw new SchemaError({
366
435
  message: "error fetching chain heights"
@@ -390,10 +459,7 @@ var BoltzSwapProvider = class {
390
459
  async getSwapStatus(id) {
391
460
  let response;
392
461
  try {
393
- response = await this.request(
394
- `/v2/swap/${id}`,
395
- "GET"
396
- );
462
+ response = await this.request(`/v2/swap/${id}`, "GET");
397
463
  } catch (error) {
398
464
  if (error instanceof NetworkError && error.statusCode === 404 && isSwapNotFoundBody(error)) {
399
465
  throw new SwapNotFoundError(id, error.errorData);
@@ -489,12 +555,10 @@ var BoltzSwapProvider = class {
489
555
  throw new SwapError({ message: "Invalid 'to' chain" });
490
556
  if (["BTC", "ARK"].indexOf(from) === -1)
491
557
  throw new SwapError({ message: "Invalid 'from' chain" });
492
- if (to === from)
493
- throw new SwapError({ message: "Invalid swap direction" });
558
+ if (to === from) throw new SwapError({ message: "Invalid swap direction" });
494
559
  if (!preimageHash || preimageHash.length != 64)
495
560
  throw new SwapError({ message: "Invalid preimageHash" });
496
- if (feeSatsPerByte <= 0)
497
- throw new SwapError({ message: "Invalid feeSatsPerByte" });
561
+ if (feeSatsPerByte <= 0) throw new SwapError({ message: "Invalid feeSatsPerByte" });
498
562
  if (serverLockAmount !== void 0 && userLockAmount !== void 0 || serverLockAmount === void 0 && userLockAmount === void 0)
499
563
  throw new SwapError({
500
564
  message: "Either serverLockAmount or userLockAmount must be provided"
@@ -549,12 +613,8 @@ var BoltzSwapProvider = class {
549
613
  message: "Error refunding submarine swap"
550
614
  });
551
615
  return {
552
- transaction: import_sdk.Transaction.fromPSBT(
553
- import_base.base64.decode(response.transaction)
554
- ),
555
- checkpoint: import_sdk.Transaction.fromPSBT(
556
- import_base.base64.decode(response.checkpoint)
557
- )
616
+ transaction: import_sdk.Transaction.fromPSBT(import_base.base64.decode(response.transaction)),
617
+ checkpoint: import_sdk.Transaction.fromPSBT(import_base.base64.decode(response.checkpoint))
558
618
  };
559
619
  }
560
620
  /** Requests Boltz co-signature for a chain swap refund. Returns signed transaction + checkpoint. */
@@ -573,53 +633,53 @@ var BoltzSwapProvider = class {
573
633
  message: "Error refunding chain swap"
574
634
  });
575
635
  return {
576
- transaction: import_sdk.Transaction.fromPSBT(
577
- import_base.base64.decode(response.transaction)
578
- ),
579
- checkpoint: import_sdk.Transaction.fromPSBT(
580
- import_base.base64.decode(response.checkpoint)
581
- )
636
+ transaction: import_sdk.Transaction.fromPSBT(import_base.base64.decode(response.transaction)),
637
+ checkpoint: import_sdk.Transaction.fromPSBT(import_base.base64.decode(response.checkpoint))
582
638
  };
583
639
  }
584
- /** Monitors swap status updates via WebSocket. Calls update callback on each status change. Resolves when terminal. */
640
+ /**
641
+ * Monitors swap status updates and forwards them to the update callback.
642
+ * Prefers a WebSocket subscription; on connection error or premature close
643
+ * it falls back to REST polling so callers don't fail when the WS endpoint
644
+ * is flaky (observed in CI). Resolves when the swap reaches a terminal
645
+ * status.
646
+ */
585
647
  async monitorSwap(swapId, update) {
586
648
  return new Promise((resolve, reject) => {
587
- const webSocket = new globalThis.WebSocket(this.wsUrl);
588
- const connectionTimeout = setTimeout(() => {
589
- webSocket.close();
590
- reject(new NetworkError("WebSocket connection timeout"));
591
- }, 3e4);
592
- webSocket.onerror = (error) => {
593
- clearTimeout(connectionTimeout);
594
- reject(
595
- new NetworkError(
596
- `WebSocket error: ${error.message}`
597
- )
598
- );
599
- };
600
- webSocket.onopen = () => {
601
- clearTimeout(connectionTimeout);
602
- webSocket.send(
603
- JSON.stringify({
604
- op: "subscribe",
605
- channel: "swap.update",
606
- args: [swapId]
607
- })
608
- );
649
+ let settled = false;
650
+ let lastStatus = null;
651
+ let pollTimer = null;
652
+ let webSocket = null;
653
+ let connectionTimeout = null;
654
+ const cleanup = () => {
655
+ if (connectionTimeout) {
656
+ clearTimeout(connectionTimeout);
657
+ connectionTimeout = null;
658
+ }
659
+ if (pollTimer) {
660
+ clearInterval(pollTimer);
661
+ pollTimer = null;
662
+ }
663
+ if (webSocket) {
664
+ try {
665
+ webSocket.close();
666
+ } catch {
667
+ }
668
+ webSocket = null;
669
+ }
609
670
  };
610
- webSocket.onclose = () => {
611
- clearTimeout(connectionTimeout);
612
- resolve();
671
+ const finish = (err) => {
672
+ if (settled) return;
673
+ settled = true;
674
+ cleanup();
675
+ if (err) reject(err);
676
+ else resolve();
613
677
  };
614
- webSocket.onmessage = async (rawMsg) => {
615
- const msg = JSON.parse(rawMsg.data);
616
- if (msg.event !== "update" || msg.args[0].id !== swapId) return;
617
- if (msg.args[0].error) {
618
- webSocket.close();
619
- reject(new SwapError({ message: msg.args[0].error }));
620
- }
621
- const status = msg.args[0].status;
622
- const negotiable = status === "transaction.lockupFailed" && msg.args[0].failureDetails?.actual !== void 0 && msg.args[0].failureDetails?.expected !== void 0;
678
+ const handleStatus = (status, data) => {
679
+ if (settled) return;
680
+ if (status === lastStatus) return;
681
+ lastStatus = status;
682
+ const negotiable = status === "transaction.lockupFailed" && data?.failureDetails?.actual !== void 0 && data?.failureDetails?.expected !== void 0;
623
683
  switch (status) {
624
684
  case "invoice.settled":
625
685
  case "transaction.claimed":
@@ -628,13 +688,13 @@ var BoltzSwapProvider = class {
628
688
  case "invoice.failedToPay":
629
689
  case "transaction.failed":
630
690
  case "swap.expired":
631
- webSocket.close();
632
- update(status, msg.args[0]);
633
- break;
691
+ update(status, data);
692
+ finish();
693
+ return;
634
694
  case "transaction.lockupFailed":
635
- if (!negotiable) webSocket.close();
636
- update(status, msg.args[0]);
637
- break;
695
+ update(status, data);
696
+ if (!negotiable) finish();
697
+ return;
638
698
  case "invoice.paid":
639
699
  case "invoice.pending":
640
700
  case "invoice.set":
@@ -644,9 +704,77 @@ var BoltzSwapProvider = class {
644
704
  case "transaction.claim.pending":
645
705
  case "transaction.server.mempool":
646
706
  case "transaction.server.confirmed":
647
- update(status, msg.args[0]);
707
+ update(status, data);
708
+ return;
648
709
  }
649
710
  };
711
+ const startPolling = () => {
712
+ if (settled || pollTimer) return;
713
+ const poll = async () => {
714
+ if (settled) return;
715
+ try {
716
+ const result = await this.getSwapStatus(swapId);
717
+ handleStatus(result.status, { ...result, id: swapId });
718
+ } catch {
719
+ }
720
+ };
721
+ pollTimer = setInterval(poll, 1e3);
722
+ poll();
723
+ };
724
+ try {
725
+ webSocket = new globalThis.WebSocket(this.wsUrl);
726
+ connectionTimeout = setTimeout(() => {
727
+ try {
728
+ webSocket?.close();
729
+ } catch {
730
+ }
731
+ webSocket = null;
732
+ startPolling();
733
+ }, 5e3);
734
+ webSocket.onerror = () => {
735
+ if (connectionTimeout) {
736
+ clearTimeout(connectionTimeout);
737
+ connectionTimeout = null;
738
+ }
739
+ webSocket = null;
740
+ startPolling();
741
+ };
742
+ webSocket.onopen = () => {
743
+ if (connectionTimeout) {
744
+ clearTimeout(connectionTimeout);
745
+ connectionTimeout = null;
746
+ }
747
+ webSocket?.send(
748
+ JSON.stringify({
749
+ op: "subscribe",
750
+ channel: "swap.update",
751
+ args: [swapId]
752
+ })
753
+ );
754
+ };
755
+ webSocket.onclose = () => {
756
+ if (connectionTimeout) {
757
+ clearTimeout(connectionTimeout);
758
+ connectionTimeout = null;
759
+ }
760
+ if (!settled && !pollTimer) startPolling();
761
+ };
762
+ webSocket.onmessage = (rawMsg) => {
763
+ try {
764
+ const msg = JSON.parse(rawMsg.data);
765
+ if (msg.event !== "update" || msg.args?.[0]?.id !== swapId) return;
766
+ if (msg.args[0].error) {
767
+ finish(new SwapError({ message: msg.args[0].error }));
768
+ return;
769
+ }
770
+ handleStatus(msg.args[0].status, msg.args[0]);
771
+ } catch {
772
+ }
773
+ };
774
+ } catch {
775
+ webSocket = null;
776
+ startPolling();
777
+ }
650
778
  });
651
779
  }
652
780
  /** Returns current chain swap fees for a given pair (e.g. ARK→BTC). */
@@ -654,10 +782,7 @@ var BoltzSwapProvider = class {
654
782
  if (from === to) {
655
783
  throw new SwapError({ message: "Invalid chain pair" });
656
784
  }
657
- const response = await this.request(
658
- "/v2/swap/chain",
659
- "GET"
660
- );
785
+ const response = await this.request("/v2/swap/chain", "GET");
661
786
  if (!isGetChainPairsResponse(response))
662
787
  throw new SchemaError({ message: "error fetching fees" });
663
788
  if (!response[from]?.[to]) {
@@ -672,10 +797,7 @@ var BoltzSwapProvider = class {
672
797
  if (from === to) {
673
798
  throw new SwapError({ message: "Invalid chain pair" });
674
799
  }
675
- const response = await this.request(
676
- "/v2/swap/chain",
677
- "GET"
678
- );
800
+ const response = await this.request("/v2/swap/chain", "GET");
679
801
  if (!isGetChainPairsResponse(response))
680
802
  throw new SchemaError({ message: "error fetching limits" });
681
803
  if (!response[from]?.[to]) {
@@ -804,9 +926,7 @@ var BoltzSwapProvider = class {
804
926
  return await response.json();
805
927
  } catch (error) {
806
928
  if (error instanceof NetworkError) throw error;
807
- throw new NetworkError(
808
- `Request to ${url} failed: ${error.message}`
809
- );
929
+ throw new NetworkError(`Request to ${url} failed: ${error.message}`);
810
930
  }
811
931
  }
812
932
  };
@@ -828,8 +948,7 @@ var findKeyIndex = (keys, target) => keys.findIndex((k) => (0, import_utils.equa
828
948
  var assertPublicKeys = (keys) => {
829
949
  const seen = /* @__PURE__ */ new Set();
830
950
  for (const key of keys) {
831
- if (key.length !== 33)
832
- throw new Error(`public key must be 33 bytes, got ${key.length}`);
951
+ if (key.length !== 33) throw new Error(`public key must be 33 bytes, got ${key.length}`);
833
952
  const enc = import_base2.hex.encode(key);
834
953
  if (seen.has(enc)) throw new Error(`duplicate public key ${enc}`);
835
954
  seen.add(enc);
@@ -837,9 +956,7 @@ var assertPublicKeys = (keys) => {
837
956
  };
838
957
  var aggregateKeys = (publicKeys, tweak) => {
839
958
  assertPublicKeys([...publicKeys]);
840
- return (0, import_musig2.keyAggExport)(
841
- (0, import_musig2.keyAggregate)([...publicKeys], tweak ? [tweak] : [], tweak ? [true] : [])
842
- );
959
+ return (0, import_musig2.keyAggExport)((0, import_musig2.keyAggregate)([...publicKeys], tweak ? [tweak] : [], tweak ? [true] : []));
843
960
  };
844
961
  var MusigKeyAgg = class _MusigKeyAgg {
845
962
  constructor(privateKey, myPublicKey, publicKeys, myIndex, aggPubkey, internalKey, _tweak) {
@@ -886,18 +1003,12 @@ var MusigWithMessage = class {
886
1003
  this.msg = msg;
887
1004
  }
888
1005
  generateNonce() {
889
- const nonce = (0, import_musig2.nonceGen)(
890
- this.myPublicKey,
891
- this.privateKey,
892
- this.aggPubkey,
893
- this.msg
894
- );
1006
+ const nonce = (0, import_musig2.nonceGen)(this.myPublicKey, this.privateKey, this.aggPubkey, this.msg);
895
1007
  return new MusigWithNonce(
896
1008
  this.privateKey,
897
1009
  this.myPublicKey,
898
1010
  this.publicKeys,
899
1011
  this.myIndex,
900
- this.aggPubkey,
901
1012
  this.tweak,
902
1013
  this.msg,
903
1014
  nonce
@@ -905,12 +1016,11 @@ var MusigWithMessage = class {
905
1016
  }
906
1017
  };
907
1018
  var MusigWithNonce = class {
908
- constructor(privateKey, myPublicKey, publicKeys, myIndex, aggPubkey, tweak, msg, nonce) {
1019
+ constructor(privateKey, myPublicKey, publicKeys, myIndex, tweak, msg, nonce) {
909
1020
  this.privateKey = privateKey;
910
1021
  this.myPublicKey = myPublicKey;
911
1022
  this.publicKeys = publicKeys;
912
1023
  this.myIndex = myIndex;
913
- this.aggPubkey = aggPubkey;
914
1024
  this.tweak = tweak;
915
1025
  this.msg = msg;
916
1026
  this.nonce = nonce;
@@ -942,10 +1052,8 @@ var MusigWithNonce = class {
942
1052
  const aggregatedNonce = (0, import_musig2.nonceAggregate)([...ordered]);
943
1053
  return new MusigNoncesAggregated(
944
1054
  this.privateKey,
945
- this.myPublicKey,
946
1055
  this.publicKeys,
947
1056
  this.myIndex,
948
- this.aggPubkey,
949
1057
  this.tweak,
950
1058
  this.msg,
951
1059
  this.nonce,
@@ -955,12 +1063,10 @@ var MusigWithNonce = class {
955
1063
  }
956
1064
  };
957
1065
  var MusigNoncesAggregated = class {
958
- constructor(privateKey, myPublicKey, publicKeys, myIndex, aggPubkey, tweak, msg, nonce, pubNonces, aggregatedNonce) {
1066
+ constructor(privateKey, publicKeys, myIndex, tweak, msg, nonce, pubNonces, aggregatedNonce) {
959
1067
  this.privateKey = privateKey;
960
- this.myPublicKey = myPublicKey;
961
1068
  this.publicKeys = publicKeys;
962
1069
  this.myIndex = myIndex;
963
- this.aggPubkey = aggPubkey;
964
1070
  this.tweak = tweak;
965
1071
  this.msg = msg;
966
1072
  this.nonce = nonce;
@@ -1006,11 +1112,7 @@ var MusigSession = class {
1006
1112
  const index = typeof publicKeyOrIndex === "number" ? publicKeyOrIndex : findKeyIndex(this.publicKeys, publicKeyOrIndex);
1007
1113
  if (index < 0 || index >= this.publicKeys.length)
1008
1114
  throw new Error("public key not found or index out of range");
1009
- if (!this.session.partialSigVerify(
1010
- signature,
1011
- [...this.pubNonces],
1012
- index
1013
- )) {
1115
+ if (!this.session.partialSigVerify(signature, [...this.pubNonces], index)) {
1014
1116
  throw new Error("invalid partial signature");
1015
1117
  }
1016
1118
  this.partialSignatures[index] = signature;
@@ -1019,12 +1121,7 @@ var MusigSession = class {
1019
1121
  signPartial() {
1020
1122
  const sig = this.session.sign(this.nonce.secret, this.privateKey, true);
1021
1123
  this.partialSignatures[this.myIndex] = sig;
1022
- return new MusigSigned(
1023
- this.session,
1024
- [...this.partialSignatures],
1025
- sig,
1026
- this.nonce.public
1027
- );
1124
+ return new MusigSigned(this.session, [...this.partialSignatures], sig, this.nonce.public);
1028
1125
  }
1029
1126
  };
1030
1127
  var MusigSigned = class {
@@ -1038,14 +1135,11 @@ var MusigSigned = class {
1038
1135
  if (this.partialSignatures.some((s) => s === null)) {
1039
1136
  throw new Error("not all partial signatures are set");
1040
1137
  }
1041
- return this.session.partialSigAgg(
1042
- this.partialSignatures
1043
- );
1138
+ return this.session.partialSigAgg(this.partialSignatures);
1044
1139
  }
1045
1140
  };
1046
1141
  var create = (privateKey, publicKeys) => {
1047
- if (publicKeys.length < 2)
1048
- throw new Error("need at least 2 keys to aggregate");
1142
+ if (publicKeys.length < 2) throw new Error("need at least 2 keys to aggregate");
1049
1143
  const keys = [...publicKeys];
1050
1144
  assertPublicKeys(keys);
1051
1145
  Object.freeze(keys);
@@ -1053,14 +1147,7 @@ var create = (privateKey, publicKeys) => {
1053
1147
  const myIndex = findKeyIndex(keys, myPublicKey);
1054
1148
  if (myIndex === -1) throw new Error("our key is not in publicKeys");
1055
1149
  const aggPubkey = aggregateKeys(keys);
1056
- return new MusigKeyAgg(
1057
- privateKey,
1058
- myPublicKey,
1059
- keys,
1060
- myIndex,
1061
- aggPubkey,
1062
- aggPubkey
1063
- );
1150
+ return new MusigKeyAgg(privateKey, myPublicKey, keys, myIndex, aggPubkey, aggPubkey);
1064
1151
  };
1065
1152
 
1066
1153
  // src/utils/boltz-swap-tx.ts
@@ -1136,9 +1223,7 @@ var taprootHashTree = (tree) => {
1136
1223
  };
1137
1224
  var tweakMusig = (musig, tree) => {
1138
1225
  const tweak = taprootHashTree(tree).hash;
1139
- return musig.xonlyTweakAdd(
1140
- import_secp256k12.schnorr.utils.taggedHash("TapTweak", musig.aggPubkey, tweak)
1141
- );
1226
+ return musig.xonlyTweakAdd(import_secp256k12.schnorr.utils.taggedHash("TapTweak", musig.aggPubkey, tweak));
1142
1227
  };
1143
1228
  var toXOnly = (pubKey) => {
1144
1229
  if (pubKey.length === 32) return pubKey;
@@ -1150,9 +1235,7 @@ var toXOnly = (pubKey) => {
1150
1235
  }
1151
1236
  return pubKey.subarray(1, 33);
1152
1237
  }
1153
- throw new Error(
1154
- `Invalid public key length: expected 32 or 33 bytes, got ${pubKey.length}`
1155
- );
1238
+ throw new Error(`Invalid public key length: expected 32 or 33 bytes, got ${pubKey.length}`);
1156
1239
  };
1157
1240
  var p2trScript = (publicKey) => import_btc_signer.Script.encode(["OP_1", toXOnly(publicKey)]);
1158
1241
  var detectSwapOutput = (tweakedKey, transaction) => {
@@ -1167,8 +1250,7 @@ var detectSwapOutput = (tweakedKey, transaction) => {
1167
1250
  };
1168
1251
  var DUMMY_TAPROOT_SIGNATURE = new Uint8Array(64);
1169
1252
  var constructClaimTransaction = (utxo, destinationScript, fee) => {
1170
- if (fee < BigInt(0) || fee >= utxo.amount)
1171
- throw new Error("fee exceeds utxo amount");
1253
+ if (fee < BigInt(0) || fee >= utxo.amount) throw new Error("fee exceeds utxo amount");
1172
1254
  const tx = new import_btc_signer.Transaction({ version: 2 });
1173
1255
  tx.addOutput({
1174
1256
  amount: utxo.amount - fee,
@@ -1187,9 +1269,7 @@ var constructClaimTransaction = (utxo, destinationScript, fee) => {
1187
1269
  };
1188
1270
  var targetFee = (satPerVbyte, constructTx) => {
1189
1271
  const tx = constructTx(BigInt(1));
1190
- return constructTx(
1191
- BigInt(Math.ceil((tx.vsize + tx.inputsLength) * satPerVbyte))
1192
- );
1272
+ return constructTx(BigInt(Math.ceil((tx.vsize + tx.inputsLength) * satPerVbyte)));
1193
1273
  };
1194
1274
 
1195
1275
  // src/utils/decoding.ts
@@ -1197,9 +1277,7 @@ var import_light_bolt11_decoder = __toESM(require("light-bolt11-decoder"), 1);
1197
1277
  var import_sdk2 = require("@arkade-os/sdk");
1198
1278
  var decodeInvoice = (invoice) => {
1199
1279
  const decoded = import_light_bolt11_decoder.default.decode(invoice);
1200
- const millisats = Number(
1201
- decoded.sections.find((s) => s.name === "amount")?.value ?? "0"
1202
- );
1280
+ const millisats = Number(decoded.sections.find((s) => s.name === "amount")?.value ?? "0");
1203
1281
  return {
1204
1282
  expiry: decoded.expiry ?? 3600,
1205
1283
  amountSats: Math.floor(millisats / 1e3),
@@ -1262,10 +1340,7 @@ function extractTimeLockFromLeafOutput(scriptHex) {
1262
1340
  const data = opcodes[hasCSV - 1];
1263
1341
  if (data instanceof Uint8Array) {
1264
1342
  const dataBytes = new Uint8Array(data).reverse();
1265
- const {
1266
- blocks,
1267
- seconds
1268
- } = import_bip68.default.decode(
1343
+ const { blocks, seconds } = import_bip68.default.decode(
1269
1344
  parseInt(import_base5.hex.encode(dataBytes), 16)
1270
1345
  );
1271
1346
  return blocks ?? seconds ?? 0;
@@ -1369,9 +1444,7 @@ var SwapManager = class _SwapManager {
1369
1444
  this.wsConnectedListeners.add(config.events.onWebSocketConnected);
1370
1445
  }
1371
1446
  if (config.events?.onWebSocketDisconnected) {
1372
- this.wsDisconnectedListeners.add(
1373
- config.events.onWebSocketDisconnected
1374
- );
1447
+ this.wsDisconnectedListeners.add(config.events.onWebSocketDisconnected);
1375
1448
  }
1376
1449
  this.currentReconnectDelay = this.config.reconnectDelayMs;
1377
1450
  this.currentPollRetryDelay = this.config.pollRetryDelayMs;
@@ -1522,9 +1595,7 @@ var SwapManager = class _SwapManager {
1522
1595
  */
1523
1596
  setPollInterval(ms) {
1524
1597
  if (ms <= 0) {
1525
- throw new RangeError(
1526
- `setPollInterval: ms must be a positive number, got ${ms}`
1527
- );
1598
+ throw new RangeError(`setPollInterval: ms must be a positive number, got ${ms}`);
1528
1599
  }
1529
1600
  const cappedInterval = Math.min(ms, this.config.maxPollIntervalMs);
1530
1601
  if (cappedInterval !== ms) {
@@ -1533,10 +1604,7 @@ var SwapManager = class _SwapManager {
1533
1604
  );
1534
1605
  }
1535
1606
  this.config.pollInterval = cappedInterval;
1536
- this.currentPollRetryDelay = Math.min(
1537
- cappedInterval,
1538
- this.config.pollRetryDelayMs
1539
- );
1607
+ this.currentPollRetryDelay = Math.min(cappedInterval, this.config.pollRetryDelayMs);
1540
1608
  if (this.isRunning) {
1541
1609
  if (this.usePollingFallback) {
1542
1610
  this.startPollingFallback();
@@ -1621,9 +1689,7 @@ var SwapManager = class _SwapManager {
1621
1689
  }
1622
1690
  if (this.isFinalStatus(swap)) {
1623
1691
  if (isPendingReverseSwap(swap)) {
1624
- const response = await this.swapProvider.getReverseSwapTxId(
1625
- swap.id
1626
- );
1692
+ const response = await this.swapProvider.getReverseSwapTxId(swap.id);
1627
1693
  return { txid: response.id };
1628
1694
  }
1629
1695
  if (isPendingSubmarineSwap(swap)) {
@@ -1640,31 +1706,19 @@ var SwapManager = class _SwapManager {
1640
1706
  if (updatedSwap.status === "invoice.settled") {
1641
1707
  this.swapProvider.getReverseSwapTxId(updatedSwap.id).then((response) => resolve({ txid: response.id })).catch((error) => reject(error));
1642
1708
  } else {
1643
- reject(
1644
- new Error(
1645
- `Swap failed with status: ${updatedSwap.status}`
1646
- )
1647
- );
1709
+ reject(new Error(`Swap failed with status: ${updatedSwap.status}`));
1648
1710
  }
1649
1711
  } else if (isPendingSubmarineSwap(updatedSwap)) {
1650
1712
  if (updatedSwap.status === "transaction.claimed") {
1651
1713
  resolve({ txid: updatedSwap.id });
1652
1714
  } else {
1653
- reject(
1654
- new Error(
1655
- `Swap failed with status: ${updatedSwap.status}`
1656
- )
1657
- );
1715
+ reject(new Error(`Swap failed with status: ${updatedSwap.status}`));
1658
1716
  }
1659
1717
  } else if (isPendingChainSwap(updatedSwap)) {
1660
1718
  if (updatedSwap.status === "transaction.claimed") {
1661
1719
  resolve({ txid: updatedSwap.id });
1662
1720
  } else {
1663
- reject(
1664
- new Error(
1665
- `Swap failed with status: ${updatedSwap.status}`
1666
- )
1667
- );
1721
+ reject(new Error(`Swap failed with status: ${updatedSwap.status}`));
1668
1722
  }
1669
1723
  }
1670
1724
  };
@@ -1707,16 +1761,12 @@ var SwapManager = class _SwapManager {
1707
1761
  const connectionTimeout = setTimeout(() => {
1708
1762
  logger.error("WebSocket connection timeout");
1709
1763
  this.websocket?.close();
1710
- this.enterPollingFallback(
1711
- new NetworkError("WebSocket connection failed")
1712
- );
1764
+ this.enterPollingFallback(new NetworkError("WebSocket connection failed"));
1713
1765
  }, 1e4);
1714
1766
  this.websocket.onerror = (error) => {
1715
1767
  clearTimeout(connectionTimeout);
1716
1768
  logger.error("WebSocket error:", error);
1717
- this.enterPollingFallback(
1718
- new NetworkError("WebSocket connection failed")
1719
- );
1769
+ this.enterPollingFallback(new NetworkError("WebSocket connection failed"));
1720
1770
  };
1721
1771
  this.websocket.onopen = () => {
1722
1772
  clearTimeout(connectionTimeout);
@@ -1756,9 +1806,7 @@ var SwapManager = class _SwapManager {
1756
1806
  };
1757
1807
  } catch (error) {
1758
1808
  logger.error("Failed to create WebSocket:", error);
1759
- this.enterPollingFallback(
1760
- new NetworkError("WebSocket connection failed")
1761
- );
1809
+ this.enterPollingFallback(new NetworkError("WebSocket connection failed"));
1762
1810
  }
1763
1811
  }
1764
1812
  /**
@@ -1793,11 +1841,8 @@ var SwapManager = class _SwapManager {
1793
1841
  * Schedule WebSocket reconnection with exponential backoff
1794
1842
  */
1795
1843
  scheduleReconnect() {
1796
- if (this.reconnectTimer || this.webSocketUnavailable || !this.hasWebSocketSupport())
1797
- return;
1798
- logger.log(
1799
- `Scheduling WebSocket reconnect in ${this.currentReconnectDelay}ms`
1800
- );
1844
+ if (this.reconnectTimer || this.webSocketUnavailable || !this.hasWebSocketSupport()) return;
1845
+ logger.log(`Scheduling WebSocket reconnect in ${this.currentReconnectDelay}ms`);
1801
1846
  this.reconnectTimer = setTimeout(() => {
1802
1847
  this.reconnectTimer = null;
1803
1848
  this.isReconnecting = false;
@@ -1812,8 +1857,7 @@ var SwapManager = class _SwapManager {
1812
1857
  * Subscribe to a specific swap ID on the WebSocket
1813
1858
  */
1814
1859
  subscribeToSwap(swapId) {
1815
- if (!this.websocket || this.websocket.readyState !== WebSocket.OPEN)
1816
- return;
1860
+ if (!this.websocket || this.websocket.readyState !== WebSocket.OPEN) return;
1817
1861
  this.websocket.send(
1818
1862
  JSON.stringify({
1819
1863
  op: "subscribe",
@@ -1836,9 +1880,7 @@ var SwapManager = class _SwapManager {
1836
1880
  if (msg.args[0].error) {
1837
1881
  logger.error(`Swap ${swapId} error:`, msg.args[0].error);
1838
1882
  const error = new Error(msg.args[0].error);
1839
- this.swapFailedListeners.forEach(
1840
- (listener) => listener(swap, error)
1841
- );
1883
+ this.swapFailedListeners.forEach((listener) => listener(swap, error));
1842
1884
  return;
1843
1885
  }
1844
1886
  const newStatus = msg.args[0].status;
@@ -1856,19 +1898,14 @@ var SwapManager = class _SwapManager {
1856
1898
  const oldStatus = swap.status;
1857
1899
  if (oldStatus === newStatus) return;
1858
1900
  swap.status = newStatus;
1859
- this.swapUpdateListeners.forEach(
1860
- (listener) => listener(swap, oldStatus)
1861
- );
1901
+ this.swapUpdateListeners.forEach((listener) => listener(swap, oldStatus));
1862
1902
  const subscribers = this.swapSubscriptions.get(swap.id);
1863
1903
  if (subscribers) {
1864
1904
  subscribers.forEach((callback) => {
1865
1905
  try {
1866
1906
  callback(swap, oldStatus);
1867
1907
  } catch (error) {
1868
- logger.error(
1869
- `Error in swap subscription callback for ${swap.id}:`,
1870
- error
1871
- );
1908
+ logger.error(`Error in swap subscription callback for ${swap.id}:`, error);
1872
1909
  }
1873
1910
  });
1874
1911
  }
@@ -1893,9 +1930,7 @@ var SwapManager = class _SwapManager {
1893
1930
  */
1894
1931
  async executeAutonomousAction(swap) {
1895
1932
  if (this.swapsInProgress.has(swap.id)) {
1896
- logger.log(
1897
- `Swap ${swap.id} is already being processed, skipping autonomous action`
1898
- );
1933
+ logger.log(`Swap ${swap.id} is already being processed, skipping autonomous action`);
1899
1934
  return;
1900
1935
  }
1901
1936
  try {
@@ -1910,9 +1945,7 @@ var SwapManager = class _SwapManager {
1910
1945
  if (isReverseClaimableStatus(swap.status)) {
1911
1946
  logger.log(`Auto-claiming reverse swap ${swap.id}`);
1912
1947
  await this.executeClaimAction(swap);
1913
- this.actionExecutedListeners.forEach(
1914
- (listener) => listener(swap, "claim")
1915
- );
1948
+ this.actionExecutedListeners.forEach((listener) => listener(swap, "claim"));
1916
1949
  }
1917
1950
  } else if (isPendingSubmarineSwap(swap)) {
1918
1951
  if (!swap.request?.invoice || swap.request.invoice.length === 0) {
@@ -1924,9 +1957,7 @@ var SwapManager = class _SwapManager {
1924
1957
  if (isSubmarineRefundableStatus(swap.status)) {
1925
1958
  logger.log(`Auto-refunding submarine swap ${swap.id}`);
1926
1959
  await this.executeRefundAction(swap);
1927
- this.actionExecutedListeners.forEach(
1928
- (listener) => listener(swap, "refund")
1929
- );
1960
+ this.actionExecutedListeners.forEach((listener) => listener(swap, "refund"));
1930
1961
  }
1931
1962
  } else if (isPendingChainSwap(swap)) {
1932
1963
  if (isChainClaimableStatus(swap.status)) {
@@ -1976,13 +2007,8 @@ var SwapManager = class _SwapManager {
1976
2007
  }
1977
2008
  }
1978
2009
  } catch (error) {
1979
- logger.error(
1980
- `Failed to execute autonomous action for swap ${swap.id}:`,
1981
- error
1982
- );
1983
- this.swapFailedListeners.forEach(
1984
- (listener) => listener(swap, error)
1985
- );
2010
+ logger.error(`Failed to execute autonomous action for swap ${swap.id}:`, error);
2011
+ this.swapFailedListeners.forEach((listener) => listener(swap, error));
1986
2012
  } finally {
1987
2013
  this.swapsInProgress.delete(swap.id);
1988
2014
  }
@@ -2083,9 +2109,7 @@ var SwapManager = class _SwapManager {
2083
2109
  logger.log(`Resuming chain refund for swap ${swap.id}`);
2084
2110
  await this.executeAutonomousAction(swap);
2085
2111
  } else if (isPendingChainSwap(swap) && swap.request.to === "ARK" && isChainSignableStatus(swap.status)) {
2086
- logger.log(
2087
- `Resuming server claim signing for swap ${swap.id}`
2088
- );
2112
+ logger.log(`Resuming server claim signing for swap ${swap.id}`);
2089
2113
  await this.executeAutonomousAction(swap);
2090
2114
  }
2091
2115
  } catch (error) {
@@ -2144,9 +2168,7 @@ var SwapManager = class _SwapManager {
2144
2168
  }
2145
2169
  async pollSingleSwap(swap) {
2146
2170
  try {
2147
- const statusResponse = await this.swapProvider.getSwapStatus(
2148
- swap.id
2149
- );
2171
+ const statusResponse = await this.swapProvider.getSwapStatus(swap.id);
2150
2172
  this.notFoundCounts.delete(swap.id);
2151
2173
  if (statusResponse.status !== swap.status) {
2152
2174
  await this.handleSwapStatusUpdate(swap, statusResponse.status);
@@ -2157,9 +2179,7 @@ var SwapManager = class _SwapManager {
2157
2179
  return;
2158
2180
  }
2159
2181
  if (error instanceof NetworkError && error.statusCode === 429) {
2160
- logger.warn(
2161
- `Rate-limited polling swap ${swap.id}, retrying in 2s`
2162
- );
2182
+ logger.warn(`Rate-limited polling swap ${swap.id}, retrying in 2s`);
2163
2183
  const existing = this.pollRetryTimers.get(swap.id);
2164
2184
  if (existing) clearTimeout(existing);
2165
2185
  this.pollRetryTimers.set(
@@ -2167,25 +2187,17 @@ var SwapManager = class _SwapManager {
2167
2187
  setTimeout(async () => {
2168
2188
  this.pollRetryTimers.delete(swap.id);
2169
2189
  try {
2170
- const retry = await this.swapProvider.getSwapStatus(
2171
- swap.id
2172
- );
2190
+ const retry = await this.swapProvider.getSwapStatus(swap.id);
2173
2191
  this.notFoundCounts.delete(swap.id);
2174
2192
  if (retry.status !== swap.status) {
2175
- await this.handleSwapStatusUpdate(
2176
- swap,
2177
- retry.status
2178
- );
2193
+ await this.handleSwapStatusUpdate(swap, retry.status);
2179
2194
  }
2180
2195
  } catch (retryError) {
2181
2196
  if (retryError instanceof SwapNotFoundError) {
2182
2197
  await this.handleSwapNotFound(swap);
2183
2198
  return;
2184
2199
  }
2185
- logger.error(
2186
- `Retry poll for swap ${swap.id} also failed:`,
2187
- retryError
2188
- );
2200
+ logger.error(`Retry poll for swap ${swap.id} also failed:`, retryError);
2189
2201
  }
2190
2202
  }, 2e3)
2191
2203
  );
@@ -2237,9 +2249,7 @@ var SwapManager = class _SwapManager {
2237
2249
  this.pollRetryTimers.delete(swap.id);
2238
2250
  }
2239
2251
  this.notFoundCounts.delete(swap.id);
2240
- this.swapUpdateListeners.forEach(
2241
- (listener) => listener(swap, oldStatus)
2242
- );
2252
+ this.swapUpdateListeners.forEach((listener) => listener(swap, oldStatus));
2243
2253
  const subscribers = this.swapSubscriptions.get(swap.id);
2244
2254
  if (subscribers) {
2245
2255
  subscribers.forEach((callback) => {
@@ -2304,9 +2314,7 @@ async function saveSwap(swap, saver) {
2304
2314
  if (saver.saveSubmarineSwap) {
2305
2315
  await saver.saveSubmarineSwap(swap);
2306
2316
  } else {
2307
- console.warn(
2308
- "No saveSubmarineSwap handler provided, swap not saved"
2309
- );
2317
+ console.warn("No saveSubmarineSwap handler provided, swap not saved");
2310
2318
  }
2311
2319
  } else if (isPendingChainSwap(swap)) {
2312
2320
  if (saver.saveChainSwap) {
@@ -2363,6 +2371,26 @@ function enrichSubmarineSwapInvoice(swap, invoice) {
2363
2371
  return swap;
2364
2372
  }
2365
2373
 
2374
+ // src/repositories/swap-repository.ts
2375
+ function hasImpossibleSwapsFilter(filter) {
2376
+ if (!filter) return false;
2377
+ 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;
2378
+ }
2379
+ function matchesCriterion(value, criterion) {
2380
+ if (criterion === void 0) return true;
2381
+ return Array.isArray(criterion) ? criterion.includes(value) : value === criterion;
2382
+ }
2383
+ function applySwapsFilter(swaps, filter) {
2384
+ return swaps.filter(
2385
+ (swap) => !!swap && matchesCriterion(swap.id, filter.id) && matchesCriterion(swap.status, filter.status) && matchesCriterion(swap.type, filter.type)
2386
+ );
2387
+ }
2388
+ function applyCreatedAtOrder(swaps, filter) {
2389
+ if (filter?.orderBy !== "createdAt") return swaps;
2390
+ const direction = filter.orderDirection === "asc" ? 1 : -1;
2391
+ return swaps.slice().sort((a, b) => (a.createdAt - b.createdAt) * direction);
2392
+ }
2393
+
2366
2394
  // src/repositories/IndexedDb/swap-repository.ts
2367
2395
  var import_sdk4 = require("@arkade-os/sdk");
2368
2396
  var DEFAULT_DB_NAME = "arkade-boltz-swap";
@@ -2378,6 +2406,10 @@ function initDatabase(db) {
2378
2406
  swapStore.createIndex("createdAt", "createdAt", { unique: false });
2379
2407
  }
2380
2408
  }
2409
+ function asArray(v) {
2410
+ if (v === void 0) return void 0;
2411
+ return Array.isArray(v) ? v : [v];
2412
+ }
2381
2413
  var IndexedDbSwapRepository = class {
2382
2414
  constructor(dbName = DEFAULT_DB_NAME) {
2383
2415
  this.dbName = dbName;
@@ -2392,10 +2424,7 @@ var IndexedDbSwapRepository = class {
2392
2424
  async saveSwap(swap) {
2393
2425
  const db = await this.getDB();
2394
2426
  return new Promise((resolve, reject) => {
2395
- const transaction = db.transaction(
2396
- [STORE_SWAPS_STATE],
2397
- "readwrite"
2398
- );
2427
+ const transaction = db.transaction([STORE_SWAPS_STATE], "readwrite");
2399
2428
  const store = transaction.objectStore(STORE_SWAPS_STATE);
2400
2429
  const request = store.put(swap);
2401
2430
  request.onsuccess = () => resolve();
@@ -2405,10 +2434,7 @@ var IndexedDbSwapRepository = class {
2405
2434
  async deleteSwap(id) {
2406
2435
  const db = await this.getDB();
2407
2436
  return new Promise((resolve, reject) => {
2408
- const transaction = db.transaction(
2409
- [STORE_SWAPS_STATE],
2410
- "readwrite"
2411
- );
2437
+ const transaction = db.transaction([STORE_SWAPS_STATE], "readwrite");
2412
2438
  const store = transaction.objectStore(STORE_SWAPS_STATE);
2413
2439
  const request = store.delete(id);
2414
2440
  request.onsuccess = () => resolve();
@@ -2421,10 +2447,7 @@ var IndexedDbSwapRepository = class {
2421
2447
  async clear() {
2422
2448
  const db = await this.getDB();
2423
2449
  return new Promise((resolve, reject) => {
2424
- const transaction = db.transaction(
2425
- [STORE_SWAPS_STATE],
2426
- "readwrite"
2427
- );
2450
+ const transaction = db.transaction([STORE_SWAPS_STATE], "readwrite");
2428
2451
  const store = transaction.objectStore(STORE_SWAPS_STATE);
2429
2452
  const request = store.clear();
2430
2453
  request.onsuccess = () => resolve();
@@ -2441,11 +2464,10 @@ var IndexedDbSwapRepository = class {
2441
2464
  request.onsuccess = () => resolve(request.result ?? []);
2442
2465
  })
2443
2466
  );
2444
- return Promise.all(requests).then(
2445
- (results) => results.flatMap((result) => result)
2446
- );
2467
+ return Promise.all(requests).then((results) => results.flatMap((result) => result));
2447
2468
  }
2448
2469
  async getAllSwapsFromStore(filter) {
2470
+ if (hasImpossibleSwapsFilter(filter)) return [];
2449
2471
  const db = await this.getDB();
2450
2472
  const store = db.transaction([STORE_SWAPS_STATE], "readonly").objectStore(STORE_SWAPS_STATE);
2451
2473
  if (!filter || Object.keys(filter).length === 0) {
@@ -2455,9 +2477,8 @@ var IndexedDbSwapRepository = class {
2455
2477
  request.onerror = () => reject(request.error);
2456
2478
  });
2457
2479
  }
2458
- const normalizedFilter = normalizeFilter(filter);
2459
- if (normalizedFilter.has("id")) {
2460
- const ids = normalizedFilter.get("id");
2480
+ const ids = asArray(filter.id);
2481
+ if (ids) {
2461
2482
  const swaps = await Promise.all(
2462
2483
  ids.map(
2463
2484
  (id) => new Promise((resolve, reject) => {
@@ -2467,34 +2488,17 @@ var IndexedDbSwapRepository = class {
2467
2488
  })
2468
2489
  )
2469
2490
  );
2470
- return this.sortIfNeeded(
2471
- this.applySwapsFilter(swaps, normalizedFilter),
2472
- filter
2473
- );
2491
+ return applyCreatedAtOrder(applySwapsFilter(swaps, filter), filter);
2474
2492
  }
2475
- if (normalizedFilter.has("type")) {
2476
- const types = normalizedFilter.get("type");
2477
- const swaps = await this.getSwapsByIndexValues(
2478
- store,
2479
- "type",
2480
- types
2481
- );
2482
- return this.sortIfNeeded(
2483
- this.applySwapsFilter(swaps, normalizedFilter),
2484
- filter
2485
- );
2493
+ const types = asArray(filter.type);
2494
+ if (types) {
2495
+ const swaps = await this.getSwapsByIndexValues(store, "type", types);
2496
+ return applyCreatedAtOrder(applySwapsFilter(swaps, filter), filter);
2486
2497
  }
2487
- if (normalizedFilter.has("status")) {
2488
- const ids = normalizedFilter.get("status");
2489
- const swaps = await this.getSwapsByIndexValues(
2490
- store,
2491
- "status",
2492
- ids
2493
- );
2494
- return this.sortIfNeeded(
2495
- this.applySwapsFilter(swaps, normalizedFilter),
2496
- filter
2497
- );
2498
+ const statuses = asArray(filter.status);
2499
+ if (statuses) {
2500
+ const swaps = await this.getSwapsByIndexValues(store, "status", statuses);
2501
+ return applyCreatedAtOrder(applySwapsFilter(swaps, filter), filter);
2498
2502
  }
2499
2503
  if (filter.orderBy === "createdAt") {
2500
2504
  return this.getAllSwapsByCreatedAt(store, filter.orderDirection);
@@ -2504,22 +2508,7 @@ var IndexedDbSwapRepository = class {
2504
2508
  request.onsuccess = () => resolve(request.result ?? []);
2505
2509
  request.onerror = () => reject(request.error);
2506
2510
  });
2507
- return this.sortIfNeeded(
2508
- this.applySwapsFilter(allSwaps, normalizedFilter),
2509
- filter
2510
- );
2511
- }
2512
- applySwapsFilter(swaps, filter) {
2513
- return swaps.filter((swap) => {
2514
- if (swap === void 0) return false;
2515
- if (filter.has("id") && !filter.get("id")?.includes(swap.id))
2516
- return false;
2517
- if (filter.has("status") && !filter.get("status")?.includes(swap.status))
2518
- return false;
2519
- if (filter.has("type") && !filter.get("type")?.includes(swap.type))
2520
- return false;
2521
- return true;
2522
- });
2511
+ return applyCreatedAtOrder(applySwapsFilter(allSwaps, filter), filter);
2523
2512
  }
2524
2513
  async getAllSwapsByCreatedAt(store, orderDirection) {
2525
2514
  const index = store.index("createdAt");
@@ -2539,30 +2528,12 @@ var IndexedDbSwapRepository = class {
2539
2528
  };
2540
2529
  });
2541
2530
  }
2542
- sortIfNeeded(swaps, filter) {
2543
- if (filter?.orderBy !== "createdAt") return swaps;
2544
- const direction = filter.orderDirection === "asc" ? 1 : -1;
2545
- return swaps.slice().sort((a, b) => (a.createdAt - b.createdAt) * direction);
2546
- }
2547
2531
  async [Symbol.asyncDispose]() {
2548
2532
  if (!this.db) return;
2549
2533
  await (0, import_sdk4.closeDatabase)(this.dbName);
2550
2534
  this.db = null;
2551
2535
  }
2552
2536
  };
2553
- var FILTER_FIELDS = ["id", "status", "type"];
2554
- function normalizeFilter(filter) {
2555
- const res = /* @__PURE__ */ new Map();
2556
- FILTER_FIELDS.forEach((current) => {
2557
- if (!filter?.[current]) return;
2558
- if (Array.isArray(filter[current])) {
2559
- res.set(current, filter[current]);
2560
- } else {
2561
- res.set(current, [filter[current]]);
2562
- }
2563
- });
2564
- return res;
2565
- }
2566
2537
 
2567
2538
  // src/utils/identity.ts
2568
2539
  var import_sdk5 = require("@arkade-os/sdk");
@@ -2574,13 +2545,8 @@ function claimVHTLCIdentity(identity, preimage) {
2574
2545
  let signedTx = await identity.sign(cpy, inputIndexes);
2575
2546
  signedTx = import_sdk5.Transaction.fromPSBT(signedTx.toPSBT());
2576
2547
  if (preimage) {
2577
- for (const inputIndex of inputIndexes || Array.from(
2578
- { length: signedTx.inputsLength },
2579
- (_, i) => i
2580
- )) {
2581
- (0, import_sdk5.setArkPsbtField)(signedTx, inputIndex, import_sdk5.ConditionWitness, [
2582
- preimage
2583
- ]);
2548
+ for (const inputIndex of inputIndexes || Array.from({ length: signedTx.inputsLength }, (_, i) => i)) {
2549
+ (0, import_sdk5.setArkPsbtField)(signedTx, inputIndex, import_sdk5.ConditionWitness, [preimage]);
2584
2550
  }
2585
2551
  }
2586
2552
  return signedTx;
@@ -2635,17 +2601,13 @@ function createVHTLCBatchHandler(intentId, vhtlc, arkProvider, identity, session
2635
2601
  if (!sweepTapTreeRoot) {
2636
2602
  throw new Error("Sweep tap tree root not set");
2637
2603
  }
2638
- const xOnlyPublicKeys = event.cosignersPublicKeys.map(
2639
- (k) => k.slice(2)
2640
- );
2604
+ const xOnlyPublicKeys = event.cosignersPublicKeys.map((k) => k.slice(2));
2641
2605
  const signerPublicKey = await session.getPublicKey();
2642
2606
  const xonlySignerPublicKey = signerPublicKey.subarray(1);
2643
2607
  if (!xOnlyPublicKeys.includes(import_base7.hex.encode(xonlySignerPublicKey))) {
2644
2608
  return { skip: true };
2645
2609
  }
2646
- const commitmentTx = import_sdk6.Transaction.fromPSBT(
2647
- import_base7.base64.decode(event.unsignedCommitmentTx)
2648
- );
2610
+ const commitmentTx = import_sdk6.Transaction.fromPSBT(import_base7.base64.decode(event.unsignedCommitmentTx));
2649
2611
  (0, import_sdk6.validateVtxoTxGraph)(vtxoTree, commitmentTx, sweepTapTreeRoot);
2650
2612
  const sharedOutput = commitmentTx.getOutput(0);
2651
2613
  if (!sharedOutput?.amount) {
@@ -2661,18 +2623,11 @@ function createVHTLCBatchHandler(intentId, vhtlc, arkProvider, identity, session
2661
2623
  if (!session) {
2662
2624
  return { fullySigned: true };
2663
2625
  }
2664
- const { hasAllNonces } = await session.aggregatedNonces(
2665
- event.txid,
2666
- event.nonces
2667
- );
2626
+ const { hasAllNonces } = await session.aggregatedNonces(event.txid, event.nonces);
2668
2627
  if (!hasAllNonces) return { fullySigned: false };
2669
2628
  const signatures = await session.sign();
2670
2629
  const pubkey = import_base7.hex.encode(await session.getPublicKey());
2671
- await arkProvider.submitTreeSignatures(
2672
- event.id,
2673
- pubkey,
2674
- signatures
2675
- );
2630
+ await arkProvider.submitTreeSignatures(event.id, pubkey, signatures);
2676
2631
  return { fullySigned: true };
2677
2632
  },
2678
2633
  onBatchFinalization: async (event, _, connectorTree) => {
@@ -2680,9 +2635,7 @@ function createVHTLCBatchHandler(intentId, vhtlc, arkProvider, identity, session
2680
2635
  return;
2681
2636
  }
2682
2637
  if (!connectorTree) {
2683
- throw new Error(
2684
- "BatchFinalizationEvent: expected connector tree to be defined"
2685
- );
2638
+ throw new Error("BatchFinalizationEvent: expected connector tree to be defined");
2686
2639
  }
2687
2640
  (0, import_sdk6.validateConnectorsTxGraph)(event.commitmentTx, connectorTree);
2688
2641
  const connectors = connectorTree.leaves();
@@ -2697,9 +2650,7 @@ function createVHTLCBatchHandler(intentId, vhtlc, arkProvider, identity, session
2697
2650
  connectors[connectorIndex]
2698
2651
  );
2699
2652
  const signedForfeitTx = await identity.sign(forfeitTx);
2700
- await arkProvider.submitSignedForfeitTxs([
2701
- import_base7.base64.encode(signedForfeitTx.toPSBT())
2702
- ]);
2653
+ await arkProvider.submitSignedForfeitTxs([import_base7.base64.encode(signedForfeitTx.toPSBT())]);
2703
2654
  }
2704
2655
  };
2705
2656
  }
@@ -2759,36 +2710,22 @@ var createVHTLCScript = (args) => {
2759
2710
  serverPubkey,
2760
2711
  timeoutBlockHeights: vhtlcTimeouts
2761
2712
  } = args;
2762
- const receiverXOnlyPublicKey = normalizeToXOnlyKey(
2763
- import_base8.hex.decode(receiverPubkey),
2764
- "receiver"
2765
- );
2766
- const senderXOnlyPublicKey = normalizeToXOnlyKey(
2767
- import_base8.hex.decode(senderPubkey),
2768
- "sender"
2769
- );
2770
- const serverXOnlyPublicKey = normalizeToXOnlyKey(
2771
- import_base8.hex.decode(serverPubkey),
2772
- "server"
2773
- );
2713
+ const receiverXOnlyPublicKey = normalizeToXOnlyKey(import_base8.hex.decode(receiverPubkey), "receiver");
2714
+ const senderXOnlyPublicKey = normalizeToXOnlyKey(import_base8.hex.decode(senderPubkey), "sender");
2715
+ const serverXOnlyPublicKey = normalizeToXOnlyKey(import_base8.hex.decode(serverPubkey), "server");
2774
2716
  const vhtlcScript = new import_sdk7.VHTLC.Script({
2775
2717
  preimageHash: (0, import_legacy.ripemd160)(preimageHash),
2776
2718
  sender: senderXOnlyPublicKey,
2777
2719
  receiver: receiverXOnlyPublicKey,
2778
2720
  server: serverXOnlyPublicKey,
2779
2721
  refundLocktime: BigInt(vhtlcTimeouts.refund),
2780
- unilateralClaimDelay: toBip68RelativeTimelock(
2781
- vhtlcTimeouts.unilateralClaim
2782
- ),
2783
- unilateralRefundDelay: toBip68RelativeTimelock(
2784
- vhtlcTimeouts.unilateralRefund
2785
- ),
2722
+ unilateralClaimDelay: toBip68RelativeTimelock(vhtlcTimeouts.unilateralClaim),
2723
+ unilateralRefundDelay: toBip68RelativeTimelock(vhtlcTimeouts.unilateralRefund),
2786
2724
  unilateralRefundWithoutReceiverDelay: toBip68RelativeTimelock(
2787
2725
  vhtlcTimeouts.unilateralRefundWithoutReceiver
2788
2726
  )
2789
2727
  });
2790
- if (!vhtlcScript.claimScript)
2791
- throw new Error("Failed to create VHTLC script");
2728
+ if (!vhtlcScript.claimScript) throw new Error("Failed to create VHTLC script");
2792
2729
  const hrp = network === "bitcoin" ? "ark" : "tark";
2793
2730
  const vhtlcAddress = vhtlcScript.address(hrp, serverXOnlyPublicKey).encode();
2794
2731
  return { vhtlcScript, vhtlcAddress };
@@ -2822,11 +2759,7 @@ var joinBatch = async (arkProvider, identity, input, output, {
2822
2759
  unknown: [import_sdk7.VtxoTaprootTree.encode(input.tapTree)],
2823
2760
  sequence: (0, import_sdk7.getSequence)(input.tapLeafScript)
2824
2761
  };
2825
- const registerIntent = import_sdk7.Intent.create(
2826
- intentMessage,
2827
- [intentInput],
2828
- [output]
2829
- );
2762
+ const registerIntent = import_sdk7.Intent.create(intentMessage, [intentInput], [output]);
2830
2763
  const deleteIntent = import_sdk7.Intent.create(deleteMessage, [intentInput]);
2831
2764
  const [signedRegisterIntent, signedDeleteIntent] = await Promise.all([
2832
2765
  identity.sign(registerIntent),
@@ -2850,14 +2783,8 @@ var joinBatch = async (arkProvider, identity, input, output, {
2850
2783
  normalizeToXOnlyKey(forfeitPubkey, "forfeit"),
2851
2784
  isRecoverable2 ? void 0 : import_btc_signer4.OutScript.encode(decodedAddress)
2852
2785
  );
2853
- const topics = [
2854
- import_base8.hex.encode(signerPublicKey),
2855
- `${input.txid}:${input.vout}`
2856
- ];
2857
- const eventStream = arkProvider.getEventStream(
2858
- abortController.signal,
2859
- topics
2860
- );
2786
+ const topics = [import_base8.hex.encode(signerPublicKey), `${input.txid}:${input.vout}`];
2787
+ const eventStream = arkProvider.getEventStream(abortController.signal, topics);
2861
2788
  const commitmentTxid = await import_sdk7.Batch.join(eventStream, handler, {
2862
2789
  abortController
2863
2790
  });
@@ -2878,14 +2805,8 @@ var joinBatch = async (arkProvider, identity, input, output, {
2878
2805
  };
2879
2806
  var claimVHTLCwithOffchainTx = async (identity, vhtlcScript, serverXOnlyPublicKey, input, output, arkInfo, arkProvider) => {
2880
2807
  const rawCheckpointTapscript = import_base8.hex.decode(arkInfo.checkpointTapscript);
2881
- const serverUnrollScript = import_sdk7.CSVMultisigTapscript.decode(
2882
- rawCheckpointTapscript
2883
- );
2884
- const { arkTx, checkpoints } = (0, import_sdk7.buildOffchainTx)(
2885
- [input],
2886
- [output],
2887
- serverUnrollScript
2888
- );
2808
+ const serverUnrollScript = import_sdk7.CSVMultisigTapscript.decode(rawCheckpointTapscript);
2809
+ const { arkTx, checkpoints } = (0, import_sdk7.buildOffchainTx)([input], [output], serverUnrollScript);
2889
2810
  const signedArkTx = await identity.sign(arkTx);
2890
2811
  const { arkTxid, finalArkTx, signedCheckpointTxs } = await arkProvider.submitTx(
2891
2812
  import_base8.base64.encode(signedArkTx.toPSBT()),
@@ -2893,9 +2814,7 @@ var claimVHTLCwithOffchainTx = async (identity, vhtlcScript, serverXOnlyPublicKe
2893
2814
  );
2894
2815
  const finalTx = import_sdk7.Transaction.fromPSBT(import_base8.base64.decode(finalArkTx));
2895
2816
  const serverPubkeyHex = import_base8.hex.encode(serverXOnlyPublicKey);
2896
- const claimLeafHash = (0, import_payment3.tapLeafHash)(
2897
- scriptFromTapLeafScript(vhtlcScript.claim())
2898
- );
2817
+ const claimLeafHash = (0, import_payment3.tapLeafHash)(scriptFromTapLeafScript(vhtlcScript.claim()));
2899
2818
  for (let i = 0; i < finalTx.inputsLength; i++) {
2900
2819
  if (!verifySignatures(finalTx, i, [serverPubkeyHex], claimLeafHash)) {
2901
2820
  throw new Error("Invalid final Ark transaction");
@@ -2905,13 +2824,9 @@ var claimVHTLCwithOffchainTx = async (identity, vhtlcScript, serverXOnlyPublicKe
2905
2824
  signedCheckpointTxs.map(async (c, idx) => {
2906
2825
  const tx = import_sdk7.Transaction.fromPSBT(import_base8.base64.decode(c));
2907
2826
  const checkpointLeaf = checkpoints[idx].getInput(0).tapLeafScript[0];
2908
- const cpLeafHash = (0, import_payment3.tapLeafHash)(
2909
- scriptFromTapLeafScript(checkpointLeaf)
2910
- );
2827
+ const cpLeafHash = (0, import_payment3.tapLeafHash)(scriptFromTapLeafScript(checkpointLeaf));
2911
2828
  if (!verifySignatures(tx, 0, [serverPubkeyHex], cpLeafHash)) {
2912
- throw new Error(
2913
- "Invalid server signature in checkpoint transaction"
2914
- );
2829
+ throw new Error("Invalid server signature in checkpoint transaction");
2915
2830
  }
2916
2831
  const signedCheckpoint = await identity.sign(tx, [0]);
2917
2832
  return import_base8.base64.encode(signedCheckpoint.toPSBT());
@@ -2921,61 +2836,37 @@ var claimVHTLCwithOffchainTx = async (identity, vhtlcScript, serverXOnlyPublicKe
2921
2836
  };
2922
2837
  var refundVHTLCwithOffchainTx = async (swapId, identity, arkProvider, boltzXOnlyPublicKey, ourXOnlyPublicKey, serverXOnlyPublicKey, input, output, arkInfo, refundFunc) => {
2923
2838
  const rawCheckpointTapscript = import_base8.hex.decode(arkInfo.checkpointTapscript);
2924
- const serverUnrollScript = import_sdk7.CSVMultisigTapscript.decode(
2925
- rawCheckpointTapscript
2839
+ const serverUnrollScript = import_sdk7.CSVMultisigTapscript.decode(rawCheckpointTapscript);
2840
+ const { arkTx: unsignedRefundTx, checkpoints: checkpointPtxs } = (0, import_sdk7.buildOffchainTx)(
2841
+ [input],
2842
+ [output],
2843
+ serverUnrollScript
2926
2844
  );
2927
- const { arkTx: unsignedRefundTx, checkpoints: checkpointPtxs } = (0, import_sdk7.buildOffchainTx)([input], [output], serverUnrollScript);
2928
2845
  if (checkpointPtxs.length !== 1)
2929
- throw new Error(
2930
- `Expected one checkpoint transaction, got ${checkpointPtxs.length}`
2931
- );
2846
+ throw new Error(`Expected one checkpoint transaction, got ${checkpointPtxs.length}`);
2932
2847
  const unsignedCheckpointTx = checkpointPtxs[0];
2933
2848
  let boltzSignedRefundTx;
2934
2849
  let boltzSignedCheckpointTx;
2935
2850
  try {
2936
- const result = await refundFunc(
2937
- swapId,
2938
- unsignedRefundTx,
2939
- unsignedCheckpointTx
2940
- );
2851
+ const result = await refundFunc(swapId, unsignedRefundTx, unsignedCheckpointTx);
2941
2852
  boltzSignedRefundTx = result.transaction;
2942
2853
  boltzSignedCheckpointTx = result.checkpoint;
2943
2854
  } catch (error) {
2944
- throw new BoltzRefundError(
2945
- `Boltz rejected refund for swap ${swapId}`,
2946
- error
2947
- );
2855
+ throw new BoltzRefundError(`Boltz rejected refund for swap ${swapId}`, error);
2948
2856
  }
2949
2857
  const boltzXOnlyPublicKeyHex = import_base8.hex.encode(boltzXOnlyPublicKey);
2950
- const refundLeafHash = (0, import_payment3.tapLeafHash)(
2951
- scriptFromTapLeafScript(input.tapLeafScript)
2952
- );
2953
- if (!verifySignatures(
2954
- boltzSignedRefundTx,
2955
- 0,
2956
- [boltzXOnlyPublicKeyHex],
2957
- refundLeafHash
2958
- )) {
2858
+ const refundLeafHash = (0, import_payment3.tapLeafHash)(scriptFromTapLeafScript(input.tapLeafScript));
2859
+ if (!verifySignatures(boltzSignedRefundTx, 0, [boltzXOnlyPublicKeyHex], refundLeafHash)) {
2959
2860
  throw new Error("Invalid Boltz signature in refund transaction");
2960
2861
  }
2961
2862
  const checkpointLeaf = unsignedCheckpointTx.getInput(0).tapLeafScript[0];
2962
- const checkpointLeafHash = (0, import_payment3.tapLeafHash)(
2963
- scriptFromTapLeafScript(checkpointLeaf)
2964
- );
2965
- if (!verifySignatures(
2966
- boltzSignedCheckpointTx,
2967
- 0,
2968
- [boltzXOnlyPublicKeyHex],
2969
- checkpointLeafHash
2970
- )) {
2863
+ const checkpointLeafHash = (0, import_payment3.tapLeafHash)(scriptFromTapLeafScript(checkpointLeaf));
2864
+ if (!verifySignatures(boltzSignedCheckpointTx, 0, [boltzXOnlyPublicKeyHex], checkpointLeafHash)) {
2971
2865
  throw new Error("Invalid Boltz signature in checkpoint transaction");
2972
2866
  }
2973
2867
  const signedRefundTx = await identity.sign(unsignedRefundTx);
2974
2868
  const signedCheckpointTx = await identity.sign(unsignedCheckpointTx);
2975
- const combinedSignedRefundTx = (0, import_sdk7.combineTapscriptSigs)(
2976
- boltzSignedRefundTx,
2977
- signedRefundTx
2978
- );
2869
+ const combinedSignedRefundTx = (0, import_sdk7.combineTapscriptSigs)(boltzSignedRefundTx, signedRefundTx);
2979
2870
  const combinedSignedCheckpointTx = (0, import_sdk7.combineTapscriptSigs)(
2980
2871
  boltzSignedCheckpointTx,
2981
2872
  signedCheckpointTx
@@ -2999,25 +2890,16 @@ var refundVHTLCwithOffchainTx = async (swapId, identity, arkProvider, boltzXOnly
2999
2890
  `Expected one signed checkpoint transaction, got ${signedCheckpointTxs.length}`
3000
2891
  );
3001
2892
  }
3002
- const serverSignedCheckpointTx = import_sdk7.Transaction.fromPSBT(
3003
- import_base8.base64.decode(signedCheckpointTxs[0])
3004
- );
2893
+ const serverSignedCheckpointTx = import_sdk7.Transaction.fromPSBT(import_base8.base64.decode(signedCheckpointTxs[0]));
3005
2894
  const serverPubkeyHex = import_base8.hex.encode(serverXOnlyPublicKey);
3006
- if (!verifySignatures(
3007
- serverSignedCheckpointTx,
3008
- 0,
3009
- [serverPubkeyHex],
3010
- checkpointLeafHash
3011
- )) {
2895
+ if (!verifySignatures(serverSignedCheckpointTx, 0, [serverPubkeyHex], checkpointLeafHash)) {
3012
2896
  throw new Error("Invalid server signature in checkpoint transaction");
3013
2897
  }
3014
2898
  const finalCheckpointTx = (0, import_sdk7.combineTapscriptSigs)(
3015
2899
  combinedSignedCheckpointTx,
3016
2900
  serverSignedCheckpointTx
3017
2901
  );
3018
- await arkProvider.finalizeTx(arkTxid, [
3019
- import_base8.base64.encode(finalCheckpointTx.toPSBT())
3020
- ]);
2902
+ await arkProvider.finalizeTx(arkTxid, [import_base8.base64.encode(finalCheckpointTx.toPSBT())]);
3021
2903
  };
3022
2904
  function scriptFromTapLeafScript(leaf) {
3023
2905
  return leaf[1].subarray(0, leaf[1].length - 1);
@@ -3025,21 +2907,21 @@ function scriptFromTapLeafScript(leaf) {
3025
2907
 
3026
2908
  // src/arkade-swaps.ts
3027
2909
  var dedupeVtxos = (vtxos) => [
3028
- ...new Map(
3029
- vtxos.map((vtxo) => [`${vtxo.txid}:${vtxo.vout}`, vtxo])
3030
- ).values()
2910
+ ...new Map(vtxos.map((vtxo) => [`${vtxo.txid}:${vtxo.vout}`, vtxo])).values()
3031
2911
  ];
3032
2912
  var hasNonEmptyString = (value) => typeof value === "string" && value.length > 0;
3033
2913
  var canRecoverViaBoltz3of3 = (refundableVtxos, swap) => {
3034
2914
  const hasRequiredSwapMetadata = hasNonEmptyString(swap.id) && hasNonEmptyString(swap.request.refundPublicKey) && hasNonEmptyString(swap.response.address) && hasNonEmptyString(swap.response.claimPublicKey) && !!swap.response.timeoutBlockHeights;
3035
2915
  if (!hasRequiredSwapMetadata) return false;
3036
- return refundableVtxos.some(
3037
- (vtxo) => !vtxo.isSpent && !(0, import_sdk8.isRecoverable)(vtxo)
3038
- );
2916
+ return refundableVtxos.some((vtxo) => !vtxo.isSpent && !(0, import_sdk8.isRecoverable)(vtxo));
3039
2917
  };
3040
2918
  var isSubmarineRefundLocktimeReached = (refundTimestamp) => Math.floor(Date.now() / 1e3) >= refundTimestamp;
3041
2919
  var CLAIM_VTXO_RETRY_ATTEMPTS = 3;
3042
2920
  var CLAIM_VTXO_RETRY_DELAY_MS = 500;
2921
+ var quoteOptionsForSwap = (swap) => {
2922
+ const amount = swap.response?.claimDetails?.amount;
2923
+ return typeof amount === "number" ? { minAcceptableAmount: amount } : void 0;
2924
+ };
3043
2925
  var ArkadeSwaps = class _ArkadeSwaps {
3044
2926
  /** The Arkade wallet instance used for signing and address generation. */
3045
2927
  wallet;
@@ -3075,10 +2957,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
3075
2957
  return new _ArkadeSwaps(config);
3076
2958
  }
3077
2959
  const arkProvider = config.arkProvider ?? config.wallet.arkProvider;
3078
- if (!arkProvider)
3079
- throw new Error(
3080
- "Ark provider is required either in wallet or config."
3081
- );
2960
+ if (!arkProvider) throw new Error("Ark provider is required either in wallet or config.");
3082
2961
  const arkInfo = await arkProvider.getInfo();
3083
2962
  const network = arkInfo.network;
3084
2963
  const swapProvider = new BoltzSwapProvider({ network });
@@ -3089,16 +2968,11 @@ var ArkadeSwaps = class _ArkadeSwaps {
3089
2968
  if (!config.swapProvider) throw new Error("Swap provider is required.");
3090
2969
  this.wallet = config.wallet;
3091
2970
  const arkProvider = config.arkProvider ?? config.wallet.arkProvider;
3092
- if (!arkProvider)
3093
- throw new Error(
3094
- "Ark provider is required either in wallet or config."
3095
- );
2971
+ if (!arkProvider) throw new Error("Ark provider is required either in wallet or config.");
3096
2972
  this.arkProvider = arkProvider;
3097
2973
  const indexerProvider = config.indexerProvider ?? config.wallet.indexerProvider;
3098
2974
  if (!indexerProvider)
3099
- throw new Error(
3100
- "Indexer provider is required either in wallet or config."
3101
- );
2975
+ throw new Error("Indexer provider is required either in wallet or config.");
3102
2976
  this.indexerProvider = indexerProvider;
3103
2977
  this.swapProvider = config.swapProvider;
3104
2978
  if (config.swapRepository) {
@@ -3109,10 +2983,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
3109
2983
  if (config.swapManager !== false) {
3110
2984
  const swapManagerConfig = !config.swapManager || config.swapManager === true ? {} : config.swapManager;
3111
2985
  const shouldAutostart = swapManagerConfig.autoStart ?? true;
3112
- this.swapManager = new SwapManager(
3113
- this.swapProvider,
3114
- swapManagerConfig
3115
- );
2986
+ this.swapManager = new SwapManager(this.swapProvider, swapManagerConfig);
3116
2987
  this.swapManager.setCallbacks({
3117
2988
  claim: async (swap) => {
3118
2989
  await this.claimVHTLC(swap);
@@ -3260,19 +3131,15 @@ var ArkadeSwaps = class _ArkadeSwaps {
3260
3131
  * @throws {SwapError} If amount is <= 0 or key retrieval fails.
3261
3132
  */
3262
3133
  async createReverseSwap(args) {
3263
- if (args.amount <= 0)
3264
- throw new SwapError({ message: "Amount must be greater than 0" });
3265
- const claimPublicKey = import_base9.hex.encode(
3266
- await this.wallet.identity.compressedPublicKey()
3267
- );
3134
+ if (args.amount <= 0) throw new SwapError({ message: "Amount must be greater than 0" });
3135
+ const claimPublicKey = import_base9.hex.encode(await this.wallet.identity.compressedPublicKey());
3268
3136
  if (!claimPublicKey)
3269
3137
  throw new SwapError({
3270
3138
  message: "Failed to get claim public key from wallet"
3271
3139
  });
3272
3140
  const preimage = (0, import_utils3.randomBytes)(32);
3273
3141
  const preimageHash = import_base9.hex.encode((0, import_sha23.sha256)(preimage));
3274
- if (!preimageHash)
3275
- throw new SwapError({ message: "Failed to get preimage hash" });
3142
+ if (!preimageHash) throw new SwapError({ message: "Failed to get preimage hash" });
3276
3143
  const swapRequest = {
3277
3144
  invoiceAmount: args.amount,
3278
3145
  claimPublicKey,
@@ -3302,18 +3169,14 @@ var ArkadeSwaps = class _ArkadeSwaps {
3302
3169
  */
3303
3170
  async claimVHTLC(pendingSwap) {
3304
3171
  if (!pendingSwap.preimage)
3305
- throw new Error(
3306
- `Swap ${pendingSwap.id}: preimage is required to claim VHTLC`
3307
- );
3172
+ throw new Error(`Swap ${pendingSwap.id}: preimage is required to claim VHTLC`);
3308
3173
  const {
3309
3174
  refundPublicKey,
3310
3175
  lockupAddress,
3311
3176
  timeoutBlockHeights: vhtlcTimeouts
3312
3177
  } = pendingSwap.response;
3313
3178
  if (!refundPublicKey || !lockupAddress || !vhtlcTimeouts)
3314
- throw new Error(
3315
- `Swap ${pendingSwap.id}: incomplete reverse swap response`
3316
- );
3179
+ throw new Error(`Swap ${pendingSwap.id}: incomplete reverse swap response`);
3317
3180
  const preimage = import_base9.hex.decode(pendingSwap.preimage);
3318
3181
  const arkInfo = await this.arkProvider.getInfo();
3319
3182
  const address = await this.wallet.getAddress();
@@ -3358,15 +3221,11 @@ var ArkadeSwaps = class _ArkadeSwaps {
3358
3221
  break;
3359
3222
  }
3360
3223
  if (attempt < CLAIM_VTXO_RETRY_ATTEMPTS) {
3361
- await new Promise(
3362
- (resolve) => setTimeout(resolve, CLAIM_VTXO_RETRY_DELAY_MS)
3363
- );
3224
+ await new Promise((resolve) => setTimeout(resolve, CLAIM_VTXO_RETRY_DELAY_MS));
3364
3225
  }
3365
3226
  }
3366
3227
  if (!vtxo) {
3367
- throw new Error(
3368
- `Swap ${pendingSwap.id}: no spendable virtual coins found`
3369
- );
3228
+ throw new Error(`Swap ${pendingSwap.id}: no spendable virtual coins found`);
3370
3229
  }
3371
3230
  if (vtxo.isSpent) {
3372
3231
  throw new Error(`Swap ${pendingSwap.id}: VHTLC is already spent`);
@@ -3380,10 +3239,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
3380
3239
  amount: BigInt(vtxo.value),
3381
3240
  script: import_sdk8.ArkAddress.decode(address).pkScript
3382
3241
  };
3383
- const vhtlcIdentity = claimVHTLCIdentity(
3384
- this.wallet.identity,
3385
- preimage
3386
- );
3242
+ const vhtlcIdentity = claimVHTLCIdentity(this.wallet.identity, preimage);
3387
3243
  let finalStatus;
3388
3244
  if ((0, import_sdk8.isRecoverable)(vtxo)) {
3389
3245
  await this.joinBatch(vhtlcIdentity, input, output, arkInfo);
@@ -3502,9 +3358,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
3502
3358
  async sendLightningPayment(args) {
3503
3359
  const pendingSwap = await this.createSubmarineSwap(args);
3504
3360
  if (!pendingSwap.response.address)
3505
- throw new Error(
3506
- `Swap ${pendingSwap.id}: missing address in submarine swap response`
3507
- );
3361
+ throw new Error(`Swap ${pendingSwap.id}: missing address in submarine swap response`);
3508
3362
  await this.savePendingSubmarineSwap(pendingSwap);
3509
3363
  const txid = await this.wallet.send({
3510
3364
  address: pendingSwap.response.address,
@@ -3537,9 +3391,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
3537
3391
  * @throws {SwapError} If invoice is missing or key retrieval fails.
3538
3392
  */
3539
3393
  async createSubmarineSwap(args) {
3540
- const refundPublicKey = import_base9.hex.encode(
3541
- await this.wallet.identity.compressedPublicKey()
3542
- );
3394
+ const refundPublicKey = import_base9.hex.encode(await this.wallet.identity.compressedPublicKey());
3543
3395
  if (!refundPublicKey)
3544
3396
  throw new SwapError({
3545
3397
  message: "Failed to get refund public key from wallet"
@@ -3577,9 +3429,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
3577
3429
  async buildSubmarineVHTLCContext(swap, arkInfo) {
3578
3430
  const preimageHash = swap.request.invoice ? getInvoicePaymentHash(swap.request.invoice) : swap.preimageHash;
3579
3431
  if (!preimageHash)
3580
- throw new Error(
3581
- `Swap ${swap.id}: preimage hash is required to refund VHTLC`
3582
- );
3432
+ throw new Error(`Swap ${swap.id}: preimage hash is required to refund VHTLC`);
3583
3433
  const resolvedArkInfo = arkInfo ?? await this.arkProvider.getInfo();
3584
3434
  const ourXOnlyPublicKey = normalizeToXOnlyKey(
3585
3435
  await this.wallet.identity.xOnlyPublicKey(),
@@ -3593,9 +3443,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
3593
3443
  );
3594
3444
  const { claimPublicKey, timeoutBlockHeights: vhtlcTimeouts } = swap.response;
3595
3445
  if (!claimPublicKey || !vhtlcTimeouts)
3596
- throw new Error(
3597
- `Swap ${swap.id}: incomplete submarine swap response`
3598
- );
3446
+ throw new Error(`Swap ${swap.id}: incomplete submarine swap response`);
3599
3447
  const boltzXOnlyPublicKey = normalizeToXOnlyKey(
3600
3448
  import_base9.hex.decode(claimPublicKey),
3601
3449
  "boltz",
@@ -3610,9 +3458,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
3610
3458
  timeoutBlockHeights: vhtlcTimeouts
3611
3459
  });
3612
3460
  if (!vhtlcScript.claimScript)
3613
- throw new Error(
3614
- `Swap ${swap.id}: failed to create VHTLC script for submarine swap`
3615
- );
3461
+ throw new Error(`Swap ${swap.id}: failed to create VHTLC script for submarine swap`);
3616
3462
  if (vhtlcAddress !== swap.response.address)
3617
3463
  throw new Error(
3618
3464
  `VHTLC address mismatch for swap ${swap.id}: expected ${swap.response.address}, got ${vhtlcAddress}`
@@ -3651,10 +3497,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
3651
3497
  recoverableOnly: true
3652
3498
  })
3653
3499
  ]);
3654
- const refundableVtxos = dedupeVtxos([
3655
- ...spendableResult.vtxos,
3656
- ...recoverableResult.vtxos
3657
- ]);
3500
+ const refundableVtxos = dedupeVtxos([...spendableResult.vtxos, ...recoverableResult.vtxos]);
3658
3501
  let diagnostic;
3659
3502
  if (refundableVtxos.length === 0) {
3660
3503
  const { vtxos: allVtxos } = await this.indexerProvider.getVtxos({
@@ -3674,13 +3517,8 @@ var ArkadeSwaps = class _ArkadeSwaps {
3674
3517
  submarineRecoveryInfoFromLookup(swap, lookup) {
3675
3518
  const { refundableVtxos, diagnostic, vhtlcTimeouts } = lookup;
3676
3519
  if (refundableVtxos.length > 0) {
3677
- const cltvSatisfied = isSubmarineRefundLocktimeReached(
3678
- vhtlcTimeouts.refund
3679
- );
3680
- const amountSats = refundableVtxos.reduce(
3681
- (sum, vtxo) => sum + Number(vtxo.value),
3682
- 0
3683
- );
3520
+ const cltvSatisfied = isSubmarineRefundLocktimeReached(vhtlcTimeouts.refund);
3521
+ const amountSats = refundableVtxos.reduce((sum, vtxo) => sum + Number(vtxo.value), 0);
3684
3522
  const isRecoverable2 = cltvSatisfied || canRecoverViaBoltz3of3(refundableVtxos, swap);
3685
3523
  return {
3686
3524
  swap,
@@ -3744,19 +3582,13 @@ var ArkadeSwaps = class _ArkadeSwaps {
3744
3582
  );
3745
3583
  }
3746
3584
  if (diagnostic.allSpent) {
3747
- throw new Error(
3748
- `Swap ${pendingSwap.id}: VHTLC is already spent`
3749
- );
3585
+ throw new Error(`Swap ${pendingSwap.id}: VHTLC is already spent`);
3750
3586
  }
3751
- throw new Error(
3752
- `Swap ${pendingSwap.id}: VHTLC has no refundable VTXOs yet`
3753
- );
3587
+ throw new Error(`Swap ${pendingSwap.id}: VHTLC has no refundable VTXOs yet`);
3754
3588
  }
3755
3589
  const outputScript = import_sdk8.ArkAddress.decode(address).pkScript;
3756
3590
  const refundWithoutReceiverLeaf = vhtlcScript.refundWithoutReceiver();
3757
- const cltvSatisfied = isSubmarineRefundLocktimeReached(
3758
- vhtlcTimeouts.refund
3759
- );
3591
+ const cltvSatisfied = isSubmarineRefundLocktimeReached(vhtlcTimeouts.refund);
3760
3592
  let boltzCallCount = 0;
3761
3593
  let sweptCount = 0;
3762
3594
  let skippedCount = 0;
@@ -3808,9 +3640,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
3808
3640
  input,
3809
3641
  output,
3810
3642
  arkInfo,
3811
- this.swapProvider.refundSubmarineSwap.bind(
3812
- this.swapProvider
3813
- )
3643
+ this.swapProvider.refundSubmarineSwap.bind(this.swapProvider)
3814
3644
  );
3815
3645
  boltzCallCount++;
3816
3646
  sweptCount++;
@@ -3833,13 +3663,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
3833
3663
  tapLeafScript: refundWithoutReceiverLeaf,
3834
3664
  tapTree: vhtlcScript.encode()
3835
3665
  };
3836
- await this.joinBatch(
3837
- this.wallet.identity,
3838
- fallbackInput,
3839
- output,
3840
- arkInfo,
3841
- false
3842
- );
3666
+ await this.joinBatch(this.wallet.identity, fallbackInput, output, arkInfo, false);
3843
3667
  sweptCount++;
3844
3668
  }
3845
3669
  }
@@ -3935,10 +3759,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
3935
3759
  try {
3936
3760
  return {
3937
3761
  swap,
3938
- context: await this.buildSubmarineVHTLCContext(
3939
- swap,
3940
- arkInfo
3941
- )
3762
+ context: await this.buildSubmarineVHTLCContext(swap, arkInfo)
3942
3763
  };
3943
3764
  } catch (err) {
3944
3765
  return {
@@ -3951,9 +3772,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
3951
3772
  const valid = prepared.filter(
3952
3773
  (item) => "context" in item
3953
3774
  );
3954
- const scripts = [
3955
- ...new Set(valid.map(({ context }) => context.vhtlcPkScriptHex))
3956
- ];
3775
+ const scripts = [...new Set(valid.map(({ context }) => context.vhtlcPkScriptHex))];
3957
3776
  const refundableByScript = /* @__PURE__ */ new Map();
3958
3777
  if (scripts.length > 0) {
3959
3778
  const [spendableResult, recoverableResult] = await Promise.all([
@@ -3988,9 +3807,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
3988
3807
  error: item.error
3989
3808
  };
3990
3809
  }
3991
- const refundableVtxos = refundableByScript.get(
3992
- item.context.vhtlcPkScriptHex.toLowerCase()
3993
- ) ?? [];
3810
+ const refundableVtxos = refundableByScript.get(item.context.vhtlcPkScriptHex.toLowerCase()) ?? [];
3994
3811
  return this.submarineRecoveryInfoFromLookup(item.swap, {
3995
3812
  ...item.context,
3996
3813
  refundableVtxos
@@ -4169,9 +3986,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
4169
3986
  */
4170
3987
  async waitAndClaimBtc(pendingSwap) {
4171
3988
  if (this.swapManager && await this.swapManager.hasSwap(pendingSwap.id)) {
4172
- const { txid } = await this.swapManager.waitForSwapCompletion(
4173
- pendingSwap.id
4174
- );
3989
+ const { txid } = await this.swapManager.waitForSwapCompletion(pendingSwap.id);
4175
3990
  return { txid };
4176
3991
  }
4177
3992
  return new Promise((resolve, reject) => {
@@ -4198,24 +4013,25 @@ var ArkadeSwaps = class _ArkadeSwaps {
4198
4013
  }
4199
4014
  case "transaction.claimed":
4200
4015
  await updateSwapStatus();
4201
- const claimedStatus = await this.getSwapStatus(
4202
- pendingSwap.id
4203
- );
4016
+ const claimedStatus = await this.getSwapStatus(pendingSwap.id);
4204
4017
  resolve({
4205
4018
  txid: claimedStatus.transaction?.id ?? ""
4206
4019
  });
4207
4020
  break;
4208
4021
  case "transaction.lockupFailed":
4209
4022
  await updateSwapStatus();
4210
- await this.quoteSwap(swap.response.id).catch((err) => {
4211
- reject(
4212
- new SwapError({
4213
- message: `Failed to renegotiate quote: ${err.message}`,
4214
- isRefundable: true,
4215
- pendingSwap: swap
4216
- })
4217
- );
4218
- });
4023
+ await this.quoteSwap(swap.response.id, quoteOptionsForSwap(swap)).catch(
4024
+ (err) => {
4025
+ reject(
4026
+ new SwapError({
4027
+ message: `Failed to renegotiate quote: ${err.message}`,
4028
+ isRefundable: true,
4029
+ pendingSwap: swap,
4030
+ cause: err
4031
+ })
4032
+ );
4033
+ }
4034
+ );
4219
4035
  break;
4220
4036
  case "swap.expired":
4221
4037
  await updateSwapStatus();
@@ -4253,30 +4069,18 @@ var ArkadeSwaps = class _ArkadeSwaps {
4253
4069
  */
4254
4070
  async claimBtc(pendingSwap) {
4255
4071
  if (!pendingSwap.toAddress)
4256
- throw new Error(
4257
- `Swap ${pendingSwap.id}: destination address is required`
4258
- );
4072
+ throw new Error(`Swap ${pendingSwap.id}: destination address is required`);
4259
4073
  if (!pendingSwap.response.claimDetails.swapTree)
4260
- throw new Error(
4261
- `Swap ${pendingSwap.id}: missing swap tree in claim details`
4262
- );
4074
+ throw new Error(`Swap ${pendingSwap.id}: missing swap tree in claim details`);
4263
4075
  if (!pendingSwap.response.claimDetails.serverPublicKey)
4264
- throw new Error(
4265
- `Swap ${pendingSwap.id}: missing server public key in claim details`
4266
- );
4076
+ throw new Error(`Swap ${pendingSwap.id}: missing server public key in claim details`);
4267
4077
  const swapStatus = await this.getSwapStatus(pendingSwap.id);
4268
4078
  if (!swapStatus.transaction?.hex)
4269
- throw new Error(
4270
- `Swap ${pendingSwap.id}: BTC transaction hex is required`
4271
- );
4272
- const lockupTx = import_btc_signer5.Transaction.fromRaw(
4273
- import_base9.hex.decode(swapStatus.transaction.hex)
4274
- );
4079
+ throw new Error(`Swap ${pendingSwap.id}: BTC transaction hex is required`);
4080
+ const lockupTx = import_btc_signer5.Transaction.fromRaw(import_base9.hex.decode(swapStatus.transaction.hex));
4275
4081
  const arkInfo = await this.arkProvider.getInfo();
4276
4082
  const network = arkInfo.network === "bitcoin" ? import_utils4.NETWORK : arkInfo.network === "mutinynet" ? MUTINYNET_NETWORK : REGTEST_NETWORK;
4277
- const swapTree = deserializeSwapTree(
4278
- pendingSwap.response.claimDetails.swapTree
4279
- );
4083
+ const swapTree = deserializeSwapTree(pendingSwap.response.claimDetails.swapTree);
4280
4084
  const musig = tweakMusig(
4281
4085
  create(import_base9.hex.decode(pendingSwap.ephemeralKey), [
4282
4086
  import_base9.hex.decode(pendingSwap.response.claimDetails.serverPublicKey),
@@ -4297,19 +4101,14 @@ var ArkadeSwaps = class _ArkadeSwaps {
4297
4101
  vout: swapOutput.vout,
4298
4102
  transactionId: lockupTx.id
4299
4103
  },
4300
- import_btc_signer5.OutScript.encode(
4301
- (0, import_btc_signer5.Address)(network).decode(pendingSwap.toAddress)
4302
- ),
4104
+ import_btc_signer5.OutScript.encode((0, import_btc_signer5.Address)(network).decode(pendingSwap.toAddress)),
4303
4105
  feeToDeliverExactAmount > fee ? feeToDeliverExactAmount : fee
4304
4106
  )
4305
4107
  );
4306
4108
  const musigMessage = musig.message(
4307
- claimTx.preimageWitnessV1(
4308
- 0,
4309
- [swapOutput.script],
4310
- import_btc_signer5.SigHash.DEFAULT,
4311
- [swapOutput.amount]
4312
- )
4109
+ claimTx.preimageWitnessV1(0, [swapOutput.script], import_btc_signer5.SigHash.DEFAULT, [
4110
+ swapOutput.amount
4111
+ ])
4313
4112
  ).generateNonce();
4314
4113
  const signedTxData = await this.swapProvider.postChainClaimDetails(
4315
4114
  pendingSwap.response.id,
@@ -4323,14 +4122,10 @@ var ArkadeSwaps = class _ArkadeSwaps {
4323
4122
  }
4324
4123
  );
4325
4124
  if (!signedTxData.pubNonce || !signedTxData.partialSignature)
4326
- throw new Error(
4327
- `Swap ${pendingSwap.id}: invalid signature data from server`
4328
- );
4125
+ throw new Error(`Swap ${pendingSwap.id}: invalid signature data from server`);
4329
4126
  const musigSession = musigMessage.aggregateNonces([
4330
4127
  [
4331
- import_base9.hex.decode(
4332
- pendingSwap.response.claimDetails.serverPublicKey
4333
- ),
4128
+ import_base9.hex.decode(pendingSwap.response.claimDetails.serverPublicKey),
4334
4129
  import_base9.hex.decode(signedTxData.pubNonce)
4335
4130
  ]
4336
4131
  ]).initializeSession();
@@ -4350,13 +4145,9 @@ var ArkadeSwaps = class _ArkadeSwaps {
4350
4145
  */
4351
4146
  async refundArk(pendingSwap) {
4352
4147
  if (!pendingSwap.response.lockupDetails.serverPublicKey)
4353
- throw new Error(
4354
- `Swap ${pendingSwap.id}: missing server public key in lockup details`
4355
- );
4148
+ throw new Error(`Swap ${pendingSwap.id}: missing server public key in lockup details`);
4356
4149
  if (!pendingSwap.response.lockupDetails.timeouts)
4357
- throw new Error(
4358
- `Swap ${pendingSwap.id}: missing timeouts in lockup details`
4359
- );
4150
+ throw new Error(`Swap ${pendingSwap.id}: missing timeouts in lockup details`);
4360
4151
  const arkInfo = await this.arkProvider.getInfo();
4361
4152
  const address = await this.wallet.getAddress();
4362
4153
  const ourXOnlyPublicKey = normalizeToXOnlyKey(
@@ -4398,9 +4189,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
4398
4189
  timeoutBlockHeights: pendingSwap.response.lockupDetails.timeouts
4399
4190
  });
4400
4191
  if (!vhtlcScript.refundScript)
4401
- throw new Error(
4402
- `Swap ${pendingSwap.id}: failed to create VHTLC script for chain swap`
4403
- );
4192
+ throw new Error(`Swap ${pendingSwap.id}: failed to create VHTLC script for chain swap`);
4404
4193
  if (pendingSwap.response.lockupDetails.lockupAddress !== vhtlcAddress) {
4405
4194
  throw new SwapError({
4406
4195
  message: "Unable to claim: invalid VHTLC address"
@@ -4481,9 +4270,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
4481
4270
  */
4482
4271
  async waitAndClaimArk(pendingSwap) {
4483
4272
  if (this.swapManager && await this.swapManager.hasSwap(pendingSwap.id)) {
4484
- const { txid } = await this.swapManager.waitForSwapCompletion(
4485
- pendingSwap.id
4486
- );
4273
+ const { txid } = await this.swapManager.waitForSwapCompletion(pendingSwap.id);
4487
4274
  return { txid };
4488
4275
  }
4489
4276
  return new Promise((resolve, reject) => {
@@ -4504,37 +4291,33 @@ var ArkadeSwaps = class _ArkadeSwaps {
4504
4291
  break;
4505
4292
  case "transaction.claimed":
4506
4293
  await updateSwapStatus();
4507
- const claimedStatus = await this.getSwapStatus(
4508
- pendingSwap.id
4509
- );
4294
+ const claimedStatus = await this.getSwapStatus(pendingSwap.id);
4510
4295
  resolve({
4511
4296
  txid: claimedStatus.transaction?.id ?? ""
4512
4297
  });
4513
4298
  break;
4514
4299
  case "transaction.claim.pending":
4515
4300
  await updateSwapStatus();
4516
- await this.signCooperativeClaimForServer(swap).catch(
4301
+ await this.signCooperativeClaimForServer(swap).catch((err) => {
4302
+ logger.error(`Failed to sign cooperative claim for ${swap.id}:`, err);
4303
+ });
4304
+ break;
4305
+ case "transaction.lockupFailed":
4306
+ await updateSwapStatus();
4307
+ await this.quoteSwap(swap.response.id, quoteOptionsForSwap(swap)).catch(
4517
4308
  (err) => {
4518
- logger.error(
4519
- `Failed to sign cooperative claim for ${swap.id}:`,
4520
- err
4309
+ reject(
4310
+ new SwapError({
4311
+ message: `Failed to renegotiate quote: ${err.message}`,
4312
+ isRefundable: false,
4313
+ // TODO btc refund not implemented yet
4314
+ pendingSwap: swap,
4315
+ cause: err
4316
+ })
4521
4317
  );
4522
4318
  }
4523
4319
  );
4524
4320
  break;
4525
- case "transaction.lockupFailed":
4526
- await updateSwapStatus();
4527
- await this.quoteSwap(swap.response.id).catch((err) => {
4528
- reject(
4529
- new SwapError({
4530
- message: `Failed to renegotiate quote: ${err.message}`,
4531
- isRefundable: false,
4532
- // TODO btc refund not implemented yet
4533
- pendingSwap: swap
4534
- })
4535
- );
4536
- });
4537
- break;
4538
4321
  case "swap.expired":
4539
4322
  await updateSwapStatus();
4540
4323
  reject(
@@ -4574,17 +4357,11 @@ var ArkadeSwaps = class _ArkadeSwaps {
4574
4357
  */
4575
4358
  async claimArk(pendingSwap) {
4576
4359
  if (!pendingSwap.toAddress)
4577
- throw new Error(
4578
- `Swap ${pendingSwap.id}: destination address is required`
4579
- );
4360
+ throw new Error(`Swap ${pendingSwap.id}: destination address is required`);
4580
4361
  if (!pendingSwap.response.claimDetails.serverPublicKey)
4581
- throw new Error(
4582
- `Swap ${pendingSwap.id}: missing server public key in claim details`
4583
- );
4362
+ throw new Error(`Swap ${pendingSwap.id}: missing server public key in claim details`);
4584
4363
  if (!pendingSwap.response.claimDetails.timeouts)
4585
- throw new Error(
4586
- `Swap ${pendingSwap.id}: missing timeouts in claim details`
4587
- );
4364
+ throw new Error(`Swap ${pendingSwap.id}: missing timeouts in claim details`);
4588
4365
  const arkInfo = await this.arkProvider.getInfo();
4589
4366
  const preimage = import_base9.hex.decode(pendingSwap.preimage);
4590
4367
  const address = await this.wallet.getAddress();
@@ -4596,10 +4373,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
4596
4373
  pendingSwap.response.claimDetails.serverPublicKey,
4597
4374
  "sender"
4598
4375
  );
4599
- const serverXOnlyPublicKey = normalizeToXOnlyKey(
4600
- arkInfo.signerPubkey,
4601
- "server"
4602
- );
4376
+ const serverXOnlyPublicKey = normalizeToXOnlyKey(arkInfo.signerPubkey, "server");
4603
4377
  const { vhtlcAddress, vhtlcScript } = this.createVHTLCScript({
4604
4378
  network: arkInfo.network,
4605
4379
  preimageHash: import_base9.hex.decode(pendingSwap.request.preimageHash),
@@ -4609,9 +4383,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
4609
4383
  timeoutBlockHeights: pendingSwap.response.claimDetails.timeouts
4610
4384
  });
4611
4385
  if (!vhtlcScript.claimScript)
4612
- throw new Error(
4613
- `Swap ${pendingSwap.id}: failed to create VHTLC script for chain swap`
4614
- );
4386
+ throw new Error(`Swap ${pendingSwap.id}: failed to create VHTLC script for chain swap`);
4615
4387
  if (pendingSwap.response.claimDetails.lockupAddress !== vhtlcAddress) {
4616
4388
  throw new SwapError({
4617
4389
  message: "Unable to claim: invalid VHTLC address"
@@ -4628,15 +4400,11 @@ var ArkadeSwaps = class _ArkadeSwaps {
4628
4400
  break;
4629
4401
  }
4630
4402
  if (attempt < CLAIM_VTXO_RETRY_ATTEMPTS) {
4631
- await new Promise(
4632
- (resolve) => setTimeout(resolve, CLAIM_VTXO_RETRY_DELAY_MS)
4633
- );
4403
+ await new Promise((resolve) => setTimeout(resolve, CLAIM_VTXO_RETRY_DELAY_MS));
4634
4404
  }
4635
4405
  }
4636
4406
  if (!vtxo) {
4637
- throw new Error(
4638
- `Swap ${pendingSwap.id}: no spendable virtual coins found`
4639
- );
4407
+ throw new Error(`Swap ${pendingSwap.id}: no spendable virtual coins found`);
4640
4408
  }
4641
4409
  const input = {
4642
4410
  ...vtxo,
@@ -4647,10 +4415,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
4647
4415
  amount: BigInt(vtxo.value),
4648
4416
  script: import_sdk8.ArkAddress.decode(address).pkScript
4649
4417
  };
4650
- const vhtlcIdentity = claimVHTLCIdentity(
4651
- this.wallet.identity,
4652
- preimage
4653
- );
4418
+ const vhtlcIdentity = claimVHTLCIdentity(this.wallet.identity, preimage);
4654
4419
  if ((0, import_sdk8.isRecoverable)(vtxo)) {
4655
4420
  await this.joinBatch(vhtlcIdentity, input, output, arkInfo);
4656
4421
  } else {
@@ -4676,16 +4441,10 @@ var ArkadeSwaps = class _ArkadeSwaps {
4676
4441
  */
4677
4442
  async signCooperativeClaimForServer(pendingSwap) {
4678
4443
  if (!pendingSwap.response.lockupDetails.swapTree)
4679
- throw new Error(
4680
- `Swap ${pendingSwap.id}: missing swap tree in lockup details`
4681
- );
4444
+ throw new Error(`Swap ${pendingSwap.id}: missing swap tree in lockup details`);
4682
4445
  if (!pendingSwap.response.lockupDetails.serverPublicKey)
4683
- throw new Error(
4684
- `Swap ${pendingSwap.id}: missing server public key in lockup details`
4685
- );
4686
- const claimDetails = await this.swapProvider.getChainClaimDetails(
4687
- pendingSwap.id
4688
- );
4446
+ throw new Error(`Swap ${pendingSwap.id}: missing server public key in lockup details`);
4447
+ const claimDetails = await this.swapProvider.getChainClaimDetails(pendingSwap.id);
4689
4448
  const serverPubKey = pendingSwap.response.lockupDetails.serverPublicKey;
4690
4449
  if (claimDetails.publicKey !== serverPubKey) {
4691
4450
  throw new Error(
@@ -4701,9 +4460,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
4701
4460
  );
4702
4461
  const musigNonces = musig.message(import_base9.hex.decode(claimDetails.transactionHash)).generateNonce().aggregateNonces([
4703
4462
  [
4704
- import_base9.hex.decode(
4705
- pendingSwap.response.lockupDetails.serverPublicKey
4706
- ),
4463
+ import_base9.hex.decode(pendingSwap.response.lockupDetails.serverPublicKey),
4707
4464
  import_base9.hex.decode(claimDetails.pubNonce)
4708
4465
  ]
4709
4466
  ]).initializeSession();
@@ -4722,10 +4479,8 @@ var ArkadeSwaps = class _ArkadeSwaps {
4722
4479
  * @returns The transaction ID of the claim.
4723
4480
  */
4724
4481
  async waitAndClaimChain(pendingSwap) {
4725
- if (pendingSwap.request.to === "ARK")
4726
- return this.waitAndClaimArk(pendingSwap);
4727
- if (pendingSwap.request.to === "BTC")
4728
- return this.waitAndClaimBtc(pendingSwap);
4482
+ if (pendingSwap.request.to === "ARK") return this.waitAndClaimArk(pendingSwap);
4483
+ if (pendingSwap.request.to === "BTC") return this.waitAndClaimBtc(pendingSwap);
4729
4484
  throw new SwapError({
4730
4485
  message: `Unsupported swap destination: ${pendingSwap.request.to}`
4731
4486
  });
@@ -4740,11 +4495,9 @@ var ArkadeSwaps = class _ArkadeSwaps {
4740
4495
  */
4741
4496
  async createChainSwap(args) {
4742
4497
  const { to, from, receiverLockAmount, senderLockAmount, toAddress } = args;
4743
- if (!toAddress)
4744
- throw new SwapError({ message: "Destination address is required" });
4498
+ if (!toAddress) throw new SwapError({ message: "Destination address is required" });
4745
4499
  const feeSatsPerByte = args.feeSatsPerByte ?? 1;
4746
- if (feeSatsPerByte <= 0)
4747
- throw new SwapError({ message: "Invalid feeSatsPerByte" });
4500
+ if (feeSatsPerByte <= 0) throw new SwapError({ message: "Invalid feeSatsPerByte" });
4748
4501
  let amount, serverLockAmount, userLockAmount;
4749
4502
  if (receiverLockAmount) {
4750
4503
  amount = receiverLockAmount;
@@ -4759,8 +4512,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
4759
4512
  }
4760
4513
  const preimage = (0, import_utils3.randomBytes)(32);
4761
4514
  const preimageHash = import_base9.hex.encode((0, import_sha23.sha256)(preimage));
4762
- if (!preimageHash)
4763
- throw new SwapError({ message: "Failed to get preimage hash" });
4515
+ if (!preimageHash) throw new SwapError({ message: "Failed to get preimage hash" });
4764
4516
  const ephemeralKey = import_secp256k13.secp256k1.utils.randomSecretKey();
4765
4517
  const refundPublicKey = to === "ARK" ? import_base9.hex.encode(import_secp256k13.secp256k1.getPublicKey(ephemeralKey)) : import_base9.hex.encode(await this.wallet.identity.compressedPublicKey());
4766
4518
  if (!refundPublicKey)
@@ -4809,30 +4561,20 @@ var ArkadeSwaps = class _ArkadeSwaps {
4809
4561
  const { to, from, swap, arkInfo } = args;
4810
4562
  if (from === "ARK") {
4811
4563
  if (!swap.response.lockupDetails.serverPublicKey)
4812
- throw new Error(
4813
- `Swap ${swap.id}: missing serverPublicKey in lockup details`
4814
- );
4564
+ throw new Error(`Swap ${swap.id}: missing serverPublicKey in lockup details`);
4815
4565
  if (!swap.response.lockupDetails.timeouts)
4816
- throw new Error(
4817
- `Swap ${swap.id}: missing timeouts in lockup details`
4818
- );
4566
+ throw new Error(`Swap ${swap.id}: missing timeouts in lockup details`);
4819
4567
  }
4820
4568
  if (to === "ARK") {
4821
4569
  if (!swap.response.claimDetails.serverPublicKey)
4822
- throw new Error(
4823
- `Swap ${swap.id}: missing serverPublicKey in claim details`
4824
- );
4570
+ throw new Error(`Swap ${swap.id}: missing serverPublicKey in claim details`);
4825
4571
  if (!swap.response.claimDetails.timeouts)
4826
- throw new Error(
4827
- `Swap ${swap.id}: missing timeouts in claim details`
4828
- );
4572
+ throw new Error(`Swap ${swap.id}: missing timeouts in claim details`);
4829
4573
  }
4830
4574
  const lockupAddress = to === "ARK" ? swap.response.claimDetails.lockupAddress : swap.response.lockupDetails.lockupAddress;
4831
4575
  const receiverPubkey = to === "ARK" ? swap.request.claimPublicKey : swap.response.lockupDetails.serverPublicKey;
4832
4576
  const senderPubkey = to === "ARK" ? swap.response.claimDetails.serverPublicKey : swap.request.refundPublicKey;
4833
- const serverPubkey = import_base9.hex.encode(
4834
- normalizeToXOnlyKey(arkInfo.signerPubkey, "server")
4835
- );
4577
+ const serverPubkey = import_base9.hex.encode(normalizeToXOnlyKey(arkInfo.signerPubkey, "server"));
4836
4578
  const vhtlcTimeouts = to === "ARK" ? swap.response.claimDetails.timeouts : swap.response.lockupDetails.timeouts;
4837
4579
  const { vhtlcAddress } = this.createVHTLCScript({
4838
4580
  network: arkInfo.network,
@@ -4850,15 +4592,110 @@ var ArkadeSwaps = class _ArkadeSwaps {
4850
4592
  return true;
4851
4593
  }
4852
4594
  /**
4853
- * Renegotiates the quote for an existing swap.
4595
+ * Renegotiates the quote for an existing chain swap. Convenience wrapper
4596
+ * over `getSwapQuote` + `acceptSwapQuote` with a safety floor.
4597
+ *
4598
+ * The floor is resolved in order:
4599
+ * 1. `options.minAcceptableAmount` if provided.
4600
+ * 2. The original `response.claimDetails.amount` of the stored
4601
+ * pending swap (Boltz-confirmed server-lock amount at creation).
4602
+ * 3. Otherwise throws `QuoteRejectedError({ reason: "no_baseline" })`.
4603
+ *
4604
+ * `options.maxSlippageBps` (default 0) relaxes the floor by basis points.
4605
+ * Quotes ≤ 0 are always rejected. On rejection the acceptance is NOT
4606
+ * posted to Boltz.
4607
+ *
4608
+ * Prefer `getSwapQuote` / `acceptSwapQuote` for callers that want to
4609
+ * inspect the quote before committing.
4610
+ *
4854
4611
  * @param swapId - The ID of the swap.
4612
+ * @param options - Optional floor and slippage configuration.
4855
4613
  * @returns The accepted quote amount.
4614
+ * @throws QuoteRejectedError if the quote is non-positive, below the
4615
+ * effective floor, or no baseline is available.
4856
4616
  */
4857
- async quoteSwap(swapId) {
4617
+ async quoteSwap(swapId, options) {
4618
+ const effectiveFloor = await this.resolveEffectiveFloor(swapId, options);
4619
+ const amount = await this.getSwapQuote(swapId);
4620
+ this.validateQuote(amount, effectiveFloor);
4621
+ await this.swapProvider.postChainQuote(swapId, { amount });
4622
+ return amount;
4623
+ }
4624
+ /**
4625
+ * Fetches a renegotiated quote from Boltz without accepting it.
4626
+ * Pair with `acceptSwapQuote` to commit a specific value.
4627
+ */
4628
+ async getSwapQuote(swapId) {
4858
4629
  const { amount } = await this.swapProvider.getChainQuote(swapId);
4630
+ return amount;
4631
+ }
4632
+ /**
4633
+ * Accepts a quote amount for an existing chain swap, after validating it
4634
+ * against the configured floor. See `quoteSwap` for floor-resolution rules.
4635
+ *
4636
+ * @throws QuoteRejectedError if `amount` ≤ 0, below the effective floor,
4637
+ * or no baseline is available.
4638
+ */
4639
+ async acceptSwapQuote(swapId, amount, options) {
4640
+ const effectiveFloor = await this.resolveEffectiveFloor(swapId, options);
4641
+ this.validateQuote(amount, effectiveFloor);
4859
4642
  await this.swapProvider.postChainQuote(swapId, { amount });
4860
4643
  return amount;
4861
4644
  }
4645
+ async resolveEffectiveFloor(swapId, options) {
4646
+ this.validateQuoteOptions(options);
4647
+ const floor = await this.resolveQuoteFloor(swapId, options);
4648
+ const slippageBps = options?.maxSlippageBps ?? 0;
4649
+ return Math.floor(floor - floor * slippageBps / 1e4);
4650
+ }
4651
+ async resolveQuoteFloor(swapId, options) {
4652
+ if (options?.minAcceptableAmount !== void 0) {
4653
+ return options.minAcceptableAmount;
4654
+ }
4655
+ const swaps = await this.swapRepository.getAllSwaps({
4656
+ id: swapId,
4657
+ type: "chain"
4658
+ });
4659
+ const stored = swaps[0];
4660
+ const amount = stored?.response?.claimDetails?.amount;
4661
+ if (typeof amount !== "number") {
4662
+ throw new QuoteRejectedError({ reason: "no_baseline" });
4663
+ }
4664
+ return amount;
4665
+ }
4666
+ validateQuoteOptions(options) {
4667
+ if (options?.minAcceptableAmount !== void 0) {
4668
+ const v = options.minAcceptableAmount;
4669
+ if (!Number.isInteger(v) || v <= 0) {
4670
+ throw new TypeError(
4671
+ `Invalid minAcceptableAmount: ${v} \u2014 must be a positive integer`
4672
+ );
4673
+ }
4674
+ }
4675
+ if (options?.maxSlippageBps !== void 0) {
4676
+ const v = options.maxSlippageBps;
4677
+ if (!Number.isInteger(v) || v < 0 || v > 1e4) {
4678
+ throw new TypeError(
4679
+ `Invalid maxSlippageBps: ${v} \u2014 must be an integer in [0, 10000]`
4680
+ );
4681
+ }
4682
+ }
4683
+ }
4684
+ validateQuote(amount, effectiveFloor) {
4685
+ if (!(amount > 0)) {
4686
+ throw new QuoteRejectedError({
4687
+ reason: "non_positive",
4688
+ quotedAmount: amount
4689
+ });
4690
+ }
4691
+ if (amount < effectiveFloor) {
4692
+ throw new QuoteRejectedError({
4693
+ reason: "below_floor",
4694
+ quotedAmount: amount,
4695
+ floor: effectiveFloor
4696
+ });
4697
+ }
4698
+ }
4862
4699
  // =========================================================================
4863
4700
  // Shared utilities
4864
4701
  // =========================================================================
@@ -4872,14 +4709,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
4872
4709
  * @returns The commitment transaction ID.
4873
4710
  */
4874
4711
  async joinBatch(identity, input, output, arkInfo, isRecoverable2 = true) {
4875
- return joinBatch(
4876
- this.arkProvider,
4877
- identity,
4878
- input,
4879
- output,
4880
- arkInfo,
4881
- isRecoverable2
4882
- );
4712
+ return joinBatch(this.arkProvider, identity, input, output, arkInfo, isRecoverable2);
4883
4713
  }
4884
4714
  /**
4885
4715
  * Creates a VHTLC script for the swap.
@@ -4917,9 +4747,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
4917
4747
  async getPendingSubmarineSwaps() {
4918
4748
  const swaps = await this.getPendingSubmarineSwapsFromStorage();
4919
4749
  if (!swaps) return [];
4920
- return swaps.filter(
4921
- (swap) => swap.status === "invoice.set"
4922
- );
4750
+ return swaps.filter((swap) => swap.status === "invoice.set");
4923
4751
  }
4924
4752
  /**
4925
4753
  * Returns pending reverse swaps (those with status `swap.created`).
@@ -4927,9 +4755,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
4927
4755
  async getPendingReverseSwaps() {
4928
4756
  const swaps = await this.getPendingReverseSwapsFromStorage();
4929
4757
  if (!swaps) return [];
4930
- return swaps.filter(
4931
- (swap) => swap.status === "swap.created"
4932
- );
4758
+ return swaps.filter((swap) => swap.status === "swap.created");
4933
4759
  }
4934
4760
  /**
4935
4761
  * Returns pending chain swaps (those with status `swap.created`).
@@ -4968,10 +4794,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
4968
4794
  this.savePendingReverseSwap.bind(this)
4969
4795
  )
4970
4796
  ).catch((error) => {
4971
- logger.error(
4972
- `Failed to refresh swap status for ${swap.id}:`,
4973
- error
4974
- );
4797
+ logger.error(`Failed to refresh swap status for ${swap.id}:`, error);
4975
4798
  })
4976
4799
  );
4977
4800
  }
@@ -4985,23 +4808,15 @@ var ArkadeSwaps = class _ArkadeSwaps {
4985
4808
  this.savePendingSubmarineSwap.bind(this)
4986
4809
  )
4987
4810
  ).catch((error) => {
4988
- logger.error(
4989
- `Failed to refresh swap status for ${swap.id}:`,
4990
- error
4991
- );
4811
+ logger.error(`Failed to refresh swap status for ${swap.id}:`, error);
4992
4812
  })
4993
4813
  );
4994
4814
  }
4995
4815
  for (const swap of await this.getPendingChainSwapsFromStorage()) {
4996
4816
  if (isChainFinalStatus(swap.status)) continue;
4997
4817
  promises.push(
4998
- this.getSwapStatus(swap.id).then(
4999
- ({ status }) => this.savePendingChainSwap({ ...swap, status })
5000
- ).catch((error) => {
5001
- logger.error(
5002
- `Failed to refresh swap status for ${swap.id}:`,
5003
- error
5004
- );
4818
+ this.getSwapStatus(swap.id).then(({ status }) => this.savePendingChainSwap({ ...swap, status })).catch((error) => {
4819
+ logger.error(`Failed to refresh swap status for ${swap.id}:`, error);
5005
4820
  })
5006
4821
  );
5007
4822
  }
@@ -5018,9 +4833,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
5018
4833
  * display/monitoring and are not automatically wired into the SwapManager.
5019
4834
  */
5020
4835
  async restoreSwaps(boltzFees) {
5021
- const publicKey = import_base9.hex.encode(
5022
- await this.wallet.identity.compressedPublicKey()
5023
- );
4836
+ const publicKey = import_base9.hex.encode(await this.wallet.identity.compressedPublicKey());
5024
4837
  if (!publicKey) throw new Error("Failed to get public key from wallet");
5025
4838
  const fees = boltzFees ?? await this.swapProvider.getFees();
5026
4839
  const chainSwaps = [];
@@ -5072,25 +4885,14 @@ var ArkadeSwaps = class _ArkadeSwaps {
5072
4885
  preimage: ""
5073
4886
  });
5074
4887
  } else if (isRestoredSubmarineSwap(swap)) {
5075
- const {
5076
- amount,
5077
- lockupAddress,
5078
- serverPublicKey,
5079
- tree,
5080
- timeoutBlockHeights
5081
- } = swap.refundDetails;
4888
+ const { amount, lockupAddress, serverPublicKey, tree, timeoutBlockHeights } = swap.refundDetails;
5082
4889
  let preimage = "";
5083
4890
  if (!isSubmarineFinalStatus(status)) {
5084
4891
  try {
5085
- const data = await this.swapProvider.getSwapPreimage(
5086
- swap.id
5087
- );
4892
+ const data = await this.swapProvider.getSwapPreimage(swap.id);
5088
4893
  preimage = data.preimage;
5089
4894
  } catch (error) {
5090
- logger.warn(
5091
- `Failed to restore preimage for submarine swap ${id}`,
5092
- error
5093
- );
4895
+ logger.warn(`Failed to restore preimage for submarine swap ${id}`, error);
5094
4896
  }
5095
4897
  }
5096
4898
  submarineSwaps.push({
@@ -5128,12 +4930,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
5128
4930
  } else if (isRestoredChainSwap(swap)) {
5129
4931
  const refundDetails = swap.refundDetails;
5130
4932
  if (!refundDetails) continue;
5131
- const {
5132
- amount,
5133
- lockupAddress,
5134
- serverPublicKey,
5135
- timeoutBlockHeight
5136
- } = refundDetails;
4933
+ const { amount, lockupAddress, serverPublicKey, timeoutBlockHeight } = refundDetails;
5137
4934
  chainSwaps.push({
5138
4935
  id,
5139
4936
  type: "chain",
@@ -5185,9 +4982,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
5185
4982
  var SWAP_POLL_TASK_TYPE = "swap-poll";
5186
4983
 
5187
4984
  // src/expo/arkade-lightning.ts
5188
- function getRandomId() {
5189
- return Math.random().toString(36).slice(2) + Date.now().toString(36);
5190
- }
4985
+ var import_sdk9 = require("@arkade-os/sdk");
5191
4986
  function warnOnRemovedBackgroundFields(bg) {
5192
4987
  if (!bg || typeof bg !== "object") return;
5193
4988
  const removed = [];
@@ -5243,9 +5038,7 @@ var ExpoArkadeSwaps = class _ExpoArkadeSwaps {
5243
5038
  const instance = new _ExpoArkadeSwaps(inner, config);
5244
5039
  await instance.seedSwapPollTask();
5245
5040
  if (config.background.foregroundIntervalMs && config.background.foregroundIntervalMs > 0) {
5246
- instance.startForegroundPolling(
5247
- config.background.foregroundIntervalMs
5248
- );
5041
+ instance.startForegroundPolling(config.background.foregroundIntervalMs);
5249
5042
  }
5250
5043
  return instance;
5251
5044
  }
@@ -5259,9 +5052,7 @@ var ExpoArkadeSwaps = class _ExpoArkadeSwaps {
5259
5052
  const { taskQueue } = this.config.background;
5260
5053
  const results = await taskQueue.getResults();
5261
5054
  if (results.length > 0) {
5262
- await taskQueue.acknowledgeResults(
5263
- results.map((r) => r.id)
5264
- );
5055
+ await taskQueue.acknowledgeResults(results.map((r) => r.id));
5265
5056
  }
5266
5057
  await this.seedSwapPollTask();
5267
5058
  }
@@ -5270,7 +5061,7 @@ var ExpoArkadeSwaps = class _ExpoArkadeSwaps {
5270
5061
  const existing = await taskQueue.getTasks(SWAP_POLL_TASK_TYPE);
5271
5062
  if (existing.length > 0) return;
5272
5063
  const task = {
5273
- id: getRandomId(),
5064
+ id: (0, import_sdk9.getRandomId)(),
5274
5065
  type: SWAP_POLL_TASK_TYPE,
5275
5066
  data: {},
5276
5067
  createdAt: Date.now()
@@ -5387,17 +5178,17 @@ var ExpoArkadeSwaps = class _ExpoArkadeSwaps {
5387
5178
  verifyChainSwap(args) {
5388
5179
  return this.inner.verifyChainSwap(args);
5389
5180
  }
5390
- quoteSwap(swapId) {
5391
- return this.inner.quoteSwap(swapId);
5181
+ quoteSwap(swapId, options) {
5182
+ return this.inner.quoteSwap(swapId, options);
5183
+ }
5184
+ getSwapQuote(swapId) {
5185
+ return this.inner.getSwapQuote(swapId);
5186
+ }
5187
+ acceptSwapQuote(swapId, amount, options) {
5188
+ return this.inner.acceptSwapQuote(swapId, amount, options);
5392
5189
  }
5393
5190
  joinBatch(identity, input, output, arkInfo, isRecoverable2) {
5394
- return this.inner.joinBatch(
5395
- identity,
5396
- input,
5397
- output,
5398
- arkInfo,
5399
- isRecoverable2
5400
- );
5191
+ return this.inner.joinBatch(identity, input, output, arkInfo, isRecoverable2);
5401
5192
  }
5402
5193
  createVHTLCScript(params) {
5403
5194
  return this.inner.createVHTLCScript(params);