@arkade-os/boltz-swap 0.3.42 → 0.3.44

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.
@@ -324,7 +324,10 @@ declare class ArkadeSwaps {
324
324
  * swap's ARK lockup address.
325
325
  *
326
326
  * Path selection per VTXO:
327
- * - CLTV has elapsed → `refundWithoutReceiver` via `joinBatch` (no Boltz).
327
+ * - CLTV elapsed, live VTXO → `refundWithoutReceiver` offchain (sender +
328
+ * server, no Boltz, no batch round).
329
+ * - CLTV elapsed, swept VTXO → `refundWithoutReceiver` via `joinBatch`
330
+ * (a swept VTXO is no longer a live leaf).
328
331
  * - Pre-CLTV recoverable → skipped (Boltz can't co-sign swept-batch refund).
329
332
  * - Pre-CLTV non-recoverable → cooperative 3-of-3 refund via Boltz.
330
333
  *
@@ -463,6 +466,29 @@ declare class ArkadeSwaps {
463
466
  * @returns The commitment transaction ID.
464
467
  */
465
468
  joinBatch(identity: Identity, input: ArkTxInput, output: TransactionOutput, arkInfo: ArkInfo, isRecoverable?: boolean): Promise<string>;
469
+ /**
470
+ * Settle a `refundWithoutReceiver` (sender + server, no Boltz) refund for a
471
+ * single VTXO whose CLTV refund locktime has elapsed.
472
+ *
473
+ * A live VTXO settles the leaf with an offchain Ark tx — no batch round. A
474
+ * swept (recoverable) VTXO is no longer a live leaf, so it can only be
475
+ * reclaimed by re-registering it into a batch.
476
+ */
477
+ private settleRefundWithoutReceiver;
478
+ /**
479
+ * Refund every VTXO at a swap's VHTLC address back to the wallet, shared by
480
+ * {@link ArkadeSwaps.refundVHTLC} (submarine) and {@link ArkadeSwaps.refundArk}
481
+ * (chain). Path selection per VTXO:
482
+ * - CLTV elapsed → `refundWithoutReceiver` (offchain for a live VTXO, via a
483
+ * batch round for a swept one — see {@link settleRefundWithoutReceiver}).
484
+ * - Pre-CLTV recoverable → skipped (Boltz can't co-sign a swept-batch refund).
485
+ * - Pre-CLTV non-recoverable → cooperative 3-of-3 refund via Boltz, falling
486
+ * back to `refundWithoutReceiver` offchain if Boltz rejects after the
487
+ * locktime has since elapsed.
488
+ *
489
+ * @returns Counts of VTXOs swept vs. deferred.
490
+ */
491
+ private refundVtxos;
466
492
  /**
467
493
  * Creates a VHTLC script for the swap.
468
494
  * Works for submarine, reverse, and chain swaps.
@@ -324,7 +324,10 @@ declare class ArkadeSwaps {
324
324
  * swap's ARK lockup address.
325
325
  *
326
326
  * Path selection per VTXO:
327
- * - CLTV has elapsed → `refundWithoutReceiver` via `joinBatch` (no Boltz).
327
+ * - CLTV elapsed, live VTXO → `refundWithoutReceiver` offchain (sender +
328
+ * server, no Boltz, no batch round).
329
+ * - CLTV elapsed, swept VTXO → `refundWithoutReceiver` via `joinBatch`
330
+ * (a swept VTXO is no longer a live leaf).
328
331
  * - Pre-CLTV recoverable → skipped (Boltz can't co-sign swept-batch refund).
329
332
  * - Pre-CLTV non-recoverable → cooperative 3-of-3 refund via Boltz.
330
333
  *
@@ -463,6 +466,29 @@ declare class ArkadeSwaps {
463
466
  * @returns The commitment transaction ID.
464
467
  */
465
468
  joinBatch(identity: Identity, input: ArkTxInput, output: TransactionOutput, arkInfo: ArkInfo, isRecoverable?: boolean): Promise<string>;
469
+ /**
470
+ * Settle a `refundWithoutReceiver` (sender + server, no Boltz) refund for a
471
+ * single VTXO whose CLTV refund locktime has elapsed.
472
+ *
473
+ * A live VTXO settles the leaf with an offchain Ark tx — no batch round. A
474
+ * swept (recoverable) VTXO is no longer a live leaf, so it can only be
475
+ * reclaimed by re-registering it into a batch.
476
+ */
477
+ private settleRefundWithoutReceiver;
478
+ /**
479
+ * Refund every VTXO at a swap's VHTLC address back to the wallet, shared by
480
+ * {@link ArkadeSwaps.refundVHTLC} (submarine) and {@link ArkadeSwaps.refundArk}
481
+ * (chain). Path selection per VTXO:
482
+ * - CLTV elapsed → `refundWithoutReceiver` (offchain for a live VTXO, via a
483
+ * batch round for a swept one — see {@link settleRefundWithoutReceiver}).
484
+ * - Pre-CLTV recoverable → skipped (Boltz can't co-sign a swept-batch refund).
485
+ * - Pre-CLTV non-recoverable → cooperative 3-of-3 refund via Boltz, falling
486
+ * back to `refundWithoutReceiver` offchain if Boltz rejects after the
487
+ * locktime has since elapsed.
488
+ *
489
+ * @returns Counts of VTXOs swept vs. deferred.
490
+ */
491
+ private refundVtxos;
466
492
  /**
467
493
  * Creates a VHTLC script for the swap.
468
494
  * Works for submarine, reverse, and chain swaps.
@@ -7,7 +7,7 @@ import {
7
7
  isSubmarineFinalStatus,
8
8
  isSubmarineSwapRefundable,
9
9
  logger
10
- } from "./chunk-UXYHW7KV.js";
10
+ } from "./chunk-QVXFEX5F.js";
11
11
 
12
12
  // src/expo/swapsPollProcessor.ts
13
13
  var SWAP_POLL_TASK_TYPE = "swap-poll";
@@ -3100,6 +3100,40 @@ var claimVHTLCwithOffchainTx = async (identity, vhtlcScript, serverXOnlyPublicKe
3100
3100
  await arkProvider.finalizeTx(arkTxid, finalCheckpoints);
3101
3101
  return arkTxid;
3102
3102
  };
3103
+ var refundWithoutReceiverVHTLCwithOffchainTx = async (identity, vhtlcScript, serverXOnlyPublicKey, input, output, arkInfo, arkProvider) => {
3104
+ const rawCheckpointTapscript = hex7.decode(arkInfo.checkpointTapscript);
3105
+ const serverUnrollScript = CSVMultisigTapscript2.decode(rawCheckpointTapscript);
3106
+ const { arkTx, checkpoints } = buildOffchainTx([input], [output], serverUnrollScript);
3107
+ const signedArkTx = await identity.sign(arkTx);
3108
+ const { arkTxid, finalArkTx, signedCheckpointTxs } = await arkProvider.submitTx(
3109
+ base643.encode(signedArkTx.toPSBT()),
3110
+ checkpoints.map((c) => base643.encode(c.toPSBT()))
3111
+ );
3112
+ const finalTx = Transaction5.fromPSBT(base643.decode(finalArkTx));
3113
+ const serverPubkeyHex = hex7.encode(serverXOnlyPublicKey);
3114
+ const refundLeafHash = tapLeafHash3(
3115
+ scriptFromTapLeafScript(vhtlcScript.refundWithoutReceiver())
3116
+ );
3117
+ for (let i = 0; i < finalTx.inputsLength; i++) {
3118
+ if (!verifySignatures(finalTx, i, [serverPubkeyHex], refundLeafHash)) {
3119
+ throw new Error("Invalid final Ark transaction");
3120
+ }
3121
+ }
3122
+ const finalCheckpoints = await Promise.all(
3123
+ signedCheckpointTxs.map(async (c, idx) => {
3124
+ const tx = Transaction5.fromPSBT(base643.decode(c));
3125
+ const checkpointLeaf = checkpoints[idx].getInput(0).tapLeafScript[0];
3126
+ const cpLeafHash = tapLeafHash3(scriptFromTapLeafScript(checkpointLeaf));
3127
+ if (!verifySignatures(tx, 0, [serverPubkeyHex], cpLeafHash)) {
3128
+ throw new Error("Invalid server signature in checkpoint transaction");
3129
+ }
3130
+ const signedCheckpoint = await identity.sign(tx, [0]);
3131
+ return base643.encode(signedCheckpoint.toPSBT());
3132
+ })
3133
+ );
3134
+ await arkProvider.finalizeTx(arkTxid, finalCheckpoints);
3135
+ return arkTxid;
3136
+ };
3103
3137
  var refundVHTLCwithOffchainTx = async (swapId, identity, arkProvider, boltzXOnlyPublicKey, ourXOnlyPublicKey, serverXOnlyPublicKey, input, output, arkInfo, refundFunc) => {
3104
3138
  const rawCheckpointTapscript = hex7.decode(arkInfo.checkpointTapscript);
3105
3139
  const serverUnrollScript = CSVMultisigTapscript2.decode(rawCheckpointTapscript);
@@ -3854,85 +3888,22 @@ var ArkadeSwaps = class _ArkadeSwaps {
3854
3888
  }
3855
3889
  const outputScript = ArkAddress2.decode(address).pkScript;
3856
3890
  const refundWithoutReceiverLeaf = vhtlcScript.refundWithoutReceiver();
3857
- const cltvSatisfied = isSubmarineRefundLocktimeReached(vhtlcTimeouts.refund);
3858
- let boltzCallCount = 0;
3859
- let sweptCount = 0;
3860
- let skippedCount = 0;
3861
- for (const vtxo of refundableVtxos) {
3862
- const isRecoverableVtxo = isRecoverable(vtxo);
3863
- const output = {
3864
- amount: BigInt(vtxo.value),
3865
- script: outputScript
3866
- };
3867
- if (cltvSatisfied) {
3868
- const input2 = {
3869
- ...vtxo,
3870
- tapLeafScript: refundWithoutReceiverLeaf,
3871
- tapTree: vhtlcScript.encode()
3872
- };
3873
- await this.joinBatch(
3874
- this.wallet.identity,
3875
- input2,
3876
- output,
3877
- arkInfo,
3878
- isRecoverableVtxo
3879
- );
3880
- sweptCount++;
3881
- continue;
3882
- }
3883
- if (isRecoverableVtxo) {
3884
- logger.error(
3885
- `Swap ${pendingSwap.id}: recoverable VTXO ${vtxo.txid}:${vtxo.vout} cannot be refunded yet \u2014 refundWithoutReceiver locktime has not passed (refundLocktime=${vhtlcTimeouts.refund}, currentTimestamp=${Math.floor(Date.now() / 1e3)}). Refund will be retried after locktime.`
3886
- );
3887
- skippedCount++;
3888
- continue;
3889
- }
3890
- const input = {
3891
- ...vtxo,
3892
- tapLeafScript: vhtlcScript.refund(),
3893
- tapTree: vhtlcScript.encode()
3894
- };
3895
- try {
3896
- if (boltzCallCount > 0) {
3897
- await new Promise((r) => setTimeout(r, 2e3));
3898
- }
3899
- boltzCallCount++;
3900
- await refundVHTLCwithOffchainTx(
3901
- pendingSwap.id,
3902
- this.wallet.identity,
3903
- this.arkProvider,
3904
- boltzXOnlyPublicKey,
3905
- ourXOnlyPublicKey,
3906
- serverXOnlyPublicKey,
3907
- input,
3908
- output,
3909
- arkInfo,
3910
- this.swapProvider.refundSubmarineSwap.bind(this.swapProvider)
3911
- );
3912
- sweptCount++;
3913
- } catch (error) {
3914
- if (!(error instanceof BoltzRefundError)) {
3915
- throw error;
3916
- }
3917
- if (!isSubmarineRefundLocktimeReached(vhtlcTimeouts.refund)) {
3918
- logger.error(
3919
- `Swap ${pendingSwap.id}: Boltz rejected VTXO outpoint and refundWithoutReceiver locktime has not passed yet (currentTimestamp=${Math.floor(Date.now() / 1e3)}, locktime=${vhtlcTimeouts.refund}). Refund will be retried after locktime.`
3920
- );
3921
- skippedCount++;
3922
- continue;
3923
- }
3924
- logger.warn(
3925
- `Swap ${pendingSwap.id}: Boltz rejected VTXO outpoint, falling back to refundWithoutReceiver via joinBatch`
3926
- );
3927
- const fallbackInput = {
3928
- ...vtxo,
3929
- tapLeafScript: refundWithoutReceiverLeaf,
3930
- tapTree: vhtlcScript.encode()
3931
- };
3932
- await this.joinBatch(this.wallet.identity, fallbackInput, output, arkInfo, false);
3933
- sweptCount++;
3934
- }
3935
- }
3891
+ const refundContext = {
3892
+ arkInfo,
3893
+ vhtlcScript,
3894
+ serverXOnlyPublicKey,
3895
+ refundWithoutReceiverLeaf,
3896
+ outputScript
3897
+ };
3898
+ const { swept: sweptCount, skipped: skippedCount } = await this.refundVtxos({
3899
+ swapId: pendingSwap.id,
3900
+ vtxos: refundableVtxos,
3901
+ refundLocktime: vhtlcTimeouts.refund,
3902
+ refundContext,
3903
+ boltzXOnlyPublicKey,
3904
+ ourXOnlyPublicKey,
3905
+ refundViaBoltz: this.swapProvider.refundSubmarineSwap.bind(this.swapProvider)
3906
+ });
3936
3907
  if (!isSubmarineSuccessStatus(pendingSwap.status)) {
3937
3908
  const fullyRefunded = skippedCount === 0;
3938
3909
  await updateSubmarineSwapStatus(
@@ -4490,7 +4461,10 @@ var ArkadeSwaps = class _ArkadeSwaps {
4490
4461
  * swap's ARK lockup address.
4491
4462
  *
4492
4463
  * Path selection per VTXO:
4493
- * - CLTV has elapsed → `refundWithoutReceiver` via `joinBatch` (no Boltz).
4464
+ * - CLTV elapsed, live VTXO → `refundWithoutReceiver` offchain (sender +
4465
+ * server, no Boltz, no batch round).
4466
+ * - CLTV elapsed, swept VTXO → `refundWithoutReceiver` via `joinBatch`
4467
+ * (a swept VTXO is no longer a live leaf).
4494
4468
  * - Pre-CLTV recoverable → skipped (Boltz can't co-sign swept-batch refund).
4495
4469
  * - Pre-CLTV non-recoverable → cooperative 3-of-3 refund via Boltz.
4496
4470
  *
@@ -4547,84 +4521,22 @@ var ArkadeSwaps = class _ArkadeSwaps {
4547
4521
  const outputScript = ArkAddress2.decode(address).pkScript;
4548
4522
  const refundWithoutReceiverLeaf = vhtlcScript.refundWithoutReceiver();
4549
4523
  const refundLocktime = pendingSwap.response.lockupDetails.timeouts.refund;
4550
- let boltzCallCount = 0;
4551
- let sweptCount = 0;
4552
- let skippedCount = 0;
4553
- for (const vtxo of unspentVtxos) {
4554
- const isRecoverableVtxo = isRecoverable(vtxo);
4555
- const output = {
4556
- amount: BigInt(vtxo.value),
4557
- script: outputScript
4558
- };
4559
- if (isSubmarineRefundLocktimeReached(refundLocktime)) {
4560
- const input2 = {
4561
- ...vtxo,
4562
- tapLeafScript: refundWithoutReceiverLeaf,
4563
- tapTree: vhtlcScript.encode()
4564
- };
4565
- await this.joinBatch(
4566
- this.wallet.identity,
4567
- input2,
4568
- output,
4569
- arkInfo,
4570
- isRecoverableVtxo
4571
- );
4572
- sweptCount++;
4573
- continue;
4574
- }
4575
- if (isRecoverableVtxo) {
4576
- logger.error(
4577
- `Swap ${pendingSwap.id}: recoverable VTXO ${vtxo.txid}:${vtxo.vout} cannot be refunded yet \u2014 refundWithoutReceiver locktime has not passed (refundLocktime=${refundLocktime}, currentTimestamp=${Math.floor(Date.now() / 1e3)}). Refund will be retried after locktime.`
4578
- );
4579
- skippedCount++;
4580
- continue;
4581
- }
4582
- const input = {
4583
- ...vtxo,
4584
- tapLeafScript: vhtlcScript.refund(),
4585
- tapTree: vhtlcScript.encode()
4586
- };
4587
- try {
4588
- if (boltzCallCount > 0) {
4589
- await new Promise((r) => setTimeout(r, 2e3));
4590
- }
4591
- boltzCallCount++;
4592
- await refundVHTLCwithOffchainTx(
4593
- pendingSwap.id,
4594
- this.wallet.identity,
4595
- this.arkProvider,
4596
- boltzXOnlyPublicKey,
4597
- ourXOnlyPublicKey,
4598
- serverXOnlyPublicKey,
4599
- input,
4600
- output,
4601
- arkInfo,
4602
- this.swapProvider.refundChainSwap.bind(this.swapProvider)
4603
- );
4604
- sweptCount++;
4605
- } catch (error) {
4606
- if (!(error instanceof BoltzRefundError)) {
4607
- throw error;
4608
- }
4609
- if (!isSubmarineRefundLocktimeReached(refundLocktime)) {
4610
- logger.error(
4611
- `Swap ${pendingSwap.id}: Boltz rejected VTXO outpoint and refundWithoutReceiver locktime has not passed yet (currentTimestamp=${Math.floor(Date.now() / 1e3)}, locktime=${refundLocktime}). Refund will be retried after locktime.`
4612
- );
4613
- skippedCount++;
4614
- continue;
4615
- }
4616
- logger.warn(
4617
- `Swap ${pendingSwap.id}: Boltz rejected VTXO outpoint, falling back to refundWithoutReceiver via joinBatch`
4618
- );
4619
- const fallbackInput = {
4620
- ...vtxo,
4621
- tapLeafScript: refundWithoutReceiverLeaf,
4622
- tapTree: vhtlcScript.encode()
4623
- };
4624
- await this.joinBatch(this.wallet.identity, fallbackInput, output, arkInfo, false);
4625
- sweptCount++;
4626
- }
4627
- }
4524
+ const refundContext = {
4525
+ arkInfo,
4526
+ vhtlcScript,
4527
+ serverXOnlyPublicKey,
4528
+ refundWithoutReceiverLeaf,
4529
+ outputScript
4530
+ };
4531
+ const { swept: sweptCount, skipped: skippedCount } = await this.refundVtxos({
4532
+ swapId: pendingSwap.id,
4533
+ vtxos: unspentVtxos,
4534
+ refundLocktime,
4535
+ refundContext,
4536
+ boltzXOnlyPublicKey,
4537
+ ourXOnlyPublicKey,
4538
+ refundViaBoltz: this.swapProvider.refundChainSwap.bind(this.swapProvider)
4539
+ });
4628
4540
  const finalStatus = await this.getSwapStatus(pendingSwap.id);
4629
4541
  await this.savePendingChainSwap({
4630
4542
  ...pendingSwap,
@@ -5157,6 +5069,120 @@ var ArkadeSwaps = class _ArkadeSwaps {
5157
5069
  async joinBatch(identity, input, output, arkInfo, isRecoverable2 = true) {
5158
5070
  return joinBatch(this.arkProvider, identity, input, output, arkInfo, isRecoverable2);
5159
5071
  }
5072
+ /**
5073
+ * Settle a `refundWithoutReceiver` (sender + server, no Boltz) refund for a
5074
+ * single VTXO whose CLTV refund locktime has elapsed.
5075
+ *
5076
+ * A live VTXO settles the leaf with an offchain Ark tx — no batch round. A
5077
+ * swept (recoverable) VTXO is no longer a live leaf, so it can only be
5078
+ * reclaimed by re-registering it into a batch.
5079
+ */
5080
+ async settleRefundWithoutReceiver(ctx, vtxo) {
5081
+ const input = {
5082
+ ...vtxo,
5083
+ tapLeafScript: ctx.refundWithoutReceiverLeaf,
5084
+ tapTree: ctx.vhtlcScript.encode()
5085
+ };
5086
+ const output = { amount: BigInt(vtxo.value), script: ctx.outputScript };
5087
+ if (isRecoverable(vtxo)) {
5088
+ await this.joinBatch(this.wallet.identity, input, output, ctx.arkInfo, true);
5089
+ } else {
5090
+ await refundWithoutReceiverVHTLCwithOffchainTx(
5091
+ this.wallet.identity,
5092
+ ctx.vhtlcScript,
5093
+ ctx.serverXOnlyPublicKey,
5094
+ input,
5095
+ output,
5096
+ ctx.arkInfo,
5097
+ this.arkProvider
5098
+ );
5099
+ }
5100
+ }
5101
+ /**
5102
+ * Refund every VTXO at a swap's VHTLC address back to the wallet, shared by
5103
+ * {@link ArkadeSwaps.refundVHTLC} (submarine) and {@link ArkadeSwaps.refundArk}
5104
+ * (chain). Path selection per VTXO:
5105
+ * - CLTV elapsed → `refundWithoutReceiver` (offchain for a live VTXO, via a
5106
+ * batch round for a swept one — see {@link settleRefundWithoutReceiver}).
5107
+ * - Pre-CLTV recoverable → skipped (Boltz can't co-sign a swept-batch refund).
5108
+ * - Pre-CLTV non-recoverable → cooperative 3-of-3 refund via Boltz, falling
5109
+ * back to `refundWithoutReceiver` offchain if Boltz rejects after the
5110
+ * locktime has since elapsed.
5111
+ *
5112
+ * @returns Counts of VTXOs swept vs. deferred.
5113
+ */
5114
+ async refundVtxos(params) {
5115
+ const {
5116
+ swapId,
5117
+ vtxos,
5118
+ refundLocktime,
5119
+ refundContext,
5120
+ boltzXOnlyPublicKey,
5121
+ ourXOnlyPublicKey,
5122
+ refundViaBoltz
5123
+ } = params;
5124
+ const { vhtlcScript, serverXOnlyPublicKey, arkInfo, outputScript } = refundContext;
5125
+ let boltzCallCount = 0;
5126
+ let sweptCount = 0;
5127
+ let skippedCount = 0;
5128
+ for (const vtxo of vtxos) {
5129
+ const isRecoverableVtxo = isRecoverable(vtxo);
5130
+ const output = { amount: BigInt(vtxo.value), script: outputScript };
5131
+ if (isSubmarineRefundLocktimeReached(refundLocktime)) {
5132
+ await this.settleRefundWithoutReceiver(refundContext, vtxo);
5133
+ sweptCount++;
5134
+ continue;
5135
+ }
5136
+ if (isRecoverableVtxo) {
5137
+ logger.error(
5138
+ `Swap ${swapId}: recoverable VTXO ${vtxo.txid}:${vtxo.vout} cannot be refunded yet \u2014 refundWithoutReceiver locktime has not passed (refundLocktime=${refundLocktime}, currentTimestamp=${Math.floor(Date.now() / 1e3)}). Refund will be retried after locktime.`
5139
+ );
5140
+ skippedCount++;
5141
+ continue;
5142
+ }
5143
+ const input = {
5144
+ ...vtxo,
5145
+ tapLeafScript: vhtlcScript.refund(),
5146
+ tapTree: vhtlcScript.encode()
5147
+ };
5148
+ try {
5149
+ if (boltzCallCount > 0) {
5150
+ await new Promise((r) => setTimeout(r, 2e3));
5151
+ }
5152
+ boltzCallCount++;
5153
+ await refundVHTLCwithOffchainTx(
5154
+ swapId,
5155
+ this.wallet.identity,
5156
+ this.arkProvider,
5157
+ boltzXOnlyPublicKey,
5158
+ ourXOnlyPublicKey,
5159
+ serverXOnlyPublicKey,
5160
+ input,
5161
+ output,
5162
+ arkInfo,
5163
+ refundViaBoltz
5164
+ );
5165
+ sweptCount++;
5166
+ } catch (error) {
5167
+ if (!(error instanceof BoltzRefundError)) {
5168
+ throw error;
5169
+ }
5170
+ if (!isSubmarineRefundLocktimeReached(refundLocktime)) {
5171
+ logger.error(
5172
+ `Swap ${swapId}: Boltz rejected VTXO outpoint and refundWithoutReceiver locktime has not passed yet (currentTimestamp=${Math.floor(Date.now() / 1e3)}, locktime=${refundLocktime}). Refund will be retried after locktime.`
5173
+ );
5174
+ skippedCount++;
5175
+ continue;
5176
+ }
5177
+ logger.warn(
5178
+ `Swap ${swapId}: Boltz rejected VTXO outpoint, falling back to refundWithoutReceiver offchain`
5179
+ );
5180
+ await this.settleRefundWithoutReceiver(refundContext, vtxo);
5181
+ sweptCount++;
5182
+ }
5183
+ }
5184
+ return { swept: sweptCount, skipped: skippedCount };
5185
+ }
5160
5186
  /**
5161
5187
  * Creates a VHTLC script for the swap.
5162
5188
  * Works for submarine, reverse, and chain swaps.