@arkade-os/boltz-swap 0.3.6 → 0.3.8
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/dist/{background-5IKGSVTP.js → background-RLZLTWCI.js} +2 -2
- package/dist/{chunk-LMHVRFGY.js → chunk-XUBVFCQZ.js} +1 -1
- package/dist/{chunk-SUFFGYDJ.js → chunk-ZJ2Q5QSA.js} +65 -25
- package/dist/expo/index.cjs +65 -26
- package/dist/expo/index.js +4 -4
- package/dist/index.cjs +194 -41
- package/dist/index.d.cts +19 -1
- package/dist/index.d.ts +19 -1
- package/dist/index.js +134 -17
- package/package.json +2 -2
|
@@ -2,8 +2,8 @@ import {
|
|
|
2
2
|
defineExpoSwapBackgroundTask,
|
|
3
3
|
registerExpoSwapBackgroundTask,
|
|
4
4
|
unregisterExpoSwapBackgroundTask
|
|
5
|
-
} from "./chunk-
|
|
6
|
-
import "./chunk-
|
|
5
|
+
} from "./chunk-XUBVFCQZ.js";
|
|
6
|
+
import "./chunk-ZJ2Q5QSA.js";
|
|
7
7
|
import "./chunk-3RG5ZIWI.js";
|
|
8
8
|
export {
|
|
9
9
|
defineExpoSwapBackgroundTask,
|
|
@@ -814,10 +814,16 @@ var isValidArkAddress = (address) => {
|
|
|
814
814
|
// src/utils/signatures.ts
|
|
815
815
|
import { verifyTapscriptSignatures } from "@arkade-os/sdk";
|
|
816
816
|
import { hex } from "@scure/base";
|
|
817
|
-
var verifySignatures = (tx, inputIndex, requiredSigners) => {
|
|
817
|
+
var verifySignatures = (tx, inputIndex, requiredSigners, expectedLeafHash) => {
|
|
818
818
|
try {
|
|
819
819
|
verifyTapscriptSignatures(tx, inputIndex, requiredSigners);
|
|
820
|
-
|
|
820
|
+
const input = tx.getInput(inputIndex);
|
|
821
|
+
const expectedHex = hex.encode(expectedLeafHash);
|
|
822
|
+
return requiredSigners.every(
|
|
823
|
+
(signer) => input.tapScriptSig?.some(
|
|
824
|
+
([{ pubKey, leafHash }]) => hex.encode(pubKey) === signer && hex.encode(leafHash) === expectedHex
|
|
825
|
+
)
|
|
826
|
+
);
|
|
821
827
|
} catch (_) {
|
|
822
828
|
return false;
|
|
823
829
|
}
|
|
@@ -2429,7 +2435,8 @@ import {
|
|
|
2429
2435
|
VtxoScript as VtxoScript2,
|
|
2430
2436
|
VtxoTaprootTree,
|
|
2431
2437
|
CSVMultisigTapscript as CSVMultisigTapscript2,
|
|
2432
|
-
combineTapscriptSigs
|
|
2438
|
+
combineTapscriptSigs,
|
|
2439
|
+
Transaction as Transaction5
|
|
2433
2440
|
} from "@arkade-os/sdk";
|
|
2434
2441
|
import { hex as hex7, base64 as base643 } from "@scure/base";
|
|
2435
2442
|
|
|
@@ -2593,7 +2600,8 @@ function createForfeitTx(input, forfeitOutputScript, connector) {
|
|
|
2593
2600
|
|
|
2594
2601
|
// src/utils/vhtlc.ts
|
|
2595
2602
|
import { ripemd160 } from "@noble/hashes/legacy.js";
|
|
2596
|
-
import { Address, OutScript
|
|
2603
|
+
import { Address, OutScript } from "@scure/btc-signer";
|
|
2604
|
+
import { tapLeafHash as tapLeafHash3 } from "@scure/btc-signer/payment.js";
|
|
2597
2605
|
var createVHTLCScript = (args) => {
|
|
2598
2606
|
const {
|
|
2599
2607
|
network,
|
|
@@ -2741,14 +2749,28 @@ var claimVHTLCwithOffchainTx = async (identity, vhtlcScript, serverXOnlyPublicKe
|
|
|
2741
2749
|
base643.encode(signedArkTx.toPSBT()),
|
|
2742
2750
|
checkpoints.map((c) => base643.encode(c.toPSBT()))
|
|
2743
2751
|
);
|
|
2744
|
-
|
|
2745
|
-
|
|
2752
|
+
const finalTx = Transaction5.fromPSBT(base643.decode(finalArkTx));
|
|
2753
|
+
const serverPubkeyHex = hex7.encode(serverXOnlyPublicKey);
|
|
2754
|
+
const claimLeafHash = tapLeafHash3(
|
|
2755
|
+
scriptFromTapLeafScript(vhtlcScript.claim())
|
|
2756
|
+
);
|
|
2757
|
+
for (let i = 0; i < finalTx.inputsLength; i++) {
|
|
2758
|
+
if (!verifySignatures(finalTx, i, [serverPubkeyHex], claimLeafHash)) {
|
|
2759
|
+
throw new Error("Invalid final Ark transaction");
|
|
2760
|
+
}
|
|
2746
2761
|
}
|
|
2747
2762
|
const finalCheckpoints = await Promise.all(
|
|
2748
|
-
signedCheckpointTxs.map(async (c) => {
|
|
2749
|
-
const tx = Transaction5.fromPSBT(base643.decode(c)
|
|
2750
|
-
|
|
2751
|
-
|
|
2763
|
+
signedCheckpointTxs.map(async (c, idx) => {
|
|
2764
|
+
const tx = Transaction5.fromPSBT(base643.decode(c));
|
|
2765
|
+
const checkpointLeaf = checkpoints[idx].getInput(0).tapLeafScript[0];
|
|
2766
|
+
const cpLeafHash = tapLeafHash3(
|
|
2767
|
+
scriptFromTapLeafScript(checkpointLeaf)
|
|
2768
|
+
);
|
|
2769
|
+
if (!verifySignatures(tx, 0, [serverPubkeyHex], cpLeafHash)) {
|
|
2770
|
+
throw new Error(
|
|
2771
|
+
"Invalid server signature in checkpoint transaction"
|
|
2772
|
+
);
|
|
2773
|
+
}
|
|
2752
2774
|
const signedCheckpoint = await identity.sign(tx, [0]);
|
|
2753
2775
|
return base643.encode(signedCheckpoint.toPSBT());
|
|
2754
2776
|
})
|
|
@@ -2771,10 +2793,27 @@ var refundVHTLCwithOffchainTx = async (swapId, identity, arkProvider, boltzXOnly
|
|
|
2771
2793
|
checkpoint: boltzSignedCheckpointTx
|
|
2772
2794
|
} = await refundFunc(swapId, unsignedRefundTx, unsignedCheckpointTx);
|
|
2773
2795
|
const boltzXOnlyPublicKeyHex = hex7.encode(boltzXOnlyPublicKey);
|
|
2774
|
-
|
|
2796
|
+
const refundLeafHash = tapLeafHash3(
|
|
2797
|
+
scriptFromTapLeafScript(input.tapLeafScript)
|
|
2798
|
+
);
|
|
2799
|
+
if (!verifySignatures(
|
|
2800
|
+
boltzSignedRefundTx,
|
|
2801
|
+
0,
|
|
2802
|
+
[boltzXOnlyPublicKeyHex],
|
|
2803
|
+
refundLeafHash
|
|
2804
|
+
)) {
|
|
2775
2805
|
throw new Error("Invalid Boltz signature in refund transaction");
|
|
2776
2806
|
}
|
|
2777
|
-
|
|
2807
|
+
const checkpointLeaf = unsignedCheckpointTx.getInput(0).tapLeafScript[0];
|
|
2808
|
+
const checkpointLeafHash = tapLeafHash3(
|
|
2809
|
+
scriptFromTapLeafScript(checkpointLeaf)
|
|
2810
|
+
);
|
|
2811
|
+
if (!verifySignatures(
|
|
2812
|
+
boltzSignedCheckpointTx,
|
|
2813
|
+
0,
|
|
2814
|
+
[boltzXOnlyPublicKeyHex],
|
|
2815
|
+
checkpointLeafHash
|
|
2816
|
+
)) {
|
|
2778
2817
|
throw new Error("Invalid Boltz signature in checkpoint transaction");
|
|
2779
2818
|
}
|
|
2780
2819
|
const signedRefundTx = await identity.sign(unsignedRefundTx);
|
|
@@ -2798,7 +2837,7 @@ var refundVHTLCwithOffchainTx = async (swapId, identity, arkProvider, boltzXOnly
|
|
|
2798
2837
|
hex7.encode(boltzXOnlyPublicKey),
|
|
2799
2838
|
hex7.encode(serverXOnlyPublicKey)
|
|
2800
2839
|
];
|
|
2801
|
-
if (!verifySignatures(tx, inputIndex, requiredSigners)) {
|
|
2840
|
+
if (!verifySignatures(tx, inputIndex, requiredSigners, refundLeafHash)) {
|
|
2802
2841
|
throw new Error("Invalid refund transaction");
|
|
2803
2842
|
}
|
|
2804
2843
|
if (signedCheckpointTxs.length !== 1) {
|
|
@@ -2809,6 +2848,15 @@ var refundVHTLCwithOffchainTx = async (swapId, identity, arkProvider, boltzXOnly
|
|
|
2809
2848
|
const serverSignedCheckpointTx = Transaction5.fromPSBT(
|
|
2810
2849
|
base643.decode(signedCheckpointTxs[0])
|
|
2811
2850
|
);
|
|
2851
|
+
const serverPubkeyHex = hex7.encode(serverXOnlyPublicKey);
|
|
2852
|
+
if (!verifySignatures(
|
|
2853
|
+
serverSignedCheckpointTx,
|
|
2854
|
+
0,
|
|
2855
|
+
[serverPubkeyHex],
|
|
2856
|
+
checkpointLeafHash
|
|
2857
|
+
)) {
|
|
2858
|
+
throw new Error("Invalid server signature in checkpoint transaction");
|
|
2859
|
+
}
|
|
2812
2860
|
const finalCheckpointTx = combineTapscriptSigs(
|
|
2813
2861
|
combinedSignedCheckpointTx,
|
|
2814
2862
|
serverSignedCheckpointTx
|
|
@@ -2817,17 +2865,9 @@ var refundVHTLCwithOffchainTx = async (swapId, identity, arkProvider, boltzXOnly
|
|
|
2817
2865
|
base643.encode(finalCheckpointTx.toPSBT())
|
|
2818
2866
|
]);
|
|
2819
2867
|
};
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
});
|
|
2824
|
-
if (!tx) return false;
|
|
2825
|
-
const inputs = [];
|
|
2826
|
-
for (let i = 0; i < tx.inputsLength; i++) {
|
|
2827
|
-
inputs.push(tx.getInput(i));
|
|
2828
|
-
}
|
|
2829
|
-
return inputs.every((input) => input.witnessUtxo);
|
|
2830
|
-
};
|
|
2868
|
+
function scriptFromTapLeafScript(leaf) {
|
|
2869
|
+
return leaf[1].subarray(0, leaf[1].length - 1);
|
|
2870
|
+
}
|
|
2831
2871
|
|
|
2832
2872
|
// src/arkade-swaps.ts
|
|
2833
2873
|
var ArkadeSwaps = class _ArkadeSwaps {
|
|
@@ -3253,7 +3293,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
|
|
|
3253
3293
|
async sendLightningPayment(args) {
|
|
3254
3294
|
const pendingSwap = await this.createSubmarineSwap(args);
|
|
3255
3295
|
await this.savePendingSubmarineSwap(pendingSwap);
|
|
3256
|
-
const txid = await this.wallet.
|
|
3296
|
+
const txid = await this.wallet.send({
|
|
3257
3297
|
address: pendingSwap.response.address,
|
|
3258
3298
|
amount: pendingSwap.response.expectedAmount
|
|
3259
3299
|
});
|
package/dist/expo/index.cjs
CHANGED
|
@@ -1164,10 +1164,16 @@ var init_signatures = __esm({
|
|
|
1164
1164
|
"use strict";
|
|
1165
1165
|
import_sdk3 = require("@arkade-os/sdk");
|
|
1166
1166
|
import_base4 = require("@scure/base");
|
|
1167
|
-
verifySignatures = (tx, inputIndex, requiredSigners) => {
|
|
1167
|
+
verifySignatures = (tx, inputIndex, requiredSigners, expectedLeafHash) => {
|
|
1168
1168
|
try {
|
|
1169
1169
|
(0, import_sdk3.verifyTapscriptSignatures)(tx, inputIndex, requiredSigners);
|
|
1170
|
-
|
|
1170
|
+
const input = tx.getInput(inputIndex);
|
|
1171
|
+
const expectedHex = import_base4.hex.encode(expectedLeafHash);
|
|
1172
|
+
return requiredSigners.every(
|
|
1173
|
+
(signer) => input.tapScriptSig?.some(
|
|
1174
|
+
([{ pubKey, leafHash }]) => import_base4.hex.encode(pubKey) === signer && import_base4.hex.encode(leafHash) === expectedHex
|
|
1175
|
+
)
|
|
1176
|
+
);
|
|
1171
1177
|
} catch (_) {
|
|
1172
1178
|
return false;
|
|
1173
1179
|
}
|
|
@@ -2563,7 +2569,10 @@ var init_batch = __esm({
|
|
|
2563
2569
|
});
|
|
2564
2570
|
|
|
2565
2571
|
// src/utils/vhtlc.ts
|
|
2566
|
-
|
|
2572
|
+
function scriptFromTapLeafScript(leaf) {
|
|
2573
|
+
return leaf[1].subarray(0, leaf[1].length - 1);
|
|
2574
|
+
}
|
|
2575
|
+
var import_sdk7, import_base8, import_legacy, import_btc_signer4, import_payment3, createVHTLCScript, joinBatch, claimVHTLCwithOffchainTx, refundVHTLCwithOffchainTx;
|
|
2567
2576
|
var init_vhtlc = __esm({
|
|
2568
2577
|
"src/utils/vhtlc.ts"() {
|
|
2569
2578
|
"use strict";
|
|
@@ -2573,6 +2582,7 @@ var init_vhtlc = __esm({
|
|
|
2573
2582
|
init_batch();
|
|
2574
2583
|
import_legacy = require("@noble/hashes/legacy.js");
|
|
2575
2584
|
import_btc_signer4 = require("@scure/btc-signer");
|
|
2585
|
+
import_payment3 = require("@scure/btc-signer/payment.js");
|
|
2576
2586
|
init_signatures();
|
|
2577
2587
|
createVHTLCScript = (args) => {
|
|
2578
2588
|
const {
|
|
@@ -2721,14 +2731,28 @@ var init_vhtlc = __esm({
|
|
|
2721
2731
|
import_base8.base64.encode(signedArkTx.toPSBT()),
|
|
2722
2732
|
checkpoints.map((c) => import_base8.base64.encode(c.toPSBT()))
|
|
2723
2733
|
);
|
|
2724
|
-
|
|
2725
|
-
|
|
2734
|
+
const finalTx = import_sdk7.Transaction.fromPSBT(import_base8.base64.decode(finalArkTx));
|
|
2735
|
+
const serverPubkeyHex = import_base8.hex.encode(serverXOnlyPublicKey);
|
|
2736
|
+
const claimLeafHash = (0, import_payment3.tapLeafHash)(
|
|
2737
|
+
scriptFromTapLeafScript(vhtlcScript.claim())
|
|
2738
|
+
);
|
|
2739
|
+
for (let i = 0; i < finalTx.inputsLength; i++) {
|
|
2740
|
+
if (!verifySignatures(finalTx, i, [serverPubkeyHex], claimLeafHash)) {
|
|
2741
|
+
throw new Error("Invalid final Ark transaction");
|
|
2742
|
+
}
|
|
2726
2743
|
}
|
|
2727
2744
|
const finalCheckpoints = await Promise.all(
|
|
2728
|
-
signedCheckpointTxs.map(async (c) => {
|
|
2729
|
-
const tx =
|
|
2730
|
-
|
|
2731
|
-
|
|
2745
|
+
signedCheckpointTxs.map(async (c, idx) => {
|
|
2746
|
+
const tx = import_sdk7.Transaction.fromPSBT(import_base8.base64.decode(c));
|
|
2747
|
+
const checkpointLeaf = checkpoints[idx].getInput(0).tapLeafScript[0];
|
|
2748
|
+
const cpLeafHash = (0, import_payment3.tapLeafHash)(
|
|
2749
|
+
scriptFromTapLeafScript(checkpointLeaf)
|
|
2750
|
+
);
|
|
2751
|
+
if (!verifySignatures(tx, 0, [serverPubkeyHex], cpLeafHash)) {
|
|
2752
|
+
throw new Error(
|
|
2753
|
+
"Invalid server signature in checkpoint transaction"
|
|
2754
|
+
);
|
|
2755
|
+
}
|
|
2732
2756
|
const signedCheckpoint = await identity.sign(tx, [0]);
|
|
2733
2757
|
return import_base8.base64.encode(signedCheckpoint.toPSBT());
|
|
2734
2758
|
})
|
|
@@ -2751,10 +2775,27 @@ var init_vhtlc = __esm({
|
|
|
2751
2775
|
checkpoint: boltzSignedCheckpointTx
|
|
2752
2776
|
} = await refundFunc(swapId, unsignedRefundTx, unsignedCheckpointTx);
|
|
2753
2777
|
const boltzXOnlyPublicKeyHex = import_base8.hex.encode(boltzXOnlyPublicKey);
|
|
2754
|
-
|
|
2778
|
+
const refundLeafHash = (0, import_payment3.tapLeafHash)(
|
|
2779
|
+
scriptFromTapLeafScript(input.tapLeafScript)
|
|
2780
|
+
);
|
|
2781
|
+
if (!verifySignatures(
|
|
2782
|
+
boltzSignedRefundTx,
|
|
2783
|
+
0,
|
|
2784
|
+
[boltzXOnlyPublicKeyHex],
|
|
2785
|
+
refundLeafHash
|
|
2786
|
+
)) {
|
|
2755
2787
|
throw new Error("Invalid Boltz signature in refund transaction");
|
|
2756
2788
|
}
|
|
2757
|
-
|
|
2789
|
+
const checkpointLeaf = unsignedCheckpointTx.getInput(0).tapLeafScript[0];
|
|
2790
|
+
const checkpointLeafHash = (0, import_payment3.tapLeafHash)(
|
|
2791
|
+
scriptFromTapLeafScript(checkpointLeaf)
|
|
2792
|
+
);
|
|
2793
|
+
if (!verifySignatures(
|
|
2794
|
+
boltzSignedCheckpointTx,
|
|
2795
|
+
0,
|
|
2796
|
+
[boltzXOnlyPublicKeyHex],
|
|
2797
|
+
checkpointLeafHash
|
|
2798
|
+
)) {
|
|
2758
2799
|
throw new Error("Invalid Boltz signature in checkpoint transaction");
|
|
2759
2800
|
}
|
|
2760
2801
|
const signedRefundTx = await identity.sign(unsignedRefundTx);
|
|
@@ -2771,14 +2812,14 @@ var init_vhtlc = __esm({
|
|
|
2771
2812
|
import_base8.base64.encode(combinedSignedRefundTx.toPSBT()),
|
|
2772
2813
|
[import_base8.base64.encode(unsignedCheckpointTx.toPSBT())]
|
|
2773
2814
|
);
|
|
2774
|
-
const tx =
|
|
2815
|
+
const tx = import_sdk7.Transaction.fromPSBT(import_base8.base64.decode(finalArkTx));
|
|
2775
2816
|
const inputIndex = 0;
|
|
2776
2817
|
const requiredSigners = [
|
|
2777
2818
|
import_base8.hex.encode(ourXOnlyPublicKey),
|
|
2778
2819
|
import_base8.hex.encode(boltzXOnlyPublicKey),
|
|
2779
2820
|
import_base8.hex.encode(serverXOnlyPublicKey)
|
|
2780
2821
|
];
|
|
2781
|
-
if (!verifySignatures(tx, inputIndex, requiredSigners)) {
|
|
2822
|
+
if (!verifySignatures(tx, inputIndex, requiredSigners, refundLeafHash)) {
|
|
2782
2823
|
throw new Error("Invalid refund transaction");
|
|
2783
2824
|
}
|
|
2784
2825
|
if (signedCheckpointTxs.length !== 1) {
|
|
@@ -2786,9 +2827,18 @@ var init_vhtlc = __esm({
|
|
|
2786
2827
|
`Expected one signed checkpoint transaction, got ${signedCheckpointTxs.length}`
|
|
2787
2828
|
);
|
|
2788
2829
|
}
|
|
2789
|
-
const serverSignedCheckpointTx =
|
|
2830
|
+
const serverSignedCheckpointTx = import_sdk7.Transaction.fromPSBT(
|
|
2790
2831
|
import_base8.base64.decode(signedCheckpointTxs[0])
|
|
2791
2832
|
);
|
|
2833
|
+
const serverPubkeyHex = import_base8.hex.encode(serverXOnlyPublicKey);
|
|
2834
|
+
if (!verifySignatures(
|
|
2835
|
+
serverSignedCheckpointTx,
|
|
2836
|
+
0,
|
|
2837
|
+
[serverPubkeyHex],
|
|
2838
|
+
checkpointLeafHash
|
|
2839
|
+
)) {
|
|
2840
|
+
throw new Error("Invalid server signature in checkpoint transaction");
|
|
2841
|
+
}
|
|
2792
2842
|
const finalCheckpointTx = (0, import_sdk7.combineTapscriptSigs)(
|
|
2793
2843
|
combinedSignedCheckpointTx,
|
|
2794
2844
|
serverSignedCheckpointTx
|
|
@@ -2797,17 +2847,6 @@ var init_vhtlc = __esm({
|
|
|
2797
2847
|
import_base8.base64.encode(finalCheckpointTx.toPSBT())
|
|
2798
2848
|
]);
|
|
2799
2849
|
};
|
|
2800
|
-
validFinalArkTx = (finalArkTx, _pubkey, _tapLeaves) => {
|
|
2801
|
-
const tx = import_btc_signer4.Transaction.fromPSBT(import_base8.base64.decode(finalArkTx), {
|
|
2802
|
-
allowUnknown: true
|
|
2803
|
-
});
|
|
2804
|
-
if (!tx) return false;
|
|
2805
|
-
const inputs = [];
|
|
2806
|
-
for (let i = 0; i < tx.inputsLength; i++) {
|
|
2807
|
-
inputs.push(tx.getInput(i));
|
|
2808
|
-
}
|
|
2809
|
-
return inputs.every((input) => input.witnessUtxo);
|
|
2810
|
-
};
|
|
2811
2850
|
}
|
|
2812
2851
|
});
|
|
2813
2852
|
|
|
@@ -3259,7 +3298,7 @@ var init_arkade_swaps = __esm({
|
|
|
3259
3298
|
async sendLightningPayment(args) {
|
|
3260
3299
|
const pendingSwap = await this.createSubmarineSwap(args);
|
|
3261
3300
|
await this.savePendingSubmarineSwap(pendingSwap);
|
|
3262
|
-
const txid = await this.wallet.
|
|
3301
|
+
const txid = await this.wallet.send({
|
|
3263
3302
|
address: pendingSwap.response.address,
|
|
3264
3303
|
amount: pendingSwap.response.expectedAmount
|
|
3265
3304
|
});
|
package/dist/expo/index.js
CHANGED
|
@@ -4,10 +4,10 @@ import {
|
|
|
4
4
|
registerExpoSwapBackgroundTask,
|
|
5
5
|
swapsPollProcessor,
|
|
6
6
|
unregisterExpoSwapBackgroundTask
|
|
7
|
-
} from "../chunk-
|
|
7
|
+
} from "../chunk-XUBVFCQZ.js";
|
|
8
8
|
import {
|
|
9
9
|
ArkadeSwaps
|
|
10
|
-
} from "../chunk-
|
|
10
|
+
} from "../chunk-ZJ2Q5QSA.js";
|
|
11
11
|
import "../chunk-3RG5ZIWI.js";
|
|
12
12
|
|
|
13
13
|
// src/expo/arkade-lightning.ts
|
|
@@ -56,7 +56,7 @@ var ExpoArkadeSwaps = class _ExpoArkadeSwaps {
|
|
|
56
56
|
await instance.seedSwapPollTask();
|
|
57
57
|
if (config.background.minimumBackgroundInterval) {
|
|
58
58
|
try {
|
|
59
|
-
const { registerExpoSwapBackgroundTask: registerExpoSwapBackgroundTask2 } = await import("../background-
|
|
59
|
+
const { registerExpoSwapBackgroundTask: registerExpoSwapBackgroundTask2 } = await import("../background-RLZLTWCI.js");
|
|
60
60
|
await registerExpoSwapBackgroundTask2(
|
|
61
61
|
config.background.taskName,
|
|
62
62
|
{
|
|
@@ -119,7 +119,7 @@ var ExpoArkadeSwaps = class _ExpoArkadeSwaps {
|
|
|
119
119
|
}
|
|
120
120
|
await this.inner.dispose();
|
|
121
121
|
try {
|
|
122
|
-
const { unregisterExpoSwapBackgroundTask: unregisterExpoSwapBackgroundTask2 } = await import("../background-
|
|
122
|
+
const { unregisterExpoSwapBackgroundTask: unregisterExpoSwapBackgroundTask2 } = await import("../background-RLZLTWCI.js");
|
|
123
123
|
await unregisterExpoSwapBackgroundTask2(this.taskName);
|
|
124
124
|
} catch (err) {
|
|
125
125
|
const message = err instanceof Error ? err.message : String(err);
|
package/dist/index.cjs
CHANGED
|
@@ -1288,10 +1288,16 @@ var isValidArkAddress = (address) => {
|
|
|
1288
1288
|
// src/utils/signatures.ts
|
|
1289
1289
|
var import_sdk3 = require("@arkade-os/sdk");
|
|
1290
1290
|
var import_base4 = require("@scure/base");
|
|
1291
|
-
var verifySignatures = (tx, inputIndex, requiredSigners) => {
|
|
1291
|
+
var verifySignatures = (tx, inputIndex, requiredSigners, expectedLeafHash) => {
|
|
1292
1292
|
try {
|
|
1293
1293
|
(0, import_sdk3.verifyTapscriptSignatures)(tx, inputIndex, requiredSigners);
|
|
1294
|
-
|
|
1294
|
+
const input = tx.getInput(inputIndex);
|
|
1295
|
+
const expectedHex = import_base4.hex.encode(expectedLeafHash);
|
|
1296
|
+
return requiredSigners.every(
|
|
1297
|
+
(signer) => input.tapScriptSig?.some(
|
|
1298
|
+
([{ pubKey, leafHash }]) => import_base4.hex.encode(pubKey) === signer && import_base4.hex.encode(leafHash) === expectedHex
|
|
1299
|
+
)
|
|
1300
|
+
);
|
|
1295
1301
|
} catch (_) {
|
|
1296
1302
|
return false;
|
|
1297
1303
|
}
|
|
@@ -2654,6 +2660,7 @@ function createForfeitTx(input, forfeitOutputScript, connector) {
|
|
|
2654
2660
|
// src/utils/vhtlc.ts
|
|
2655
2661
|
var import_legacy = require("@noble/hashes/legacy.js");
|
|
2656
2662
|
var import_btc_signer4 = require("@scure/btc-signer");
|
|
2663
|
+
var import_payment3 = require("@scure/btc-signer/payment.js");
|
|
2657
2664
|
var createVHTLCScript = (args) => {
|
|
2658
2665
|
const {
|
|
2659
2666
|
network,
|
|
@@ -2801,14 +2808,28 @@ var claimVHTLCwithOffchainTx = async (identity, vhtlcScript, serverXOnlyPublicKe
|
|
|
2801
2808
|
import_base8.base64.encode(signedArkTx.toPSBT()),
|
|
2802
2809
|
checkpoints.map((c) => import_base8.base64.encode(c.toPSBT()))
|
|
2803
2810
|
);
|
|
2804
|
-
|
|
2805
|
-
|
|
2811
|
+
const finalTx = import_sdk7.Transaction.fromPSBT(import_base8.base64.decode(finalArkTx));
|
|
2812
|
+
const serverPubkeyHex = import_base8.hex.encode(serverXOnlyPublicKey);
|
|
2813
|
+
const claimLeafHash = (0, import_payment3.tapLeafHash)(
|
|
2814
|
+
scriptFromTapLeafScript(vhtlcScript.claim())
|
|
2815
|
+
);
|
|
2816
|
+
for (let i = 0; i < finalTx.inputsLength; i++) {
|
|
2817
|
+
if (!verifySignatures(finalTx, i, [serverPubkeyHex], claimLeafHash)) {
|
|
2818
|
+
throw new Error("Invalid final Ark transaction");
|
|
2819
|
+
}
|
|
2806
2820
|
}
|
|
2807
2821
|
const finalCheckpoints = await Promise.all(
|
|
2808
|
-
signedCheckpointTxs.map(async (c) => {
|
|
2809
|
-
const tx =
|
|
2810
|
-
|
|
2811
|
-
|
|
2822
|
+
signedCheckpointTxs.map(async (c, idx) => {
|
|
2823
|
+
const tx = import_sdk7.Transaction.fromPSBT(import_base8.base64.decode(c));
|
|
2824
|
+
const checkpointLeaf = checkpoints[idx].getInput(0).tapLeafScript[0];
|
|
2825
|
+
const cpLeafHash = (0, import_payment3.tapLeafHash)(
|
|
2826
|
+
scriptFromTapLeafScript(checkpointLeaf)
|
|
2827
|
+
);
|
|
2828
|
+
if (!verifySignatures(tx, 0, [serverPubkeyHex], cpLeafHash)) {
|
|
2829
|
+
throw new Error(
|
|
2830
|
+
"Invalid server signature in checkpoint transaction"
|
|
2831
|
+
);
|
|
2832
|
+
}
|
|
2812
2833
|
const signedCheckpoint = await identity.sign(tx, [0]);
|
|
2813
2834
|
return import_base8.base64.encode(signedCheckpoint.toPSBT());
|
|
2814
2835
|
})
|
|
@@ -2831,10 +2852,27 @@ var refundVHTLCwithOffchainTx = async (swapId, identity, arkProvider, boltzXOnly
|
|
|
2831
2852
|
checkpoint: boltzSignedCheckpointTx
|
|
2832
2853
|
} = await refundFunc(swapId, unsignedRefundTx, unsignedCheckpointTx);
|
|
2833
2854
|
const boltzXOnlyPublicKeyHex = import_base8.hex.encode(boltzXOnlyPublicKey);
|
|
2834
|
-
|
|
2855
|
+
const refundLeafHash = (0, import_payment3.tapLeafHash)(
|
|
2856
|
+
scriptFromTapLeafScript(input.tapLeafScript)
|
|
2857
|
+
);
|
|
2858
|
+
if (!verifySignatures(
|
|
2859
|
+
boltzSignedRefundTx,
|
|
2860
|
+
0,
|
|
2861
|
+
[boltzXOnlyPublicKeyHex],
|
|
2862
|
+
refundLeafHash
|
|
2863
|
+
)) {
|
|
2835
2864
|
throw new Error("Invalid Boltz signature in refund transaction");
|
|
2836
2865
|
}
|
|
2837
|
-
|
|
2866
|
+
const checkpointLeaf = unsignedCheckpointTx.getInput(0).tapLeafScript[0];
|
|
2867
|
+
const checkpointLeafHash = (0, import_payment3.tapLeafHash)(
|
|
2868
|
+
scriptFromTapLeafScript(checkpointLeaf)
|
|
2869
|
+
);
|
|
2870
|
+
if (!verifySignatures(
|
|
2871
|
+
boltzSignedCheckpointTx,
|
|
2872
|
+
0,
|
|
2873
|
+
[boltzXOnlyPublicKeyHex],
|
|
2874
|
+
checkpointLeafHash
|
|
2875
|
+
)) {
|
|
2838
2876
|
throw new Error("Invalid Boltz signature in checkpoint transaction");
|
|
2839
2877
|
}
|
|
2840
2878
|
const signedRefundTx = await identity.sign(unsignedRefundTx);
|
|
@@ -2851,14 +2889,14 @@ var refundVHTLCwithOffchainTx = async (swapId, identity, arkProvider, boltzXOnly
|
|
|
2851
2889
|
import_base8.base64.encode(combinedSignedRefundTx.toPSBT()),
|
|
2852
2890
|
[import_base8.base64.encode(unsignedCheckpointTx.toPSBT())]
|
|
2853
2891
|
);
|
|
2854
|
-
const tx =
|
|
2892
|
+
const tx = import_sdk7.Transaction.fromPSBT(import_base8.base64.decode(finalArkTx));
|
|
2855
2893
|
const inputIndex = 0;
|
|
2856
2894
|
const requiredSigners = [
|
|
2857
2895
|
import_base8.hex.encode(ourXOnlyPublicKey),
|
|
2858
2896
|
import_base8.hex.encode(boltzXOnlyPublicKey),
|
|
2859
2897
|
import_base8.hex.encode(serverXOnlyPublicKey)
|
|
2860
2898
|
];
|
|
2861
|
-
if (!verifySignatures(tx, inputIndex, requiredSigners)) {
|
|
2899
|
+
if (!verifySignatures(tx, inputIndex, requiredSigners, refundLeafHash)) {
|
|
2862
2900
|
throw new Error("Invalid refund transaction");
|
|
2863
2901
|
}
|
|
2864
2902
|
if (signedCheckpointTxs.length !== 1) {
|
|
@@ -2866,9 +2904,18 @@ var refundVHTLCwithOffchainTx = async (swapId, identity, arkProvider, boltzXOnly
|
|
|
2866
2904
|
`Expected one signed checkpoint transaction, got ${signedCheckpointTxs.length}`
|
|
2867
2905
|
);
|
|
2868
2906
|
}
|
|
2869
|
-
const serverSignedCheckpointTx =
|
|
2907
|
+
const serverSignedCheckpointTx = import_sdk7.Transaction.fromPSBT(
|
|
2870
2908
|
import_base8.base64.decode(signedCheckpointTxs[0])
|
|
2871
2909
|
);
|
|
2910
|
+
const serverPubkeyHex = import_base8.hex.encode(serverXOnlyPublicKey);
|
|
2911
|
+
if (!verifySignatures(
|
|
2912
|
+
serverSignedCheckpointTx,
|
|
2913
|
+
0,
|
|
2914
|
+
[serverPubkeyHex],
|
|
2915
|
+
checkpointLeafHash
|
|
2916
|
+
)) {
|
|
2917
|
+
throw new Error("Invalid server signature in checkpoint transaction");
|
|
2918
|
+
}
|
|
2872
2919
|
const finalCheckpointTx = (0, import_sdk7.combineTapscriptSigs)(
|
|
2873
2920
|
combinedSignedCheckpointTx,
|
|
2874
2921
|
serverSignedCheckpointTx
|
|
@@ -2877,17 +2924,9 @@ var refundVHTLCwithOffchainTx = async (swapId, identity, arkProvider, boltzXOnly
|
|
|
2877
2924
|
import_base8.base64.encode(finalCheckpointTx.toPSBT())
|
|
2878
2925
|
]);
|
|
2879
2926
|
};
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
});
|
|
2884
|
-
if (!tx) return false;
|
|
2885
|
-
const inputs = [];
|
|
2886
|
-
for (let i = 0; i < tx.inputsLength; i++) {
|
|
2887
|
-
inputs.push(tx.getInput(i));
|
|
2888
|
-
}
|
|
2889
|
-
return inputs.every((input) => input.witnessUtxo);
|
|
2890
|
-
};
|
|
2927
|
+
function scriptFromTapLeafScript(leaf) {
|
|
2928
|
+
return leaf[1].subarray(0, leaf[1].length - 1);
|
|
2929
|
+
}
|
|
2891
2930
|
|
|
2892
2931
|
// src/arkade-swaps.ts
|
|
2893
2932
|
var ArkadeSwaps = class _ArkadeSwaps {
|
|
@@ -3313,7 +3352,7 @@ var ArkadeSwaps = class _ArkadeSwaps {
|
|
|
3313
3352
|
async sendLightningPayment(args) {
|
|
3314
3353
|
const pendingSwap = await this.createSubmarineSwap(args);
|
|
3315
3354
|
await this.savePendingSubmarineSwap(pendingSwap);
|
|
3316
|
-
const txid = await this.wallet.
|
|
3355
|
+
const txid = await this.wallet.send({
|
|
3317
3356
|
address: pendingSwap.response.address,
|
|
3318
3357
|
amount: pendingSwap.response.expectedAmount
|
|
3319
3358
|
});
|
|
@@ -4997,6 +5036,28 @@ var ArkadeSwapsMessageHandler = class _ArkadeSwapsMessageHandler {
|
|
|
4997
5036
|
};
|
|
4998
5037
|
|
|
4999
5038
|
// src/serviceWorker/arkade-swaps-runtime.ts
|
|
5039
|
+
var import_sdk10 = require("@arkade-os/sdk");
|
|
5040
|
+
function isMessageBusNotInitializedError(error) {
|
|
5041
|
+
return error instanceof Error && error.message.includes(import_sdk10.MESSAGE_BUS_NOT_INITIALIZED);
|
|
5042
|
+
}
|
|
5043
|
+
var DEDUPABLE_REQUEST_TYPES = /* @__PURE__ */ new Set([
|
|
5044
|
+
"GET_FEES",
|
|
5045
|
+
"GET_LIMITS",
|
|
5046
|
+
"GET_SWAP_STATUS",
|
|
5047
|
+
"GET_PENDING_SUBMARINE_SWAPS",
|
|
5048
|
+
"GET_PENDING_REVERSE_SWAPS",
|
|
5049
|
+
"GET_PENDING_CHAIN_SWAPS",
|
|
5050
|
+
"GET_SWAP_HISTORY",
|
|
5051
|
+
"QUOTE_SWAP",
|
|
5052
|
+
"SM-GET_PENDING_SWAPS",
|
|
5053
|
+
"SM-HAS_SWAP",
|
|
5054
|
+
"SM-IS_PROCESSING",
|
|
5055
|
+
"SM-GET_STATS"
|
|
5056
|
+
]);
|
|
5057
|
+
function getRequestDedupKey(request) {
|
|
5058
|
+
const { id, tag, ...rest } = request;
|
|
5059
|
+
return JSON.stringify(rest);
|
|
5060
|
+
}
|
|
5000
5061
|
var ServiceWorkerArkadeSwaps = class _ServiceWorkerArkadeSwaps {
|
|
5001
5062
|
constructor(messageTag, serviceWorker, swapRepository, withSwapManager) {
|
|
5002
5063
|
this.messageTag = messageTag;
|
|
@@ -5011,6 +5072,10 @@ var ServiceWorkerArkadeSwaps = class _ServiceWorkerArkadeSwaps {
|
|
|
5011
5072
|
actionExecutedListeners = /* @__PURE__ */ new Set();
|
|
5012
5073
|
wsConnectedListeners = /* @__PURE__ */ new Set();
|
|
5013
5074
|
wsDisconnectedListeners = /* @__PURE__ */ new Set();
|
|
5075
|
+
initPayload = null;
|
|
5076
|
+
reinitPromise = null;
|
|
5077
|
+
pingPromise = null;
|
|
5078
|
+
inflightRequests = /* @__PURE__ */ new Map();
|
|
5014
5079
|
static async create(config) {
|
|
5015
5080
|
const messageTag = config.messageTag ?? DEFAULT_MESSAGE_TAG;
|
|
5016
5081
|
const swapRepository = config.swapRepository ?? new IndexedDbSwapRepository();
|
|
@@ -5020,18 +5085,20 @@ var ServiceWorkerArkadeSwaps = class _ServiceWorkerArkadeSwaps {
|
|
|
5020
5085
|
swapRepository,
|
|
5021
5086
|
Boolean(config.swapManager)
|
|
5022
5087
|
);
|
|
5088
|
+
const initPayload = {
|
|
5089
|
+
network: config.network,
|
|
5090
|
+
arkServerUrl: config.arkServerUrl,
|
|
5091
|
+
swapProvider: { baseUrl: config.swapProvider.getApiUrl() },
|
|
5092
|
+
swapManager: config.swapManager
|
|
5093
|
+
};
|
|
5023
5094
|
const initMessage = {
|
|
5024
5095
|
tag: messageTag,
|
|
5025
5096
|
id: getRandomId(),
|
|
5026
5097
|
type: "INIT_ARKADE_SWAPS",
|
|
5027
|
-
payload:
|
|
5028
|
-
network: config.network,
|
|
5029
|
-
arkServerUrl: config.arkServerUrl,
|
|
5030
|
-
swapProvider: { baseUrl: config.swapProvider.getApiUrl() },
|
|
5031
|
-
swapManager: config.swapManager
|
|
5032
|
-
}
|
|
5098
|
+
payload: initPayload
|
|
5033
5099
|
};
|
|
5034
5100
|
await svcArkadeSwaps.sendMessage(initMessage);
|
|
5101
|
+
svcArkadeSwaps.initPayload = initPayload;
|
|
5035
5102
|
return svcArkadeSwaps;
|
|
5036
5103
|
}
|
|
5037
5104
|
async startSwapManager() {
|
|
@@ -5572,17 +5639,23 @@ var ServiceWorkerArkadeSwaps = class _ServiceWorkerArkadeSwaps {
|
|
|
5572
5639
|
async [Symbol.asyncDispose]() {
|
|
5573
5640
|
return this.dispose();
|
|
5574
5641
|
}
|
|
5575
|
-
|
|
5642
|
+
sendMessageDirect(request) {
|
|
5576
5643
|
return new Promise((resolve, reject) => {
|
|
5577
|
-
const timeoutMs = 3e4;
|
|
5578
|
-
let timeout;
|
|
5579
5644
|
const cleanup = () => {
|
|
5580
|
-
|
|
5645
|
+
clearTimeout(timeoutId);
|
|
5581
5646
|
navigator.serviceWorker.removeEventListener(
|
|
5582
5647
|
"message",
|
|
5583
5648
|
messageHandler
|
|
5584
5649
|
);
|
|
5585
5650
|
};
|
|
5651
|
+
const timeoutId = setTimeout(() => {
|
|
5652
|
+
cleanup();
|
|
5653
|
+
reject(
|
|
5654
|
+
new import_sdk10.ServiceWorkerTimeoutError(
|
|
5655
|
+
`Service worker message timed out (${request.type})`
|
|
5656
|
+
)
|
|
5657
|
+
);
|
|
5658
|
+
}, 3e4);
|
|
5586
5659
|
const messageHandler = (event) => {
|
|
5587
5660
|
const response = event.data;
|
|
5588
5661
|
if (!response || response.tag !== this.messageTag || response.id !== request.id) {
|
|
@@ -5595,17 +5668,97 @@ var ServiceWorkerArkadeSwaps = class _ServiceWorkerArkadeSwaps {
|
|
|
5595
5668
|
resolve(response);
|
|
5596
5669
|
}
|
|
5597
5670
|
};
|
|
5598
|
-
|
|
5671
|
+
navigator.serviceWorker.addEventListener("message", messageHandler);
|
|
5672
|
+
this.serviceWorker.postMessage(request);
|
|
5673
|
+
});
|
|
5674
|
+
}
|
|
5675
|
+
async sendMessage(request) {
|
|
5676
|
+
if (!DEDUPABLE_REQUEST_TYPES.has(request.type)) {
|
|
5677
|
+
return this.sendMessageWithRetry(request);
|
|
5678
|
+
}
|
|
5679
|
+
const key = getRequestDedupKey(request);
|
|
5680
|
+
const existing = this.inflightRequests.get(key);
|
|
5681
|
+
if (existing) return existing;
|
|
5682
|
+
const promise = this.sendMessageWithRetry(request).finally(() => {
|
|
5683
|
+
this.inflightRequests.delete(key);
|
|
5684
|
+
});
|
|
5685
|
+
this.inflightRequests.set(key, promise);
|
|
5686
|
+
return promise;
|
|
5687
|
+
}
|
|
5688
|
+
pingServiceWorker() {
|
|
5689
|
+
if (this.pingPromise) return this.pingPromise;
|
|
5690
|
+
this.pingPromise = new Promise((resolve, reject) => {
|
|
5691
|
+
const pingId = getRandomId();
|
|
5692
|
+
const cleanup = () => {
|
|
5693
|
+
clearTimeout(timeoutId);
|
|
5694
|
+
navigator.serviceWorker.removeEventListener(
|
|
5695
|
+
"message",
|
|
5696
|
+
onMessage
|
|
5697
|
+
);
|
|
5698
|
+
};
|
|
5699
|
+
const timeoutId = setTimeout(() => {
|
|
5599
5700
|
cleanup();
|
|
5600
5701
|
reject(
|
|
5601
|
-
new
|
|
5602
|
-
|
|
5702
|
+
new import_sdk10.ServiceWorkerTimeoutError(
|
|
5703
|
+
"Service worker ping timed out"
|
|
5603
5704
|
)
|
|
5604
5705
|
);
|
|
5605
|
-
},
|
|
5606
|
-
|
|
5607
|
-
|
|
5706
|
+
}, 2e3);
|
|
5707
|
+
const onMessage = (event) => {
|
|
5708
|
+
if (event.data?.id === pingId && event.data?.tag === "PONG") {
|
|
5709
|
+
cleanup();
|
|
5710
|
+
resolve();
|
|
5711
|
+
}
|
|
5712
|
+
};
|
|
5713
|
+
navigator.serviceWorker.addEventListener("message", onMessage);
|
|
5714
|
+
this.serviceWorker.postMessage({
|
|
5715
|
+
id: pingId,
|
|
5716
|
+
tag: "PING"
|
|
5717
|
+
});
|
|
5718
|
+
}).finally(() => {
|
|
5719
|
+
this.pingPromise = null;
|
|
5720
|
+
});
|
|
5721
|
+
return this.pingPromise;
|
|
5722
|
+
}
|
|
5723
|
+
// Send a message, retrying up to 2 times if the service worker was
|
|
5724
|
+
// killed and restarted by the OS (mobile browsers do this aggressively).
|
|
5725
|
+
async sendMessageWithRetry(request) {
|
|
5726
|
+
if (this.initPayload) {
|
|
5727
|
+
try {
|
|
5728
|
+
await this.pingServiceWorker();
|
|
5729
|
+
} catch {
|
|
5730
|
+
await this.reinitialize();
|
|
5731
|
+
}
|
|
5732
|
+
}
|
|
5733
|
+
const maxRetries = 2;
|
|
5734
|
+
for (let attempt = 0; ; attempt++) {
|
|
5735
|
+
try {
|
|
5736
|
+
return await this.sendMessageDirect(request);
|
|
5737
|
+
} catch (error) {
|
|
5738
|
+
if (!isMessageBusNotInitializedError(error) || attempt >= maxRetries) {
|
|
5739
|
+
throw error;
|
|
5740
|
+
}
|
|
5741
|
+
await this.reinitialize();
|
|
5742
|
+
}
|
|
5743
|
+
}
|
|
5744
|
+
}
|
|
5745
|
+
async reinitialize() {
|
|
5746
|
+
if (this.reinitPromise) return this.reinitPromise;
|
|
5747
|
+
this.reinitPromise = (async () => {
|
|
5748
|
+
if (!this.initPayload) {
|
|
5749
|
+
throw new Error("Cannot re-initialize: missing configuration");
|
|
5750
|
+
}
|
|
5751
|
+
const initMessage = {
|
|
5752
|
+
tag: this.messageTag,
|
|
5753
|
+
type: "INIT_ARKADE_SWAPS",
|
|
5754
|
+
id: getRandomId(),
|
|
5755
|
+
payload: this.initPayload
|
|
5756
|
+
};
|
|
5757
|
+
await this.sendMessageDirect(initMessage);
|
|
5758
|
+
})().finally(() => {
|
|
5759
|
+
this.reinitPromise = null;
|
|
5608
5760
|
});
|
|
5761
|
+
return this.reinitPromise;
|
|
5609
5762
|
}
|
|
5610
5763
|
initEventStream() {
|
|
5611
5764
|
if (this.eventListenerInitialized) return;
|
package/dist/index.d.cts
CHANGED
|
@@ -83,7 +83,17 @@ declare const getInvoiceSatoshis: (invoice: string) => number;
|
|
|
83
83
|
declare const getInvoicePaymentHash: (invoice: string) => string;
|
|
84
84
|
declare const isValidArkAddress: (address: string) => boolean;
|
|
85
85
|
|
|
86
|
-
|
|
86
|
+
/**
|
|
87
|
+
* Verifies that a transaction input has valid tapscript signatures
|
|
88
|
+
* from all required signers for a specific tapscript leaf.
|
|
89
|
+
*
|
|
90
|
+
* @param tx - The transaction to verify.
|
|
91
|
+
* @param inputIndex - The index of the input to check.
|
|
92
|
+
* @param requiredSigners - Hex-encoded x-only public keys of all required signers.
|
|
93
|
+
* @param expectedLeafHash - The tapscript leaf hash that signatures must commit to.
|
|
94
|
+
* @returns `true` if all required signers have valid signatures on the expected leaf, `false` otherwise.
|
|
95
|
+
*/
|
|
96
|
+
declare const verifySignatures: (tx: Transaction, inputIndex: number, requiredSigners: string[], expectedLeafHash: Uint8Array) => boolean;
|
|
87
97
|
|
|
88
98
|
/**
|
|
89
99
|
* Generic type for swap save functions
|
|
@@ -552,6 +562,10 @@ declare class ServiceWorkerArkadeSwaps implements IArkadeSwaps {
|
|
|
552
562
|
private actionExecutedListeners;
|
|
553
563
|
private wsConnectedListeners;
|
|
554
564
|
private wsDisconnectedListeners;
|
|
565
|
+
private initPayload;
|
|
566
|
+
private reinitPromise;
|
|
567
|
+
private pingPromise;
|
|
568
|
+
private inflightRequests;
|
|
555
569
|
private constructor();
|
|
556
570
|
static create(config: SvcWrkArkadeSwapsConfig): Promise<ServiceWorkerArkadeSwaps>;
|
|
557
571
|
startSwapManager(): Promise<void>;
|
|
@@ -644,7 +658,11 @@ declare class ServiceWorkerArkadeSwaps implements IArkadeSwaps {
|
|
|
644
658
|
refreshSwapsStatus(): Promise<void>;
|
|
645
659
|
dispose(): Promise<void>;
|
|
646
660
|
[Symbol.asyncDispose](): Promise<void>;
|
|
661
|
+
private sendMessageDirect;
|
|
647
662
|
private sendMessage;
|
|
663
|
+
private pingServiceWorker;
|
|
664
|
+
private sendMessageWithRetry;
|
|
665
|
+
private reinitialize;
|
|
648
666
|
private initEventStream;
|
|
649
667
|
private handleEventMessage;
|
|
650
668
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -83,7 +83,17 @@ declare const getInvoiceSatoshis: (invoice: string) => number;
|
|
|
83
83
|
declare const getInvoicePaymentHash: (invoice: string) => string;
|
|
84
84
|
declare const isValidArkAddress: (address: string) => boolean;
|
|
85
85
|
|
|
86
|
-
|
|
86
|
+
/**
|
|
87
|
+
* Verifies that a transaction input has valid tapscript signatures
|
|
88
|
+
* from all required signers for a specific tapscript leaf.
|
|
89
|
+
*
|
|
90
|
+
* @param tx - The transaction to verify.
|
|
91
|
+
* @param inputIndex - The index of the input to check.
|
|
92
|
+
* @param requiredSigners - Hex-encoded x-only public keys of all required signers.
|
|
93
|
+
* @param expectedLeafHash - The tapscript leaf hash that signatures must commit to.
|
|
94
|
+
* @returns `true` if all required signers have valid signatures on the expected leaf, `false` otherwise.
|
|
95
|
+
*/
|
|
96
|
+
declare const verifySignatures: (tx: Transaction, inputIndex: number, requiredSigners: string[], expectedLeafHash: Uint8Array) => boolean;
|
|
87
97
|
|
|
88
98
|
/**
|
|
89
99
|
* Generic type for swap save functions
|
|
@@ -552,6 +562,10 @@ declare class ServiceWorkerArkadeSwaps implements IArkadeSwaps {
|
|
|
552
562
|
private actionExecutedListeners;
|
|
553
563
|
private wsConnectedListeners;
|
|
554
564
|
private wsDisconnectedListeners;
|
|
565
|
+
private initPayload;
|
|
566
|
+
private reinitPromise;
|
|
567
|
+
private pingPromise;
|
|
568
|
+
private inflightRequests;
|
|
555
569
|
private constructor();
|
|
556
570
|
static create(config: SvcWrkArkadeSwapsConfig): Promise<ServiceWorkerArkadeSwaps>;
|
|
557
571
|
startSwapManager(): Promise<void>;
|
|
@@ -644,7 +658,11 @@ declare class ServiceWorkerArkadeSwaps implements IArkadeSwaps {
|
|
|
644
658
|
refreshSwapsStatus(): Promise<void>;
|
|
645
659
|
dispose(): Promise<void>;
|
|
646
660
|
[Symbol.asyncDispose](): Promise<void>;
|
|
661
|
+
private sendMessageDirect;
|
|
647
662
|
private sendMessage;
|
|
663
|
+
private pingServiceWorker;
|
|
664
|
+
private sendMessageWithRetry;
|
|
665
|
+
private reinitialize;
|
|
648
666
|
private initEventStream;
|
|
649
667
|
private handleEventMessage;
|
|
650
668
|
}
|
package/dist/index.js
CHANGED
|
@@ -49,7 +49,7 @@ import {
|
|
|
49
49
|
updateReverseSwapStatus,
|
|
50
50
|
updateSubmarineSwapStatus,
|
|
51
51
|
verifySignatures
|
|
52
|
-
} from "./chunk-
|
|
52
|
+
} from "./chunk-ZJ2Q5QSA.js";
|
|
53
53
|
import "./chunk-3RG5ZIWI.js";
|
|
54
54
|
|
|
55
55
|
// src/serviceWorker/arkade-swaps-message-handler.ts
|
|
@@ -526,6 +526,31 @@ var ArkadeSwapsMessageHandler = class _ArkadeSwapsMessageHandler {
|
|
|
526
526
|
};
|
|
527
527
|
|
|
528
528
|
// src/serviceWorker/arkade-swaps-runtime.ts
|
|
529
|
+
import {
|
|
530
|
+
MESSAGE_BUS_NOT_INITIALIZED,
|
|
531
|
+
ServiceWorkerTimeoutError
|
|
532
|
+
} from "@arkade-os/sdk";
|
|
533
|
+
function isMessageBusNotInitializedError(error) {
|
|
534
|
+
return error instanceof Error && error.message.includes(MESSAGE_BUS_NOT_INITIALIZED);
|
|
535
|
+
}
|
|
536
|
+
var DEDUPABLE_REQUEST_TYPES = /* @__PURE__ */ new Set([
|
|
537
|
+
"GET_FEES",
|
|
538
|
+
"GET_LIMITS",
|
|
539
|
+
"GET_SWAP_STATUS",
|
|
540
|
+
"GET_PENDING_SUBMARINE_SWAPS",
|
|
541
|
+
"GET_PENDING_REVERSE_SWAPS",
|
|
542
|
+
"GET_PENDING_CHAIN_SWAPS",
|
|
543
|
+
"GET_SWAP_HISTORY",
|
|
544
|
+
"QUOTE_SWAP",
|
|
545
|
+
"SM-GET_PENDING_SWAPS",
|
|
546
|
+
"SM-HAS_SWAP",
|
|
547
|
+
"SM-IS_PROCESSING",
|
|
548
|
+
"SM-GET_STATS"
|
|
549
|
+
]);
|
|
550
|
+
function getRequestDedupKey(request) {
|
|
551
|
+
const { id, tag, ...rest } = request;
|
|
552
|
+
return JSON.stringify(rest);
|
|
553
|
+
}
|
|
529
554
|
var ServiceWorkerArkadeSwaps = class _ServiceWorkerArkadeSwaps {
|
|
530
555
|
constructor(messageTag, serviceWorker, swapRepository, withSwapManager) {
|
|
531
556
|
this.messageTag = messageTag;
|
|
@@ -540,6 +565,10 @@ var ServiceWorkerArkadeSwaps = class _ServiceWorkerArkadeSwaps {
|
|
|
540
565
|
actionExecutedListeners = /* @__PURE__ */ new Set();
|
|
541
566
|
wsConnectedListeners = /* @__PURE__ */ new Set();
|
|
542
567
|
wsDisconnectedListeners = /* @__PURE__ */ new Set();
|
|
568
|
+
initPayload = null;
|
|
569
|
+
reinitPromise = null;
|
|
570
|
+
pingPromise = null;
|
|
571
|
+
inflightRequests = /* @__PURE__ */ new Map();
|
|
543
572
|
static async create(config) {
|
|
544
573
|
const messageTag = config.messageTag ?? DEFAULT_MESSAGE_TAG;
|
|
545
574
|
const swapRepository = config.swapRepository ?? new IndexedDbSwapRepository();
|
|
@@ -549,18 +578,20 @@ var ServiceWorkerArkadeSwaps = class _ServiceWorkerArkadeSwaps {
|
|
|
549
578
|
swapRepository,
|
|
550
579
|
Boolean(config.swapManager)
|
|
551
580
|
);
|
|
581
|
+
const initPayload = {
|
|
582
|
+
network: config.network,
|
|
583
|
+
arkServerUrl: config.arkServerUrl,
|
|
584
|
+
swapProvider: { baseUrl: config.swapProvider.getApiUrl() },
|
|
585
|
+
swapManager: config.swapManager
|
|
586
|
+
};
|
|
552
587
|
const initMessage = {
|
|
553
588
|
tag: messageTag,
|
|
554
589
|
id: getRandomId(),
|
|
555
590
|
type: "INIT_ARKADE_SWAPS",
|
|
556
|
-
payload:
|
|
557
|
-
network: config.network,
|
|
558
|
-
arkServerUrl: config.arkServerUrl,
|
|
559
|
-
swapProvider: { baseUrl: config.swapProvider.getApiUrl() },
|
|
560
|
-
swapManager: config.swapManager
|
|
561
|
-
}
|
|
591
|
+
payload: initPayload
|
|
562
592
|
};
|
|
563
593
|
await svcArkadeSwaps.sendMessage(initMessage);
|
|
594
|
+
svcArkadeSwaps.initPayload = initPayload;
|
|
564
595
|
return svcArkadeSwaps;
|
|
565
596
|
}
|
|
566
597
|
async startSwapManager() {
|
|
@@ -1101,17 +1132,23 @@ var ServiceWorkerArkadeSwaps = class _ServiceWorkerArkadeSwaps {
|
|
|
1101
1132
|
async [Symbol.asyncDispose]() {
|
|
1102
1133
|
return this.dispose();
|
|
1103
1134
|
}
|
|
1104
|
-
|
|
1135
|
+
sendMessageDirect(request) {
|
|
1105
1136
|
return new Promise((resolve, reject) => {
|
|
1106
|
-
const timeoutMs = 3e4;
|
|
1107
|
-
let timeout;
|
|
1108
1137
|
const cleanup = () => {
|
|
1109
|
-
|
|
1138
|
+
clearTimeout(timeoutId);
|
|
1110
1139
|
navigator.serviceWorker.removeEventListener(
|
|
1111
1140
|
"message",
|
|
1112
1141
|
messageHandler
|
|
1113
1142
|
);
|
|
1114
1143
|
};
|
|
1144
|
+
const timeoutId = setTimeout(() => {
|
|
1145
|
+
cleanup();
|
|
1146
|
+
reject(
|
|
1147
|
+
new ServiceWorkerTimeoutError(
|
|
1148
|
+
`Service worker message timed out (${request.type})`
|
|
1149
|
+
)
|
|
1150
|
+
);
|
|
1151
|
+
}, 3e4);
|
|
1115
1152
|
const messageHandler = (event) => {
|
|
1116
1153
|
const response = event.data;
|
|
1117
1154
|
if (!response || response.tag !== this.messageTag || response.id !== request.id) {
|
|
@@ -1124,17 +1161,97 @@ var ServiceWorkerArkadeSwaps = class _ServiceWorkerArkadeSwaps {
|
|
|
1124
1161
|
resolve(response);
|
|
1125
1162
|
}
|
|
1126
1163
|
};
|
|
1127
|
-
|
|
1164
|
+
navigator.serviceWorker.addEventListener("message", messageHandler);
|
|
1165
|
+
this.serviceWorker.postMessage(request);
|
|
1166
|
+
});
|
|
1167
|
+
}
|
|
1168
|
+
async sendMessage(request) {
|
|
1169
|
+
if (!DEDUPABLE_REQUEST_TYPES.has(request.type)) {
|
|
1170
|
+
return this.sendMessageWithRetry(request);
|
|
1171
|
+
}
|
|
1172
|
+
const key = getRequestDedupKey(request);
|
|
1173
|
+
const existing = this.inflightRequests.get(key);
|
|
1174
|
+
if (existing) return existing;
|
|
1175
|
+
const promise = this.sendMessageWithRetry(request).finally(() => {
|
|
1176
|
+
this.inflightRequests.delete(key);
|
|
1177
|
+
});
|
|
1178
|
+
this.inflightRequests.set(key, promise);
|
|
1179
|
+
return promise;
|
|
1180
|
+
}
|
|
1181
|
+
pingServiceWorker() {
|
|
1182
|
+
if (this.pingPromise) return this.pingPromise;
|
|
1183
|
+
this.pingPromise = new Promise((resolve, reject) => {
|
|
1184
|
+
const pingId = getRandomId();
|
|
1185
|
+
const cleanup = () => {
|
|
1186
|
+
clearTimeout(timeoutId);
|
|
1187
|
+
navigator.serviceWorker.removeEventListener(
|
|
1188
|
+
"message",
|
|
1189
|
+
onMessage
|
|
1190
|
+
);
|
|
1191
|
+
};
|
|
1192
|
+
const timeoutId = setTimeout(() => {
|
|
1128
1193
|
cleanup();
|
|
1129
1194
|
reject(
|
|
1130
|
-
new
|
|
1131
|
-
|
|
1195
|
+
new ServiceWorkerTimeoutError(
|
|
1196
|
+
"Service worker ping timed out"
|
|
1132
1197
|
)
|
|
1133
1198
|
);
|
|
1134
|
-
},
|
|
1135
|
-
|
|
1136
|
-
|
|
1199
|
+
}, 2e3);
|
|
1200
|
+
const onMessage = (event) => {
|
|
1201
|
+
if (event.data?.id === pingId && event.data?.tag === "PONG") {
|
|
1202
|
+
cleanup();
|
|
1203
|
+
resolve();
|
|
1204
|
+
}
|
|
1205
|
+
};
|
|
1206
|
+
navigator.serviceWorker.addEventListener("message", onMessage);
|
|
1207
|
+
this.serviceWorker.postMessage({
|
|
1208
|
+
id: pingId,
|
|
1209
|
+
tag: "PING"
|
|
1210
|
+
});
|
|
1211
|
+
}).finally(() => {
|
|
1212
|
+
this.pingPromise = null;
|
|
1213
|
+
});
|
|
1214
|
+
return this.pingPromise;
|
|
1215
|
+
}
|
|
1216
|
+
// Send a message, retrying up to 2 times if the service worker was
|
|
1217
|
+
// killed and restarted by the OS (mobile browsers do this aggressively).
|
|
1218
|
+
async sendMessageWithRetry(request) {
|
|
1219
|
+
if (this.initPayload) {
|
|
1220
|
+
try {
|
|
1221
|
+
await this.pingServiceWorker();
|
|
1222
|
+
} catch {
|
|
1223
|
+
await this.reinitialize();
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
1226
|
+
const maxRetries = 2;
|
|
1227
|
+
for (let attempt = 0; ; attempt++) {
|
|
1228
|
+
try {
|
|
1229
|
+
return await this.sendMessageDirect(request);
|
|
1230
|
+
} catch (error) {
|
|
1231
|
+
if (!isMessageBusNotInitializedError(error) || attempt >= maxRetries) {
|
|
1232
|
+
throw error;
|
|
1233
|
+
}
|
|
1234
|
+
await this.reinitialize();
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
}
|
|
1238
|
+
async reinitialize() {
|
|
1239
|
+
if (this.reinitPromise) return this.reinitPromise;
|
|
1240
|
+
this.reinitPromise = (async () => {
|
|
1241
|
+
if (!this.initPayload) {
|
|
1242
|
+
throw new Error("Cannot re-initialize: missing configuration");
|
|
1243
|
+
}
|
|
1244
|
+
const initMessage = {
|
|
1245
|
+
tag: this.messageTag,
|
|
1246
|
+
type: "INIT_ARKADE_SWAPS",
|
|
1247
|
+
id: getRandomId(),
|
|
1248
|
+
payload: this.initPayload
|
|
1249
|
+
};
|
|
1250
|
+
await this.sendMessageDirect(initMessage);
|
|
1251
|
+
})().finally(() => {
|
|
1252
|
+
this.reinitPromise = null;
|
|
1137
1253
|
});
|
|
1254
|
+
return this.reinitPromise;
|
|
1138
1255
|
}
|
|
1139
1256
|
initEventStream() {
|
|
1140
1257
|
if (this.eventListenerInitialized) return;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arkade-os/boltz-swap",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.8",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "A production-ready TypeScript package that brings Boltz submarine-swaps to Arkade.",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
"author": "Arkade-OS",
|
|
61
61
|
"license": "MIT",
|
|
62
62
|
"dependencies": {
|
|
63
|
-
"@arkade-os/sdk": "0.4.
|
|
63
|
+
"@arkade-os/sdk": "0.4.10",
|
|
64
64
|
"@noble/hashes": "2.0.1",
|
|
65
65
|
"@scure/base": "2.0.0",
|
|
66
66
|
"@scure/btc-signer": "2.0.1",
|