@buildonspark/spark-sdk 0.1.38 → 0.1.40

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/android/build/intermediates/incremental/mergeDebugJniLibFolders/merger.xml +1 -1
  3. package/android/build/intermediates/library_jni/debug/copyDebugJniLibsProjectOnly/jni/arm64-v8a/libspark_frost.so +0 -0
  4. package/android/build/intermediates/library_jni/debug/copyDebugJniLibsProjectOnly/jni/arm64-v8a/libuniffi_spark_frost.so +0 -0
  5. package/android/build/intermediates/library_jni/debug/copyDebugJniLibsProjectOnly/jni/armeabi-v7a/libspark_frost.so +0 -0
  6. package/android/build/intermediates/library_jni/debug/copyDebugJniLibsProjectOnly/jni/armeabi-v7a/libuniffi_spark_frost.so +0 -0
  7. package/android/build/intermediates/library_jni/debug/copyDebugJniLibsProjectOnly/jni/x86/libspark_frost.so +0 -0
  8. package/android/build/intermediates/library_jni/debug/copyDebugJniLibsProjectOnly/jni/x86/libuniffi_spark_frost.so +0 -0
  9. package/android/build/intermediates/library_jni/debug/copyDebugJniLibsProjectOnly/jni/x86_64/libspark_frost.so +0 -0
  10. package/android/build/intermediates/library_jni/debug/copyDebugJniLibsProjectOnly/jni/x86_64/libuniffi_spark_frost.so +0 -0
  11. package/android/build/intermediates/merged_jni_libs/debug/mergeDebugJniLibFolders/out/arm64-v8a/libspark_frost.so +0 -0
  12. package/android/build/intermediates/merged_jni_libs/debug/mergeDebugJniLibFolders/out/arm64-v8a/libuniffi_spark_frost.so +0 -0
  13. package/android/build/intermediates/merged_jni_libs/debug/mergeDebugJniLibFolders/out/armeabi-v7a/libspark_frost.so +0 -0
  14. package/android/build/intermediates/merged_jni_libs/debug/mergeDebugJniLibFolders/out/armeabi-v7a/libuniffi_spark_frost.so +0 -0
  15. package/android/build/intermediates/merged_jni_libs/debug/mergeDebugJniLibFolders/out/x86/libspark_frost.so +0 -0
  16. package/android/build/intermediates/merged_jni_libs/debug/mergeDebugJniLibFolders/out/x86/libuniffi_spark_frost.so +0 -0
  17. package/android/build/intermediates/merged_jni_libs/debug/mergeDebugJniLibFolders/out/x86_64/libspark_frost.so +0 -0
  18. package/android/build/intermediates/merged_jni_libs/debug/mergeDebugJniLibFolders/out/x86_64/libuniffi_spark_frost.so +0 -0
  19. package/android/build/intermediates/merged_native_libs/debug/mergeDebugNativeLibs/out/lib/arm64-v8a/libspark_frost.so +0 -0
  20. package/android/build/intermediates/merged_native_libs/debug/mergeDebugNativeLibs/out/lib/arm64-v8a/libuniffi_spark_frost.so +0 -0
  21. package/android/build/intermediates/merged_native_libs/debug/mergeDebugNativeLibs/out/lib/armeabi-v7a/libspark_frost.so +0 -0
  22. package/android/build/intermediates/merged_native_libs/debug/mergeDebugNativeLibs/out/lib/armeabi-v7a/libuniffi_spark_frost.so +0 -0
  23. package/android/build/intermediates/merged_native_libs/debug/mergeDebugNativeLibs/out/lib/x86/libspark_frost.so +0 -0
  24. package/android/build/intermediates/merged_native_libs/debug/mergeDebugNativeLibs/out/lib/x86/libuniffi_spark_frost.so +0 -0
  25. package/android/build/intermediates/merged_native_libs/debug/mergeDebugNativeLibs/out/lib/x86_64/libspark_frost.so +0 -0
  26. package/android/build/intermediates/merged_native_libs/debug/mergeDebugNativeLibs/out/lib/x86_64/libuniffi_spark_frost.so +0 -0
  27. package/dist/{RequestLightningSendInput-B4JdzclX.d.ts → RequestLightningSendInput-CJtcHOnu.d.ts} +1 -1
  28. package/dist/{RequestLightningSendInput-39_zGri6.d.cts → RequestLightningSendInput-DfmfqzZo.d.cts} +1 -1
  29. package/dist/address/index.d.cts +1 -1
  30. package/dist/address/index.d.ts +1 -1
  31. package/dist/address/index.js +2 -2
  32. package/dist/{chunk-W3EC5XSA.js → chunk-5MNQB2T4.js} +2 -2
  33. package/dist/chunk-ED3ZAFDI.js +784 -0
  34. package/dist/{chunk-VJTDG4BQ.js → chunk-HK6LPV6Z.js} +10 -1
  35. package/dist/{chunk-7WRK6WNJ.js → chunk-LHT4QTFK.js} +556 -41
  36. package/dist/{chunk-RAPBVYJY.js → chunk-RFCXPGDM.js} +26 -4
  37. package/dist/{chunk-DI7QXUQJ.js → chunk-W2VXS35Y.js} +4 -4
  38. package/dist/graphql/objects/index.d.cts +5 -4
  39. package/dist/graphql/objects/index.d.ts +5 -4
  40. package/dist/{index-CxAi2L8y.d.ts → index-BDEYgYxP.d.ts} +42 -4
  41. package/dist/{index-Dm17Ggfe.d.cts → index-CLdtdMU4.d.cts} +42 -4
  42. package/dist/index.cjs +1069 -40
  43. package/dist/index.d.cts +6 -6
  44. package/dist/index.d.ts +6 -6
  45. package/dist/index.js +33 -17
  46. package/dist/index.node.cjs +1069 -40
  47. package/dist/index.node.d.cts +6 -6
  48. package/dist/index.node.d.ts +6 -6
  49. package/dist/index.node.js +33 -17
  50. package/dist/native/index.cjs +1069 -40
  51. package/dist/native/index.d.cts +108 -5
  52. package/dist/native/index.d.ts +108 -5
  53. package/dist/native/index.js +1065 -40
  54. package/dist/{network-GFGEHkS4.d.cts → network-B10hBoHp.d.cts} +8 -1
  55. package/dist/{network-DobHpaV6.d.ts → network-CCgyIsGl.d.ts} +8 -1
  56. package/dist/services/config.cjs +29 -12
  57. package/dist/services/config.d.cts +4 -4
  58. package/dist/services/config.d.ts +4 -4
  59. package/dist/services/config.js +5 -5
  60. package/dist/services/connection.d.cts +4 -4
  61. package/dist/services/connection.d.ts +4 -4
  62. package/dist/services/connection.js +2 -2
  63. package/dist/services/index.cjs +30 -13
  64. package/dist/services/index.d.cts +4 -4
  65. package/dist/services/index.d.ts +4 -4
  66. package/dist/services/index.js +8 -8
  67. package/dist/services/lrc-connection.d.cts +4 -4
  68. package/dist/services/lrc-connection.d.ts +4 -4
  69. package/dist/services/lrc-connection.js +1 -1
  70. package/dist/services/token-transactions.cjs +1 -1
  71. package/dist/services/token-transactions.d.cts +4 -4
  72. package/dist/services/token-transactions.d.ts +4 -4
  73. package/dist/services/token-transactions.js +3 -3
  74. package/dist/services/wallet-config.d.cts +4 -4
  75. package/dist/services/wallet-config.d.ts +4 -4
  76. package/dist/signer/signer.cjs +23 -6
  77. package/dist/signer/signer.d.cts +3 -2
  78. package/dist/signer/signer.d.ts +3 -2
  79. package/dist/signer/signer.js +1 -1
  80. package/dist/{signer-DFGw9RRp.d.ts → signer-C5h1DpjF.d.ts} +4 -1
  81. package/dist/{signer-C1t40Wus.d.cts → signer-CYwn7h9U.d.cts} +4 -1
  82. package/dist/types/index.d.cts +4 -3
  83. package/dist/types/index.d.ts +4 -3
  84. package/dist/utils/index.cjs +891 -2
  85. package/dist/utils/index.d.cts +62 -6
  86. package/dist/utils/index.d.ts +62 -6
  87. package/dist/utils/index.js +23 -7
  88. package/package.json +1 -1
  89. package/src/services/deposit.ts +23 -5
  90. package/src/services/token-transactions.ts +1 -1
  91. package/src/services/transfer.ts +218 -11
  92. package/src/services/tree-creation.ts +29 -14
  93. package/src/signer/signer.ts +47 -5
  94. package/src/spark-wallet/spark-wallet.ts +430 -4
  95. package/src/tests/integration/swap.test.ts +225 -0
  96. package/src/tests/integration/tree-creation.test.ts +5 -1
  97. package/src/utils/index.ts +1 -0
  98. package/src/utils/mempool.ts +26 -1
  99. package/src/utils/network.ts +15 -0
  100. package/src/utils/transaction.ts +22 -2
  101. package/src/utils/unilateral-exit.ts +729 -0
  102. package/dist/chunk-E5SL7XTO.js +0 -301
  103. package/dist/{chunk-LIP2K6KR.js → chunk-2CDJZQN4.js} +3 -3
  104. package/dist/{chunk-RGWBSZIO.js → chunk-I4JI6TYN.js} +4 -4
