@arkade-os/boltz-swap 0.3.6 → 0.3.7

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.
@@ -2,8 +2,8 @@ import {
2
2
  defineExpoSwapBackgroundTask,
3
3
  registerExpoSwapBackgroundTask,
4
4
  unregisterExpoSwapBackgroundTask
5
- } from "./chunk-LMHVRFGY.js";
6
- import "./chunk-SUFFGYDJ.js";
5
+ } from "./chunk-XUBVFCQZ.js";
6
+ import "./chunk-ZJ2Q5QSA.js";
7
7
  import "./chunk-3RG5ZIWI.js";
8
8
  export {
9
9
  defineExpoSwapBackgroundTask,
@@ -8,7 +8,7 @@ import {
8
8
  isSubmarineFinalStatus,
9
9
  isSubmarineSwapRefundable,
10
10
  logger
11
- } from "./chunk-SUFFGYDJ.js";
11
+ } from "./chunk-ZJ2Q5QSA.js";
12
12
  import {
13
13
  __require
14
14
  } from "./chunk-3RG5ZIWI.js";
@@ -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
- return true;
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, Transaction as Transaction5 } from "@scure/btc-signer";
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
- if (!validFinalArkTx(finalArkTx, serverXOnlyPublicKey, vhtlcScript.leaves)) {
2745
- throw new Error("Invalid final Ark transaction");
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
- allowUnknown: true
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
- if (!verifySignatures(boltzSignedRefundTx, 0, [boltzXOnlyPublicKeyHex])) {
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
- if (!verifySignatures(boltzSignedCheckpointTx, 0, [boltzXOnlyPublicKeyHex])) {
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
- var validFinalArkTx = (finalArkTx, _pubkey, _tapLeaves) => {
2821
- const tx = Transaction5.fromPSBT(base643.decode(finalArkTx), {
2822
- allowUnknown: true
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.sendBitcoin({
3296
+ const txid = await this.wallet.send({
3257
3297
  address: pendingSwap.response.address,
3258
3298
  amount: pendingSwap.response.expectedAmount
3259
3299
  });
@@ -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
- return true;
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
- var import_sdk7, import_base8, import_legacy, import_btc_signer4, createVHTLCScript, joinBatch, claimVHTLCwithOffchainTx, refundVHTLCwithOffchainTx, validFinalArkTx;
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
- if (!validFinalArkTx(finalArkTx, serverXOnlyPublicKey, vhtlcScript.leaves)) {
2725
- throw new Error("Invalid final Ark transaction");
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 = import_btc_signer4.Transaction.fromPSBT(import_base8.base64.decode(c), {
2730
- allowUnknown: true
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
- if (!verifySignatures(boltzSignedRefundTx, 0, [boltzXOnlyPublicKeyHex])) {
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
- if (!verifySignatures(boltzSignedCheckpointTx, 0, [boltzXOnlyPublicKeyHex])) {
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 = import_btc_signer4.Transaction.fromPSBT(import_base8.base64.decode(finalArkTx));
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 = import_btc_signer4.Transaction.fromPSBT(
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.sendBitcoin({
3301
+ const txid = await this.wallet.send({
3263
3302
  address: pendingSwap.response.address,
3264
3303
  amount: pendingSwap.response.expectedAmount
3265
3304
  });
@@ -4,10 +4,10 @@ import {
4
4
  registerExpoSwapBackgroundTask,
5
5
  swapsPollProcessor,
6
6
  unregisterExpoSwapBackgroundTask
7
- } from "../chunk-LMHVRFGY.js";
7
+ } from "../chunk-XUBVFCQZ.js";
8
8
  import {
9
9
  ArkadeSwaps
10
- } from "../chunk-SUFFGYDJ.js";
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-5IKGSVTP.js");
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-5IKGSVTP.js");
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
- return true;
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
- if (!validFinalArkTx(finalArkTx, serverXOnlyPublicKey, vhtlcScript.leaves)) {
2805
- throw new Error("Invalid final Ark transaction");
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 = import_btc_signer4.Transaction.fromPSBT(import_base8.base64.decode(c), {
2810
- allowUnknown: true
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
- if (!verifySignatures(boltzSignedRefundTx, 0, [boltzXOnlyPublicKeyHex])) {
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
- if (!verifySignatures(boltzSignedCheckpointTx, 0, [boltzXOnlyPublicKeyHex])) {
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 = import_btc_signer4.Transaction.fromPSBT(import_base8.base64.decode(finalArkTx));
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 = import_btc_signer4.Transaction.fromPSBT(
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
- var validFinalArkTx = (finalArkTx, _pubkey, _tapLeaves) => {
2881
- const tx = import_btc_signer4.Transaction.fromPSBT(import_base8.base64.decode(finalArkTx), {
2882
- allowUnknown: true
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.sendBitcoin({
3355
+ const txid = await this.wallet.send({
3317
3356
  address: pendingSwap.response.address,
3318
3357
  amount: pendingSwap.response.expectedAmount
3319
3358
  });
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
- declare const verifySignatures: (tx: Transaction, inputIndex: number, requiredSigners: string[]) => boolean;
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
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
- declare const verifySignatures: (tx: Transaction, inputIndex: number, requiredSigners: string[]) => boolean;
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
package/dist/index.js CHANGED
@@ -49,7 +49,7 @@ import {
49
49
  updateReverseSwapStatus,
50
50
  updateSubmarineSwapStatus,
51
51
  verifySignatures
52
- } from "./chunk-SUFFGYDJ.js";
52
+ } from "./chunk-ZJ2Q5QSA.js";
53
53
  import "./chunk-3RG5ZIWI.js";
54
54
 
55
55
  // src/serviceWorker/arkade-swaps-message-handler.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arkade-os/boltz-swap",
3
- "version": "0.3.6",
3
+ "version": "0.3.7",
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.8",
63
+ "@arkade-os/sdk": "0.4.9",
64
64
  "@noble/hashes": "2.0.1",
65
65
  "@scure/base": "2.0.0",
66
66
  "@scure/btc-signer": "2.0.1",