@buildonspark/spark-sdk 0.2.3 → 0.2.4

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 (73) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/{chunk-PTRXJS7Q.js → chunk-TVUMSHWA.js} +1 -1
  3. package/dist/{chunk-PLLJIZC3.js → chunk-W4ZRBSWM.js} +2298 -778
  4. package/dist/{chunk-CDLETEDT.js → chunk-WAQKYSDI.js} +13 -1
  5. package/dist/{client-CGTRS23n.d.ts → client-BF4cn8F4.d.ts} +15 -3
  6. package/dist/{client-CcYzmpmj.d.cts → client-KhNkrXz4.d.cts} +15 -3
  7. package/dist/debug.cjs +2282 -762
  8. package/dist/debug.d.cts +17 -4
  9. package/dist/debug.d.ts +17 -4
  10. package/dist/debug.js +2 -2
  11. package/dist/graphql/objects/index.cjs +13 -1
  12. package/dist/graphql/objects/index.d.cts +2 -2
  13. package/dist/graphql/objects/index.d.ts +2 -2
  14. package/dist/graphql/objects/index.js +1 -1
  15. package/dist/index.cjs +2283 -752
  16. package/dist/index.d.cts +189 -8
  17. package/dist/index.d.ts +189 -8
  18. package/dist/index.js +29 -3
  19. package/dist/index.node.cjs +2387 -753
  20. package/dist/index.node.d.cts +9 -189
  21. package/dist/index.node.d.ts +9 -189
  22. package/dist/index.node.js +131 -3
  23. package/dist/native/index.cjs +2283 -752
  24. package/dist/native/index.d.cts +95 -30
  25. package/dist/native/index.d.ts +95 -30
  26. package/dist/native/index.js +2284 -767
  27. package/dist/{spark-wallet-CxcGPXRB.d.ts → spark-wallet-C1Tr_VKI.d.ts} +31 -25
  28. package/dist/{spark-wallet-DJJm19BP.d.cts → spark-wallet-DG3x2obf.d.cts} +31 -25
  29. package/dist/spark-wallet.node-CGxoeCpH.d.ts +13 -0
  30. package/dist/spark-wallet.node-CN9LoB_O.d.cts +13 -0
  31. package/dist/tests/test-utils.cjs +570 -73
  32. package/dist/tests/test-utils.d.cts +11 -11
  33. package/dist/tests/test-utils.d.ts +11 -11
  34. package/dist/tests/test-utils.js +53 -16
  35. package/dist/types/index.cjs +13 -1
  36. package/dist/types/index.d.cts +1 -1
  37. package/dist/types/index.d.ts +1 -1
  38. package/dist/types/index.js +1 -1
  39. package/dist/{xchain-address-Bh9w1SeC.d.ts → xchain-address-BHu6CpZC.d.ts} +54 -7
  40. package/dist/{xchain-address-SZ7dkVUE.d.cts → xchain-address-HBr6isnc.d.cts} +54 -7
  41. package/package.json +1 -1
  42. package/src/graphql/client.ts +8 -0
  43. package/src/graphql/mutations/CompleteLeavesSwap.ts +9 -1
  44. package/src/graphql/mutations/RequestSwapLeaves.ts +4 -0
  45. package/src/graphql/objects/CompleteLeavesSwapInput.ts +34 -34
  46. package/src/graphql/objects/LeavesSwapRequest.ts +4 -0
  47. package/src/graphql/objects/RequestLeavesSwapInput.ts +48 -47
  48. package/src/graphql/objects/SwapLeaf.ts +40 -32
  49. package/src/graphql/objects/UserLeafInput.ts +24 -0
  50. package/src/graphql/objects/UserRequest.ts +4 -0
  51. package/src/index.node.ts +1 -1
  52. package/src/native/index.ts +4 -5
  53. package/src/services/coop-exit.ts +171 -36
  54. package/src/services/deposit.ts +471 -74
  55. package/src/services/lightning.ts +18 -5
  56. package/src/services/signing.ts +162 -50
  57. package/src/services/transfer.ts +950 -384
  58. package/src/services/tree-creation.ts +342 -121
  59. package/src/spark-wallet/spark-wallet.node.ts +71 -66
  60. package/src/spark-wallet/spark-wallet.ts +405 -153
  61. package/src/tests/integration/coop-exit.test.ts +3 -8
  62. package/src/tests/integration/deposit.test.ts +3 -3
  63. package/src/tests/integration/lightning.test.ts +521 -466
  64. package/src/tests/integration/swap.test.ts +559 -307
  65. package/src/tests/integration/transfer.test.ts +625 -623
  66. package/src/tests/integration/wallet.test.ts +2 -2
  67. package/src/tests/integration/watchtower.test.ts +211 -0
  68. package/src/tests/test-utils.ts +63 -14
  69. package/src/tests/utils/test-faucet.ts +4 -2
  70. package/src/utils/adaptor-signature.ts +15 -5
  71. package/src/utils/fetch.ts +75 -0
  72. package/src/utils/mempool.ts +9 -4
  73. package/src/utils/transaction.ts +388 -26
package/dist/debug.cjs CHANGED
@@ -1826,7 +1826,11 @@ var SwapLeafFromJson = (obj) => {
1826
1826
  return {
1827
1827
  leafId: obj["swap_leaf_leaf_id"],
1828
1828
  rawUnsignedRefundTransaction: obj["swap_leaf_raw_unsigned_refund_transaction"],
1829
- adaptorSignedSignature: obj["swap_leaf_adaptor_signed_signature"]
1829
+ adaptorSignedSignature: obj["swap_leaf_adaptor_signed_signature"],
1830
+ directRawUnsignedRefundTransaction: obj["swap_leaf_direct_raw_unsigned_refund_transaction"],
1831
+ directAdaptorSignedSignature: obj["swap_leaf_direct_adaptor_signed_signature"],
1832
+ directFromCpfpRawUnsignedRefundTransaction: obj["swap_leaf_direct_from_cpfp_raw_unsigned_refund_transaction"],
1833
+ directFromCpfpAdaptorSignedSignature: obj["swap_leaf_direct_from_cpfp_adaptor_signed_signature"]
1830
1834
  };
1831
1835
  };
1832
1836
 
@@ -1924,6 +1928,10 @@ fragment LeavesSwapRequestFragment on LeavesSwapRequest {
1924
1928
  swap_leaf_leaf_id: leaf_id
1925
1929
  swap_leaf_raw_unsigned_refund_transaction: raw_unsigned_refund_transaction
1926
1930
  swap_leaf_adaptor_signed_signature: adaptor_signed_signature
1931
+ swap_leaf_direct_raw_unsigned_refund_transaction: direct_raw_unsigned_refund_transaction
1932
+ swap_leaf_direct_adaptor_signed_signature: direct_adaptor_signed_signature
1933
+ swap_leaf_direct_from_cpfp_raw_unsigned_refund_transaction: direct_from_cpfp_raw_unsigned_refund_transaction
1934
+ swap_leaf_direct_from_cpfp_adaptor_signed_signature: direct_from_cpfp_adaptor_signed_signature
1927
1935
  }
1928
1936
  }`;
1929
1937
 
@@ -1931,10 +1939,18 @@ fragment LeavesSwapRequestFragment on LeavesSwapRequest {
1931
1939
  var CompleteLeavesSwap = `