@@ -211,6 +211,7 @@ var NativeSparkFrost = class {
211
211
  import {
212
212
  bytesToHex as bytesToHex2,
213
213
  bytesToNumberBE as bytesToNumberBE2,
214
+ equalBytes as equalBytes2,
214
215
  hexToBytes
215
216
  } from "@noble/curves/abstract/utils";
216
217
  import { schnorr as schnorr2, secp256k1 as secp256k15 } from "@noble/curves/secp256k1";
@@ -738,11 +739,13 @@ function decodeBytesToSigningCommitment(bytes) {
738
739
  }
739
740
 
740
741
  // src/signer/signer.ts
741
- import { PARITY } from "@buildonspark/lrc20-sdk";
742
- import { Receipt } from "@buildonspark/lrc20-sdk";
743
- import { privateNegate, privateAdd } from "@bitcoinerlab/secp256k1";
742
+ import { privateAdd, privateNegate } from "@bitcoinerlab/secp256k1";
743
+ import {
744
+ fromPrivateKey,
745
+ PARITY,
746
+ Receipt
747
+ } from "@buildonspark/lrc20-sdk";
744
748
  import { sha256 } from "@noble/hashes/sha2";
745
- import { fromPrivateKey } from "@buildonspark/lrc20-sdk";
746
749
  var sparkFrostModule = void 0;
747
750
  var getSparkFrostModule = async () => {
748
751
  if (isReactNative) {
@@ -1228,6 +1231,25 @@ var DefaultSparkSigner = class {
1228
1231
  const receiptProof = privateAdd(privateKey, pxhPubkey);
1229
1232
  return Buffer.from(receiptProof);
1230
1233
  }
1234
+ signTransactionIndex(tx, index, publicKey) {
1235
+ let privateKey;
1236
+ if (equalBytes2(publicKey, this.identityKey?.publicKey ?? new Uint8Array())) {
1237
+ privateKey = this.identityKey?.privateKey;
1238
+ } else if (equalBytes2(publicKey, this.depositKey?.publicKey ?? new Uint8Array())) {
1239
+ privateKey = this.depositKey?.privateKey;
1240
+ } else {
1241
+ privateKey = hexToBytes(
1242
+ this.publicKeyToPrivateKeyMap.get(bytesToHex2(publicKey)) ?? ""
1243
+ );
1244
+ }
1245
+ if (!privateKey) {
1246
+ throw new ValidationError("Private key not found for public key", {
1247
+ field: "privateKey",
1248
+ value: bytesToHex2(publicKey)
1249
+ });
1250
+ }
1251
+ tx.signIdx(privateKey, index);
1252
+ }
1231
1253
  };
1232
1254
 
1233
1255
  // src/signer/signer.react-native.ts
@@ -1298,7 +1320,7 @@ import { isNode as isNode4, mapCurrencyAmount } from "@lightsparkdev/core";
1298
1320
  import {
1299
1321
  bytesToHex as bytesToHex12,
1300
1322
  bytesToNumberBE as bytesToNumberBE7,
1301
- equalBytes as equalBytes4,
1323
+ equalBytes as equalBytes5,
1302
1324
  hexToBytes as hexToBytes13
1303
1325
  } from "@noble/curves/abstract/utils";
1304
1326
  import { secp256k1 as secp256k115 } from "@noble/curves/secp256k1";
@@ -16313,6 +16335,14 @@ function getNetworkFromAddress(address2) {
16313
16335
  }
16314
16336
  return null;
16315
16337
  }
16338
+ function getNetworkFromString(network) {
16339
+ const net = (network ?? "REGTEST").toUpperCase();
16340
+ if (net === "MAINNET") return 0 /* MAINNET */;
16341
+ if (net === "TESTNET") return 1 /* TESTNET */;
16342
+ if (net === "SIGNET") return 2 /* SIGNET */;
16343
+ if (net === "LOCAL") return 4 /* LOCAL */;
16344
+ return 3 /* REGTEST */;
16345
+ }
16316
16346
 
16317
16347
  // src/tests/isHermeticTest.ts
16318
16348
  import { isNode } from "@lightsparkdev/core";
@@ -17864,8 +17894,20 @@ function getTxIdNoReverse(tx) {
17864
17894
  // src/utils/transaction.ts
17865
17895
  import { Transaction as Transaction2 } from "@scure/btc-signer";
17866
17896
  var TIME_LOCK_INTERVAL = 100;
17897
+ var ESTIMATED_TX_SIZE = 191;
17898
+ var DEFAULT_SATS_PER_VBYTE = 5;
17899
+ var DEFAULT_FEE_SATS = ESTIMATED_TX_SIZE * DEFAULT_SATS_PER_VBYTE;
17900
+ function maybeApplyFee(amount) {
17901
+ if (amount > BigInt(DEFAULT_FEE_SATS)) {
17902
+ return amount - BigInt(DEFAULT_FEE_SATS);
17903
+ }
17904
+ return amount;
17905
+ }
17867
17906
  function createRefundTx(sequence, nodeOutPoint, amountSats, receivingPubkey, network) {
17868
- const newRefundTx = new Transaction2({ allowUnknownOutputs: true });
17907
+ const newRefundTx = new Transaction2({
17908
+ version: 3,
17909
+ allowUnknownOutputs: true
17910
+ });
17869
17911
  newRefundTx.addInput({
17870
17912
  ...nodeOutPoint,
17871
17913
  sequence
@@ -17894,7 +17936,7 @@ function getNextTransactionSequence(currSequence, forRefresh) {
17894
17936
  needRefresh: true
17895
17937
  };
17896
17938
  }
17897
- if (nextTimelock <= 0) {
17939
+ if (nextTimelock < 0) {
17898
17940
  throw new ValidationError("timelock interval is less than or equal to 0", {
17899
17941
  field: "nextTimelock",
17900
17942
  value: nextTimelock
@@ -17916,7 +17958,7 @@ function getEphemeralAnchorOutput() {
17916
17958
  // src/services/transfer.ts
17917
17959
  import {
17918
17960
  bytesToHex as bytesToHex6,
17919
- equalBytes as equalBytes2,
17961
+ equalBytes as equalBytes3,
17920
17962
  hexToBytes as hexToBytes5,
17921
17963
  numberToBytesBE as numberToBytesBE3
17922
17964
  } from "@noble/curves/abstract/utils";
@@ -18008,6 +18050,32 @@ var BaseTransferService = class {
18008
18050
  }
18009
18051
  return updatedTransfer;
18010
18052
  }
18053
+ async deliverTransferPackage(transfer, leaves, refundSignatureMap) {
18054
+ const keyTweakInputMap = await this.prepareSendTransferKeyTweaks(
18055
+ transfer.id,
18056
+ transfer.receiverIdentityPublicKey,
18057
+ leaves,
18058
+ refundSignatureMap
18059
+ );
18060
+ const transferPackage = await this.prepareTransferPackage(
18061
+ transfer.id,
18062
+ keyTweakInputMap,
18063
+ leaves,
18064
+ transfer.receiverIdentityPublicKey
18065
+ );
18066
+ const sparkClient = await this.connectionManager.createSparkClient(
18067
+ this.config.getCoordinatorAddress()
18068
+ );
18069
+ const response = await sparkClient.finalize_transfer_with_transfer_package({
18070
+ transferId: transfer.id,
18071
+ ownerIdentityPublicKey: await this.config.signer.getIdentityPublicKey(),
18072
+ transferPackage
18073
+ });
18074
+ if (!response.transfer) {
18075
+ throw new ValidationError("No transfer response from operator");
18076
+ }
18077
+ return response.transfer;
18078
+ }
18011
18079
  async sendTransferWithKeyTweaks(leaves, receiverIdentityPubkey) {
18012
18080
  const transferID = uuidv7();
18013
18081
  const keyTweakInputMap = await this.prepareSendTransferKeyTweaks(
@@ -18279,7 +18347,7 @@ var BaseTransferService = class {
18279
18347
  return void 0;
18280
18348
  }
18281
18349
  compareTransfers(transfer1, transfer2) {
18282
- return transfer1.id === transfer2.id && equalBytes2(
18350
+ return transfer1.id === transfer2.id && equalBytes3(
18283
18351
  transfer1.senderIdentityPublicKey,
18284
18352
  transfer2.senderIdentityPublicKey
18285
18353
  ) && transfer1.status === transfer2.status && transfer1.totalValue === transfer2.totalValue && transfer1.expiryTime?.getTime() === transfer2.expiryTime?.getTime() && transfer1.leaves.length === transfer2.leaves.length;
@@ -18765,9 +18833,20 @@ var TransferService = class extends BaseTransferService {
18765
18833
  if (!input) {
18766
18834
  throw Error("Could not fetch tx input");
18767
18835
  }
18768
- const newTx = new Transaction3({ allowUnknownOutputs: true });
18769
- for (let j = 0; j < nodeTx.outputsLength; j++) {
18770
- newTx.addOutput(nodeTx.getOutput(j));
18836
+ const newTx = new Transaction3({ version: 3, allowUnknownOutputs: true });
18837
+ const originalOutput = nodeTx.getOutput(0);
18838
+ if (!originalOutput) {
18839
+ throw Error("Could not get original output");
18840
+ }
18841
+ newTx.addOutput({
18842
+ script: originalOutput.script,
18843
+ amount: originalOutput.amount
18844
+ });
18845
+ for (let j = 1; j < nodeTx.outputsLength; j++) {
18846
+ const additionalOutput = nodeTx.getOutput(j);
18847
+ if (additionalOutput) {
18848
+ newTx.addOutput(additionalOutput);
18849
+ }
18771
18850
  }
18772
18851
  if (i === 0) {
18773
18852
  const currSequence = input.sequence;
@@ -18794,9 +18873,23 @@ var TransferService = class extends BaseTransferService {
18794
18873
  throw Error("leaf does not have refund tx");
18795
18874
  }
18796
18875
  const refundTx = getTxFromRawTxBytes(leaf?.refundTx);
18797
- const newRefundTx = new Transaction3({ allowUnknownOutputs: true });
18798
- for (let j = 0; j < refundTx.outputsLength; j++) {
18799
- newRefundTx.addOutput(refundTx.getOutput(j));
18876
+ const newRefundTx = new Transaction3({
18877
+ version: 3,
18878
+ allowUnknownOutputs: true
18879
+ });
18880
+ const originalRefundOutput = refundTx.getOutput(0);
18881
+ if (!originalRefundOutput) {
18882
+ throw Error("Could not get original refund output");
18883
+ }
18884
+ newRefundTx.addOutput({
18885
+ script: originalRefundOutput.script,
18886
+ amount: originalRefundOutput.amount
18887
+ });
18888
+ for (let j = 1; j < refundTx.outputsLength; j++) {
18889
+ const additionalOutput = refundTx.getOutput(j);
18890
+ if (additionalOutput) {
18891
+ newRefundTx.addOutput(additionalOutput);
18892
+ }
18800
18893
  }
18801
18894
  const refundTxInput = refundTx.getInput(0);
18802
18895
  if (!refundTxInput) {
@@ -18905,10 +18998,11 @@ var TransferService = class extends BaseTransferService {
18905
18998
  nodeTxSignature: leafSignature,
18906
18999
  refundTxSignature: refundSignature
18907
19000
  });
18908
- return await sparkClient.finalize_node_signatures({
19001
+ const result = await sparkClient.finalize_node_signatures({
18909
19002
  intent: 3 /* REFRESH */,
18910
19003
  nodeSignatures
18911
19004
  });
19005
+ return result;
18912
19006
  }
18913
19007
  async extendTimelock(node, signingPubKey) {
18914
19008
  const nodeTx = getTxFromRawTxBytes(node.nodeTx);
@@ -18919,9 +19013,20 @@ var TransferService = class extends BaseTransferService {
18919
19013
  index: 0
18920
19014
  };
18921
19015
  const { nextSequence: newNodeSequence } = getNextTransactionSequence(refundSequence);
18922
- const newNodeTx = new Transaction3({ allowUnknownOutputs: true });
19016
+ const newNodeTx = new Transaction3({
19017
+ version: 3,
19018
+ allowUnknownOutputs: true
19019
+ });
18923
19020
  newNodeTx.addInput({ ...newNodeOutPoint, sequence: newNodeSequence });
18924
- newNodeTx.addOutput(nodeTx.getOutput(0));
19021
+ const originalOutput = nodeTx.getOutput(0);
19022
+ if (!originalOutput) {
19023
+ throw Error("Could not get original node output");
19024
+ }
19025
+ newNodeTx.addOutput({
19026
+ script: originalOutput.script,
19027
+ amount: originalOutput.amount
19028
+ // feeReducedAmount,
19029
+ });
18925
19030
  newNodeTx.addOutput(getEphemeralAnchorOutput());
18926
19031
  const newRefundOutPoint = {
18927
19032
  txid: hexToBytes5(getTxId(newNodeTx)),
@@ -18935,11 +19040,16 @@ var TransferService = class extends BaseTransferService {
18935
19040
  initialSequence(),
18936
19041
  newRefundOutPoint,
18937
19042
  amountSats,
19043
+ // feeReducedRefundAmount,
18938
19044
  signingPubKey,
18939
19045
  this.config.getNetwork()
18940
19046
  );
18941
19047
  const nodeSighash = getSigHashFromTx(newNodeTx, 0, nodeTx.getOutput(0));
18942
- const refundSighash = getSigHashFromTx(newRefundTx, 0, nodeTx.getOutput(0));
19048
+ const refundSighash = getSigHashFromTx(
19049
+ newRefundTx,
19050
+ 0,
19051
+ newNodeTx.getOutput(0)
19052
+ );
18943
19053
  const newNodeSigningJob = {
18944
19054
  signingPublicKey: signingPubKey,
18945
19055
  rawTx: newNodeTx.toBytes(),
@@ -19013,6 +19123,94 @@ var TransferService = class extends BaseTransferService {
19013
19123
  ]
19014
19124
  });
19015
19125
  }
19126
+ async refreshTimelockRefundTx(node, signingPubKey) {
19127
+ const nodeTx = getTxFromRawTxBytes(node.nodeTx);
19128
+ const refundTx = getTxFromRawTxBytes(node.refundTx);
19129
+ const currSequence = refundTx.getInput(0).sequence || 0;
19130
+ const { nextSequence } = getNextTransactionSequence(currSequence);
19131
+ const newRefundTx = new Transaction3({
19132
+ version: 3,
19133
+ allowUnknownOutputs: true
19134
+ });
19135
+ const originalRefundOutput = refundTx.getOutput(0);
19136
+ if (!originalRefundOutput) {
19137
+ throw Error("Could not get original refund output");
19138
+ }
19139
+ newRefundTx.addOutput({
19140
+ script: originalRefundOutput.script,
19141
+ amount: originalRefundOutput.amount
19142
+ });
19143
+ for (let j = 1; j < refundTx.outputsLength; j++) {
19144
+ const additionalOutput = refundTx.getOutput(j);
19145
+ if (additionalOutput) {
19146
+ newRefundTx.addOutput(additionalOutput);
19147
+ }
19148
+ }
19149
+ const refundTxInput = refundTx.getInput(0);
19150
+ if (!refundTxInput) {
19151
+ throw Error("refund tx doesn't have input");
19152
+ }
19153
+ newRefundTx.addInput({
19154
+ ...refundTxInput,
19155
+ sequence: nextSequence
19156
+ });
19157
+ const refundSigningJob = {
19158
+ signingPublicKey: signingPubKey,
19159
+ rawTx: newRefundTx.toBytes(),
19160
+ signingNonceCommitment: await this.config.signer.getRandomSigningCommitment()
19161
+ };
19162
+ const sparkClient = await this.connectionManager.createSparkClient(
19163
+ this.config.getCoordinatorAddress()
19164
+ );
19165
+ const response = await sparkClient.refresh_timelock({
19166
+ leafId: node.id,
19167
+ ownerIdentityPublicKey: await this.config.signer.getIdentityPublicKey(),
19168
+ signingJobs: [refundSigningJob]
19169
+ });
19170
+ if (response.signingResults.length !== 1) {
19171
+ throw Error(
19172
+ `Expected 1 signing result, got ${response.signingResults.length}`
19173
+ );
19174
+ }
19175
+ const signingResult = response.signingResults[0];
19176
+ if (!signingResult || !refundSigningJob.signingNonceCommitment) {
19177
+ throw Error("Signing result or nonce commitment does not exist");
19178
+ }
19179
+ const rawTx = getTxFromRawTxBytes(refundSigningJob.rawTx);
19180
+ const txOut = nodeTx.getOutput(0);
19181
+ const rawTxSighash = getSigHashFromTx(rawTx, 0, txOut);
19182
+ const userSignature = await this.config.signer.signFrost({
19183
+ message: rawTxSighash,
19184
+ privateAsPubKey: signingPubKey,
19185
+ publicKey: signingPubKey,
19186
+ verifyingKey: signingResult.verifyingKey,
19187
+ selfCommitment: refundSigningJob.signingNonceCommitment,
19188
+ statechainCommitments: signingResult.signingResult?.signingNonceCommitments,
19189
+ adaptorPubKey: new Uint8Array()
19190
+ });
19191
+ const signature = await this.config.signer.aggregateFrost({
19192
+ message: rawTxSighash,
19193
+ statechainSignatures: signingResult.signingResult?.signatureShares,
19194
+ statechainPublicKeys: signingResult.signingResult?.publicKeys,
19195
+ verifyingKey: signingResult.verifyingKey,
19196
+ statechainCommitments: signingResult.signingResult?.signingNonceCommitments,
19197
+ selfCommitment: refundSigningJob.signingNonceCommitment,
19198
+ publicKey: signingPubKey,
19199
+ selfSignature: userSignature,
19200
+ adaptorPubKey: new Uint8Array()
19201
+ });
19202
+ const result = await sparkClient.finalize_node_signatures({
19203
+ intent: 3 /* REFRESH */,
19204
+ nodeSignatures: [
19205
+ {
19206
+ nodeId: node.id,
19207
+ nodeTxSignature: new Uint8Array(),
19208
+ refundTxSignature: signature
19209
+ }
19210
+ ]
19211
+ });
19212
+ return result;
19213
+ }
19016
19214
  };
19017
19215
 
19018
19216
  // src/services/coop-exit.ts
@@ -19180,7 +19378,7 @@ import { sha256 as sha2568 } from "@noble/hashes/sha2";
19180
19378
  import { hexToBytes as hexToBytes6 } from "@noble/hashes/utils";
19181
19379
  import * as btc3 from "@scure/btc-signer";
19182
19380
  import { p2tr as p2tr2, Transaction as Transaction5 } from "@scure/btc-signer";
19183
- import { equalBytes as equalBytes3 } from "@scure/btc-signer/utils";
19381
+ import { equalBytes as equalBytes4 } from "@scure/btc-signer/utils";
19184
19382
 
19185
19383
  // src/utils/proof.ts
19186
19384
  import { sha256 as sha2567 } from "@noble/hashes/sha2";
@@ -19314,7 +19512,7 @@ var DepositService = class {
19314
19512
  depositTx,
19315
19513
  vout
19316
19514
  }) {
19317
- const rootTx = new Transaction5();
19515
+ const rootTx = new Transaction5({ version: 3 });
19318
19516
  const output = depositTx.getOutput(vout);
19319
19517
  if (!output) {
19320
19518
  throw new ValidationError("Invalid deposit transaction output", {
@@ -19332,17 +19530,19 @@ var DepositService = class {
19332
19530
  expected: "Output with script and amount"
19333
19531
  });
19334
19532
  }
19533
+ let outputAmount = amount;
19335
19534
  rootTx.addInput({
19336
19535
  txid: getTxId(depositTx),
19337
19536
  index: vout
19338
19537
  });
19339
19538
  rootTx.addOutput({
19340
19539
  script,
19341
- amount
19540
+ amount: outputAmount
19342
19541
  });
19542
+ rootTx.addOutput(getEphemeralAnchorOutput());
19343
19543
  const rootNonceCommitment = await this.config.signer.getRandomSigningCommitment();
19344
19544
  const rootTxSighash = getSigHashFromTx(rootTx, 0, output);
19345
- const refundTx = new Transaction5();
19545
+ const refundTx = new Transaction5({ version: 3 });
19346
19546
  const sequence = 1 << 30 | INITIAL_TIME_LOCK2;
19347
19547
  refundTx.addInput({
19348
19548
  txid: getTxId(rootTx),
@@ -19357,10 +19557,11 @@ var DepositService = class {
19357
19557
  const refundPkScript = btc3.OutScript.encode(refundAddress);
19358
19558
  refundTx.addOutput({
19359
19559
  script: refundPkScript,
19360
- amount
19560
+ amount: outputAmount
19361
19561
  });
19562
+ refundTx.addOutput(getEphemeralAnchorOutput());
19362
19563
  const refundNonceCommitment = await this.config.signer.getRandomSigningCommitment();
19363
- const refundTxSighash = getSigHashFromTx(refundTx, 0, output);
19564
+ const refundTxSighash = getSigHashFromTx(refundTx, 0, rootTx.getOutput(0));
19364
19565
  const sparkClient = await this.connectionManager.createSparkClient(
19365
19566
  this.config.getCoordinatorAddress()
19366
19567
  );
@@ -19420,7 +19621,7 @@ var DepositService = class {
19420
19621
  }
19421
19622
  );
19422
19623
  }
19423
- if (!equalBytes3(treeResp.rootNodeSignatureShares.verifyingKey, verifyingKey)) {
19624
+ if (!equalBytes4(treeResp.rootNodeSignatureShares.verifyingKey, verifyingKey)) {
19424
19625
  throw new ValidationError("Verifying key mismatch", {
19425
19626
  field: "verifyingKey",
19426
19627
  value: treeResp.rootNodeSignatureShares.verifyingKey,
@@ -23862,7 +24063,7 @@ function isValidPublicKey(publicKey) {
23862
24063
  }
23863
24064
 
23864
24065
  // src/services/token-transactions.ts
23865
- var MAX_TOKEN_OUTPUTS = 1e3;
24066
+ var MAX_TOKEN_OUTPUTS = 500;
23866
24067
  var TokenTransactionService = class {
23867
24068
  config;
23868
24069
  connectionManager;
@@ -24426,6 +24627,12 @@ import { hexToBytes as hexToBytes10 } from "@noble/curves/abstract/utils";
24426
24627
  import { sha256 as sha25612 } from "@noble/hashes/sha2";
24427
24628
  import { Address as Address4, OutScript as OutScript3, Transaction as Transaction7 } from "@scure/btc-signer";
24428
24629
  var INITIAL_TIME_LOCK3 = 2e3;
24630
+ function maybeApplyFee3(amount) {
24631
+ if (amount > BigInt(DEFAULT_FEE_SATS)) {
24632
+ return amount - BigInt(DEFAULT_FEE_SATS);
24633
+ }
24634
+ return amount;
24635
+ }
24429
24636
  var TreeCreationService = class {
24430
24637
  config;
24431
24638
  connectionManager;
@@ -24624,7 +24831,7 @@ var TreeCreationService = class {
24624
24831
  refundTxSigningJob: void 0,
24625
24832
  children: []
24626
24833
  };
24627
- const tx = new Transaction7();
24834
+ const tx = new Transaction7({ version: 3 });
24628
24835
  tx.addInput({
24629
24836
  txid: getTxId(parentTx),
24630
24837
  index: vout
@@ -24636,6 +24843,7 @@ var TreeCreationService = class {
24636
24843
  tx.addOutput({
24637
24844
  script: parentTxOut.script,
24638
24845
  amount: parentTxOut.amount
24846
+ // maybeApplyFee(parentTxOut.amount),
24639
24847
  });
24640
24848
  tx.addOutput(getEphemeralAnchorOutput());
24641
24849
  const signingNonceCommitment = await this.config.signer.getRandomSigningCommitment();
@@ -24652,7 +24860,7 @@ var TreeCreationService = class {
24652
24860
  refundTxSigningJob: void 0,
24653
24861
  children: []
24654
24862
  };
24655
- const childTx = new Transaction7();
24863
+ const childTx = new Transaction7({ version: 3 });
24656
24864
  childTx.addInput({
24657
24865
  txid: getTxId(tx),
24658
24866
  index: 0,
@@ -24661,6 +24869,7 @@ var TreeCreationService = class {
24661
24869
  childTx.addOutput({
24662
24870
  script: parentTxOut.script,
24663
24871
  amount: parentTxOut.amount
24872
+ // maybeApplyFee(parentTxOut.amount),
24664
24873
  });
24665
24874
  childTx.addOutput(getEphemeralAnchorOutput());
24666
24875
  const childSigningNonceCommitment = await this.config.signer.getRandomSigningCommitment();
@@ -24671,7 +24880,7 @@ var TreeCreationService = class {
24671
24880
  };
24672
24881
  childCreationNode.nodeTxSigningCommitment = childSigningNonceCommitment;
24673
24882
  childCreationNode.nodeTxSigningJob = childSigningJob;
24674
- const refundTx = new Transaction7();
24883
+ const refundTx = new Transaction7({ version: 3 });
24675
24884
  refundTx.addInput({
24676
24885
  txid: getTxId(childTx),
24677
24886
  index: 0,
@@ -24687,8 +24896,9 @@ var TreeCreationService = class {
24687
24896
  const refundPkScript = OutScript3.encode(refundAddress);
24688
24897
  refundTx.addOutput({
24689
24898
  script: refundPkScript,
24690
- amount: parentTxOut.amount
24899
+ amount: maybeApplyFee3(parentTxOut.amount)
24691
24900
  });
24901
+ refundTx.addOutput(getEphemeralAnchorOutput());
24692
24902
  const refundSigningNonceCommitment = await this.config.signer.getRandomSigningCommitment();
24693
24903
  const refundSigningJob = {
24694
24904
  signingPublicKey: node.signingPublicKey,
@@ -24705,7 +24915,7 @@ var TreeCreationService = class {
24705
24915
  if (!parentTxOutput?.script || !parentTxOutput?.amount) {
24706
24916
  throw new Error("parentTxOutput is undefined");
24707
24917
  }
24708
- const rootNodeTx = new Transaction7();
24918
+ const rootNodeTx = new Transaction7({ version: 3 });
24709
24919
  rootNodeTx.addInput({
24710
24920
  txid: getTxId(parentTx),
24711
24921
  index: vout
@@ -24720,10 +24930,10 @@ var TreeCreationService = class {
24720
24930
  rootNodeTx.addOutput({
24721
24931
  script: childPkScript,
24722
24932
  amount: parentTxOutput.amount / 2n
24933
+ // feeAdjustedAmount / 2n,
24723
24934
  });
24724
24935
  }
24725
- const anchor = getEphemeralAnchorOutput();
24726
- rootNodeTx.addOutput(anchor);
24936
+ rootNodeTx.addOutput(getEphemeralAnchorOutput());
24727
24937
  const rootNodeSigningCommitment = await this.config.signer.getRandomSigningCommitment();
24728
24938
  const rootNodeSigningJob = {
24729
24939
  signingPublicKey: root.signingPublicKey,
@@ -25410,7 +25620,7 @@ var SparkWallet = class _SparkWallet extends EventEmitter {
25410
25620
  try {
25411
25621
  if (event?.$case === "transfer" && event.transfer.transfer && event.transfer.transfer.type !== 40 /* COUNTER_SWAP */) {
25412
25622
  const { senderIdentityPublicKey, receiverIdentityPublicKey } = event.transfer.transfer;
25413
- if (event.transfer.transfer && !equalBytes4(senderIdentityPublicKey, receiverIdentityPublicKey)) {
25623
+ if (event.transfer.transfer && !equalBytes5(senderIdentityPublicKey, receiverIdentityPublicKey)) {
25414
25624
  await this.claimTransfer({
25415
25625
  transfer: event.transfer.transfer,
25416
25626
  emit: true,
@@ -25572,10 +25782,10 @@ var SparkWallet = class _SparkWallet extends EventEmitter {
25572
25782
  leavesToIgnore.add(nodeId);
25573
25783
  continue;
25574
25784
  }
25575
- if (leaf.status !== operatorLeaf.status || !leaf.signingKeyshare || !operatorLeaf.signingKeyshare || !equalBytes4(
25785
+ if (leaf.status !== operatorLeaf.status || !leaf.signingKeyshare || !operatorLeaf.signingKeyshare || !equalBytes5(
25576
25786
  leaf.signingKeyshare.publicKey,
25577
25787
  operatorLeaf.signingKeyshare.publicKey
25578
- ) || !equalBytes4(leaf.nodeTx, operatorLeaf.nodeTx) || !equalBytes4(leaf.refundTx, operatorLeaf.refundTx)) {
25788
+ ) || !equalBytes5(leaf.nodeTx, operatorLeaf.nodeTx) || !equalBytes5(leaf.refundTx, operatorLeaf.refundTx)) {
25579
25789
  leavesToIgnore.add(nodeId);
25580
25790
  }
25581
25791
  }
@@ -25583,7 +25793,7 @@ var SparkWallet = class _SparkWallet extends EventEmitter {
25583
25793
  }
25584
25794
  }
25585
25795
  const verifyKey = (pubkey1, pubkey2, verifyingKey) => {
25586
- return equalBytes4(addPublicKeys(pubkey1, pubkey2), verifyingKey);
25796
+ return equalBytes5(addPublicKeys(pubkey1, pubkey2), verifyingKey);
25587
25797
  };
25588
25798
  for (const [id, leaf] of Object.entries(leaves.nodes)) {
25589
25799
  if (!verifyKey(
@@ -25978,7 +26188,7 @@ var SparkWallet = class _SparkWallet extends EventEmitter {
25978
26188
  adaptorPrivateKey
25979
26189
  );
25980
26190
  }
25981
- await this.transferService.sendTransferTweakKey(
26191
+ await this.transferService.deliverTransferPackage(
25982
26192
  transfer,
25983
26193
  leafKeyTweaks,
25984
26194
  signatureMap
@@ -26751,7 +26961,7 @@ var SparkWallet = class _SparkWallet extends EventEmitter {
26751
26961
  this.config.getNetworkType()
26752
26962
  );
26753
26963
  const signerIdentityPublicKey = await this.config.signer.getIdentityPublicKey();
26754
- const isSelfTransfer = equalBytes4(
26964
+ const isSelfTransfer = equalBytes5(
26755
26965
  signerIdentityPublicKey,
26756
26966
  hexToBytes13(receiverAddress)
26757
26967
  );
@@ -27663,6 +27873,112 @@ var SparkWallet = class _SparkWallet extends EventEmitter {
27663
27873
  }
27664
27874
  return this.config.signer.validateMessageWithIdentityKey(hash, signature);
27665
27875
  }
27876
+ /**
27877
+ * Signs a transaction with wallet keys.
27878
+ *
27879
+ * @param {string} txHex - The transaction hex to sign
27880
+ * @param {string} keyType - The type of key to use for signing ("identity", "deposit", or "auto-detect")
27881
+ * @returns {Promise<string>} The signed transaction hex
27882
+ */
27883
+ async signTransaction(txHex, keyType = "auto-detect") {
27884
+ try {
27885
+ const tx = Transaction9.fromRaw(hexToBytes13(txHex));
27886
+ let publicKey;
27887
+ switch (keyType.toLowerCase()) {
27888
+ case "identity":
27889
+ publicKey = await this.config.signer.getIdentityPublicKey();
27890
+ break;
27891
+ case "deposit":
27892
+ publicKey = await this.config.signer.getDepositSigningKey();
27893
+ break;
27894
+ case "auto-detect":
27895
+ default:
27896
+ const detectedKey = await this.detectKeyForTransaction(tx);
27897
+ if (detectedKey) {
27898
+ publicKey = detectedKey.publicKey;
27899
+ } else {
27900
+ publicKey = await this.config.signer.getIdentityPublicKey();
27901
+ }
27902
+ break;
27903
+ }
27904
+ let inputsSigned = 0;
27905
+ for (let i = 0; i < tx.inputsLength; i++) {
27906
+ const input = tx.getInput(i);
27907
+ if (!input?.witnessUtxo?.script) {
27908
+ continue;
27909
+ }
27910
+ const script = input.witnessUtxo.script;
27911
+ if (script.length === 1 && script[0] === 81) {
27912
+ continue;
27913
+ }
27914
+ const identityScript = getP2TRScriptFromPublicKey(
27915
+ publicKey,
27916
+ this.config.getNetwork()
27917
+ );
27918
+ if (bytesToHex12(script) === bytesToHex12(identityScript)) {
27919
+ try {
27920
+ this.config.signer.signTransactionIndex(tx, i, publicKey);
27921
+ inputsSigned++;
27922
+ } catch (error) {
27923
+ throw new ValidationError(`Failed to sign input ${i}: ${error}`, {
27924
+ field: "input",
27925
+ value: i
27926
+ });
27927
+ }
27928
+ }
27929
+ }
27930
+ if (inputsSigned === 0) {
27931
+ throw new Error(
27932
+ "No inputs were signed. Check that the transaction contains inputs controlled by this wallet."
27933
+ );
27934
+ }
27935
+ tx.finalize();
27936
+ const signedTxHex = tx.hex;
27937
+ return signedTxHex;
27938
+ } catch (error) {
27939
+ console.error("\u274C Error signing transaction:", error);
27940
+ throw error;
27941
+ }
27942
+ }
27943
+ /**
27944
+ * Helper method to auto-detect which key should be used for signing a transaction.
27945
+ */
27946
+ async detectKeyForTransaction(tx) {
27947
+ try {
27948
+ const identityPubKey = await this.config.signer.getIdentityPublicKey();
27949
+ const depositPubKey = await this.config.signer.getDepositSigningKey();
27950
+ for (let i = 0; i < tx.inputsLength; i++) {
27951
+ const input = tx.getInput(i);
27952
+ if (input?.witnessUtxo?.script) {
27953
+ const script = input.witnessUtxo.script;
27954
+ const identityScript = getP2TRScriptFromPublicKey(
27955
+ identityPubKey,
27956
+ this.config.getNetwork()
27957
+ );
27958
+ const depositScript = getP2TRScriptFromPublicKey(
27959
+ depositPubKey,
27960
+ this.config.getNetwork()
27961
+ );
27962
+ if (bytesToHex12(script) === bytesToHex12(identityScript)) {
27963
+ return {
27964
+ publicKey: identityPubKey,
27965
+ keyType: "identity"
27966
+ };
27967
+ }
27968
+ if (bytesToHex12(script) === bytesToHex12(depositScript)) {
27969
+ return {
27970
+ publicKey: depositPubKey,
27971
+ keyType: "deposit"
27972
+ };
27973
+ }
27974
+ }
27975
+ }
27976
+ return null;
27977
+ } catch (error) {
27978
+ console.warn("Error during key auto-detection:", error);
27979
+ return null;
27980
+ }
27981
+ }
27666
27982
  /**
27667
27983
  * Get a Lightning receive request by ID.
27668
27984
  *
@@ -27693,6 +28009,246 @@ var SparkWallet = class _SparkWallet extends EventEmitter {
27693
28009
  const sspClient = this.getSspClient();
27694
28010
  return await sspClient.getCoopExitRequest(id);
27695
28011
  }
28012
+ /**
28013
+ * Check the remaining timelock on a given node.
28014
+ *
28015
+ * @param {string} nodeId - The ID of the node to check
28016
+ * @returns {Promise<{nodeTimelock: number, refundTimelock: number}>} The remaining timelocks in blocks for both node and refund transactions
28017
+ */
28018
+ async checkTimelock(nodeId) {
28019
+ const sparkClient = await this.connectionManager.createSparkClient(
28020
+ this.config.getCoordinatorAddress()
28021
+ );
28022
+ try {
28023
+ const response = await sparkClient.query_nodes({
28024
+ source: {
28025
+ $case: "nodeIds",
28026
+ nodeIds: {
28027
+ nodeIds: [nodeId]
28028
+ }
28029
+ },
28030
+ includeParents: false,
28031
+ network: NetworkToProto[this.config.getNetwork()]
28032
+ });
28033
+ const node = response.nodes[nodeId];
28034
+ if (!node) {
28035
+ throw new ValidationError("Node not found", {
28036
+ field: "nodeId",
28037
+ value: nodeId
28038
+ });
28039
+ }
28040
+ const isRootNode = !node.parentNodeId;
28041
+ if (!node.nodeTx || node.nodeTx.length === 0) {
28042
+ throw new ValidationError(
28043
+ `Node transaction data is missing or empty for ${isRootNode ? "root" : "non-root"} node`,
28044
+ {
28045
+ field: "nodeTx",
28046
+ value: node.nodeTx?.length || 0
28047
+ }
28048
+ );
28049
+ }
28050
+ if (!node.refundTx || node.refundTx.length === 0) {
28051
+ throw new ValidationError(
28052
+ `Refund transaction data is missing or empty for ${isRootNode ? "root" : "non-root"} node`,
28053
+ {
28054
+ field: "refundTx",
28055
+ value: node.refundTx?.length || 0
28056
+ }
28057
+ );
28058
+ }
28059
+ let nodeTx, refundTx;
28060
+ try {
28061
+ nodeTx = getTxFromRawTxBytes(node.nodeTx);
28062
+ } catch (error) {
28063
+ throw new ValidationError(
28064
+ `Failed to parse node transaction for ${isRootNode ? "root" : "non-root"} node: ${error instanceof Error ? error.message : String(error)}`,
28065
+ {
28066
+ field: "nodeTx",
28067
+ value: node.nodeTx.length
28068
+ }
28069
+ );
28070
+ }
28071
+ try {
28072
+ refundTx = getTxFromRawTxBytes(node.refundTx);
28073
+ } catch (error) {
28074
+ throw new ValidationError(
28075
+ `Failed to parse refund transaction for ${isRootNode ? "root" : "non-root"} node: ${error instanceof Error ? error.message : String(error)}`,
28076
+ {
28077
+ field: "refundTx",
28078
+ value: node.refundTx.length
28079
+ }
28080
+ );
28081
+ }
28082
+ const nodeInput = nodeTx.getInput(0);
28083
+ if (!nodeInput) {
28084
+ throw new ValidationError(
28085
+ `Node transaction has no inputs for ${isRootNode ? "root" : "non-root"} node`,
28086
+ {
28087
+ field: "nodeInput",
28088
+ value: nodeTx.inputsLength
28089
+ }
28090
+ );
28091
+ }
28092
+ if (!nodeInput.sequence) {
28093
+ throw new ValidationError(
28094
+ `Node transaction has no sequence for ${isRootNode ? "root" : "non-root"} node`,
28095
+ {
28096
+ field: "sequence",
28097
+ value: nodeInput.sequence
28098
+ }
28099
+ );
28100
+ }
28101
+ const refundInput = refundTx.getInput(0);
28102
+ if (!refundInput) {
28103
+ throw new ValidationError(
28104
+ `Refund transaction has no inputs for ${isRootNode ? "root" : "non-root"} node`,
28105
+ {
28106
+ field: "refundInput",
28107
+ value: refundTx.inputsLength
28108
+ }
28109
+ );
28110
+ }
28111
+ if (!refundInput.sequence) {
28112
+ throw new ValidationError(
28113
+ `Refund transaction has no sequence for ${isRootNode ? "root" : "non-root"} node`,
28114
+ {
28115
+ field: "sequence",
28116
+ value: refundInput.sequence
28117
+ }
28118
+ );
28119
+ }
28120
+ const nodeTimelock = nodeInput.sequence & 65535;
28121
+ const refundTimelock = refundInput.sequence & 65535;
28122
+ return {
28123
+ nodeTimelock,
28124
+ refundTimelock
28125
+ };
28126
+ } catch (error) {
28127
+ throw new NetworkError(
28128
+ `Failed to check timelock for node ${nodeId}`,
28129
+ {
28130
+ method: "query_nodes"
28131
+ },
28132
+ error
28133
+ );
28134
+ }
28135
+ }
28136
+ /**
28137
+ * Refresh the timelock of a specific node.
28138
+ *
28139
+ * @param {string} nodeId - The ID of the node to refresh
28140
+ * @returns {Promise<void>} Promise that resolves when the timelock is refreshed
28141
+ */
28142
+ async testOnly_expireTimelock(nodeId) {
28143
+ const sparkClient = await this.connectionManager.createSparkClient(
28144
+ this.config.getCoordinatorAddress()
28145
+ );
28146
+ try {
28147
+ const response = await sparkClient.query_nodes({
28148
+ source: {
28149
+ $case: "nodeIds",
28150
+ nodeIds: {
28151
+ nodeIds: [nodeId]
28152
+ }
28153
+ },
28154
+ includeParents: true
28155
+ });
28156
+ const node = response.nodes[nodeId];
28157
+ if (!node) {
28158
+ throw new ValidationError("Node not found", {
28159
+ field: "nodeId",
28160
+ value: nodeId
28161
+ });
28162
+ }
28163
+ if (!node.parentNodeId) {
28164
+ throw new ValidationError("Node has no parent", {
28165
+ field: "parentNodeId",
28166
+ value: node.parentNodeId
28167
+ });
28168
+ }
28169
+ const parentNode = response.nodes[node.parentNodeId];
28170
+ if (!parentNode) {
28171
+ throw new ValidationError("Parent node not found", {
28172
+ field: "parentNodeId",
28173
+ value: node.parentNodeId
28174
+ });
28175
+ }
28176
+ const signingPubKey = await this.config.signer.generatePublicKey(
28177
+ sha25613(node.id)
28178
+ );
28179
+ const result = await this.transferService.refreshTimelockNodes(
28180
+ [node],
28181
+ parentNode,
28182
+ signingPubKey
28183
+ );
28184
+ const leafIndex = this.leaves.findIndex((leaf) => leaf.id === node.id);
28185
+ if (leafIndex !== -1 && result.nodes.length > 0) {
28186
+ const newNode = result.nodes[0];
28187
+ if (newNode) {
28188
+ this.leaves[leafIndex] = newNode;
28189
+ }
28190
+ }
28191
+ } catch (error) {
28192
+ throw new NetworkError(
28193
+ "Failed to refresh timelock",
28194
+ {
28195
+ method: "refresh_timelock"
28196
+ },
28197
+ error
28198
+ );
28199
+ }
28200
+ }
28201
+ /**
28202
+ * Refresh the timelock of a specific node's refund transaction only.
28203
+ *
28204
+ * @param {string} nodeId - The ID of the node whose refund transaction to refresh
28205
+ * @returns {Promise<void>} Promise that resolves when the refund timelock is refreshed
28206
+ */
28207
+ async testOnly_expireTimelockRefundTx(nodeId) {
28208
+ const sparkClient = await this.connectionManager.createSparkClient(
28209
+ this.config.getCoordinatorAddress()
28210
+ );
28211
+ try {
28212
+ const response = await sparkClient.query_nodes({
28213
+ source: {
28214
+ $case: "nodeIds",
28215
+ nodeIds: {
28216
+ nodeIds: [nodeId]
28217
+ }
28218
+ },
28219
+ includeParents: false
28220
+ });
28221
+ const node = response.nodes[nodeId];
28222
+ if (!node) {
28223
+ throw new ValidationError("Node not found", {
28224
+ field: "nodeId",
28225
+ value: nodeId
28226
+ });
28227
+ }
28228
+ const signingPubKey = await this.config.signer.generatePublicKey(
28229
+ sha25613(node.id)
28230
+ );
28231
+ const result = await this.transferService.refreshTimelockRefundTx(
28232
+ node,
28233
+ signingPubKey
28234
+ );
28235
+ const leafIndex = this.leaves.findIndex((leaf) => leaf.id === node.id);
28236
+ if (leafIndex !== -1 && result.nodes.length > 0) {
28237
+ const newNode = result.nodes[0];
28238
+ if (newNode) {
28239
+ this.leaves[leafIndex] = newNode;
28240
+ }
28241
+ }
28242
+ } catch (error) {
28243
+ throw new NetworkError(
28244
+ "Failed to refresh refund timelock",
28245
+ {
28246
+ method: "refresh_timelock_refund_tx"
28247
+ },
28248
+ error
28249
+ );
28250
+ }
28251
+ }
27696
28252
  cleanup() {
27697
28253
  if (this.claimTransfersInterval) {
27698
28254
  clearInterval(this.claimTransfersInterval);
@@ -27775,9 +28331,471 @@ async function getLatestDepositTxId(address2) {
27775
28331
  }
27776
28332
  return null;
27777
28333
  }
28334
+ async function isTxBroadcast(txid, baseUrl, network) {
28335
+ const headers = {};
28336
+ if (network === 3 /* REGTEST */) {
28337
+ const auth = btoa(
28338
+ `${ELECTRS_CREDENTIALS.username}:${ELECTRS_CREDENTIALS.password}`
28339
+ );
28340
+ headers["Authorization"] = `Basic ${auth}`;
28341
+ }
28342
+ const response = await fetch(`${baseUrl}/tx/${txid}`, {
28343
+ headers
28344
+ });
28345
+ const tx = await response.json();
28346
+ if (tx.error) {
28347
+ return false;
28348
+ }
28349
+ return true;
28350
+ }
28351
+
28352
+ // src/utils/unilateral-exit.ts
28353
+ import { bytesToHex as bytesToHex13, hexToBytes as hexToBytes14 } from "@noble/curves/abstract/utils";
28354
+ import { ripemd160 } from "@noble/hashes/legacy";
28355
+ import { sha256 as sha25614 } from "@noble/hashes/sha2";
28356
+ import * as btc5 from "@scure/btc-signer";
28357
+ function isEphemeralAnchorOutput(script, amount) {
28358
+ return Boolean(
28359
+ amount === 0n && script && // Pattern 1: Bare OP_TRUE (single byte 0x51)
28360
+ (script.length === 1 && script[0] === 81 || // Pattern 2: Push OP_TRUE (two bytes 0x01 0x51) - MALFORMED but we detect it
28361
+ script.length === 2 && script[0] === 1 && script[1] === 81 || // Pattern 3: Bitcoin v29 ephemeral anchor script (7 bytes: 015152014e0173)
28362
+ script.length === 7 && script[0] === 1 && script[1] === 81 && script[2] === 82 && script[3] === 1 && script[4] === 78 && script[5] === 1 && script[6] === 115 || // Pattern 4: Bitcoin ephemeral anchor OP_1 + push 2 bytes (4 bytes: 51024e73)
28363
+ script.length === 4 && script[0] === 81 && script[1] === 2 && script[2] === 78 && script[3] === 115)
28364
+ );
28365
+ }
28366
+ async function constructUnilateralExitTxs(nodeHexStrings, sparkClient, network) {
28367
+ const result = [];
28368
+ const nodes = nodeHexStrings.map((hex) => TreeNode.decode(hexToBytes14(hex)));
28369
+ const nodeMap = /* @__PURE__ */ new Map();
28370
+ for (const node of nodes) {
28371
+ nodeMap.set(node.id, node);
28372
+ }
28373
+ for (const node of nodes) {
28374
+ const transactions = [];
28375
+ const chain = [];
28376
+ let currentNode = node;
28377
+ while (currentNode) {
28378
+ chain.unshift(currentNode);
28379
+ if (currentNode.parentNodeId) {
28380
+ let parentNode = nodeMap.get(currentNode.parentNodeId);
28381
+ if (!parentNode && sparkClient) {
28382
+ try {
28383
+ const response = await sparkClient.query_nodes({
28384
+ source: {
28385
+ $case: "nodeIds",
28386
+ nodeIds: {
28387
+ nodeIds: [currentNode.parentNodeId]
28388
+ }
28389
+ },
28390
+ includeParents: true,
28391
+ network: network || 0
28392
+ // Default to mainnet if not provided
28393
+ });
28394
+ parentNode = response.nodes[currentNode.parentNodeId];
28395
+ if (parentNode) {
28396
+ nodeMap.set(currentNode.parentNodeId, parentNode);
28397
+ }
28398
+ } catch (error) {
28399
+ console.warn(
28400
+ `Failed to query parent node ${currentNode.parentNodeId}: ${error}`
28401
+ );
28402
+ break;
28403
+ }
28404
+ }
28405
+ if (parentNode) {
28406
+ currentNode = parentNode;
28407
+ } else {
28408
+ if (!sparkClient) {
28409
+ console.warn(
28410
+ `Parent node ${currentNode.parentNodeId} not found. Provide a sparkClient to fetch missing parents.`
28411
+ );
28412
+ } else {
28413
+ console.warn(
28414
+ `Parent node ${currentNode.parentNodeId} not found in database. Chain may be incomplete.`
28415
+ );
28416
+ }
28417
+ break;
28418
+ }
28419
+ } else {
28420
+ break;
28421
+ }
28422
+ }
28423
+ for (const chainNode of chain) {
28424
+ const nodeTx = bytesToHex13(chainNode.nodeTx);
28425
+ transactions.push(nodeTx);
28426
+ if (chainNode.id === node.id) {
28427
+ const refundTx = bytesToHex13(chainNode.refundTx);
28428
+ transactions.push(refundTx);
28429
+ }
28430
+ }
28431
+ result.push({
28432
+ leafId: node.id,
28433
+ transactions
28434
+ });
28435
+ }
28436
+ return result;
28437
+ }
28438
+ async function constructUnilateralExitFeeBumpPackages(nodeHexStrings, utxos, feeRate, electrsUrl, sparkClient, network) {
28439
+ const result = [];
28440
+ const availableUtxos = [...utxos].sort((a, b) => {
28441
+ if (a.value > b.value) return -1;
28442
+ if (a.value < b.value) return 1;
28443
+ return 0;
28444
+ });
28445
+ const nodes = [];
28446
+ for (let i = 0; i < nodeHexStrings.length; i++) {
28447
+ const hex = nodeHexStrings[i];
28448
+ try {
28449
+ if (!hex || hex.length === 0) {
28450
+ throw new Error(`Node hex string at index ${i} is empty`);
28451
+ }
28452
+ if (hex.startsWith("03000000") || hex.startsWith("02000000") || hex.startsWith("01000000")) {
28453
+ throw new Error(
28454
+ `Node hex string at index ${i} appears to be a raw transaction hex, not a TreeNode protobuf. Use 'leafidtohex' command to convert node IDs to proper hex strings.`
28455
+ );
28456
+ }
28457
+ const nodeBytes = hexToBytes14(hex);
28458
+ const node = TreeNode.decode(nodeBytes);
28459
+ if (!node.id) {
28460
+ throw new Error(
28461
+ `Decoded TreeNode at index ${i} is missing required 'id' field`
28462
+ );
28463
+ }
28464
+ if (!node.nodeTx || node.nodeTx.length === 0) {
28465
+ throw new Error(
28466
+ `Decoded TreeNode at index ${i} is missing required 'nodeTx' field`
28467
+ );
28468
+ }
28469
+ nodes.push(node);
28470
+ } catch (decodeError) {
28471
+ throw new Error(
28472
+ `Failed to decode TreeNode hex string at index ${i}: ${decodeError}. Make sure you're providing TreeNode protobuf hex strings, not raw transaction hex. Use 'leafidtohex' command to get proper hex strings.`
28473
+ );
28474
+ }
28475
+ }
28476
+ const nodeMap = /* @__PURE__ */ new Map();
28477
+ for (const node of nodes) {
28478
+ nodeMap.set(node.id, node);
28479
+ }
28480
+ const broadcastTxs = /* @__PURE__ */ new Map();
28481
+ for (const node of nodes) {
28482
+ const txPackages = [];
28483
+ let previousFeeBumpTx;
28484
+ const chain = [];
28485
+ let currentNode = node;
28486
+ while (currentNode) {
28487
+ chain.unshift(currentNode);
28488
+ if (currentNode.parentNodeId) {
28489
+ let parentNode = nodeMap.get(currentNode.parentNodeId);
28490
+ if (!parentNode && sparkClient) {
28491
+ try {
28492
+ const response = await sparkClient.query_nodes({
28493
+ source: {
28494
+ $case: "nodeIds",
28495
+ nodeIds: {
28496
+ nodeIds: [currentNode.parentNodeId]
28497
+ }
28498
+ },
28499
+ includeParents: true,
28500
+ network: network || 0
28501
+ // Default to mainnet if not provided
28502
+ });
28503
+ parentNode = response.nodes[currentNode.parentNodeId];
28504
+ if (parentNode) {
28505
+ nodeMap.set(currentNode.parentNodeId, parentNode);
28506
+ }
28507
+ } catch (error) {
28508
+ console.warn(
28509
+ `Failed to query parent node ${currentNode.parentNodeId}: ${error}`
28510
+ );
28511
+ break;
28512
+ }
28513
+ }
28514
+ if (parentNode) {
28515
+ currentNode = parentNode;
28516
+ } else {
28517
+ if (!sparkClient) {
28518
+ console.warn(
28519
+ `Parent node ${currentNode.parentNodeId} not found. Provide a sparkClient to fetch missing parents.`
28520
+ );
28521
+ } else {
28522
+ console.warn(
28523
+ `Parent node ${currentNode.parentNodeId} not found in database. Chain may be incomplete.`
28524
+ );
28525
+ }
28526
+ break;
28527
+ }
28528
+ } else {
28529
+ break;
28530
+ }
28531
+ }
28532
+ for (const chainNode of chain) {
28533
+ let nodeTxHex = bytesToHex13(chainNode.nodeTx);
28534
+ try {
28535
+ const txObj = getTxFromRawTxHex(nodeTxHex);
28536
+ const txid = getTxId(txObj);
28537
+ if (broadcastTxs.get(txid)) {
28538
+ continue;
28539
+ }
28540
+ broadcastTxs.set(txid, true);
28541
+ const isBroadcast = await isTxBroadcast(txid, electrsUrl, network);
28542
+ if (isBroadcast) {
28543
+ continue;
28544
+ } else {
28545
+ }
28546
+ let anchorOutputScriptHex;
28547
+ for (let i = txObj.outputsLength - 1; i >= 0; i--) {
28548
+ const output = txObj.getOutput(i);
28549
+ if (output?.amount === 0n && output.script) {
28550
+ anchorOutputScriptHex = bytesToHex13(output.script);
28551
+ break;
28552
+ }
28553
+ }
28554
+ } catch (parseError) {
28555
+ console.error(
28556
+ `\u274C Error parsing nodeTx for anchor check (node ${chainNode.id}): ${parseError}`
28557
+ );
28558
+ console.log(
28559
+ ` This may indicate a corrupted transaction in the TreeNode.`
28560
+ );
28561
+ console.log(` Transaction hex: ${nodeTxHex}`);
28562
+ console.log(
28563
+ ` Attempting to continue with original hex, but fee bump may fail.`
28564
+ );
28565
+ }
28566
+ const {
28567
+ feeBumpPsbt: nodeFeeBumpPsbt,
28568
+ usedUtxos,
28569
+ correctedParentTx
28570
+ } = constructFeeBumpTx(nodeTxHex, availableUtxos, feeRate, void 0);
28571
+ const feeBumpTx = btc5.Transaction.fromPSBT(hexToBytes14(nodeFeeBumpPsbt));
28572
+ var feeBumpOut = feeBumpTx.outputsLength === 1 ? feeBumpTx.getOutput(0) : null;
28573
+ var feeBumpOutPubKey = null;
28574
+ for (const usedUtxo of usedUtxos) {
28575
+ if (feeBumpOut && bytesToHex13(feeBumpOut.script) == usedUtxo.script) {
28576
+ feeBumpOutPubKey = usedUtxo.publicKey;
28577
+ }
28578
+ const index = availableUtxos.findIndex(
28579
+ (u) => u.txid === usedUtxo.txid && u.vout === usedUtxo.vout
28580
+ );
28581
+ if (index !== -1) {
28582
+ availableUtxos.splice(index, 1);
28583
+ }
28584
+ }
28585
+ if (feeBumpOut)
28586
+ availableUtxos.unshift({
28587
+ txid: getTxId(feeBumpTx),
28588
+ vout: 0,
28589
+ value: feeBumpOut.amount,
28590
+ script: bytesToHex13(feeBumpOut.script),
28591
+ publicKey: feeBumpOutPubKey
28592
+ });
28593
+ const finalNodeTx = correctedParentTx || nodeTxHex;
28594
+ txPackages.push({ tx: finalNodeTx, feeBumpPsbt: nodeFeeBumpPsbt });
28595
+ if (chainNode.id === node.id) {
28596
+ let refundTxHex = bytesToHex13(chainNode.refundTx);
28597
+ try {
28598
+ const txObj = getTxFromRawTxHex(refundTxHex);
28599
+ let anchorOutputScriptHex;
28600
+ for (let i = txObj.outputsLength - 1; i >= 0; i--) {
28601
+ const output = txObj.getOutput(i);
28602
+ if (output?.amount === 0n && output.script) {
28603
+ anchorOutputScriptHex = bytesToHex13(output.script);
28604
+ break;
28605
+ }
28606
+ }
28607
+ } catch (parseError) {
28608
+ console.error(
28609
+ `\u274C Error parsing refundTx for anchor check (node ${chainNode.id}): ${parseError}`
28610
+ );
28611
+ console.log(
28612
+ ` This may indicate a corrupted refund transaction in the TreeNode.`
28613
+ );
28614
+ console.log(` Refund transaction hex: ${refundTxHex}`);
28615
+ console.log(
28616
+ ` Attempting to continue with original refund hex, but this transaction may be invalid.`
28617
+ );
28618
+ }
28619
+ const refundFeeBump = constructFeeBumpTx(
28620
+ refundTxHex,
28621
+ availableUtxos,
28622
+ feeRate,
28623
+ void 0
28624
+ );
28625
+ txPackages.push({
28626
+ tx: refundTxHex,
28627
+ feeBumpPsbt: refundFeeBump.feeBumpPsbt
28628
+ });
28629
+ }
28630
+ }
28631
+ result.push({
28632
+ leafId: node.id,
28633
+ txPackages
28634
+ });
28635
+ }
28636
+ return result;
28637
+ }
28638
+ function hash160(data) {
28639
+ const sha256Hash = sha25614(data);
28640
+ return ripemd160(sha256Hash);
28641
+ }
28642
+ function constructFeeBumpTx(txHex, utxos, feeRate, previousFeeBumpTx) {
28643
+ if (!txHex || txHex.length === 0) {
28644
+ throw new Error("Transaction hex string is empty or undefined");
28645
+ }
28646
+ if (utxos.length === 0) {
28647
+ throw new Error("No UTXOs available for fee bump");
28648
+ }
28649
+ let correctedTxHex = txHex;
28650
+ let parentTx;
28651
+ try {
28652
+ parentTx = getTxFromRawTxHex(correctedTxHex);
28653
+ if (!parentTx) {
28654
+ throw new Error("getTxFromRawTxHex returned null/undefined");
28655
+ }
28656
+ } catch (parseError) {
28657
+ throw new Error(
28658
+ `Failed to parse parent transaction hex: ${parseError}. Transaction hex: ${correctedTxHex}`
28659
+ );
28660
+ }
28661
+ try {
28662
+ const outputsLength = parentTx.outputsLength;
28663
+ const inputsLength = parentTx.inputsLength;
28664
+ if (typeof outputsLength !== "number" || outputsLength < 0) {
28665
+ throw new Error(
28666
+ "Invalid transaction: outputsLength is not a valid number"
28667
+ );
28668
+ }
28669
+ if (typeof inputsLength !== "number" || inputsLength < 0) {
28670
+ throw new Error(
28671
+ "Invalid transaction: inputsLength is not a valid number"
28672
+ );
28673
+ }
28674
+ } catch (validationError) {
28675
+ throw new Error(
28676
+ `Transaction validation failed: ${validationError}. This may indicate a corrupted or malformed transaction.`
28677
+ );
28678
+ }
28679
+ const parentTxIdFromLib = parentTx.id;
28680
+ let ephemeralAnchorIndex = -1;
28681
+ for (let i = 0; i < parentTx.outputsLength; i++) {
28682
+ const output = parentTx.getOutput(i);
28683
+ const isEphemeralAnchor = isEphemeralAnchorOutput(
28684
+ output?.script,
28685
+ output?.amount
28686
+ );
28687
+ if (isEphemeralAnchor) {
28688
+ ephemeralAnchorIndex = i;
28689
+ break;
28690
+ }
28691
+ }
28692
+ if (ephemeralAnchorIndex === -1) {
28693
+ throw new Error(
28694
+ "No ephemeral anchor output found in parent transaction. Expected a 0-value output with OP_TRUE script (0x51), malformed OP_TRUE (0x0151), Bitcoin v29 ephemeral anchor script (015152014e0173), or Bitcoin OP_1 + push 2 bytes script (51024e73)."
28695
+ );
28696
+ }
28697
+ const ephemeralAnchorOutput = parentTx.getOutput(ephemeralAnchorIndex);
28698
+ if (!ephemeralAnchorOutput)
28699
+ throw new Error("No ephemeral anchor output found");
28700
+ if (!ephemeralAnchorOutput.script)
28701
+ throw new Error("No script found in ephemeral anchor output");
28702
+ if (utxos.length === 0) {
28703
+ throw new Error("No UTXOs available for fee bump");
28704
+ }
28705
+ const builder = new btc5.Transaction({
28706
+ version: 3,
28707
+ allowUnknown: true,
28708
+ allowLegacyWitnessUtxo: true
28709
+ });
28710
+ let totalValue = 0n;
28711
+ const processedUtxos = [];
28712
+ for (let i = 0; i < utxos.length; i++) {
28713
+ const fundingUtxo = utxos[i];
28714
+ if (!fundingUtxo) {
28715
+ throw new Error(`UTXO at index ${i} is undefined`);
28716
+ }
28717
+ const pubKeyHash = hash160(hexToBytes14(fundingUtxo.publicKey));
28718
+ const scriptToUse = new Uint8Array([0, 20, ...pubKeyHash]);
28719
+ const providedScript = hexToBytes14(fundingUtxo.script);
28720
+ if (bytesToHex13(scriptToUse) !== bytesToHex13(providedScript)) {
28721
+ throw new Error(
28722
+ `\u274C Derived script doesn't match provided script for UTXO ${i + 1}.`
28723
+ );
28724
+ }
28725
+ builder.addInput({
28726
+ txid: fundingUtxo.txid,
28727
+ index: fundingUtxo.vout,
28728
+ sequence: 4294967295,
28729
+ witnessUtxo: {
28730
+ script: scriptToUse,
28731
+ // Always P2WPKH
28732
+ amount: fundingUtxo.value
28733
+ }
28734
+ });
28735
+ totalValue += fundingUtxo.value;
28736
+ processedUtxos.push({
28737
+ utxo: fundingUtxo,
28738
+ p2wpkhScript: scriptToUse
28739
+ });
28740
+ }
28741
+ builder.addInput({
28742
+ txid: parentTxIdFromLib,
28743
+ index: ephemeralAnchorIndex,
28744
+ sequence: 4294967295,
28745
+ witnessUtxo: {
28746
+ script: ephemeralAnchorOutput.script,
28747
+ // Use the original script directly (not P2WSH wrapped)
28748
+ amount: 0n
28749
+ }
28750
+ });
28751
+ const fee = 1500n;
28752
+ const remainingValue = totalValue - fee;
28753
+ if (remainingValue <= 0n) {
28754
+ throw new Error(
28755
+ `Insufficient funds for fee bump. Required fee: ${fee} sats, Available: ${totalValue} sats`
28756
+ );
28757
+ }
28758
+ if (processedUtxos.length === 0) {
28759
+ throw new Error("No processed UTXOs available for change output");
28760
+ }
28761
+ const firstProcessedUtxo = processedUtxos[0];
28762
+ if (!firstProcessedUtxo) {
28763
+ throw new Error("First processed UTXO is undefined");
28764
+ }
28765
+ builder.addOutput({
28766
+ script: firstProcessedUtxo.p2wpkhScript,
28767
+ amount: remainingValue
28768
+ });
28769
+ for (let i = 0; i < processedUtxos.length; i++) {
28770
+ const processed = processedUtxos[i];
28771
+ if (!processed) {
28772
+ throw new Error(`Processed UTXO at index ${i} is undefined`);
28773
+ }
28774
+ try {
28775
+ builder.updateInput(i, {
28776
+ witnessScript: processed.p2wpkhScript
28777
+ });
28778
+ builder.signIdx;
28779
+ } catch (error) {
28780
+ throw new Error(`Failed to handle funding UTXO input ${i + 1}: ${error}`);
28781
+ }
28782
+ }
28783
+ let psbtHex;
28784
+ try {
28785
+ psbtHex = bytesToHex13(builder.toPSBT());
28786
+ } catch (error) {
28787
+ throw new Error(`Failed to extract transaction: ${error}`);
28788
+ }
28789
+ return {
28790
+ feeBumpPsbt: psbtHex,
28791
+ usedUtxos: utxos,
28792
+ correctedParentTx: correctedTxHex !== txHex ? correctedTxHex : void 0
28793
+ };
28794
+ }
27778
28795
  export {
27779
28796
  AuthenticationError,
27780
28797
  ConfigurationError,
28798
+ DEFAULT_FEE_SATS,
27781
28799
  ReactNativeSparkSigner as DefaultSparkSigner,
27782
28800
  InternalValidationError,
27783
28801
  LRC_WALLET_NETWORK,
@@ -27801,6 +28819,9 @@ export {
27801
28819
  collectResponses,
27802
28820
  computeTaprootKeyNoScript,
27803
28821
  computerLagrangeCoefficients,
28822
+ constructFeeBumpTx,
28823
+ constructUnilateralExitFeeBumpPackages,
28824
+ constructUnilateralExitTxs,
27804
28825
  createRefundTx,
27805
28826
  createSigningCommitment,
27806
28827
  createSigningNonce,
@@ -27819,6 +28840,7 @@ export {
27819
28840
  getLatestDepositTxId,
27820
28841
  getNetwork,
27821
28842
  getNetworkFromAddress,
28843
+ getNetworkFromString,
27822
28844
  getNextTransactionSequence,
27823
28845
  getP2TRAddressFromPkScript,
27824
28846
  getP2TRAddressFromPublicKey,
@@ -27834,7 +28856,10 @@ export {
27834
28856
  getTxFromRawTxHex,
27835
28857
  getTxId,
27836
28858
  getTxIdNoReverse,
28859
+ isEphemeralAnchorOutput,
28860
+ isTxBroadcast,
27837
28861
  lastKeyWithTarget,
28862
+ maybeApplyFee,
27838
28863
  modInverse,
27839
28864
  proofOfPossessionMessageHashForDepositAddress,
27840
28865
  recoverSecret,