@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
package/dist/index.cjs CHANGED
@@ -1289,6 +1289,7 @@ var index_exports = {};
1289
1289
  __export(index_exports, {
1290
1290
  AuthenticationError: () => AuthenticationError,
1291
1291
  ConfigurationError: () => ConfigurationError,
1292
+ DEFAULT_FEE_SATS: () => DEFAULT_FEE_SATS,
1292
1293
  InternalValidationError: () => InternalValidationError,
1293
1294
  LRC_WALLET_NETWORK: () => LRC_WALLET_NETWORK,
1294
1295
  LRC_WALLET_NETWORK_TYPE: () => LRC_WALLET_NETWORK_TYPE,
@@ -1310,6 +1311,9 @@ __export(index_exports, {
1310
1311
  collectResponses: () => collectResponses,
1311
1312
  computeTaprootKeyNoScript: () => computeTaprootKeyNoScript,
1312
1313
  computerLagrangeCoefficients: () => computerLagrangeCoefficients,
1314
+ constructFeeBumpTx: () => constructFeeBumpTx,
1315
+ constructUnilateralExitFeeBumpPackages: () => constructUnilateralExitFeeBumpPackages,
1316
+ constructUnilateralExitTxs: () => constructUnilateralExitTxs,
1313
1317
  createDummyTx: () => createDummyTx,
1314
1318
  createRefundTx: () => createRefundTx,
1315
1319
  createSigningCommitment: () => createSigningCommitment,
@@ -1329,6 +1333,7 @@ __export(index_exports, {
1329
1333
  getLatestDepositTxId: () => getLatestDepositTxId,
1330
1334
  getNetwork: () => getNetwork,
1331
1335
  getNetworkFromAddress: () => getNetworkFromAddress,
1336
+ getNetworkFromString: () => getNetworkFromString,
1332
1337
  getNextTransactionSequence: () => getNextTransactionSequence,
1333
1338
  getP2TRAddressFromPkScript: () => getP2TRAddressFromPkScript,
1334
1339
  getP2TRAddressFromPublicKey: () => getP2TRAddressFromPublicKey,
@@ -1344,7 +1349,10 @@ __export(index_exports, {
1344
1349
  getTxFromRawTxHex: () => getTxFromRawTxHex,
1345
1350
  getTxId: () => getTxId,
1346
1351
  getTxIdNoReverse: () => getTxIdNoReverse,
1352
+ isEphemeralAnchorOutput: () => isEphemeralAnchorOutput,
1353
+ isTxBroadcast: () => isTxBroadcast,
1347
1354
  lastKeyWithTarget: () => lastKeyWithTarget,
1355
+ maybeApplyFee: () => maybeApplyFee,
1348
1356
  modInverse: () => modInverse,
1349
1357
  proofOfPossessionMessageHashForDepositAddress: () => proofOfPossessionMessageHashForDepositAddress,
1350
1358
  recoverSecret: () => recoverSecret,
@@ -17017,11 +17025,9 @@ function decodeBytesToSigningCommitment(bytes2) {
17017
17025
  }
17018
17026
 
17019
17027
  // src/signer/signer.ts
17020
- var import_lrc20_sdk = require("@buildonspark/lrc20-sdk");
17021
- var import_lrc20_sdk2 = require("@buildonspark/lrc20-sdk");
17022
17028
  var import_secp256k16 = require("@bitcoinerlab/secp256k1");
17029
+ var import_lrc20_sdk = require("@buildonspark/lrc20-sdk");
17023
17030
  var import_sha22 = require("@noble/hashes/sha2");
17024
- var import_lrc20_sdk3 = require("@buildonspark/lrc20-sdk");
17025
17031
  var sparkFrostModule = void 0;
17026
17032
  var getSparkFrostModule = async () => {
17027
17033
  if (isReactNative) {
@@ -17487,16 +17493,16 @@ var DefaultSparkSigner = class {
17487
17493
  }
17488
17494
  if (receipt) {
17489
17495
  const receiptPrivateKey = this.getReceiptPrivateKey(receipt);
17490
- const tweakedKeyPair = (0, import_lrc20_sdk3.fromPrivateKey)(import_buffer.Buffer.from(receiptPrivateKey));
17496
+ const tweakedKeyPair = (0, import_lrc20_sdk.fromPrivateKey)(import_buffer.Buffer.from(receiptPrivateKey));
17491
17497
  psbt.signInput(input, tweakedKeyPair, sighashTypes);
17492
17498
  return psbt;
17493
17499
  }
17494
- const keypair = (0, import_lrc20_sdk3.fromPrivateKey)(import_buffer.Buffer.from(this.identityKey.privateKey));
17500
+ const keypair = (0, import_lrc20_sdk.fromPrivateKey)(import_buffer.Buffer.from(this.identityKey.privateKey));
17495
17501
  psbt.signInput(input, keypair, sighashTypes);
17496
17502
  return psbt;
17497
17503
  }
17498
17504
  getReceiptPrivateKey(receipt) {
17499
- const pxh = import_lrc20_sdk2.Receipt.receiptHash(receipt);
17505
+ const pxh = import_lrc20_sdk.Receipt.receiptHash(receipt);
17500
17506
  let innerKey = this.identityKey.publicKey;
17501
17507
  let privateKey = this.identityKey.privateKey;
17502
17508
  if (innerKey[0] === 3) {
@@ -17507,11 +17513,30 @@ var DefaultSparkSigner = class {
17507
17513
  const receiptProof = (0, import_secp256k16.privateAdd)(privateKey, pxhPubkey);
17508
17514
  return import_buffer.Buffer.from(receiptProof);
17509
17515
  }
17516
+ signTransactionIndex(tx, index, publicKey) {
17517
+ let privateKey;
17518
+ if ((0, import_utils4.equalBytes)(publicKey, this.identityKey?.publicKey ?? new Uint8Array())) {
17519
+ privateKey = this.identityKey?.privateKey;
17520
+ } else if ((0, import_utils4.equalBytes)(publicKey, this.depositKey?.publicKey ?? new Uint8Array())) {
17521
+ privateKey = this.depositKey?.privateKey;
17522
+ } else {
17523
+ privateKey = (0, import_utils4.hexToBytes)(
17524
+ this.publicKeyToPrivateKeyMap.get((0, import_utils4.bytesToHex)(publicKey)) ?? ""
17525
+ );
17526
+ }
17527
+ if (!privateKey) {
17528
+ throw new ValidationError("Private key not found for public key", {
17529
+ field: "privateKey",
17530
+ value: (0, import_utils4.bytesToHex)(publicKey)
17531
+ });
17532
+ }
17533
+ tx.signIdx(privateKey, index);
17534
+ }
17510
17535
  };
17511
17536
 
17512
17537
  // src/utils/network.ts
17513
17538
  init_buffer();
17514
- var import_lrc20_sdk4 = require("@buildonspark/lrc20-sdk");
17539
+ var import_lrc20_sdk2 = require("@buildonspark/lrc20-sdk");
17515
17540
  var btc = __toESM(require("@scure/btc-signer"), 1);
17516
17541
  var bitcoin = __toESM(require("bitcoinjs-lib"), 1);
17517
17542
  var Network2 = /* @__PURE__ */ ((Network5) => {
@@ -17545,11 +17570,11 @@ var LRC_WALLET_NETWORK = Object.freeze({
17545
17570
  [4 /* LOCAL */]: bitcoin.networks.regtest
17546
17571
  });
17547
17572
  var LRC_WALLET_NETWORK_TYPE = Object.freeze({
17548
- [0 /* MAINNET */]: import_lrc20_sdk4.NetworkType.MAINNET,
17549
- [1 /* TESTNET */]: import_lrc20_sdk4.NetworkType.TESTNET,
17550
- [2 /* SIGNET */]: import_lrc20_sdk4.NetworkType.TESTNET,
17551
- [3 /* REGTEST */]: import_lrc20_sdk4.NetworkType.REGTEST,
17552
- [4 /* LOCAL */]: import_lrc20_sdk4.NetworkType.LOCAL
17573
+ [0 /* MAINNET */]: import_lrc20_sdk2.NetworkType.MAINNET,
17574
+ [1 /* TESTNET */]: import_lrc20_sdk2.NetworkType.TESTNET,
17575
+ [2 /* SIGNET */]: import_lrc20_sdk2.NetworkType.TESTNET,
17576
+ [3 /* REGTEST */]: import_lrc20_sdk2.NetworkType.REGTEST,
17577
+ [4 /* LOCAL */]: import_lrc20_sdk2.NetworkType.LOCAL
17553
17578
  });
17554
17579
  function getNetworkFromAddress(address2) {
17555
17580
  try {
@@ -17572,6 +17597,14 @@ function getNetworkFromAddress(address2) {
17572
17597
  }
17573
17598
  return null;
17574
17599
  }
17600
+ function getNetworkFromString(network) {
17601
+ const net = (network ?? "REGTEST").toUpperCase();
17602
+ if (net === "MAINNET") return 0 /* MAINNET */;
17603
+ if (net === "TESTNET") return 1 /* TESTNET */;
17604
+ if (net === "SIGNET") return 2 /* SIGNET */;
17605
+ if (net === "LOCAL") return 4 /* LOCAL */;
17606
+ return 3 /* REGTEST */;
17607
+ }
17575
17608
 
17576
17609
  // src/services/wallet-config.ts
17577
17610
  init_buffer();
@@ -19129,8 +19162,20 @@ function getTxIdNoReverse(tx) {
19129
19162
  init_buffer();
19130
19163
  var import_btc_signer = require("@scure/btc-signer");
19131
19164
  var TIME_LOCK_INTERVAL = 100;
19165
+ var ESTIMATED_TX_SIZE = 191;
19166
+ var DEFAULT_SATS_PER_VBYTE = 5;
19167
+ var DEFAULT_FEE_SATS = ESTIMATED_TX_SIZE * DEFAULT_SATS_PER_VBYTE;
19168
+ function maybeApplyFee(amount) {
19169
+ if (amount > BigInt(DEFAULT_FEE_SATS)) {
19170
+ return amount - BigInt(DEFAULT_FEE_SATS);
19171
+ }
19172
+ return amount;
19173
+ }
19132
19174
  function createRefundTx(sequence, nodeOutPoint, amountSats, receivingPubkey, network) {
19133
- const newRefundTx = new import_btc_signer.Transaction({ allowUnknownOutputs: true });
19175
+ const newRefundTx = new import_btc_signer.Transaction({
19176
+ version: 3,
19177
+ allowUnknownOutputs: true
19178
+ });
19134
19179
  newRefundTx.addInput({
19135
19180
  ...nodeOutPoint,
19136
19181
  sequence
@@ -19159,7 +19204,7 @@ function getNextTransactionSequence(currSequence, forRefresh) {
19159
19204
  needRefresh: true
19160
19205
  };
19161
19206
  }
19162
- if (nextTimelock <= 0) {
19207
+ if (nextTimelock < 0) {
19163
19208
  throw new ValidationError("timelock interval is less than or equal to 0", {
19164
19209
  field: "nextTimelock",
19165
19210
  value: nextTimelock
@@ -19270,6 +19315,32 @@ var BaseTransferService = class {
19270
19315
  }
19271
19316
  return updatedTransfer;
19272
19317
  }
19318
+ async deliverTransferPackage(transfer, leaves, refundSignatureMap) {
19319
+ const keyTweakInputMap = await this.prepareSendTransferKeyTweaks(
19320
+ transfer.id,
19321
+ transfer.receiverIdentityPublicKey,
19322
+ leaves,
19323
+ refundSignatureMap
19324
+ );
19325
+ const transferPackage = await this.prepareTransferPackage(
19326
+ transfer.id,
19327
+ keyTweakInputMap,
19328
+ leaves,
19329
+ transfer.receiverIdentityPublicKey
19330
+ );
19331
+ const sparkClient = await this.connectionManager.createSparkClient(
19332
+ this.config.getCoordinatorAddress()
19333
+ );
19334
+ const response = await sparkClient.finalize_transfer_with_transfer_package({
19335
+ transferId: transfer.id,
19336
+ ownerIdentityPublicKey: await this.config.signer.getIdentityPublicKey(),
19337
+ transferPackage
19338
+ });
19339
+ if (!response.transfer) {
19340
+ throw new ValidationError("No transfer response from operator");
19341
+ }
19342
+ return response.transfer;
19343
+ }
19273
19344
  async sendTransferWithKeyTweaks(leaves, receiverIdentityPubkey) {
19274
19345
  const transferID = (0, import_uuidv7.uuidv7)();
19275
19346
  const keyTweakInputMap = await this.prepareSendTransferKeyTweaks(
@@ -20027,9 +20098,20 @@ var TransferService = class extends BaseTransferService {
20027
20098
  if (!input) {
20028
20099
  throw Error("Could not fetch tx input");
20029
20100
  }
20030
- const newTx = new import_btc_signer2.Transaction({ allowUnknownOutputs: true });
20031
- for (let j = 0; j < nodeTx.outputsLength; j++) {
20032
- newTx.addOutput(nodeTx.getOutput(j));
20101
+ const newTx = new import_btc_signer2.Transaction({ version: 3, allowUnknownOutputs: true });
20102
+ const originalOutput = nodeTx.getOutput(0);
20103
+ if (!originalOutput) {
20104
+ throw Error("Could not get original output");
20105
+ }
20106
+ newTx.addOutput({
20107
+ script: originalOutput.script,
20108
+ amount: originalOutput.amount
20109
+ });
20110
+ for (let j = 1; j < nodeTx.outputsLength; j++) {
20111
+ const additionalOutput = nodeTx.getOutput(j);
20112
+ if (additionalOutput) {
20113
+ newTx.addOutput(additionalOutput);
20114
+ }
20033
20115
  }
20034
20116
  if (i === 0) {
20035
20117
  const currSequence = input.sequence;
@@ -20056,9 +20138,23 @@ var TransferService = class extends BaseTransferService {
20056
20138
  throw Error("leaf does not have refund tx");
20057
20139
  }
20058
20140
  const refundTx = getTxFromRawTxBytes(leaf?.refundTx);
20059
- const newRefundTx = new import_btc_signer2.Transaction({ allowUnknownOutputs: true });
20060
- for (let j = 0; j < refundTx.outputsLength; j++) {
20061
- newRefundTx.addOutput(refundTx.getOutput(j));
20141
+ const newRefundTx = new import_btc_signer2.Transaction({
20142
+ version: 3,
20143
+ allowUnknownOutputs: true
20144
+ });
20145
+ const originalRefundOutput = refundTx.getOutput(0);
20146
+ if (!originalRefundOutput) {
20147
+ throw Error("Could not get original refund output");
20148
+ }
20149
+ newRefundTx.addOutput({
20150
+ script: originalRefundOutput.script,
20151
+ amount: originalRefundOutput.amount
20152
+ });
20153
+ for (let j = 1; j < refundTx.outputsLength; j++) {
20154
+ const additionalOutput = refundTx.getOutput(j);
20155
+ if (additionalOutput) {
20156
+ newRefundTx.addOutput(additionalOutput);
20157
+ }
20062
20158
  }
20063
20159
  const refundTxInput = refundTx.getInput(0);
20064
20160
  if (!refundTxInput) {
@@ -20167,10 +20263,11 @@ var TransferService = class extends BaseTransferService {
20167
20263
  nodeTxSignature: leafSignature,
20168
20264
  refundTxSignature: refundSignature
20169
20265
  });
20170
- return await sparkClient.finalize_node_signatures({
20266
+ const result = await sparkClient.finalize_node_signatures({
20171
20267
  intent: 3 /* REFRESH */,
20172
20268
  nodeSignatures
20173
20269
  });
20270
+ return result;
20174
20271
  }
20175
20272
  async extendTimelock(node, signingPubKey) {
20176
20273
  const nodeTx = getTxFromRawTxBytes(node.nodeTx);
@@ -20181,9 +20278,20 @@ var TransferService = class extends BaseTransferService {
20181
20278
  index: 0
20182
20279
  };
20183
20280
  const { nextSequence: newNodeSequence } = getNextTransactionSequence(refundSequence);
20184
- const newNodeTx = new import_btc_signer2.Transaction({ allowUnknownOutputs: true });
20281
+ const newNodeTx = new import_btc_signer2.Transaction({
20282
+ version: 3,
20283
+ allowUnknownOutputs: true
20284
+ });
20185
20285
  newNodeTx.addInput({ ...newNodeOutPoint, sequence: newNodeSequence });
20186
- newNodeTx.addOutput(nodeTx.getOutput(0));
20286
+ const originalOutput = nodeTx.getOutput(0);
20287
+ if (!originalOutput) {
20288
+ throw Error("Could not get original node output");
20289
+ }
20290
+ newNodeTx.addOutput({
20291
+ script: originalOutput.script,
20292
+ amount: originalOutput.amount
20293
+ // feeReducedAmount,
20294
+ });
20187
20295
  newNodeTx.addOutput(getEphemeralAnchorOutput());
20188
20296
  const newRefundOutPoint = {
20189
20297
  txid: (0, import_utils7.hexToBytes)(getTxId(newNodeTx)),
@@ -20197,11 +20305,16 @@ var TransferService = class extends BaseTransferService {
20197
20305
  initialSequence(),
20198
20306
  newRefundOutPoint,
20199
20307
  amountSats,
20308
+ // feeReducedRefundAmount,
20200
20309
  signingPubKey,
20201
20310
  this.config.getNetwork()
20202
20311
  );
20203
20312
  const nodeSighash = getSigHashFromTx(newNodeTx, 0, nodeTx.getOutput(0));
20204
- const refundSighash = getSigHashFromTx(newRefundTx, 0, nodeTx.getOutput(0));
20313
+ const refundSighash = getSigHashFromTx(
20314
+ newRefundTx,
20315
+ 0,
20316
+ newNodeTx.getOutput(0)
20317
+ );
20205
20318
  const newNodeSigningJob = {
20206
20319
  signingPublicKey: signingPubKey,
20207
20320
  rawTx: newNodeTx.toBytes(),
@@ -20275,6 +20388,94 @@ var TransferService = class extends BaseTransferService {
20275
20388
  ]
20276
20389
  });
20277
20390
  }
20391
+ async refreshTimelockRefundTx(node, signingPubKey) {
20392
+ const nodeTx = getTxFromRawTxBytes(node.nodeTx);
20393
+ const refundTx = getTxFromRawTxBytes(node.refundTx);
20394
+ const currSequence = refundTx.getInput(0).sequence || 0;
20395
+ const { nextSequence } = getNextTransactionSequence(currSequence);
20396
+ const newRefundTx = new import_btc_signer2.Transaction({
20397
+ version: 3,
20398
+ allowUnknownOutputs: true
20399
+ });
20400
+ const originalRefundOutput = refundTx.getOutput(0);
20401
+ if (!originalRefundOutput) {
20402
+ throw Error("Could not get original refund output");
20403
+ }
20404
+ newRefundTx.addOutput({
20405
+ script: originalRefundOutput.script,
20406
+ amount: originalRefundOutput.amount
20407
+ });
20408
+ for (let j = 1; j < refundTx.outputsLength; j++) {
20409
+ const additionalOutput = refundTx.getOutput(j);
20410
+ if (additionalOutput) {
20411
+ newRefundTx.addOutput(additionalOutput);
20412
+ }
20413
+ }
20414
+ const refundTxInput = refundTx.getInput(0);
20415
+ if (!refundTxInput) {
20416
+ throw Error("refund tx doesn't have input");
20417
+ }
20418
+ newRefundTx.addInput({
20419
+ ...refundTxInput,
20420
+ sequence: nextSequence
20421
+ });
20422
+ const refundSigningJob = {
20423
+ signingPublicKey: signingPubKey,
20424
+ rawTx: newRefundTx.toBytes(),
20425
+ signingNonceCommitment: await this.config.signer.getRandomSigningCommitment()
20426
+ };
20427
+ const sparkClient = await this.connectionManager.createSparkClient(
20428
+ this.config.getCoordinatorAddress()
20429
+ );
20430
+ const response = await sparkClient.refresh_timelock({
20431
+ leafId: node.id,
20432
+ ownerIdentityPublicKey: await this.config.signer.getIdentityPublicKey(),
20433
+ signingJobs: [refundSigningJob]
20434
+ });
20435
+ if (response.signingResults.length !== 1) {
20436
+ throw Error(
20437
+ `Expected 1 signing result, got ${response.signingResults.length}`
20438
+ );
20439
+ }
20440
+ const signingResult = response.signingResults[0];
20441
+ if (!signingResult || !refundSigningJob.signingNonceCommitment) {
20442
+ throw Error("Signing result or nonce commitment does not exist");
20443
+ }
20444
+ const rawTx = getTxFromRawTxBytes(refundSigningJob.rawTx);
20445
+ const txOut = nodeTx.getOutput(0);
20446
+ const rawTxSighash = getSigHashFromTx(rawTx, 0, txOut);
20447
+ const userSignature = await this.config.signer.signFrost({
20448
+ message: rawTxSighash,
20449
+ privateAsPubKey: signingPubKey,
20450
+ publicKey: signingPubKey,
20451
+ verifyingKey: signingResult.verifyingKey,
20452
+ selfCommitment: refundSigningJob.signingNonceCommitment,
20453
+ statechainCommitments: signingResult.signingResult?.signingNonceCommitments,
20454
+ adaptorPubKey: new Uint8Array()
20455
+ });
20456
+ const signature = await this.config.signer.aggregateFrost({
20457
+ message: rawTxSighash,
20458
+ statechainSignatures: signingResult.signingResult?.signatureShares,
20459
+ statechainPublicKeys: signingResult.signingResult?.publicKeys,
20460
+ verifyingKey: signingResult.verifyingKey,
20461
+ statechainCommitments: signingResult.signingResult?.signingNonceCommitments,
20462
+ selfCommitment: refundSigningJob.signingNonceCommitment,
20463
+ publicKey: signingPubKey,
20464
+ selfSignature: userSignature,
20465
+ adaptorPubKey: new Uint8Array()
20466
+ });
20467
+ const result = await sparkClient.finalize_node_signatures({
20468
+ intent: 3 /* REFRESH */,
20469
+ nodeSignatures: [
20470
+ {
20471
+ nodeId: node.id,
20472
+ nodeTxSignature: new Uint8Array(),
20473
+ refundTxSignature: signature
20474
+ }
20475
+ ]
20476
+ });
20477
+ return result;
20478
+ }
20278
20479
  };
20279
20480
 
20280
20481
  // src/services/coop-exit.ts
@@ -20578,7 +20779,7 @@ var DepositService = class {
20578
20779
  depositTx,
20579
20780
  vout
20580
20781
  }) {
20581
- const rootTx = new import_btc_signer4.Transaction();
20782
+ const rootTx = new import_btc_signer4.Transaction({ version: 3 });
20582
20783
  const output = depositTx.getOutput(vout);
20583
20784
  if (!output) {
20584
20785
  throw new ValidationError("Invalid deposit transaction output", {
@@ -20596,17 +20797,19 @@ var DepositService = class {
20596
20797
  expected: "Output with script and amount"
20597
20798
  });
20598
20799
  }
20800
+ let outputAmount = amount;
20599
20801
  rootTx.addInput({
20600
20802
  txid: getTxId(depositTx),
20601
20803
  index: vout
20602
20804
  });
20603
20805
  rootTx.addOutput({
20604
20806
  script,
20605
- amount
20807
+ amount: outputAmount
20606
20808
  });
20809
+ rootTx.addOutput(getEphemeralAnchorOutput());
20607
20810
  const rootNonceCommitment = await this.config.signer.getRandomSigningCommitment();
20608
20811
  const rootTxSighash = getSigHashFromTx(rootTx, 0, output);
20609
- const refundTx = new import_btc_signer4.Transaction();
20812
+ const refundTx = new import_btc_signer4.Transaction({ version: 3 });
20610
20813
  const sequence = 1 << 30 | INITIAL_TIME_LOCK2;
20611
20814
  refundTx.addInput({
20612
20815
  txid: getTxId(rootTx),
@@ -20621,10 +20824,11 @@ var DepositService = class {
20621
20824
  const refundPkScript = btc3.OutScript.encode(refundAddress);
20622
20825
  refundTx.addOutput({
20623
20826
  script: refundPkScript,
20624
- amount
20827
+ amount: outputAmount
20625
20828
  });
20829
+ refundTx.addOutput(getEphemeralAnchorOutput());
20626
20830
  const refundNonceCommitment = await this.config.signer.getRandomSigningCommitment();
20627
- const refundTxSighash = getSigHashFromTx(refundTx, 0, output);
20831
+ const refundTxSighash = getSigHashFromTx(refundTx, 0, rootTx.getOutput(0));
20628
20832
  const sparkClient = await this.connectionManager.createSparkClient(
20629
20833
  this.config.getCoordinatorAddress()
20630
20834
  );
@@ -25132,7 +25336,7 @@ function isValidPublicKey(publicKey) {
25132
25336
  }
25133
25337
 
25134
25338
  // src/services/token-transactions.ts
25135
- var MAX_TOKEN_OUTPUTS = 1e3;
25339
+ var MAX_TOKEN_OUTPUTS = 500;
25136
25340
  var TokenTransactionService = class {
25137
25341
  config;
25138
25342
  connectionManager;
@@ -25697,6 +25901,12 @@ var import_utils15 = require("@noble/curves/abstract/utils");
25697
25901
  var import_sha212 = require("@noble/hashes/sha2");
25698
25902
  var import_btc_signer5 = require("@scure/btc-signer");
25699
25903
  var INITIAL_TIME_LOCK3 = 2e3;
25904
+ function maybeApplyFee3(amount) {
25905
+ if (amount > BigInt(DEFAULT_FEE_SATS)) {
25906
+ return amount - BigInt(DEFAULT_FEE_SATS);
25907
+ }
25908
+ return amount;
25909
+ }
25700
25910
  var TreeCreationService = class {
25701
25911
  config;
25702
25912
  connectionManager;
@@ -25895,7 +26105,7 @@ var TreeCreationService = class {
25895
26105
  refundTxSigningJob: void 0,
25896
26106
  children: []
25897
26107
  };
25898
- const tx = new import_btc_signer5.Transaction();
26108
+ const tx = new import_btc_signer5.Transaction({ version: 3 });
25899
26109
  tx.addInput({
25900
26110
  txid: getTxId(parentTx),
25901
26111
  index: vout
@@ -25907,6 +26117,7 @@ var TreeCreationService = class {
25907
26117
  tx.addOutput({
25908
26118
  script: parentTxOut.script,
25909
26119
  amount: parentTxOut.amount
26120
+ // maybeApplyFee(parentTxOut.amount),
25910
26121
  });
25911
26122
  tx.addOutput(getEphemeralAnchorOutput());
25912
26123
  const signingNonceCommitment = await this.config.signer.getRandomSigningCommitment();
@@ -25923,7 +26134,7 @@ var TreeCreationService = class {
25923
26134
  refundTxSigningJob: void 0,
25924
26135
  children: []
25925
26136
  };
25926
- const childTx = new import_btc_signer5.Transaction();
26137
+ const childTx = new import_btc_signer5.Transaction({ version: 3 });
25927
26138
  childTx.addInput({
25928
26139
  txid: getTxId(tx),
25929
26140
  index: 0,
@@ -25932,6 +26143,7 @@ var TreeCreationService = class {
25932
26143
  childTx.addOutput({
25933
26144
  script: parentTxOut.script,
25934
26145
  amount: parentTxOut.amount
26146
+ // maybeApplyFee(parentTxOut.amount),
25935
26147
  });
25936
26148
  childTx.addOutput(getEphemeralAnchorOutput());
25937
26149
  const childSigningNonceCommitment = await this.config.signer.getRandomSigningCommitment();
@@ -25942,7 +26154,7 @@ var TreeCreationService = class {
25942
26154
  };
25943
26155
  childCreationNode.nodeTxSigningCommitment = childSigningNonceCommitment;
25944
26156
  childCreationNode.nodeTxSigningJob = childSigningJob;
25945
- const refundTx = new import_btc_signer5.Transaction();
26157
+ const refundTx = new import_btc_signer5.Transaction({ version: 3 });
25946
26158
  refundTx.addInput({
25947
26159
  txid: getTxId(childTx),
25948
26160
  index: 0,
@@ -25958,8 +26170,9 @@ var TreeCreationService = class {
25958
26170
  const refundPkScript = import_btc_signer5.OutScript.encode(refundAddress);
25959
26171
  refundTx.addOutput({
25960
26172
  script: refundPkScript,
25961
- amount: parentTxOut.amount
26173
+ amount: maybeApplyFee3(parentTxOut.amount)
25962
26174
  });
26175
+ refundTx.addOutput(getEphemeralAnchorOutput());
25963
26176
  const refundSigningNonceCommitment = await this.config.signer.getRandomSigningCommitment();
25964
26177
  const refundSigningJob = {
25965
26178
  signingPublicKey: node.signingPublicKey,
@@ -25976,7 +26189,7 @@ var TreeCreationService = class {
25976
26189
  if (!parentTxOutput?.script || !parentTxOutput?.amount) {
25977
26190
  throw new Error("parentTxOutput is undefined");
25978
26191
  }
25979
- const rootNodeTx = new import_btc_signer5.Transaction();
26192
+ const rootNodeTx = new import_btc_signer5.Transaction({ version: 3 });
25980
26193
  rootNodeTx.addInput({
25981
26194
  txid: getTxId(parentTx),
25982
26195
  index: vout
@@ -25991,10 +26204,10 @@ var TreeCreationService = class {
25991
26204
  rootNodeTx.addOutput({
25992
26205
  script: childPkScript,
25993
26206
  amount: parentTxOutput.amount / 2n
26207
+ // feeAdjustedAmount / 2n,
25994
26208
  });
25995
26209
  }
25996
- const anchor = getEphemeralAnchorOutput();
25997
- rootNodeTx.addOutput(anchor);
26210
+ rootNodeTx.addOutput(getEphemeralAnchorOutput());
25998
26211
  const rootNodeSigningCommitment = await this.config.signer.getRandomSigningCommitment();
25999
26212
  const rootNodeSigningJob = {
26000
26213
  signingPublicKey: root.signingPublicKey,
@@ -26145,7 +26358,7 @@ var TreeCreationService = class {
26145
26358
  };
26146
26359
 
26147
26360
  // src/spark-wallet/spark-wallet.ts
26148
- var import_lrc20_sdk5 = require("@buildonspark/lrc20-sdk");
26361
+ var import_lrc20_sdk3 = require("@buildonspark/lrc20-sdk");
26149
26362
  var import_sha213 = require("@noble/hashes/sha2");
26150
26363
  var import_eventemitter3 = require("eventemitter3");
26151
26364
 
@@ -27054,7 +27267,7 @@ var SparkWallet = class _SparkWallet extends import_eventemitter3.EventEmitter {
27054
27267
  }
27055
27268
  await this.initWalletFromSeed(seed, accountNumber);
27056
27269
  const network = this.config.getNetwork();
27057
- this.lrc20Wallet = await import_lrc20_sdk5.LRCWallet.create(
27270
+ this.lrc20Wallet = await import_lrc20_sdk3.LRCWallet.create(
27058
27271
  LRC_WALLET_NETWORK[network],
27059
27272
  LRC_WALLET_NETWORK_TYPE[network],
27060
27273
  this.config.lrc20ApiConfig,
@@ -27253,7 +27466,7 @@ var SparkWallet = class _SparkWallet extends import_eventemitter3.EventEmitter {
27253
27466
  adaptorPrivateKey
27254
27467
  );
27255
27468
  }
27256
- await this.transferService.sendTransferTweakKey(
27469
+ await this.transferService.deliverTransferPackage(
27257
27470
  transfer,
27258
27471
  leafKeyTweaks,
27259
27472
  signatureMap
@@ -28938,6 +29151,112 @@ var SparkWallet = class _SparkWallet extends import_eventemitter3.EventEmitter {
28938
29151
  }
28939
29152
  return this.config.signer.validateMessageWithIdentityKey(hash, signature);
28940
29153
  }
29154
+ /**
29155
+ * Signs a transaction with wallet keys.
29156
+ *
29157
+ * @param {string} txHex - The transaction hex to sign
29158
+ * @param {string} keyType - The type of key to use for signing ("identity", "deposit", or "auto-detect")
29159
+ * @returns {Promise<string>} The signed transaction hex
29160
+ */
29161
+ async signTransaction(txHex, keyType = "auto-detect") {
29162
+ try {
29163
+ const tx = import_btc_signer7.Transaction.fromRaw((0, import_utils20.hexToBytes)(txHex));
29164
+ let publicKey;
29165
+ switch (keyType.toLowerCase()) {
29166
+ case "identity":
29167
+ publicKey = await this.config.signer.getIdentityPublicKey();
29168
+ break;
29169
+ case "deposit":
29170
+ publicKey = await this.config.signer.getDepositSigningKey();
29171
+ break;
29172
+ case "auto-detect":
29173
+ default:
29174
+ const detectedKey = await this.detectKeyForTransaction(tx);
29175
+ if (detectedKey) {
29176
+ publicKey = detectedKey.publicKey;
29177
+ } else {
29178
+ publicKey = await this.config.signer.getIdentityPublicKey();
29179
+ }
29180
+ break;
29181
+ }
29182
+ let inputsSigned = 0;
29183
+ for (let i = 0; i < tx.inputsLength; i++) {
29184
+ const input = tx.getInput(i);
29185
+ if (!input?.witnessUtxo?.script) {
29186
+ continue;
29187
+ }
29188
+ const script = input.witnessUtxo.script;
29189
+ if (script.length === 1 && script[0] === 81) {
29190
+ continue;
29191
+ }
29192
+ const identityScript = getP2TRScriptFromPublicKey(
29193
+ publicKey,
29194
+ this.config.getNetwork()
29195
+ );
29196
+ if ((0, import_utils20.bytesToHex)(script) === (0, import_utils20.bytesToHex)(identityScript)) {
29197
+ try {
29198
+ this.config.signer.signTransactionIndex(tx, i, publicKey);
29199
+ inputsSigned++;
29200
+ } catch (error) {
29201
+ throw new ValidationError(`Failed to sign input ${i}: ${error}`, {
29202
+ field: "input",
29203
+ value: i
29204
+ });
29205
+ }
29206
+ }
29207
+ }
29208
+ if (inputsSigned === 0) {
29209
+ throw new Error(
29210
+ "No inputs were signed. Check that the transaction contains inputs controlled by this wallet."
29211
+ );
29212
+ }
29213
+ tx.finalize();
29214
+ const signedTxHex = tx.hex;
29215
+ return signedTxHex;
29216
+ } catch (error) {
29217
+ console.error("\u274C Error signing transaction:", error);
29218
+ throw error;
29219
+ }
29220
+ }
29221
+ /**
29222
+ * Helper method to auto-detect which key should be used for signing a transaction.
29223
+ */
29224
+ async detectKeyForTransaction(tx) {
29225
+ try {
29226
+ const identityPubKey = await this.config.signer.getIdentityPublicKey();
29227
+ const depositPubKey = await this.config.signer.getDepositSigningKey();
29228
+ for (let i = 0; i < tx.inputsLength; i++) {
29229
+ const input = tx.getInput(i);
29230
+ if (input?.witnessUtxo?.script) {
29231
+ const script = input.witnessUtxo.script;
29232
+ const identityScript = getP2TRScriptFromPublicKey(
29233
+ identityPubKey,
29234
+ this.config.getNetwork()
29235
+ );
29236
+ const depositScript = getP2TRScriptFromPublicKey(
29237
+ depositPubKey,
29238
+ this.config.getNetwork()
29239
+ );
29240
+ if ((0, import_utils20.bytesToHex)(script) === (0, import_utils20.bytesToHex)(identityScript)) {
29241
+ return {
29242
+ publicKey: identityPubKey,
29243
+ keyType: "identity"
29244
+ };
29245
+ }
29246
+ if ((0, import_utils20.bytesToHex)(script) === (0, import_utils20.bytesToHex)(depositScript)) {
29247
+ return {
29248
+ publicKey: depositPubKey,
29249
+ keyType: "deposit"
29250
+ };
29251
+ }
29252
+ }
29253
+ }
29254
+ return null;
29255
+ } catch (error) {
29256
+ console.warn("Error during key auto-detection:", error);
29257
+ return null;
29258
+ }
29259
+ }
28941
29260
  /**
28942
29261
  * Get a Lightning receive request by ID.
28943
29262
  *
@@ -28968,6 +29287,246 @@ var SparkWallet = class _SparkWallet extends import_eventemitter3.EventEmitter {
28968
29287
  const sspClient = this.getSspClient();
28969
29288
  return await sspClient.getCoopExitRequest(id);
28970
29289
  }
29290
+ /**
29291
+ * Check the remaining timelock on a given node.
29292
+ *
29293
+ * @param {string} nodeId - The ID of the node to check
29294
+ * @returns {Promise<{nodeTimelock: number, refundTimelock: number}>} The remaining timelocks in blocks for both node and refund transactions
29295
+ */
29296
+ async checkTimelock(nodeId) {
29297
+ const sparkClient = await this.connectionManager.createSparkClient(
29298
+ this.config.getCoordinatorAddress()
29299
+ );
29300
+ try {
29301
+ const response = await sparkClient.query_nodes({
29302
+ source: {
29303
+ $case: "nodeIds",
29304
+ nodeIds: {
29305
+ nodeIds: [nodeId]
29306
+ }
29307
+ },
29308
+ includeParents: false,
29309
+ network: NetworkToProto[this.config.getNetwork()]
29310
+ });
29311
+ const node = response.nodes[nodeId];
29312
+ if (!node) {
29313
+ throw new ValidationError("Node not found", {
29314
+ field: "nodeId",
29315
+ value: nodeId
29316
+ });
29317
+ }
29318
+ const isRootNode = !node.parentNodeId;
29319
+ if (!node.nodeTx || node.nodeTx.length === 0) {
29320
+ throw new ValidationError(
29321
+ `Node transaction data is missing or empty for ${isRootNode ? "root" : "non-root"} node`,
29322
+ {
29323
+ field: "nodeTx",
29324
+ value: node.nodeTx?.length || 0
29325
+ }
29326
+ );
29327
+ }
29328
+ if (!node.refundTx || node.refundTx.length === 0) {
29329
+ throw new ValidationError(
29330
+ `Refund transaction data is missing or empty for ${isRootNode ? "root" : "non-root"} node`,
29331
+ {
29332
+ field: "refundTx",
29333
+ value: node.refundTx?.length || 0
29334
+ }
29335
+ );
29336
+ }
29337
+ let nodeTx, refundTx;
29338
+ try {
29339
+ nodeTx = getTxFromRawTxBytes(node.nodeTx);
29340
+ } catch (error) {
29341
+ throw new ValidationError(
29342
+ `Failed to parse node transaction for ${isRootNode ? "root" : "non-root"} node: ${error instanceof Error ? error.message : String(error)}`,
29343
+ {
29344
+ field: "nodeTx",
29345
+ value: node.nodeTx.length
29346
+ }
29347
+ );
29348
+ }
29349
+ try {
29350
+ refundTx = getTxFromRawTxBytes(node.refundTx);
29351
+ } catch (error) {
29352
+ throw new ValidationError(
29353
+ `Failed to parse refund transaction for ${isRootNode ? "root" : "non-root"} node: ${error instanceof Error ? error.message : String(error)}`,
29354
+ {
29355
+ field: "refundTx",
29356
+ value: node.refundTx.length
29357
+ }
29358
+ );
29359
+ }
29360
+ const nodeInput = nodeTx.getInput(0);
29361
+ if (!nodeInput) {
29362
+ throw new ValidationError(
29363
+ `Node transaction has no inputs for ${isRootNode ? "root" : "non-root"} node`,
29364
+ {
29365
+ field: "nodeInput",
29366
+ value: nodeTx.inputsLength
29367
+ }
29368
+ );
29369
+ }
29370
+ if (!nodeInput.sequence) {
29371
+ throw new ValidationError(
29372
+ `Node transaction has no sequence for ${isRootNode ? "root" : "non-root"} node`,
29373
+ {
29374
+ field: "sequence",
29375
+ value: nodeInput.sequence
29376
+ }
29377
+ );
29378
+ }
29379
+ const refundInput = refundTx.getInput(0);
29380
+ if (!refundInput) {
29381
+ throw new ValidationError(
29382
+ `Refund transaction has no inputs for ${isRootNode ? "root" : "non-root"} node`,
29383
+ {
29384
+ field: "refundInput",
29385
+ value: refundTx.inputsLength
29386
+ }
29387
+ );
29388
+ }
29389
+ if (!refundInput.sequence) {
29390
+ throw new ValidationError(
29391
+ `Refund transaction has no sequence for ${isRootNode ? "root" : "non-root"} node`,
29392
+ {
29393
+ field: "sequence",
29394
+ value: refundInput.sequence
29395
+ }
29396
+ );
29397
+ }
29398
+ const nodeTimelock = nodeInput.sequence & 65535;
29399
+ const refundTimelock = refundInput.sequence & 65535;
29400
+ return {
29401
+ nodeTimelock,
29402
+ refundTimelock
29403
+ };
29404
+ } catch (error) {
29405
+ throw new NetworkError(
29406
+ `Failed to check timelock for node ${nodeId}`,
29407
+ {
29408
+ method: "query_nodes"
29409
+ },
29410
+ error
29411
+ );
29412
+ }
29413
+ }
29414
+ /**
29415
+ * Refresh the timelock of a specific node.
29416
+ *
29417
+ * @param {string} nodeId - The ID of the node to refresh
29418
+ * @returns {Promise<void>} Promise that resolves when the timelock is refreshed
29419
+ */
29420
+ async testOnly_expireTimelock(nodeId) {
29421
+ const sparkClient = await this.connectionManager.createSparkClient(
29422
+ this.config.getCoordinatorAddress()
29423
+ );
29424
+ try {
29425
+ const response = await sparkClient.query_nodes({
29426
+ source: {
29427
+ $case: "nodeIds",
29428
+ nodeIds: {
29429
+ nodeIds: [nodeId]
29430
+ }
29431
+ },
29432
+ includeParents: true
29433
+ });
29434
+ const node = response.nodes[nodeId];
29435
+ if (!node) {
29436
+ throw new ValidationError("Node not found", {
29437
+ field: "nodeId",
29438
+ value: nodeId
29439
+ });
29440
+ }
29441
+ if (!node.parentNodeId) {
29442
+ throw new ValidationError("Node has no parent", {
29443
+ field: "parentNodeId",
29444
+ value: node.parentNodeId
29445
+ });
29446
+ }
29447
+ const parentNode = response.nodes[node.parentNodeId];
29448
+ if (!parentNode) {
29449
+ throw new ValidationError("Parent node not found", {
29450
+ field: "parentNodeId",
29451
+ value: node.parentNodeId
29452
+ });
29453
+ }
29454
+ const signingPubKey = await this.config.signer.generatePublicKey(
29455
+ (0, import_sha213.sha256)(node.id)
29456
+ );
29457
+ const result = await this.transferService.refreshTimelockNodes(
29458
+ [node],
29459
+ parentNode,
29460
+ signingPubKey
29461
+ );
29462
+ const leafIndex = this.leaves.findIndex((leaf) => leaf.id === node.id);
29463
+ if (leafIndex !== -1 && result.nodes.length > 0) {
29464
+ const newNode = result.nodes[0];
29465
+ if (newNode) {
29466
+ this.leaves[leafIndex] = newNode;
29467
+ }
29468
+ }
29469
+ } catch (error) {
29470
+ throw new NetworkError(
29471
+ "Failed to refresh timelock",
29472
+ {
29473
+ method: "refresh_timelock"
29474
+ },
29475
+ error
29476
+ );
29477
+ }
29478
+ }
29479
+ /**
29480
+ * Refresh the timelock of a specific node's refund transaction only.
29481
+ *
29482
+ * @param {string} nodeId - The ID of the node whose refund transaction to refresh
29483
+ * @returns {Promise<void>} Promise that resolves when the refund timelock is refreshed
29484
+ */
29485
+ async testOnly_expireTimelockRefundTx(nodeId) {
29486
+ const sparkClient = await this.connectionManager.createSparkClient(
29487
+ this.config.getCoordinatorAddress()
29488
+ );
29489
+ try {
29490
+ const response = await sparkClient.query_nodes({
29491
+ source: {
29492
+ $case: "nodeIds",
29493
+ nodeIds: {
29494
+ nodeIds: [nodeId]
29495
+ }
29496
+ },
29497
+ includeParents: false
29498
+ });
29499
+ const node = response.nodes[nodeId];
29500
+ if (!node) {
29501
+ throw new ValidationError("Node not found", {
29502
+ field: "nodeId",
29503
+ value: nodeId
29504
+ });
29505
+ }
29506
+ const signingPubKey = await this.config.signer.generatePublicKey(
29507
+ (0, import_sha213.sha256)(node.id)
29508
+ );
29509
+ const result = await this.transferService.refreshTimelockRefundTx(
29510
+ node,
29511
+ signingPubKey
29512
+ );
29513
+ const leafIndex = this.leaves.findIndex((leaf) => leaf.id === node.id);
29514
+ if (leafIndex !== -1 && result.nodes.length > 0) {
29515
+ const newNode = result.nodes[0];
29516
+ if (newNode) {
29517
+ this.leaves[leafIndex] = newNode;
29518
+ }
29519
+ }
29520
+ } catch (error) {
29521
+ throw new NetworkError(
29522
+ "Failed to refresh refund timelock",
29523
+ {
29524
+ method: "refresh_timelock_refund_tx"
29525
+ },
29526
+ error
29527
+ );
29528
+ }
29529
+ }
28971
29530
  cleanup() {
28972
29531
  if (this.claimTransfersInterval) {
28973
29532
  clearInterval(this.claimTransfersInterval);
@@ -29062,10 +29621,473 @@ async function getLatestDepositTxId(address2) {
29062
29621
  }
29063
29622
  return null;
29064
29623
  }
29624
+ async function isTxBroadcast(txid, baseUrl, network) {
29625
+ const headers = {};
29626
+ if (network === 3 /* REGTEST */) {
29627
+ const auth = btoa(
29628
+ `${ELECTRS_CREDENTIALS.username}:${ELECTRS_CREDENTIALS.password}`
29629
+ );
29630
+ headers["Authorization"] = `Basic ${auth}`;
29631
+ }
29632
+ const response = await fetch(`${baseUrl}/tx/${txid}`, {
29633
+ headers
29634
+ });
29635
+ const tx = await response.json();
29636
+ if (tx.error) {
29637
+ return false;
29638
+ }
29639
+ return true;
29640
+ }
29641
+
29642
+ // src/utils/unilateral-exit.ts
29643
+ init_buffer();
29644
+ var import_utils21 = require("@noble/curves/abstract/utils");
29645
+ var import_legacy = require("@noble/hashes/legacy");
29646
+ var import_sha214 = require("@noble/hashes/sha2");
29647
+ var btc5 = __toESM(require("@scure/btc-signer"), 1);
29648
+ function isEphemeralAnchorOutput(script, amount) {
29649
+ return Boolean(
29650
+ amount === 0n && script && // Pattern 1: Bare OP_TRUE (single byte 0x51)
29651
+ (script.length === 1 && script[0] === 81 || // Pattern 2: Push OP_TRUE (two bytes 0x01 0x51) - MALFORMED but we detect it
29652
+ script.length === 2 && script[0] === 1 && script[1] === 81 || // Pattern 3: Bitcoin v29 ephemeral anchor script (7 bytes: 015152014e0173)
29653
+ 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)
29654
+ script.length === 4 && script[0] === 81 && script[1] === 2 && script[2] === 78 && script[3] === 115)
29655
+ );
29656
+ }
29657
+ async function constructUnilateralExitTxs(nodeHexStrings, sparkClient, network) {
29658
+ const result = [];
29659
+ const nodes = nodeHexStrings.map((hex) => TreeNode.decode((0, import_utils21.hexToBytes)(hex)));
29660
+ const nodeMap = /* @__PURE__ */ new Map();
29661
+ for (const node of nodes) {
29662
+ nodeMap.set(node.id, node);
29663
+ }
29664
+ for (const node of nodes) {
29665
+ const transactions = [];
29666
+ const chain = [];
29667
+ let currentNode = node;
29668
+ while (currentNode) {
29669
+ chain.unshift(currentNode);
29670
+ if (currentNode.parentNodeId) {
29671
+ let parentNode = nodeMap.get(currentNode.parentNodeId);
29672
+ if (!parentNode && sparkClient) {
29673
+ try {
29674
+ const response = await sparkClient.query_nodes({
29675
+ source: {
29676
+ $case: "nodeIds",
29677
+ nodeIds: {
29678
+ nodeIds: [currentNode.parentNodeId]
29679
+ }
29680
+ },
29681
+ includeParents: true,
29682
+ network: network || 0
29683
+ // Default to mainnet if not provided
29684
+ });
29685
+ parentNode = response.nodes[currentNode.parentNodeId];
29686
+ if (parentNode) {
29687
+ nodeMap.set(currentNode.parentNodeId, parentNode);
29688
+ }
29689
+ } catch (error) {
29690
+ console.warn(
29691
+ `Failed to query parent node ${currentNode.parentNodeId}: ${error}`
29692
+ );
29693
+ break;
29694
+ }
29695
+ }
29696
+ if (parentNode) {
29697
+ currentNode = parentNode;
29698
+ } else {
29699
+ if (!sparkClient) {
29700
+ console.warn(
29701
+ `Parent node ${currentNode.parentNodeId} not found. Provide a sparkClient to fetch missing parents.`
29702
+ );
29703
+ } else {
29704
+ console.warn(
29705
+ `Parent node ${currentNode.parentNodeId} not found in database. Chain may be incomplete.`
29706
+ );
29707
+ }
29708
+ break;
29709
+ }
29710
+ } else {
29711
+ break;
29712
+ }
29713
+ }
29714
+ for (const chainNode of chain) {
29715
+ const nodeTx = (0, import_utils21.bytesToHex)(chainNode.nodeTx);
29716
+ transactions.push(nodeTx);
29717
+ if (chainNode.id === node.id) {
29718
+ const refundTx = (0, import_utils21.bytesToHex)(chainNode.refundTx);
29719
+ transactions.push(refundTx);
29720
+ }
29721
+ }
29722
+ result.push({
29723
+ leafId: node.id,
29724
+ transactions
29725
+ });
29726
+ }
29727
+ return result;
29728
+ }
29729
+ async function constructUnilateralExitFeeBumpPackages(nodeHexStrings, utxos, feeRate, electrsUrl, sparkClient, network) {
29730
+ const result = [];
29731
+ const availableUtxos = [...utxos].sort((a, b) => {
29732
+ if (a.value > b.value) return -1;
29733
+ if (a.value < b.value) return 1;
29734
+ return 0;
29735
+ });
29736
+ const nodes = [];
29737
+ for (let i = 0; i < nodeHexStrings.length; i++) {
29738
+ const hex = nodeHexStrings[i];
29739
+ try {
29740
+ if (!hex || hex.length === 0) {
29741
+ throw new Error(`Node hex string at index ${i} is empty`);
29742
+ }
29743
+ if (hex.startsWith("03000000") || hex.startsWith("02000000") || hex.startsWith("01000000")) {
29744
+ throw new Error(
29745
+ `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.`
29746
+ );
29747
+ }
29748
+ const nodeBytes = (0, import_utils21.hexToBytes)(hex);
29749
+ const node = TreeNode.decode(nodeBytes);
29750
+ if (!node.id) {
29751
+ throw new Error(
29752
+ `Decoded TreeNode at index ${i} is missing required 'id' field`
29753
+ );
29754
+ }
29755
+ if (!node.nodeTx || node.nodeTx.length === 0) {
29756
+ throw new Error(
29757
+ `Decoded TreeNode at index ${i} is missing required 'nodeTx' field`
29758
+ );
29759
+ }
29760
+ nodes.push(node);
29761
+ } catch (decodeError) {
29762
+ throw new Error(
29763
+ `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.`
29764
+ );
29765
+ }
29766
+ }
29767
+ const nodeMap = /* @__PURE__ */ new Map();
29768
+ for (const node of nodes) {
29769
+ nodeMap.set(node.id, node);
29770
+ }
29771
+ const broadcastTxs = /* @__PURE__ */ new Map();
29772
+ for (const node of nodes) {
29773
+ const txPackages = [];
29774
+ let previousFeeBumpTx;
29775
+ const chain = [];
29776
+ let currentNode = node;
29777
+ while (currentNode) {
29778
+ chain.unshift(currentNode);
29779
+ if (currentNode.parentNodeId) {
29780
+ let parentNode = nodeMap.get(currentNode.parentNodeId);
29781
+ if (!parentNode && sparkClient) {
29782
+ try {
29783
+ const response = await sparkClient.query_nodes({
29784
+ source: {
29785
+ $case: "nodeIds",
29786
+ nodeIds: {
29787
+ nodeIds: [currentNode.parentNodeId]
29788
+ }
29789
+ },
29790
+ includeParents: true,
29791
+ network: network || 0
29792
+ // Default to mainnet if not provided
29793
+ });
29794
+ parentNode = response.nodes[currentNode.parentNodeId];
29795
+ if (parentNode) {
29796
+ nodeMap.set(currentNode.parentNodeId, parentNode);
29797
+ }
29798
+ } catch (error) {
29799
+ console.warn(
29800
+ `Failed to query parent node ${currentNode.parentNodeId}: ${error}`
29801
+ );
29802
+ break;
29803
+ }
29804
+ }
29805
+ if (parentNode) {
29806
+ currentNode = parentNode;
29807
+ } else {
29808
+ if (!sparkClient) {
29809
+ console.warn(
29810
+ `Parent node ${currentNode.parentNodeId} not found. Provide a sparkClient to fetch missing parents.`
29811
+ );
29812
+ } else {
29813
+ console.warn(
29814
+ `Parent node ${currentNode.parentNodeId} not found in database. Chain may be incomplete.`
29815
+ );
29816
+ }
29817
+ break;
29818
+ }
29819
+ } else {
29820
+ break;
29821
+ }
29822
+ }
29823
+ for (const chainNode of chain) {
29824
+ let nodeTxHex = (0, import_utils21.bytesToHex)(chainNode.nodeTx);
29825
+ try {
29826
+ const txObj = getTxFromRawTxHex(nodeTxHex);
29827
+ const txid = getTxId(txObj);
29828
+ if (broadcastTxs.get(txid)) {
29829
+ continue;
29830
+ }
29831
+ broadcastTxs.set(txid, true);
29832
+ const isBroadcast = await isTxBroadcast(txid, electrsUrl, network);
29833
+ if (isBroadcast) {
29834
+ continue;
29835
+ } else {
29836
+ }
29837
+ let anchorOutputScriptHex;
29838
+ for (let i = txObj.outputsLength - 1; i >= 0; i--) {
29839
+ const output = txObj.getOutput(i);
29840
+ if (output?.amount === 0n && output.script) {
29841
+ anchorOutputScriptHex = (0, import_utils21.bytesToHex)(output.script);
29842
+ break;
29843
+ }
29844
+ }
29845
+ } catch (parseError) {
29846
+ console.error(
29847
+ `\u274C Error parsing nodeTx for anchor check (node ${chainNode.id}): ${parseError}`
29848
+ );
29849
+ console.log(
29850
+ ` This may indicate a corrupted transaction in the TreeNode.`
29851
+ );
29852
+ console.log(` Transaction hex: ${nodeTxHex}`);
29853
+ console.log(
29854
+ ` Attempting to continue with original hex, but fee bump may fail.`
29855
+ );
29856
+ }
29857
+ const {
29858
+ feeBumpPsbt: nodeFeeBumpPsbt,
29859
+ usedUtxos,
29860
+ correctedParentTx
29861
+ } = constructFeeBumpTx(nodeTxHex, availableUtxos, feeRate, void 0);
29862
+ const feeBumpTx = btc5.Transaction.fromPSBT((0, import_utils21.hexToBytes)(nodeFeeBumpPsbt));
29863
+ var feeBumpOut = feeBumpTx.outputsLength === 1 ? feeBumpTx.getOutput(0) : null;
29864
+ var feeBumpOutPubKey = null;
29865
+ for (const usedUtxo of usedUtxos) {
29866
+ if (feeBumpOut && (0, import_utils21.bytesToHex)(feeBumpOut.script) == usedUtxo.script) {
29867
+ feeBumpOutPubKey = usedUtxo.publicKey;
29868
+ }
29869
+ const index = availableUtxos.findIndex(
29870
+ (u) => u.txid === usedUtxo.txid && u.vout === usedUtxo.vout
29871
+ );
29872
+ if (index !== -1) {
29873
+ availableUtxos.splice(index, 1);
29874
+ }
29875
+ }
29876
+ if (feeBumpOut)
29877
+ availableUtxos.unshift({
29878
+ txid: getTxId(feeBumpTx),
29879
+ vout: 0,
29880
+ value: feeBumpOut.amount,
29881
+ script: (0, import_utils21.bytesToHex)(feeBumpOut.script),
29882
+ publicKey: feeBumpOutPubKey
29883
+ });
29884
+ const finalNodeTx = correctedParentTx || nodeTxHex;
29885
+ txPackages.push({ tx: finalNodeTx, feeBumpPsbt: nodeFeeBumpPsbt });
29886
+ if (chainNode.id === node.id) {
29887
+ let refundTxHex = (0, import_utils21.bytesToHex)(chainNode.refundTx);
29888
+ try {
29889
+ const txObj = getTxFromRawTxHex(refundTxHex);
29890
+ let anchorOutputScriptHex;
29891
+ for (let i = txObj.outputsLength - 1; i >= 0; i--) {
29892
+ const output = txObj.getOutput(i);
29893
+ if (output?.amount === 0n && output.script) {
29894
+ anchorOutputScriptHex = (0, import_utils21.bytesToHex)(output.script);
29895
+ break;
29896
+ }
29897
+ }
29898
+ } catch (parseError) {
29899
+ console.error(
29900
+ `\u274C Error parsing refundTx for anchor check (node ${chainNode.id}): ${parseError}`
29901
+ );
29902
+ console.log(
29903
+ ` This may indicate a corrupted refund transaction in the TreeNode.`
29904
+ );
29905
+ console.log(` Refund transaction hex: ${refundTxHex}`);
29906
+ console.log(
29907
+ ` Attempting to continue with original refund hex, but this transaction may be invalid.`
29908
+ );
29909
+ }
29910
+ const refundFeeBump = constructFeeBumpTx(
29911
+ refundTxHex,
29912
+ availableUtxos,
29913
+ feeRate,
29914
+ void 0
29915
+ );
29916
+ txPackages.push({
29917
+ tx: refundTxHex,
29918
+ feeBumpPsbt: refundFeeBump.feeBumpPsbt
29919
+ });
29920
+ }
29921
+ }
29922
+ result.push({
29923
+ leafId: node.id,
29924
+ txPackages
29925
+ });
29926
+ }
29927
+ return result;
29928
+ }
29929
+ function hash160(data) {
29930
+ const sha256Hash = (0, import_sha214.sha256)(data);
29931
+ return (0, import_legacy.ripemd160)(sha256Hash);
29932
+ }
29933
+ function constructFeeBumpTx(txHex, utxos, feeRate, previousFeeBumpTx) {
29934
+ if (!txHex || txHex.length === 0) {
29935
+ throw new Error("Transaction hex string is empty or undefined");
29936
+ }
29937
+ if (utxos.length === 0) {
29938
+ throw new Error("No UTXOs available for fee bump");
29939
+ }
29940
+ let correctedTxHex = txHex;
29941
+ let parentTx;
29942
+ try {
29943
+ parentTx = getTxFromRawTxHex(correctedTxHex);
29944
+ if (!parentTx) {
29945
+ throw new Error("getTxFromRawTxHex returned null/undefined");
29946
+ }
29947
+ } catch (parseError) {
29948
+ throw new Error(
29949
+ `Failed to parse parent transaction hex: ${parseError}. Transaction hex: ${correctedTxHex}`
29950
+ );
29951
+ }
29952
+ try {
29953
+ const outputsLength = parentTx.outputsLength;
29954
+ const inputsLength = parentTx.inputsLength;
29955
+ if (typeof outputsLength !== "number" || outputsLength < 0) {
29956
+ throw new Error(
29957
+ "Invalid transaction: outputsLength is not a valid number"
29958
+ );
29959
+ }
29960
+ if (typeof inputsLength !== "number" || inputsLength < 0) {
29961
+ throw new Error(
29962
+ "Invalid transaction: inputsLength is not a valid number"
29963
+ );
29964
+ }
29965
+ } catch (validationError) {
29966
+ throw new Error(
29967
+ `Transaction validation failed: ${validationError}. This may indicate a corrupted or malformed transaction.`
29968
+ );
29969
+ }
29970
+ const parentTxIdFromLib = parentTx.id;
29971
+ let ephemeralAnchorIndex = -1;
29972
+ for (let i = 0; i < parentTx.outputsLength; i++) {
29973
+ const output = parentTx.getOutput(i);
29974
+ const isEphemeralAnchor = isEphemeralAnchorOutput(
29975
+ output?.script,
29976
+ output?.amount
29977
+ );
29978
+ if (isEphemeralAnchor) {
29979
+ ephemeralAnchorIndex = i;
29980
+ break;
29981
+ }
29982
+ }
29983
+ if (ephemeralAnchorIndex === -1) {
29984
+ throw new Error(
29985
+ "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)."
29986
+ );
29987
+ }
29988
+ const ephemeralAnchorOutput = parentTx.getOutput(ephemeralAnchorIndex);
29989
+ if (!ephemeralAnchorOutput)
29990
+ throw new Error("No ephemeral anchor output found");
29991
+ if (!ephemeralAnchorOutput.script)
29992
+ throw new Error("No script found in ephemeral anchor output");
29993
+ if (utxos.length === 0) {
29994
+ throw new Error("No UTXOs available for fee bump");
29995
+ }
29996
+ const builder = new btc5.Transaction({
29997
+ version: 3,
29998
+ allowUnknown: true,
29999
+ allowLegacyWitnessUtxo: true
30000
+ });
30001
+ let totalValue = 0n;
30002
+ const processedUtxos = [];
30003
+ for (let i = 0; i < utxos.length; i++) {
30004
+ const fundingUtxo = utxos[i];
30005
+ if (!fundingUtxo) {
30006
+ throw new Error(`UTXO at index ${i} is undefined`);
30007
+ }
30008
+ const pubKeyHash = hash160((0, import_utils21.hexToBytes)(fundingUtxo.publicKey));
30009
+ const scriptToUse = new Uint8Array([0, 20, ...pubKeyHash]);
30010
+ const providedScript = (0, import_utils21.hexToBytes)(fundingUtxo.script);
30011
+ if ((0, import_utils21.bytesToHex)(scriptToUse) !== (0, import_utils21.bytesToHex)(providedScript)) {
30012
+ throw new Error(
30013
+ `\u274C Derived script doesn't match provided script for UTXO ${i + 1}.`
30014
+ );
30015
+ }
30016
+ builder.addInput({
30017
+ txid: fundingUtxo.txid,
30018
+ index: fundingUtxo.vout,
30019
+ sequence: 4294967295,
30020
+ witnessUtxo: {
30021
+ script: scriptToUse,
30022
+ // Always P2WPKH
30023
+ amount: fundingUtxo.value
30024
+ }
30025
+ });
30026
+ totalValue += fundingUtxo.value;
30027
+ processedUtxos.push({
30028
+ utxo: fundingUtxo,
30029
+ p2wpkhScript: scriptToUse
30030
+ });
30031
+ }
30032
+ builder.addInput({
30033
+ txid: parentTxIdFromLib,
30034
+ index: ephemeralAnchorIndex,
30035
+ sequence: 4294967295,
30036
+ witnessUtxo: {
30037
+ script: ephemeralAnchorOutput.script,
30038
+ // Use the original script directly (not P2WSH wrapped)
30039
+ amount: 0n
30040
+ }
30041
+ });
30042
+ const fee = 1500n;
30043
+ const remainingValue = totalValue - fee;
30044
+ if (remainingValue <= 0n) {
30045
+ throw new Error(
30046
+ `Insufficient funds for fee bump. Required fee: ${fee} sats, Available: ${totalValue} sats`
30047
+ );
30048
+ }
30049
+ if (processedUtxos.length === 0) {
30050
+ throw new Error("No processed UTXOs available for change output");
30051
+ }
30052
+ const firstProcessedUtxo = processedUtxos[0];
30053
+ if (!firstProcessedUtxo) {
30054
+ throw new Error("First processed UTXO is undefined");
30055
+ }
30056
+ builder.addOutput({
30057
+ script: firstProcessedUtxo.p2wpkhScript,
30058
+ amount: remainingValue
30059
+ });
30060
+ for (let i = 0; i < processedUtxos.length; i++) {
30061
+ const processed = processedUtxos[i];
30062
+ if (!processed) {
30063
+ throw new Error(`Processed UTXO at index ${i} is undefined`);
30064
+ }
30065
+ try {
30066
+ builder.updateInput(i, {
30067
+ witnessScript: processed.p2wpkhScript
30068
+ });
30069
+ builder.signIdx;
30070
+ } catch (error) {
30071
+ throw new Error(`Failed to handle funding UTXO input ${i + 1}: ${error}`);
30072
+ }
30073
+ }
30074
+ let psbtHex;
30075
+ try {
30076
+ psbtHex = (0, import_utils21.bytesToHex)(builder.toPSBT());
30077
+ } catch (error) {
30078
+ throw new Error(`Failed to extract transaction: ${error}`);
30079
+ }
30080
+ return {
30081
+ feeBumpPsbt: psbtHex,
30082
+ usedUtxos: utxos,
30083
+ correctedParentTx: correctedTxHex !== txHex ? correctedTxHex : void 0
30084
+ };
30085
+ }
29065
30086
  // Annotate the CommonJS export names for ESM import in node:
29066
30087
  0 && (module.exports = {
29067
30088
  AuthenticationError,
29068
30089
  ConfigurationError,
30090
+ DEFAULT_FEE_SATS,
29069
30091
  InternalValidationError,
29070
30092
  LRC_WALLET_NETWORK,
29071
30093
  LRC_WALLET_NETWORK_TYPE,
@@ -29087,6 +30109,9 @@ async function getLatestDepositTxId(address2) {
29087
30109
  collectResponses,
29088
30110
  computeTaprootKeyNoScript,
29089
30111
  computerLagrangeCoefficients,
30112
+ constructFeeBumpTx,
30113
+ constructUnilateralExitFeeBumpPackages,
30114
+ constructUnilateralExitTxs,
29090
30115
  createDummyTx,
29091
30116
  createRefundTx,
29092
30117
  createSigningCommitment,
@@ -29106,6 +30131,7 @@ async function getLatestDepositTxId(address2) {
29106
30131
  getLatestDepositTxId,
29107
30132
  getNetwork,
29108
30133
  getNetworkFromAddress,
30134
+ getNetworkFromString,
29109
30135
  getNextTransactionSequence,
29110
30136
  getP2TRAddressFromPkScript,
29111
30137
  getP2TRAddressFromPublicKey,
@@ -29121,7 +30147,10 @@ async function getLatestDepositTxId(address2) {
29121
30147
  getTxFromRawTxHex,
29122
30148
  getTxId,
29123
30149
  getTxIdNoReverse,
30150
+ isEphemeralAnchorOutput,
30151
+ isTxBroadcast,
29124
30152
  lastKeyWithTarget,
30153
+ maybeApplyFee,
29125
30154
  modInverse,
29126
30155
  proofOfPossessionMessageHashForDepositAddress,
29127
30156
  recoverSecret,