1932
1940
  mutation CompleteLeavesSwap(
1933
1941
  $adaptor_secret_key: String!
1942
+ $direct_adaptor_secret_key: String!
1943
+ $direct_from_cpfp_adaptor_secret_key: String!
1934
1944
  $user_outbound_transfer_external_id: UUID!
1935
1945
  $leaves_swap_request_id: ID!
1936
1946
  ) {
1937
- complete_leaves_swap(input: { adaptor_secret_key: $adaptor_secret_key, user_outbound_transfer_external_id: $user_outbound_transfer_external_id, leaves_swap_request_id: $leaves_swap_request_id }) {
1947
+ complete_leaves_swap(input: {
1948
+ adaptor_secret_key: $adaptor_secret_key,
1949
+ direct_adaptor_secret_key: $direct_adaptor_secret_key,
1950
+ direct_from_cpfp_adaptor_secret_key: $direct_from_cpfp_adaptor_secret_key,
1951
+ user_outbound_transfer_external_id: $user_outbound_transfer_external_id,
1952
+ leaves_swap_request_id: $leaves_swap_request_id
1953
+ }) {
1938
1954
  request {
1939
1955
  ...LeavesSwapRequestFragment
1940
1956
  }
@@ -2235,6 +2251,8 @@ init_buffer();
2235
2251
  var RequestSwapLeaves = `
2236
2252
  mutation RequestSwapLeaves(
2237
2253
  $adaptor_pubkey: PublicKey!
2254
+ $direct_adaptor_pubkey: PublicKey
2255
+ $direct_from_cpfp_adaptor_pubkey: PublicKey
2238
2256
  $total_amount_sats: Long!
2239
2257
  $target_amount_sats: Long!
2240
2258
  $fee_sats: Long!
@@ -2244,6 +2262,8 @@ var RequestSwapLeaves = `
2244
2262
  ) {
2245
2263
  request_leaves_swap(input: {
2246
2264
  adaptor_pubkey: $adaptor_pubkey
2265
+ direct_adaptor_pubkey: $direct_adaptor_pubkey
2266
+ direct_from_cpfp_adaptor_pubkey: $direct_from_cpfp_adaptor_pubkey
2247
2267
  total_amount_sats: $total_amount_sats
2248
2268
  target_amount_sats: $target_amount_sats
2249
2269
  fee_sats: $fee_sats
@@ -2815,6 +2835,10 @@ fragment UserRequestFragment on UserRequest {
2815
2835
  swap_leaf_leaf_id: leaf_id
2816
2836
  swap_leaf_raw_unsigned_refund_transaction: raw_unsigned_refund_transaction
2817
2837
  swap_leaf_adaptor_signed_signature: adaptor_signed_signature
2838
+ swap_leaf_direct_raw_unsigned_refund_transaction: direct_raw_unsigned_refund_transaction
2839
+ swap_leaf_direct_adaptor_signed_signature: direct_adaptor_signed_signature
2840
+ swap_leaf_direct_from_cpfp_raw_unsigned_refund_transaction: direct_from_cpfp_raw_unsigned_refund_transaction
2841
+ swap_leaf_direct_from_cpfp_adaptor_signed_signature: direct_from_cpfp_adaptor_signed_signature
2818
2842
  }
2819
2843
  }
2820
2844
  ... on LightningReceiveRequest {
@@ -3097,6 +3121,8 @@ var SspClient = class {
3097
3121
  }
3098
3122
  async requestLeaveSwap({
3099
3123
  adaptorPubkey,
3124
+ directAdaptorPubkey,
3125
+ directFromCpfpAdaptorPubkey,
3100
3126
  totalAmountSats,
3101
3127
  targetAmountSats,
3102
3128
  feeSats,
@@ -3108,6 +3134,8 @@ var SspClient = class {
3108
3134
  queryPayload: RequestSwapLeaves,
3109
3135
  variables: {
3110
3136
  adaptor_pubkey: adaptorPubkey,
3137
+ direct_adaptor_pubkey: directAdaptorPubkey,
3138
+ direct_from_cpfp_adaptor_pubkey: directFromCpfpAdaptorPubkey,
3111
3139
  total_amount_sats: totalAmountSats,
3112
3140
  target_amount_sats: targetAmountSats,
3113
3141
  fee_sats: feeSats,
@@ -3126,6 +3154,8 @@ var SspClient = class {
3126
3154
  }
3127
3155
  async completeLeaveSwap({
3128
3156
  adaptorSecretKey,
3157
+ directAdaptorSecretKey,
3158
+ directFromCpfpAdaptorSecretKey,
3129
3159
  userOutboundTransferExternalId,
3130
3160
  leavesSwapRequestId
3131
3161
  }) {
@@ -3133,6 +3163,8 @@ var SspClient = class {
3133
3163
  queryPayload: CompleteLeavesSwap,
3134
3164
  variables: {
3135
3165
  adaptor_secret_key: adaptorSecretKey,
3166
+ direct_adaptor_secret_key: directAdaptorSecretKey,
3167
+ direct_from_cpfp_adaptor_secret_key: directFromCpfpAdaptorSecretKey,
3136
3168
  user_outbound_transfer_external_id: userOutboundTransferExternalId,
3137
3169
  leaves_swap_request_id: leavesSwapRequestId
3138
3170
  },
@@ -17948,7 +17980,7 @@ init_buffer();
17948
17980
  var import_core10 = require("@lightsparkdev/core");
17949
17981
  var isReactNative = typeof navigator !== "undefined" && navigator.product === "ReactNative";
17950
17982
  var isBun = globalThis.Bun !== void 0;
17951
- var packageVersion = true ? "0.2.3" : "unknown";
17983
+ var packageVersion = true ? "0.2.4" : "unknown";
17952
17984
  var baseEnvStr = "unknown";
17953
17985
  if (isBun) {
17954
17986
  const bunVersion = "version" in globalThis.Bun ? globalThis.Bun.version : "unknown-version";
@@ -23174,7 +23206,14 @@ function getTxIdNoReverse(tx) {
23174
23206
  // src/utils/transaction.ts
23175
23207
  init_buffer();
23176
23208
  var import_btc_signer = require("@scure/btc-signer");
23209
+ var INITIAL_TIMELOCK = 2e3;
23210
+ var TEST_UNILATERAL_TIMELOCK = 100;
23177
23211
  var TIME_LOCK_INTERVAL = 100;
23212
+ var DIRECT_TIMELOCK_OFFSET = 50;
23213
+ var INITIAL_SEQUENCE = 1 << 30 | INITIAL_TIMELOCK;
23214
+ var INITIAL_DIRECT_SEQUENCE = 1 << 30 | INITIAL_TIMELOCK + DIRECT_TIMELOCK_OFFSET;
23215
+ var TEST_UNILATERAL_SEQUENCE = 1 << 30 | TEST_UNILATERAL_TIMELOCK;
23216
+ var TEST_UNILATERAL_DIRECT_SEQUENCE = 1 << 30 | TEST_UNILATERAL_TIMELOCK + DIRECT_TIMELOCK_OFFSET;
23178
23217
  var ESTIMATED_TX_SIZE = 191;
23179
23218
  var DEFAULT_SATS_PER_VBYTE = 5;
23180
23219
  var DEFAULT_FEE_SATS = ESTIMATED_TX_SIZE * DEFAULT_SATS_PER_VBYTE;
@@ -23184,29 +23223,270 @@ function maybeApplyFee(amount) {
23184
23223
  }
23185
23224
  return amount;
23186
23225
  }
23187
- function createRefundTx(sequence, nodeOutPoint, amountSats, receivingPubkey, network) {
23188
- const newRefundTx = new import_btc_signer.Transaction({
23226
+ function createRootTx(depositOutPoint, depositTxOut) {
23227
+ const cpfpRootTx = new import_btc_signer.Transaction({
23228
+ version: 3,
23229
+ allowUnknownOutputs: true
23230
+ });
23231
+ cpfpRootTx.addInput(depositOutPoint);
23232
+ cpfpRootTx.addOutput(depositTxOut);
23233
+ cpfpRootTx.addOutput(getEphemeralAnchorOutput());
23234
+ const directRootTx = new import_btc_signer.Transaction({
23235
+ version: 3,
23236
+ allowUnknownOutputs: true
23237
+ });
23238
+ directRootTx.addInput(depositOutPoint);
23239
+ directRootTx.addOutput({
23240
+ script: depositTxOut.script,
23241
+ amount: maybeApplyFee(depositTxOut.amount ?? 0n)
23242
+ });
23243
+ return [cpfpRootTx, directRootTx];
23244
+ }
23245
+ function createSplitTx(parentOutPoint, childTxOuts) {
23246
+ const cpfpSplitTx = new import_btc_signer.Transaction({
23247
+ version: 3,
23248
+ allowUnknownOutputs: true
23249
+ });
23250
+ cpfpSplitTx.addInput(parentOutPoint);
23251
+ for (const txOut of childTxOuts) {
23252
+ cpfpSplitTx.addOutput(txOut);
23253
+ }
23254
+ cpfpSplitTx.addOutput(getEphemeralAnchorOutput());
23255
+ const directSplitTx = new import_btc_signer.Transaction({
23256
+ version: 3,
23257
+ allowUnknownOutputs: true
23258
+ });
23259
+ directSplitTx.addInput(parentOutPoint);
23260
+ let totalOutputAmount = 0n;
23261
+ for (const txOut of childTxOuts) {
23262
+ totalOutputAmount += txOut.amount ?? 0n;
23263
+ }
23264
+ if (totalOutputAmount > BigInt(DEFAULT_FEE_SATS)) {
23265
+ const feeRatio = Number(DEFAULT_FEE_SATS) / Number(totalOutputAmount);
23266
+ for (const txOut of childTxOuts) {
23267
+ const adjustedAmount = BigInt(
23268
+ Math.floor(Number(txOut.amount ?? 0n) * (1 - feeRatio))
23269
+ );
23270
+ directSplitTx.addOutput({
23271
+ script: txOut.script,
23272
+ amount: adjustedAmount
23273
+ });
23274
+ }
23275
+ } else {
23276
+ for (const txOut of childTxOuts) {
23277
+ directSplitTx.addOutput(txOut);
23278
+ }
23279
+ }
23280
+ return [cpfpSplitTx, directSplitTx];
23281
+ }
23282
+ function createNodeTx({
23283
+ txOut,
23284
+ parentOutPoint,
23285
+ applyFee,
23286
+ includeAnchor
23287
+ }) {
23288
+ const nodeTx = new import_btc_signer.Transaction({
23289
+ version: 3,
23290
+ allowUnknownOutputs: true
23291
+ });
23292
+ nodeTx.addInput(parentOutPoint);
23293
+ if (applyFee) {
23294
+ nodeTx.addOutput({
23295
+ script: txOut.script,
23296
+ amount: maybeApplyFee(txOut.amount ?? 0n)
23297
+ });
23298
+ } else {
23299
+ nodeTx.addOutput(txOut);
23300
+ }
23301
+ if (includeAnchor) {
23302
+ nodeTx.addOutput(getEphemeralAnchorOutput());
23303
+ }
23304
+ return nodeTx;
23305
+ }
23306
+ function createNodeTxs(txOut, txIn, directTxIn) {
23307
+ const cpfpNodeTx = createNodeTx({
23308
+ txOut,
23309
+ parentOutPoint: txIn,
23310
+ includeAnchor: true
23311
+ });
23312
+ let directNodeTx;
23313
+ if (directTxIn) {
23314
+ directNodeTx = createNodeTx({
23315
+ txOut,
23316
+ parentOutPoint: directTxIn,
23317
+ includeAnchor: false,
23318
+ applyFee: true
23319
+ });
23320
+ }
23321
+ return { cpfpNodeTx, directNodeTx };
23322
+ }
23323
+ function createLeafNodeTx(sequence, directSequence, parentOutPoint, txOut, shouldCalculateFee) {
23324
+ const cpfpLeafTx = new import_btc_signer.Transaction({
23325
+ version: 3,
23326
+ allowUnknownOutputs: true
23327
+ });
23328
+ cpfpLeafTx.addInput({
23329
+ ...parentOutPoint,
23330
+ sequence
23331
+ });
23332
+ cpfpLeafTx.addOutput(txOut);
23333
+ cpfpLeafTx.addOutput(getEphemeralAnchorOutput());
23334
+ const directLeafTx = new import_btc_signer.Transaction({
23335
+ version: 3,
23336
+ allowUnknownOutputs: true
23337
+ });
23338
+ directLeafTx.addInput({
23339
+ ...parentOutPoint,
23340
+ sequence: directSequence
23341
+ });
23342
+ const amountSats = txOut.amount ?? 0n;
23343
+ let outputAmount = amountSats;
23344
+ if (shouldCalculateFee) {
23345
+ outputAmount = maybeApplyFee(amountSats);
23346
+ }
23347
+ directLeafTx.addOutput({
23348
+ script: txOut.script,
23349
+ amount: outputAmount
23350
+ });
23351
+ return [cpfpLeafTx, directLeafTx];
23352
+ }
23353
+ function createRefundTx({
23354
+ sequence,
23355
+ input,
23356
+ amountSats,
23357
+ receivingPubkey,
23358
+ network,
23359
+ shouldCalculateFee,
23360
+ includeAnchor
23361
+ }) {
23362
+ const refundTx = new import_btc_signer.Transaction({
23189
23363
  version: 3,
23190
23364
  allowUnknownOutputs: true
23191
23365
  });
23192
- newRefundTx.addInput({
23193
- ...nodeOutPoint,
23366
+ refundTx.addInput({
23367
+ ...input,
23194
23368
  sequence
23195
23369
  });
23196
23370
  const refundPkScript = getP2TRScriptFromPublicKey(receivingPubkey, network);
23197
- newRefundTx.addOutput({
23371
+ let outputAmount = amountSats;
23372
+ if (shouldCalculateFee) {
23373
+ outputAmount = maybeApplyFee(amountSats);
23374
+ }
23375
+ refundTx.addOutput({
23198
23376
  script: refundPkScript,
23377
+ amount: outputAmount
23378
+ });
23379
+ if (includeAnchor) {
23380
+ refundTx.addOutput(getEphemeralAnchorOutput());
23381
+ }
23382
+ return refundTx;
23383
+ }
23384
+ function createRefundTxs({
23385
+ sequence,
23386
+ directSequence,
23387
+ input,
23388
+ directInput,
23389
+ amountSats,
23390
+ receivingPubkey,
23391
+ network
23392
+ }) {
23393
+ const cpfpRefundTx = createRefundTx({
23394
+ sequence,
23395
+ input,
23396
+ amountSats,
23397
+ receivingPubkey,
23398
+ network,
23399
+ shouldCalculateFee: false,
23400
+ includeAnchor: true
23401
+ });
23402
+ let directRefundTx;
23403
+ let directFromCpfpRefundTx;
23404
+ if (directSequence && directInput) {
23405
+ directRefundTx = createRefundTx({
23406
+ sequence: directSequence,
23407
+ input: directInput,
23408
+ amountSats,
23409
+ receivingPubkey,
23410
+ network,
23411
+ shouldCalculateFee: true,
23412
+ includeAnchor: false
23413
+ });
23414
+ directFromCpfpRefundTx = createRefundTx({
23415
+ sequence: directSequence,
23416
+ input,
23417
+ amountSats,
23418
+ receivingPubkey,
23419
+ network,
23420
+ shouldCalculateFee: true,
23421
+ includeAnchor: false
23422
+ });
23423
+ } else if (directInput && !directSequence) {
23424
+ throw new ValidationError(
23425
+ "directSequence must be provided if directInput is",
23426
+ {
23427
+ field: "directSequence",
23428
+ value: directSequence
23429
+ }
23430
+ );
23431
+ }
23432
+ return { cpfpRefundTx, directRefundTx, directFromCpfpRefundTx };
23433
+ }
23434
+ function createConnectorRefundTransactions(sequence, cpfpNodeOutPoint, directNodeOutPoint, connectorOutput, amountSats, receiverPubKey, network, shouldCalculateFee) {
23435
+ const cpfpRefundTx = new import_btc_signer.Transaction({
23436
+ version: 3,
23437
+ allowUnknownOutputs: true
23438
+ });
23439
+ cpfpRefundTx.addInput({
23440
+ ...cpfpNodeOutPoint,
23441
+ sequence
23442
+ });
23443
+ cpfpRefundTx.addInput(connectorOutput);
23444
+ const receiverScript = getP2TRScriptFromPublicKey(receiverPubKey, network);
23445
+ cpfpRefundTx.addOutput({
23446
+ script: receiverScript,
23199
23447
  amount: amountSats
23200
23448
  });
23201
- newRefundTx.addOutput(getEphemeralAnchorOutput());
23202
- return newRefundTx;
23449
+ const directRefundTx = new import_btc_signer.Transaction({
23450
+ version: 3,
23451
+ allowUnknownOutputs: true
23452
+ });
23453
+ directRefundTx.addInput({
23454
+ ...directNodeOutPoint,
23455
+ sequence
23456
+ });
23457
+ directRefundTx.addInput(connectorOutput);
23458
+ let outputAmount = amountSats;
23459
+ if (shouldCalculateFee) {
23460
+ outputAmount = maybeApplyFee(amountSats);
23461
+ }
23462
+ directRefundTx.addOutput({
23463
+ script: receiverScript,
23464
+ amount: outputAmount
23465
+ });
23466
+ const directFromCpfpTx = new import_btc_signer.Transaction({
23467
+ version: 3,
23468
+ allowUnknownOutputs: true
23469
+ });
23470
+ directFromCpfpTx.addInput({
23471
+ ...cpfpNodeOutPoint,
23472
+ sequence
23473
+ });
23474
+ directFromCpfpTx.addInput(connectorOutput);
23475
+ directFromCpfpTx.addOutput({
23476
+ script: receiverScript,
23477
+ amount: outputAmount
23478
+ });
23479
+ return [cpfpRefundTx, directRefundTx, directFromCpfpTx];
23203
23480
  }
23204
23481
  function getCurrentTimelock(currSequence) {
23205
23482
  return (currSequence || 0) & 65535;
23206
23483
  }
23207
23484
  function getTransactionSequence(currSequence) {
23208
23485
  const timelock = getCurrentTimelock(currSequence);
23209
- return 1 << 30 | timelock;
23486
+ return {
23487
+ nextSequence: 1 << 30 | timelock,
23488
+ nextDirectSequence: 1 << 30 | timelock + DIRECT_TIMELOCK_OFFSET
23489
+ };
23210
23490
  }
23211
23491
  function checkIfValidSequence(currSequence) {
23212
23492
  const TIME_LOCK_ACTIVE = (currSequence || 0) & 2147483648;
@@ -23224,24 +23504,32 @@ function checkIfValidSequence(currSequence) {
23224
23504
  });
23225
23505
  }
23226
23506
  }
23227
- function getNextTransactionSequence(currSequence, forRefresh) {
23507
+ function doesLeafNeedRefresh(currSequence, isNodeTx) {
23228
23508
  const currentTimelock = getCurrentTimelock(currSequence);
23229
- const nextTimelock = currentTimelock - TIME_LOCK_INTERVAL;
23230
- if (forRefresh && nextTimelock <= 100 && currentTimelock > 0) {
23231
- return {
23232
- nextSequence: 1 << 30 | nextTimelock,
23233
- needRefresh: true
23234
- };
23509
+ if (isNodeTx) {
23510
+ return currentTimelock === 0;
23235
23511
  }
23236
- if (nextTimelock < 0) {
23512
+ return currentTimelock <= 100;
23513
+ }
23514
+ function getNextTransactionSequence(currSequence, isNodeTx) {
23515
+ const currentTimelock = getCurrentTimelock(currSequence);
23516
+ const nextTimelock = currentTimelock - TIME_LOCK_INTERVAL;
23517
+ if (isNodeTx && nextTimelock < 0) {
23237
23518
  throw new ValidationError("timelock interval is less than 0", {
23238
23519
  field: "nextTimelock",
23239
- value: nextTimelock
23520
+ value: nextTimelock,
23521
+ expected: "Non-negative timelock interval"
23522
+ });
23523
+ } else if (!isNodeTx && nextTimelock <= 0) {
23524
+ throw new ValidationError("timelock interval is less than or equal to 0", {
23525
+ field: "nextTimelock",
23526
+ value: nextTimelock,
23527
+ expected: "Timelock greater than 0"
23240
23528
  });
23241
23529
  }
23242
23530
  return {
23243
23531
  nextSequence: 1 << 30 | nextTimelock,
23244
- needRefresh: nextTimelock <= 100
23532
+ nextDirectSequence: 1 << 30 | nextTimelock + DIRECT_TIMELOCK_OFFSET
23245
23533
  };
23246
23534
  }
23247
23535
  function getEphemeralAnchorOutput() {
@@ -23287,11 +23575,7 @@ function getTransferPackageSigningPayload(transferID, transferPackage) {
23287
23575
  }
23288
23576
 
23289
23577
  // src/services/transfer.ts
23290
- var INITIAL_TIME_LOCK = 2e3;
23291
23578
  var DEFAULT_EXPIRY_TIME = 10 * 60 * 1e3;
23292
- function initialSequence() {
23293
- return 1 << 30 | INITIAL_TIME_LOCK;
23294
- }
23295
23579
  function getSigningJobProto(signingJob) {
23296
23580
  return {
23297
23581
  signingPublicKey: signingJob.signingPublicKey,
@@ -23308,12 +23592,14 @@ var BaseTransferService = class {
23308
23592
  this.connectionManager = connectionManager;
23309
23593
  this.signingService = signingService;
23310
23594
  }
23311
- async sendTransferTweakKey(transfer, leaves, refundSignatureMap) {
23595
+ async sendTransferTweakKey(transfer, leaves, cpfpRefundSignatureMap, directRefundSignatureMap, directFromCpfpRefundSignatureMap) {
23312
23596
  const keyTweakInputMap = await this.prepareSendTransferKeyTweaks(
23313
23597
  transfer.id,
23314
23598
  transfer.receiverIdentityPublicKey,
23315
23599
  leaves,
23316
- refundSignatureMap
23600
+ cpfpRefundSignatureMap,
23601
+ directRefundSignatureMap,
23602
+ directFromCpfpRefundSignatureMap
23317
23603
  );
23318
23604
  let updatedTransfer;
23319
23605
  const coordinatorOperator = this.config.getSigningOperators()[this.config.getCoordinatorIdentifier()];
@@ -23351,13 +23637,26 @@ var BaseTransferService = class {
23351
23637
  }
23352
23638
  return updatedTransfer;
23353
23639
  }
23354
- async deliverTransferPackage(transfer, leaves, refundSignatureMap) {
23640
+ async deliverTransferPackage(transfer, leaves, cpfpRefundSignatureMap, directRefundSignatureMap, directFromCpfpRefundSignatureMap) {
23355
23641
  const keyTweakInputMap = await this.prepareSendTransferKeyTweaks(
23356
23642
  transfer.id,
23357
23643
  transfer.receiverIdentityPublicKey,
23358
23644
  leaves,
23359
- refundSignatureMap
23645
+ cpfpRefundSignatureMap,
23646
+ directRefundSignatureMap,
23647
+ directFromCpfpRefundSignatureMap
23360
23648
  );
23649
+ for (const [key, operator] of Object.entries(
23650
+ this.config.getSigningOperators()
23651
+ )) {
23652
+ const tweaks = keyTweakInputMap.get(key);
23653
+ if (!tweaks) {
23654
+ throw new ValidationError("No tweaks for operator", {
23655
+ field: "operator",
23656
+ value: key
23657
+ });
23658
+ }
23659
+ }
23361
23660
  const transferPackage = await this.prepareTransferPackage(
23362
23661
  transfer.id,
23363
23662
  keyTweakInputMap,
@@ -23383,6 +23682,8 @@ var BaseTransferService = class {
23383
23682
  transferID,
23384
23683
  receiverIdentityPubkey,
23385
23684
  leaves,
23685
+ /* @__PURE__ */ new Map(),
23686
+ /* @__PURE__ */ new Map(),
23386
23687
  /* @__PURE__ */ new Map()
23387
23688
  );
23388
23689
  const transferPackage = await this.prepareTransferPackage(
@@ -23396,7 +23697,7 @@ var BaseTransferService = class {
23396
23697
  );
23397
23698
  let response;
23398
23699
  try {
23399
- response = await sparkClient.start_transfer({
23700
+ response = await sparkClient.start_transfer_v2({
23400
23701
  transferId: transferID,
23401
23702
  ownerIdentityPublicKey: await this.config.signer.getIdentityPublicKey(),
23402
23703
  receiverIdentityPublicKey: receiverIdentityPubkey,
@@ -23425,12 +23726,22 @@ var BaseTransferService = class {
23425
23726
  nodes.push(leaf.leaf.id);
23426
23727
  }
23427
23728
  const signingCommitments = await sparkClient.get_signing_commitments({
23428
- nodeIds: nodes
23729
+ nodeIds: nodes,
23730
+ count: 3
23429
23731
  });
23430
- const leafSigningJobs = await this.signingService.signRefunds(
23732
+ const {
23733
+ cpfpLeafSigningJobs,
23734
+ directLeafSigningJobs,
23735
+ directFromCpfpLeafSigningJobs
23736
+ } = await this.signingService.signRefunds(
23431
23737
  leaves,
23432
- signingCommitments.signingCommitments,
23433
- receiverIdentityPubkey
23738
+ receiverIdentityPubkey,
23739
+ signingCommitments.signingCommitments.slice(0, leaves.length),
23740
+ signingCommitments.signingCommitments.slice(
23741
+ leaves.length,
23742
+ 2 * leaves.length
23743
+ ),
23744
+ signingCommitments.signingCommitments.slice(2 * leaves.length)
23434
23745
  );
23435
23746
  const encryptedKeyTweaks = {};
23436
23747
  for (const [key, value] of keyTweakInputMap) {
@@ -23450,12 +23761,11 @@ var BaseTransferService = class {
23450
23761
  encryptedKeyTweaks[key] = Uint8Array.from(encryptedProto);
23451
23762
  }
23452
23763
  const transferPackage = {
23453
- leavesToSend: leafSigningJobs,
23764
+ leavesToSend: cpfpLeafSigningJobs,
23454
23765
  keyTweakPackage: encryptedKeyTweaks,
23455
23766
  userSignature: new Uint8Array(),
23456
- // TODO: Add direct refund signature
23457
- directLeavesToSend: [],
23458
- directFromCpfpLeavesToSend: []
23767
+ directLeavesToSend: directLeafSigningJobs,
23768
+ directFromCpfpLeavesToSend: directFromCpfpLeafSigningJobs
23459
23769
  };
23460
23770
  const transferPackageSigningPayload = getTransferPackageSigningPayload(
23461
23771
  transferID,
@@ -23515,7 +23825,7 @@ var BaseTransferService = class {
23515
23825
  }
23516
23826
  return updatedTransfer;
23517
23827
  }
23518
- async signRefunds(leafDataMap, operatorSigningResults, adaptorPubKey) {
23828
+ async signRefunds(leafDataMap, operatorSigningResults, cpfpAdaptorPubKey, directAdaptorPubKey, directFromCpfpAdaptorPubKey) {
23519
23829
  const nodeSignatures = [];
23520
23830
  for (const operatorSigningResult of operatorSigningResults) {
23521
23831
  const leafData = leafDataMap.get(operatorSigningResult.leafId);
@@ -23530,54 +23840,120 @@ var BaseTransferService = class {
23530
23840
  `Output not found for leaf ${operatorSigningResult.leafId}`
23531
23841
  );
23532
23842
  }
23533
- const refundTxSighash = getSigHashFromTx(leafData.refundTx, 0, txOutput);
23843
+ const cpfpRefundTxSighash = getSigHashFromTx(
23844
+ leafData.refundTx,
23845
+ 0,
23846
+ txOutput
23847
+ );
23534
23848
  const publicKey = await this.config.signer.getPublicKeyFromDerivation(
23535
23849
  leafData.keyDerivation
23536
23850
  );
23537
- const userSignature = await this.config.signer.signFrost({
23538
- message: refundTxSighash,
23851
+ const cpfpUserSignature = await this.config.signer.signFrost({
23852
+ message: cpfpRefundTxSighash,
23539
23853
  publicKey,
23540
23854
  keyDerivation: leafData.keyDerivation,
23541
23855
  selfCommitment: leafData.signingNonceCommitment,
23542
23856
  statechainCommitments: operatorSigningResult.refundTxSigningResult?.signingNonceCommitments,
23543
- adaptorPubKey,
23857
+ adaptorPubKey: cpfpAdaptorPubKey,
23544
23858
  verifyingKey: operatorSigningResult.verifyingKey
23545
23859
  });
23546
- const refundAggregate = await this.config.signer.aggregateFrost({
23547
- message: refundTxSighash,
23860
+ const cpfpRefundAggregate = await this.config.signer.aggregateFrost({
23861
+ message: cpfpRefundTxSighash,
23548
23862
  statechainSignatures: operatorSigningResult.refundTxSigningResult?.signatureShares,
23549
23863
  statechainPublicKeys: operatorSigningResult.refundTxSigningResult?.publicKeys,
23550
23864
  verifyingKey: operatorSigningResult.verifyingKey,
23551
23865
  statechainCommitments: operatorSigningResult.refundTxSigningResult?.signingNonceCommitments,
23552
23866
  selfCommitment: leafData.signingNonceCommitment,
23553
23867
  publicKey,
23554
- selfSignature: userSignature,
23555
- adaptorPubKey
23868
+ selfSignature: cpfpUserSignature,
23869
+ adaptorPubKey: cpfpAdaptorPubKey
23556
23870
  });
23871
+ let directRefundAggregate;
23872
+ let directFromCpfpRefundAggregate;
23873
+ if (leafData.directTx) {
23874
+ const directTxOutput = leafData.directTx.getOutput(0);
23875
+ if (leafData.directRefundTx) {
23876
+ const directRefundTxSighash = getSigHashFromTx(
23877
+ leafData.directRefundTx,
23878
+ 0,
23879
+ directTxOutput
23880
+ );
23881
+ const directUserSignature = await this.config.signer.signFrost({
23882
+ message: directRefundTxSighash,
23883
+ publicKey,
23884
+ keyDerivation: leafData.keyDerivation,
23885
+ selfCommitment: leafData.directSigningNonceCommitment,
23886
+ statechainCommitments: operatorSigningResult.directRefundTxSigningResult?.signingNonceCommitments,
23887
+ adaptorPubKey: directAdaptorPubKey,
23888
+ verifyingKey: operatorSigningResult.verifyingKey
23889
+ });
23890
+ directRefundAggregate = await this.config.signer.aggregateFrost({
23891
+ message: directRefundTxSighash,
23892
+ statechainSignatures: operatorSigningResult.directRefundTxSigningResult?.signatureShares,
23893
+ statechainPublicKeys: operatorSigningResult.directRefundTxSigningResult?.publicKeys,
23894
+ verifyingKey: operatorSigningResult.verifyingKey,
23895
+ statechainCommitments: operatorSigningResult.directRefundTxSigningResult?.signingNonceCommitments,
23896
+ selfCommitment: leafData.directSigningNonceCommitment,
23897
+ publicKey,
23898
+ selfSignature: directUserSignature,
23899
+ adaptorPubKey: directAdaptorPubKey
23900
+ });
23901
+ }
23902
+ if (leafData.directFromCpfpRefundTx) {
23903
+ const directFromCpfpRefundTxSighash = getSigHashFromTx(
23904
+ leafData.directFromCpfpRefundTx,
23905
+ 0,
23906
+ txOutput
23907
+ );
23908
+ const directFromCpfpUserSignature = await this.config.signer.signFrost({
23909
+ message: directFromCpfpRefundTxSighash,
23910
+ publicKey,
23911
+ keyDerivation: leafData.keyDerivation,
23912
+ selfCommitment: leafData.directFromCpfpRefundSigningNonceCommitment,
23913
+ statechainCommitments: operatorSigningResult.directFromCpfpRefundTxSigningResult?.signingNonceCommitments,
23914
+ adaptorPubKey: directFromCpfpAdaptorPubKey,
23915
+ verifyingKey: operatorSigningResult.verifyingKey
23916
+ });
23917
+ directFromCpfpRefundAggregate = await this.config.signer.aggregateFrost({
23918
+ message: directFromCpfpRefundTxSighash,
23919
+ statechainSignatures: operatorSigningResult.directFromCpfpRefundTxSigningResult?.signatureShares,
23920
+ statechainPublicKeys: operatorSigningResult.directFromCpfpRefundTxSigningResult?.publicKeys,
23921
+ verifyingKey: operatorSigningResult.verifyingKey,
23922
+ statechainCommitments: operatorSigningResult.directFromCpfpRefundTxSigningResult?.signingNonceCommitments,
23923
+ selfCommitment: leafData.directFromCpfpRefundSigningNonceCommitment,
23924
+ publicKey,
23925
+ selfSignature: directFromCpfpUserSignature,
23926
+ adaptorPubKey: directFromCpfpAdaptorPubKey
23927
+ });
23928
+ }
23929
+ }
23557
23930
  nodeSignatures.push({
23558
23931
  nodeId: operatorSigningResult.leafId,
23559
- refundTxSignature: refundAggregate,
23560
23932
  nodeTxSignature: new Uint8Array(),
23561
- // TODO: Add direct refund signature
23562
23933
  directNodeTxSignature: new Uint8Array(),
23563
- directRefundTxSignature: new Uint8Array(),
23564
- directFromCpfpRefundTxSignature: new Uint8Array()
23934
+ refundTxSignature: cpfpRefundAggregate,
23935
+ directRefundTxSignature: directRefundAggregate ?? new Uint8Array(),
23936
+ directFromCpfpRefundTxSignature: directFromCpfpRefundAggregate ?? new Uint8Array()
23565
23937
  });
23566
23938
  }
23567
23939
  return nodeSignatures;
23568
23940
  }
23569
- async prepareSendTransferKeyTweaks(transferID, receiverIdentityPubkey, leaves, refundSignatureMap) {
23941
+ async prepareSendTransferKeyTweaks(transferID, receiverIdentityPubkey, leaves, cpfpRefundSignatureMap, directRefundSignatureMap, directFromCpfpRefundSignatureMap) {
23570
23942
  const receiverEciesPubKey = ecies2.PublicKey.fromHex(
23571
23943
  (0, import_utils8.bytesToHex)(receiverIdentityPubkey)
23572
23944
  );
23573
23945
  const leavesTweaksMap = /* @__PURE__ */ new Map();
23574
23946
  for (const leaf of leaves) {
23575
- const refundSignature = refundSignatureMap.get(leaf.leaf.id);
23947
+ const cpfpRefundSignature = cpfpRefundSignatureMap.get(leaf.leaf.id);
23948
+ const directRefundSignature = directRefundSignatureMap.get(leaf.leaf.id);
23949
+ const directFromCpfpRefundSignature = directFromCpfpRefundSignatureMap.get(leaf.leaf.id);
23576
23950
  const leafTweaksMap = await this.prepareSingleSendTransferKeyTweak(
23577
23951
  transferID,
23578
23952
  leaf,
23579
23953
  receiverEciesPubKey,
23580
- refundSignature
23954
+ cpfpRefundSignature,
23955
+ directRefundSignature,
23956
+ directFromCpfpRefundSignature
23581
23957
  );
23582
23958
  for (const [identifier, leafTweak] of leafTweaksMap) {
23583
23959
  leavesTweaksMap.set(identifier, [
@@ -23588,7 +23964,7 @@ var BaseTransferService = class {
23588
23964
  }
23589
23965
  return leavesTweaksMap;
23590
23966
  }
23591
- async prepareSingleSendTransferKeyTweak(transferID, leaf, receiverEciesPubKey, refundSignature) {
23967
+ async prepareSingleSendTransferKeyTweak(transferID, leaf, receiverEciesPubKey, cpfpRefundSignature, directRefundSignature, directFromCpfpRefundSignature) {
23592
23968
  const signingOperators = this.config.getSigningOperators();
23593
23969
  const { shares, secretCipher } = await this.config.signer.subtractSplitAndEncrypt({
23594
23970
  first: leaf.keyDerivation,
@@ -23636,10 +24012,9 @@ var BaseTransferService = class {
23636
24012
  pubkeySharesTweak: Object.fromEntries(pubkeySharesTweak),
23637
24013
  secretCipher,
23638
24014
  signature,
23639
- refundSignature: refundSignature ?? new Uint8Array(),
23640
- // TODO: Add direct refund signature
23641
- directRefundSignature: new Uint8Array(),
23642
- directFromCpfpRefundSignature: new Uint8Array()
24015
+ refundSignature: cpfpRefundSignature ?? new Uint8Array(),
24016
+ directRefundSignature: directRefundSignature ?? new Uint8Array(),
24017
+ directFromCpfpRefundSignature: directFromCpfpRefundSignature ?? new Uint8Array()
23643
24018
  });
23644
24019
  }
23645
24020
  return leafTweaksMap;
@@ -23669,7 +24044,12 @@ var TransferService = class extends BaseTransferService {
23669
24044
  * Deprecated in v0.1.32
23670
24045
  */
23671
24046
  async sendTransfer(leaves, receiverIdentityPubkey) {
23672
- const { transfer, signatureMap } = await this.sendTransferSignRefund(
24047
+ const {
24048
+ transfer,
24049
+ signatureMap,
24050
+ directSignatureMap,
24051
+ directFromCpfpSignatureMap
24052
+ } = await this.sendTransferSignRefund(
23673
24053
  leaves,
23674
24054
  receiverIdentityPubkey,
23675
24055
  new Date(Date.now() + DEFAULT_EXPIRY_TIME)
@@ -23677,7 +24057,9 @@ var TransferService = class extends BaseTransferService {
23677
24057
  const transferWithTweakedKeys = await this.sendTransferTweakKey(
23678
24058
  transfer,
23679
24059
  leaves,
23680
- signatureMap
24060
+ signatureMap,
24061
+ directSignatureMap,
24062
+ directFromCpfpSignatureMap
23681
24063
  );
23682
24064
  return transferWithTweakedKeys;
23683
24065
  }
@@ -23781,7 +24163,13 @@ var TransferService = class extends BaseTransferService {
23781
24163
  return transferResp.transfers[0];
23782
24164
  }
23783
24165
  async sendTransferSignRefund(leaves, receiverIdentityPubkey, expiryTime) {
23784
- const { transfer, signatureMap, leafDataMap } = await this.sendTransferSignRefundInternal(
24166
+ const {
24167
+ transfer,
24168
+ signatureMap,
24169
+ directSignatureMap,
24170
+ directFromCpfpSignatureMap,
24171
+ leafDataMap
24172
+ } = await this.sendTransferSignRefundInternal(
23785
24173
  leaves,
23786
24174
  receiverIdentityPubkey,
23787
24175
  expiryTime,
@@ -23790,11 +24178,19 @@ var TransferService = class extends BaseTransferService {
23790
24178
  return {
23791
24179
  transfer,
23792
24180
  signatureMap,
24181
+ directSignatureMap,
24182
+ directFromCpfpSignatureMap,
23793
24183
  leafDataMap
23794
24184
  };
23795
24185
  }
23796
24186
  async startSwapSignRefund(leaves, receiverIdentityPubkey, expiryTime) {
23797
- const { transfer, signatureMap, leafDataMap } = await this.sendTransferSignRefundInternal(
24187
+ const {
24188
+ transfer,
24189
+ signatureMap,
24190
+ directSignatureMap,
24191
+ directFromCpfpSignatureMap,
24192
+ leafDataMap
24193
+ } = await this.sendTransferSignRefundInternal(
23798
24194
  leaves,
23799
24195
  receiverIdentityPubkey,
23800
24196
  expiryTime,
@@ -23803,31 +24199,45 @@ var TransferService = class extends BaseTransferService {
23803
24199
  return {
23804
24200
  transfer,
23805
24201
  signatureMap,
24202
+ directSignatureMap,
24203
+ directFromCpfpSignatureMap,
23806
24204
  leafDataMap
23807
24205
  };
23808
24206
  }
23809
- async counterSwapSignRefund(leaves, receiverIdentityPubkey, expiryTime, adaptorPubKey) {
24207
+ async counterSwapSignRefund(leaves, receiverIdentityPubkey, expiryTime, cpfpAdaptorPubKey, directAdaptorPubKey, directFromCpfpAdaptorPubKey) {
23810
24208
  return this.sendTransferSignRefundInternal(
23811
24209
  leaves,
23812
24210
  receiverIdentityPubkey,
23813
24211
  expiryTime,
23814
24212
  true,
23815
- adaptorPubKey
24213
+ cpfpAdaptorPubKey,
24214
+ directAdaptorPubKey,
24215
+ directFromCpfpAdaptorPubKey
23816
24216
  );
23817
24217
  }
23818
- async sendTransferSignRefundInternal(leaves, receiverIdentityPubkey, expiryTime, forSwap, adaptorPubKey) {
24218
+ async sendTransferSignRefundInternal(leaves, receiverIdentityPubkey, expiryTime, forSwap, cpfpAdaptorPubKey, directAdaptorPubKey, directFromCpfpAdaptorPubKey) {
23819
24219
  const transferId = (0, import_uuidv7.uuidv7)();
23820
24220
  const leafDataMap = /* @__PURE__ */ new Map();
23821
24221
  for (const leaf of leaves) {
23822
24222
  const signingNonceCommitment = await this.config.signer.getRandomSigningCommitment();
24223
+ const directSigningNonceCommitment = await this.config.signer.getRandomSigningCommitment();
24224
+ const directFromCpfpRefundSigningNonceCommitment = await this.config.signer.getRandomSigningCommitment();
23823
24225
  const tx = getTxFromRawTxBytes(leaf.leaf.nodeTx);
23824
24226
  const refundTx = getTxFromRawTxBytes(leaf.leaf.refundTx);
24227
+ const directTx = leaf.leaf.directTx.length > 0 ? getTxFromRawTxBytes(leaf.leaf.directTx) : void 0;
24228
+ const directRefundTx = leaf.leaf.directRefundTx.length > 0 ? getTxFromRawTxBytes(leaf.leaf.directRefundTx) : void 0;
24229
+ const directFromCpfpRefundTx = leaf.leaf.directFromCpfpRefundTx.length > 0 ? getTxFromRawTxBytes(leaf.leaf.directFromCpfpRefundTx) : void 0;
23825
24230
  leafDataMap.set(leaf.leaf.id, {
23826
24231
  keyDerivation: leaf.keyDerivation,
23827
24232
  receivingPubkey: receiverIdentityPubkey,
23828
24233
  signingNonceCommitment,
24234
+ directSigningNonceCommitment,
23829
24235
  tx,
24236
+ directTx,
23830
24237
  refundTx,
24238
+ directRefundTx,
24239
+ directFromCpfpRefundTx,
24240
+ directFromCpfpRefundSigningNonceCommitment,
23831
24241
  vout: leaf.leaf.vout
23832
24242
  });
23833
24243
  }
@@ -23840,8 +24250,8 @@ var TransferService = class extends BaseTransferService {
23840
24250
  );
23841
24251
  let response;
23842
24252
  try {
23843
- if (adaptorPubKey !== void 0) {
23844
- response = await sparkClient.counter_leaf_swap({
24253
+ if (cpfpAdaptorPubKey !== void 0 || directAdaptorPubKey !== void 0 || directFromCpfpAdaptorPubKey !== void 0) {
24254
+ response = await sparkClient.counter_leaf_swap_v2({
23845
24255
  transfer: {
23846
24256
  transferId,
23847
24257
  leavesToSend: signingJobs,
@@ -23850,10 +24260,12 @@ var TransferService = class extends BaseTransferService {
23850
24260
  expiryTime
23851
24261
  },
23852
24262
  swapId: (0, import_uuidv7.uuidv7)(),
23853
- adaptorPublicKey: adaptorPubKey || new Uint8Array()
24263
+ adaptorPublicKey: cpfpAdaptorPubKey,
24264
+ directAdaptorPublicKey: directAdaptorPubKey,
24265
+ directFromCpfpAdaptorPublicKey: directFromCpfpAdaptorPubKey
23854
24266
  });
23855
24267
  } else if (forSwap) {
23856
- response = await sparkClient.start_leaf_swap({
24268
+ response = await sparkClient.start_leaf_swap_v2({
23857
24269
  transferId,
23858
24270
  leavesToSend: signingJobs,
23859
24271
  ownerIdentityPublicKey: await this.config.signer.getIdentityPublicKey(),
@@ -23861,7 +24273,7 @@ var TransferService = class extends BaseTransferService {
23861
24273
  expiryTime
23862
24274
  });
23863
24275
  } else {
23864
- response = await sparkClient.start_transfer({
24276
+ response = await sparkClient.start_transfer_v2({
23865
24277
  transferId,
23866
24278
  leavesToSend: signingJobs,
23867
24279
  ownerIdentityPublicKey: await this.config.signer.getIdentityPublicKey(),
@@ -23878,15 +24290,29 @@ var TransferService = class extends BaseTransferService {
23878
24290
  const signatures = await this.signRefunds(
23879
24291
  leafDataMap,
23880
24292
  response.signingResults,
23881
- adaptorPubKey
24293
+ cpfpAdaptorPubKey,
24294
+ directAdaptorPubKey,
24295
+ directFromCpfpAdaptorPubKey
23882
24296
  );
23883
- const signatureMap = /* @__PURE__ */ new Map();
24297
+ const cpfpSignatureMap = /* @__PURE__ */ new Map();
24298
+ const directSignatureMap = /* @__PURE__ */ new Map();
24299
+ const directFromCpfpSignatureMap = /* @__PURE__ */ new Map();
23884
24300
  for (const signature of signatures) {
23885
- signatureMap.set(signature.nodeId, signature.refundTxSignature);
24301
+ cpfpSignatureMap.set(signature.nodeId, signature.refundTxSignature);
24302
+ directSignatureMap.set(
24303
+ signature.nodeId,
24304
+ signature.directRefundTxSignature
24305
+ );
24306
+ directFromCpfpSignatureMap.set(
24307
+ signature.nodeId,
24308
+ signature.directFromCpfpRefundTxSignature
24309
+ );
23886
24310
  }
23887
24311
  return {
23888
24312
  transfer: response.transfer,
23889
- signatureMap,
24313
+ signatureMap: cpfpSignatureMap,
24314
+ directSignatureMap,
24315
+ directFromCpfpSignatureMap,
23890
24316
  leafDataMap,
23891
24317
  signingResults: response.signingResults
23892
24318
  };
@@ -23899,38 +24325,68 @@ var TransferService = class extends BaseTransferService {
23899
24325
  throw new Error(`Leaf data not found for leaf ${leaf.leaf.id}`);
23900
24326
  }
23901
24327
  const nodeTx = getTxFromRawTxBytes(leaf.leaf.nodeTx);
23902
- const nodeOutPoint = {
24328
+ const cpfpNodeOutPoint = {
23903
24329
  txid: (0, import_utils8.hexToBytes)(getTxId(nodeTx)),
23904
24330
  index: 0
23905
24331
  };
24332
+ let directNodeTx;
24333
+ let directNodeOutPoint;
24334
+ if (leaf.leaf.directTx.length > 0) {
24335
+ directNodeTx = getTxFromRawTxBytes(leaf.leaf.directTx);
24336
+ directNodeOutPoint = {
24337
+ txid: (0, import_utils8.hexToBytes)(getTxId(directNodeTx)),
24338
+ index: 0
24339
+ };
24340
+ }
23906
24341
  const currRefundTx = getTxFromRawTxBytes(leaf.leaf.refundTx);
23907
- const nextSequence = isForClaim ? getTransactionSequence(currRefundTx.getInput(0).sequence) : getNextTransactionSequence(currRefundTx.getInput(0).sequence).nextSequence;
24342
+ const sequence = currRefundTx.getInput(0).sequence;
24343
+ if (!sequence) {
24344
+ throw new ValidationError("Invalid refund transaction", {
24345
+ field: "sequence",
24346
+ value: currRefundTx.getInput(0),
24347
+ expected: "Non-null sequence"
24348
+ });
24349
+ }
24350
+ const { nextSequence, nextDirectSequence } = isForClaim ? getTransactionSequence(sequence) : getNextTransactionSequence(sequence);
23908
24351
  const amountSats = currRefundTx.getOutput(0).amount;
23909
24352
  if (amountSats === void 0) {
23910
24353
  throw new Error("Amount not found in signRefunds");
23911
24354
  }
23912
- const refundTx = createRefundTx(
23913
- nextSequence,
23914
- nodeOutPoint,
24355
+ const { cpfpRefundTx, directRefundTx, directFromCpfpRefundTx } = createRefundTxs({
24356
+ sequence: nextSequence,
24357
+ directSequence: nextDirectSequence,
24358
+ input: cpfpNodeOutPoint,
24359
+ directInput: directNodeOutPoint,
23915
24360
  amountSats,
23916
- refundSigningData.receivingPubkey,
23917
- this.config.getNetwork()
24361
+ receivingPubkey: refundSigningData.receivingPubkey,
24362
+ network: this.config.getNetwork()
24363
+ });
24364
+ refundSigningData.refundTx = cpfpRefundTx;
24365
+ refundSigningData.directRefundTx = directRefundTx;
24366
+ refundSigningData.directFromCpfpRefundTx = directFromCpfpRefundTx;
24367
+ const cpfpRefundNonceCommitmentProto = refundSigningData.signingNonceCommitment;
24368
+ const directRefundNonceCommitmentProto = refundSigningData.directSigningNonceCommitment;
24369
+ const directFromCpfpRefundNonceCommitmentProto = refundSigningData.directFromCpfpRefundSigningNonceCommitment;
24370
+ const signingPublicKey = await this.config.signer.getPublicKeyFromDerivation(
24371
+ refundSigningData.keyDerivation
23918
24372
  );
23919
- refundSigningData.refundTx = refundTx;
23920
- const refundNonceCommitmentProto = refundSigningData.signingNonceCommitment;
23921
24373
  signingJobs.push({
23922
24374
  leafId: leaf.leaf.id,
23923
24375
  refundTxSigningJob: {
23924
- signingPublicKey: await this.config.signer.getPublicKeyFromDerivation(
23925
- refundSigningData.keyDerivation
23926
- ),
23927
- rawTx: refundTx.toBytes(),
23928
- signingNonceCommitment: refundNonceCommitmentProto.commitment
24376
+ signingPublicKey,
24377
+ rawTx: cpfpRefundTx.toBytes(),
24378
+ signingNonceCommitment: cpfpRefundNonceCommitmentProto.commitment
23929
24379
  },
23930
- // TODO: Add direct refund signature
23931
- directRefundTxSigningJob: void 0,
23932
- // TODO: Add direct refund signature
23933
- directFromCpfpRefundTxSigningJob: void 0
24380
+ directRefundTxSigningJob: directRefundTx ? {
24381
+ signingPublicKey,
24382
+ rawTx: directRefundTx.toBytes(),
24383
+ signingNonceCommitment: directRefundNonceCommitmentProto.commitment
24384
+ } : void 0,
24385
+ directFromCpfpRefundTxSigningJob: directFromCpfpRefundTx ? {
24386
+ signingPublicKey,
24387
+ rawTx: directFromCpfpRefundTx.toBytes(),
24388
+ signingNonceCommitment: directFromCpfpRefundNonceCommitmentProto.commitment
24389
+ } : void 0
23934
24390
  });
23935
24391
  }
23936
24392
  return signingJobs;
@@ -24051,13 +24507,17 @@ var TransferService = class extends BaseTransferService {
24051
24507
  const leafDataMap = /* @__PURE__ */ new Map();
24052
24508
  for (const leafKey of leafKeys) {
24053
24509
  const tx = getTxFromRawTxBytes(leafKey.leaf.nodeTx);
24510
+ const directTx = leafKey.leaf.directTx.length > 0 ? getTxFromRawTxBytes(leafKey.leaf.directTx) : void 0;
24054
24511
  leafDataMap.set(leafKey.leaf.id, {
24055
24512
  keyDerivation: leafKey.newKeyDerivation,
24056
24513
  receivingPubkey: await this.config.signer.getPublicKeyFromDerivation(
24057
24514
  leafKey.newKeyDerivation
24058
24515
  ),
24059
24516
  signingNonceCommitment: await this.config.signer.getRandomSigningCommitment(),
24517
+ directSigningNonceCommitment: await this.config.signer.getRandomSigningCommitment(),
24518
+ directFromCpfpRefundSigningNonceCommitment: await this.config.signer.getRandomSigningCommitment(),
24060
24519
  tx,
24520
+ directTx,
24061
24521
  vout: leafKey.leaf.vout
24062
24522
  });
24063
24523
  }
@@ -24079,7 +24539,7 @@ var TransferService = class extends BaseTransferService {
24079
24539
  }
24080
24540
  }
24081
24541
  try {
24082
- resp = await sparkClient.claim_transfer_sign_refunds({
24542
+ resp = await sparkClient.claim_transfer_sign_refunds_v2({
24083
24543
  transferId: transfer.id,
24084
24544
  ownerIdentityPublicKey: await this.config.signer.getIdentityPublicKey(),
24085
24545
  signingJobs
@@ -24094,7 +24554,7 @@ var TransferService = class extends BaseTransferService {
24094
24554
  this.config.getCoordinatorAddress()
24095
24555
  );
24096
24556
  try {
24097
- return await sparkClient.finalize_node_signatures({
24557
+ return await sparkClient.finalize_node_signatures_v2({
24098
24558
  intent: 1 /* TRANSFER */,
24099
24559
  nodeSignatures
24100
24560
  });
@@ -24133,109 +24593,134 @@ var TransferService = class extends BaseTransferService {
24133
24593
  throw new Error(`Error querying pending transfers by sender: ${error}`);
24134
24594
  }
24135
24595
  }
24136
- async refreshTimelockNodes(nodes, parentNode) {
24137
- if (nodes.length === 0) {
24138
- throw Error("no nodes to refresh");
24139
- }
24596
+ async refreshTimelockNodesInternal(node, parentNode, useTestUnilateralSequence) {
24140
24597
  const signingJobs = [];
24141
- const newNodeTxs = [];
24142
- for (let i = 0; i < nodes.length; i++) {
24143
- const node = nodes[i];
24144
- if (!node) {
24145
- throw Error("could not get node");
24146
- }
24147
- const nodeTx = getTxFromRawTxBytes(node?.nodeTx);
24148
- const input = nodeTx.getInput(0);
24149
- if (!input) {
24150
- throw Error("Could not fetch tx input");
24151
- }
24152
- const newTx = new import_btc_signer2.Transaction({ version: 3, allowUnknownOutputs: true });
24153
- const originalOutput = nodeTx.getOutput(0);
24154
- if (!originalOutput) {
24155
- throw Error("Could not get original output");
24156
- }
24157
- newTx.addOutput({
24158
- script: originalOutput.script,
24159
- amount: originalOutput.amount
24160
- });
24161
- for (let j = 1; j < nodeTx.outputsLength; j++) {
24162
- const additionalOutput = nodeTx.getOutput(j);
24163
- if (additionalOutput) {
24164
- newTx.addOutput(additionalOutput);
24165
- }
24166
- }
24167
- if (i === 0) {
24168
- const currSequence = input.sequence;
24169
- newTx.addInput({
24170
- ...input,
24171
- sequence: getNextTransactionSequence(currSequence).nextSequence
24172
- });
24173
- } else {
24174
- newTx.addInput({
24175
- ...input,
24176
- sequence: initialSequence(),
24177
- txid: newNodeTxs[i - 1]?.id
24178
- });
24179
- }
24180
- signingJobs.push({
24181
- signingPublicKey: await this.config.signer.getPublicKeyFromDerivation({
24182
- type: "leaf" /* LEAF */,
24183
- path: node.id
24184
- }),
24185
- rawTx: newTx.toBytes(),
24186
- signingNonceCommitment: await this.config.signer.getRandomSigningCommitment()
24598
+ const parentNodeTx = getTxFromRawTxBytes(parentNode.nodeTx);
24599
+ const parentNodeOutput = parentNodeTx.getOutput(0);
24600
+ if (!parentNodeOutput) {
24601
+ throw Error("Could not get parent node output");
24602
+ }
24603
+ const nodeTx = getTxFromRawTxBytes(node.nodeTx);
24604
+ const nodeInput = nodeTx.getInput(0);
24605
+ const nodeOutput = nodeTx.getOutput(0);
24606
+ if (!nodeOutput) {
24607
+ throw Error("Could not get node output");
24608
+ }
24609
+ let directNodeTx;
24610
+ let directNodeInput;
24611
+ if (node.directTx.length > 0) {
24612
+ directNodeTx = getTxFromRawTxBytes(node.directTx);
24613
+ directNodeInput = directNodeTx.getInput(0);
24614
+ }
24615
+ const currSequence = nodeInput.sequence;
24616
+ if (!currSequence) {
24617
+ throw new ValidationError("Invalid node transaction", {
24618
+ field: "sequence",
24619
+ value: nodeInput,
24620
+ expected: "Non-null sequence"
24187
24621
  });
24188
- newNodeTxs[i] = newTx;
24189
24622
  }
24190
- const leaf = nodes[nodes.length - 1];
24191
- if (!leaf?.refundTx) {
24192
- throw Error("leaf does not have refund tx");
24623
+ let { nextSequence, nextDirectSequence } = getNextTransactionSequence(
24624
+ currSequence,
24625
+ true
24626
+ );
24627
+ const output = {
24628
+ script: parentNodeOutput.script,
24629
+ amount: parentNodeOutput.amount
24630
+ };
24631
+ const newNodeInput = {
24632
+ txid: nodeInput.txid,
24633
+ index: nodeInput.index,
24634
+ sequence: useTestUnilateralSequence ? TEST_UNILATERAL_SEQUENCE : nextSequence
24635
+ };
24636
+ const newDirectInput = directNodeTx && directNodeInput ? {
24637
+ txid: directNodeInput.txid,
24638
+ index: directNodeInput.index,
24639
+ sequence: useTestUnilateralSequence ? TEST_UNILATERAL_DIRECT_SEQUENCE : nextDirectSequence
24640
+ } : void 0;
24641
+ const { cpfpNodeTx, directNodeTx: newDirectNodeTx } = createNodeTxs(
24642
+ output,
24643
+ newNodeInput,
24644
+ newDirectInput
24645
+ );
24646
+ const newCpfpNodeOutput = cpfpNodeTx.getOutput(0);
24647
+ if (!newCpfpNodeOutput) {
24648
+ throw Error("Could not get new cpfp node output");
24193
24649
  }
24194
- const refundTx = getTxFromRawTxBytes(leaf?.refundTx);
24195
- const newRefundTx = new import_btc_signer2.Transaction({
24196
- version: 3,
24197
- allowUnknownOutputs: true
24650
+ const newDirectNodeOutput = newDirectNodeTx?.getOutput(0);
24651
+ const signingPublicKey = await this.config.signer.getPublicKeyFromDerivation({
24652
+ type: "leaf" /* LEAF */,
24653
+ path: node.id
24198
24654
  });
24199
- const originalRefundOutput = refundTx.getOutput(0);
24200
- if (!originalRefundOutput) {
24201
- throw Error("Could not get original refund output");
24202
- }
24203
- newRefundTx.addOutput({
24204
- script: originalRefundOutput.script,
24205
- amount: originalRefundOutput.amount
24655
+ signingJobs.push({
24656
+ signingPublicKey,
24657
+ rawTx: cpfpNodeTx.toBytes(),
24658
+ signingNonceCommitment: await this.config.signer.getRandomSigningCommitment(),
24659
+ type: "node",
24660
+ parentTxOut: parentNodeOutput
24206
24661
  });
24207
- for (let j = 1; j < refundTx.outputsLength; j++) {
24208
- const additionalOutput = refundTx.getOutput(j);
24209
- if (additionalOutput) {
24210
- newRefundTx.addOutput(additionalOutput);
24211
- }
24212
- }
24213
- const refundTxInput = refundTx.getInput(0);
24214
- if (!refundTxInput) {
24215
- throw Error("refund tx doesn't have input");
24662
+ if (newDirectNodeTx) {
24663
+ signingJobs.push({
24664
+ signingPublicKey,
24665
+ rawTx: newDirectNodeTx.toBytes(),
24666
+ signingNonceCommitment: await this.config.signer.getRandomSigningCommitment(),
24667
+ type: "directNode",
24668
+ parentTxOut: parentNodeOutput
24669
+ });
24216
24670
  }
24217
- if (!newNodeTxs[newNodeTxs.length - 1]) {
24218
- throw Error("Could not get last node tx");
24671
+ const newCpfpRefundOutPoint = {
24672
+ txid: (0, import_utils8.hexToBytes)(getTxId(cpfpNodeTx)),
24673
+ index: 0
24674
+ };
24675
+ let newDirectRefundOutPoint;
24676
+ if (newDirectNodeTx) {
24677
+ newDirectRefundOutPoint = {
24678
+ txid: (0, import_utils8.hexToBytes)(getTxId(newDirectNodeTx)),
24679
+ index: 0
24680
+ };
24219
24681
  }
24220
- newRefundTx.addInput({
24221
- ...refundTxInput,
24222
- sequence: initialSequence(),
24223
- txid: getTxId(newNodeTxs[newNodeTxs.length - 1])
24224
- });
24225
- const refundSigningJob = {
24226
- signingPublicKey: await this.config.signer.getPublicKeyFromDerivation({
24682
+ const { cpfpRefundTx, directRefundTx, directFromCpfpRefundTx } = createRefundTxs({
24683
+ sequence: INITIAL_SEQUENCE,
24684
+ directSequence: INITIAL_DIRECT_SEQUENCE,
24685
+ input: newCpfpRefundOutPoint,
24686
+ directInput: newDirectRefundOutPoint,
24687
+ amountSats: nodeOutput.amount,
24688
+ receivingPubkey: await this.config.signer.getPublicKeyFromDerivation({
24227
24689
  type: "leaf" /* LEAF */,
24228
- path: leaf.id
24690
+ path: node.id
24229
24691
  }),
24230
- rawTx: newRefundTx.toBytes(),
24231
- signingNonceCommitment: await this.config.signer.getRandomSigningCommitment()
24232
- };
24233
- signingJobs.push(refundSigningJob);
24692
+ network: this.config.getNetwork()
24693
+ });
24694
+ signingJobs.push({
24695
+ signingPublicKey,
24696
+ rawTx: cpfpRefundTx.toBytes(),
24697
+ signingNonceCommitment: await this.config.signer.getRandomSigningCommitment(),
24698
+ type: "cpfp",
24699
+ parentTxOut: newCpfpNodeOutput
24700
+ });
24701
+ if (directRefundTx && newDirectNodeOutput) {
24702
+ signingJobs.push({
24703
+ signingPublicKey,
24704
+ rawTx: directRefundTx.toBytes(),
24705
+ signingNonceCommitment: await this.config.signer.getRandomSigningCommitment(),
24706
+ type: "direct",
24707
+ parentTxOut: newDirectNodeOutput
24708
+ });
24709
+ }
24710
+ if (directFromCpfpRefundTx && newCpfpNodeOutput) {
24711
+ signingJobs.push({
24712
+ signingPublicKey,
24713
+ rawTx: directFromCpfpRefundTx.toBytes(),
24714
+ signingNonceCommitment: await this.config.signer.getRandomSigningCommitment(),
24715
+ type: "directFromCpfp",
24716
+ parentTxOut: newCpfpNodeOutput
24717
+ });
24718
+ }
24234
24719
  const sparkClient = await this.connectionManager.createSparkClient(
24235
24720
  this.config.getCoordinatorAddress()
24236
24721
  );
24237
- const response = await sparkClient.refresh_timelock({
24238
- leafId: leaf.id,
24722
+ const response = await sparkClient.refresh_timelock_v2({
24723
+ leafId: node.id,
24239
24724
  ownerIdentityPublicKey: await this.config.signer.getIdentityPublicKey(),
24240
24725
  signingJobs: signingJobs.map(getSigningJobProto)
24241
24726
  });
@@ -24245,45 +24730,27 @@ var TransferService = class extends BaseTransferService {
24245
24730
  );
24246
24731
  }
24247
24732
  let nodeSignatures = [];
24248
- let leafSignature;
24249
- let refundSignature;
24250
- let leafNodeId;
24251
- for (let i = 0; i < response.signingResults.length; i++) {
24252
- const signingResult = response.signingResults[i];
24733
+ let leafCpfpSignature;
24734
+ let leafDirectSignature;
24735
+ let cpfpRefundSignature;
24736
+ let directRefundSignature;
24737
+ let directFromCpfpRefundSignature;
24738
+ for (const [i, signingResult] of response.signingResults.entries()) {
24253
24739
  const signingJob = signingJobs[i];
24254
24740
  if (!signingJob || !signingResult) {
24255
24741
  throw Error("Signing job does not exist");
24256
24742
  }
24257
- if (!signingJob.signingNonceCommitment) {
24258
- throw Error("nonce commitment does not exist");
24259
- }
24260
24743
  const rawTx = getTxFromRawTxBytes(signingJob.rawTx);
24261
- let parentTx;
24262
- let nodeId;
24263
- let vout;
24264
- if (i === nodes.length) {
24265
- nodeId = nodes[i - 1]?.id;
24266
- parentTx = newNodeTxs[i - 1];
24267
- vout = 0;
24268
- } else if (i === 0) {
24269
- nodeId = nodes[i]?.id;
24270
- parentTx = getTxFromRawTxBytes(parentNode.nodeTx);
24271
- vout = nodes[i]?.vout;
24272
- } else {
24273
- nodeId = nodes[i]?.id;
24274
- parentTx = newNodeTxs[i - 1];
24275
- vout = nodes[i]?.vout;
24744
+ const txOut = signingJob.parentTxOut;
24745
+ if (!txOut) {
24746
+ throw Error("Could not get tx out");
24276
24747
  }
24277
- if (!parentTx || !nodeId || vout === void 0) {
24278
- throw Error("Could not parse signing results");
24279
- }
24280
- const txOut = parentTx.getOutput(vout);
24281
24748
  const rawTxSighash = getSigHashFromTx(rawTx, 0, txOut);
24282
24749
  const userSignature = await this.config.signer.signFrost({
24283
24750
  message: rawTxSighash,
24284
24751
  keyDerivation: {
24285
24752
  type: "leaf" /* LEAF */,
24286
- path: nodeId
24753
+ path: node.id
24287
24754
  },
24288
24755
  publicKey: signingJob.signingPublicKey,
24289
24756
  verifyingKey: signingResult.verifyingKey,
@@ -24302,41 +24769,35 @@ var TransferService = class extends BaseTransferService {
24302
24769
  selfSignature: userSignature,
24303
24770
  adaptorPubKey: new Uint8Array()
24304
24771
  });
24305
- if (i !== nodes.length && i !== nodes.length - 1) {
24306
- nodeSignatures.push({
24307
- nodeId,
24308
- nodeTxSignature: signature,
24309
- refundTxSignature: new Uint8Array(),
24310
- // TODO: Add direct refund signature
24311
- directNodeTxSignature: new Uint8Array(),
24312
- directRefundTxSignature: new Uint8Array(),
24313
- directFromCpfpRefundTxSignature: new Uint8Array()
24314
- });
24315
- } else if (i === nodes.length) {
24316
- refundSignature = signature;
24317
- } else if (i === nodes.length - 1) {
24318
- leafNodeId = nodeId;
24319
- leafSignature = signature;
24772
+ if (signingJob.type === "node") {
24773
+ leafCpfpSignature = signature;
24774
+ } else if (signingJob.type === "directNode") {
24775
+ leafDirectSignature = signature;
24776
+ } else if (signingJob.type === "cpfp") {
24777
+ cpfpRefundSignature = signature;
24778
+ } else if (signingJob.type === "direct") {
24779
+ directRefundSignature = signature;
24780
+ } else if (signingJob.type === "directFromCpfp") {
24781
+ directFromCpfpRefundSignature = signature;
24320
24782
  }
24321
24783
  }
24322
- if (!leafSignature || !refundSignature || !leafNodeId) {
24323
- throw Error("leaf or refund signature does not exist");
24324
- }
24325
24784
  nodeSignatures.push({
24326
- nodeId: leafNodeId,
24327
- nodeTxSignature: leafSignature,
24328
- refundTxSignature: refundSignature,
24329
- // TODO: Add direct refund signature
24330
- directNodeTxSignature: new Uint8Array(),
24331
- directRefundTxSignature: new Uint8Array(),
24332
- directFromCpfpRefundTxSignature: new Uint8Array()
24785
+ nodeId: node.id,
24786
+ nodeTxSignature: leafCpfpSignature || new Uint8Array(),
24787
+ directNodeTxSignature: leafDirectSignature || new Uint8Array(),
24788
+ refundTxSignature: cpfpRefundSignature || new Uint8Array(),
24789
+ directRefundTxSignature: directRefundSignature || new Uint8Array(),
24790
+ directFromCpfpRefundTxSignature: directFromCpfpRefundSignature || new Uint8Array()
24333
24791
  });
24334
- const result = await sparkClient.finalize_node_signatures({
24792
+ const result = await sparkClient.finalize_node_signatures_v2({
24335
24793
  intent: 3 /* REFRESH */,
24336
24794
  nodeSignatures
24337
24795
  });
24338
24796
  return result;
24339
24797
  }
24798
+ async refreshTimelockNodes(node, parentNode) {
24799
+ return await this.refreshTimelockNodesInternal(node, parentNode);
24800
+ }
24340
24801
  async extendTimelock(node) {
24341
24802
  const nodeTx = getTxFromRawTxBytes(node.nodeTx);
24342
24803
  const refundTx = getTxFromRawTxBytes(node.refundTx);
@@ -24345,7 +24806,10 @@ var TransferService = class extends BaseTransferService {
24345
24806
  txid: (0, import_utils8.hexToBytes)(getTxId(nodeTx)),
24346
24807
  index: 0
24347
24808
  };
24348
- const { nextSequence: newNodeSequence } = getNextTransactionSequence(refundSequence);
24809
+ const {
24810
+ nextSequence: newNodeSequence,
24811
+ nextDirectSequence: newDirectNodeSequence
24812
+ } = getNextTransactionSequence(refundSequence);
24349
24813
  const newNodeTx = new import_btc_signer2.Transaction({
24350
24814
  version: 3,
24351
24815
  allowUnknownOutputs: true
@@ -24358,81 +24822,122 @@ var TransferService = class extends BaseTransferService {
24358
24822
  newNodeTx.addOutput({
24359
24823
  script: originalOutput.script,
24360
24824
  amount: originalOutput.amount
24361
- // feeReducedAmount,
24362
24825
  });
24363
24826
  newNodeTx.addOutput(getEphemeralAnchorOutput());
24364
- const newRefundOutPoint = {
24827
+ let newDirectNodeTx;
24828
+ if (node.directTx.length > 0) {
24829
+ newDirectNodeTx = new import_btc_signer2.Transaction({
24830
+ version: 3,
24831
+ allowUnknownOutputs: true
24832
+ });
24833
+ newDirectNodeTx.addInput({
24834
+ ...newNodeOutPoint,
24835
+ sequence: newDirectNodeSequence
24836
+ });
24837
+ newDirectNodeTx.addOutput({
24838
+ script: originalOutput.script,
24839
+ amount: maybeApplyFee(originalOutput.amount)
24840
+ });
24841
+ }
24842
+ const newCpfpRefundOutPoint = {
24365
24843
  txid: (0, import_utils8.hexToBytes)(getTxId(newNodeTx)),
24366
24844
  index: 0
24367
24845
  };
24846
+ let newDirectRefundOutPoint;
24847
+ if (newDirectNodeTx) {
24848
+ newDirectRefundOutPoint = {
24849
+ txid: (0, import_utils8.hexToBytes)(getTxId(newDirectNodeTx)),
24850
+ index: 0
24851
+ };
24852
+ }
24368
24853
  const amountSats = refundTx.getOutput(0).amount;
24369
24854
  if (amountSats === void 0) {
24370
24855
  throw new Error("Amount not found in extendTimelock");
24371
24856
  }
24372
- const signingPubKey = await this.config.signer.getPublicKeyFromDerivation({
24857
+ const signingPublicKey = await this.config.signer.getPublicKeyFromDerivation({
24373
24858
  type: "leaf" /* LEAF */,
24374
24859
  path: node.id
24375
24860
  });
24376
- const newRefundTx = createRefundTx(
24377
- initialSequence(),
24378
- newRefundOutPoint,
24861
+ const {
24862
+ cpfpRefundTx: newCpfpRefundTx,
24863
+ directRefundTx: newDirectRefundTx,
24864
+ directFromCpfpRefundTx: newDirectFromCpfpRefundTx
24865
+ } = createRefundTxs({
24866
+ sequence: INITIAL_SEQUENCE,
24867
+ directSequence: INITIAL_DIRECT_SEQUENCE,
24868
+ input: newCpfpRefundOutPoint,
24869
+ directInput: newDirectRefundOutPoint,
24379
24870
  amountSats,
24380
- // feeReducedRefundAmount,
24381
- signingPubKey,
24382
- this.config.getNetwork()
24383
- );
24871
+ receivingPubkey: signingPublicKey,
24872
+ network: this.config.getNetwork()
24873
+ });
24874
+ if (!newCpfpRefundTx) {
24875
+ throw new ValidationError(
24876
+ "Failed to create refund transactions in extendTimelock"
24877
+ );
24878
+ }
24384
24879
  const nodeSighash = getSigHashFromTx(newNodeTx, 0, nodeTx.getOutput(0));
24385
- const refundSighash = getSigHashFromTx(
24386
- newRefundTx,
24880
+ const directNodeSighash = newDirectNodeTx ? getSigHashFromTx(newDirectNodeTx, 0, nodeTx.getOutput(0)) : void 0;
24881
+ const cpfpRefundSighash = getSigHashFromTx(
24882
+ newCpfpRefundTx,
24387
24883
  0,
24388
24884
  newNodeTx.getOutput(0)
24389
24885
  );
24886
+ const directRefundSighash = newDirectNodeTx && newDirectRefundTx ? getSigHashFromTx(newDirectRefundTx, 0, newDirectNodeTx.getOutput(0)) : void 0;
24887
+ const directFromCpfpRefundSighash = newDirectFromCpfpRefundTx ? getSigHashFromTx(newDirectFromCpfpRefundTx, 0, newNodeTx.getOutput(0)) : void 0;
24390
24888
  const newNodeSigningJob = {
24391
- signingPublicKey: signingPubKey,
24889
+ signingPublicKey,
24392
24890
  rawTx: newNodeTx.toBytes(),
24393
24891
  signingNonceCommitment: await this.config.signer.getRandomSigningCommitment()
24394
24892
  };
24395
- const newRefundSigningJob = {
24396
- signingPublicKey: signingPubKey,
24397
- rawTx: newRefundTx.toBytes(),
24893
+ const newDirectNodeSigningJob = newDirectNodeTx ? {
24894
+ signingPublicKey,
24895
+ rawTx: newDirectNodeTx.toBytes(),
24896
+ signingNonceCommitment: await this.config.signer.getRandomSigningCommitment()
24897
+ } : void 0;
24898
+ const newCpfpRefundSigningJob = {
24899
+ signingPublicKey,
24900
+ rawTx: newCpfpRefundTx.toBytes(),
24398
24901
  signingNonceCommitment: await this.config.signer.getRandomSigningCommitment()
24399
24902
  };
24903
+ const newDirectRefundSigningJob = newDirectRefundTx ? {
24904
+ signingPublicKey,
24905
+ rawTx: newDirectRefundTx.toBytes(),
24906
+ signingNonceCommitment: await this.config.signer.getRandomSigningCommitment()
24907
+ } : void 0;
24908
+ const newDirectFromCpfpRefundSigningJob = newDirectFromCpfpRefundTx ? {
24909
+ signingPublicKey,
24910
+ rawTx: newDirectFromCpfpRefundTx.toBytes(),
24911
+ signingNonceCommitment: await this.config.signer.getRandomSigningCommitment()
24912
+ } : void 0;
24400
24913
  const sparkClient = await this.connectionManager.createSparkClient(
24401
24914
  this.config.getCoordinatorAddress()
24402
24915
  );
24403
- const response = await sparkClient.extend_leaf({
24916
+ const response = await sparkClient.extend_leaf_v2({
24404
24917
  leafId: node.id,
24405
24918
  ownerIdentityPublicKey: await this.config.signer.getIdentityPublicKey(),
24406
24919
  nodeTxSigningJob: getSigningJobProto(newNodeSigningJob),
24407
- refundTxSigningJob: getSigningJobProto(newRefundSigningJob)
24920
+ directNodeTxSigningJob: newDirectNodeSigningJob ? getSigningJobProto(newDirectNodeSigningJob) : void 0,
24921
+ refundTxSigningJob: getSigningJobProto(newCpfpRefundSigningJob),
24922
+ directRefundTxSigningJob: newDirectRefundSigningJob ? getSigningJobProto(newDirectRefundSigningJob) : void 0,
24923
+ directFromCpfpRefundTxSigningJob: newDirectFromCpfpRefundSigningJob ? getSigningJobProto(newDirectFromCpfpRefundSigningJob) : void 0
24408
24924
  });
24409
24925
  if (!response.nodeTxSigningResult || !response.refundTxSigningResult) {
24410
24926
  throw new Error("Signing result does not exist");
24411
24927
  }
24928
+ const keyDerivation = {
24929
+ type: "leaf" /* LEAF */,
24930
+ path: node.id
24931
+ };
24412
24932
  const nodeUserSig = await this.config.signer.signFrost({
24413
24933
  message: nodeSighash,
24414
- keyDerivation: {
24415
- type: "leaf" /* LEAF */,
24416
- path: node.id
24417
- },
24418
- publicKey: signingPubKey,
24934
+ keyDerivation,
24935
+ publicKey: signingPublicKey,
24419
24936
  verifyingKey: response.nodeTxSigningResult.verifyingKey,
24420
24937
  selfCommitment: newNodeSigningJob.signingNonceCommitment,
24421
24938
  statechainCommitments: response.nodeTxSigningResult.signingResult?.signingNonceCommitments,
24422
24939
  adaptorPubKey: new Uint8Array()
24423
24940
  });
24424
- const refundUserSig = await this.config.signer.signFrost({
24425
- message: refundSighash,
24426
- keyDerivation: {
24427
- type: "leaf" /* LEAF */,
24428
- path: node.id
24429
- },
24430
- publicKey: signingPubKey,
24431
- verifyingKey: response.refundTxSigningResult.verifyingKey,
24432
- selfCommitment: newRefundSigningJob.signingNonceCommitment,
24433
- statechainCommitments: response.refundTxSigningResult.signingResult?.signingNonceCommitments,
24434
- adaptorPubKey: new Uint8Array()
24435
- });
24436
24941
  const nodeSig = await this.config.signer.aggregateFrost({
24437
24942
  message: nodeSighash,
24438
24943
  statechainSignatures: response.nodeTxSigningResult.signingResult?.signatureShares,
@@ -24440,122 +24945,253 @@ var TransferService = class extends BaseTransferService {
24440
24945
  verifyingKey: response.nodeTxSigningResult.verifyingKey,
24441
24946
  statechainCommitments: response.nodeTxSigningResult.signingResult?.signingNonceCommitments,
24442
24947
  selfCommitment: newNodeSigningJob.signingNonceCommitment,
24443
- publicKey: signingPubKey,
24948
+ publicKey: signingPublicKey,
24444
24949
  selfSignature: nodeUserSig,
24445
24950
  adaptorPubKey: new Uint8Array()
24446
24951
  });
24447
- const refundSig = await this.config.signer.aggregateFrost({
24448
- message: refundSighash,
24952
+ let directNodeSig;
24953
+ if (directNodeSighash && newDirectNodeSigningJob && response.directNodeTxSigningResult) {
24954
+ const directNodeUserSig = await this.config.signer.signFrost({
24955
+ message: directNodeSighash,
24956
+ keyDerivation,
24957
+ publicKey: signingPublicKey,
24958
+ verifyingKey: response.directNodeTxSigningResult.verifyingKey,
24959
+ selfCommitment: newDirectNodeSigningJob.signingNonceCommitment,
24960
+ statechainCommitments: response.directNodeTxSigningResult.signingResult?.signingNonceCommitments,
24961
+ adaptorPubKey: new Uint8Array()
24962
+ });
24963
+ directNodeSig = await this.config.signer.aggregateFrost({
24964
+ message: directNodeSighash,
24965
+ statechainSignatures: response.directNodeTxSigningResult.signingResult?.signatureShares,
24966
+ statechainPublicKeys: response.directNodeTxSigningResult.signingResult?.publicKeys,
24967
+ verifyingKey: response.directNodeTxSigningResult.verifyingKey,
24968
+ statechainCommitments: response.directNodeTxSigningResult.signingResult?.signingNonceCommitments,
24969
+ selfCommitment: newDirectNodeSigningJob.signingNonceCommitment,
24970
+ publicKey: signingPublicKey,
24971
+ selfSignature: directNodeUserSig,
24972
+ adaptorPubKey: new Uint8Array()
24973
+ });
24974
+ }
24975
+ const cpfpRefundUserSig = await this.config.signer.signFrost({
24976
+ message: cpfpRefundSighash,
24977
+ keyDerivation,
24978
+ publicKey: signingPublicKey,
24979
+ verifyingKey: response.refundTxSigningResult.verifyingKey,
24980
+ selfCommitment: newCpfpRefundSigningJob.signingNonceCommitment,
24981
+ statechainCommitments: response.refundTxSigningResult.signingResult?.signingNonceCommitments,
24982
+ adaptorPubKey: new Uint8Array()
24983
+ });
24984
+ const cpfpRefundSig = await this.config.signer.aggregateFrost({
24985
+ message: cpfpRefundSighash,
24449
24986
  statechainSignatures: response.refundTxSigningResult.signingResult?.signatureShares,
24450
24987
  statechainPublicKeys: response.refundTxSigningResult.signingResult?.publicKeys,
24451
24988
  verifyingKey: response.refundTxSigningResult.verifyingKey,
24452
24989
  statechainCommitments: response.refundTxSigningResult.signingResult?.signingNonceCommitments,
24453
- selfCommitment: newRefundSigningJob.signingNonceCommitment,
24454
- publicKey: signingPubKey,
24455
- selfSignature: refundUserSig,
24990
+ selfCommitment: newCpfpRefundSigningJob.signingNonceCommitment,
24991
+ publicKey: signingPublicKey,
24992
+ selfSignature: cpfpRefundUserSig,
24456
24993
  adaptorPubKey: new Uint8Array()
24457
24994
  });
24458
- return await sparkClient.finalize_node_signatures({
24459
- intent: 4 /* EXTEND */,
24995
+ let directRefundSig;
24996
+ if (directRefundSighash && newDirectRefundSigningJob && response.directRefundTxSigningResult) {
24997
+ const directRefundUserSig = await this.config.signer.signFrost({
24998
+ message: directRefundSighash,
24999
+ keyDerivation,
25000
+ publicKey: signingPublicKey,
25001
+ verifyingKey: response.directRefundTxSigningResult.verifyingKey,
25002
+ selfCommitment: newDirectRefundSigningJob.signingNonceCommitment,
25003
+ statechainCommitments: response.directRefundTxSigningResult.signingResult?.signingNonceCommitments,
25004
+ adaptorPubKey: new Uint8Array()
25005
+ });
25006
+ directRefundSig = await this.config.signer.aggregateFrost({
25007
+ message: directRefundSighash,
25008
+ statechainSignatures: response.directRefundTxSigningResult.signingResult?.signatureShares,
25009
+ statechainPublicKeys: response.directRefundTxSigningResult.signingResult?.publicKeys,
25010
+ verifyingKey: response.directRefundTxSigningResult.verifyingKey,
25011
+ statechainCommitments: response.directRefundTxSigningResult.signingResult?.signingNonceCommitments,
25012
+ selfCommitment: newDirectRefundSigningJob.signingNonceCommitment,
25013
+ publicKey: signingPublicKey,
25014
+ selfSignature: directRefundUserSig,
25015
+ adaptorPubKey: new Uint8Array()
25016
+ });
25017
+ }
25018
+ let directFromCpfpRefundSig;
25019
+ if (directFromCpfpRefundSighash && newDirectFromCpfpRefundSigningJob && response.directFromCpfpRefundTxSigningResult) {
25020
+ const directFromCpfpRefundUserSig = await this.config.signer.signFrost({
25021
+ message: directFromCpfpRefundSighash,
25022
+ keyDerivation,
25023
+ publicKey: signingPublicKey,
25024
+ verifyingKey: response.directFromCpfpRefundTxSigningResult.verifyingKey,
25025
+ selfCommitment: newDirectFromCpfpRefundSigningJob.signingNonceCommitment,
25026
+ statechainCommitments: response.directFromCpfpRefundTxSigningResult.signingResult?.signingNonceCommitments,
25027
+ adaptorPubKey: new Uint8Array()
25028
+ });
25029
+ directFromCpfpRefundSig = await this.config.signer.aggregateFrost({
25030
+ message: directFromCpfpRefundSighash,
25031
+ statechainSignatures: response.directFromCpfpRefundTxSigningResult.signingResult?.signatureShares,
25032
+ statechainPublicKeys: response.directFromCpfpRefundTxSigningResult.signingResult?.publicKeys,
25033
+ verifyingKey: response.directFromCpfpRefundTxSigningResult.verifyingKey,
25034
+ statechainCommitments: response.directFromCpfpRefundTxSigningResult.signingResult?.signingNonceCommitments,
25035
+ selfCommitment: newDirectFromCpfpRefundSigningJob.signingNonceCommitment,
25036
+ publicKey: signingPublicKey,
25037
+ selfSignature: directFromCpfpRefundUserSig,
25038
+ adaptorPubKey: new Uint8Array()
25039
+ });
25040
+ }
25041
+ return await sparkClient.finalize_node_signatures_v2({
25042
+ intent: 4 /* EXTEND */,
24460
25043
  nodeSignatures: [
24461
25044
  {
24462
25045
  nodeId: response.leafId,
24463
25046
  nodeTxSignature: nodeSig,
24464
- refundTxSignature: refundSig
25047
+ directNodeTxSignature: directNodeSig,
25048
+ refundTxSignature: cpfpRefundSig,
25049
+ directRefundTxSignature: directRefundSig,
25050
+ directFromCpfpRefundTxSignature: directFromCpfpRefundSig
24465
25051
  }
24466
25052
  ]
24467
25053
  });
24468
25054
  }
24469
- async refreshTimelockRefundTx(node) {
25055
+ async testonly_expireTimeLockNodeTx(node, parentNode) {
25056
+ return await this.refreshTimelockNodesInternal(node, parentNode, true);
25057
+ }
25058
+ async testonly_expireTimeLockRefundtx(node) {
24470
25059
  const nodeTx = getTxFromRawTxBytes(node.nodeTx);
24471
- const refundTx = getTxFromRawTxBytes(node.refundTx);
24472
- const currSequence = refundTx.getInput(0).sequence || 0;
24473
- const { nextSequence } = getNextTransactionSequence(currSequence);
24474
- const signingPubKey = await this.config.signer.getPublicKeyFromDerivation({
25060
+ const directNodeTx = node.directTx.length > 0 ? getTxFromRawTxBytes(node.directTx) : void 0;
25061
+ const cpfpRefundTx = getTxFromRawTxBytes(node.refundTx);
25062
+ const currSequence = cpfpRefundTx.getInput(0).sequence || 0;
25063
+ const currTimelock = getCurrentTimelock(currSequence);
25064
+ if (currTimelock <= 100) {
25065
+ throw new ValidationError("Cannot expire timelock below 100", {
25066
+ field: "currTimelock",
25067
+ value: currTimelock,
25068
+ expected: "Timelock greater than 100"
25069
+ });
25070
+ }
25071
+ const nextSequence = TEST_UNILATERAL_SEQUENCE;
25072
+ const nextDirectSequence = TEST_UNILATERAL_SEQUENCE + DIRECT_TIMELOCK_OFFSET;
25073
+ const nodeOutput = nodeTx.getOutput(0);
25074
+ if (!nodeOutput) {
25075
+ throw Error("Could not get node output");
25076
+ }
25077
+ const keyDerivation = {
24475
25078
  type: "leaf" /* LEAF */,
24476
25079
  path: node.id
24477
- });
24478
- const newRefundTx = new import_btc_signer2.Transaction({
24479
- version: 3,
24480
- allowUnknownOutputs: true
24481
- });
24482
- const originalRefundOutput = refundTx.getOutput(0);
24483
- if (!originalRefundOutput) {
24484
- throw Error("Could not get original refund output");
25080
+ };
25081
+ const signingPublicKey = await this.config.signer.getPublicKeyFromDerivation(keyDerivation);
25082
+ const cpfpRefundOutPoint = {
25083
+ txid: (0, import_utils8.hexToBytes)(getTxId(nodeTx)),
25084
+ index: 0
25085
+ };
25086
+ let directRefundOutPoint;
25087
+ if (directNodeTx) {
25088
+ directRefundOutPoint = {
25089
+ txid: (0, import_utils8.hexToBytes)(getTxId(directNodeTx)),
25090
+ index: 0
25091
+ };
24485
25092
  }
24486
- newRefundTx.addOutput({
24487
- script: originalRefundOutput.script,
24488
- amount: originalRefundOutput.amount
25093
+ const {
25094
+ cpfpRefundTx: newCpfpRefundTx,
25095
+ directRefundTx: newDirectRefundTx,
25096
+ directFromCpfpRefundTx: newDirectFromCpfpRefundTx
25097
+ } = createRefundTxs({
25098
+ sequence: nextSequence,
25099
+ directSequence: nextDirectSequence,
25100
+ input: cpfpRefundOutPoint,
25101
+ directInput: directRefundOutPoint,
25102
+ amountSats: nodeOutput.amount,
25103
+ receivingPubkey: signingPublicKey,
25104
+ network: this.config.getNetwork()
24489
25105
  });
24490
- for (let j = 1; j < refundTx.outputsLength; j++) {
24491
- const additionalOutput = refundTx.getOutput(j);
24492
- if (additionalOutput) {
24493
- newRefundTx.addOutput(additionalOutput);
24494
- }
25106
+ const signingJobs = [];
25107
+ signingJobs.push({
25108
+ signingPublicKey,
25109
+ rawTx: newCpfpRefundTx.toBytes(),
25110
+ signingNonceCommitment: await this.config.signer.getRandomSigningCommitment(),
25111
+ type: "cpfp",
25112
+ parentTxOut: nodeOutput
25113
+ });
25114
+ const directNodeTxOut = directNodeTx?.getOutput(0);
25115
+ if (newDirectRefundTx && directNodeTxOut) {
25116
+ signingJobs.push({
25117
+ signingPublicKey,
25118
+ rawTx: newDirectRefundTx.toBytes(),
25119
+ signingNonceCommitment: await this.config.signer.getRandomSigningCommitment(),
25120
+ type: "direct",
25121
+ parentTxOut: directNodeTxOut
25122
+ });
24495
25123
  }
24496
- const refundTxInput = refundTx.getInput(0);
24497
- if (!refundTxInput) {
24498
- throw Error("refund tx doesn't have input");
25124
+ if (newDirectFromCpfpRefundTx) {
25125
+ signingJobs.push({
25126
+ signingPublicKey,
25127
+ rawTx: newDirectFromCpfpRefundTx.toBytes(),
25128
+ signingNonceCommitment: await this.config.signer.getRandomSigningCommitment(),
25129
+ type: "directFromCpfp",
25130
+ parentTxOut: nodeOutput
25131
+ });
24499
25132
  }
24500
- newRefundTx.addInput({
24501
- ...refundTxInput,
24502
- sequence: nextSequence
24503
- });
24504
- const refundSigningJob = {
24505
- signingPublicKey: signingPubKey,
24506
- rawTx: newRefundTx.toBytes(),
24507
- signingNonceCommitment: await this.config.signer.getRandomSigningCommitment()
24508
- };
24509
25133
  const sparkClient = await this.connectionManager.createSparkClient(
24510
25134
  this.config.getCoordinatorAddress()
24511
25135
  );
24512
- const response = await sparkClient.refresh_timelock({
25136
+ const response = await sparkClient.refresh_timelock_v2({
24513
25137
  leafId: node.id,
24514
25138
  ownerIdentityPublicKey: await this.config.signer.getIdentityPublicKey(),
24515
- signingJobs: [getSigningJobProto(refundSigningJob)]
25139
+ signingJobs: signingJobs.map(getSigningJobProto)
24516
25140
  });
24517
- if (response.signingResults.length !== 1) {
25141
+ if (response.signingResults.length !== signingJobs.length) {
24518
25142
  throw Error(
24519
- `Expected 1 signing result, got ${response.signingResults.length}`
25143
+ `Expected ${signingJobs.length} signing results, got ${response.signingResults.length}`
24520
25144
  );
24521
25145
  }
24522
- const signingResult = response.signingResults[0];
24523
- if (!signingResult || !refundSigningJob.signingNonceCommitment) {
24524
- throw Error("Signing result or nonce commitment does not exist");
25146
+ let cpfpRefundSignature;
25147
+ let directRefundSignature;
25148
+ let directFromCpfpRefundSignature;
25149
+ for (const [i, signingJob] of signingJobs.entries()) {
25150
+ const signingResult = response.signingResults[i];
25151
+ if (!signingResult) {
25152
+ throw Error("Signing result does not exist");
25153
+ }
25154
+ const rawTx = getTxFromRawTxBytes(signingJob.rawTx);
25155
+ const txOut = signingJob.parentTxOut;
25156
+ const rawTxSighash = getSigHashFromTx(rawTx, 0, txOut);
25157
+ const userSignature = await this.config.signer.signFrost({
25158
+ message: rawTxSighash,
25159
+ keyDerivation,
25160
+ publicKey: signingPublicKey,
25161
+ verifyingKey: signingResult.verifyingKey,
25162
+ selfCommitment: signingJob.signingNonceCommitment,
25163
+ statechainCommitments: signingResult.signingResult?.signingNonceCommitments,
25164
+ adaptorPubKey: new Uint8Array()
25165
+ });
25166
+ const signature = await this.config.signer.aggregateFrost({
25167
+ message: rawTxSighash,
25168
+ statechainSignatures: signingResult.signingResult?.signatureShares,
25169
+ statechainPublicKeys: signingResult.signingResult?.publicKeys,
25170
+ verifyingKey: signingResult.verifyingKey,
25171
+ statechainCommitments: signingResult.signingResult?.signingNonceCommitments,
25172
+ selfCommitment: signingJob.signingNonceCommitment,
25173
+ publicKey: signingPublicKey,
25174
+ selfSignature: userSignature,
25175
+ adaptorPubKey: new Uint8Array()
25176
+ });
25177
+ if (signingJob.type === "cpfp") {
25178
+ cpfpRefundSignature = signature;
25179
+ } else if (signingJob.type === "direct") {
25180
+ directRefundSignature = signature;
25181
+ } else if (signingJob.type === "directFromCpfp") {
25182
+ directFromCpfpRefundSignature = signature;
25183
+ }
24525
25184
  }
24526
- const rawTx = getTxFromRawTxBytes(refundSigningJob.rawTx);
24527
- const txOut = nodeTx.getOutput(0);
24528
- const rawTxSighash = getSigHashFromTx(rawTx, 0, txOut);
24529
- const userSignature = await this.config.signer.signFrost({
24530
- message: rawTxSighash,
24531
- keyDerivation: {
24532
- type: "leaf" /* LEAF */,
24533
- path: node.id
24534
- },
24535
- publicKey: signingPubKey,
24536
- verifyingKey: signingResult.verifyingKey,
24537
- selfCommitment: refundSigningJob.signingNonceCommitment,
24538
- statechainCommitments: signingResult.signingResult?.signingNonceCommitments,
24539
- adaptorPubKey: new Uint8Array()
24540
- });
24541
- const signature = await this.config.signer.aggregateFrost({
24542
- message: rawTxSighash,
24543
- statechainSignatures: signingResult.signingResult?.signatureShares,
24544
- statechainPublicKeys: signingResult.signingResult?.publicKeys,
24545
- verifyingKey: signingResult.verifyingKey,
24546
- statechainCommitments: signingResult.signingResult?.signingNonceCommitments,
24547
- selfCommitment: refundSigningJob.signingNonceCommitment,
24548
- publicKey: signingPubKey,
24549
- selfSignature: userSignature,
24550
- adaptorPubKey: new Uint8Array()
24551
- });
24552
- const result = await sparkClient.finalize_node_signatures({
25185
+ const result = await sparkClient.finalize_node_signatures_v2({
24553
25186
  intent: 3 /* REFRESH */,
24554
25187
  nodeSignatures: [
24555
25188
  {
24556
25189
  nodeId: node.id,
24557
25190
  nodeTxSignature: new Uint8Array(),
24558
- refundTxSignature: signature
25191
+ directNodeTxSignature: new Uint8Array(),
25192
+ refundTxSignature: cpfpRefundSignature,
25193
+ directRefundTxSignature: directRefundSignature,
25194
+ directFromCpfpRefundTxSignature: directFromCpfpRefundSignature
24559
25195
  }
24560
25196
  ]
24561
25197
  });
@@ -24574,7 +25210,12 @@ var CoopExitService = class extends BaseTransferService {
24574
25210
  connectorOutputs,
24575
25211
  receiverPubKey
24576
25212
  }) {
24577
- const { transfer, signaturesMap } = await this.signCoopExitRefunds(
25213
+ const {
25214
+ transfer,
25215
+ signaturesMap,
25216
+ directSignaturesMap,
25217
+ directFromCpfpSignaturesMap
25218
+ } = await this.signCoopExitRefunds(
24578
25219
  leaves,
24579
25220
  exitTxId,
24580
25221
  connectorOutputs,
@@ -24583,34 +25224,81 @@ var CoopExitService = class extends BaseTransferService {
24583
25224
  const transferTweak = await this.deliverTransferPackage(
24584
25225
  transfer,
24585
25226
  leaves,
24586
- signaturesMap
25227
+ signaturesMap,
25228
+ directSignaturesMap,
25229
+ directFromCpfpSignaturesMap
24587
25230
  );
24588
- return { transfer: transferTweak, signaturesMap };
24589
- }
24590
- createConnectorRefundTransaction(sequence, nodeOutPoint, connectorOutput, amountSats, receiverPubKey) {
24591
- const refundTx = new import_btc_signer3.Transaction();
24592
- if (!nodeOutPoint.txid || nodeOutPoint.index === void 0) {
24593
- throw new ValidationError("Invalid node outpoint", {
24594
- field: "nodeOutPoint",
24595
- value: { txid: nodeOutPoint.txid, index: nodeOutPoint.index },
25231
+ return {
25232
+ transfer: transferTweak,
25233
+ signaturesMap,
25234
+ directSignaturesMap,
25235
+ directFromCpfpSignaturesMap
25236
+ };
25237
+ }
25238
+ createConnectorRefundTransactions(sequence, directSequence, cpfpNodeOutPoint, directNodeOutPoint, connectorOutput, amountSats, receiverPubKey) {
25239
+ const cpfpRefundTx = new import_btc_signer3.Transaction();
25240
+ if (!cpfpNodeOutPoint.txid || cpfpNodeOutPoint.index === void 0) {
25241
+ throw new ValidationError("Invalid CPFP node outpoint", {
25242
+ field: "cpfpNodeOutPoint",
25243
+ value: { txid: cpfpNodeOutPoint.txid, index: cpfpNodeOutPoint.index },
24596
25244
  expected: "Both txid and index must be defined"
24597
25245
  });
24598
25246
  }
24599
- refundTx.addInput({
24600
- txid: nodeOutPoint.txid,
24601
- index: nodeOutPoint.index,
25247
+ cpfpRefundTx.addInput({
25248
+ txid: cpfpNodeOutPoint.txid,
25249
+ index: cpfpNodeOutPoint.index,
24602
25250
  sequence
24603
25251
  });
24604
- refundTx.addInput(connectorOutput);
25252
+ cpfpRefundTx.addInput(connectorOutput);
24605
25253
  const receiverScript = getP2TRScriptFromPublicKey(
24606
25254
  receiverPubKey,
24607
25255
  this.config.getNetwork()
24608
25256
  );
24609
- refundTx.addOutput({
25257
+ cpfpRefundTx.addOutput({
24610
25258
  script: receiverScript,
24611
25259
  amount: amountSats
24612
25260
  });
24613
- return refundTx;
25261
+ let directRefundTx;
25262
+ let directFromCpfpRefundTx;
25263
+ if (directNodeOutPoint) {
25264
+ if (!directNodeOutPoint.txid || directNodeOutPoint.index === void 0) {
25265
+ throw new ValidationError("Invalid direct node outpoint", {
25266
+ field: "directNodeOutPoint",
25267
+ value: {
25268
+ txid: directNodeOutPoint.txid,
25269
+ index: directNodeOutPoint.index
25270
+ },
25271
+ expected: "Both txid and index must be defined"
25272
+ });
25273
+ }
25274
+ directRefundTx = new import_btc_signer3.Transaction();
25275
+ directRefundTx.addInput({
25276
+ txid: directNodeOutPoint.txid,
25277
+ index: directNodeOutPoint.index,
25278
+ sequence: directSequence
25279
+ });
25280
+ directRefundTx.addInput(connectorOutput);
25281
+ directRefundTx.addOutput({
25282
+ script: receiverScript,
25283
+ amount: maybeApplyFee(amountSats)
25284
+ });
25285
+ directFromCpfpRefundTx = new import_btc_signer3.Transaction();
25286
+ directFromCpfpRefundTx.addInput({
25287
+ txid: cpfpNodeOutPoint.txid,
25288
+ index: cpfpNodeOutPoint.index,
25289
+ sequence: directSequence
25290
+ });
25291
+ directFromCpfpRefundTx.addInput(connectorOutput);
25292
+ directFromCpfpRefundTx.addOutput({
25293
+ script: receiverScript,
25294
+ amount: maybeApplyFee(amountSats)
25295
+ });
25296
+ }
25297
+ return {
25298
+ cpfpRefundTx,
25299
+ directRefundTx,
25300
+ directFromCpfpRefundTx
25301
+ };
24614
25302
  }
24615
25303
  async signCoopExitRefunds(leaves, exitTxId, connectorOutputs, receiverPubKey) {
24616
25304
  if (leaves.length !== connectorOutputs.length) {
@@ -24646,39 +25334,67 @@ var CoopExitService = class extends BaseTransferService {
24646
25334
  });
24647
25335
  }
24648
25336
  const currentRefundTx = getTxFromRawTxBytes(leaf.leaf.refundTx);
24649
- const { nextSequence } = getNextTransactionSequence(
24650
- currentRefundTx.getInput(0).sequence
24651
- );
24652
- const refundTx = this.createConnectorRefundTransaction(
25337
+ const sequence = currentRefundTx.getInput(0).sequence;
25338
+ if (!sequence) {
25339
+ throw new ValidationError("Invalid refund transaction", {
25340
+ field: "sequence",
25341
+ value: currentRefundTx.getInput(0),
25342
+ expected: "Non-null sequence"
25343
+ });
25344
+ }
25345
+ const { nextSequence, nextDirectSequence } = getNextTransactionSequence(sequence);
25346
+ let currentDirectRefundTx;
25347
+ if (leaf.leaf.directRefundTx.length > 0) {
25348
+ currentDirectRefundTx = getTxFromRawTxBytes(leaf.leaf.directRefundTx);
25349
+ }
25350
+ const { cpfpRefundTx, directRefundTx, directFromCpfpRefundTx } = this.createConnectorRefundTransactions(
24653
25351
  nextSequence,
25352
+ nextDirectSequence,
24654
25353
  currentRefundTx.getInput(0),
25354
+ currentDirectRefundTx?.getInput(0),
24655
25355
  connectorOutput,
24656
25356
  BigInt(leaf.leaf.value),
24657
25357
  receiverPubKey
24658
25358
  );
24659
25359
  const signingNonceCommitment = await this.config.signer.getRandomSigningCommitment();
25360
+ const directSigningNonceCommitment = await this.config.signer.getRandomSigningCommitment();
25361
+ const directFromCpfpSigningNonceCommitment = await this.config.signer.getRandomSigningCommitment();
25362
+ const signingPublicKey = await this.config.signer.getPublicKeyFromDerivation(leaf.keyDerivation);
24660
25363
  const signingJob = {
24661
25364
  leafId: leaf.leaf.id,
24662
25365
  refundTxSigningJob: {
24663
25366
  signingPublicKey: await this.config.signer.getPublicKeyFromDerivation(
24664
25367
  leaf.keyDerivation
24665
25368
  ),
24666
- rawTx: refundTx.toBytes(),
25369
+ rawTx: cpfpRefundTx.toBytes(),
24667
25370
  signingNonceCommitment: signingNonceCommitment.commitment
24668
25371
  },
24669
- // TODO: Add direct refund signature
24670
- directRefundTxSigningJob: void 0,
24671
- directFromCpfpRefundTxSigningJob: void 0
25372
+ directRefundTxSigningJob: directRefundTx ? {
25373
+ signingPublicKey,
25374
+ rawTx: directRefundTx.toBytes(),
25375
+ signingNonceCommitment: directSigningNonceCommitment.commitment
25376
+ } : void 0,
25377
+ directFromCpfpRefundTxSigningJob: directFromCpfpRefundTx ? {
25378
+ signingPublicKey,
25379
+ rawTx: directFromCpfpRefundTx.toBytes(),
25380
+ signingNonceCommitment: directFromCpfpSigningNonceCommitment.commitment
25381
+ } : void 0
24672
25382
  };
24673
25383
  signingJobs.push(signingJob);
24674
25384
  const tx = getTxFromRawTxBytes(leaf.leaf.nodeTx);
25385
+ const directTx = leaf.leaf.directTx.length > 0 ? getTxFromRawTxBytes(leaf.leaf.directTx) : void 0;
24675
25386
  leafDataMap.set(leaf.leaf.id, {
24676
25387
  keyDerivation: leaf.keyDerivation,
24677
- refundTx,
25388
+ receivingPubkey: receiverPubKey,
24678
25389
  signingNonceCommitment,
25390
+ directSigningNonceCommitment,
24679
25391
  tx,
24680
- vout: leaf.leaf.vout,
24681
- receivingPubkey: receiverPubKey
25392
+ directTx,
25393
+ refundTx: cpfpRefundTx,
25394
+ directRefundTx,
25395
+ directFromCpfpRefundTx,
25396
+ directFromCpfpRefundSigningNonceCommitment: directFromCpfpSigningNonceCommitment,
25397
+ vout: leaf.leaf.vout
24682
25398
  });
24683
25399
  }
24684
25400
  const sparkClient = await this.connectionManager.createSparkClient(
@@ -24686,7 +25402,7 @@ var CoopExitService = class extends BaseTransferService {
24686
25402
  );
24687
25403
  let response;
24688
25404
  try {
24689
- response = await sparkClient.cooperative_exit({
25405
+ response = await sparkClient.cooperative_exit_v2({
24690
25406
  transfer: {
24691
25407
  transferId: (0, import_uuidv72.uuidv7)(),
24692
25408
  leavesToSend: signingJobs,
@@ -24720,10 +25436,25 @@ var CoopExitService = class extends BaseTransferService {
24720
25436
  response.signingResults
24721
25437
  );
24722
25438
  const signaturesMap = /* @__PURE__ */ new Map();
25439
+ const directSignaturesMap = /* @__PURE__ */ new Map();
25440
+ const directFromCpfpSignaturesMap = /* @__PURE__ */ new Map();
24723
25441
  for (const signature of signatures) {
24724
25442
  signaturesMap.set(signature.nodeId, signature.refundTxSignature);
25443
+ directSignaturesMap.set(
25444
+ signature.nodeId,
25445
+ signature.directRefundTxSignature
25446
+ );
25447
+ directFromCpfpSignaturesMap.set(
25448
+ signature.nodeId,
25449
+ signature.directFromCpfpRefundTxSignature
25450
+ );
24725
25451
  }
24726
- return { transfer: response.transfer, signaturesMap };
25452
+ return {
25453
+ transfer: response.transfer,
25454
+ signaturesMap,
25455
+ directSignaturesMap,
25456
+ directFromCpfpSignaturesMap
25457
+ };
24727
25458
  }
24728
25459
  };
24729
25460
 
@@ -24732,7 +25463,6 @@ init_buffer();
24732
25463
  var import_secp256k18 = require("@noble/curves/secp256k1");
24733
25464
  var import_sha28 = require("@noble/hashes/sha2");
24734
25465
  var import_utils9 = require("@noble/hashes/utils");
24735
- var btc3 = __toESM(require("@scure/btc-signer"), 1);
24736
25466
  var import_btc_signer4 = require("@scure/btc-signer");
24737
25467
  var import_utils10 = require("@scure/btc-signer/utils");
24738
25468
 
@@ -24751,7 +25481,6 @@ function proofOfPossessionMessageHashForDepositAddress(userPubkey, operatorPubke
24751
25481
  }
24752
25482
 
24753
25483
  // src/services/deposit.ts
24754
- var INITIAL_TIME_LOCK2 = 2e3;
24755
25484
  var DepositService = class {
24756
25485
  config;
24757
25486
  connectionManager;
@@ -24869,7 +25598,6 @@ var DepositService = class {
24869
25598
  depositTx,
24870
25599
  vout
24871
25600
  }) {
24872
- const rootTx = new import_btc_signer4.Transaction({ version: 3 });
24873
25601
  const output = depositTx.getOutput(vout);
24874
25602
  if (!output) {
24875
25603
  throw new ValidationError("Invalid deposit transaction output", {
@@ -24887,39 +25615,345 @@ var DepositService = class {
24887
25615
  expected: "Output with script and amount"
24888
25616
  });
24889
25617
  }
24890
- let outputAmount = amount;
24891
- rootTx.addInput({
24892
- txid: getTxId(depositTx),
25618
+ const depositOutPoint = {
25619
+ txid: (0, import_utils9.hexToBytes)(getTxId(depositTx)),
24893
25620
  index: vout
24894
- });
24895
- rootTx.addOutput({
25621
+ };
25622
+ const depositTxOut = {
24896
25623
  script,
24897
- amount: outputAmount
25624
+ amount
25625
+ };
25626
+ const [cpfpRootTx, directRootTx] = createRootTx(
25627
+ depositOutPoint,
25628
+ depositTxOut
25629
+ );
25630
+ const cpfpRootNonceCommitment = await this.config.signer.getRandomSigningCommitment();
25631
+ const directRootNonceCommitment = await this.config.signer.getRandomSigningCommitment();
25632
+ const cpfpRootTxSighash = getSigHashFromTx(cpfpRootTx, 0, output);
25633
+ const directRootTxSighash = getSigHashFromTx(directRootTx, 0, output);
25634
+ const signingPubKey = await this.config.signer.getPublicKeyFromDerivation(keyDerivation);
25635
+ const { cpfpRefundTx, directRefundTx, directFromCpfpRefundTx } = createRefundTxs({
25636
+ sequence: INITIAL_SEQUENCE,
25637
+ directSequence: INITIAL_DIRECT_SEQUENCE,
25638
+ input: { txid: (0, import_utils9.hexToBytes)(getTxId(cpfpRootTx)), index: 0 },
25639
+ directInput: { txid: (0, import_utils9.hexToBytes)(getTxId(directRootTx)), index: 0 },
25640
+ amountSats: amount,
25641
+ receivingPubkey: signingPubKey,
25642
+ network: this.config.getNetwork()
24898
25643
  });
24899
- rootTx.addOutput(getEphemeralAnchorOutput());
24900
- const rootNonceCommitment = await this.config.signer.getRandomSigningCommitment();
24901
- const rootTxSighash = getSigHashFromTx(rootTx, 0, output);
24902
- const refundTx = new import_btc_signer4.Transaction({ version: 3 });
24903
- const sequence = 1 << 30 | INITIAL_TIME_LOCK2;
24904
- refundTx.addInput({
24905
- txid: getTxId(rootTx),
24906
- index: 0,
24907
- sequence
25644
+ const cpfpRefundNonceCommitment = await this.config.signer.getRandomSigningCommitment();
25645
+ const directRefundNonceCommitment = await this.config.signer.getRandomSigningCommitment();
25646
+ const directFromCpfpRefundNonceCommitment = await this.config.signer.getRandomSigningCommitment();
25647
+ const cpfpRefundTxSighash = getSigHashFromTx(
25648
+ cpfpRefundTx,
25649
+ 0,
25650
+ cpfpRootTx.getOutput(0)
25651
+ );
25652
+ if (!directRefundTx || !directFromCpfpRefundTx) {
25653
+ throw new ValidationError(
25654
+ "Expected direct refund transactions for tree creation",
25655
+ {
25656
+ field: "directRefundTx",
25657
+ value: directRefundTx
25658
+ }
25659
+ );
25660
+ }
25661
+ const directRefundTxSighash = getSigHashFromTx(
25662
+ directRefundTx,
25663
+ 0,
25664
+ directRootTx.getOutput(0)
25665
+ );
25666
+ const directFromCpfpRefundTxSighash = getSigHashFromTx(
25667
+ directFromCpfpRefundTx,
25668
+ 0,
25669
+ cpfpRootTx.getOutput(0)
25670
+ );
25671
+ const sparkClient = await this.connectionManager.createSparkClient(
25672
+ this.config.getCoordinatorAddress()
25673
+ );
25674
+ let treeResp;
25675
+ try {
25676
+ treeResp = await sparkClient.start_deposit_tree_creation({
25677
+ identityPublicKey: await this.config.signer.getIdentityPublicKey(),
25678
+ onChainUtxo: {
25679
+ vout,
25680
+ rawTx: depositTx.toBytes(true),
25681
+ network: this.config.getNetworkProto()
25682
+ },
25683
+ rootTxSigningJob: {
25684
+ rawTx: cpfpRootTx.toBytes(),
25685
+ signingPublicKey: signingPubKey,
25686
+ signingNonceCommitment: cpfpRootNonceCommitment.commitment
25687
+ },
25688
+ refundTxSigningJob: {
25689
+ rawTx: cpfpRefundTx.toBytes(),
25690
+ signingPublicKey: signingPubKey,
25691
+ signingNonceCommitment: cpfpRefundNonceCommitment.commitment
25692
+ },
25693
+ directRootTxSigningJob: {
25694
+ rawTx: directRootTx.toBytes(),
25695
+ signingPublicKey: signingPubKey,
25696
+ signingNonceCommitment: directRootNonceCommitment.commitment
25697
+ },
25698
+ directRefundTxSigningJob: {
25699
+ rawTx: directRefundTx.toBytes(),
25700
+ signingPublicKey: signingPubKey,
25701
+ signingNonceCommitment: directRefundNonceCommitment.commitment
25702
+ },
25703
+ directFromCpfpRefundTxSigningJob: {
25704
+ rawTx: directFromCpfpRefundTx.toBytes(),
25705
+ signingPublicKey: signingPubKey,
25706
+ signingNonceCommitment: directFromCpfpRefundNonceCommitment.commitment
25707
+ }
25708
+ });
25709
+ } catch (error) {
25710
+ throw new NetworkError(
25711
+ "Failed to start deposit tree creation",
25712
+ {
25713
+ operation: "start_deposit_tree_creation",
25714
+ errorCount: 1,
25715
+ errors: error instanceof Error ? error.message : String(error)
25716
+ },
25717
+ error
25718
+ );
25719
+ }
25720
+ if (!treeResp.rootNodeSignatureShares?.verifyingKey) {
25721
+ throw new ValidationError("No verifying key found in tree response", {
25722
+ field: "verifyingKey",
25723
+ value: treeResp.rootNodeSignatureShares,
25724
+ expected: "Non-null verifying key"
25725
+ });
25726
+ }
25727
+ if (!treeResp.rootNodeSignatureShares.nodeTxSigningResult?.signingNonceCommitments) {
25728
+ throw new ValidationError(
25729
+ "No signing nonce commitments found in tree response",
25730
+ {
25731
+ field: "nodeTxSigningResult.signingNonceCommitments",
25732
+ value: treeResp.rootNodeSignatureShares.nodeTxSigningResult,
25733
+ expected: "Non-null signing nonce commitments"
25734
+ }
25735
+ );
25736
+ }
25737
+ if (!treeResp.rootNodeSignatureShares.refundTxSigningResult?.signingNonceCommitments) {
25738
+ throw new ValidationError(
25739
+ "No signing nonce commitments found in tree response",
25740
+ {
25741
+ field: "refundTxSigningResult.signingNonceCommitments"
25742
+ }
25743
+ );
25744
+ }
25745
+ if (!treeResp.rootNodeSignatureShares.directNodeTxSigningResult?.signingNonceCommitments) {
25746
+ throw new ValidationError(
25747
+ "No direct node signing nonce commitments found in tree response",
25748
+ {
25749
+ field: "directNodeTxSigningResult.signingNonceCommitments"
25750
+ }
25751
+ );
25752
+ }
25753
+ if (!treeResp.rootNodeSignatureShares.directRefundTxSigningResult?.signingNonceCommitments) {
25754
+ throw new ValidationError(
25755
+ "No direct refund signing nonce commitments found in tree response",
25756
+ {
25757
+ field: "directRefundTxSigningResult.signingNonceCommitments"
25758
+ }
25759
+ );
25760
+ }
25761
+ if (!treeResp.rootNodeSignatureShares.directFromCpfpRefundTxSigningResult?.signingNonceCommitments) {
25762
+ throw new ValidationError(
25763
+ "No direct from CPFP refund signing nonce commitments found in tree response",
25764
+ {
25765
+ field: "directFromCpfpRefundTxSigningResult.signingNonceCommitments"
25766
+ }
25767
+ );
25768
+ }
25769
+ if (!(0, import_utils10.equalBytes)(treeResp.rootNodeSignatureShares.verifyingKey, verifyingKey)) {
25770
+ throw new ValidationError("Verifying key mismatch", {
25771
+ field: "verifyingKey",
25772
+ value: treeResp.rootNodeSignatureShares.verifyingKey,
25773
+ expected: verifyingKey
25774
+ });
25775
+ }
25776
+ const cpfpRootSignature = await this.config.signer.signFrost({
25777
+ message: cpfpRootTxSighash,
25778
+ publicKey: signingPubKey,
25779
+ keyDerivation,
25780
+ verifyingKey,
25781
+ selfCommitment: cpfpRootNonceCommitment,
25782
+ statechainCommitments: treeResp.rootNodeSignatureShares.nodeTxSigningResult.signingNonceCommitments,
25783
+ adaptorPubKey: new Uint8Array()
25784
+ });
25785
+ const directRootSignature = await this.config.signer.signFrost({
25786
+ message: directRootTxSighash,
25787
+ publicKey: signingPubKey,
25788
+ keyDerivation,
25789
+ verifyingKey,
25790
+ selfCommitment: directRootNonceCommitment,
25791
+ statechainCommitments: treeResp.rootNodeSignatureShares.directNodeTxSigningResult.signingNonceCommitments,
25792
+ adaptorPubKey: new Uint8Array()
24908
25793
  });
25794
+ const cpfpRefundSignature = await this.config.signer.signFrost({
25795
+ message: cpfpRefundTxSighash,
25796
+ publicKey: signingPubKey,
25797
+ keyDerivation,
25798
+ verifyingKey: treeResp.rootNodeSignatureShares.verifyingKey,
25799
+ selfCommitment: cpfpRefundNonceCommitment,
25800
+ statechainCommitments: treeResp.rootNodeSignatureShares.refundTxSigningResult.signingNonceCommitments,
25801
+ adaptorPubKey: new Uint8Array()
25802
+ });
25803
+ const directRefundSignature = await this.config.signer.signFrost({
25804
+ message: directRefundTxSighash,
25805
+ publicKey: signingPubKey,
25806
+ keyDerivation,
25807
+ verifyingKey: treeResp.rootNodeSignatureShares.verifyingKey,
25808
+ selfCommitment: directRefundNonceCommitment,
25809
+ statechainCommitments: treeResp.rootNodeSignatureShares.directRefundTxSigningResult.signingNonceCommitments,
25810
+ adaptorPubKey: new Uint8Array()
25811
+ });
25812
+ const directFromCpfpRefundSignature = await this.config.signer.signFrost({
25813
+ message: directFromCpfpRefundTxSighash,
25814
+ publicKey: signingPubKey,
25815
+ keyDerivation,
25816
+ verifyingKey: treeResp.rootNodeSignatureShares.verifyingKey,
25817
+ selfCommitment: directFromCpfpRefundNonceCommitment,
25818
+ statechainCommitments: treeResp.rootNodeSignatureShares.directFromCpfpRefundTxSigningResult.signingNonceCommitments,
25819
+ adaptorPubKey: new Uint8Array()
25820
+ });
25821
+ const cpfpRootAggregate = await this.config.signer.aggregateFrost({
25822
+ message: cpfpRootTxSighash,
25823
+ statechainSignatures: treeResp.rootNodeSignatureShares.nodeTxSigningResult.signatureShares,
25824
+ statechainPublicKeys: treeResp.rootNodeSignatureShares.nodeTxSigningResult.publicKeys,
25825
+ verifyingKey: treeResp.rootNodeSignatureShares.verifyingKey,
25826
+ statechainCommitments: treeResp.rootNodeSignatureShares.nodeTxSigningResult.signingNonceCommitments,
25827
+ selfCommitment: cpfpRootNonceCommitment,
25828
+ publicKey: signingPubKey,
25829
+ selfSignature: cpfpRootSignature,
25830
+ adaptorPubKey: new Uint8Array()
25831
+ });
25832
+ const directRootAggregate = await this.config.signer.aggregateFrost({
25833
+ message: directRootTxSighash,
25834
+ statechainSignatures: treeResp.rootNodeSignatureShares.directNodeTxSigningResult.signatureShares,
25835
+ statechainPublicKeys: treeResp.rootNodeSignatureShares.directNodeTxSigningResult.publicKeys,
25836
+ verifyingKey: treeResp.rootNodeSignatureShares.verifyingKey,
25837
+ statechainCommitments: treeResp.rootNodeSignatureShares.directNodeTxSigningResult.signingNonceCommitments,
25838
+ selfCommitment: directRootNonceCommitment,
25839
+ publicKey: signingPubKey,
25840
+ selfSignature: directRootSignature,
25841
+ adaptorPubKey: new Uint8Array()
25842
+ });
25843
+ const cpfpRefundAggregate = await this.config.signer.aggregateFrost({
25844
+ message: cpfpRefundTxSighash,
25845
+ statechainSignatures: treeResp.rootNodeSignatureShares.refundTxSigningResult.signatureShares,
25846
+ statechainPublicKeys: treeResp.rootNodeSignatureShares.refundTxSigningResult.publicKeys,
25847
+ verifyingKey: treeResp.rootNodeSignatureShares.verifyingKey,
25848
+ statechainCommitments: treeResp.rootNodeSignatureShares.refundTxSigningResult.signingNonceCommitments,
25849
+ selfCommitment: cpfpRefundNonceCommitment,
25850
+ publicKey: signingPubKey,
25851
+ selfSignature: cpfpRefundSignature,
25852
+ adaptorPubKey: new Uint8Array()
25853
+ });
25854
+ const directRefundAggregate = await this.config.signer.aggregateFrost({
25855
+ message: directRefundTxSighash,
25856
+ statechainSignatures: treeResp.rootNodeSignatureShares.directRefundTxSigningResult.signatureShares,
25857
+ statechainPublicKeys: treeResp.rootNodeSignatureShares.directRefundTxSigningResult.publicKeys,
25858
+ verifyingKey: treeResp.rootNodeSignatureShares.verifyingKey,
25859
+ statechainCommitments: treeResp.rootNodeSignatureShares.directRefundTxSigningResult.signingNonceCommitments,
25860
+ selfCommitment: directRefundNonceCommitment,
25861
+ publicKey: signingPubKey,
25862
+ selfSignature: directRefundSignature,
25863
+ adaptorPubKey: new Uint8Array()
25864
+ });
25865
+ const directFromCpfpRefundAggregate = await this.config.signer.aggregateFrost({
25866
+ message: directFromCpfpRefundTxSighash,
25867
+ statechainSignatures: treeResp.rootNodeSignatureShares.directFromCpfpRefundTxSigningResult.signatureShares,
25868
+ statechainPublicKeys: treeResp.rootNodeSignatureShares.directFromCpfpRefundTxSigningResult.publicKeys,
25869
+ verifyingKey: treeResp.rootNodeSignatureShares.verifyingKey,
25870
+ statechainCommitments: treeResp.rootNodeSignatureShares.directFromCpfpRefundTxSigningResult.signingNonceCommitments,
25871
+ selfCommitment: directFromCpfpRefundNonceCommitment,
25872
+ publicKey: signingPubKey,
25873
+ selfSignature: directFromCpfpRefundSignature,
25874
+ adaptorPubKey: new Uint8Array()
25875
+ });
25876
+ let finalizeResp;
25877
+ try {
25878
+ finalizeResp = await sparkClient.finalize_node_signatures_v2({
25879
+ intent: 0 /* CREATION */,
25880
+ nodeSignatures: [
25881
+ {
25882
+ nodeId: treeResp.rootNodeSignatureShares.nodeId,
25883
+ nodeTxSignature: cpfpRootAggregate,
25884
+ refundTxSignature: cpfpRefundAggregate,
25885
+ directNodeTxSignature: directRootAggregate,
25886
+ directRefundTxSignature: directRefundAggregate,
25887
+ directFromCpfpRefundTxSignature: directFromCpfpRefundAggregate
25888
+ }
25889
+ ]
25890
+ });
25891
+ } catch (error) {
25892
+ throw new NetworkError(
25893
+ "Failed to finalize node signatures",
25894
+ {
25895
+ operation: "finalize_node_signatures",
25896
+ errorCount: 1,
25897
+ errors: error instanceof Error ? error.message : String(error)
25898
+ },
25899
+ error
25900
+ );
25901
+ }
25902
+ return finalizeResp;
25903
+ }
25904
+ /**
25905
+ * @deprecated
25906
+ * Use createTreeRoot instead.
25907
+ * This is currently only used to test backwards compatibility.
25908
+ */
25909
+ async createTreeWithoutDirectTx({
25910
+ keyDerivation,
25911
+ verifyingKey,
25912
+ depositTx,
25913
+ vout
25914
+ }) {
25915
+ const output = depositTx.getOutput(vout);
25916
+ if (!output) {
25917
+ throw new ValidationError("Invalid deposit transaction output", {
25918
+ field: "vout",
25919
+ value: vout,
25920
+ expected: "Valid output index"
25921
+ });
25922
+ }
25923
+ const script = output.script;
25924
+ const amount = output.amount;
25925
+ if (!script || !amount) {
25926
+ throw new ValidationError("No script or amount found in deposit tx", {
25927
+ field: "output",
25928
+ value: output,
25929
+ expected: "Output with script and amount"
25930
+ });
25931
+ }
25932
+ const depositOutPoint = {
25933
+ txid: (0, import_utils9.hexToBytes)(getTxId(depositTx)),
25934
+ index: vout
25935
+ };
25936
+ const depositTxOut = {
25937
+ script,
25938
+ amount
25939
+ };
25940
+ const [cpfpRootTx, _] = createRootTx(depositOutPoint, depositTxOut);
25941
+ const cpfpRootNonceCommitment = await this.config.signer.getRandomSigningCommitment();
25942
+ const cpfpRootTxSighash = getSigHashFromTx(cpfpRootTx, 0, output);
24909
25943
  const signingPubKey = await this.config.signer.getPublicKeyFromDerivation(keyDerivation);
24910
- const refundP2trAddress = getP2TRAddressFromPublicKey(
24911
- signingPubKey,
24912
- this.config.getNetwork()
24913
- );
24914
- const refundAddress = btc3.Address(getNetwork(this.config.getNetwork())).decode(refundP2trAddress);
24915
- const refundPkScript = btc3.OutScript.encode(refundAddress);
24916
- refundTx.addOutput({
24917
- script: refundPkScript,
24918
- amount: outputAmount
25944
+ const { cpfpRefundTx } = createRefundTxs({
25945
+ sequence: INITIAL_SEQUENCE,
25946
+ input: { txid: (0, import_utils9.hexToBytes)(getTxId(cpfpRootTx)), index: 0 },
25947
+ amountSats: amount,
25948
+ receivingPubkey: signingPubKey,
25949
+ network: this.config.getNetwork()
24919
25950
  });
24920
- refundTx.addOutput(getEphemeralAnchorOutput());
24921
- const refundNonceCommitment = await this.config.signer.getRandomSigningCommitment();
24922
- const refundTxSighash = getSigHashFromTx(refundTx, 0, rootTx.getOutput(0));
25951
+ const cpfpRefundNonceCommitment = await this.config.signer.getRandomSigningCommitment();
25952
+ const cpfpRefundTxSighash = getSigHashFromTx(
25953
+ cpfpRefundTx,
25954
+ 0,
25955
+ cpfpRootTx.getOutput(0)
25956
+ );
24923
25957
  const sparkClient = await this.connectionManager.createSparkClient(
24924
25958
  this.config.getCoordinatorAddress()
24925
25959
  );
@@ -24933,14 +25967,14 @@ var DepositService = class {
24933
25967
  network: this.config.getNetworkProto()
24934
25968
  },
24935
25969
  rootTxSigningJob: {
24936
- rawTx: rootTx.toBytes(),
25970
+ rawTx: cpfpRootTx.toBytes(),
24937
25971
  signingPublicKey: signingPubKey,
24938
- signingNonceCommitment: rootNonceCommitment.commitment
25972
+ signingNonceCommitment: cpfpRootNonceCommitment.commitment
24939
25973
  },
24940
25974
  refundTxSigningJob: {
24941
- rawTx: refundTx.toBytes(),
25975
+ rawTx: cpfpRefundTx.toBytes(),
24942
25976
  signingPublicKey: signingPubKey,
24943
- signingNonceCommitment: refundNonceCommitment.commitment
25977
+ signingNonceCommitment: cpfpRefundNonceCommitment.commitment
24944
25978
  }
24945
25979
  });
24946
25980
  } catch (error) {
@@ -24986,55 +26020,55 @@ var DepositService = class {
24986
26020
  expected: verifyingKey
24987
26021
  });
24988
26022
  }
24989
- const rootSignature = await this.config.signer.signFrost({
24990
- message: rootTxSighash,
26023
+ const cpfpRootSignature = await this.config.signer.signFrost({
26024
+ message: cpfpRootTxSighash,
24991
26025
  publicKey: signingPubKey,
24992
26026
  keyDerivation,
24993
26027
  verifyingKey,
24994
- selfCommitment: rootNonceCommitment,
26028
+ selfCommitment: cpfpRootNonceCommitment,
24995
26029
  statechainCommitments: treeResp.rootNodeSignatureShares.nodeTxSigningResult.signingNonceCommitments,
24996
26030
  adaptorPubKey: new Uint8Array()
24997
26031
  });
24998
- const refundSignature = await this.config.signer.signFrost({
24999
- message: refundTxSighash,
26032
+ const cpfpRefundSignature = await this.config.signer.signFrost({
26033
+ message: cpfpRefundTxSighash,
25000
26034
  publicKey: signingPubKey,
25001
26035
  keyDerivation,
25002
- verifyingKey,
25003
- selfCommitment: refundNonceCommitment,
26036
+ verifyingKey: treeResp.rootNodeSignatureShares.verifyingKey,
26037
+ selfCommitment: cpfpRefundNonceCommitment,
25004
26038
  statechainCommitments: treeResp.rootNodeSignatureShares.refundTxSigningResult.signingNonceCommitments,
25005
26039
  adaptorPubKey: new Uint8Array()
25006
26040
  });
25007
- const rootAggregate = await this.config.signer.aggregateFrost({
25008
- message: rootTxSighash,
26041
+ const cpfpRootAggregate = await this.config.signer.aggregateFrost({
26042
+ message: cpfpRootTxSighash,
25009
26043
  statechainSignatures: treeResp.rootNodeSignatureShares.nodeTxSigningResult.signatureShares,
25010
26044
  statechainPublicKeys: treeResp.rootNodeSignatureShares.nodeTxSigningResult.publicKeys,
25011
26045
  verifyingKey: treeResp.rootNodeSignatureShares.verifyingKey,
25012
26046
  statechainCommitments: treeResp.rootNodeSignatureShares.nodeTxSigningResult.signingNonceCommitments,
25013
- selfCommitment: rootNonceCommitment,
26047
+ selfCommitment: cpfpRootNonceCommitment,
25014
26048
  publicKey: signingPubKey,
25015
- selfSignature: rootSignature,
26049
+ selfSignature: cpfpRootSignature,
25016
26050
  adaptorPubKey: new Uint8Array()
25017
26051
  });
25018
- const refundAggregate = await this.config.signer.aggregateFrost({
25019
- message: refundTxSighash,
26052
+ const cpfpRefundAggregate = await this.config.signer.aggregateFrost({
26053
+ message: cpfpRefundTxSighash,
25020
26054
  statechainSignatures: treeResp.rootNodeSignatureShares.refundTxSigningResult.signatureShares,
25021
26055
  statechainPublicKeys: treeResp.rootNodeSignatureShares.refundTxSigningResult.publicKeys,
25022
26056
  verifyingKey: treeResp.rootNodeSignatureShares.verifyingKey,
25023
26057
  statechainCommitments: treeResp.rootNodeSignatureShares.refundTxSigningResult.signingNonceCommitments,
25024
- selfCommitment: refundNonceCommitment,
26058
+ selfCommitment: cpfpRefundNonceCommitment,
25025
26059
  publicKey: signingPubKey,
25026
- selfSignature: refundSignature,
26060
+ selfSignature: cpfpRefundSignature,
25027
26061
  adaptorPubKey: new Uint8Array()
25028
26062
  });
25029
26063
  let finalizeResp;
25030
26064
  try {
25031
- finalizeResp = await sparkClient.finalize_node_signatures({
26065
+ finalizeResp = await sparkClient.finalize_node_signatures_v2({
25032
26066
  intent: 0 /* CREATION */,
25033
26067
  nodeSignatures: [
25034
26068
  {
25035
26069
  nodeId: treeResp.rootNodeSignatureShares.nodeId,
25036
- nodeTxSignature: rootAggregate,
25037
- refundTxSignature: refundAggregate
26070
+ nodeTxSignature: cpfpRootAggregate,
26071
+ refundTxSignature: cpfpRefundAggregate
25038
26072
  }
25039
26073
  ]
25040
26074
  });
@@ -25244,7 +26278,8 @@ var LightningService = class {
25244
26278
  let signingCommitments;
25245
26279
  try {
25246
26280
  signingCommitments = await sparkClient.get_signing_commitments({
25247
- nodeIds: leaves.map((leaf) => leaf.leaf.id)
26281
+ nodeIds: leaves.map((leaf) => leaf.leaf.id),
26282
+ count: 3
25248
26283
  });
25249
26284
  } catch (error) {
25250
26285
  throw new NetworkError(
@@ -25257,10 +26292,19 @@ var LightningService = class {
25257
26292
  error
25258
26293
  );
25259
26294
  }
25260
- const leafSigningJobs = await this.signingService.signRefunds(
26295
+ const {
26296
+ cpfpLeafSigningJobs,
26297
+ directLeafSigningJobs,
26298
+ directFromCpfpLeafSigningJobs
26299
+ } = await this.signingService.signRefunds(
25261
26300
  leaves,
25262
- signingCommitments.signingCommitments,
25263
- receiverIdentityPubkey
26301
+ receiverIdentityPubkey,
26302
+ signingCommitments.signingCommitments.slice(0, leaves.length),
26303
+ signingCommitments.signingCommitments.slice(
26304
+ leaves.length,
26305
+ 2 * leaves.length
26306
+ ),
26307
+ signingCommitments.signingCommitments.slice(2 * leaves.length)
25264
26308
  );
25265
26309
  const transferId = (0, import_uuidv73.uuidv7)();
25266
26310
  let bolt11String = "";
@@ -25297,7 +26341,7 @@ var LightningService = class {
25297
26341
  const reason = isInboundPayment ? 1 /* REASON_RECEIVE */ : 0 /* REASON_SEND */;
25298
26342
  let response;
25299
26343
  try {
25300
- response = await sparkClient.initiate_preimage_swap({
26344
+ response = await sparkClient.initiate_preimage_swap_v2({
25301
26345
  paymentHash,
25302
26346
  invoiceAmount: {
25303
26347
  invoiceAmountProof: {
@@ -25309,7 +26353,9 @@ var LightningService = class {
25309
26353
  transfer: {
25310
26354
  transferId,
25311
26355
  ownerIdentityPublicKey: await this.config.signer.getIdentityPublicKey(),
25312
- leavesToSend: leafSigningJobs,
26356
+ leavesToSend: cpfpLeafSigningJobs,
26357
+ directLeavesToSend: directLeafSigningJobs,
26358
+ directFromCpfpLeavesToSend: directFromCpfpLeafSigningJobs,
25313
26359
  receiverIdentityPublicKey: receiverIdentityPubkey,
25314
26360
  expiryTime: new Date(Date.now() + 2 * 60 * 1e3)
25315
26361
  },
@@ -28042,13 +29088,6 @@ function isTokenTransaction(tokenTransaction) {
28042
29088
  init_buffer();
28043
29089
  var import_utils17 = require("@noble/curves/abstract/utils");
28044
29090
  var import_btc_signer5 = require("@scure/btc-signer");
28045
- var INITIAL_TIME_LOCK3 = 2e3;
28046
- function maybeApplyFee2(amount) {
28047
- if (amount > BigInt(DEFAULT_FEE_SATS)) {
28048
- return amount - BigInt(DEFAULT_FEE_SATS);
28049
- }
28050
- return amount;
28051
- }
28052
29091
  var TreeCreationService = class {
28053
29092
  config;
28054
29093
  connectionManager;
@@ -28163,7 +29202,7 @@ var TreeCreationService = class {
28163
29202
  );
28164
29203
  let response;
28165
29204
  try {
28166
- response = await sparkClient.create_tree(request);
29205
+ response = await sparkClient.create_tree_v2(request);
28167
29206
  } catch (error) {
28168
29207
  throw new Error(`Error creating tree: ${error}`);
28169
29208
  }
@@ -28180,7 +29219,7 @@ var TreeCreationService = class {
28180
29219
  );
28181
29220
  let finalizeResp;
28182
29221
  try {
28183
- finalizeResp = await sparkClient.finalize_node_signatures({
29222
+ finalizeResp = await sparkClient.finalize_node_signatures_v2({
28184
29223
  nodeSignatures
28185
29224
  });
28186
29225
  } catch (error) {
@@ -28245,91 +29284,111 @@ var TreeCreationService = class {
28245
29284
  async buildChildCreationNode(node, parentTx, vout, network) {
28246
29285
  const internalCreationNode = {
28247
29286
  nodeTxSigningJob: void 0,
28248
- refundTxSigningJob: void 0,
28249
- children: [],
28250
29287
  directNodeTxSigningJob: void 0,
29288
+ refundTxSigningJob: void 0,
28251
29289
  directRefundTxSigningJob: void 0,
28252
- directFromCpfpRefundTxSigningJob: void 0
29290
+ directFromCpfpRefundTxSigningJob: void 0,
29291
+ children: []
28253
29292
  };
28254
- const tx = new import_btc_signer5.Transaction({ version: 3 });
28255
- tx.addInput({
28256
- txid: getTxId(parentTx),
28257
- index: vout
28258
- });
28259
29293
  const parentTxOut = parentTx.getOutput(vout);
28260
29294
  if (!parentTxOut?.script || !parentTxOut?.amount) {
28261
29295
  throw new Error("parentTxOut is undefined");
28262
29296
  }
28263
- tx.addOutput({
29297
+ const parentOutPoint = {
29298
+ txid: (0, import_utils17.hexToBytes)(getTxId(parentTx)),
29299
+ index: vout
29300
+ };
29301
+ const parentTxOutObj = {
28264
29302
  script: parentTxOut.script,
28265
29303
  amount: parentTxOut.amount
28266
- // maybeApplyFee(parentTxOut.amount),
28267
- });
28268
- tx.addOutput(getEphemeralAnchorOutput());
28269
- const signingNonceCommitment = await this.config.signer.getRandomSigningCommitment();
28270
- const signingJob = {
29304
+ };
29305
+ const { cpfpNodeTx, directNodeTx } = createNodeTxs(
29306
+ parentTxOutObj,
29307
+ parentOutPoint
29308
+ );
29309
+ const cpfpNodeSigningCommitment = await this.config.signer.getRandomSigningCommitment();
29310
+ const directNodeSigningCommitment = await this.config.signer.getRandomSigningCommitment();
29311
+ const cpfpNodeSigningJob = {
28271
29312
  signingPublicKey: node.signingPublicKey,
28272
- rawTx: tx.toBytes(),
28273
- signingNonceCommitment: signingNonceCommitment.commitment
29313
+ rawTx: cpfpNodeTx.toBytes(),
29314
+ signingNonceCommitment: cpfpNodeSigningCommitment.commitment
28274
29315
  };
28275
- internalCreationNode.nodeTxSigningCommitment = signingNonceCommitment;
28276
- internalCreationNode.nodeTxSigningJob = signingJob;
28277
- const sequence = 1 << 30 | INITIAL_TIME_LOCK3;
29316
+ const directNodeSigningJob = directNodeTx ? {
29317
+ signingPublicKey: node.signingPublicKey,
29318
+ rawTx: directNodeTx.toBytes(),
29319
+ signingNonceCommitment: directNodeSigningCommitment.commitment
29320
+ } : void 0;
29321
+ internalCreationNode.nodeTxSigningCommitment = cpfpNodeSigningCommitment;
29322
+ internalCreationNode.directNodeTxSigningCommitment = directNodeSigningCommitment;
29323
+ internalCreationNode.nodeTxSigningJob = cpfpNodeSigningJob;
29324
+ internalCreationNode.directNodeTxSigningJob = directNodeSigningJob;
29325
+ const sequence = INITIAL_SEQUENCE;
29326
+ const directSequence = INITIAL_DIRECT_SEQUENCE;
28278
29327
  const childCreationNode = {
28279
29328
  nodeTxSigningJob: void 0,
28280
- refundTxSigningJob: void 0,
28281
- children: [],
28282
29329
  directNodeTxSigningJob: void 0,
29330
+ refundTxSigningJob: void 0,
28283
29331
  directRefundTxSigningJob: void 0,
28284
- directFromCpfpRefundTxSigningJob: void 0
29332
+ directFromCpfpRefundTxSigningJob: void 0,
29333
+ children: []
28285
29334
  };
28286
- const childTx = new import_btc_signer5.Transaction({ version: 3 });
28287
- childTx.addInput({
28288
- txid: getTxId(tx),
28289
- index: 0,
28290
- sequence
28291
- });
28292
- childTx.addOutput({
28293
- script: parentTxOut.script,
28294
- amount: parentTxOut.amount
28295
- // maybeApplyFee(parentTxOut.amount),
28296
- });
28297
- childTx.addOutput(getEphemeralAnchorOutput());
28298
- const childSigningNonceCommitment = await this.config.signer.getRandomSigningCommitment();
28299
- const childSigningJob = {
29335
+ const [cpfpLeafTx, directLeafTx] = createLeafNodeTx(
29336
+ sequence,
29337
+ directSequence,
29338
+ { txid: (0, import_utils17.hexToBytes)(getTxId(cpfpNodeTx)), index: 0 },
29339
+ parentTxOutObj,
29340
+ true
29341
+ // shouldCalculateFee
29342
+ );
29343
+ const cpfpLeafSigningCommitment = await this.config.signer.getRandomSigningCommitment();
29344
+ const directLeafSigningCommitment = await this.config.signer.getRandomSigningCommitment();
29345
+ const cpfpLeafSigningJob = {
28300
29346
  signingPublicKey: node.signingPublicKey,
28301
- rawTx: childTx.toBytes(),
28302
- signingNonceCommitment: childSigningNonceCommitment.commitment
28303
- };
28304
- childCreationNode.nodeTxSigningCommitment = childSigningNonceCommitment;
28305
- childCreationNode.nodeTxSigningJob = childSigningJob;
28306
- const refundTx = new import_btc_signer5.Transaction({ version: 3 });
28307
- refundTx.addInput({
28308
- txid: getTxId(childTx),
28309
- index: 0,
28310
- sequence
28311
- });
28312
- const refundP2trAddress = getP2TRAddressFromPublicKey(
28313
- node.signingPublicKey,
29347
+ rawTx: cpfpLeafTx.toBytes(),
29348
+ signingNonceCommitment: cpfpLeafSigningCommitment.commitment
29349
+ };
29350
+ const directLeafSigningJob = {
29351
+ signingPublicKey: node.signingPublicKey,
29352
+ rawTx: directLeafTx.toBytes(),
29353
+ signingNonceCommitment: directLeafSigningCommitment.commitment
29354
+ };
29355
+ childCreationNode.nodeTxSigningCommitment = cpfpLeafSigningCommitment;
29356
+ childCreationNode.directNodeTxSigningCommitment = directLeafSigningCommitment;
29357
+ childCreationNode.nodeTxSigningJob = cpfpLeafSigningJob;
29358
+ childCreationNode.directNodeTxSigningJob = directLeafSigningJob;
29359
+ const { cpfpRefundTx, directRefundTx, directFromCpfpRefundTx } = createRefundTxs({
29360
+ sequence,
29361
+ directSequence,
29362
+ input: { txid: (0, import_utils17.hexToBytes)(getTxId(cpfpLeafTx)), index: 0 },
29363
+ directInput: { txid: (0, import_utils17.hexToBytes)(getTxId(directLeafTx)), index: 0 },
29364
+ amountSats: parentTxOut.amount,
29365
+ receivingPubkey: node.signingPublicKey,
28314
29366
  network
28315
- );
28316
- const refundAddress = (0, import_btc_signer5.Address)(getNetwork(network)).decode(
28317
- refundP2trAddress
28318
- );
28319
- const refundPkScript = import_btc_signer5.OutScript.encode(refundAddress);
28320
- refundTx.addOutput({
28321
- script: refundPkScript,
28322
- amount: maybeApplyFee2(parentTxOut.amount)
28323
29367
  });
28324
- refundTx.addOutput(getEphemeralAnchorOutput());
28325
- const refundSigningNonceCommitment = await this.config.signer.getRandomSigningCommitment();
28326
- const refundSigningJob = {
29368
+ const cpfpRefundSigningCommitment = await this.config.signer.getRandomSigningCommitment();
29369
+ const directRefundSigningCommitment = await this.config.signer.getRandomSigningCommitment();
29370
+ const directFromCpfpRefundSigningCommitment = await this.config.signer.getRandomSigningCommitment();
29371
+ const cpfpRefundSigningJob = {
28327
29372
  signingPublicKey: node.signingPublicKey,
28328
- rawTx: refundTx.toBytes(),
28329
- signingNonceCommitment: refundSigningNonceCommitment.commitment
29373
+ rawTx: cpfpRefundTx.toBytes(),
29374
+ signingNonceCommitment: cpfpRefundSigningCommitment.commitment
28330
29375
  };
28331
- childCreationNode.refundTxSigningCommitment = refundSigningNonceCommitment;
28332
- childCreationNode.refundTxSigningJob = refundSigningJob;
29376
+ const directRefundSigningJob = directRefundTx ? {
29377
+ signingPublicKey: node.signingPublicKey,
29378
+ rawTx: directRefundTx.toBytes(),
29379
+ signingNonceCommitment: directRefundSigningCommitment.commitment
29380
+ } : void 0;
29381
+ const directFromCpfpRefundSigningJob = directFromCpfpRefundTx ? {
29382
+ signingPublicKey: node.signingPublicKey,
29383
+ rawTx: directFromCpfpRefundTx.toBytes(),
29384
+ signingNonceCommitment: directFromCpfpRefundSigningCommitment.commitment
29385
+ } : void 0;
29386
+ childCreationNode.refundTxSigningCommitment = cpfpRefundSigningCommitment;
29387
+ childCreationNode.directRefundTxSigningCommitment = directRefundSigningCommitment;
29388
+ childCreationNode.directFromCpfpRefundTxSigningCommitment = directFromCpfpRefundSigningCommitment;
29389
+ childCreationNode.refundTxSigningJob = cpfpRefundSigningJob;
29390
+ childCreationNode.directRefundTxSigningJob = directRefundSigningJob;
29391
+ childCreationNode.directFromCpfpRefundTxSigningJob = directFromCpfpRefundSigningJob;
28333
29392
  internalCreationNode.children.push(childCreationNode);
28334
29393
  return internalCreationNode;
28335
29394
  }
@@ -28338,11 +29397,7 @@ var TreeCreationService = class {
28338
29397
  if (!parentTxOutput?.script || !parentTxOutput?.amount) {
28339
29398
  throw new Error("parentTxOutput is undefined");
28340
29399
  }
28341
- const rootNodeTx = new import_btc_signer5.Transaction({ version: 3 });
28342
- rootNodeTx.addInput({
28343
- txid: getTxId(parentTx),
28344
- index: vout
28345
- });
29400
+ const childTxOuts = [];
28346
29401
  for (let i = 0; i < root.children.length; i++) {
28347
29402
  const child = root.children[i];
28348
29403
  if (!child || !child.address) {
@@ -28350,28 +29405,41 @@ var TreeCreationService = class {
28350
29405
  }
28351
29406
  const childAddress = (0, import_btc_signer5.Address)(getNetwork(network)).decode(child.address);
28352
29407
  const childPkScript = import_btc_signer5.OutScript.encode(childAddress);
28353
- rootNodeTx.addOutput({
29408
+ childTxOuts.push({
28354
29409
  script: childPkScript,
28355
29410
  amount: parentTxOutput.amount / 2n
28356
- // feeAdjustedAmount / 2n,
28357
29411
  });
28358
29412
  }
28359
- rootNodeTx.addOutput(getEphemeralAnchorOutput());
28360
- const rootNodeSigningCommitment = await this.config.signer.getRandomSigningCommitment();
28361
- const rootNodeSigningJob = {
29413
+ const parentOutPoint = {
29414
+ txid: (0, import_utils17.hexToBytes)(getTxId(parentTx)),
29415
+ index: vout
29416
+ };
29417
+ const [cpfpSplitTx, directSplitTx] = createSplitTx(
29418
+ parentOutPoint,
29419
+ childTxOuts
29420
+ );
29421
+ const cpfpSplitSigningCommitment = await this.config.signer.getRandomSigningCommitment();
29422
+ const directSplitSigningCommitment = await this.config.signer.getRandomSigningCommitment();
29423
+ const cpfpSplitSigningJob = {
28362
29424
  signingPublicKey: root.signingPublicKey,
28363
- rawTx: rootNodeTx.toBytes(),
28364
- signingNonceCommitment: rootNodeSigningCommitment.commitment
29425
+ rawTx: cpfpSplitTx.toBytes(),
29426
+ signingNonceCommitment: cpfpSplitSigningCommitment.commitment
29427
+ };
29428
+ const directSplitSigningJob = {
29429
+ signingPublicKey: root.signingPublicKey,
29430
+ rawTx: directSplitTx.toBytes(),
29431
+ signingNonceCommitment: directSplitSigningCommitment.commitment
28365
29432
  };
28366
29433
  const rootCreationNode = {
28367
- nodeTxSigningJob: rootNodeSigningJob,
29434
+ nodeTxSigningJob: cpfpSplitSigningJob,
29435
+ directNodeTxSigningJob: directSplitSigningJob,
28368
29436
  refundTxSigningJob: void 0,
28369
- children: [],
28370
- directNodeTxSigningJob: void 0,
28371
29437
  directRefundTxSigningJob: void 0,
28372
- directFromCpfpRefundTxSigningJob: void 0
29438
+ directFromCpfpRefundTxSigningJob: void 0,
29439
+ children: []
28373
29440
  };
28374
- rootCreationNode.nodeTxSigningCommitment = rootNodeSigningCommitment;
29441
+ rootCreationNode.nodeTxSigningCommitment = cpfpSplitSigningCommitment;
29442
+ rootCreationNode.directNodeTxSigningCommitment = directSplitSigningCommitment;
28375
29443
  const leftChild = root.children[0];
28376
29444
  const rightChild = root.children[1];
28377
29445
  if (!leftChild || !rightChild) {
@@ -28379,13 +29447,15 @@ var TreeCreationService = class {
28379
29447
  }
28380
29448
  const leftChildCreationNode = await this.buildChildCreationNode(
28381
29449
  leftChild,
28382
- rootNodeTx,
29450
+ cpfpSplitTx,
29451
+ // Use CPFP version for children
28383
29452
  0,
28384
29453
  network
28385
29454
  );
28386
29455
  const rightChildCreationNode = await this.buildChildCreationNode(
28387
29456
  rightChild,
28388
- rootNodeTx,
29457
+ cpfpSplitTx,
29458
+ // Use CPFP version for children
28389
29459
  1,
28390
29460
  network
28391
29461
  );
@@ -28394,19 +29464,19 @@ var TreeCreationService = class {
28394
29464
  return rootCreationNode;
28395
29465
  }
28396
29466
  async signNodeCreation(parentTx, vout, internalNode, creationNode, creationResponseNode) {
28397
- if (!creationNode.nodeTxSigningJob?.signingPublicKey || !internalNode.verificationKey) {
29467
+ if (!creationNode.nodeTxSigningJob?.signingPublicKey || !creationNode.directNodeTxSigningJob?.signingPublicKey || !internalNode.verificationKey) {
28398
29468
  throw new Error("signingPublicKey or verificationKey is undefined");
28399
29469
  }
28400
29470
  const parentTxOutput = parentTx.getOutput(vout);
28401
29471
  if (!parentTxOutput) {
28402
29472
  throw new Error("parentTxOutput is undefined");
28403
29473
  }
28404
- const tx = getTxFromRawTxBytes(creationNode.nodeTxSigningJob.rawTx);
28405
- const txSighash = getSigHashFromTx(tx, 0, parentTxOutput);
28406
- let nodeTxSignature = new Uint8Array();
29474
+ const cpfpNodeTx = getTxFromRawTxBytes(creationNode.nodeTxSigningJob.rawTx);
29475
+ const cpfpNodeTxSighash = getSigHashFromTx(cpfpNodeTx, 0, parentTxOutput);
29476
+ let cpfpNodeTxSignature = new Uint8Array();
28407
29477
  if (creationNode.nodeTxSigningCommitment) {
28408
- const userSignature = await this.config.signer.signFrost({
28409
- message: txSighash,
29478
+ const cpfpUserSignature = await this.config.signer.signFrost({
29479
+ message: cpfpNodeTxSighash,
28410
29480
  publicKey: creationNode.nodeTxSigningJob.signingPublicKey,
28411
29481
  keyDerivation: {
28412
29482
  type: "leaf" /* LEAF */,
@@ -28416,30 +29486,84 @@ var TreeCreationService = class {
28416
29486
  statechainCommitments: creationResponseNode.nodeTxSigningResult?.signingNonceCommitments,
28417
29487
  verifyingKey: internalNode.verificationKey
28418
29488
  });
28419
- nodeTxSignature = await this.config.signer.aggregateFrost({
28420
- message: txSighash,
29489
+ cpfpNodeTxSignature = await this.config.signer.aggregateFrost({
29490
+ message: cpfpNodeTxSighash,
28421
29491
  statechainSignatures: creationResponseNode.nodeTxSigningResult?.signatureShares,
28422
29492
  statechainPublicKeys: creationResponseNode.nodeTxSigningResult?.publicKeys,
28423
29493
  verifyingKey: internalNode.verificationKey,
28424
29494
  statechainCommitments: creationResponseNode.nodeTxSigningResult?.signingNonceCommitments,
28425
29495
  selfCommitment: creationNode.nodeTxSigningCommitment,
28426
- selfSignature: userSignature,
29496
+ selfSignature: cpfpUserSignature,
28427
29497
  publicKey: internalNode.signingPublicKey
28428
29498
  });
28429
29499
  }
28430
- let refundTxSignature = new Uint8Array();
28431
- if (creationNode.refundTxSigningCommitment) {
28432
- const rawTx = creationNode.refundTxSigningJob?.rawTx;
28433
- if (!rawTx) {
28434
- throw new Error("rawTx is undefined");
28435
- }
28436
- if (!creationNode.refundTxSigningJob?.signingPublicKey) {
28437
- throw new Error("signingPublicKey is undefined");
28438
- }
28439
- const refundTx = getTxFromRawTxBytes(rawTx);
28440
- const refundTxSighash = getSigHashFromTx(refundTx, 0, parentTxOutput);
28441
- const refundSigningResponse = await this.config.signer.signFrost({
28442
- message: refundTxSighash,
29500
+ const directNodeTx = getTxFromRawTxBytes(
29501
+ creationNode.directNodeTxSigningJob.rawTx
29502
+ );
29503
+ const directNodeTxSighash = getSigHashFromTx(
29504
+ directNodeTx,
29505
+ 0,
29506
+ parentTxOutput
29507
+ );
29508
+ let directNodeTxSignature = new Uint8Array();
29509
+ if (creationNode.directNodeTxSigningCommitment) {
29510
+ const directUserSignature = await this.config.signer.signFrost({
29511
+ message: directNodeTxSighash,
29512
+ publicKey: creationNode.directNodeTxSigningJob.signingPublicKey,
29513
+ keyDerivation: {
29514
+ type: "leaf" /* LEAF */,
29515
+ path: creationResponseNode.nodeId
29516
+ },
29517
+ selfCommitment: creationNode.directNodeTxSigningCommitment,
29518
+ statechainCommitments: creationResponseNode.directNodeTxSigningResult?.signingNonceCommitments,
29519
+ verifyingKey: internalNode.verificationKey
29520
+ });
29521
+ directNodeTxSignature = await this.config.signer.aggregateFrost({
29522
+ message: directNodeTxSighash,
29523
+ statechainSignatures: creationResponseNode.directNodeTxSigningResult?.signatureShares,
29524
+ statechainPublicKeys: creationResponseNode.directNodeTxSigningResult?.publicKeys,
29525
+ verifyingKey: internalNode.verificationKey,
29526
+ statechainCommitments: creationResponseNode.directNodeTxSigningResult?.signingNonceCommitments,
29527
+ selfCommitment: creationNode.directNodeTxSigningCommitment,
29528
+ selfSignature: directUserSignature,
29529
+ publicKey: internalNode.signingPublicKey
29530
+ });
29531
+ }
29532
+ let cpfpRefundTxSignature = new Uint8Array();
29533
+ let directRefundTxSignature = new Uint8Array();
29534
+ let directFromCpfpRefundTxSignature = new Uint8Array();
29535
+ if (creationNode.refundTxSigningCommitment && creationNode.directRefundTxSigningCommitment && creationNode.directFromCpfpRefundTxSigningCommitment) {
29536
+ const rawCpfpRefundTx = creationNode.refundTxSigningJob?.rawTx;
29537
+ const rawDirectRefundTx = creationNode.directRefundTxSigningJob?.rawTx;
29538
+ const rawDirectFromCpfpRefundTx = creationNode.directFromCpfpRefundTxSigningJob?.rawTx;
29539
+ if (!rawCpfpRefundTx || !rawDirectRefundTx || !rawDirectFromCpfpRefundTx) {
29540
+ throw new Error("refund transaction rawTx is undefined");
29541
+ }
29542
+ if (!creationNode.refundTxSigningJob?.signingPublicKey || !creationNode.directRefundTxSigningJob?.signingPublicKey || !creationNode.directFromCpfpRefundTxSigningJob?.signingPublicKey) {
29543
+ throw new Error("refund transaction signingPublicKey is undefined");
29544
+ }
29545
+ const cpfpRefundTx = getTxFromRawTxBytes(rawCpfpRefundTx);
29546
+ const directRefundTx = getTxFromRawTxBytes(rawDirectRefundTx);
29547
+ const directFromCpfpRefundTx = getTxFromRawTxBytes(
29548
+ rawDirectFromCpfpRefundTx
29549
+ );
29550
+ const cpfpRefundTxSighash = getSigHashFromTx(
29551
+ cpfpRefundTx,
29552
+ 0,
29553
+ cpfpNodeTx.getOutput(0)
29554
+ );
29555
+ const directRefundTxSighash = getSigHashFromTx(
29556
+ directRefundTx,
29557
+ 0,
29558
+ directNodeTx.getOutput(0)
29559
+ );
29560
+ const directFromCpfpRefundTxSighash = getSigHashFromTx(
29561
+ directFromCpfpRefundTx,
29562
+ 0,
29563
+ cpfpNodeTx.getOutput(0)
29564
+ );
29565
+ const cpfpRefundUserSignature = await this.config.signer.signFrost({
29566
+ message: cpfpRefundTxSighash,
28443
29567
  publicKey: creationNode.refundTxSigningJob.signingPublicKey,
28444
29568
  keyDerivation: {
28445
29569
  type: "leaf" /* LEAF */,
@@ -28449,27 +29573,69 @@ var TreeCreationService = class {
28449
29573
  statechainCommitments: creationResponseNode.refundTxSigningResult?.signingNonceCommitments,
28450
29574
  verifyingKey: internalNode.verificationKey
28451
29575
  });
28452
- refundTxSignature = await this.config.signer.aggregateFrost({
28453
- message: refundTxSighash,
29576
+ cpfpRefundTxSignature = await this.config.signer.aggregateFrost({
29577
+ message: cpfpRefundTxSighash,
28454
29578
  statechainSignatures: creationResponseNode.refundTxSigningResult?.signatureShares,
28455
29579
  statechainPublicKeys: creationResponseNode.refundTxSigningResult?.publicKeys,
28456
29580
  verifyingKey: internalNode.verificationKey,
28457
29581
  statechainCommitments: creationResponseNode.refundTxSigningResult?.signingNonceCommitments,
28458
29582
  selfCommitment: creationNode.refundTxSigningCommitment,
28459
- selfSignature: refundSigningResponse,
29583
+ selfSignature: cpfpRefundUserSignature,
29584
+ publicKey: internalNode.signingPublicKey
29585
+ });
29586
+ const keyDerivation = {
29587
+ type: "leaf" /* LEAF */,
29588
+ path: creationResponseNode.nodeId
29589
+ };
29590
+ const directRefundUserSignature = await this.config.signer.signFrost({
29591
+ message: directRefundTxSighash,
29592
+ publicKey: creationNode.directRefundTxSigningJob.signingPublicKey,
29593
+ keyDerivation,
29594
+ selfCommitment: creationNode.directRefundTxSigningCommitment,
29595
+ statechainCommitments: creationResponseNode.directRefundTxSigningResult?.signingNonceCommitments,
29596
+ verifyingKey: internalNode.verificationKey
29597
+ });
29598
+ directRefundTxSignature = await this.config.signer.aggregateFrost({
29599
+ message: directRefundTxSighash,
29600
+ statechainSignatures: creationResponseNode.directRefundTxSigningResult?.signatureShares,
29601
+ statechainPublicKeys: creationResponseNode.directRefundTxSigningResult?.publicKeys,
29602
+ verifyingKey: internalNode.verificationKey,
29603
+ statechainCommitments: creationResponseNode.directRefundTxSigningResult?.signingNonceCommitments,
29604
+ selfCommitment: creationNode.directRefundTxSigningCommitment,
29605
+ selfSignature: directRefundUserSignature,
28460
29606
  publicKey: internalNode.signingPublicKey
28461
29607
  });
29608
+ const directFromCpfpRefundUserSignature = await this.config.signer.signFrost({
29609
+ message: directFromCpfpRefundTxSighash,
29610
+ publicKey: creationNode.directFromCpfpRefundTxSigningJob.signingPublicKey,
29611
+ keyDerivation,
29612
+ selfCommitment: creationNode.directFromCpfpRefundTxSigningCommitment,
29613
+ statechainCommitments: creationResponseNode.directFromCpfpRefundTxSigningResult?.signingNonceCommitments,
29614
+ verifyingKey: internalNode.verificationKey
29615
+ });
29616
+ directFromCpfpRefundTxSignature = await this.config.signer.aggregateFrost(
29617
+ {
29618
+ message: directFromCpfpRefundTxSighash,
29619
+ statechainSignatures: creationResponseNode.directFromCpfpRefundTxSigningResult?.signatureShares,
29620
+ statechainPublicKeys: creationResponseNode.directFromCpfpRefundTxSigningResult?.publicKeys,
29621
+ verifyingKey: internalNode.verificationKey,
29622
+ statechainCommitments: creationResponseNode.directFromCpfpRefundTxSigningResult?.signingNonceCommitments,
29623
+ selfCommitment: creationNode.directFromCpfpRefundTxSigningCommitment,
29624
+ selfSignature: directFromCpfpRefundUserSignature,
29625
+ publicKey: internalNode.signingPublicKey
29626
+ }
29627
+ );
28462
29628
  }
28463
29629
  return {
28464
- tx,
29630
+ tx: cpfpNodeTx,
29631
+ // Return CPFP version for children
28465
29632
  signature: {
28466
29633
  nodeId: creationResponseNode.nodeId,
28467
- nodeTxSignature,
28468
- refundTxSignature,
28469
- // TODO: Add direct refund signature
28470
- directNodeTxSignature: new Uint8Array(),
28471
- directRefundTxSignature: new Uint8Array(),
28472
- directFromCpfpRefundTxSignature: new Uint8Array()
29634
+ nodeTxSignature: cpfpNodeTxSignature,
29635
+ directNodeTxSignature,
29636
+ refundTxSignature: cpfpRefundTxSignature,
29637
+ directRefundTxSignature,
29638
+ directFromCpfpRefundTxSignature
28473
29639
  }
28474
29640
  };
28475
29641
  }
@@ -28559,13 +29725,24 @@ function applyAdaptorToSignature(pubkey, hash, signature, adaptorPrivateKeyBytes
28559
29725
  const adaptorPrivateKey = (0, import_utils18.bytesToNumberBE)(adaptorPrivateKeyBytes);
28560
29726
  const newS = (0, import_modular.mod)(sBigInt + adaptorPrivateKey, import_secp256k113.secp256k1.CURVE.n);
28561
29727
  const newSig = new Uint8Array([...r, ...(0, import_utils18.numberToBytesBE)(newS, 32)]);
28562
- if (import_secp256k113.schnorr.verify(newSig, hash, pubkey)) {
28563
- return newSig;
29728
+ try {
29729
+ if (import_secp256k113.schnorr.verify(newSig, hash, pubkey)) {
29730
+ return newSig;
29731
+ }
29732
+ } catch (e) {
29733
+ console.error("[applyAdaptorToSignature] Addition verification failed:", e);
28564
29734
  }
28565
29735
  const altS = (0, import_modular.mod)(sBigInt - adaptorPrivateKey, import_secp256k113.secp256k1.CURVE.n);
28566
29736
  const altSig = new Uint8Array([...r, ...(0, import_utils18.numberToBytesBE)(altS, 32)]);
28567
- if (import_secp256k113.schnorr.verify(altSig, hash, pubkey)) {
28568
- return altSig;
29737
+ try {
29738
+ if (import_secp256k113.schnorr.verify(altSig, hash, pubkey)) {
29739
+ return altSig;
29740
+ }
29741
+ } catch (e) {
29742
+ console.error(
29743
+ "[applyAdaptorToSignature] Subtraction verification failed:",
29744
+ e
29745
+ );
28569
29746
  }
28570
29747
  throw new Error("Cannot apply adaptor to signature");
28571
29748
  }
@@ -28654,8 +29831,45 @@ var SigningService = class {
28654
29831
  constructor(config) {
28655
29832
  this.config = config;
28656
29833
  }
28657
- async signRefunds(leaves, signingCommitments, receiverIdentityPubkey) {
29834
+ async signRefundsInternal(refundTx, sighash, leaf, signingCommitments) {
28658
29835
  const leafSigningJobs = [];
29836
+ const signingCommitment = await this.config.signer.getRandomSigningCommitment();
29837
+ if (!signingCommitments) {
29838
+ throw new ValidationError("Invalid signing commitments", {
29839
+ field: "signingNonceCommitments",
29840
+ value: signingCommitments,
29841
+ expected: "Non-null signing commitments"
29842
+ });
29843
+ }
29844
+ const signingResult = await this.config.signer.signFrost({
29845
+ message: sighash,
29846
+ keyDerivation: leaf.keyDerivation,
29847
+ publicKey: await this.config.signer.getPublicKeyFromDerivation(
29848
+ leaf.keyDerivation
29849
+ ),
29850
+ selfCommitment: signingCommitment,
29851
+ statechainCommitments: signingCommitments,
29852
+ adaptorPubKey: new Uint8Array(),
29853
+ verifyingKey: leaf.leaf.verifyingPublicKey
29854
+ });
29855
+ leafSigningJobs.push({
29856
+ leafId: leaf.leaf.id,
29857
+ signingPublicKey: await this.config.signer.getPublicKeyFromDerivation(
29858
+ leaf.keyDerivation
29859
+ ),
29860
+ rawTx: refundTx.toBytes(),
29861
+ signingNonceCommitment: signingCommitment.commitment,
29862
+ userSignature: signingResult,
29863
+ signingCommitments: {
29864
+ signingCommitments
29865
+ }
29866
+ });
29867
+ return leafSigningJobs;
29868
+ }
29869
+ async signRefunds(leaves, receiverIdentityPubkey, cpfpSigningCommitments, directSigningCommitments, directFromCpfpSigningCommitments) {
29870
+ const cpfpLeafSigningJobs = [];
29871
+ const directLeafSigningJobs = [];
29872
+ const directFromCpfpLeafSigningJobs = [];
28659
29873
  for (let i = 0; i < leaves.length; i++) {
28660
29874
  const leaf = leaves[i];
28661
29875
  if (!leaf?.leaf) {
@@ -28666,14 +29880,20 @@ var SigningService = class {
28666
29880
  });
28667
29881
  }
28668
29882
  const nodeTx = getTxFromRawTxBytes(leaf.leaf.nodeTx);
28669
- const nodeOutPoint = {
29883
+ const cpfpNodeOutPoint = {
28670
29884
  txid: (0, import_utils19.hexToBytes)(getTxId(nodeTx)),
28671
29885
  index: 0
28672
29886
  };
28673
29887
  const currRefundTx = getTxFromRawTxBytes(leaf.leaf.refundTx);
28674
- const { nextSequence } = getNextTransactionSequence(
28675
- currRefundTx.getInput(0).sequence
28676
- );
29888
+ const sequence = currRefundTx.getInput(0).sequence;
29889
+ if (!sequence) {
29890
+ throw new ValidationError("Invalid refund transaction", {
29891
+ field: "sequence",
29892
+ value: currRefundTx.getInput(0),
29893
+ expected: "Non-null sequence"
29894
+ });
29895
+ }
29896
+ const { nextSequence, nextDirectSequence } = getNextTransactionSequence(sequence);
28677
29897
  const amountSats = currRefundTx.getOutput(0).amount;
28678
29898
  if (amountSats === void 0) {
28679
29899
  throw new ValidationError("Invalid refund transaction", {
@@ -28682,48 +29902,90 @@ var SigningService = class {
28682
29902
  expected: "Non-null amount"
28683
29903
  });
28684
29904
  }
28685
- const refundTx = createRefundTx(
28686
- nextSequence,
28687
- nodeOutPoint,
29905
+ let directNodeTx;
29906
+ let directNodeOutPoint;
29907
+ if (leaf.leaf.directTx.length > 0) {
29908
+ directNodeTx = getTxFromRawTxBytes(leaf.leaf.directTx);
29909
+ directNodeOutPoint = {
29910
+ txid: (0, import_utils19.hexToBytes)(getTxId(directNodeTx)),
29911
+ index: 0
29912
+ };
29913
+ }
29914
+ const { cpfpRefundTx, directRefundTx, directFromCpfpRefundTx } = createRefundTxs({
29915
+ sequence: nextSequence,
29916
+ directSequence: nextDirectSequence,
29917
+ input: cpfpNodeOutPoint,
29918
+ directInput: directNodeOutPoint,
28688
29919
  amountSats,
28689
- receiverIdentityPubkey,
28690
- this.config.getNetwork()
29920
+ receivingPubkey: receiverIdentityPubkey,
29921
+ network: this.config.getNetwork()
29922
+ });
29923
+ const refundSighash = getSigHashFromTx(
29924
+ cpfpRefundTx,
29925
+ 0,
29926
+ nodeTx.getOutput(0)
28691
29927
  );
28692
- const sighash = getSigHashFromTx(refundTx, 0, nodeTx.getOutput(0));
28693
- const signingCommitment = await this.config.signer.getRandomSigningCommitment();
28694
- const signingNonceCommitments = signingCommitments[i]?.signingNonceCommitments;
28695
- if (!signingNonceCommitments) {
28696
- throw new ValidationError("Invalid signing commitments", {
28697
- field: "signingNonceCommitments",
28698
- value: signingCommitments[i],
28699
- expected: "Non-null signing nonce commitments"
28700
- });
29928
+ const signingJobs = await this.signRefundsInternal(
29929
+ cpfpRefundTx,
29930
+ refundSighash,
29931
+ leaf,
29932
+ cpfpSigningCommitments[i]?.signingNonceCommitments
29933
+ );
29934
+ cpfpLeafSigningJobs.push(...signingJobs);
29935
+ if (directRefundTx) {
29936
+ if (!directNodeTx) {
29937
+ throw new ValidationError(
29938
+ "Direct node transaction undefined while direct refund transaction is defined",
29939
+ {
29940
+ field: "directNodeTx",
29941
+ value: directNodeTx,
29942
+ expected: "Non-null direct node transaction"
29943
+ }
29944
+ );
29945
+ }
29946
+ const refundSighash2 = getSigHashFromTx(
29947
+ directRefundTx,
29948
+ 0,
29949
+ directNodeTx.getOutput(0)
29950
+ );
29951
+ const signingJobs2 = await this.signRefundsInternal(
29952
+ directRefundTx,
29953
+ refundSighash2,
29954
+ leaf,
29955
+ directSigningCommitments[i]?.signingNonceCommitments
29956
+ );
29957
+ directLeafSigningJobs.push(...signingJobs2);
28701
29958
  }
28702
- const signingResult = await this.config.signer.signFrost({
28703
- message: sighash,
28704
- keyDerivation: leaf.keyDerivation,
28705
- publicKey: await this.config.signer.getPublicKeyFromDerivation(
28706
- leaf.keyDerivation
28707
- ),
28708
- selfCommitment: signingCommitment,
28709
- statechainCommitments: signingNonceCommitments,
28710
- adaptorPubKey: new Uint8Array(),
28711
- verifyingKey: leaf.leaf.verifyingPublicKey
28712
- });
28713
- leafSigningJobs.push({
28714
- leafId: leaf.leaf.id,
28715
- signingPublicKey: await this.config.signer.getPublicKeyFromDerivation(
28716
- leaf.keyDerivation
28717
- ),
28718
- rawTx: refundTx.toBytes(),
28719
- signingNonceCommitment: signingCommitment.commitment,
28720
- userSignature: signingResult,
28721
- signingCommitments: {
28722
- signingCommitments: signingNonceCommitments
29959
+ if (directFromCpfpRefundTx) {
29960
+ if (!directNodeTx) {
29961
+ throw new ValidationError(
29962
+ "Direct node transaction undefined while direct from CPFP refund transaction is defined",
29963
+ {
29964
+ field: "directNodeTx",
29965
+ value: directNodeTx,
29966
+ expected: "Non-null direct node transaction"
29967
+ }
29968
+ );
28723
29969
  }
28724
- });
29970
+ const refundSighash2 = getSigHashFromTx(
29971
+ directFromCpfpRefundTx,
29972
+ 0,
29973
+ nodeTx.getOutput(0)
29974
+ );
29975
+ const signingJobs2 = await this.signRefundsInternal(
29976
+ directFromCpfpRefundTx,
29977
+ refundSighash2,
29978
+ leaf,
29979
+ directFromCpfpSigningCommitments[i]?.signingNonceCommitments
29980
+ );
29981
+ directFromCpfpLeafSigningJobs.push(...signingJobs2);
29982
+ }
28725
29983
  }
28726
- return leafSigningJobs;
29984
+ return {
29985
+ cpfpLeafSigningJobs,
29986
+ directLeafSigningJobs,
29987
+ directFromCpfpLeafSigningJobs
29988
+ };
28727
29989
  }
28728
29990
  };
28729
29991
 
@@ -28731,9 +29993,32 @@ var SigningService = class {
28731
29993
  init_buffer();
28732
29994
  var import_utils20 = require("@noble/curves/abstract/utils");
28733
29995
  var import_secp256k114 = require("@noble/curves/secp256k1");
28734
- var btc4 = __toESM(require("@scure/btc-signer"), 1);
29996
+ var btc3 = __toESM(require("@scure/btc-signer"), 1);
28735
29997
  var import_btc_signer6 = require("@scure/btc-signer");
28736
29998
  var import_utils21 = require("@scure/btc-signer/utils");
29999
+
30000
+ // src/utils/fetch.ts
30001
+ init_buffer();
30002
+ var fetchImpl = typeof window !== "undefined" && window.fetch ? window.fetch.bind(window) : globalThis.fetch ? globalThis.fetch : null;
30003
+ var Headers = globalThis.Headers ?? null;
30004
+ var getFetch = () => {
30005
+ if (!fetchImpl) {
30006
+ throw new Error(
30007
+ "Fetch implementation is not set. Please set it using setFetch()."
30008
+ );
30009
+ }
30010
+ if (!Headers) {
30011
+ throw new Error(
30012
+ "Headers implementation is not set. Please set it using setFetch()."
30013
+ );
30014
+ }
30015
+ return {
30016
+ fetch: fetchImpl,
30017
+ Headers
30018
+ };
30019
+ };
30020
+
30021
+ // src/tests/utils/test-faucet.ts
28737
30022
  var STATIC_FAUCET_KEY = (0, import_utils20.hexToBytes)(
28738
30023
  "deadbeef1337cafe4242424242424242deadbeef1337cafe4242424242424242"
28739
30024
  );
@@ -28877,7 +30162,7 @@ var BitcoinFaucet = class _BitcoinFaucet {
28877
30162
  }
28878
30163
  async sendFaucetCoinToP2WPKHAddress(pubKey) {
28879
30164
  const sendToPubKeyTx = new import_btc_signer6.Transaction();
28880
- const p2wpkhAddress = btc4.p2wpkh(pubKey, getNetwork(4 /* LOCAL */)).address;
30165
+ const p2wpkhAddress = btc3.p2wpkh(pubKey, getNetwork(4 /* LOCAL */)).address;
28881
30166
  if (!p2wpkhAddress) {
28882
30167
  throw new Error("Invalid P2WPKH address");
28883
30168
  }
@@ -28933,12 +30218,13 @@ var BitcoinFaucet = class _BitcoinFaucet {
28933
30218
  }
28934
30219
  async call(method, params) {
28935
30220
  try {
28936
- const response = await fetch(this.url, {
30221
+ const { fetch: fetch2, Headers: Headers2 } = getFetch();
30222
+ const response = await fetch2(this.url, {
28937
30223
  method: "POST",
28938
- headers: {
30224
+ headers: new Headers2({
28939
30225
  "Content-Type": "application/json",
28940
30226
  Authorization: "Basic " + btoa(`${this.username}:${this.password}`)
28941
- },
30227
+ }),
28942
30228
  body: JSON.stringify({
28943
30229
  jsonrpc: "1.0",
28944
30230
  id: "spark-js",
@@ -29313,31 +30599,37 @@ var SparkWallet = class _SparkWallet extends import_eventemitter3.EventEmitter {
29313
30599
  }
29314
30600
  }
29315
30601
  async getLeaves(isBalanceCheck = false) {
29316
- const leaves = await this.queryNodes({
29317
- source: {
29318
- $case: "ownerIdentityPubkey",
29319
- ownerIdentityPubkey: await this.config.signer.getIdentityPublicKey()
29320
- },
29321
- includeParents: false,
29322
- network: NetworkToProto[this.config.getNetwork()]
29323
- });
30602
+ const operatorToLeaves = /* @__PURE__ */ new Map();
30603
+ const ownerIdentityPubkey = await this.config.signer.getIdentityPublicKey();
30604
+ let signingOperators = Object.entries(this.config.getSigningOperators());
30605
+ if (isBalanceCheck) {
30606
+ signingOperators = signingOperators.filter(
30607
+ ([id, _]) => id === this.config.getCoordinatorIdentifier()
30608
+ );
30609
+ }
30610
+ await Promise.all(
30611
+ signingOperators.map(async ([id, operator]) => {
30612
+ const leaves2 = await this.queryNodes(
30613
+ {
30614
+ source: {
30615
+ $case: "ownerIdentityPubkey",
30616
+ ownerIdentityPubkey
30617
+ },
30618
+ includeParents: false,
30619
+ network: NetworkToProto[this.config.getNetwork()]
30620
+ },
30621
+ operator.address
30622
+ );
30623
+ operatorToLeaves.set(id, leaves2);
30624
+ })
30625
+ );
30626
+ const leaves = operatorToLeaves.get(
30627
+ this.config.getCoordinatorIdentifier()
30628
+ );
29324
30629
  const leavesToIgnore = /* @__PURE__ */ new Set();
29325
30630
  if (!isBalanceCheck) {
29326
- for (const [id, operator] of Object.entries(
29327
- this.config.getSigningOperators()
29328
- )) {
30631
+ for (const [id, operatorLeaves] of operatorToLeaves) {
29329
30632
  if (id !== this.config.getCoordinatorIdentifier()) {
29330
- const operatorLeaves = await this.queryNodes(
29331
- {
29332
- source: {
29333
- $case: "ownerIdentityPubkey",
29334
- ownerIdentityPubkey: await this.config.signer.getIdentityPublicKey()
29335
- },
29336
- includeParents: false,
29337
- network: NetworkToProto[this.config.getNetwork()]
29338
- },
29339
- operator.address
29340
- );
29341
30633
  for (const [nodeId, leaf] of Object.entries(leaves.nodes)) {
29342
30634
  const operatorLeaf = operatorLeaves.nodes[nodeId];
29343
30635
  if (!operatorLeaf) {
@@ -29778,21 +31070,68 @@ var SparkWallet = class _SparkWallet extends import_eventemitter3.EventEmitter {
29778
31070
  }
29779
31071
  }))
29780
31072
  );
29781
- const { transfer, signatureMap } = await this.transferService.startSwapSignRefund(
31073
+ const {
31074
+ transfer,
31075
+ signatureMap,
31076
+ directSignatureMap,
31077
+ directFromCpfpSignatureMap
31078
+ } = await this.transferService.startSwapSignRefund(
29782
31079
  leafKeyTweaks,
29783
31080
  (0, import_utils23.hexToBytes)(this.config.getSspIdentityPublicKey()),
29784
31081
  new Date(Date.now() + 2 * 60 * 1e3)
29785
31082
  );
29786
31083
  try {
29787
31084
  if (!transfer.leaves[0]?.leaf) {
31085
+ console.error("[processSwapBatch] First leaf is missing");
29788
31086
  throw new Error("Failed to get leaf");
29789
31087
  }
29790
- const refundSignature = signatureMap.get(transfer.leaves[0].leaf.id);
29791
- if (!refundSignature) {
29792
- throw new Error("Failed to get refund signature");
31088
+ const cpfpRefundSignature = signatureMap.get(transfer.leaves[0].leaf.id);
31089
+ if (!cpfpRefundSignature) {
31090
+ console.error(
31091
+ "[processSwapBatch] Missing CPFP refund signature for first leaf"
31092
+ );
31093
+ throw new Error("Failed to get CPFP refund signature");
31094
+ }
31095
+ const directRefundSignature = directSignatureMap.get(
31096
+ transfer.leaves[0].leaf.id
31097
+ );
31098
+ if (!directRefundSignature) {
31099
+ console.error(
31100
+ "[processSwapBatch] Missing direct refund signature for first leaf"
31101
+ );
31102
+ throw new Error("Failed to get direct refund signature");
31103
+ }
31104
+ const directFromCpfpRefundSignature = directFromCpfpSignatureMap.get(
31105
+ transfer.leaves[0].leaf.id
31106
+ );
31107
+ if (!directFromCpfpRefundSignature) {
31108
+ console.error(
31109
+ "[processSwapBatch] Missing direct from CPFP refund signature for first leaf"
31110
+ );
31111
+ throw new Error("Failed to get direct from CPFP refund signature");
31112
+ }
31113
+ const {
31114
+ adaptorPrivateKey: cpfpAdaptorPrivateKey,
31115
+ adaptorSignature: cpfpAdaptorSignature
31116
+ } = generateAdaptorFromSignature(cpfpRefundSignature);
31117
+ let directAdaptorPrivateKey = new Uint8Array();
31118
+ let directAdaptorSignature = new Uint8Array();
31119
+ let directFromCpfpAdaptorPrivateKey = new Uint8Array();
31120
+ let directFromCpfpAdaptorSignature = new Uint8Array();
31121
+ if (directRefundSignature.length > 0) {
31122
+ const { adaptorPrivateKey, adaptorSignature } = generateAdaptorFromSignature(directRefundSignature);
31123
+ directAdaptorPrivateKey = adaptorPrivateKey;
31124
+ directAdaptorSignature = adaptorSignature;
31125
+ }
31126
+ if (directFromCpfpRefundSignature.length > 0) {
31127
+ const { adaptorPrivateKey, adaptorSignature } = generateAdaptorFromSignature(directFromCpfpRefundSignature);
31128
+ directFromCpfpAdaptorPrivateKey = adaptorPrivateKey;
31129
+ directFromCpfpAdaptorSignature = adaptorSignature;
29793
31130
  }
29794
- const { adaptorPrivateKey, adaptorSignature } = generateAdaptorFromSignature(refundSignature);
29795
31131
  if (!transfer.leaves[0].leaf) {
31132
+ console.error(
31133
+ "[processSwapBatch] First leaf missing when preparing user leaves"
31134
+ );
29796
31135
  throw new Error("Failed to get leaf");
29797
31136
  }
29798
31137
  const userLeaves = [];
@@ -29801,37 +31140,113 @@ var SparkWallet = class _SparkWallet extends import_eventemitter3.EventEmitter {
29801
31140
  raw_unsigned_refund_transaction: (0, import_utils23.bytesToHex)(
29802
31141
  transfer.leaves[0].intermediateRefundTx
29803
31142
  ),
29804
- adaptor_added_signature: (0, import_utils23.bytesToHex)(adaptorSignature)
31143
+ direct_raw_unsigned_refund_transaction: (0, import_utils23.bytesToHex)(
31144
+ transfer.leaves[0].intermediateDirectRefundTx
31145
+ ),
31146
+ direct_from_cpfp_raw_unsigned_refund_transaction: (0, import_utils23.bytesToHex)(
31147
+ transfer.leaves[0].intermediateDirectFromCpfpRefundTx
31148
+ ),
31149
+ adaptor_added_signature: (0, import_utils23.bytesToHex)(cpfpAdaptorSignature),
31150
+ direct_adaptor_added_signature: (0, import_utils23.bytesToHex)(directAdaptorSignature),
31151
+ direct_from_cpfp_adaptor_added_signature: (0, import_utils23.bytesToHex)(
31152
+ directFromCpfpAdaptorSignature
31153
+ )
29805
31154
  });
29806
31155
  for (let i = 1; i < transfer.leaves.length; i++) {
29807
31156
  const leaf = transfer.leaves[i];
29808
31157
  if (!leaf?.leaf) {
31158
+ console.error(`[processSwapBatch] Leaf ${i + 1} is missing`);
29809
31159
  throw new Error("Failed to get leaf");
29810
31160
  }
29811
- const refundSignature2 = signatureMap.get(leaf.leaf.id);
29812
- if (!refundSignature2) {
29813
- throw new Error("Failed to get refund signature");
31161
+ const cpfpRefundSignature2 = signatureMap.get(leaf.leaf.id);
31162
+ if (!cpfpRefundSignature2) {
31163
+ console.error(
31164
+ `[processSwapBatch] Missing CPFP refund signature for leaf ${i + 1}`
31165
+ );
31166
+ throw new Error("Failed to get CPFP refund signature");
31167
+ }
31168
+ const directRefundSignature2 = directSignatureMap.get(leaf.leaf.id);
31169
+ if (!directRefundSignature2) {
31170
+ console.error(
31171
+ `[processSwapBatch] Missing direct refund signature for leaf ${i + 1}`
31172
+ );
31173
+ throw new Error("Failed to get direct refund signature");
31174
+ }
31175
+ const directFromCpfpRefundSignature2 = directFromCpfpSignatureMap.get(
31176
+ leaf.leaf.id
31177
+ );
31178
+ if (!directFromCpfpRefundSignature2) {
31179
+ console.error(
31180
+ `[processSwapBatch] Missing direct from CPFP refund signature for leaf ${i + 1}`
31181
+ );
31182
+ throw new Error("Failed to get direct from CPFP refund signature");
29814
31183
  }
29815
- const signature = generateSignatureFromExistingAdaptor(
29816
- refundSignature2,
29817
- adaptorPrivateKey
31184
+ const cpfpSignature = generateSignatureFromExistingAdaptor(
31185
+ cpfpRefundSignature2,
31186
+ cpfpAdaptorPrivateKey
29818
31187
  );
31188
+ let directSignature = new Uint8Array();
31189
+ if (directRefundSignature2.length > 0) {
31190
+ directSignature = generateSignatureFromExistingAdaptor(
31191
+ directRefundSignature2,
31192
+ directAdaptorPrivateKey
31193
+ );
31194
+ }
31195
+ let directFromCpfpSignature = new Uint8Array();
31196
+ if (directFromCpfpRefundSignature2.length > 0) {
31197
+ directFromCpfpSignature = generateSignatureFromExistingAdaptor(
31198
+ directFromCpfpRefundSignature2,
31199
+ directFromCpfpAdaptorPrivateKey
31200
+ );
31201
+ }
29819
31202
  userLeaves.push({
29820
31203
  leaf_id: leaf.leaf.id,
29821
31204
  raw_unsigned_refund_transaction: (0, import_utils23.bytesToHex)(
29822
31205
  leaf.intermediateRefundTx
29823
31206
  ),
29824
- adaptor_added_signature: (0, import_utils23.bytesToHex)(signature)
31207
+ direct_raw_unsigned_refund_transaction: (0, import_utils23.bytesToHex)(
31208
+ leaf.intermediateDirectRefundTx
31209
+ ),
31210
+ direct_from_cpfp_raw_unsigned_refund_transaction: (0, import_utils23.bytesToHex)(
31211
+ leaf.intermediateDirectFromCpfpRefundTx
31212
+ ),
31213
+ adaptor_added_signature: (0, import_utils23.bytesToHex)(cpfpSignature),
31214
+ direct_adaptor_added_signature: (0, import_utils23.bytesToHex)(directSignature),
31215
+ direct_from_cpfp_adaptor_added_signature: (0, import_utils23.bytesToHex)(
31216
+ directFromCpfpSignature
31217
+ )
29825
31218
  });
29826
31219
  }
29827
31220
  const sspClient = this.getSspClient();
29828
- const adaptorPubkey = (0, import_utils23.bytesToHex)(
29829
- import_secp256k115.secp256k1.getPublicKey(adaptorPrivateKey)
31221
+ const cpfpAdaptorPubkey = (0, import_utils23.bytesToHex)(
31222
+ import_secp256k115.secp256k1.getPublicKey(cpfpAdaptorPrivateKey)
29830
31223
  );
31224
+ if (!cpfpAdaptorPubkey) {
31225
+ throw new Error("Failed to generate CPFP adaptor pubkey");
31226
+ }
31227
+ let directAdaptorPubkey;
31228
+ if (directAdaptorPrivateKey.length > 0) {
31229
+ directAdaptorPubkey = (0, import_utils23.bytesToHex)(
31230
+ import_secp256k115.secp256k1.getPublicKey(directAdaptorPrivateKey)
31231
+ );
31232
+ }
31233
+ let directFromCpfpAdaptorPubkey;
31234
+ if (directFromCpfpAdaptorPrivateKey.length > 0) {
31235
+ directFromCpfpAdaptorPubkey = (0, import_utils23.bytesToHex)(
31236
+ import_secp256k115.secp256k1.getPublicKey(directFromCpfpAdaptorPrivateKey)
31237
+ );
31238
+ }
29831
31239
  let request = null;
31240
+ const targetAmountSats = targetAmounts?.reduce((acc, amount) => acc + amount, 0) || leavesBatch.reduce((acc, leaf) => acc + leaf.value, 0);
31241
+ const totalAmountSats = leavesBatch.reduce(
31242
+ (acc, leaf) => acc + leaf.value,
31243
+ 0
31244
+ );
29832
31245
  request = await sspClient.requestLeaveSwap({
29833
31246
  userLeaves,
29834
- adaptorPubkey,
31247
+ adaptorPubkey: cpfpAdaptorPubkey,
31248
+ directAdaptorPubkey,
31249
+ directFromCpfpAdaptorPubkey,
29835
31250
  targetAmountSats: targetAmounts?.reduce((acc, amount) => acc + amount, 0) || leavesBatch.reduce((acc, leaf) => acc + leaf.value, 0),
29836
31251
  totalAmountSats: leavesBatch.reduce((acc, leaf) => acc + leaf.value, 0),
29837
31252
  targetAmountSatsList: targetAmounts,
@@ -29840,6 +31255,7 @@ var SparkWallet = class _SparkWallet extends import_eventemitter3.EventEmitter {
29840
31255
  idempotencyKey: (0, import_uuidv75.uuidv7)()
29841
31256
  });
29842
31257
  if (!request) {
31258
+ console.error("[processSwapBatch] Leave swap request returned null");
29843
31259
  throw new Error("Failed to request leaves swap. No response returned.");
29844
31260
  }
29845
31261
  const nodes = await this.queryNodes({
@@ -29853,50 +31269,140 @@ var SparkWallet = class _SparkWallet extends import_eventemitter3.EventEmitter {
29853
31269
  network: NetworkToProto[this.config.getNetwork()]
29854
31270
  });
29855
31271
  if (Object.values(nodes.nodes).length !== request.swapLeaves.length) {
31272
+ console.error("[processSwapBatch] Node count mismatch:", {
31273
+ actual: Object.values(nodes.nodes).length,
31274
+ expected: request.swapLeaves.length
31275
+ });
29856
31276
  throw new Error("Expected same number of nodes as swapLeaves");
29857
31277
  }
29858
31278
  for (const [nodeId, node] of Object.entries(nodes.nodes)) {
29859
31279
  if (!node.nodeTx) {
31280
+ console.error(`[processSwapBatch] Node tx missing for ${nodeId}`);
29860
31281
  throw new Error(`Node tx not found for leaf ${nodeId}`);
29861
31282
  }
29862
31283
  if (!node.verifyingPublicKey) {
31284
+ console.error(
31285
+ `[processSwapBatch] Verifying public key missing for ${nodeId}`
31286
+ );
29863
31287
  throw new Error(`Node public key not found for leaf ${nodeId}`);
29864
31288
  }
29865
31289
  const leaf = request.swapLeaves.find((leaf2) => leaf2.leafId === nodeId);
29866
31290
  if (!leaf) {
31291
+ console.error(`[processSwapBatch] Leaf not found for node ${nodeId}`);
29867
31292
  throw new Error(`Leaf not found for node ${nodeId}`);
29868
31293
  }
29869
- const nodeTx = getTxFromRawTxBytes(node.nodeTx);
29870
- const refundTxBytes = (0, import_utils23.hexToBytes)(leaf.rawUnsignedRefundTransaction);
29871
- const refundTx = getTxFromRawTxBytes(refundTxBytes);
29872
- const sighash = getSigHashFromTx(refundTx, 0, nodeTx.getOutput(0));
31294
+ const cpfpNodeTx = getTxFromRawTxBytes(node.nodeTx);
31295
+ const cpfpRefundTxBytes = (0, import_utils23.hexToBytes)(leaf.rawUnsignedRefundTransaction);
31296
+ const cpfpRefundTx = getTxFromRawTxBytes(cpfpRefundTxBytes);
31297
+ const cpfpSighash = getSigHashFromTx(
31298
+ cpfpRefundTx,
31299
+ 0,
31300
+ cpfpNodeTx.getOutput(0)
31301
+ );
29873
31302
  const nodePublicKey = node.verifyingPublicKey;
29874
31303
  const taprootKey = computeTaprootKeyNoScript(nodePublicKey.slice(1));
29875
- const adaptorSignatureBytes = (0, import_utils23.hexToBytes)(leaf.adaptorSignedSignature);
31304
+ const cpfpAdaptorSignatureBytes = (0, import_utils23.hexToBytes)(
31305
+ leaf.adaptorSignedSignature
31306
+ );
31307
+ applyAdaptorToSignature(
31308
+ taprootKey.slice(1),
31309
+ cpfpSighash,
31310
+ cpfpAdaptorSignatureBytes,
31311
+ cpfpAdaptorPrivateKey
31312
+ );
31313
+ if (!leaf.directRawUnsignedRefundTransaction) {
31314
+ throw new Error(
31315
+ `Direct raw unsigned refund transaction missing for node ${nodeId}`
31316
+ );
31317
+ }
31318
+ if (!leaf.directAdaptorSignedSignature) {
31319
+ throw new Error(
31320
+ `Direct adaptor signed signature missing for node ${nodeId}`
31321
+ );
31322
+ }
31323
+ const directNodeTx = getTxFromRawTxBytes(node.directTx);
31324
+ const directRefundTxBytes = (0, import_utils23.hexToBytes)(
31325
+ leaf.directRawUnsignedRefundTransaction
31326
+ );
31327
+ const directRefundTx = getTxFromRawTxBytes(directRefundTxBytes);
31328
+ const directSighash = getSigHashFromTx(
31329
+ directRefundTx,
31330
+ 0,
31331
+ directNodeTx.getOutput(0)
31332
+ );
31333
+ if (!leaf.directFromCpfpAdaptorSignedSignature) {
31334
+ throw new Error(
31335
+ `Direct adaptor signed signature missing for node ${nodeId}`
31336
+ );
31337
+ }
31338
+ const directAdaptorSignatureBytes = (0, import_utils23.hexToBytes)(
31339
+ leaf.directAdaptorSignedSignature
31340
+ );
31341
+ applyAdaptorToSignature(
31342
+ taprootKey.slice(1),
31343
+ directSighash,
31344
+ directAdaptorSignatureBytes,
31345
+ directAdaptorPrivateKey
31346
+ );
31347
+ if (!leaf.directRawUnsignedRefundTransaction) {
31348
+ throw new Error(
31349
+ `Direct raw unsigned refund transaction missing for node ${nodeId}`
31350
+ );
31351
+ }
31352
+ if (!leaf.directFromCpfpRawUnsignedRefundTransaction) {
31353
+ throw new Error(
31354
+ `Direct raw unsigned refund transaction missing for node ${nodeId}`
31355
+ );
31356
+ }
31357
+ const directFromCpfpRefundTxBytes = (0, import_utils23.hexToBytes)(
31358
+ leaf.directFromCpfpRawUnsignedRefundTransaction
31359
+ );
31360
+ const directFromCpfpRefundTx = getTxFromRawTxBytes(
31361
+ directFromCpfpRefundTxBytes
31362
+ );
31363
+ const directFromCpfpSighash = getSigHashFromTx(
31364
+ directFromCpfpRefundTx,
31365
+ 0,
31366
+ cpfpNodeTx.getOutput(0)
31367
+ );
31368
+ const directFromCpfpAdaptorSignatureBytes = (0, import_utils23.hexToBytes)(
31369
+ leaf.directFromCpfpAdaptorSignedSignature
31370
+ );
29876
31371
  applyAdaptorToSignature(
29877
31372
  taprootKey.slice(1),
29878
- sighash,
29879
- adaptorSignatureBytes,
29880
- adaptorPrivateKey
31373
+ directFromCpfpSighash,
31374
+ directFromCpfpAdaptorSignatureBytes,
31375
+ directFromCpfpAdaptorPrivateKey
29881
31376
  );
29882
31377
  }
29883
31378
  await this.transferService.deliverTransferPackage(
29884
31379
  transfer,
29885
31380
  leafKeyTweaks,
29886
- signatureMap
31381
+ signatureMap,
31382
+ directSignatureMap,
31383
+ directFromCpfpSignatureMap
29887
31384
  );
29888
31385
  const completeResponse = await sspClient.completeLeaveSwap({
29889
- adaptorSecretKey: (0, import_utils23.bytesToHex)(adaptorPrivateKey),
31386
+ adaptorSecretKey: (0, import_utils23.bytesToHex)(cpfpAdaptorPrivateKey),
31387
+ directAdaptorSecretKey: (0, import_utils23.bytesToHex)(directAdaptorPrivateKey),
31388
+ directFromCpfpAdaptorSecretKey: (0, import_utils23.bytesToHex)(
31389
+ directFromCpfpAdaptorPrivateKey
31390
+ ),
29890
31391
  userOutboundTransferExternalId: transfer.id,
29891
31392
  leavesSwapRequestId: request.id
29892
31393
  });
29893
31394
  if (!completeResponse || !completeResponse.inboundTransfer?.sparkId) {
31395
+ console.error(
31396
+ "[processSwapBatch] Invalid complete response:",
31397
+ completeResponse
31398
+ );
29894
31399
  throw new Error("Failed to complete leaves swap");
29895
31400
  }
29896
31401
  const incomingTransfer = await this.transferService.queryTransfer(
29897
31402
  completeResponse.inboundTransfer.sparkId
29898
31403
  );
29899
31404
  if (!incomingTransfer) {
31405
+ console.error("[processSwapBatch] No incoming transfer found");
29900
31406
  throw new Error("Failed to get incoming transfer");
29901
31407
  }
29902
31408
  return await this.claimTransfer({
@@ -29906,6 +31412,11 @@ var SparkWallet = class _SparkWallet extends import_eventemitter3.EventEmitter {
29906
31412
  optimize: false
29907
31413
  });
29908
31414
  } catch (e) {
31415
+ console.error("[processSwapBatch] Error details:", {
31416
+ error: e,
31417
+ message: e.message,
31418
+ stack: e.stack
31419
+ });
29909
31420
  await this.cancelAllSenderInitiatedTransfers();
29910
31421
  throw new Error(`Failed to request leaves swap: ${e}`);
29911
31422
  }
@@ -30376,8 +31887,9 @@ var SparkWallet = class _SparkWallet extends import_eventemitter3.EventEmitter {
30376
31887
  field: "txid"
30377
31888
  });
30378
31889
  }
31890
+ const { fetch: fetch2, Headers: Headers2 } = getFetch();
30379
31891
  const baseUrl = this.config.getElectrsUrl();
30380
- const headers = {};
31892
+ const headers = new Headers2();
30381
31893
  let txHex;
30382
31894
  if (this.config.getNetwork() === 4 /* LOCAL */) {
30383
31895
  const localFaucet = BitcoinFaucet.getInstance();
@@ -30388,9 +31900,9 @@ var SparkWallet = class _SparkWallet extends import_eventemitter3.EventEmitter {
30388
31900
  const auth = btoa(
30389
31901
  `${ELECTRS_CREDENTIALS.username}:${ELECTRS_CREDENTIALS.password}`
30390
31902
  );
30391
- headers["Authorization"] = `Basic ${auth}`;
31903
+ headers.set("Authorization", `Basic ${auth}`);
30392
31904
  }
30393
- const response = await fetch(`${baseUrl}/tx/${txid}/hex`, {
31905
+ const response = await fetch2(`${baseUrl}/tx/${txid}/hex`, {
30394
31906
  headers
30395
31907
  });
30396
31908
  txHex = await response.text();
@@ -30518,8 +32030,9 @@ var SparkWallet = class _SparkWallet extends import_eventemitter3.EventEmitter {
30518
32030
  this.mutexes.set(txid, mutex);
30519
32031
  }
30520
32032
  const nodes = await mutex.runExclusive(async () => {
32033
+ const { fetch: fetch2, Headers: Headers2 } = getFetch();
30521
32034
  const baseUrl = this.config.getElectrsUrl();
30522
- const headers = {};
32035
+ const headers = new Headers2();
30523
32036
  let txHex;
30524
32037
  if (this.config.getNetwork() === 4 /* LOCAL */) {
30525
32038
  const localFaucet = BitcoinFaucet.getInstance();
@@ -30530,9 +32043,9 @@ var SparkWallet = class _SparkWallet extends import_eventemitter3.EventEmitter {
30530
32043
  const auth = btoa(
30531
32044
  `${ELECTRS_CREDENTIALS.username}:${ELECTRS_CREDENTIALS.password}`
30532
32045
  );
30533
- headers["Authorization"] = `Basic ${auth}`;
32046
+ headers.set("Authorization", `Basic ${auth}`);
30534
32047
  }
30535
- const response = await fetch(`${baseUrl}/tx/${txid}/hex`, {
32048
+ const response = await fetch2(`${baseUrl}/tx/${txid}/hex`, {
30536
32049
  headers
30537
32050
  });
30538
32051
  txHex = await response.text();
@@ -30774,10 +32287,16 @@ var SparkWallet = class _SparkWallet extends import_eventemitter3.EventEmitter {
30774
32287
  const validNodes = [];
30775
32288
  for (const node of nodes) {
30776
32289
  const nodeTx = getTxFromRawTxBytes(node.nodeTx);
30777
- const { needRefresh } = getNextTransactionSequence(
30778
- nodeTx.getInput(0).sequence
30779
- );
30780
- if (needRefresh) {
32290
+ const sequence = nodeTx.getInput(0).sequence;
32291
+ if (!sequence) {
32292
+ throw new ValidationError("Invalid node transaction", {
32293
+ field: "sequence",
32294
+ value: nodeTx.getInput(0),
32295
+ expected: "Non-null sequence"
32296
+ });
32297
+ }
32298
+ const needsRefresh = doesLeafNeedRefresh(sequence, true);
32299
+ if (needsRefresh) {
30781
32300
  nodesToExtend.push(node);
30782
32301
  nodeIds.push(node.id);
30783
32302
  } else {
@@ -30814,11 +32333,16 @@ var SparkWallet = class _SparkWallet extends import_eventemitter3.EventEmitter {
30814
32333
  const validNodes = [];
30815
32334
  for (const node of nodes) {
30816
32335
  const refundTx = getTxFromRawTxBytes(node.refundTx);
30817
- const { needRefresh } = getNextTransactionSequence(
30818
- refundTx.getInput(0).sequence,
30819
- true
30820
- );
30821
- if (needRefresh) {
32336
+ const sequence = refundTx.getInput(0).sequence;
32337
+ if (!sequence) {
32338
+ throw new ValidationError("Invalid refund transaction", {
32339
+ field: "sequence",
32340
+ value: refundTx.getInput(0),
32341
+ expected: "Non-null sequence"
32342
+ });
32343
+ }
32344
+ const needsRefresh = doesLeafNeedRefresh(sequence);
32345
+ if (needsRefresh) {
30822
32346
  nodesToRefresh.push(node);
30823
32347
  nodeIds.push(node.id);
30824
32348
  } else {
@@ -30852,7 +32376,7 @@ var SparkWallet = class _SparkWallet extends import_eventemitter3.EventEmitter {
30852
32376
  throw new Error(`parent node ${node.parentNodeId} not found`);
30853
32377
  }
30854
32378
  const { nodes: nodes2 } = await this.transferService.refreshTimelockNodes(
30855
- [node],
32379
+ node,
30856
32380
  parentNode
30857
32381
  );
30858
32382
  if (nodes2.length !== 1) {
@@ -30901,7 +32425,9 @@ var SparkWallet = class _SparkWallet extends import_eventemitter3.EventEmitter {
30901
32425
  leavesToClaim.push({
30902
32426
  leaf: {
30903
32427
  ...leaf.leaf,
30904
- refundTx: leaf.intermediateRefundTx
32428
+ refundTx: leaf.intermediateRefundTx,
32429
+ directRefundTx: leaf.intermediateDirectRefundTx,
32430
+ directFromCpfpRefundTx: leaf.intermediateDirectFromCpfpRefundTx
30905
32431
  },
30906
32432
  keyDerivation: {
30907
32433
  type: "ecies" /* ECIES */,
@@ -30977,7 +32503,7 @@ var SparkWallet = class _SparkWallet extends import_eventemitter3.EventEmitter {
30977
32503
  if (type && transfer.type !== type) {
30978
32504
  continue;
30979
32505
  }
30980
- if (transfer.status !== 2 /* TRANSFER_STATUS_SENDER_KEY_TWEAKED */ && transfer.status !== 3 /* TRANSFER_STATUS_RECEIVER_KEY_TWEAKED */ && transfer.status !== 4 /* TRANSFER_STATUS_RECEIVER_REFUND_SIGNED */ && transfer.status !== 10 /* TRANSFER_STATUS_RECEIVER_KEY_TWEAK_APPLIED */) {
32506
+ if (transfer.status !== 2 /* TRANSFER_STATUS_SENDER_KEY_TWEAKED */ && transfer.status !== 3 /* TRANSFER_STATUS_RECEIVER_KEY_TWEAKED */ && transfer.status !== 4 /* TRANSFER_STATUS_RECEIVER_REFUND_SIGNED */ && transfer.status !== 10 /* TRANSFER_STATUS_RECEIVER_KEY_TWEAK_APPLIED */ && transfer.status !== 9 /* TRANSFER_STATUS_RECEIVER_KEY_TWEAK_LOCKED */) {
30981
32507
  continue;
30982
32508
  }
30983
32509
  promises.push(
@@ -31265,6 +32791,8 @@ var SparkWallet = class _SparkWallet extends import_eventemitter3.EventEmitter {
31265
32791
  await this.transferService.deliverTransferPackage(
31266
32792
  swapResponse.transfer,
31267
32793
  leavesToSend,
32794
+ /* @__PURE__ */ new Map(),
32795
+ /* @__PURE__ */ new Map(),
31268
32796
  /* @__PURE__ */ new Map()
31269
32797
  );
31270
32798
  const sspResponse = await sspClient.requestLightningSend({
@@ -32027,87 +33555,64 @@ var SparkWallet = class _SparkWallet extends import_eventemitter3.EventEmitter {
32027
33555
  },
32028
33556
  includeParents: true
32029
33557
  });
32030
- const node = response.nodes[nodeId];
32031
- if (!node) {
33558
+ let leaf = response.nodes[nodeId];
33559
+ if (!leaf) {
32032
33560
  throw new ValidationError("Node not found", {
32033
33561
  field: "nodeId",
32034
33562
  value: nodeId
32035
33563
  });
32036
33564
  }
32037
- if (!node.parentNodeId) {
32038
- throw new ValidationError("Node has no parent", {
32039
- field: "parentNodeId",
32040
- value: node.parentNodeId
32041
- });
32042
- }
32043
- const parentNode = response.nodes[node.parentNodeId];
32044
- if (!parentNode) {
32045
- throw new ValidationError("Parent node not found", {
32046
- field: "parentNodeId",
32047
- value: node.parentNodeId
32048
- });
32049
- }
32050
- const result = await this.transferService.refreshTimelockNodes(
32051
- [node],
32052
- parentNode
32053
- );
32054
- const leafIndex = this.leaves.findIndex((leaf) => leaf.id === node.id);
32055
- if (leafIndex !== -1 && result.nodes.length > 0) {
32056
- const newNode = result.nodes[0];
32057
- if (newNode) {
32058
- this.leaves[leafIndex] = newNode;
33565
+ let parentNode;
33566
+ let hasParentNode = false;
33567
+ if (!leaf.parentNodeId) {
33568
+ } else {
33569
+ hasParentNode = true;
33570
+ parentNode = response.nodes[leaf.parentNodeId];
33571
+ if (!parentNode) {
33572
+ throw new ValidationError("Parent node not found", {
33573
+ field: "parentNodeId",
33574
+ value: leaf.parentNodeId
33575
+ });
32059
33576
  }
32060
33577
  }
32061
- } catch (error) {
32062
- throw new NetworkError(
32063
- "Failed to refresh timelock",
32064
- {
32065
- method: "refresh_timelock"
32066
- },
32067
- error
32068
- );
32069
- }
32070
- }
32071
- /**
32072
- * Refresh the timelock of a specific node's refund transaction only.
32073
- *
32074
- * @param {string} nodeId - The ID of the node whose refund transaction to refresh
32075
- * @returns {Promise<void>} Promise that resolves when the refund timelock is refreshed
32076
- */
32077
- async testOnly_expireTimelockRefundTx(nodeId) {
32078
- const sparkClient = await this.connectionManager.createSparkClient(
32079
- this.config.getCoordinatorAddress()
32080
- );
32081
- try {
32082
- const response = await sparkClient.query_nodes({
32083
- source: {
32084
- $case: "nodeIds",
32085
- nodeIds: {
32086
- nodeIds: [nodeId]
33578
+ const nodeTx = getTxFromRawTxBytes(leaf.nodeTx);
33579
+ const refundTx = getTxFromRawTxBytes(leaf.refundTx);
33580
+ if (hasParentNode) {
33581
+ const nodeTimelock = getCurrentTimelock(nodeTx.getInput(0).sequence);
33582
+ if (nodeTimelock > 100) {
33583
+ const expiredNodeTxLeaf = await this.transferService.testonly_expireTimeLockNodeTx(
33584
+ leaf,
33585
+ parentNode
33586
+ );
33587
+ if (!expiredNodeTxLeaf.nodes[0]) {
33588
+ throw new ValidationError("No expired node tx leaf", {
33589
+ field: "expiredNodeTxLeaf",
33590
+ value: expiredNodeTxLeaf
33591
+ });
32087
33592
  }
32088
- },
32089
- includeParents: false
32090
- });
32091
- const node = response.nodes[nodeId];
32092
- if (!node) {
32093
- throw new ValidationError("Node not found", {
32094
- field: "nodeId",
32095
- value: nodeId
32096
- });
33593
+ leaf = expiredNodeTxLeaf.nodes[0];
33594
+ }
32097
33595
  }
32098
- const result = await this.transferService.refreshTimelockRefundTx(node);
32099
- const leafIndex = this.leaves.findIndex((leaf) => leaf.id === node.id);
32100
- if (leafIndex !== -1 && result.nodes.length > 0) {
32101
- const newNode = result.nodes[0];
32102
- if (newNode) {
32103
- this.leaves[leafIndex] = newNode;
33596
+ const refundTimelock = getCurrentTimelock(refundTx.getInput(0).sequence);
33597
+ if (refundTimelock > 100) {
33598
+ const expiredTxLeaf = await this.transferService.testonly_expireTimeLockRefundtx(leaf);
33599
+ if (!expiredTxLeaf.nodes[0]) {
33600
+ throw new ValidationError("No expired tx leaf", {
33601
+ field: "expiredTxLeaf",
33602
+ value: expiredTxLeaf
33603
+ });
32104
33604
  }
33605
+ leaf = expiredTxLeaf.nodes[0];
33606
+ }
33607
+ const leafIndex = this.leaves.findIndex((leaf2) => leaf2.id === leaf2.id);
33608
+ if (leafIndex !== -1) {
33609
+ this.leaves[leafIndex] = leaf;
32105
33610
  }
32106
33611
  } catch (error) {
32107
33612
  throw new NetworkError(
32108
- "Failed to refresh refund timelock",
33613
+ "Failed to refresh timelock",
32109
33614
  {
32110
- method: "refresh_timelock_refund_tx"
33615
+ method: "refresh_timelock"
32111
33616
  },
32112
33617
  error
32113
33618
  );
@@ -32171,10 +33676,15 @@ var SparkWallet = class _SparkWallet extends import_eventemitter3.EventEmitter {
32171
33676
  var utils_exports = {};
32172
33677
  __export(utils_exports, {
32173
33678
  DEFAULT_FEE_SATS: () => DEFAULT_FEE_SATS,
33679
+ DIRECT_TIMELOCK_OFFSET: () => DIRECT_TIMELOCK_OFFSET,
33680
+ INITIAL_DIRECT_SEQUENCE: () => INITIAL_DIRECT_SEQUENCE,
33681
+ INITIAL_SEQUENCE: () => INITIAL_SEQUENCE,
32174
33682
  LRC_WALLET_NETWORK: () => LRC_WALLET_NETWORK,
32175
33683
  LRC_WALLET_NETWORK_TYPE: () => LRC_WALLET_NETWORK_TYPE,
32176
33684
  Network: () => Network2,
32177
33685
  NetworkToProto: () => NetworkToProto,
33686
+ TEST_UNILATERAL_DIRECT_SEQUENCE: () => TEST_UNILATERAL_DIRECT_SEQUENCE,
33687
+ TEST_UNILATERAL_SEQUENCE: () => TEST_UNILATERAL_SEQUENCE,
32178
33688
  addPrivateKeys: () => addPrivateKeys,
32179
33689
  addPublicKeys: () => addPublicKeys,
32180
33690
  applyAdaptorToSignature: () => applyAdaptorToSignature,
@@ -32188,13 +33698,21 @@ __export(utils_exports, {
32188
33698
  constructFeeBumpTx: () => constructFeeBumpTx,
32189
33699
  constructUnilateralExitFeeBumpPackages: () => constructUnilateralExitFeeBumpPackages,
32190
33700
  constructUnilateralExitTxs: () => constructUnilateralExitTxs,
33701
+ createConnectorRefundTransactions: () => createConnectorRefundTransactions,
33702
+ createLeafNodeTx: () => createLeafNodeTx,
33703
+ createNodeTx: () => createNodeTx,
33704
+ createNodeTxs: () => createNodeTxs,
32191
33705
  createRefundTx: () => createRefundTx,
33706
+ createRefundTxs: () => createRefundTxs,
33707
+ createRootTx: () => createRootTx,
32192
33708
  createSigningCommitment: () => createSigningCommitment,
32193
33709
  createSigningNonce: () => createSigningNonce,
33710
+ createSplitTx: () => createSplitTx,
32194
33711
  decodeBech32mTokenIdentifier: () => decodeBech32mTokenIdentifier,
32195
33712
  decodeBytesToSigningCommitment: () => decodeBytesToSigningCommitment,
32196
33713
  decodeBytesToSigningNonce: () => decodeBytesToSigningNonce,
32197
33714
  decodeSparkAddress: () => decodeSparkAddress,
33715
+ doesLeafNeedRefresh: () => doesLeafNeedRefresh,
32198
33716
  encodeBech32mTokenIdentifier: () => encodeBech32mTokenIdentifier,
32199
33717
  encodeSigningCommitmentToBytes: () => encodeSigningCommitmentToBytes,
32200
33718
  encodeSigningNonceToBytes: () => encodeSigningNonceToBytes,
@@ -32256,16 +33774,17 @@ init_buffer();
32256
33774
 
32257
33775
  // src/utils/mempool.ts
32258
33776
  async function getLatestDepositTxId(address2) {
33777
+ const { fetch: fetch2, Headers: Headers2 } = getFetch();
32259
33778
  const network = getNetworkFromAddress(address2);
32260
33779
  const baseUrl = network === BitcoinNetwork_default.REGTEST ? getElectrsUrl("REGTEST") : getElectrsUrl("MAINNET");
32261
- const headers = {};
33780
+ const headers = new Headers2();
32262
33781
  if (network === BitcoinNetwork_default.REGTEST) {
32263
33782
  const auth = btoa(
32264
33783
  `${ELECTRS_CREDENTIALS.username}:${ELECTRS_CREDENTIALS.password}`
32265
33784
  );
32266
- headers["Authorization"] = `Basic ${auth}`;
33785
+ headers.set("Authorization", `Basic ${auth}`);
32267
33786
  }
32268
- const response = await fetch(`${baseUrl}/address/${address2}/txs`, {
33787
+ const response = await fetch2(`${baseUrl}/address/${address2}/txs`, {
32269
33788
  headers
32270
33789
  });
32271
33790
  const addressTxs = await response.json();
@@ -32282,14 +33801,15 @@ async function getLatestDepositTxId(address2) {
32282
33801
  return null;
32283
33802
  }
32284
33803
  async function isTxBroadcast(txid, baseUrl, network) {
32285
- const headers = {};
33804
+ const { fetch: fetch2, Headers: Headers2 } = getFetch();
33805
+ const headers = new Headers2();
32286
33806
  if (network === 3 /* REGTEST */) {
32287
33807
  const auth = btoa(
32288
33808
  `${ELECTRS_CREDENTIALS.username}:${ELECTRS_CREDENTIALS.password}`
32289
33809
  );
32290
- headers["Authorization"] = `Basic ${auth}`;
33810
+ headers.set("Authorization", `Basic ${auth}`);
32291
33811
  }
32292
- const response = await fetch(`${baseUrl}/tx/${txid}`, {
33812
+ const response = await fetch2(`${baseUrl}/tx/${txid}`, {
32293
33813
  headers
32294
33814
  });
32295
33815
  const tx = await response.json();
@@ -32304,7 +33824,7 @@ init_buffer();
32304
33824
  var import_utils24 = require("@noble/curves/abstract/utils");
32305
33825
  var import_legacy = require("@noble/hashes/legacy");
32306
33826
  var import_sha212 = require("@noble/hashes/sha2");
32307
- var btc5 = __toESM(require("@scure/btc-signer"), 1);
33827
+ var btc4 = __toESM(require("@scure/btc-signer"), 1);
32308
33828
  function isEphemeralAnchorOutput(script, amount) {
32309
33829
  return Boolean(
32310
33830
  amount === 0n && script && // Pattern 1: Bare OP_TRUE (single byte 0x51)
@@ -32519,7 +34039,7 @@ async function constructUnilateralExitFeeBumpPackages(nodeHexStrings, utxos, fee
32519
34039
  usedUtxos,
32520
34040
  correctedParentTx
32521
34041
  } = constructFeeBumpTx(nodeTxHex, availableUtxos, feeRate, void 0);
32522
- const feeBumpTx = btc5.Transaction.fromPSBT((0, import_utils24.hexToBytes)(nodeFeeBumpPsbt));
34042
+ const feeBumpTx = btc4.Transaction.fromPSBT((0, import_utils24.hexToBytes)(nodeFeeBumpPsbt));
32523
34043
  var feeBumpOut = feeBumpTx.outputsLength === 1 ? feeBumpTx.getOutput(0) : null;
32524
34044
  var feeBumpOutPubKey = null;
32525
34045
  for (const usedUtxo of usedUtxos) {
@@ -32573,7 +34093,7 @@ async function constructUnilateralExitFeeBumpPackages(nodeHexStrings, utxos, fee
32573
34093
  feeRate,
32574
34094
  void 0
32575
34095
  );
32576
- const feeBumpTx2 = btc5.Transaction.fromPSBT(
34096
+ const feeBumpTx2 = btc4.Transaction.fromPSBT(
32577
34097
  (0, import_utils24.hexToBytes)(refundFeeBump.feeBumpPsbt)
32578
34098
  );
32579
34099
  var feeBumpOut = feeBumpTx2.outputsLength === 1 ? feeBumpTx2.getOutput(0) : null;
@@ -32677,7 +34197,7 @@ function constructFeeBumpTx(txHex, utxos, feeRate, previousFeeBumpTx) {
32677
34197
  if (utxos.length === 0) {
32678
34198
  throw new Error("No UTXOs available for fee bump");
32679
34199
  }
32680
- const builder = new btc5.Transaction({
34200
+ const builder = new btc4.Transaction({
32681
34201
  version: 3,
32682
34202
  allowUnknown: true,
32683
34203
  allowLegacyWitnessUtxo: true
@@ -32770,19 +34290,19 @@ function constructFeeBumpTx(txHex, utxos, feeRate, previousFeeBumpTx) {
32770
34290
 
32771
34291
  // src/utils/xchain-address.ts
32772
34292
  init_buffer();
32773
- var btc6 = __toESM(require("@scure/btc-signer"), 1);
34293
+ var btc5 = __toESM(require("@scure/btc-signer"), 1);
32774
34294
  var networkByType = {
32775
- MAINNET: btc6.NETWORK,
32776
- TESTNET: btc6.TEST_NETWORK,
34295
+ MAINNET: btc5.NETWORK,
34296
+ TESTNET: btc5.TEST_NETWORK,
32777
34297
  REGTEST: {
32778
- ...btc6.TEST_NETWORK,
34298
+ ...btc5.TEST_NETWORK,
32779
34299
  bech32: "bcrt"
32780
34300
  }
32781
34301
  };
32782
34302
  function getSparkAddressFromTaproot(taprootAddress) {
32783
34303
  for (const networkType of ["MAINNET", "TESTNET", "REGTEST"]) {
32784
34304
  try {
32785
- const result = btc6.Address(networkByType[networkType]).decode(taprootAddress);
34305
+ const result = btc5.Address(networkByType[networkType]).decode(taprootAddress);
32786
34306
  if (result.type === "tr") {
32787
34307
  const outputPublicKey = result.pubkey;
32788
34308
  return encodeSparkAddress({