@arkade-os/boltz-swap 0.3.22 → 0.3.24
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.
- package/README.md +22 -0
- package/dist/{arkade-swaps-DEvf-2g2.d.ts → arkade-swaps-CZF9XoFR.d.cts} +101 -16
- package/dist/{arkade-swaps-CvA3RP7_.d.cts → arkade-swaps-pfAgQUMP.d.ts} +101 -16
- package/dist/{background-EHOJZDKT.js → background-GCBCKLGY.js} +2 -2
- package/dist/{chunk-EQK2BJQC.js → chunk-FEXQELYZ.js} +1 -1
- package/dist/{chunk-K3QEFL7D.js → chunk-XC2ARJZO.js} +390 -70
- package/dist/expo/index.cjs +408 -73
- package/dist/expo/index.d.cts +8 -9
- package/dist/expo/index.d.ts +8 -9
- package/dist/expo/index.js +16 -4
- package/dist/index.cjs +515 -79
- package/dist/index.d.cts +46 -14
- package/dist/index.d.ts +46 -14
- package/dist/index.js +126 -10
- package/dist/repositories/realm/index.d.cts +1 -1
- package/dist/repositories/realm/index.d.ts +1 -1
- package/dist/repositories/sqlite/index.d.cts +1 -1
- package/dist/repositories/sqlite/index.d.ts +1 -1
- package/dist/{types-OyAdK824.d.cts → types-LCXS1AVA.d.cts} +63 -1
- package/dist/{types-OyAdK824.d.ts → types-LCXS1AVA.d.ts} +63 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -2762,6 +2762,10 @@ function createForfeitTx(input, forfeitOutputScript, connector) {
|
|
|
2762
2762
|
var import_legacy = require("@noble/hashes/legacy.js");
|
|
2763
2763
|
var import_btc_signer4 = require("@scure/btc-signer");
|
|
2764
2764
|
var import_payment3 = require("@scure/btc-signer/payment.js");
|
|
2765
|
+
var toBip68RelativeTimelock = (value) => ({
|
|
2766
|
+
type: value < 512 ? "blocks" : "seconds",
|
|
2767
|
+
value: BigInt(value)
|
|
2768
|
+
});
|
|
2765
2769
|
var createVHTLCScript = (args) => {
|
|
2766
2770
|
const {
|
|
2767
2771
|
network,
|
|
@@ -2769,7 +2773,7 @@ var createVHTLCScript = (args) => {
|
|
|
2769
2773
|
receiverPubkey,
|
|
2770
2774
|
senderPubkey,
|
|
2771
2775
|
serverPubkey,
|
|
2772
|
-
timeoutBlockHeights
|
|
2776
|
+
timeoutBlockHeights: vhtlcTimeouts
|
|
2773
2777
|
} = args;
|
|
2774
2778
|
const receiverXOnlyPublicKey = normalizeToXOnlyKey(
|
|
2775
2779
|
import_base8.hex.decode(receiverPubkey),
|
|
@@ -2783,27 +2787,21 @@ var createVHTLCScript = (args) => {
|
|
|
2783
2787
|
import_base8.hex.decode(serverPubkey),
|
|
2784
2788
|
"server"
|
|
2785
2789
|
);
|
|
2786
|
-
const delayType = (num) => num < 512 ? "blocks" : "seconds";
|
|
2787
2790
|
const vhtlcScript = new import_sdk7.VHTLC.Script({
|
|
2788
2791
|
preimageHash: (0, import_legacy.ripemd160)(preimageHash),
|
|
2789
2792
|
sender: senderXOnlyPublicKey,
|
|
2790
2793
|
receiver: receiverXOnlyPublicKey,
|
|
2791
2794
|
server: serverXOnlyPublicKey,
|
|
2792
|
-
refundLocktime: BigInt(
|
|
2793
|
-
unilateralClaimDelay:
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
type: delayType(
|
|
2803
|
-
timeoutBlockHeights.unilateralRefundWithoutReceiver
|
|
2804
|
-
),
|
|
2805
|
-
value: BigInt(timeoutBlockHeights.unilateralRefundWithoutReceiver)
|
|
2806
|
-
}
|
|
2795
|
+
refundLocktime: BigInt(vhtlcTimeouts.refund),
|
|
2796
|
+
unilateralClaimDelay: toBip68RelativeTimelock(
|
|
2797
|
+
vhtlcTimeouts.unilateralClaim
|
|
2798
|
+
),
|
|
2799
|
+
unilateralRefundDelay: toBip68RelativeTimelock(
|
|
2800
|
+
vhtlcTimeouts.unilateralRefund
|
|
2801
|
+
),
|
|
2802
|
+
unilateralRefundWithoutReceiverDelay: toBip68RelativeTimelock(
|
|
2803
|
+
vhtlcTimeouts.unilateralRefundWithoutReceiver
|
|
2804
|
+
)
|
|
2807
2805
|
});
|
|
2808
2806
|
if (!vhtlcScript.claimScript)
|
|
2809
2807
|
throw new Error("Failed to create VHTLC script");
|
|
@@ -3042,6 +3040,20 @@ function scriptFromTapLeafScript(leaf) {
|
|
|
3042
3040
|
}
|
|
3043
3041
|
|
|
3044
3042
|
// src/arkade-swaps.ts
|
|
3043
|
+
var dedupeVtxos = (vtxos) => [
|
|
3044
|
+
...new Map(
|
|
3045
|
+
vtxos.map((vtxo) => [`${vtxo.txid}:${vtxo.vout}`, vtxo])
|
|
3046
|
+
).values()
|
|
3047
|
+
];
|
|
3048
|
+
var hasNonEmptyString = (value) => typeof value === "string" && value.length > 0;
|
|
3049
|
+
var canRecoverViaBoltz3of3 = (refundableVtxos, swap) => {
|
|
3050
|
+
const hasRequiredSwapMetadata = hasNonEmptyString(swap.id) && hasNonEmptyString(swap.request.refundPublicKey) && hasNonEmptyString(swap.response.address) && hasNonEmptyString(swap.response.claimPublicKey) && !!swap.response.timeoutBlockHeights;
|
|
3051
|
+
if (!hasRequiredSwapMetadata) return false;
|
|
3052
|
+
return refundableVtxos.some(
|
|
3053
|
+
(vtxo) => !vtxo.isSpent && !(0, import_sdk8.isRecoverable)(vtxo)
|
|
3054
|
+
);
|
|
3055
|
+
};
|
|
3056
|
+
var isSubmarineRefundLocktimeReached = (refundTimestamp) => Math.floor(Date.now() / 1e3) >= refundTimestamp;
|
|
3045
3057
|
var CLAIM_VTXO_RETRY_ATTEMPTS = 3;
|
|
3046
3058
|
var CLAIM_VTXO_RETRY_DELAY_MS = 500;
|
|
3047
3059
|
var ArkadeSwaps = class _ArkadeSwaps {
|
|
@@ -3309,8 +3321,12 @@ var ArkadeSwaps = class _ArkadeSwaps {
|
|
|
3309
3321
|
throw new Error(
|
|
3310
3322
|
`Swap ${pendingSwap.id}: preimage is required to claim VHTLC`
|
|
3311
3323
|
);
|
|
3312
|
-
const {
|
|
3313
|
-
|
|
3324
|
+
const {
|
|
3325
|
+
refundPublicKey,
|
|
3326
|
+
lockupAddress,
|
|
3327
|
+
timeoutBlockHeights: vhtlcTimeouts
|
|
3328
|
+
} = pendingSwap.response;
|
|
3329
|
+
if (!refundPublicKey || !lockupAddress || !vhtlcTimeouts)
|
|
3314
3330
|
throw new Error(
|
|
3315
3331
|
`Swap ${pendingSwap.id}: incomplete reverse swap response`
|
|
3316
3332
|
);
|
|
@@ -3338,7 +3354,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
|
|
|
3338
3354
|
receiverPubkey: import_base9.hex.encode(receiverXOnly),
|
|
3339
3355
|
senderPubkey: import_base9.hex.encode(senderXOnly),
|
|
3340
3356
|
serverPubkey: import_base9.hex.encode(serverXOnly),
|
|
3341
|
-
timeoutBlockHeights
|
|
3357
|
+
timeoutBlockHeights: vhtlcTimeouts
|
|
3342
3358
|
});
|
|
3343
3359
|
if (!vhtlcScript.claimScript)
|
|
3344
3360
|
throw new Error(
|
|
@@ -3566,84 +3582,184 @@ var ArkadeSwaps = class _ArkadeSwaps {
|
|
|
3566
3582
|
return pendingSwap;
|
|
3567
3583
|
}
|
|
3568
3584
|
/**
|
|
3569
|
-
*
|
|
3570
|
-
*
|
|
3571
|
-
*
|
|
3572
|
-
*
|
|
3585
|
+
* Reconstruct a submarine swap's VHTLC script from stored data. This does
|
|
3586
|
+
* not query the indexer, so bulk scans can build every script first and
|
|
3587
|
+
* then use batched VTXO lookups.
|
|
3588
|
+
*
|
|
3589
|
+
* @throws {Error} If preimage hash is unavailable, the swap response is
|
|
3590
|
+
* incomplete, the script can't be built, or the reconstructed address
|
|
3591
|
+
* doesn't match the one Boltz returned.
|
|
3573
3592
|
*/
|
|
3574
|
-
async
|
|
3575
|
-
const preimageHash =
|
|
3593
|
+
async buildSubmarineVHTLCContext(swap, arkInfo) {
|
|
3594
|
+
const preimageHash = swap.request.invoice ? getInvoicePaymentHash(swap.request.invoice) : swap.preimageHash;
|
|
3576
3595
|
if (!preimageHash)
|
|
3577
3596
|
throw new Error(
|
|
3578
|
-
`Swap ${
|
|
3597
|
+
`Swap ${swap.id}: preimage hash is required to refund VHTLC`
|
|
3579
3598
|
);
|
|
3580
|
-
const
|
|
3581
|
-
const address = await this.wallet.getAddress();
|
|
3582
|
-
if (!address) throw new Error("Failed to get ark address from wallet");
|
|
3599
|
+
const resolvedArkInfo = arkInfo ?? await this.arkProvider.getInfo();
|
|
3583
3600
|
const ourXOnlyPublicKey = normalizeToXOnlyKey(
|
|
3584
3601
|
await this.wallet.identity.xOnlyPublicKey(),
|
|
3585
3602
|
"our",
|
|
3586
|
-
|
|
3603
|
+
swap.id
|
|
3587
3604
|
);
|
|
3588
3605
|
const serverXOnlyPublicKey = normalizeToXOnlyKey(
|
|
3589
|
-
import_base9.hex.decode(
|
|
3606
|
+
import_base9.hex.decode(resolvedArkInfo.signerPubkey),
|
|
3590
3607
|
"server",
|
|
3591
|
-
|
|
3608
|
+
swap.id
|
|
3592
3609
|
);
|
|
3593
|
-
const { claimPublicKey, timeoutBlockHeights } =
|
|
3594
|
-
if (!claimPublicKey || !
|
|
3610
|
+
const { claimPublicKey, timeoutBlockHeights: vhtlcTimeouts } = swap.response;
|
|
3611
|
+
if (!claimPublicKey || !vhtlcTimeouts)
|
|
3595
3612
|
throw new Error(
|
|
3596
|
-
`Swap ${
|
|
3613
|
+
`Swap ${swap.id}: incomplete submarine swap response`
|
|
3597
3614
|
);
|
|
3598
3615
|
const boltzXOnlyPublicKey = normalizeToXOnlyKey(
|
|
3599
3616
|
import_base9.hex.decode(claimPublicKey),
|
|
3600
3617
|
"boltz",
|
|
3601
|
-
|
|
3618
|
+
swap.id
|
|
3602
3619
|
);
|
|
3603
3620
|
const { vhtlcScript, vhtlcAddress } = this.createVHTLCScript({
|
|
3604
|
-
network:
|
|
3621
|
+
network: resolvedArkInfo.network,
|
|
3605
3622
|
preimageHash: import_base9.hex.decode(preimageHash),
|
|
3606
3623
|
receiverPubkey: import_base9.hex.encode(boltzXOnlyPublicKey),
|
|
3607
3624
|
senderPubkey: import_base9.hex.encode(ourXOnlyPublicKey),
|
|
3608
3625
|
serverPubkey: import_base9.hex.encode(serverXOnlyPublicKey),
|
|
3609
|
-
timeoutBlockHeights
|
|
3626
|
+
timeoutBlockHeights: vhtlcTimeouts
|
|
3610
3627
|
});
|
|
3611
3628
|
if (!vhtlcScript.claimScript)
|
|
3612
3629
|
throw new Error(
|
|
3613
|
-
`Swap ${
|
|
3630
|
+
`Swap ${swap.id}: failed to create VHTLC script for submarine swap`
|
|
3614
3631
|
);
|
|
3615
|
-
if (vhtlcAddress !==
|
|
3632
|
+
if (vhtlcAddress !== swap.response.address)
|
|
3616
3633
|
throw new Error(
|
|
3617
|
-
`VHTLC address mismatch for swap ${
|
|
3634
|
+
`VHTLC address mismatch for swap ${swap.id}: expected ${swap.response.address}, got ${vhtlcAddress}`
|
|
3618
3635
|
);
|
|
3619
3636
|
const vhtlcPkScriptHex = import_base9.hex.encode(vhtlcScript.pkScript);
|
|
3637
|
+
return {
|
|
3638
|
+
arkInfo: resolvedArkInfo,
|
|
3639
|
+
vhtlcScript,
|
|
3640
|
+
vhtlcAddress,
|
|
3641
|
+
vhtlcPkScriptHex,
|
|
3642
|
+
vhtlcTimeouts,
|
|
3643
|
+
ourXOnlyPublicKey,
|
|
3644
|
+
serverXOnlyPublicKey,
|
|
3645
|
+
boltzXOnlyPublicKey
|
|
3646
|
+
};
|
|
3647
|
+
}
|
|
3648
|
+
/**
|
|
3649
|
+
* Reconstruct a submarine swap's VHTLC script from stored data and look
|
|
3650
|
+
* up its VTXOs at the indexer. Side-effect free; shared by `refundVHTLC`
|
|
3651
|
+
* (spending path) and `inspectSubmarineRecovery` (diagnostic path).
|
|
3652
|
+
*
|
|
3653
|
+
* `refundableVtxos` merges spendable + recoverable indexer queries
|
|
3654
|
+
* (deduped by outpoint). When that set is empty, a third query
|
|
3655
|
+
* populates `diagnostic` so callers can distinguish "never funded",
|
|
3656
|
+
* "already spent", and "preconfirmed-only".
|
|
3657
|
+
*/
|
|
3658
|
+
async lookupSubmarineVHTLC(swap, arkInfo) {
|
|
3659
|
+
const context = await this.buildSubmarineVHTLCContext(swap, arkInfo);
|
|
3620
3660
|
const [spendableResult, recoverableResult] = await Promise.all([
|
|
3621
3661
|
this.indexerProvider.getVtxos({
|
|
3622
|
-
scripts: [vhtlcPkScriptHex],
|
|
3662
|
+
scripts: [context.vhtlcPkScriptHex],
|
|
3623
3663
|
spendableOnly: true
|
|
3624
3664
|
}),
|
|
3625
3665
|
this.indexerProvider.getVtxos({
|
|
3626
|
-
scripts: [vhtlcPkScriptHex],
|
|
3666
|
+
scripts: [context.vhtlcPkScriptHex],
|
|
3627
3667
|
recoverableOnly: true
|
|
3628
3668
|
})
|
|
3629
3669
|
]);
|
|
3630
|
-
const refundableVtxos = [
|
|
3631
|
-
...
|
|
3632
|
-
|
|
3633
|
-
|
|
3634
|
-
|
|
3635
|
-
).values()
|
|
3636
|
-
];
|
|
3670
|
+
const refundableVtxos = dedupeVtxos([
|
|
3671
|
+
...spendableResult.vtxos,
|
|
3672
|
+
...recoverableResult.vtxos
|
|
3673
|
+
]);
|
|
3674
|
+
let diagnostic;
|
|
3637
3675
|
if (refundableVtxos.length === 0) {
|
|
3638
3676
|
const { vtxos: allVtxos } = await this.indexerProvider.getVtxos({
|
|
3639
|
-
scripts: [vhtlcPkScriptHex]
|
|
3677
|
+
scripts: [context.vhtlcPkScriptHex]
|
|
3640
3678
|
});
|
|
3641
|
-
|
|
3679
|
+
diagnostic = {
|
|
3680
|
+
totalVtxoCount: allVtxos.length,
|
|
3681
|
+
allSpent: allVtxos.length > 0 && allVtxos.every((vtxo) => vtxo.isSpent)
|
|
3682
|
+
};
|
|
3683
|
+
}
|
|
3684
|
+
return {
|
|
3685
|
+
...context,
|
|
3686
|
+
refundableVtxos,
|
|
3687
|
+
diagnostic
|
|
3688
|
+
};
|
|
3689
|
+
}
|
|
3690
|
+
submarineRecoveryInfoFromLookup(swap, lookup) {
|
|
3691
|
+
const { refundableVtxos, diagnostic, vhtlcTimeouts } = lookup;
|
|
3692
|
+
if (refundableVtxos.length > 0) {
|
|
3693
|
+
const cltvSatisfied = isSubmarineRefundLocktimeReached(
|
|
3694
|
+
vhtlcTimeouts.refund
|
|
3695
|
+
);
|
|
3696
|
+
const amountSats = refundableVtxos.reduce(
|
|
3697
|
+
(sum, vtxo) => sum + Number(vtxo.value),
|
|
3698
|
+
0
|
|
3699
|
+
);
|
|
3700
|
+
const isRecoverable2 = cltvSatisfied || canRecoverViaBoltz3of3(refundableVtxos, swap);
|
|
3701
|
+
return {
|
|
3702
|
+
swap,
|
|
3703
|
+
status: isRecoverable2 ? "recoverable" : "pre_cltv",
|
|
3704
|
+
vtxoCount: refundableVtxos.length,
|
|
3705
|
+
amountSats,
|
|
3706
|
+
refundLocktime: vhtlcTimeouts.refund
|
|
3707
|
+
};
|
|
3708
|
+
}
|
|
3709
|
+
if (!diagnostic || diagnostic.totalVtxoCount === 0) {
|
|
3710
|
+
return {
|
|
3711
|
+
swap,
|
|
3712
|
+
status: "none",
|
|
3713
|
+
vtxoCount: 0,
|
|
3714
|
+
amountSats: 0,
|
|
3715
|
+
refundLocktime: vhtlcTimeouts.refund
|
|
3716
|
+
};
|
|
3717
|
+
}
|
|
3718
|
+
if (diagnostic.allSpent) {
|
|
3719
|
+
return {
|
|
3720
|
+
swap,
|
|
3721
|
+
status: "already_spent",
|
|
3722
|
+
vtxoCount: 0,
|
|
3723
|
+
amountSats: 0,
|
|
3724
|
+
refundLocktime: vhtlcTimeouts.refund
|
|
3725
|
+
};
|
|
3726
|
+
}
|
|
3727
|
+
return {
|
|
3728
|
+
swap,
|
|
3729
|
+
status: "none",
|
|
3730
|
+
vtxoCount: 0,
|
|
3731
|
+
amountSats: 0,
|
|
3732
|
+
refundLocktime: vhtlcTimeouts.refund
|
|
3733
|
+
};
|
|
3734
|
+
}
|
|
3735
|
+
/**
|
|
3736
|
+
* Refunds the VHTLC for a failed submarine swap, returning locked funds to the wallet.
|
|
3737
|
+
* Uses multi-party signatures (user + Boltz + server) for non-recoverable VTXOs.
|
|
3738
|
+
* @param pendingSwap - The submarine swap to refund.
|
|
3739
|
+
* @returns Counts of VTXOs swept vs. deferred. A return value of `{ swept: 0, skipped: N }`
|
|
3740
|
+
* means the call was a no-op — callers should not treat it as a successful refund.
|
|
3741
|
+
* @throws {Error} If preimage hash is unavailable, VHTLC not found, or already spent.
|
|
3742
|
+
*/
|
|
3743
|
+
async refundVHTLC(pendingSwap, cachedArkInfo) {
|
|
3744
|
+
const address = await this.wallet.getAddress();
|
|
3745
|
+
if (!address) throw new Error("Failed to get ark address from wallet");
|
|
3746
|
+
const {
|
|
3747
|
+
arkInfo,
|
|
3748
|
+
vhtlcScript,
|
|
3749
|
+
vhtlcTimeouts,
|
|
3750
|
+
ourXOnlyPublicKey,
|
|
3751
|
+
serverXOnlyPublicKey,
|
|
3752
|
+
boltzXOnlyPublicKey,
|
|
3753
|
+
refundableVtxos,
|
|
3754
|
+
diagnostic
|
|
3755
|
+
} = await this.lookupSubmarineVHTLC(pendingSwap, cachedArkInfo);
|
|
3756
|
+
if (refundableVtxos.length === 0) {
|
|
3757
|
+
if (!diagnostic || diagnostic.totalVtxoCount === 0) {
|
|
3642
3758
|
throw new Error(
|
|
3643
3759
|
`Swap ${pendingSwap.id}: VHTLC not found for address ${pendingSwap.response.address}`
|
|
3644
3760
|
);
|
|
3645
3761
|
}
|
|
3646
|
-
if (
|
|
3762
|
+
if (diagnostic.allSpent) {
|
|
3647
3763
|
throw new Error(
|
|
3648
3764
|
`Swap ${pendingSwap.id}: VHTLC is already spent`
|
|
3649
3765
|
);
|
|
@@ -3654,10 +3770,11 @@ var ArkadeSwaps = class _ArkadeSwaps {
|
|
|
3654
3770
|
}
|
|
3655
3771
|
const outputScript = import_sdk8.ArkAddress.decode(address).pkScript;
|
|
3656
3772
|
const refundWithoutReceiverLeaf = vhtlcScript.refundWithoutReceiver();
|
|
3657
|
-
const
|
|
3658
|
-
|
|
3659
|
-
|
|
3773
|
+
const cltvSatisfied = isSubmarineRefundLocktimeReached(
|
|
3774
|
+
vhtlcTimeouts.refund
|
|
3775
|
+
);
|
|
3660
3776
|
let boltzCallCount = 0;
|
|
3777
|
+
let sweptCount = 0;
|
|
3661
3778
|
let skippedCount = 0;
|
|
3662
3779
|
for (const vtxo of refundableVtxos) {
|
|
3663
3780
|
const isRecoverableVtxo = (0, import_sdk8.isRecoverable)(vtxo);
|
|
@@ -3678,11 +3795,12 @@ var ArkadeSwaps = class _ArkadeSwaps {
|
|
|
3678
3795
|
arkInfo,
|
|
3679
3796
|
isRecoverableVtxo
|
|
3680
3797
|
);
|
|
3798
|
+
sweptCount++;
|
|
3681
3799
|
continue;
|
|
3682
3800
|
}
|
|
3683
3801
|
if (isRecoverableVtxo) {
|
|
3684
3802
|
logger.error(
|
|
3685
|
-
`Swap ${pendingSwap.id}: recoverable VTXO ${vtxo.txid}:${vtxo.vout} cannot be refunded yet \u2014 refundWithoutReceiver locktime has not passed (refundLocktime=${
|
|
3803
|
+
`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.`
|
|
3686
3804
|
);
|
|
3687
3805
|
skippedCount++;
|
|
3688
3806
|
continue;
|
|
@@ -3711,14 +3829,14 @@ var ArkadeSwaps = class _ArkadeSwaps {
|
|
|
3711
3829
|
)
|
|
3712
3830
|
);
|
|
3713
3831
|
boltzCallCount++;
|
|
3832
|
+
sweptCount++;
|
|
3714
3833
|
} catch (error) {
|
|
3715
3834
|
if (!(error instanceof BoltzRefundError)) {
|
|
3716
3835
|
throw error;
|
|
3717
3836
|
}
|
|
3718
|
-
|
|
3719
|
-
if (BigInt(tipNow) < refundLocktime) {
|
|
3837
|
+
if (!isSubmarineRefundLocktimeReached(vhtlcTimeouts.refund)) {
|
|
3720
3838
|
logger.error(
|
|
3721
|
-
`Swap ${pendingSwap.id}: Boltz rejected VTXO outpoint and refundWithoutReceiver locktime has not passed yet (
|
|
3839
|
+
`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.`
|
|
3722
3840
|
);
|
|
3723
3841
|
skippedCount++;
|
|
3724
3842
|
continue;
|
|
@@ -3738,16 +3856,218 @@ var ArkadeSwaps = class _ArkadeSwaps {
|
|
|
3738
3856
|
arkInfo,
|
|
3739
3857
|
false
|
|
3740
3858
|
);
|
|
3859
|
+
sweptCount++;
|
|
3741
3860
|
}
|
|
3742
3861
|
}
|
|
3743
|
-
|
|
3744
|
-
|
|
3745
|
-
|
|
3746
|
-
|
|
3747
|
-
|
|
3748
|
-
|
|
3749
|
-
|
|
3862
|
+
if (!isSubmarineSuccessStatus(pendingSwap.status)) {
|
|
3863
|
+
const fullyRefunded = skippedCount === 0;
|
|
3864
|
+
await updateSubmarineSwapStatus(
|
|
3865
|
+
pendingSwap,
|
|
3866
|
+
pendingSwap.status,
|
|
3867
|
+
// Keep current status
|
|
3868
|
+
this.savePendingSubmarineSwap.bind(this),
|
|
3869
|
+
{ refundable: true, refunded: fullyRefunded }
|
|
3870
|
+
);
|
|
3871
|
+
}
|
|
3872
|
+
return { swept: sweptCount, skipped: skippedCount };
|
|
3873
|
+
}
|
|
3874
|
+
/**
|
|
3875
|
+
* Inspect a submarine swap's lockup address for recoverable funds.
|
|
3876
|
+
*
|
|
3877
|
+
* Side-effect free. Returns a structured snapshot the UI can use to
|
|
3878
|
+
* decide whether to offer the user a recovery action — it will not
|
|
3879
|
+
* trigger any signing or persistence.
|
|
3880
|
+
*
|
|
3881
|
+
* Only `transaction.claimed` (success with possible stranded extras)
|
|
3882
|
+
* and refundable failure statuses are recovery candidates. Pending
|
|
3883
|
+
* statuses (`invoice.set`, `transaction.mempool`, …) are returned as
|
|
3884
|
+
* `invalid_swap`; this API is for recovery, not a generic VTXO probe.
|
|
3885
|
+
*
|
|
3886
|
+
* @param swap - The submarine swap to inspect.
|
|
3887
|
+
*/
|
|
3888
|
+
async inspectSubmarineRecovery(swap) {
|
|
3889
|
+
if (!isSubmarineSuccessStatus(swap.status) && !isSubmarineRefundableStatus(swap.status)) {
|
|
3890
|
+
return {
|
|
3891
|
+
swap,
|
|
3892
|
+
status: "invalid_swap",
|
|
3893
|
+
vtxoCount: 0,
|
|
3894
|
+
amountSats: 0,
|
|
3895
|
+
refundLocktime: swap.response.timeoutBlockHeights?.refund,
|
|
3896
|
+
error: `Swap status ${swap.status} is not a recovery candidate`
|
|
3897
|
+
};
|
|
3898
|
+
}
|
|
3899
|
+
let lookup;
|
|
3900
|
+
try {
|
|
3901
|
+
lookup = await this.lookupSubmarineVHTLC(swap);
|
|
3902
|
+
} catch (err) {
|
|
3903
|
+
return {
|
|
3904
|
+
swap,
|
|
3905
|
+
status: "invalid_swap",
|
|
3906
|
+
vtxoCount: 0,
|
|
3907
|
+
amountSats: 0,
|
|
3908
|
+
refundLocktime: swap.response.timeoutBlockHeights?.refund,
|
|
3909
|
+
error: err instanceof Error ? err.message : String(err)
|
|
3910
|
+
};
|
|
3911
|
+
}
|
|
3912
|
+
return this.submarineRecoveryInfoFromLookup(swap, lookup);
|
|
3913
|
+
}
|
|
3914
|
+
/**
|
|
3915
|
+
* Scan all locally-known submarine swaps for recoverable VHTLC funds.
|
|
3916
|
+
*
|
|
3917
|
+
* Loads submarine swaps from the repository, filters to recovery
|
|
3918
|
+
* candidates (`transaction.claimed` plus refundable failure
|
|
3919
|
+
* statuses), reconstructs their scripts, and performs one batched
|
|
3920
|
+
* spendable query plus one batched recoverable query. Pending swaps are
|
|
3921
|
+
* skipped entirely — they appear in the local repository but cannot
|
|
3922
|
+
* be in a recovery state yet.
|
|
3923
|
+
*
|
|
3924
|
+
* Side-effect free: does not mutate the repository, does not sign,
|
|
3925
|
+
* and does not query Boltz swap status.
|
|
3926
|
+
*/
|
|
3927
|
+
async scanRecoverableSubmarineSwaps() {
|
|
3928
|
+
const submarineSwaps = await this.swapRepository.getAllSwaps({
|
|
3929
|
+
type: "submarine"
|
|
3930
|
+
});
|
|
3931
|
+
const candidates = submarineSwaps.filter(
|
|
3932
|
+
(swap) => isSubmarineSuccessStatus(swap.status) || isSubmarineRefundableStatus(swap.status)
|
|
3750
3933
|
);
|
|
3934
|
+
let arkInfo;
|
|
3935
|
+
let arkInfoError;
|
|
3936
|
+
if (candidates.length > 0) {
|
|
3937
|
+
try {
|
|
3938
|
+
arkInfo = await this.arkProvider.getInfo();
|
|
3939
|
+
} catch (err) {
|
|
3940
|
+
arkInfoError = err instanceof Error ? err.message : String(err);
|
|
3941
|
+
}
|
|
3942
|
+
}
|
|
3943
|
+
const prepared = await Promise.all(
|
|
3944
|
+
candidates.map(async (swap) => {
|
|
3945
|
+
if (arkInfoError) {
|
|
3946
|
+
return {
|
|
3947
|
+
swap,
|
|
3948
|
+
error: arkInfoError
|
|
3949
|
+
};
|
|
3950
|
+
}
|
|
3951
|
+
try {
|
|
3952
|
+
return {
|
|
3953
|
+
swap,
|
|
3954
|
+
context: await this.buildSubmarineVHTLCContext(
|
|
3955
|
+
swap,
|
|
3956
|
+
arkInfo
|
|
3957
|
+
)
|
|
3958
|
+
};
|
|
3959
|
+
} catch (err) {
|
|
3960
|
+
return {
|
|
3961
|
+
swap,
|
|
3962
|
+
error: err instanceof Error ? err.message : String(err)
|
|
3963
|
+
};
|
|
3964
|
+
}
|
|
3965
|
+
})
|
|
3966
|
+
);
|
|
3967
|
+
const valid = prepared.filter(
|
|
3968
|
+
(item) => "context" in item
|
|
3969
|
+
);
|
|
3970
|
+
const scripts = [
|
|
3971
|
+
...new Set(valid.map(({ context }) => context.vhtlcPkScriptHex))
|
|
3972
|
+
];
|
|
3973
|
+
const refundableByScript = /* @__PURE__ */ new Map();
|
|
3974
|
+
if (scripts.length > 0) {
|
|
3975
|
+
const [spendableResult, recoverableResult] = await Promise.all([
|
|
3976
|
+
this.indexerProvider.getVtxos({
|
|
3977
|
+
scripts,
|
|
3978
|
+
spendableOnly: true
|
|
3979
|
+
}),
|
|
3980
|
+
this.indexerProvider.getVtxos({
|
|
3981
|
+
scripts,
|
|
3982
|
+
recoverableOnly: true
|
|
3983
|
+
})
|
|
3984
|
+
]);
|
|
3985
|
+
for (const vtxo of dedupeVtxos([
|
|
3986
|
+
...spendableResult.vtxos,
|
|
3987
|
+
...recoverableResult.vtxos
|
|
3988
|
+
])) {
|
|
3989
|
+
const script = vtxo.script?.toLowerCase();
|
|
3990
|
+
if (!script) continue;
|
|
3991
|
+
const existing = refundableByScript.get(script) ?? [];
|
|
3992
|
+
existing.push(vtxo);
|
|
3993
|
+
refundableByScript.set(script, existing);
|
|
3994
|
+
}
|
|
3995
|
+
}
|
|
3996
|
+
return prepared.map((item) => {
|
|
3997
|
+
if ("error" in item) {
|
|
3998
|
+
return {
|
|
3999
|
+
swap: item.swap,
|
|
4000
|
+
status: "invalid_swap",
|
|
4001
|
+
vtxoCount: 0,
|
|
4002
|
+
amountSats: 0,
|
|
4003
|
+
refundLocktime: item.swap.response.timeoutBlockHeights?.refund,
|
|
4004
|
+
error: item.error
|
|
4005
|
+
};
|
|
4006
|
+
}
|
|
4007
|
+
const refundableVtxos = refundableByScript.get(
|
|
4008
|
+
item.context.vhtlcPkScriptHex.toLowerCase()
|
|
4009
|
+
) ?? [];
|
|
4010
|
+
return this.submarineRecoveryInfoFromLookup(item.swap, {
|
|
4011
|
+
...item.context,
|
|
4012
|
+
refundableVtxos
|
|
4013
|
+
});
|
|
4014
|
+
});
|
|
4015
|
+
}
|
|
4016
|
+
/**
|
|
4017
|
+
* Recover funds locked at a single submarine swap's VHTLC address.
|
|
4018
|
+
*
|
|
4019
|
+
* Thin wrapper around `refundVHTLC` for callers that have already
|
|
4020
|
+
* confirmed (e.g. via `inspectSubmarineRecovery`) that funds are
|
|
4021
|
+
* present. Centralises the spending logic in one place — flag-write
|
|
4022
|
+
* behavior matches `refundVHTLC` (no-op for `transaction.claimed`,
|
|
4023
|
+
* normal flag updates for failure statuses).
|
|
4024
|
+
*/
|
|
4025
|
+
async recoverSubmarineFunds(swap, arkInfo) {
|
|
4026
|
+
return this.refundVHTLC(swap, arkInfo);
|
|
4027
|
+
}
|
|
4028
|
+
/**
|
|
4029
|
+
* Recover funds for a batch of submarine swaps.
|
|
4030
|
+
*
|
|
4031
|
+
* Each swap's recovery is independent — a failure on one swap does
|
|
4032
|
+
* not abort the rest, and the caller receives a per-swap result so
|
|
4033
|
+
* they can present partial outcomes in the UI. Recovery runs
|
|
4034
|
+
* sequentially to avoid hammering Boltz / the indexer with parallel
|
|
4035
|
+
* batch joins.
|
|
4036
|
+
*/
|
|
4037
|
+
async recoverAllSubmarineFunds(swaps) {
|
|
4038
|
+
const results = [];
|
|
4039
|
+
let arkInfo;
|
|
4040
|
+
try {
|
|
4041
|
+
if (swaps.length > 0) {
|
|
4042
|
+
arkInfo = await this.arkProvider.getInfo();
|
|
4043
|
+
}
|
|
4044
|
+
} catch (err) {
|
|
4045
|
+
const error = err instanceof Error ? err.message : String(err);
|
|
4046
|
+
return swaps.map((swap) => ({
|
|
4047
|
+
swapId: swap.id,
|
|
4048
|
+
recovered: false,
|
|
4049
|
+
skipped: false,
|
|
4050
|
+
error
|
|
4051
|
+
}));
|
|
4052
|
+
}
|
|
4053
|
+
for (const swap of swaps) {
|
|
4054
|
+
try {
|
|
4055
|
+
const outcome = await this.recoverSubmarineFunds(swap, arkInfo);
|
|
4056
|
+
results.push({
|
|
4057
|
+
swapId: swap.id,
|
|
4058
|
+
recovered: outcome.swept > 0,
|
|
4059
|
+
skipped: outcome.skipped > 0
|
|
4060
|
+
});
|
|
4061
|
+
} catch (err) {
|
|
4062
|
+
results.push({
|
|
4063
|
+
swapId: swap.id,
|
|
4064
|
+
recovered: false,
|
|
4065
|
+
skipped: false,
|
|
4066
|
+
error: err instanceof Error ? err.message : String(err)
|
|
4067
|
+
});
|
|
4068
|
+
}
|
|
4069
|
+
}
|
|
4070
|
+
return results;
|
|
3751
4071
|
}
|
|
3752
4072
|
/**
|
|
3753
4073
|
* Waits for a submarine swap's Lightning payment to settle.
|
|
@@ -4529,14 +4849,14 @@ var ArkadeSwaps = class _ArkadeSwaps {
|
|
|
4529
4849
|
const serverPubkey = import_base9.hex.encode(
|
|
4530
4850
|
normalizeToXOnlyKey(arkInfo.signerPubkey, "server")
|
|
4531
4851
|
);
|
|
4532
|
-
const
|
|
4852
|
+
const vhtlcTimeouts = to === "ARK" ? swap.response.claimDetails.timeouts : swap.response.lockupDetails.timeouts;
|
|
4533
4853
|
const { vhtlcAddress } = this.createVHTLCScript({
|
|
4534
4854
|
network: arkInfo.network,
|
|
4535
4855
|
preimageHash: import_base9.hex.decode(swap.request.preimageHash),
|
|
4536
4856
|
receiverPubkey,
|
|
4537
4857
|
senderPubkey,
|
|
4538
4858
|
serverPubkey,
|
|
4539
|
-
timeoutBlockHeights
|
|
4859
|
+
timeoutBlockHeights: vhtlcTimeouts
|
|
4540
4860
|
});
|
|
4541
4861
|
if (lockupAddress !== vhtlcAddress) {
|
|
4542
4862
|
throw new SwapError({
|
|
@@ -4880,6 +5200,25 @@ var ArkadeSwaps = class _ArkadeSwaps {
|
|
|
4880
5200
|
// src/serviceWorker/arkade-swaps-message-handler.ts
|
|
4881
5201
|
var import_sdk9 = require("@arkade-os/sdk");
|
|
4882
5202
|
var DEFAULT_MESSAGE_TAG = "ARKADE_SWAPS_UPDATER";
|
|
5203
|
+
var LONG_RUNNING_ARKADE_SWAPS_REQUEST_TYPES = /* @__PURE__ */ new Set([
|
|
5204
|
+
"SEND_LIGHTNING_PAYMENT",
|
|
5205
|
+
"CLAIM_VHTLC",
|
|
5206
|
+
"REFUND_VHTLC",
|
|
5207
|
+
"INSPECT_SUBMARINE_RECOVERY",
|
|
5208
|
+
"SCAN_RECOVERABLE_SUBMARINE_SWAPS",
|
|
5209
|
+
"RECOVER_SUBMARINE_FUNDS",
|
|
5210
|
+
"RECOVER_ALL_SUBMARINE_FUNDS",
|
|
5211
|
+
"WAIT_AND_CLAIM",
|
|
5212
|
+
"WAIT_FOR_SWAP_SETTLEMENT",
|
|
5213
|
+
"RESTORE_SWAPS",
|
|
5214
|
+
"WAIT_AND_CLAIM_CHAIN",
|
|
5215
|
+
"WAIT_AND_CLAIM_ARK",
|
|
5216
|
+
"WAIT_AND_CLAIM_BTC",
|
|
5217
|
+
"CLAIM_ARK",
|
|
5218
|
+
"CLAIM_BTC",
|
|
5219
|
+
"REFUND_ARK",
|
|
5220
|
+
"SM-WAIT_FOR_COMPLETION"
|
|
5221
|
+
]);
|
|
4883
5222
|
var ArkadeSwapsMessageHandler = class _ArkadeSwapsMessageHandler {
|
|
4884
5223
|
constructor(swapRepository) {
|
|
4885
5224
|
this.swapRepository = swapRepository;
|
|
@@ -4921,6 +5260,14 @@ var ArkadeSwapsMessageHandler = class _ArkadeSwapsMessageHandler {
|
|
|
4921
5260
|
async tick(_now) {
|
|
4922
5261
|
return [];
|
|
4923
5262
|
}
|
|
5263
|
+
// Flows that surrender control to Boltz, the Ark server, or other
|
|
5264
|
+
// participants in a batch round: quiet gaps between protocol events can
|
|
5265
|
+
// easily exceed the bus-level messageTimeoutMs. Liveness is covered
|
|
5266
|
+
// out-of-band by the page-side PING / MESSAGE_BUS_NOT_INITIALIZED path
|
|
5267
|
+
// triggered by concurrent short requests (GET_FEES, GET_SWAP_STATUS, ...).
|
|
5268
|
+
isLongRunning(message) {
|
|
5269
|
+
return LONG_RUNNING_ARKADE_SWAPS_REQUEST_TYPES.has(message.type);
|
|
5270
|
+
}
|
|
4924
5271
|
tagged(res) {
|
|
4925
5272
|
return {
|
|
4926
5273
|
...res,
|
|
@@ -5002,9 +5349,54 @@ var ArkadeSwapsMessageHandler = class _ArkadeSwapsMessageHandler {
|
|
|
5002
5349
|
case "CLAIM_VHTLC":
|
|
5003
5350
|
await this.handler.claimVHTLC(message.payload);
|
|
5004
5351
|
return this.tagged({ id, type: "VHTLC_CLAIMED" });
|
|
5005
|
-
case "REFUND_VHTLC":
|
|
5006
|
-
await this.handler.refundVHTLC(
|
|
5007
|
-
|
|
5352
|
+
case "REFUND_VHTLC": {
|
|
5353
|
+
const outcome = await this.handler.refundVHTLC(
|
|
5354
|
+
message.payload
|
|
5355
|
+
);
|
|
5356
|
+
return this.tagged({
|
|
5357
|
+
id,
|
|
5358
|
+
type: "VHTLC_REFUNDED",
|
|
5359
|
+
payload: outcome
|
|
5360
|
+
});
|
|
5361
|
+
}
|
|
5362
|
+
case "INSPECT_SUBMARINE_RECOVERY": {
|
|
5363
|
+
const info = await this.handler.inspectSubmarineRecovery(
|
|
5364
|
+
message.payload
|
|
5365
|
+
);
|
|
5366
|
+
return this.tagged({
|
|
5367
|
+
id,
|
|
5368
|
+
type: "SUBMARINE_RECOVERY_INSPECTED",
|
|
5369
|
+
payload: info
|
|
5370
|
+
});
|
|
5371
|
+
}
|
|
5372
|
+
case "SCAN_RECOVERABLE_SUBMARINE_SWAPS": {
|
|
5373
|
+
const infos = await this.handler.scanRecoverableSubmarineSwaps();
|
|
5374
|
+
return this.tagged({
|
|
5375
|
+
id,
|
|
5376
|
+
type: "RECOVERABLE_SUBMARINE_SWAPS_SCANNED",
|
|
5377
|
+
payload: infos
|
|
5378
|
+
});
|
|
5379
|
+
}
|
|
5380
|
+
case "RECOVER_SUBMARINE_FUNDS": {
|
|
5381
|
+
const outcome = await this.handler.recoverSubmarineFunds(
|
|
5382
|
+
message.payload
|
|
5383
|
+
);
|
|
5384
|
+
return this.tagged({
|
|
5385
|
+
id,
|
|
5386
|
+
type: "SUBMARINE_FUNDS_RECOVERED",
|
|
5387
|
+
payload: outcome
|
|
5388
|
+
});
|
|
5389
|
+
}
|
|
5390
|
+
case "RECOVER_ALL_SUBMARINE_FUNDS": {
|
|
5391
|
+
const results = await this.handler.recoverAllSubmarineFunds(
|
|
5392
|
+
message.payload
|
|
5393
|
+
);
|
|
5394
|
+
return this.tagged({
|
|
5395
|
+
id,
|
|
5396
|
+
type: "ALL_SUBMARINE_FUNDS_RECOVERED",
|
|
5397
|
+
payload: results
|
|
5398
|
+
});
|
|
5399
|
+
}
|
|
5008
5400
|
case "WAIT_AND_CLAIM": {
|
|
5009
5401
|
const res = await this.handler.waitAndClaim(
|
|
5010
5402
|
message.payload
|
|
@@ -5352,6 +5744,8 @@ var import_sdk10 = require("@arkade-os/sdk");
|
|
|
5352
5744
|
function isMessageBusNotInitializedError(error) {
|
|
5353
5745
|
return error instanceof Error && error.message.includes(import_sdk10.MESSAGE_BUS_NOT_INITIALIZED);
|
|
5354
5746
|
}
|
|
5747
|
+
var DEFAULT_MESSAGE_TIMEOUT_MS = 3e4;
|
|
5748
|
+
var NO_MESSAGE_TIMEOUT_MS = 0;
|
|
5355
5749
|
var DEDUPABLE_REQUEST_TYPES = /* @__PURE__ */ new Set([
|
|
5356
5750
|
"GET_FEES",
|
|
5357
5751
|
"GET_LIMITS",
|
|
@@ -5627,12 +6021,48 @@ var ServiceWorkerArkadeSwaps = class _ServiceWorkerArkadeSwaps {
|
|
|
5627
6021
|
});
|
|
5628
6022
|
}
|
|
5629
6023
|
async refundVHTLC(pendingSwap) {
|
|
5630
|
-
await this.sendMessage({
|
|
6024
|
+
const res = await this.sendMessage({
|
|
5631
6025
|
id: getRandomId(),
|
|
5632
6026
|
tag: this.messageTag,
|
|
5633
6027
|
type: "REFUND_VHTLC",
|
|
5634
6028
|
payload: pendingSwap
|
|
5635
6029
|
});
|
|
6030
|
+
return res.payload;
|
|
6031
|
+
}
|
|
6032
|
+
async inspectSubmarineRecovery(swap) {
|
|
6033
|
+
const res = await this.sendMessage({
|
|
6034
|
+
id: getRandomId(),
|
|
6035
|
+
tag: this.messageTag,
|
|
6036
|
+
type: "INSPECT_SUBMARINE_RECOVERY",
|
|
6037
|
+
payload: swap
|
|
6038
|
+
});
|
|
6039
|
+
return res.payload;
|
|
6040
|
+
}
|
|
6041
|
+
async scanRecoverableSubmarineSwaps() {
|
|
6042
|
+
const res = await this.sendMessage({
|
|
6043
|
+
id: getRandomId(),
|
|
6044
|
+
tag: this.messageTag,
|
|
6045
|
+
type: "SCAN_RECOVERABLE_SUBMARINE_SWAPS"
|
|
6046
|
+
});
|
|
6047
|
+
return res.payload;
|
|
6048
|
+
}
|
|
6049
|
+
async recoverSubmarineFunds(swap) {
|
|
6050
|
+
const res = await this.sendMessage({
|
|
6051
|
+
id: getRandomId(),
|
|
6052
|
+
tag: this.messageTag,
|
|
6053
|
+
type: "RECOVER_SUBMARINE_FUNDS",
|
|
6054
|
+
payload: swap
|
|
6055
|
+
});
|
|
6056
|
+
return res.payload;
|
|
6057
|
+
}
|
|
6058
|
+
async recoverAllSubmarineFunds(swaps) {
|
|
6059
|
+
const res = await this.sendMessage({
|
|
6060
|
+
id: getRandomId(),
|
|
6061
|
+
tag: this.messageTag,
|
|
6062
|
+
type: "RECOVER_ALL_SUBMARINE_FUNDS",
|
|
6063
|
+
payload: swaps
|
|
6064
|
+
});
|
|
6065
|
+
return res.payload;
|
|
5636
6066
|
}
|
|
5637
6067
|
async waitAndClaim(pendingSwap) {
|
|
5638
6068
|
try {
|
|
@@ -5961,7 +6391,7 @@ var ServiceWorkerArkadeSwaps = class _ServiceWorkerArkadeSwaps {
|
|
|
5961
6391
|
async [Symbol.asyncDispose]() {
|
|
5962
6392
|
return this.dispose();
|
|
5963
6393
|
}
|
|
5964
|
-
sendMessageDirect(request) {
|
|
6394
|
+
sendMessageDirect(request, timeoutMs) {
|
|
5965
6395
|
return new Promise((resolve, reject) => {
|
|
5966
6396
|
const cleanup = () => {
|
|
5967
6397
|
clearTimeout(timeoutId);
|
|
@@ -5970,14 +6400,14 @@ var ServiceWorkerArkadeSwaps = class _ServiceWorkerArkadeSwaps {
|
|
|
5970
6400
|
messageHandler
|
|
5971
6401
|
);
|
|
5972
6402
|
};
|
|
5973
|
-
const timeoutId = setTimeout(() => {
|
|
6403
|
+
const timeoutId = timeoutMs > 0 ? setTimeout(() => {
|
|
5974
6404
|
cleanup();
|
|
5975
6405
|
reject(
|
|
5976
6406
|
new import_sdk10.ServiceWorkerTimeoutError(
|
|
5977
6407
|
`Service worker message timed out (${request.type})`
|
|
5978
6408
|
)
|
|
5979
6409
|
);
|
|
5980
|
-
},
|
|
6410
|
+
}, timeoutMs) : void 0;
|
|
5981
6411
|
const messageHandler = (event) => {
|
|
5982
6412
|
const response = event.data;
|
|
5983
6413
|
if (!response || response.tag !== this.messageTag || response.id !== request.id) {
|
|
@@ -6052,10 +6482,13 @@ var ServiceWorkerArkadeSwaps = class _ServiceWorkerArkadeSwaps {
|
|
|
6052
6482
|
await this.reinitialize();
|
|
6053
6483
|
}
|
|
6054
6484
|
}
|
|
6485
|
+
const timeoutMs = LONG_RUNNING_ARKADE_SWAPS_REQUEST_TYPES.has(
|
|
6486
|
+
request.type
|
|
6487
|
+
) ? NO_MESSAGE_TIMEOUT_MS : DEFAULT_MESSAGE_TIMEOUT_MS;
|
|
6055
6488
|
const maxRetries = 2;
|
|
6056
6489
|
for (let attempt = 0; ; attempt++) {
|
|
6057
6490
|
try {
|
|
6058
|
-
return await this.sendMessageDirect(request);
|
|
6491
|
+
return await this.sendMessageDirect(request, timeoutMs);
|
|
6059
6492
|
} catch (error) {
|
|
6060
6493
|
if (!isMessageBusNotInitializedError(error) || attempt >= maxRetries) {
|
|
6061
6494
|
throw error;
|
|
@@ -6076,7 +6509,10 @@ var ServiceWorkerArkadeSwaps = class _ServiceWorkerArkadeSwaps {
|
|
|
6076
6509
|
id: getRandomId(),
|
|
6077
6510
|
payload: this.initPayload
|
|
6078
6511
|
};
|
|
6079
|
-
await this.sendMessageDirect(
|
|
6512
|
+
await this.sendMessageDirect(
|
|
6513
|
+
initMessage,
|
|
6514
|
+
DEFAULT_MESSAGE_TIMEOUT_MS
|
|
6515
|
+
);
|
|
6080
6516
|
})().finally(() => {
|
|
6081
6517
|
this.reinitPromise = null;
|
|
6082
6518
|
});
|