@buildonspark/spark-sdk 0.3.8 → 0.4.0

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 (94) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/android/build.gradle +1 -1
  3. package/android/src/main/java/uniffi/uniffi/spark_frost/spark_frost.kt +1361 -1367
  4. package/android/src/main/jniLibs/arm64-v8a/libuniffi_spark_frost.so +0 -0
  5. package/android/src/main/jniLibs/armeabi-v7a/libuniffi_spark_frost.so +0 -0
  6. package/android/src/main/jniLibs/x86/libuniffi_spark_frost.so +0 -0
  7. package/android/src/main/jniLibs/x86_64/libuniffi_spark_frost.so +0 -0
  8. package/dist/bare/index.cjs +1342 -1346
  9. package/dist/bare/index.d.cts +114 -68
  10. package/dist/bare/index.d.ts +114 -68
  11. package/dist/bare/index.js +1266 -1279
  12. package/dist/{chunk-FXIESWE6.js → chunk-27ILUWDJ.js} +1 -1
  13. package/dist/{chunk-5ASXVNTM.js → chunk-4YFT7DAE.js} +1 -1
  14. package/dist/{chunk-FP2CRVQH.js → chunk-G3LHXHF3.js} +1045 -1308
  15. package/dist/{chunk-XI6FCNYG.js → chunk-JLF6WJ7K.js} +1 -1
  16. package/dist/{chunk-3LPEQGVJ.js → chunk-LOXWCMZL.js} +1 -1
  17. package/dist/{chunk-5HU5W56H.js → chunk-WICAF6BS.js} +2 -2
  18. package/dist/{chunk-VFN34EOX.js → chunk-YEBEN7XD.js} +258 -0
  19. package/dist/{client-pNpGP15j.d.cts → client-BIqiUNy4.d.cts} +1 -1
  20. package/dist/{client-By-N7oJS.d.ts → client-BaQf-5gD.d.ts} +1 -1
  21. package/dist/debug.cjs +1330 -1336
  22. package/dist/debug.d.cts +20 -16
  23. package/dist/debug.d.ts +20 -16
  24. package/dist/debug.js +5 -5
  25. package/dist/graphql/objects/index.d.cts +3 -3
  26. package/dist/graphql/objects/index.d.ts +3 -3
  27. package/dist/index.cjs +1363 -1365
  28. package/dist/index.d.cts +7 -7
  29. package/dist/index.d.ts +7 -7
  30. package/dist/index.js +32 -24
  31. package/dist/index.node.cjs +1363 -1365
  32. package/dist/index.node.d.cts +7 -7
  33. package/dist/index.node.d.ts +7 -7
  34. package/dist/index.node.js +31 -23
  35. package/dist/{logging-DMFVY384.d.ts → logging-BNGm6dBp.d.ts} +42 -37
  36. package/dist/{logging-DxLp34Xm.d.cts → logging-D3IfXfHG.d.cts} +42 -37
  37. package/dist/native/index.react-native.cjs +1505 -1366
  38. package/dist/native/index.react-native.d.cts +112 -58
  39. package/dist/native/index.react-native.d.ts +112 -58
  40. package/dist/native/index.react-native.js +1415 -1289
  41. package/dist/proto/spark.cjs +258 -0
  42. package/dist/proto/spark.d.cts +1 -1
  43. package/dist/proto/spark.d.ts +1 -1
  44. package/dist/proto/spark.js +5 -1
  45. package/dist/proto/spark_token.d.cts +1 -1
  46. package/dist/proto/spark_token.d.ts +1 -1
  47. package/dist/proto/spark_token.js +2 -2
  48. package/dist/{spark-By6yHsrk.d.cts → spark-DOpheE8_.d.cts} +39 -2
  49. package/dist/{spark-By6yHsrk.d.ts → spark-DOpheE8_.d.ts} +39 -2
  50. package/dist/{spark-wallet.browser-C1dQknVj.d.ts → spark-wallet.browser-B2rGwjuM.d.ts} +2 -2
  51. package/dist/{spark-wallet.browser-CNMo3IvO.d.cts → spark-wallet.browser-Ck9No4Ks.d.cts} +2 -2
  52. package/dist/{spark-wallet.node-Og6__NMh.d.ts → spark-wallet.node-BqmKsGPs.d.ts} +2 -2
  53. package/dist/{spark-wallet.node-BZJhJZKq.d.cts → spark-wallet.node-C2TIkyt4.d.cts} +2 -2
  54. package/dist/tests/test-utils.cjs +1304 -1236
  55. package/dist/tests/test-utils.d.cts +18 -4
  56. package/dist/tests/test-utils.d.ts +18 -4
  57. package/dist/tests/test-utils.js +7 -7
  58. package/dist/{token-transactions-CLR3rnYi.d.cts → token-transactions-Db8mkjnU.d.cts} +2 -2
  59. package/dist/{token-transactions-C7yefB2S.d.ts → token-transactions-DoMcrxXQ.d.ts} +2 -2
  60. package/dist/types/index.cjs +256 -0
  61. package/dist/types/index.d.cts +2 -2
  62. package/dist/types/index.d.ts +2 -2
  63. package/dist/types/index.js +2 -2
  64. package/dist/{wallet-config-BoyMVa6n.d.ts → wallet-config-Bg3kWltL.d.ts} +42 -35
  65. package/dist/{wallet-config-xom-9UFF.d.cts → wallet-config-CuZKNo9S.d.cts} +42 -35
  66. package/ios/spark_frostFFI.xcframework/ios-arm64/SparkFrost +0 -0
  67. package/ios/spark_frostFFI.xcframework/ios-arm64/spark_frostFFI.framework/spark_frostFFI +0 -0
  68. package/ios/spark_frostFFI.xcframework/ios-arm64_x86_64-simulator/SparkFrost +0 -0
  69. package/ios/spark_frostFFI.xcframework/ios-arm64_x86_64-simulator/spark_frostFFI.framework/spark_frostFFI +0 -0
  70. package/ios/spark_frostFFI.xcframework/macos-arm64_x86_64/spark_frostFFI.framework/spark_frostFFI +0 -0
  71. package/package.json +1 -1
  72. package/src/index.react-native.ts +8 -2
  73. package/src/proto/spark.ts +348 -4
  74. package/src/services/config.ts +5 -0
  75. package/src/services/coop-exit.ts +26 -107
  76. package/src/services/deposit.ts +12 -48
  77. package/src/services/signing.ts +62 -49
  78. package/src/services/transfer.ts +437 -722
  79. package/src/services/wallet-config.ts +10 -0
  80. package/src/services/xhr-transport.ts +13 -3
  81. package/src/signer/signer.react-native.ts +73 -1
  82. package/src/spark-wallet/proto-descriptors.ts +1 -1
  83. package/src/spark-wallet/spark-wallet.ts +162 -315
  84. package/src/spark-wallet/types.ts +2 -2
  85. package/src/spark_descriptors.pb +0 -0
  86. package/src/tests/integration/lightning.test.ts +1 -27
  87. package/src/tests/integration/static_deposit.test.ts +6 -9
  88. package/src/tests/integration/unilateral-exit.test.ts +117 -0
  89. package/src/tests/optimize.test.ts +31 -1
  90. package/src/tests/utils/signing.ts +33 -0
  91. package/src/tests/utils/test-faucet.ts +61 -0
  92. package/src/utils/optimize.ts +42 -0
  93. package/src/utils/transaction.ts +250 -249
  94. package/src/utils/unilateral-exit.ts +1 -40
@@ -1113,30 +1113,30 @@ function signFrost({
1113
1113
  adaptorPubKey
1114
1114
  }) {
1115
1115
  const logMsg = JSON.stringify({
1116
- message: (0, import_utils12.bytesToHex)(message),
1116
+ message: (0, import_utils13.bytesToHex)(message),
1117
1117
  keyPackage: {
1118
- secretKey: (0, import_utils12.bytesToHex)(keyPackage.secretKey),
1119
- publicKey: (0, import_utils12.bytesToHex)(keyPackage.publicKey),
1120
- verifyingKey: (0, import_utils12.bytesToHex)(keyPackage.verifyingKey)
1118
+ secretKey: (0, import_utils13.bytesToHex)(keyPackage.secretKey),
1119
+ publicKey: (0, import_utils13.bytesToHex)(keyPackage.publicKey),
1120
+ verifyingKey: (0, import_utils13.bytesToHex)(keyPackage.verifyingKey)
1121
1121
  },
1122
1122
  nonce: {
1123
- hiding: (0, import_utils12.bytesToHex)(nonce.hiding),
1124
- binding: (0, import_utils12.bytesToHex)(nonce.binding)
1123
+ hiding: (0, import_utils13.bytesToHex)(nonce.hiding),
1124
+ binding: (0, import_utils13.bytesToHex)(nonce.binding)
1125
1125
  },
1126
1126
  selfCommitment: {
1127
- hiding: (0, import_utils12.bytesToHex)(selfCommitment.hiding),
1128
- binding: (0, import_utils12.bytesToHex)(selfCommitment.binding)
1127
+ hiding: (0, import_utils13.bytesToHex)(selfCommitment.hiding),
1128
+ binding: (0, import_utils13.bytesToHex)(selfCommitment.binding)
1129
1129
  },
1130
1130
  statechainCommitments: Object.fromEntries(
1131
1131
  Object.entries(statechainCommitments ?? {}).map(([k, v]) => [
1132
1132
  k,
1133
1133
  {
1134
- hiding: (0, import_utils12.bytesToHex)(v.hiding),
1135
- binding: (0, import_utils12.bytesToHex)(v.binding)
1134
+ hiding: (0, import_utils13.bytesToHex)(v.hiding),
1135
+ binding: (0, import_utils13.bytesToHex)(v.binding)
1136
1136
  }
1137
1137
  ])
1138
1138
  ),
1139
- adaptorPubKey: adaptorPubKey ? (0, import_utils12.bytesToHex)(adaptorPubKey) : void 0
1139
+ adaptorPubKey: adaptorPubKey ? (0, import_utils13.bytesToHex)(adaptorPubKey) : void 0
1140
1140
  });
1141
1141
  SparkSdkLogger.get(LOGGER_NAMES.wasm).trace("signFrost", logMsg);
1142
1142
  const result = wasm_sign_frost(
@@ -1149,7 +1149,7 @@ function signFrost({
1149
1149
  );
1150
1150
  SparkSdkLogger.get(LOGGER_NAMES.wasm).trace(
1151
1151
  "signFrost result",
1152
- (0, import_utils12.bytesToHex)(result)
1152
+ (0, import_utils13.bytesToHex)(result)
1153
1153
  );
1154
1154
  return result;
1155
1155
  }
@@ -1165,36 +1165,36 @@ function aggregateFrost({
1165
1165
  adaptorPubKey
1166
1166
  }) {
1167
1167
  const logMsg = JSON.stringify({
1168
- message: (0, import_utils12.bytesToHex)(message),
1168
+ message: (0, import_utils13.bytesToHex)(message),
1169
1169
  statechainCommitments: Object.fromEntries(
1170
1170
  Object.entries(statechainCommitments ?? {}).map(([k, v]) => [
1171
1171
  k,
1172
1172
  {
1173
- hiding: (0, import_utils12.bytesToHex)(v.hiding),
1174
- binding: (0, import_utils12.bytesToHex)(v.binding)
1173
+ hiding: (0, import_utils13.bytesToHex)(v.hiding),
1174
+ binding: (0, import_utils13.bytesToHex)(v.binding)
1175
1175
  }
1176
1176
  ])
1177
1177
  ),
1178
1178
  selfCommitment: {
1179
- hiding: (0, import_utils12.bytesToHex)(selfCommitment.hiding),
1180
- binding: (0, import_utils12.bytesToHex)(selfCommitment.binding)
1179
+ hiding: (0, import_utils13.bytesToHex)(selfCommitment.hiding),
1180
+ binding: (0, import_utils13.bytesToHex)(selfCommitment.binding)
1181
1181
  },
1182
1182
  statechainSignatures: Object.fromEntries(
1183
1183
  Object.entries(statechainSignatures ?? {}).map(([k, v]) => [
1184
1184
  k,
1185
- (0, import_utils12.bytesToHex)(v)
1185
+ (0, import_utils13.bytesToHex)(v)
1186
1186
  ])
1187
1187
  ),
1188
- selfSignature: (0, import_utils12.bytesToHex)(selfSignature),
1188
+ selfSignature: (0, import_utils13.bytesToHex)(selfSignature),
1189
1189
  statechainPublicKeys: Object.fromEntries(
1190
1190
  Object.entries(statechainPublicKeys ?? {}).map(([k, v]) => [
1191
1191
  k,
1192
- (0, import_utils12.bytesToHex)(v)
1192
+ (0, import_utils13.bytesToHex)(v)
1193
1193
  ])
1194
1194
  ),
1195
- selfPublicKey: (0, import_utils12.bytesToHex)(selfPublicKey),
1196
- verifyingKey: (0, import_utils12.bytesToHex)(verifyingKey),
1197
- adaptorPubKey: adaptorPubKey ? (0, import_utils12.bytesToHex)(adaptorPubKey) : void 0
1195
+ selfPublicKey: (0, import_utils13.bytesToHex)(selfPublicKey),
1196
+ verifyingKey: (0, import_utils13.bytesToHex)(verifyingKey),
1197
+ adaptorPubKey: adaptorPubKey ? (0, import_utils13.bytesToHex)(adaptorPubKey) : void 0
1198
1198
  });
1199
1199
  SparkSdkLogger.get(LOGGER_NAMES.wasm).trace("aggregateFrost", logMsg);
1200
1200
  const result = wasm_aggregate_frost(
@@ -1210,7 +1210,7 @@ function aggregateFrost({
1210
1210
  );
1211
1211
  SparkSdkLogger.get(LOGGER_NAMES.wasm).trace(
1212
1212
  "aggregateFrost result",
1213
- (0, import_utils12.bytesToHex)(result)
1213
+ (0, import_utils13.bytesToHex)(result)
1214
1214
  );
1215
1215
  return result;
1216
1216
  }
@@ -1232,12 +1232,12 @@ function decryptEcies({
1232
1232
  }) {
1233
1233
  return decrypt_ecies(encryptedMsg, privateKey);
1234
1234
  }
1235
- var import_utils12;
1235
+ var import_utils13;
1236
1236
  var init_wasm = __esm({
1237
1237
  "src/spark_bindings/wasm/index.ts"() {
1238
1238
  "use strict";
1239
1239
  init_buffer();
1240
- import_utils12 = require("@noble/curves/utils");
1240
+ import_utils13 = require("@noble/curves/utils");
1241
1241
  init_spark_bindings();
1242
1242
  init_logging();
1243
1243
  }
@@ -1254,7 +1254,6 @@ __export(index_react_native_exports, {
1254
1254
  DIRECT_TIMELOCK_OFFSET: () => DIRECT_TIMELOCK_OFFSET,
1255
1255
  DefaultSparkSigner: () => ReactNativeSparkSigner,
1256
1256
  HTLC_TIMELOCK_OFFSET: () => HTLC_TIMELOCK_OFFSET,
1257
- INITIAL_DIRECT_SEQUENCE: () => INITIAL_DIRECT_SEQUENCE,
1258
1257
  INITIAL_SEQUENCE: () => INITIAL_SEQUENCE,
1259
1258
  InternalValidationError: () => InternalValidationError,
1260
1259
  LOGGER_NAMES: () => LOGGER_NAMES,
@@ -1264,12 +1263,14 @@ __export(index_react_native_exports, {
1264
1263
  NotImplementedError: () => NotImplementedError,
1265
1264
  RPCError: () => RPCError,
1266
1265
  ReactNativeSparkSigner: () => ReactNativeSparkSigner,
1266
+ ReactNativeTaprootSparkSigner: () => ReactNativeTaprootSparkSigner,
1267
1267
  SparkSDKError: () => SparkSDKError,
1268
1268
  SparkSdkLogger: () => SparkSdkLogger,
1269
1269
  SparkWallet: () => SparkWalletReactNative,
1270
1270
  SparkWalletEvent: () => SparkWalletEvent,
1271
1271
  TEST_UNILATERAL_DIRECT_SEQUENCE: () => TEST_UNILATERAL_DIRECT_SEQUENCE,
1272
1272
  TEST_UNILATERAL_SEQUENCE: () => TEST_UNILATERAL_SEQUENCE,
1273
+ TaprootSparkSigner: () => ReactNativeTaprootSparkSigner,
1273
1274
  TokenTransactionService: () => TokenTransactionService,
1274
1275
  ValidationError: () => ValidationError,
1275
1276
  WalletConfig: () => WalletConfig,
@@ -1288,21 +1289,24 @@ __export(index_react_native_exports, {
1288
1289
  constructFeeBumpTx: () => constructFeeBumpTx,
1289
1290
  constructUnilateralExitFeeBumpPackages: () => constructUnilateralExitFeeBumpPackages,
1290
1291
  constructUnilateralExitTxs: () => constructUnilateralExitTxs,
1291
- createConnectorRefundTransactions: () => createConnectorRefundTransactions,
1292
- createLeafNodeTx: () => createLeafNodeTx,
1293
- createNodeTx: () => createNodeTx,
1294
- createNodeTxs: () => createNodeTxs,
1295
- createRefundTx: () => createRefundTx,
1296
- createRefundTxs: () => createRefundTxs,
1297
- createRootTx: () => createRootTx,
1292
+ createConnectorRefundTxs: () => createConnectorRefundTxs,
1293
+ createCurrentTimelockRefundTxs: () => createCurrentTimelockRefundTxs,
1294
+ createDecrementedTimelockNodeTx: () => createDecrementedTimelockNodeTx,
1295
+ createDecrementedTimelockRefundTxs: () => createDecrementedTimelockRefundTxs,
1296
+ createInitialTimelockNodeTx: () => createInitialTimelockNodeTx,
1297
+ createInitialTimelockRefundTxs: () => createInitialTimelockRefundTxs,
1298
+ createRootNodeTx: () => createRootNodeTx,
1298
1299
  createSigningCommitment: () => createSigningCommitment,
1299
1300
  createSigningNonce: () => createSigningNonce,
1300
- createSplitTx: () => createSplitTx,
1301
+ createTestUnilateralRefundTxs: () => createTestUnilateralRefundTxs,
1302
+ createTestUnilateralTimelockNodeTx: () => createTestUnilateralTimelockNodeTx,
1303
+ createZeroTimelockNodeTx: () => createZeroTimelockNodeTx,
1301
1304
  decodeBech32mTokenIdentifier: () => decodeBech32mTokenIdentifier,
1302
1305
  decodeBytesToSigningCommitment: () => decodeBytesToSigningCommitment,
1303
1306
  decodeBytesToSigningNonce: () => decodeBytesToSigningNonce,
1304
1307
  decodeSparkAddress: () => decodeSparkAddress,
1305
1308
  doesLeafNeedRefresh: () => doesLeafNeedRefresh,
1309
+ doesTxnNeedRenewed: () => doesTxnNeedRenewed,
1306
1310
  encodeBech32mTokenIdentifier: () => encodeBech32mTokenIdentifier,
1307
1311
  encodeSigningCommitmentToBytes: () => encodeSigningCommitmentToBytes,
1308
1312
  encodeSigningNonceToBytes: () => encodeSigningNonceToBytes,
@@ -1340,12 +1344,14 @@ __export(index_react_native_exports, {
1340
1344
  getTxFromRawTxHex: () => getTxFromRawTxHex,
1341
1345
  getTxId: () => getTxId,
1342
1346
  getTxIdNoReverse: () => getTxIdNoReverse,
1347
+ hash160: () => hash160,
1343
1348
  isEphemeralAnchorOutput: () => isEphemeralAnchorOutput,
1344
1349
  isLegacySparkAddress: () => isLegacySparkAddress,
1345
1350
  isSafeForNumber: () => isSafeForNumber,
1346
1351
  isTxBroadcast: () => isTxBroadcast,
1347
1352
  isValidPublicKey: () => isValidPublicKey,
1348
1353
  isValidSparkAddress: () => isValidSparkAddress,
1354
+ isZeroTimelock: () => isZeroTimelock,
1349
1355
  lastKeyWithTarget: () => lastKeyWithTarget,
1350
1356
  maybeApplyFee: () => maybeApplyFee,
1351
1357
  modInverse: () => modInverse,
@@ -3945,6 +3951,12 @@ var RenewLeafRequest = {
3945
3951
  writer.uint32(26).fork()
3946
3952
  ).join();
3947
3953
  break;
3954
+ case "renewNodeZeroTimelockSigningJob":
3955
+ RenewNodeZeroTimelockSigningJob.encode(
3956
+ message.signingJobs.renewNodeZeroTimelockSigningJob,
3957
+ writer.uint32(34).fork()
3958
+ ).join();
3959
+ break;
3948
3960
  }
3949
3961
  return writer;
3950
3962
  },
@@ -3982,6 +3994,16 @@ var RenewLeafRequest = {
3982
3994
  };
3983
3995
  continue;
3984
3996
  }
3997
+ case 4: {
3998
+ if (tag !== 34) {
3999
+ break;
4000
+ }
4001
+ message.signingJobs = {
4002
+ $case: "renewNodeZeroTimelockSigningJob",
4003
+ renewNodeZeroTimelockSigningJob: RenewNodeZeroTimelockSigningJob.decode(reader, reader.uint32())
4004
+ };
4005
+ continue;
4006
+ }
3985
4007
  }
3986
4008
  if ((tag & 7) === 4 || tag === 0) {
3987
4009
  break;
@@ -3999,6 +4021,11 @@ var RenewLeafRequest = {
3999
4021
  } : isSet3(object.renewRefundTimelockSigningJob) ? {
4000
4022
  $case: "renewRefundTimelockSigningJob",
4001
4023
  renewRefundTimelockSigningJob: RenewRefundTimelockSigningJob.fromJSON(object.renewRefundTimelockSigningJob)
4024
+ } : isSet3(object.renewNodeZeroTimelockSigningJob) ? {
4025
+ $case: "renewNodeZeroTimelockSigningJob",
4026
+ renewNodeZeroTimelockSigningJob: RenewNodeZeroTimelockSigningJob.fromJSON(
4027
+ object.renewNodeZeroTimelockSigningJob
4028
+ )
4002
4029
  } : void 0
4003
4030
  };
4004
4031
  },
@@ -4015,6 +4042,10 @@ var RenewLeafRequest = {
4015
4042
  obj.renewRefundTimelockSigningJob = RenewRefundTimelockSigningJob.toJSON(
4016
4043
  message.signingJobs.renewRefundTimelockSigningJob
4017
4044
  );
4045
+ } else if (message.signingJobs?.$case === "renewNodeZeroTimelockSigningJob") {
4046
+ obj.renewNodeZeroTimelockSigningJob = RenewNodeZeroTimelockSigningJob.toJSON(
4047
+ message.signingJobs.renewNodeZeroTimelockSigningJob
4048
+ );
4018
4049
  }
4019
4050
  return obj;
4020
4051
  },
@@ -4047,6 +4078,17 @@ var RenewLeafRequest = {
4047
4078
  }
4048
4079
  break;
4049
4080
  }
4081
+ case "renewNodeZeroTimelockSigningJob": {
4082
+ if (object.signingJobs?.renewNodeZeroTimelockSigningJob !== void 0 && object.signingJobs?.renewNodeZeroTimelockSigningJob !== null) {
4083
+ message.signingJobs = {
4084
+ $case: "renewNodeZeroTimelockSigningJob",
4085
+ renewNodeZeroTimelockSigningJob: RenewNodeZeroTimelockSigningJob.fromPartial(
4086
+ object.signingJobs.renewNodeZeroTimelockSigningJob
4087
+ )
4088
+ };
4089
+ }
4090
+ break;
4091
+ }
4050
4092
  }
4051
4093
  return message;
4052
4094
  }
@@ -4321,6 +4363,125 @@ var RenewRefundTimelockSigningJob = {
4321
4363
  return message;
4322
4364
  }
4323
4365
  };
4366
+ function createBaseRenewNodeZeroTimelockSigningJob() {
4367
+ return {
4368
+ nodeTxSigningJob: void 0,
4369
+ refundTxSigningJob: void 0,
4370
+ directNodeTxSigningJob: void 0,
4371
+ directRefundTxSigningJob: void 0,
4372
+ directFromCpfpRefundTxSigningJob: void 0
4373
+ };
4374
+ }
4375
+ var RenewNodeZeroTimelockSigningJob = {
4376
+ encode(message, writer = new import_wire4.BinaryWriter()) {
4377
+ if (message.nodeTxSigningJob !== void 0) {
4378
+ UserSignedTxSigningJob.encode(message.nodeTxSigningJob, writer.uint32(10).fork()).join();
4379
+ }
4380
+ if (message.refundTxSigningJob !== void 0) {
4381
+ UserSignedTxSigningJob.encode(message.refundTxSigningJob, writer.uint32(18).fork()).join();
4382
+ }
4383
+ if (message.directNodeTxSigningJob !== void 0) {
4384
+ UserSignedTxSigningJob.encode(message.directNodeTxSigningJob, writer.uint32(26).fork()).join();
4385
+ }
4386
+ if (message.directRefundTxSigningJob !== void 0) {
4387
+ UserSignedTxSigningJob.encode(message.directRefundTxSigningJob, writer.uint32(34).fork()).join();
4388
+ }
4389
+ if (message.directFromCpfpRefundTxSigningJob !== void 0) {
4390
+ UserSignedTxSigningJob.encode(message.directFromCpfpRefundTxSigningJob, writer.uint32(42).fork()).join();
4391
+ }
4392
+ return writer;
4393
+ },
4394
+ decode(input, length) {
4395
+ const reader = input instanceof import_wire4.BinaryReader ? input : new import_wire4.BinaryReader(input);
4396
+ const end = length === void 0 ? reader.len : reader.pos + length;
4397
+ const message = createBaseRenewNodeZeroTimelockSigningJob();
4398
+ while (reader.pos < end) {
4399
+ const tag = reader.uint32();
4400
+ switch (tag >>> 3) {
4401
+ case 1: {
4402
+ if (tag !== 10) {
4403
+ break;
4404
+ }
4405
+ message.nodeTxSigningJob = UserSignedTxSigningJob.decode(reader, reader.uint32());
4406
+ continue;
4407
+ }
4408
+ case 2: {
4409
+ if (tag !== 18) {
4410
+ break;
4411
+ }
4412
+ message.refundTxSigningJob = UserSignedTxSigningJob.decode(reader, reader.uint32());
4413
+ continue;
4414
+ }
4415
+ case 3: {
4416
+ if (tag !== 26) {
4417
+ break;
4418
+ }
4419
+ message.directNodeTxSigningJob = UserSignedTxSigningJob.decode(reader, reader.uint32());
4420
+ continue;
4421
+ }
4422
+ case 4: {
4423
+ if (tag !== 34) {
4424
+ break;
4425
+ }
4426
+ message.directRefundTxSigningJob = UserSignedTxSigningJob.decode(reader, reader.uint32());
4427
+ continue;
4428
+ }
4429
+ case 5: {
4430
+ if (tag !== 42) {
4431
+ break;
4432
+ }
4433
+ message.directFromCpfpRefundTxSigningJob = UserSignedTxSigningJob.decode(reader, reader.uint32());
4434
+ continue;
4435
+ }
4436
+ }
4437
+ if ((tag & 7) === 4 || tag === 0) {
4438
+ break;
4439
+ }
4440
+ reader.skip(tag & 7);
4441
+ }
4442
+ return message;
4443
+ },
4444
+ fromJSON(object) {
4445
+ return {
4446
+ nodeTxSigningJob: isSet3(object.nodeTxSigningJob) ? UserSignedTxSigningJob.fromJSON(object.nodeTxSigningJob) : void 0,
4447
+ refundTxSigningJob: isSet3(object.refundTxSigningJob) ? UserSignedTxSigningJob.fromJSON(object.refundTxSigningJob) : void 0,
4448
+ directNodeTxSigningJob: isSet3(object.directNodeTxSigningJob) ? UserSignedTxSigningJob.fromJSON(object.directNodeTxSigningJob) : void 0,
4449
+ directRefundTxSigningJob: isSet3(object.directRefundTxSigningJob) ? UserSignedTxSigningJob.fromJSON(object.directRefundTxSigningJob) : void 0,
4450
+ directFromCpfpRefundTxSigningJob: isSet3(object.directFromCpfpRefundTxSigningJob) ? UserSignedTxSigningJob.fromJSON(object.directFromCpfpRefundTxSigningJob) : void 0
4451
+ };
4452
+ },
4453
+ toJSON(message) {
4454
+ const obj = {};
4455
+ if (message.nodeTxSigningJob !== void 0) {
4456
+ obj.nodeTxSigningJob = UserSignedTxSigningJob.toJSON(message.nodeTxSigningJob);
4457
+ }
4458
+ if (message.refundTxSigningJob !== void 0) {
4459
+ obj.refundTxSigningJob = UserSignedTxSigningJob.toJSON(message.refundTxSigningJob);
4460
+ }
4461
+ if (message.directNodeTxSigningJob !== void 0) {
4462
+ obj.directNodeTxSigningJob = UserSignedTxSigningJob.toJSON(message.directNodeTxSigningJob);
4463
+ }
4464
+ if (message.directRefundTxSigningJob !== void 0) {
4465
+ obj.directRefundTxSigningJob = UserSignedTxSigningJob.toJSON(message.directRefundTxSigningJob);
4466
+ }
4467
+ if (message.directFromCpfpRefundTxSigningJob !== void 0) {
4468
+ obj.directFromCpfpRefundTxSigningJob = UserSignedTxSigningJob.toJSON(message.directFromCpfpRefundTxSigningJob);
4469
+ }
4470
+ return obj;
4471
+ },
4472
+ create(base) {
4473
+ return RenewNodeZeroTimelockSigningJob.fromPartial(base ?? {});
4474
+ },
4475
+ fromPartial(object) {
4476
+ const message = createBaseRenewNodeZeroTimelockSigningJob();
4477
+ message.nodeTxSigningJob = object.nodeTxSigningJob !== void 0 && object.nodeTxSigningJob !== null ? UserSignedTxSigningJob.fromPartial(object.nodeTxSigningJob) : void 0;
4478
+ message.refundTxSigningJob = object.refundTxSigningJob !== void 0 && object.refundTxSigningJob !== null ? UserSignedTxSigningJob.fromPartial(object.refundTxSigningJob) : void 0;
4479
+ message.directNodeTxSigningJob = object.directNodeTxSigningJob !== void 0 && object.directNodeTxSigningJob !== null ? UserSignedTxSigningJob.fromPartial(object.directNodeTxSigningJob) : void 0;
4480
+ message.directRefundTxSigningJob = object.directRefundTxSigningJob !== void 0 && object.directRefundTxSigningJob !== null ? UserSignedTxSigningJob.fromPartial(object.directRefundTxSigningJob) : void 0;
4481
+ message.directFromCpfpRefundTxSigningJob = object.directFromCpfpRefundTxSigningJob !== void 0 && object.directFromCpfpRefundTxSigningJob !== null ? UserSignedTxSigningJob.fromPartial(object.directFromCpfpRefundTxSigningJob) : void 0;
4482
+ return message;
4483
+ }
4484
+ };
4324
4485
  function createBaseRenewLeafResponse() {
4325
4486
  return { renewResult: void 0 };
4326
4487
  }
@@ -4333,6 +4494,9 @@ var RenewLeafResponse = {
4333
4494
  case "renewRefundTimelockResult":
4334
4495
  RenewRefundTimelockResult.encode(message.renewResult.renewRefundTimelockResult, writer.uint32(18).fork()).join();
4335
4496
  break;
4497
+ case "renewNodeZeroTimelockResult":
4498
+ RenewNodeZeroTimelockResult.encode(message.renewResult.renewNodeZeroTimelockResult, writer.uint32(26).fork()).join();
4499
+ break;
4336
4500
  }
4337
4501
  return writer;
4338
4502
  },
@@ -4363,6 +4527,16 @@ var RenewLeafResponse = {
4363
4527
  };
4364
4528
  continue;
4365
4529
  }
4530
+ case 3: {
4531
+ if (tag !== 26) {
4532
+ break;
4533
+ }
4534
+ message.renewResult = {
4535
+ $case: "renewNodeZeroTimelockResult",
4536
+ renewNodeZeroTimelockResult: RenewNodeZeroTimelockResult.decode(reader, reader.uint32())
4537
+ };
4538
+ continue;
4539
+ }
4366
4540
  }
4367
4541
  if ((tag & 7) === 4 || tag === 0) {
4368
4542
  break;
@@ -4379,6 +4553,9 @@ var RenewLeafResponse = {
4379
4553
  } : isSet3(object.renewRefundTimelockResult) ? {
4380
4554
  $case: "renewRefundTimelockResult",
4381
4555
  renewRefundTimelockResult: RenewRefundTimelockResult.fromJSON(object.renewRefundTimelockResult)
4556
+ } : isSet3(object.renewNodeZeroTimelockResult) ? {
4557
+ $case: "renewNodeZeroTimelockResult",
4558
+ renewNodeZeroTimelockResult: RenewNodeZeroTimelockResult.fromJSON(object.renewNodeZeroTimelockResult)
4382
4559
  } : void 0
4383
4560
  };
4384
4561
  },
@@ -4388,6 +4565,10 @@ var RenewLeafResponse = {
4388
4565
  obj.renewNodeTimelockResult = RenewNodeTimelockResult.toJSON(message.renewResult.renewNodeTimelockResult);
4389
4566
  } else if (message.renewResult?.$case === "renewRefundTimelockResult") {
4390
4567
  obj.renewRefundTimelockResult = RenewRefundTimelockResult.toJSON(message.renewResult.renewRefundTimelockResult);
4568
+ } else if (message.renewResult?.$case === "renewNodeZeroTimelockResult") {
4569
+ obj.renewNodeZeroTimelockResult = RenewNodeZeroTimelockResult.toJSON(
4570
+ message.renewResult.renewNodeZeroTimelockResult
4571
+ );
4391
4572
  }
4392
4573
  return obj;
4393
4574
  },
@@ -4417,6 +4598,17 @@ var RenewLeafResponse = {
4417
4598
  }
4418
4599
  break;
4419
4600
  }
4601
+ case "renewNodeZeroTimelockResult": {
4602
+ if (object.renewResult?.renewNodeZeroTimelockResult !== void 0 && object.renewResult?.renewNodeZeroTimelockResult !== null) {
4603
+ message.renewResult = {
4604
+ $case: "renewNodeZeroTimelockResult",
4605
+ renewNodeZeroTimelockResult: RenewNodeZeroTimelockResult.fromPartial(
4606
+ object.renewResult.renewNodeZeroTimelockResult
4607
+ )
4608
+ };
4609
+ }
4610
+ break;
4611
+ }
4420
4612
  }
4421
4613
  return message;
4422
4614
  }
@@ -4540,6 +4732,74 @@ var RenewRefundTimelockResult = {
4540
4732
  return message;
4541
4733
  }
4542
4734
  };
4735
+ function createBaseRenewNodeZeroTimelockResult() {
4736
+ return { splitNode: void 0, node: void 0 };
4737
+ }
4738
+ var RenewNodeZeroTimelockResult = {
4739
+ encode(message, writer = new import_wire4.BinaryWriter()) {
4740
+ if (message.splitNode !== void 0) {
4741
+ TreeNode.encode(message.splitNode, writer.uint32(10).fork()).join();
4742
+ }
4743
+ if (message.node !== void 0) {
4744
+ TreeNode.encode(message.node, writer.uint32(18).fork()).join();
4745
+ }
4746
+ return writer;
4747
+ },
4748
+ decode(input, length) {
4749
+ const reader = input instanceof import_wire4.BinaryReader ? input : new import_wire4.BinaryReader(input);
4750
+ const end = length === void 0 ? reader.len : reader.pos + length;
4751
+ const message = createBaseRenewNodeZeroTimelockResult();
4752
+ while (reader.pos < end) {
4753
+ const tag = reader.uint32();
4754
+ switch (tag >>> 3) {
4755
+ case 1: {
4756
+ if (tag !== 10) {
4757
+ break;
4758
+ }
4759
+ message.splitNode = TreeNode.decode(reader, reader.uint32());
4760
+ continue;
4761
+ }
4762
+ case 2: {
4763
+ if (tag !== 18) {
4764
+ break;
4765
+ }
4766
+ message.node = TreeNode.decode(reader, reader.uint32());
4767
+ continue;
4768
+ }
4769
+ }
4770
+ if ((tag & 7) === 4 || tag === 0) {
4771
+ break;
4772
+ }
4773
+ reader.skip(tag & 7);
4774
+ }
4775
+ return message;
4776
+ },
4777
+ fromJSON(object) {
4778
+ return {
4779
+ splitNode: isSet3(object.splitNode) ? TreeNode.fromJSON(object.splitNode) : void 0,
4780
+ node: isSet3(object.node) ? TreeNode.fromJSON(object.node) : void 0
4781
+ };
4782
+ },
4783
+ toJSON(message) {
4784
+ const obj = {};
4785
+ if (message.splitNode !== void 0) {
4786
+ obj.splitNode = TreeNode.toJSON(message.splitNode);
4787
+ }
4788
+ if (message.node !== void 0) {
4789
+ obj.node = TreeNode.toJSON(message.node);
4790
+ }
4791
+ return obj;
4792
+ },
4793
+ create(base) {
4794
+ return RenewNodeZeroTimelockResult.fromPartial(base ?? {});
4795
+ },
4796
+ fromPartial(object) {
4797
+ const message = createBaseRenewNodeZeroTimelockResult();
4798
+ message.splitNode = object.splitNode !== void 0 && object.splitNode !== null ? TreeNode.fromPartial(object.splitNode) : void 0;
4799
+ message.node = object.node !== void 0 && object.node !== null ? TreeNode.fromPartial(object.node) : void 0;
4800
+ return message;
4801
+ }
4802
+ };
4543
4803
  function createBaseNodeSignatureShares() {
4544
4804
  return {
4545
4805
  nodeId: "",
@@ -18242,7 +18502,11 @@ var BASE_CONFIG = {
18242
18502
  console: {
18243
18503
  otel: false
18244
18504
  },
18245
- events: {}
18505
+ events: {},
18506
+ optimizationOptions: {
18507
+ auto: true,
18508
+ multiplicity: 0
18509
+ }
18246
18510
  };
18247
18511
  var LOCAL_WALLET_CONFIG = {
18248
18512
  ...BASE_CONFIG,
@@ -19899,6 +20163,7 @@ function getTransferPackageSigningPayload(transferID, transferPackage) {
19899
20163
 
19900
20164
  // src/utils/transaction.ts
19901
20165
  init_buffer();
20166
+ var import_utils11 = require("@noble/hashes/utils");
19902
20167
  var import_btc_signer = require("@scure/btc-signer");
19903
20168
  var INITIAL_TIMELOCK = 2e3;
19904
20169
  var TEST_UNILATERAL_TIMELOCK = 100;
@@ -19907,9 +20172,9 @@ var DIRECT_TIMELOCK_OFFSET = 50;
19907
20172
  var HTLC_TIMELOCK_OFFSET = 70;
19908
20173
  var DIRECT_HTLC_TIMELOCK_OFFSET = 85;
19909
20174
  var INITIAL_SEQUENCE = 1 << 30 | INITIAL_TIMELOCK;
19910
- var INITIAL_DIRECT_SEQUENCE = 1 << 30 | INITIAL_TIMELOCK + DIRECT_TIMELOCK_OFFSET;
19911
20175
  var TEST_UNILATERAL_SEQUENCE = 1 << 30 | TEST_UNILATERAL_TIMELOCK;
19912
20176
  var TEST_UNILATERAL_DIRECT_SEQUENCE = 1 << 30 | TEST_UNILATERAL_TIMELOCK + DIRECT_TIMELOCK_OFFSET;
20177
+ var INITIAL_ROOT_NODE_SEQUENCE = 1 << 30 | 0;
19913
20178
  var ESTIMATED_TX_SIZE = 191;
19914
20179
  var DEFAULT_SATS_PER_VBYTE = 5;
19915
20180
  var DEFAULT_FEE_SATS = ESTIMATED_TX_SIZE * DEFAULT_SATS_PER_VBYTE;
@@ -19919,63 +20184,8 @@ function maybeApplyFee(amount) {
19919
20184
  }
19920
20185
  return amount;
19921
20186
  }
19922
- function createRootTx(depositOutPoint, depositTxOut) {
19923
- const cpfpRootTx = new import_btc_signer.Transaction({
19924
- version: 3,
19925
- allowUnknownOutputs: true
19926
- });
19927
- cpfpRootTx.addInput(depositOutPoint);
19928
- cpfpRootTx.addOutput(depositTxOut);
19929
- cpfpRootTx.addOutput(getEphemeralAnchorOutput());
19930
- const directRootTx = new import_btc_signer.Transaction({
19931
- version: 3,
19932
- allowUnknownOutputs: true
19933
- });
19934
- directRootTx.addInput(depositOutPoint);
19935
- directRootTx.addOutput({
19936
- script: depositTxOut.script,
19937
- amount: maybeApplyFee(depositTxOut.amount ?? 0n)
19938
- });
19939
- return [cpfpRootTx, directRootTx];
19940
- }
19941
- function createSplitTx(parentOutPoint, childTxOuts) {
19942
- const cpfpSplitTx = new import_btc_signer.Transaction({
19943
- version: 3,
19944
- allowUnknownOutputs: true
19945
- });
19946
- cpfpSplitTx.addInput(parentOutPoint);
19947
- for (const txOut of childTxOuts) {
19948
- cpfpSplitTx.addOutput(txOut);
19949
- }
19950
- cpfpSplitTx.addOutput(getEphemeralAnchorOutput());
19951
- const directSplitTx = new import_btc_signer.Transaction({
19952
- version: 3,
19953
- allowUnknownOutputs: true
19954
- });
19955
- directSplitTx.addInput(parentOutPoint);
19956
- let totalOutputAmount = 0n;
19957
- for (const txOut of childTxOuts) {
19958
- totalOutputAmount += txOut.amount ?? 0n;
19959
- }
19960
- if (totalOutputAmount > BigInt(DEFAULT_FEE_SATS)) {
19961
- const feeRatio = Number(DEFAULT_FEE_SATS) / Number(totalOutputAmount);
19962
- for (const txOut of childTxOuts) {
19963
- const adjustedAmount = BigInt(
19964
- Math.floor(Number(txOut.amount ?? 0n) * (1 - feeRatio))
19965
- );
19966
- directSplitTx.addOutput({
19967
- script: txOut.script,
19968
- amount: adjustedAmount
19969
- });
19970
- }
19971
- } else {
19972
- for (const txOut of childTxOuts) {
19973
- directSplitTx.addOutput(txOut);
19974
- }
19975
- }
19976
- return [cpfpSplitTx, directSplitTx];
19977
- }
19978
20187
  function createNodeTx({
20188
+ sequence,
19979
20189
  txOut,
19980
20190
  parentOutPoint,
19981
20191
  applyFee,
@@ -19985,7 +20195,10 @@ function createNodeTx({
19985
20195
  version: 3,
19986
20196
  allowUnknownOutputs: true
19987
20197
  });
19988
- nodeTx.addInput(parentOutPoint);
20198
+ nodeTx.addInput({
20199
+ ...parentOutPoint,
20200
+ sequence
20201
+ });
19989
20202
  if (applyFee) {
19990
20203
  nodeTx.addOutput({
19991
20204
  script: txOut.script,
@@ -19999,52 +20212,92 @@ function createNodeTx({
19999
20212
  }
20000
20213
  return nodeTx;
20001
20214
  }
20002
- function createNodeTxs(txOut, txIn, directTxIn) {
20003
- const cpfpNodeTx = createNodeTx({
20004
- txOut,
20005
- parentOutPoint: txIn,
20006
- includeAnchor: true
20007
- });
20008
- let directNodeTx;
20009
- if (directTxIn) {
20010
- directNodeTx = createNodeTx({
20011
- txOut,
20012
- parentOutPoint: directTxIn,
20013
- includeAnchor: false,
20014
- applyFee: true
20215
+ function createNodeTxs({
20216
+ parentTx,
20217
+ sequence,
20218
+ directSequence,
20219
+ vout
20220
+ }) {
20221
+ const parentOutput = parentTx.getOutput(vout);
20222
+ if (!parentOutput.amount || !parentOutput.script) {
20223
+ throw new ValidationError("Parent output amount or script not found", {
20224
+ field: "parentOutput",
20225
+ value: parentOutput
20015
20226
  });
20016
20227
  }
20017
- return { cpfpNodeTx, directNodeTx };
20228
+ const output = {
20229
+ script: parentOutput.script,
20230
+ amount: parentOutput.amount
20231
+ };
20232
+ const input = {
20233
+ txid: (0, import_utils11.hexToBytes)(getTxId(parentTx)),
20234
+ index: vout
20235
+ };
20236
+ const nodeTx = createNodeTx({
20237
+ sequence,
20238
+ txOut: output,
20239
+ parentOutPoint: input,
20240
+ includeAnchor: true
20241
+ });
20242
+ const directNodeTx = createNodeTx({
20243
+ sequence: directSequence ?? sequence + DIRECT_TIMELOCK_OFFSET,
20244
+ txOut: output,
20245
+ parentOutPoint: input,
20246
+ includeAnchor: false,
20247
+ applyFee: true
20248
+ });
20249
+ return { nodeTx, directNodeTx };
20018
20250
  }
20019
- function createLeafNodeTx(sequence, directSequence, parentOutPoint, txOut, shouldCalculateFee) {
20020
- const cpfpLeafTx = new import_btc_signer.Transaction({
20021
- version: 3,
20022
- allowUnknownOutputs: true
20251
+ function createRootNodeTx(parentTx, vout) {
20252
+ return createNodeTxs({
20253
+ parentTx,
20254
+ sequence: INITIAL_ROOT_NODE_SEQUENCE,
20255
+ vout
20023
20256
  });
20024
- cpfpLeafTx.addInput({
20025
- ...parentOutPoint,
20026
- sequence
20257
+ }
20258
+ function createZeroTimelockNodeTx(parentTx) {
20259
+ return createNodeTxs({
20260
+ parentTx,
20261
+ sequence: INITIAL_ROOT_NODE_SEQUENCE,
20262
+ directSequence: DIRECT_TIMELOCK_OFFSET,
20263
+ vout: 0
20027
20264
  });
20028
- cpfpLeafTx.addOutput(txOut);
20029
- cpfpLeafTx.addOutput(getEphemeralAnchorOutput());
20030
- const directLeafTx = new import_btc_signer.Transaction({
20031
- version: 3,
20032
- allowUnknownOutputs: true
20265
+ }
20266
+ function createInitialTimelockNodeTx(parentTx) {
20267
+ return createNodeTxs({
20268
+ parentTx,
20269
+ sequence: INITIAL_SEQUENCE,
20270
+ vout: 0
20033
20271
  });
20034
- directLeafTx.addInput({
20035
- ...parentOutPoint,
20036
- sequence: directSequence
20272
+ }
20273
+ function createDecrementedTimelockNodeTx(parentTx, currentTx) {
20274
+ const currentSequence = currentTx.getInput(0).sequence;
20275
+ if (!currentSequence) {
20276
+ throw new ValidationError("Current sequence not found", {
20277
+ field: "currentSequence",
20278
+ value: currentSequence
20279
+ });
20280
+ }
20281
+ return createNodeTxs({
20282
+ parentTx,
20283
+ sequence: getNextTransactionSequence(currentSequence).nextSequence,
20284
+ vout: 0
20037
20285
  });
20038
- const amountSats = txOut.amount ?? 0n;
20039
- let outputAmount = amountSats;
20040
- if (shouldCalculateFee) {
20041
- outputAmount = maybeApplyFee(amountSats);
20286
+ }
20287
+ function createTestUnilateralTimelockNodeTx(parentTx, nodeTx) {
20288
+ const sequence = nodeTx.getInput(0).sequence;
20289
+ if (!sequence) {
20290
+ throw new ValidationError("Sequence not found", {
20291
+ field: "sequence",
20292
+ value: sequence
20293
+ });
20042
20294
  }
20043
- directLeafTx.addOutput({
20044
- script: txOut.script,
20045
- amount: outputAmount
20295
+ const isBit30Defined = (sequence || 0) & 1 << 30;
20296
+ return createNodeTxs({
20297
+ parentTx,
20298
+ sequence: isBit30Defined | TEST_UNILATERAL_TIMELOCK,
20299
+ vout: 0
20046
20300
  });
20047
- return [cpfpLeafTx, directLeafTx];
20048
20301
  }
20049
20302
  function createRefundTx({
20050
20303
  sequence,
@@ -20100,110 +20353,109 @@ function getNextHTLCTransactionSequence(currSequence, isNodeTx) {
20100
20353
  };
20101
20354
  }
20102
20355
  function createRefundTxs({
20103
- sequence,
20104
- directSequence,
20105
- input,
20106
- directInput,
20107
- amountSats,
20356
+ nodeTx,
20357
+ directNodeTx,
20108
20358
  receivingPubkey,
20109
- network
20359
+ network,
20360
+ sequence
20110
20361
  }) {
20111
- const cpfpRefundTx = createRefundTx({
20112
- sequence,
20113
- input,
20114
- amountSats,
20115
- receivingPubkey,
20116
- network,
20117
- shouldCalculateFee: false,
20118
- includeAnchor: true
20119
- });
20362
+ const refundInput = {
20363
+ txid: (0, import_utils11.hexToBytes)(getTxId(nodeTx)),
20364
+ index: 0
20365
+ };
20366
+ const nodeAmountSats = nodeTx.getOutput(0).amount;
20367
+ if (nodeAmountSats === void 0) {
20368
+ throw new ValidationError("Node amount not found", {
20369
+ field: "nodeAmountSats",
20370
+ value: nodeAmountSats
20371
+ });
20372
+ }
20120
20373
  let directRefundTx;
20121
- let directFromCpfpRefundTx;
20122
- if (directSequence && directInput) {
20374
+ if (directNodeTx) {
20375
+ const directRefundInput = {
20376
+ txid: (0, import_utils11.hexToBytes)(getTxId(directNodeTx)),
20377
+ index: 0
20378
+ };
20379
+ const directAmountSats = directNodeTx.getOutput(0).amount;
20380
+ if (directAmountSats === void 0) {
20381
+ throw new ValidationError("Direct amount not found", {
20382
+ field: "directAmountSats",
20383
+ value: directAmountSats
20384
+ });
20385
+ }
20123
20386
  directRefundTx = createRefundTx({
20124
- sequence: directSequence,
20125
- input: directInput,
20126
- amountSats,
20127
- receivingPubkey,
20128
- network,
20129
- shouldCalculateFee: true,
20130
- includeAnchor: false
20131
- });
20132
- directFromCpfpRefundTx = createRefundTx({
20133
- sequence: directSequence,
20134
- input,
20135
- amountSats,
20387
+ sequence: sequence + DIRECT_TIMELOCK_OFFSET,
20388
+ input: directRefundInput,
20389
+ amountSats: directAmountSats,
20136
20390
  receivingPubkey,
20137
20391
  network,
20138
20392
  shouldCalculateFee: true,
20139
20393
  includeAnchor: false
20140
20394
  });
20141
- } else if (directInput && !directSequence) {
20142
- throw new ValidationError(
20143
- "directSequence must be provided if directInput is",
20144
- {
20145
- field: "directSequence",
20146
- value: directSequence
20147
- }
20148
- );
20149
20395
  }
20150
- return { cpfpRefundTx, directRefundTx, directFromCpfpRefundTx };
20151
- }
20152
- function createConnectorRefundTransactions(sequence, cpfpNodeOutPoint, directNodeOutPoint, connectorOutput, amountSats, receiverPubKey, network, shouldCalculateFee) {
20153
- const cpfpRefundTx = new import_btc_signer.Transaction({
20154
- version: 3,
20155
- allowUnknownOutputs: true
20396
+ const cpfpRefundTx = createRefundTx({
20397
+ sequence,
20398
+ input: refundInput,
20399
+ amountSats: nodeAmountSats,
20400
+ receivingPubkey,
20401
+ network,
20402
+ shouldCalculateFee: false,
20403
+ includeAnchor: true
20156
20404
  });
20157
- cpfpRefundTx.addInput({
20158
- ...cpfpNodeOutPoint,
20159
- sequence
20405
+ const directFromCpfpRefundTx = createRefundTx({
20406
+ sequence: sequence + DIRECT_TIMELOCK_OFFSET,
20407
+ input: refundInput,
20408
+ amountSats: nodeAmountSats,
20409
+ receivingPubkey,
20410
+ network,
20411
+ shouldCalculateFee: true,
20412
+ includeAnchor: false
20160
20413
  });
20161
- cpfpRefundTx.addInput(connectorOutput);
20162
- const receiverScript = getP2TRScriptFromPublicKey(receiverPubKey, network);
20163
- cpfpRefundTx.addOutput({
20164
- script: receiverScript,
20165
- amount: amountSats
20414
+ return { cpfpRefundTx, directRefundTx, directFromCpfpRefundTx };
20415
+ }
20416
+ function createInitialTimelockRefundTxs(params) {
20417
+ return createRefundTxs({
20418
+ ...params,
20419
+ sequence: INITIAL_SEQUENCE
20166
20420
  });
20167
- const directRefundTx = new import_btc_signer.Transaction({
20168
- version: 3,
20169
- allowUnknownOutputs: true
20421
+ }
20422
+ function createDecrementedTimelockRefundTxs(params) {
20423
+ const nextSequence = getNextTransactionSequence(params.sequence).nextSequence;
20424
+ return createRefundTxs({
20425
+ ...params,
20426
+ sequence: nextSequence
20170
20427
  });
20171
- directRefundTx.addInput({
20172
- ...directNodeOutPoint,
20173
- sequence
20428
+ }
20429
+ function createCurrentTimelockRefundTxs(params) {
20430
+ return createRefundTxs(params);
20431
+ }
20432
+ function createTestUnilateralRefundTxs(params) {
20433
+ return createRefundTxs({
20434
+ ...params,
20435
+ sequence: TEST_UNILATERAL_SEQUENCE
20174
20436
  });
20175
- directRefundTx.addInput(connectorOutput);
20176
- let outputAmount = amountSats;
20177
- if (shouldCalculateFee) {
20178
- outputAmount = maybeApplyFee(amountSats);
20437
+ }
20438
+ function createConnectorRefundTxs(params) {
20439
+ const { connectorOutput, ...baseParams } = params;
20440
+ const { cpfpRefundTx, directRefundTx, directFromCpfpRefundTx } = createDecrementedTimelockRefundTxs(baseParams);
20441
+ cpfpRefundTx.addInput(connectorOutput);
20442
+ if (directRefundTx) {
20443
+ directRefundTx.addInput(connectorOutput);
20179
20444
  }
20180
- directRefundTx.addOutput({
20181
- script: receiverScript,
20182
- amount: outputAmount
20183
- });
20184
- const directFromCpfpTx = new import_btc_signer.Transaction({
20185
- version: 3,
20186
- allowUnknownOutputs: true
20187
- });
20188
- directFromCpfpTx.addInput({
20189
- ...cpfpNodeOutPoint,
20190
- sequence
20191
- });
20192
- directFromCpfpTx.addInput(connectorOutput);
20193
- directFromCpfpTx.addOutput({
20194
- script: receiverScript,
20195
- amount: outputAmount
20196
- });
20197
- return [cpfpRefundTx, directRefundTx, directFromCpfpTx];
20445
+ if (directFromCpfpRefundTx) {
20446
+ directFromCpfpRefundTx.addInput(connectorOutput);
20447
+ }
20448
+ return { cpfpRefundTx, directRefundTx, directFromCpfpRefundTx };
20198
20449
  }
20199
20450
  function getCurrentTimelock(currSequence) {
20200
20451
  return (currSequence || 0) & 65535;
20201
20452
  }
20202
20453
  function getTransactionSequence(currSequence) {
20203
20454
  const timelock = getCurrentTimelock(currSequence);
20455
+ const isBit30Defined = (currSequence || 0) & 1 << 30;
20204
20456
  return {
20205
- nextSequence: 1 << 30 | timelock,
20206
- nextDirectSequence: 1 << 30 | timelock + DIRECT_TIMELOCK_OFFSET
20457
+ nextSequence: isBit30Defined | timelock,
20458
+ nextDirectSequence: isBit30Defined | timelock + DIRECT_TIMELOCK_OFFSET
20207
20459
  };
20208
20460
  }
20209
20461
  function checkIfValidSequence(currSequence) {
@@ -20222,6 +20474,13 @@ function checkIfValidSequence(currSequence) {
20222
20474
  });
20223
20475
  }
20224
20476
  }
20477
+ function isZeroTimelock(currSequence) {
20478
+ return getCurrentTimelock(currSequence) === 0;
20479
+ }
20480
+ function doesTxnNeedRenewed(currSequence) {
20481
+ const currentTimelock = getCurrentTimelock(currSequence);
20482
+ return currentTimelock <= 100;
20483
+ }
20225
20484
  function doesLeafNeedRefresh(currSequence, isNodeTx) {
20226
20485
  const currentTimelock = getCurrentTimelock(currSequence);
20227
20486
  if (isNodeTx) {
@@ -20232,6 +20491,7 @@ function doesLeafNeedRefresh(currSequence, isNodeTx) {
20232
20491
  function getNextTransactionSequence(currSequence, isNodeTx) {
20233
20492
  const currentTimelock = getCurrentTimelock(currSequence);
20234
20493
  const nextTimelock = currentTimelock - TIME_LOCK_INTERVAL;
20494
+ const isBit30Defined = (currSequence || 0) & 1 << 30;
20235
20495
  if (isNodeTx && nextTimelock < 0) {
20236
20496
  throw new ValidationError("timelock interval is less than 0", {
20237
20497
  field: "nextTimelock",
@@ -20246,8 +20506,8 @@ function getNextTransactionSequence(currSequence, isNodeTx) {
20246
20506
  });
20247
20507
  }
20248
20508
  return {
20249
- nextSequence: 1 << 30 | nextTimelock,
20250
- nextDirectSequence: 1 << 30 | nextTimelock + DIRECT_TIMELOCK_OFFSET
20509
+ nextSequence: isBit30Defined | nextTimelock,
20510
+ nextDirectSequence: isBit30Defined | nextTimelock + DIRECT_TIMELOCK_OFFSET
20251
20511
  };
20252
20512
  }
20253
20513
  function getEphemeralAnchorOutput() {
@@ -20260,7 +20520,7 @@ function getEphemeralAnchorOutput() {
20260
20520
 
20261
20521
  // src/utils/unilateral-exit.ts
20262
20522
  init_buffer();
20263
- var import_utils11 = require("@noble/curves/utils");
20523
+ var import_utils12 = require("@noble/curves/utils");
20264
20524
  var import_legacy = require("@noble/hashes/legacy");
20265
20525
  var import_sha25 = require("@noble/hashes/sha2");
20266
20526
  var btc3 = __toESM(require("@scure/btc-signer"), 1);
@@ -20275,7 +20535,7 @@ function isEphemeralAnchorOutput(script, amount) {
20275
20535
  }
20276
20536
  async function constructUnilateralExitTxs(nodeHexStrings, sparkClient, network) {
20277
20537
  const result = [];
20278
- const nodes = nodeHexStrings.map((hex) => TreeNode.decode((0, import_utils11.hexToBytes)(hex)));
20538
+ const nodes = nodeHexStrings.map((hex) => TreeNode.decode((0, import_utils12.hexToBytes)(hex)));
20279
20539
  const nodeMap = /* @__PURE__ */ new Map();
20280
20540
  for (const node of nodes) {
20281
20541
  nodeMap.set(node.id, node);
@@ -20331,10 +20591,10 @@ async function constructUnilateralExitTxs(nodeHexStrings, sparkClient, network)
20331
20591
  }
20332
20592
  }
20333
20593
  for (const chainNode of chain) {
20334
- const nodeTx = (0, import_utils11.bytesToHex)(chainNode.nodeTx);
20594
+ const nodeTx = (0, import_utils12.bytesToHex)(chainNode.nodeTx);
20335
20595
  transactions.push(nodeTx);
20336
20596
  if (chainNode.id === node.id) {
20337
- const refundTx = (0, import_utils11.bytesToHex)(chainNode.refundTx);
20597
+ const refundTx = (0, import_utils12.bytesToHex)(chainNode.refundTx);
20338
20598
  transactions.push(refundTx);
20339
20599
  }
20340
20600
  }
@@ -20364,7 +20624,7 @@ async function constructUnilateralExitFeeBumpPackages(nodeHexStrings, utxos, fee
20364
20624
  `Node hex string at index ${i} appears to be a raw transaction hex, not a TreeNode protobuf. Use 'leafidtohex' command to convert node IDs to proper hex strings.`
20365
20625
  );
20366
20626
  }
20367
- const nodeBytes = (0, import_utils11.hexToBytes)(hex);
20627
+ const nodeBytes = (0, import_utils12.hexToBytes)(hex);
20368
20628
  const node = TreeNode.decode(nodeBytes);
20369
20629
  if (!node.id) {
20370
20630
  throw new Error(
@@ -20440,7 +20700,7 @@ async function constructUnilateralExitFeeBumpPackages(nodeHexStrings, utxos, fee
20440
20700
  }
20441
20701
  }
20442
20702
  for (const chainNode of chain) {
20443
- let nodeTxHex = (0, import_utils11.bytesToHex)(chainNode.nodeTx);
20703
+ let nodeTxHex = (0, import_utils12.bytesToHex)(chainNode.nodeTx);
20444
20704
  try {
20445
20705
  const txObj = getTxFromRawTxHex(nodeTxHex);
20446
20706
  const txid = getTxId(txObj);
@@ -20457,7 +20717,7 @@ async function constructUnilateralExitFeeBumpPackages(nodeHexStrings, utxos, fee
20457
20717
  for (let i = txObj.outputsLength - 1; i >= 0; i--) {
20458
20718
  const output = txObj.getOutput(i);
20459
20719
  if (output?.amount === 0n && output.script) {
20460
- anchorOutputScriptHex = (0, import_utils11.bytesToHex)(output.script);
20720
+ anchorOutputScriptHex = (0, import_utils12.bytesToHex)(output.script);
20461
20721
  break;
20462
20722
  }
20463
20723
  }
@@ -20478,11 +20738,11 @@ async function constructUnilateralExitFeeBumpPackages(nodeHexStrings, utxos, fee
20478
20738
  usedUtxos,
20479
20739
  correctedParentTx
20480
20740
  } = constructFeeBumpTx(nodeTxHex, availableUtxos, feeRate, void 0);
20481
- const feeBumpTx = btc3.Transaction.fromPSBT((0, import_utils11.hexToBytes)(nodeFeeBumpPsbt));
20741
+ const feeBumpTx = btc3.Transaction.fromPSBT((0, import_utils12.hexToBytes)(nodeFeeBumpPsbt));
20482
20742
  var feeBumpOut = feeBumpTx.outputsLength === 1 ? feeBumpTx.getOutput(0) : null;
20483
20743
  var feeBumpOutPubKey = null;
20484
20744
  for (const usedUtxo of usedUtxos) {
20485
- if (feeBumpOut && (0, import_utils11.bytesToHex)(feeBumpOut.script) == usedUtxo.script) {
20745
+ if (feeBumpOut && (0, import_utils12.bytesToHex)(feeBumpOut.script) == usedUtxo.script) {
20486
20746
  feeBumpOutPubKey = usedUtxo.publicKey;
20487
20747
  }
20488
20748
  const index = availableUtxos.findIndex(
@@ -20497,20 +20757,20 @@ async function constructUnilateralExitFeeBumpPackages(nodeHexStrings, utxos, fee
20497
20757
  txid: getTxId(feeBumpTx),
20498
20758
  vout: 0,
20499
20759
  value: feeBumpOut.amount,
20500
- script: (0, import_utils11.bytesToHex)(feeBumpOut.script),
20760
+ script: (0, import_utils12.bytesToHex)(feeBumpOut.script),
20501
20761
  publicKey: feeBumpOutPubKey
20502
20762
  });
20503
20763
  const finalNodeTx = correctedParentTx || nodeTxHex;
20504
20764
  txPackages.push({ tx: finalNodeTx, feeBumpPsbt: nodeFeeBumpPsbt });
20505
20765
  if (chainNode.id === node.id) {
20506
- let refundTxHex = (0, import_utils11.bytesToHex)(chainNode.refundTx);
20766
+ let refundTxHex = (0, import_utils12.bytesToHex)(chainNode.refundTx);
20507
20767
  try {
20508
20768
  const txObj = getTxFromRawTxHex(refundTxHex);
20509
20769
  let anchorOutputScriptHex;
20510
20770
  for (let i = txObj.outputsLength - 1; i >= 0; i--) {
20511
20771
  const output = txObj.getOutput(i);
20512
20772
  if (output?.amount === 0n && output.script) {
20513
- anchorOutputScriptHex = (0, import_utils11.bytesToHex)(output.script);
20773
+ anchorOutputScriptHex = (0, import_utils12.bytesToHex)(output.script);
20514
20774
  break;
20515
20775
  }
20516
20776
  }
@@ -20533,12 +20793,12 @@ async function constructUnilateralExitFeeBumpPackages(nodeHexStrings, utxos, fee
20533
20793
  void 0
20534
20794
  );
20535
20795
  const feeBumpTx2 = btc3.Transaction.fromPSBT(
20536
- (0, import_utils11.hexToBytes)(refundFeeBump.feeBumpPsbt)
20796
+ (0, import_utils12.hexToBytes)(refundFeeBump.feeBumpPsbt)
20537
20797
  );
20538
20798
  var feeBumpOut = feeBumpTx2.outputsLength === 1 ? feeBumpTx2.getOutput(0) : null;
20539
20799
  var feeBumpOutPubKey = null;
20540
20800
  for (const usedUtxo of usedUtxos) {
20541
- if (feeBumpOut && (0, import_utils11.bytesToHex)(feeBumpOut.script) == usedUtxo.script) {
20801
+ if (feeBumpOut && (0, import_utils12.bytesToHex)(feeBumpOut.script) == usedUtxo.script) {
20542
20802
  feeBumpOutPubKey = usedUtxo.publicKey;
20543
20803
  }
20544
20804
  const index = availableUtxos.findIndex(
@@ -20553,7 +20813,7 @@ async function constructUnilateralExitFeeBumpPackages(nodeHexStrings, utxos, fee
20553
20813
  txid: getTxId(feeBumpTx2),
20554
20814
  vout: 0,
20555
20815
  value: feeBumpOut.amount,
20556
- script: (0, import_utils11.bytesToHex)(feeBumpOut.script),
20816
+ script: (0, import_utils12.bytesToHex)(feeBumpOut.script),
20557
20817
  publicKey: feeBumpOutPubKey
20558
20818
  });
20559
20819
  txPackages.push({
@@ -20648,10 +20908,10 @@ function constructFeeBumpTx(txHex, utxos, feeRate, previousFeeBumpTx) {
20648
20908
  if (!fundingUtxo) {
20649
20909
  throw new Error(`UTXO at index ${i} is undefined`);
20650
20910
  }
20651
- const pubKeyHash = hash160((0, import_utils11.hexToBytes)(fundingUtxo.publicKey));
20911
+ const pubKeyHash = hash160((0, import_utils12.hexToBytes)(fundingUtxo.publicKey));
20652
20912
  const scriptToUse = new Uint8Array([0, 20, ...pubKeyHash]);
20653
- const providedScript = (0, import_utils11.hexToBytes)(fundingUtxo.script);
20654
- if ((0, import_utils11.bytesToHex)(scriptToUse) !== (0, import_utils11.bytesToHex)(providedScript)) {
20913
+ const providedScript = (0, import_utils12.hexToBytes)(fundingUtxo.script);
20914
+ if ((0, import_utils12.bytesToHex)(scriptToUse) !== (0, import_utils12.bytesToHex)(providedScript)) {
20655
20915
  throw new Error(
20656
20916
  `\u274C Derived script doesn't match provided script for UTXO ${i + 1}.`
20657
20917
  );
@@ -20716,7 +20976,7 @@ function constructFeeBumpTx(txHex, utxos, feeRate, previousFeeBumpTx) {
20716
20976
  }
20717
20977
  let psbtHex;
20718
20978
  try {
20719
- psbtHex = (0, import_utils11.bytesToHex)(builder.toPSBT());
20979
+ psbtHex = (0, import_utils12.bytesToHex)(builder.toPSBT());
20720
20980
  } catch (error) {
20721
20981
  throw new Error(`Failed to extract transaction: ${error}`);
20722
20982
  }
@@ -20894,12 +21154,12 @@ var NativeSparkFrost = class {
20894
21154
  init_buffer();
20895
21155
  var import_secp256k17 = require("@bitcoinerlab/secp256k1");
20896
21156
  var import_secp256k18 = require("@noble/curves/secp256k1");
20897
- var import_utils13 = require("@noble/curves/utils");
21157
+ var import_utils14 = require("@noble/curves/utils");
20898
21158
  var import_sha26 = require("@noble/hashes/sha2");
20899
21159
  var import_bip32 = require("@scure/bip32");
20900
21160
  var import_bip39 = require("@scure/bip39");
20901
21161
  var import_english = require("@scure/bip39/wordlists/english");
20902
- var import_utils14 = require("@scure/btc-signer/utils");
21162
+ var import_utils15 = require("@scure/btc-signer/utils");
20903
21163
  var ecies = __toESM(require("eciesjs"), 1);
20904
21164
 
20905
21165
  // src/constants.ts
@@ -20912,7 +21172,7 @@ var isWebExtension = (
20912
21172
  "chrome" in globalThis && globalThis.chrome.runtime?.id
20913
21173
  );
20914
21174
  var userAgent = "navigator" in globalThis ? globalThis.navigator.userAgent || "unknown-user-agent" : void 0;
20915
- var packageVersion = true ? "0.3.8" : "unknown";
21175
+ var packageVersion = true ? "0.4.0" : "unknown";
20916
21176
  var baseEnvStr = "unknown";
20917
21177
  if (isBun) {
20918
21178
  const bunVersion = "version" in globalThis.Bun ? globalThis.Bun.version : "unknown-version";
@@ -20991,6 +21251,63 @@ var DefaultSparkKeysGenerator = class {
20991
21251
  };
20992
21252
  }
20993
21253
  };
21254
+ var TaprootOutputKeysGenerator = class {
21255
+ constructor(useAddressIndex = false) {
21256
+ this.useAddressIndex = useAddressIndex;
21257
+ }
21258
+ async deriveKeysFromSeed(seed, accountNumber) {
21259
+ const hdkey = import_bip32.HDKey.fromMasterSeed(seed);
21260
+ if (!hdkey.privateKey || !hdkey.publicKey) {
21261
+ throw new ValidationError("Failed to derive keys from seed", {
21262
+ field: "hdkey",
21263
+ value: seed
21264
+ });
21265
+ }
21266
+ const derivationPath = this.useAddressIndex ? `m/86'/0'/0'/0/${accountNumber}` : `m/86'/0'/${accountNumber}'/0/0`;
21267
+ const taprootInternalKey = hdkey.derive(derivationPath);
21268
+ let tweakedPrivateKey = (0, import_utils15.taprootTweakPrivKey)(taprootInternalKey.privateKey);
21269
+ let tweakedPublicKey = import_secp256k18.secp256k1.getPublicKey(tweakedPrivateKey);
21270
+ if (tweakedPublicKey[0] === 3) {
21271
+ tweakedPrivateKey = (0, import_secp256k17.privateNegate)(tweakedPrivateKey);
21272
+ tweakedPublicKey = import_secp256k18.secp256k1.getPublicKey(tweakedPrivateKey);
21273
+ }
21274
+ const identityKey = {
21275
+ publicKey: tweakedPublicKey,
21276
+ privateKey: tweakedPrivateKey
21277
+ };
21278
+ const signingKey = hdkey.derive(`${derivationPath}/1'`);
21279
+ const depositKey = hdkey.derive(`${derivationPath}/2'`);
21280
+ const staticDepositKey = hdkey.derive(`${derivationPath}/3'`);
21281
+ if (!signingKey.privateKey || !signingKey.publicKey || !depositKey.privateKey || !depositKey.publicKey || !staticDepositKey.privateKey || !staticDepositKey.publicKey) {
21282
+ throw new ValidationError(
21283
+ "Failed to derive all required keys from seed",
21284
+ {
21285
+ field: "derivedKeys"
21286
+ }
21287
+ );
21288
+ }
21289
+ return {
21290
+ identityKey: {
21291
+ privateKey: identityKey.privateKey,
21292
+ publicKey: identityKey.publicKey
21293
+ },
21294
+ signingHDKey: {
21295
+ hdKey: signingKey,
21296
+ privateKey: signingKey.privateKey,
21297
+ publicKey: signingKey.publicKey
21298
+ },
21299
+ depositKey: {
21300
+ privateKey: depositKey.privateKey,
21301
+ publicKey: depositKey.publicKey
21302
+ },
21303
+ staticDepositHDKey: {
21304
+ hdKey: staticDepositKey,
21305
+ privateKey: staticDepositKey.privateKey,
21306
+ publicKey: staticDepositKey.publicKey
21307
+ }
21308
+ };
21309
+ }
21310
+ };
20994
21311
  var DefaultSparkSigner = class {
20995
21312
  constructor({
20996
21313
  sparkKeysGenerator
@@ -21026,7 +21343,7 @@ var DefaultSparkSigner = class {
21026
21343
  });
21027
21344
  }
21028
21345
  const receiverEciesPrivKey = ecies.PrivateKey.fromHex(
21029
- (0, import_utils13.bytesToHex)(this.identityKey.privateKey)
21346
+ (0, import_utils14.bytesToHex)(this.identityKey.privateKey)
21030
21347
  );
21031
21348
  const privateKey = ecies.decrypt(receiverEciesPrivKey.toHex(), ciphertext);
21032
21349
  return privateKey;
@@ -21160,7 +21477,7 @@ var DefaultSparkSigner = class {
21160
21477
  threshold,
21161
21478
  numShares
21162
21479
  }) {
21163
- const secretAsInt = (0, import_utils13.bytesToNumberBE)(secret);
21480
+ const secretAsInt = (0, import_utils14.bytesToNumberBE)(secret);
21164
21481
  return splitSecretWithProofs(secretAsInt, curveOrder, threshold, numShares);
21165
21482
  }
21166
21483
  async signFrost({
@@ -21196,7 +21513,7 @@ var DefaultSparkSigner = class {
21196
21513
  publicKey,
21197
21514
  verifyingKey
21198
21515
  };
21199
- const logMessage = (0, import_utils13.bytesToHex)(message);
21516
+ const logMessage = (0, import_utils14.bytesToHex)(message);
21200
21517
  const result = await SparkFrost.signFrost({
21201
21518
  message,
21202
21519
  keyPackage,
@@ -21238,7 +21555,7 @@ var DefaultSparkSigner = class {
21238
21555
  }
21239
21556
  async createSparkWalletFromSeed(seed, accountNumber) {
21240
21557
  if (typeof seed === "string") {
21241
- seed = (0, import_utils13.hexToBytes)(seed);
21558
+ seed = (0, import_utils14.hexToBytes)(seed);
21242
21559
  }
21243
21560
  const {
21244
21561
  identityKey,
@@ -21250,7 +21567,7 @@ var DefaultSparkSigner = class {
21250
21567
  this.depositKey = depositKey;
21251
21568
  this.signingKey = signingKey.hdKey;
21252
21569
  this.staticDepositKey = staticDepositKey.hdKey;
21253
- return (0, import_utils13.bytesToHex)(identityKey.publicKey);
21570
+ return (0, import_utils14.bytesToHex)(identityKey.publicKey);
21254
21571
  }
21255
21572
  async signMessageWithIdentityKey(message, compact) {
21256
21573
  if (!this.identityKey?.privateKey) {
@@ -21271,7 +21588,7 @@ var DefaultSparkSigner = class {
21271
21588
  });
21272
21589
  }
21273
21590
  const receiverEciesPrivKey = ecies.PrivateKey.fromHex(
21274
- (0, import_utils13.bytesToHex)(this.identityKey.privateKey)
21591
+ (0, import_utils14.bytesToHex)(this.identityKey.privateKey)
21275
21592
  );
21276
21593
  const privateKey = ecies.decrypt(receiverEciesPrivKey.toHex(), ciphertext);
21277
21594
  const publicKey = import_secp256k18.secp256k1.getPublicKey(privateKey);
@@ -21295,20 +21612,27 @@ var DefaultSparkSigner = class {
21295
21612
  }
21296
21613
  signTransactionIndex(tx, index, publicKey) {
21297
21614
  let privateKey;
21298
- if ((0, import_utils13.equalBytes)(publicKey, this.identityKey?.publicKey ?? new Uint8Array())) {
21615
+ if ((0, import_utils14.equalBytes)(publicKey, this.identityKey?.publicKey ?? new Uint8Array())) {
21299
21616
  privateKey = this.identityKey?.privateKey;
21300
- } else if ((0, import_utils13.equalBytes)(publicKey, this.depositKey?.publicKey ?? new Uint8Array())) {
21617
+ } else if ((0, import_utils14.equalBytes)(publicKey, this.depositKey?.publicKey ?? new Uint8Array())) {
21301
21618
  privateKey = this.depositKey?.privateKey;
21302
21619
  }
21303
21620
  if (!privateKey) {
21304
21621
  throw new ValidationError("Private key not found for public key", {
21305
21622
  field: "privateKey",
21306
- value: (0, import_utils13.bytesToHex)(publicKey)
21623
+ value: (0, import_utils14.bytesToHex)(publicKey)
21307
21624
  });
21308
21625
  }
21309
21626
  tx.signIdx(privateKey, index);
21310
21627
  }
21311
21628
  };
21629
+ var TaprootSparkSigner = class extends DefaultSparkSigner {
21630
+ constructor(useAddressIndex = false) {
21631
+ super({
21632
+ sparkKeysGenerator: new TaprootOutputKeysGenerator(useAddressIndex)
21633
+ });
21634
+ }
21635
+ };
21312
21636
 
21313
21637
  // src/signer/signer.react-native.ts
21314
21638
  var ReactNativeSparkSigner = class extends DefaultSparkSigner {
@@ -21372,6 +21696,70 @@ var ReactNativeSparkSigner = class extends DefaultSparkSigner {
21372
21696
  });
21373
21697
  }
21374
21698
  };
21699
+ var ReactNativeTaprootSparkSigner = class extends TaprootSparkSigner {
21700
+ constructor(useAddressIndex = false) {
21701
+ super(useAddressIndex);
21702
+ }
21703
+ async signFrost({
21704
+ message,
21705
+ keyDerivation,
21706
+ publicKey,
21707
+ verifyingKey,
21708
+ selfCommitment,
21709
+ statechainCommitments,
21710
+ adaptorPubKey
21711
+ }) {
21712
+ const signingPrivateKey = await this.getSigningPrivateKeyFromDerivation(keyDerivation);
21713
+ if (!signingPrivateKey) {
21714
+ throw new ValidationError("Private key not found for public key", {
21715
+ field: "privateKey"
21716
+ });
21717
+ }
21718
+ const commitment = selfCommitment.commitment;
21719
+ const nonce = this.commitmentToNonceMap.get(commitment);
21720
+ if (!nonce) {
21721
+ throw new ValidationError("Nonce not found for commitment", {
21722
+ field: "nonce"
21723
+ });
21724
+ }
21725
+ const keyPackage = {
21726
+ secretKey: signingPrivateKey,
21727
+ publicKey,
21728
+ verifyingKey
21729
+ };
21730
+ return NativeSparkFrost.signFrost({
21731
+ message,
21732
+ keyPackage,
21733
+ nonce,
21734
+ selfCommitment: commitment,
21735
+ statechainCommitments,
21736
+ adaptorPubKey
21737
+ });
21738
+ }
21739
+ async aggregateFrost({
21740
+ message,
21741
+ publicKey,
21742
+ verifyingKey,
21743
+ selfCommitment,
21744
+ statechainCommitments,
21745
+ adaptorPubKey,
21746
+ selfSignature,
21747
+ statechainSignatures,
21748
+ statechainPublicKeys
21749
+ }) {
21750
+ return NativeSparkFrost.aggregateFrost({
21751
+ message,
21752
+ statechainSignatures,
21753
+ statechainPublicKeys,
21754
+ verifyingKey,
21755
+ statechainCommitments,
21756
+ selfCommitment: selfCommitment.commitment,
21757
+ selfPublicKey: publicKey,
21758
+ selfSignature,
21759
+ adaptorPubKey
21760
+ });
21761
+ }
21762
+ };
21375
21763
 
21376
21764
  // src/spark-wallet/spark-wallet.react-native.ts
21377
21765
  init_buffer();
@@ -21513,7 +21901,16 @@ function headersToMetadata(headers) {
21513
21901
  const parts = line.split(": ");
21514
21902
  const header = parts.shift() ?? "";
21515
21903
  const value = parts.join(": ");
21516
- metadata.set(header, value);
21904
+ if (header.endsWith("-bin")) {
21905
+ try {
21906
+ metadata.set(header, import_js_base64.Base64.toUint8Array(value));
21907
+ } catch (e) {
21908
+ console.warn(`Failed to decode binary metadata ${header}:`, e);
21909
+ metadata.set(header, value);
21910
+ }
21911
+ } else {
21912
+ metadata.set(header, value);
21913
+ }
21517
21914
  });
21518
21915
  return metadata;
21519
21916
  }
@@ -21539,7 +21936,7 @@ function getStatusFromHttpCode(statusCode) {
21539
21936
  }
21540
21937
  }
21541
21938
  function getErrorDetailsFromHttpResponse(statusCode, responseText) {
21542
- return `Received HTTP ${statusCode} response: ` + (responseText.length > 1e3 ? responseText.slice(0, 1e3) + "... (truncated)" : responseText);
21939
+ return `Received HTTP ${statusCode} response: ` + (responseText?.length > 1e3 ? responseText?.slice(0, 1e3) + "... (truncated)" : responseText);
21543
21940
  }
21544
21941
 
21545
21942
  // src/spark-wallet/spark-wallet.ts
@@ -21549,7 +21946,7 @@ var import_secp256k114 = require("@noble/curves/secp256k1");
21549
21946
  var import_utils25 = require("@noble/curves/utils");
21550
21947
  var import_bip392 = require("@scure/bip39");
21551
21948
  var import_english2 = require("@scure/bip39/wordlists/english");
21552
- var import_btc_signer7 = require("@scure/btc-signer");
21949
+ var import_btc_signer5 = require("@scure/btc-signer");
21553
21950
  var import_async_mutex = require("async-mutex");
21554
21951
  var import_uuidv75 = require("uuidv7");
21555
21952
 
@@ -22798,28 +23195,22 @@ var WalletConfigService = class {
22798
23195
  getEvents() {
22799
23196
  return this.config.events;
22800
23197
  }
23198
+ getOptimizationOptions() {
23199
+ return this.config.optimizationOptions;
23200
+ }
22801
23201
  };
22802
23202
 
22803
23203
  // src/services/coop-exit.ts
22804
23204
  init_buffer();
22805
- var import_btc_signer3 = require("@scure/btc-signer");
22806
23205
  var import_uuidv73 = require("uuidv7");
22807
23206
 
22808
23207
  // src/services/transfer.ts
22809
23208
  init_buffer();
22810
23209
  var import_secp256k19 = require("@noble/curves/secp256k1");
22811
- var import_utils15 = require("@noble/curves/utils");
23210
+ var import_utils16 = require("@noble/curves/utils");
22812
23211
  var import_sha28 = require("@noble/hashes/sha2");
22813
- var import_btc_signer2 = require("@scure/btc-signer");
22814
23212
  var ecies2 = __toESM(require("eciesjs"), 1);
22815
23213
  var import_uuidv72 = require("uuidv7");
22816
- function getSigningJobProto(signingJob) {
22817
- return {
22818
- signingPublicKey: signingJob.signingPublicKey,
22819
- rawTx: signingJob.rawTx,
22820
- signingNonceCommitment: signingJob.signingNonceCommitment.commitment
22821
- };
22822
- }
22823
23214
  var BaseTransferService = class {
22824
23215
  constructor(config, connectionManager, signingService) {
22825
23216
  __publicField(this, "config");
@@ -23166,7 +23557,7 @@ var BaseTransferService = class {
23166
23557
  }
23167
23558
  async prepareSendTransferKeyTweaks(transferID, receiverIdentityPubkey, leaves, cpfpRefundSignatureMap, directRefundSignatureMap, directFromCpfpRefundSignatureMap) {
23168
23559
  const receiverEciesPubKey = ecies2.PublicKey.fromHex(
23169
- (0, import_utils15.bytesToHex)(receiverIdentityPubkey)
23560
+ (0, import_utils16.bytesToHex)(receiverIdentityPubkey)
23170
23561
  );
23171
23562
  const leavesTweaksMap = /* @__PURE__ */ new Map();
23172
23563
  for (const leaf of leaves) {
@@ -23207,7 +23598,7 @@ var BaseTransferService = class {
23207
23598
  throw new Error(`Share not found for operator ${operator.id}`);
23208
23599
  }
23209
23600
  const pubkeyTweak = import_secp256k19.secp256k1.getPublicKey(
23210
- (0, import_utils15.numberToBytesBE)(share.share, 32),
23601
+ (0, import_utils16.numberToBytesBE)(share.share, 32),
23211
23602
  true
23212
23603
  );
23213
23604
  pubkeySharesTweak.set(identifier, pubkeyTweak);
@@ -23232,7 +23623,7 @@ var BaseTransferService = class {
23232
23623
  leafTweaksMap.set(identifier, {
23233
23624
  leafId: leaf.leaf.id,
23234
23625
  secretShareTweak: {
23235
- secretShare: (0, import_utils15.numberToBytesBE)(share.share, 32),
23626
+ secretShare: (0, import_utils16.numberToBytesBE)(share.share, 32),
23236
23627
  proofs: share.proofs
23237
23628
  },
23238
23629
  pubkeySharesTweak: Object.fromEntries(pubkeySharesTweak),
@@ -23255,7 +23646,7 @@ var BaseTransferService = class {
23255
23646
  return void 0;
23256
23647
  }
23257
23648
  compareTransfers(transfer1, transfer2) {
23258
- return transfer1.id === transfer2.id && (0, import_utils15.equalBytes)(
23649
+ return transfer1.id === transfer2.id && (0, import_utils16.equalBytes)(
23259
23650
  transfer1.senderIdentityPublicKey,
23260
23651
  transfer2.senderIdentityPublicKey
23261
23652
  ) && transfer1.status === transfer2.status && transfer1.totalValue === transfer2.totalValue && transfer1.expiryTime?.getTime() === transfer2.expiryTime?.getTime() && transfer1.leaves.length === transfer2.leaves.length;
@@ -23501,42 +23892,27 @@ var TransferService = class extends BaseTransferService {
23501
23892
  throw new Error(`Leaf data not found for leaf ${leaf.leaf.id}`);
23502
23893
  }
23503
23894
  const nodeTx = getTxFromRawTxBytes(leaf.leaf.nodeTx);
23504
- const cpfpNodeOutPoint = {
23505
- txid: (0, import_utils15.hexToBytes)(getTxId(nodeTx)),
23506
- index: 0
23507
- };
23508
23895
  let directNodeTx;
23509
- let directNodeOutPoint;
23510
23896
  if (leaf.leaf.directTx.length > 0) {
23511
23897
  directNodeTx = getTxFromRawTxBytes(leaf.leaf.directTx);
23512
- directNodeOutPoint = {
23513
- txid: (0, import_utils15.hexToBytes)(getTxId(directNodeTx)),
23514
- index: 0
23515
- };
23516
23898
  }
23517
23899
  const currRefundTx = getTxFromRawTxBytes(leaf.leaf.refundTx);
23518
- const sequence = currRefundTx.getInput(0).sequence;
23519
- if (!sequence) {
23900
+ const currentSequence = currRefundTx.getInput(0).sequence;
23901
+ if (!currentSequence) {
23520
23902
  throw new ValidationError("Invalid refund transaction", {
23521
23903
  field: "sequence",
23522
23904
  value: currRefundTx.getInput(0),
23523
23905
  expected: "Non-null sequence"
23524
23906
  });
23525
23907
  }
23526
- const { nextSequence, nextDirectSequence } = isForClaim ? getTransactionSequence(sequence) : getNextTransactionSequence(sequence);
23527
- const amountSats = currRefundTx.getOutput(0).amount;
23528
- if (amountSats === void 0) {
23529
- throw new Error("Amount not found in signRefunds");
23530
- }
23531
- const { cpfpRefundTx, directRefundTx, directFromCpfpRefundTx } = createRefundTxs({
23532
- sequence: nextSequence,
23533
- directSequence: nextDirectSequence,
23534
- input: cpfpNodeOutPoint,
23535
- directInput: directNodeOutPoint,
23536
- amountSats,
23908
+ const refundTxsParams = {
23909
+ nodeTx,
23910
+ directNodeTx,
23911
+ sequence: currentSequence,
23537
23912
  receivingPubkey: refundSigningData.receivingPubkey,
23538
23913
  network: this.config.getNetwork()
23539
- });
23914
+ };
23915
+ const { cpfpRefundTx, directRefundTx, directFromCpfpRefundTx } = isForClaim ? createCurrentTimelockRefundTxs(refundTxsParams) : createDecrementedTimelockRefundTxs(refundTxsParams);
23540
23916
  refundSigningData.refundTx = cpfpRefundTx;
23541
23917
  refundSigningData.directRefundTx = directRefundTx;
23542
23918
  refundSigningData.directFromCpfpRefundTx = directFromCpfpRefundTx;
@@ -23644,7 +24020,7 @@ var TransferService = class extends BaseTransferService {
23644
24020
  throw new Error(`Share not found for operator ${operator.id}`);
23645
24021
  }
23646
24022
  const pubkeyTweak = import_secp256k19.secp256k1.getPublicKey(
23647
- (0, import_utils15.numberToBytesBE)(share.share, 32)
24023
+ (0, import_utils16.numberToBytesBE)(share.share, 32)
23648
24024
  );
23649
24025
  pubkeySharesTweak.set(identifier, pubkeyTweak);
23650
24026
  }
@@ -23657,7 +24033,7 @@ var TransferService = class extends BaseTransferService {
23657
24033
  leafTweaksMap.set(identifier, {
23658
24034
  leafId: leaf.leaf.id,
23659
24035
  secretShareTweak: {
23660
- secretShare: (0, import_utils15.numberToBytesBE)(share.share, 32),
24036
+ secretShare: (0, import_utils16.numberToBytesBE)(share.share, 32),
23661
24037
  proofs: share.proofs
23662
24038
  },
23663
24039
  pubkeySharesTweak: Object.fromEntries(pubkeySharesTweak)
@@ -23749,71 +24125,127 @@ var TransferService = class extends BaseTransferService {
23749
24125
  throw new Error(`Error querying pending transfers by sender: ${error}`);
23750
24126
  }
23751
24127
  }
23752
- async refreshTimelockNodesInternal(node, parentNode, useTestUnilateralSequence) {
23753
- const signingJobs = [];
23754
- const parentNodeTx = getTxFromRawTxBytes(parentNode.nodeTx);
23755
- const parentNodeOutput = parentNodeTx.getOutput(0);
23756
- if (!parentNodeOutput) {
23757
- throw Error("Could not get parent node output");
24128
+ async renewRefundTxn(node, parentNode) {
24129
+ const sparkClient = await this.connectionManager.createSparkClient(
24130
+ this.config.getCoordinatorAddress()
24131
+ );
24132
+ const signingJobs = await this.createRenewRefundSigningJobs(
24133
+ node,
24134
+ parentNode
24135
+ );
24136
+ const statechainCommitments = await sparkClient.get_signing_commitments({
24137
+ nodeIds: [node.id],
24138
+ count: signingJobs.length
24139
+ });
24140
+ const mappedSigningJobs = signingJobs.map((signingJob, index) => {
24141
+ const signingNonceCommitments = statechainCommitments.signingCommitments[index]?.signingNonceCommitments;
24142
+ if (!signingNonceCommitments) {
24143
+ throw new Error("Signing nonce commitments not found");
24144
+ }
24145
+ return {
24146
+ ...signingJob,
24147
+ signingNonceCommitments
24148
+ };
24149
+ });
24150
+ const userSignedTxSigningJobs = await this.signingService.signSigningJobs(mappedSigningJobs);
24151
+ const renewRefundTimelockSigningJob = {
24152
+ nodeTxSigningJob: userSignedTxSigningJobs.get("node"),
24153
+ refundTxSigningJob: userSignedTxSigningJobs.get("cpfp"),
24154
+ directNodeTxSigningJob: userSignedTxSigningJobs.get("directNode"),
24155
+ directRefundTxSigningJob: userSignedTxSigningJobs.get("direct"),
24156
+ directFromCpfpRefundTxSigningJob: userSignedTxSigningJobs.get("directFromCpfp")
24157
+ };
24158
+ const response = await sparkClient.renew_leaf({
24159
+ leafId: node.id,
24160
+ signingJobs: {
24161
+ $case: "renewRefundTimelockSigningJob",
24162
+ renewRefundTimelockSigningJob
24163
+ }
24164
+ });
24165
+ if (response.renewResult?.$case !== "renewRefundTimelockResult" || !response.renewResult?.renewRefundTimelockResult.node) {
24166
+ throw new ValidationError("Unexpected renew result", {
24167
+ field: "renewResult",
24168
+ value: response.renewResult
24169
+ });
23758
24170
  }
23759
- const nodeTx = getTxFromRawTxBytes(node.nodeTx);
23760
- const nodeInput = nodeTx.getInput(0);
23761
- const nodeOutput = nodeTx.getOutput(0);
23762
- if (!nodeOutput) {
23763
- throw Error("Could not get node output");
23764
- }
23765
- let directNodeTx;
23766
- let directNodeInput;
23767
- if (node.directTx.length > 0) {
23768
- directNodeTx = getTxFromRawTxBytes(node.directTx);
23769
- directNodeInput = directNodeTx.getInput(0);
23770
- }
23771
- const currSequence = nodeInput.sequence;
23772
- if (!currSequence) {
23773
- throw new ValidationError("Invalid node transaction", {
23774
- field: "sequence",
23775
- value: nodeInput,
23776
- expected: "Non-null sequence"
24171
+ return response.renewResult?.renewRefundTimelockResult.node;
24172
+ }
24173
+ async renewNodeTxn(node, parentNode) {
24174
+ const sparkClient = await this.connectionManager.createSparkClient(
24175
+ this.config.getCoordinatorAddress()
24176
+ );
24177
+ const signingJobs = await this.createRenewNodeSigningJobs(node, parentNode);
24178
+ const statechainCommitments = await sparkClient.get_signing_commitments({
24179
+ nodeIds: [node.id],
24180
+ count: signingJobs.length
24181
+ });
24182
+ const mappedSigningJobs = signingJobs.map((signingJob, index) => {
24183
+ const signingNonceCommitments = statechainCommitments.signingCommitments[index]?.signingNonceCommitments;
24184
+ if (!signingNonceCommitments) {
24185
+ throw new Error("Signing nonce commitments not found");
24186
+ }
24187
+ return {
24188
+ ...signingJob,
24189
+ signingNonceCommitments
24190
+ };
24191
+ });
24192
+ const userSignedTxSigningJobs = await this.signingService.signSigningJobs(mappedSigningJobs);
24193
+ const response = await sparkClient.renew_leaf({
24194
+ leafId: node.id,
24195
+ signingJobs: {
24196
+ $case: "renewNodeTimelockSigningJob",
24197
+ renewNodeTimelockSigningJob: {
24198
+ splitNodeTxSigningJob: userSignedTxSigningJobs.get("split"),
24199
+ splitNodeDirectTxSigningJob: userSignedTxSigningJobs.get("directSplit"),
24200
+ nodeTxSigningJob: userSignedTxSigningJobs.get("node"),
24201
+ directNodeTxSigningJob: userSignedTxSigningJobs.get("directNode"),
24202
+ refundTxSigningJob: userSignedTxSigningJobs.get("cpfp"),
24203
+ directRefundTxSigningJob: userSignedTxSigningJobs.get("direct"),
24204
+ directFromCpfpRefundTxSigningJob: userSignedTxSigningJobs.get("directFromCpfp")
24205
+ }
24206
+ }
24207
+ });
24208
+ if (response.renewResult?.$case !== "renewNodeTimelockResult" || !response.renewResult?.renewNodeTimelockResult.node) {
24209
+ throw new ValidationError("Unexpected renew result", {
24210
+ field: "renewResult",
24211
+ value: response.renewResult
23777
24212
  });
23778
24213
  }
23779
- let { nextSequence, nextDirectSequence } = getNextTransactionSequence(
23780
- currSequence,
23781
- true
24214
+ return response.renewResult.renewNodeTimelockResult.node;
24215
+ }
24216
+ async createRenewRefundSigningJobs(node, parentNode) {
24217
+ const signingJobs = [];
24218
+ const parentTx = getTxFromRawTxBytes(parentNode.nodeTx);
24219
+ const parentNodeOutput = getTxFromRawTxBytes(parentNode.nodeTx).getOutput(
24220
+ 0
23782
24221
  );
23783
- const output = {
24222
+ if (!parentNodeOutput) {
24223
+ throw new Error("Parent node output not found");
24224
+ }
24225
+ const unsignedParentNodeOutput = {
23784
24226
  script: parentNodeOutput.script,
23785
24227
  amount: parentNodeOutput.amount
23786
24228
  };
23787
- const newNodeInput = {
23788
- txid: nodeInput.txid,
23789
- index: nodeInput.index,
23790
- sequence: useTestUnilateralSequence ? TEST_UNILATERAL_SEQUENCE : nextSequence
23791
- };
23792
- const newDirectInput = directNodeTx && directNodeInput ? {
23793
- txid: directNodeInput.txid,
23794
- index: directNodeInput.index,
23795
- sequence: useTestUnilateralSequence ? TEST_UNILATERAL_DIRECT_SEQUENCE : nextDirectSequence
23796
- } : void 0;
23797
- const { cpfpNodeTx, directNodeTx: newDirectNodeTx } = createNodeTxs(
23798
- output,
23799
- newNodeInput,
23800
- newDirectInput
23801
- );
23802
- const newCpfpNodeOutput = cpfpNodeTx.getOutput(0);
23803
- if (!newCpfpNodeOutput) {
23804
- throw Error("Could not get new cpfp node output");
23805
- }
23806
- const newDirectNodeOutput = newDirectNodeTx?.getOutput(0);
23807
- const signingPublicKey = await this.config.signer.getPublicKeyFromDerivation({
24229
+ const keyDerivation = {
23808
24230
  type: "leaf" /* LEAF */,
23809
24231
  path: node.id
23810
- });
24232
+ };
24233
+ const signingPublicKey = await this.config.signer.getPublicKeyFromDerivation(keyDerivation);
24234
+ const nodeTx = getTxFromRawTxBytes(node.nodeTx);
24235
+ const refundTx = getTxFromRawTxBytes(node.refundTx);
24236
+ const { nodeTx: newNodeTx, directNodeTx: newDirectNodeTx } = createDecrementedTimelockNodeTx(parentTx, nodeTx);
23811
24237
  signingJobs.push({
23812
24238
  signingPublicKey,
23813
- rawTx: cpfpNodeTx.toBytes(),
24239
+ rawTx: newNodeTx.toBytes(),
23814
24240
  signingNonceCommitment: await this.config.signer.getRandomSigningCommitment(),
23815
24241
  type: "node",
23816
- parentTxOut: parentNodeOutput
24242
+ parentTxOut: unsignedParentNodeOutput,
24243
+ leafId: node.id,
24244
+ keyDerivation: {
24245
+ type: "leaf" /* LEAF */,
24246
+ path: node.id
24247
+ },
24248
+ verifyingKey: node.verifyingPublicKey
23817
24249
  });
23818
24250
  if (newDirectNodeTx) {
23819
24251
  signingJobs.push({
@@ -23821,537 +24253,299 @@ var TransferService = class extends BaseTransferService {
23821
24253
  rawTx: newDirectNodeTx.toBytes(),
23822
24254
  signingNonceCommitment: await this.config.signer.getRandomSigningCommitment(),
23823
24255
  type: "directNode",
23824
- parentTxOut: parentNodeOutput
24256
+ parentTxOut: unsignedParentNodeOutput,
24257
+ leafId: node.id,
24258
+ keyDerivation: {
24259
+ type: "leaf" /* LEAF */,
24260
+ path: node.id
24261
+ },
24262
+ verifyingKey: node.verifyingPublicKey
23825
24263
  });
23826
24264
  }
23827
- const newCpfpRefundOutPoint = {
23828
- txid: (0, import_utils15.hexToBytes)(getTxId(cpfpNodeTx)),
23829
- index: 0
23830
- };
23831
- let newDirectRefundOutPoint;
23832
- if (newDirectNodeTx) {
23833
- newDirectRefundOutPoint = {
23834
- txid: (0, import_utils15.hexToBytes)(getTxId(newDirectNodeTx)),
23835
- index: 0
23836
- };
24265
+ const newCpfpNodeOutput = newNodeTx.getOutput(0);
24266
+ if (!newCpfpNodeOutput) {
24267
+ throw Error("Could not get new cpfp node output");
23837
24268
  }
23838
- const { cpfpRefundTx, directRefundTx, directFromCpfpRefundTx } = createRefundTxs({
23839
- sequence: INITIAL_SEQUENCE,
23840
- directSequence: INITIAL_DIRECT_SEQUENCE,
23841
- input: newCpfpRefundOutPoint,
23842
- directInput: newDirectRefundOutPoint,
23843
- amountSats: nodeOutput.amount,
23844
- receivingPubkey: await this.config.signer.getPublicKeyFromDerivation({
23845
- type: "leaf" /* LEAF */,
23846
- path: node.id
23847
- }),
24269
+ const newDirectNodeOutput = newDirectNodeTx?.getOutput(0);
24270
+ const amountSats = refundTx.getOutput(0).amount;
24271
+ if (amountSats === void 0) {
24272
+ throw new Error("Amount not found in extendTimelock");
24273
+ }
24274
+ const directAmountSats = newDirectNodeOutput?.amount;
24275
+ if (directAmountSats === void 0) {
24276
+ throw new Error("Amount not found in extendTimelock");
24277
+ }
24278
+ const {
24279
+ cpfpRefundTx: newRefundTx,
24280
+ directRefundTx: newDirectRefundTx,
24281
+ directFromCpfpRefundTx: newDirectFromCpfpRefundTx
24282
+ } = createInitialTimelockRefundTxs({
24283
+ nodeTx: newNodeTx,
24284
+ directNodeTx: newDirectNodeTx,
24285
+ receivingPubkey: signingPublicKey,
23848
24286
  network: this.config.getNetwork()
23849
24287
  });
23850
24288
  signingJobs.push({
23851
24289
  signingPublicKey,
23852
- rawTx: cpfpRefundTx.toBytes(),
24290
+ rawTx: newRefundTx.toBytes(),
23853
24291
  signingNonceCommitment: await this.config.signer.getRandomSigningCommitment(),
23854
24292
  type: "cpfp",
23855
- parentTxOut: newCpfpNodeOutput
24293
+ parentTxOut: newCpfpNodeOutput,
24294
+ leafId: node.id,
24295
+ keyDerivation,
24296
+ verifyingKey: node.verifyingPublicKey
23856
24297
  });
23857
- if (directRefundTx && newDirectNodeOutput) {
24298
+ if (newDirectRefundTx && newDirectNodeOutput) {
23858
24299
  signingJobs.push({
23859
24300
  signingPublicKey,
23860
- rawTx: directRefundTx.toBytes(),
24301
+ rawTx: newDirectRefundTx.toBytes(),
23861
24302
  signingNonceCommitment: await this.config.signer.getRandomSigningCommitment(),
23862
24303
  type: "direct",
23863
- parentTxOut: newDirectNodeOutput
24304
+ parentTxOut: newDirectNodeOutput,
24305
+ leafId: node.id,
24306
+ keyDerivation,
24307
+ verifyingKey: node.verifyingPublicKey
23864
24308
  });
23865
24309
  }
23866
- if (directFromCpfpRefundTx && newCpfpNodeOutput) {
24310
+ if (newDirectFromCpfpRefundTx && newDirectNodeOutput) {
23867
24311
  signingJobs.push({
23868
24312
  signingPublicKey,
23869
- rawTx: directFromCpfpRefundTx.toBytes(),
24313
+ rawTx: newDirectFromCpfpRefundTx.toBytes(),
23870
24314
  signingNonceCommitment: await this.config.signer.getRandomSigningCommitment(),
23871
24315
  type: "directFromCpfp",
23872
- parentTxOut: newCpfpNodeOutput
24316
+ parentTxOut: newCpfpNodeOutput,
24317
+ leafId: node.id,
24318
+ keyDerivation,
24319
+ verifyingKey: node.verifyingPublicKey
23873
24320
  });
23874
24321
  }
23875
- const sparkClient = await this.connectionManager.createSparkClient(
23876
- this.config.getCoordinatorAddress()
23877
- );
23878
- const response = await sparkClient.refresh_timelock_v2({
23879
- leafId: node.id,
23880
- ownerIdentityPublicKey: await this.config.signer.getIdentityPublicKey(),
23881
- signingJobs: signingJobs.map(getSigningJobProto)
23882
- });
23883
- if (signingJobs.length !== response.signingResults.length) {
23884
- throw Error(
23885
- `number of signing jobs and signing results do not match: ${signingJobs.length} !== ${response.signingResults.length}`
23886
- );
23887
- }
23888
- let nodeSignatures = [];
23889
- let leafCpfpSignature;
23890
- let leafDirectSignature;
23891
- let cpfpRefundSignature;
23892
- let directRefundSignature;
23893
- let directFromCpfpRefundSignature;
23894
- for (const [i, signingResult] of response.signingResults.entries()) {
23895
- const signingJob = signingJobs[i];
23896
- if (!signingJob || !signingResult) {
23897
- throw Error("Signing job does not exist");
23898
- }
23899
- const rawTx = getTxFromRawTxBytes(signingJob.rawTx);
23900
- const txOut = signingJob.parentTxOut;
23901
- if (!txOut) {
23902
- throw Error("Could not get tx out");
23903
- }
23904
- const rawTxSighash = getSigHashFromTx(rawTx, 0, txOut);
23905
- const userSignature = await this.config.signer.signFrost({
23906
- message: rawTxSighash,
23907
- keyDerivation: {
23908
- type: "leaf" /* LEAF */,
23909
- path: node.id
23910
- },
23911
- publicKey: signingJob.signingPublicKey,
23912
- verifyingKey: signingResult.verifyingKey,
23913
- selfCommitment: signingJob.signingNonceCommitment,
23914
- statechainCommitments: signingResult.signingResult?.signingNonceCommitments,
23915
- adaptorPubKey: new Uint8Array()
23916
- });
23917
- const signature = await this.config.signer.aggregateFrost({
23918
- message: rawTxSighash,
23919
- statechainSignatures: signingResult.signingResult?.signatureShares,
23920
- statechainPublicKeys: signingResult.signingResult?.publicKeys,
23921
- verifyingKey: signingResult.verifyingKey,
23922
- statechainCommitments: signingResult.signingResult?.signingNonceCommitments,
23923
- selfCommitment: signingJob.signingNonceCommitment,
23924
- publicKey: signingJob.signingPublicKey,
23925
- selfSignature: userSignature,
23926
- adaptorPubKey: new Uint8Array()
23927
- });
23928
- if (signingJob.type === "node") {
23929
- leafCpfpSignature = signature;
23930
- } else if (signingJob.type === "directNode") {
23931
- leafDirectSignature = signature;
23932
- } else if (signingJob.type === "cpfp") {
23933
- cpfpRefundSignature = signature;
23934
- } else if (signingJob.type === "direct") {
23935
- directRefundSignature = signature;
23936
- } else if (signingJob.type === "directFromCpfp") {
23937
- directFromCpfpRefundSignature = signature;
23938
- }
23939
- }
23940
- nodeSignatures.push({
23941
- nodeId: node.id,
23942
- nodeTxSignature: leafCpfpSignature || new Uint8Array(),
23943
- directNodeTxSignature: leafDirectSignature || new Uint8Array(),
23944
- refundTxSignature: cpfpRefundSignature || new Uint8Array(),
23945
- directRefundTxSignature: directRefundSignature || new Uint8Array(),
23946
- directFromCpfpRefundTxSignature: directFromCpfpRefundSignature || new Uint8Array()
23947
- });
23948
- const result = await sparkClient.finalize_node_signatures_v2({
23949
- intent: 3 /* REFRESH */,
23950
- nodeSignatures
23951
- });
23952
- return result;
23953
- }
23954
- async refreshTimelockNodes(node, parentNode) {
23955
- return await this.refreshTimelockNodesInternal(node, parentNode);
24322
+ return signingJobs;
23956
24323
  }
23957
- async extendTimelock(node) {
23958
- const nodeTx = getTxFromRawTxBytes(node.nodeTx);
23959
- const refundTx = getTxFromRawTxBytes(node.refundTx);
23960
- const refundSequence = refundTx.getInput(0).sequence || 0;
23961
- const newNodeOutPoint = {
23962
- txid: (0, import_utils15.hexToBytes)(getTxId(nodeTx)),
23963
- index: 0
23964
- };
23965
- const {
23966
- nextSequence: newNodeSequence,
23967
- nextDirectSequence: newDirectNodeSequence
23968
- } = getNextTransactionSequence(refundSequence);
23969
- const newNodeTx = new import_btc_signer2.Transaction({
23970
- version: 3,
23971
- allowUnknownOutputs: true
23972
- });
23973
- newNodeTx.addInput({ ...newNodeOutPoint, sequence: newNodeSequence });
23974
- const originalOutput = nodeTx.getOutput(0);
23975
- if (!originalOutput) {
23976
- throw Error("Could not get original node output");
23977
- }
23978
- newNodeTx.addOutput({
23979
- script: originalOutput.script,
23980
- amount: originalOutput.amount
23981
- });
23982
- newNodeTx.addOutput(getEphemeralAnchorOutput());
23983
- let newDirectNodeTx;
23984
- if (node.directTx.length > 0) {
23985
- newDirectNodeTx = new import_btc_signer2.Transaction({
23986
- version: 3,
23987
- allowUnknownOutputs: true
23988
- });
23989
- newDirectNodeTx.addInput({
23990
- ...newNodeOutPoint,
23991
- sequence: newDirectNodeSequence
23992
- });
23993
- newDirectNodeTx.addOutput({
23994
- script: originalOutput.script,
23995
- amount: maybeApplyFee(originalOutput.amount)
23996
- });
23997
- }
23998
- const newCpfpRefundOutPoint = {
23999
- txid: (0, import_utils15.hexToBytes)(getTxId(newNodeTx)),
24000
- index: 0
24001
- };
24002
- let newDirectRefundOutPoint;
24003
- if (newDirectNodeTx) {
24004
- newDirectRefundOutPoint = {
24005
- txid: (0, import_utils15.hexToBytes)(getTxId(newDirectNodeTx)),
24006
- index: 0
24007
- };
24008
- }
24009
- const amountSats = refundTx.getOutput(0).amount;
24010
- if (amountSats === void 0) {
24011
- throw new Error("Amount not found in extendTimelock");
24012
- }
24013
- const signingPublicKey = await this.config.signer.getPublicKeyFromDerivation({
24014
- type: "leaf" /* LEAF */,
24015
- path: node.id
24016
- });
24017
- const {
24018
- cpfpRefundTx: newCpfpRefundTx,
24019
- directRefundTx: newDirectRefundTx,
24020
- directFromCpfpRefundTx: newDirectFromCpfpRefundTx
24021
- } = createRefundTxs({
24022
- sequence: INITIAL_SEQUENCE,
24023
- directSequence: INITIAL_DIRECT_SEQUENCE,
24024
- input: newCpfpRefundOutPoint,
24025
- directInput: newDirectRefundOutPoint,
24026
- amountSats,
24027
- receivingPubkey: signingPublicKey,
24028
- network: this.config.getNetwork()
24029
- });
24030
- if (!newCpfpRefundTx) {
24031
- throw new ValidationError(
24032
- "Failed to create refund transactions in extendTimelock"
24033
- );
24034
- }
24035
- const nodeSighash = getSigHashFromTx(newNodeTx, 0, nodeTx.getOutput(0));
24036
- const directNodeSighash = newDirectNodeTx ? getSigHashFromTx(newDirectNodeTx, 0, nodeTx.getOutput(0)) : void 0;
24037
- const cpfpRefundSighash = getSigHashFromTx(
24038
- newCpfpRefundTx,
24039
- 0,
24040
- newNodeTx.getOutput(0)
24324
+ async createRenewNodeSigningJobs(node, parentNode) {
24325
+ const signingJobs = [];
24326
+ const parentTx = getTxFromRawTxBytes(parentNode.nodeTx);
24327
+ const parentNodeOutput = getTxFromRawTxBytes(parentNode.nodeTx).getOutput(
24328
+ 0
24041
24329
  );
24042
- const directRefundSighash = newDirectNodeTx && newDirectRefundTx ? getSigHashFromTx(newDirectRefundTx, 0, newDirectNodeTx.getOutput(0)) : void 0;
24043
- const directFromCpfpRefundSighash = newDirectFromCpfpRefundTx ? getSigHashFromTx(newDirectFromCpfpRefundTx, 0, newNodeTx.getOutput(0)) : void 0;
24044
- const newNodeSigningJob = {
24045
- signingPublicKey,
24046
- rawTx: newNodeTx.toBytes(),
24047
- signingNonceCommitment: await this.config.signer.getRandomSigningCommitment()
24048
- };
24049
- const newDirectNodeSigningJob = newDirectNodeTx ? {
24050
- signingPublicKey,
24051
- rawTx: newDirectNodeTx.toBytes(),
24052
- signingNonceCommitment: await this.config.signer.getRandomSigningCommitment()
24053
- } : void 0;
24054
- const newCpfpRefundSigningJob = {
24055
- signingPublicKey,
24056
- rawTx: newCpfpRefundTx.toBytes(),
24057
- signingNonceCommitment: await this.config.signer.getRandomSigningCommitment()
24330
+ const unsignedParentNodeOutput = {
24331
+ script: parentNodeOutput.script,
24332
+ amount: parentNodeOutput.amount
24058
24333
  };
24059
- const newDirectRefundSigningJob = newDirectRefundTx ? {
24060
- signingPublicKey,
24061
- rawTx: newDirectRefundTx.toBytes(),
24062
- signingNonceCommitment: await this.config.signer.getRandomSigningCommitment()
24063
- } : void 0;
24064
- const newDirectFromCpfpRefundSigningJob = newDirectFromCpfpRefundTx ? {
24065
- signingPublicKey,
24066
- rawTx: newDirectFromCpfpRefundTx.toBytes(),
24067
- signingNonceCommitment: await this.config.signer.getRandomSigningCommitment()
24068
- } : void 0;
24069
- const sparkClient = await this.connectionManager.createSparkClient(
24070
- this.config.getCoordinatorAddress()
24071
- );
24072
- const response = await sparkClient.extend_leaf_v2({
24073
- leafId: node.id,
24074
- ownerIdentityPublicKey: await this.config.signer.getIdentityPublicKey(),
24075
- nodeTxSigningJob: getSigningJobProto(newNodeSigningJob),
24076
- directNodeTxSigningJob: newDirectNodeSigningJob ? getSigningJobProto(newDirectNodeSigningJob) : void 0,
24077
- refundTxSigningJob: getSigningJobProto(newCpfpRefundSigningJob),
24078
- directRefundTxSigningJob: newDirectRefundSigningJob ? getSigningJobProto(newDirectRefundSigningJob) : void 0,
24079
- directFromCpfpRefundTxSigningJob: newDirectFromCpfpRefundSigningJob ? getSigningJobProto(newDirectFromCpfpRefundSigningJob) : void 0
24080
- });
24081
- if (!response.nodeTxSigningResult || !response.refundTxSigningResult) {
24082
- throw new Error("Signing result does not exist");
24083
- }
24084
24334
  const keyDerivation = {
24085
24335
  type: "leaf" /* LEAF */,
24086
24336
  path: node.id
24087
24337
  };
24088
- const nodeUserSig = await this.config.signer.signFrost({
24089
- message: nodeSighash,
24338
+ const signingPublicKey = await this.config.signer.getPublicKeyFromDerivation(keyDerivation);
24339
+ const { nodeTx: splitNodeTx, directNodeTx: splitNodeDirectTx } = createZeroTimelockNodeTx(parentTx);
24340
+ signingJobs.push({
24341
+ signingPublicKey,
24342
+ rawTx: splitNodeTx.toBytes(),
24343
+ signingNonceCommitment: await this.config.signer.getRandomSigningCommitment(),
24344
+ type: "split",
24345
+ parentTxOut: unsignedParentNodeOutput,
24346
+ leafId: node.id,
24090
24347
  keyDerivation,
24091
- publicKey: signingPublicKey,
24092
- verifyingKey: response.nodeTxSigningResult.verifyingKey,
24093
- selfCommitment: newNodeSigningJob.signingNonceCommitment,
24094
- statechainCommitments: response.nodeTxSigningResult.signingResult?.signingNonceCommitments,
24095
- adaptorPubKey: new Uint8Array()
24348
+ verifyingKey: node.verifyingPublicKey
24096
24349
  });
24097
- const nodeSig = await this.config.signer.aggregateFrost({
24098
- message: nodeSighash,
24099
- statechainSignatures: response.nodeTxSigningResult.signingResult?.signatureShares,
24100
- statechainPublicKeys: response.nodeTxSigningResult.signingResult?.publicKeys,
24101
- verifyingKey: response.nodeTxSigningResult.verifyingKey,
24102
- statechainCommitments: response.nodeTxSigningResult.signingResult?.signingNonceCommitments,
24103
- selfCommitment: newNodeSigningJob.signingNonceCommitment,
24104
- publicKey: signingPublicKey,
24105
- selfSignature: nodeUserSig,
24106
- adaptorPubKey: new Uint8Array()
24107
- });
24108
- let directNodeSig;
24109
- if (directNodeSighash && newDirectNodeSigningJob && response.directNodeTxSigningResult) {
24110
- const directNodeUserSig = await this.config.signer.signFrost({
24111
- message: directNodeSighash,
24350
+ if (splitNodeDirectTx) {
24351
+ signingJobs.push({
24352
+ signingPublicKey,
24353
+ rawTx: splitNodeDirectTx.toBytes(),
24354
+ signingNonceCommitment: await this.config.signer.getRandomSigningCommitment(),
24355
+ type: "directSplit",
24356
+ parentTxOut: unsignedParentNodeOutput,
24357
+ leafId: node.id,
24112
24358
  keyDerivation,
24113
- publicKey: signingPublicKey,
24114
- verifyingKey: response.directNodeTxSigningResult.verifyingKey,
24115
- selfCommitment: newDirectNodeSigningJob.signingNonceCommitment,
24116
- statechainCommitments: response.directNodeTxSigningResult.signingResult?.signingNonceCommitments,
24117
- adaptorPubKey: new Uint8Array()
24118
- });
24119
- directNodeSig = await this.config.signer.aggregateFrost({
24120
- message: directNodeSighash,
24121
- statechainSignatures: response.directNodeTxSigningResult.signingResult?.signatureShares,
24122
- statechainPublicKeys: response.directNodeTxSigningResult.signingResult?.publicKeys,
24123
- verifyingKey: response.directNodeTxSigningResult.verifyingKey,
24124
- statechainCommitments: response.directNodeTxSigningResult.signingResult?.signingNonceCommitments,
24125
- selfCommitment: newDirectNodeSigningJob.signingNonceCommitment,
24126
- publicKey: signingPublicKey,
24127
- selfSignature: directNodeUserSig,
24128
- adaptorPubKey: new Uint8Array()
24359
+ verifyingKey: node.verifyingPublicKey
24129
24360
  });
24130
24361
  }
24131
- const cpfpRefundUserSig = await this.config.signer.signFrost({
24132
- message: cpfpRefundSighash,
24362
+ const splitNodeOutput = splitNodeTx.getOutput(0);
24363
+ const splitNodeDirectOutput = splitNodeDirectTx.getOutput(0);
24364
+ if (!splitNodeDirectOutput.amount || !splitNodeDirectOutput.script) {
24365
+ throw new Error("Could not get split node output");
24366
+ }
24367
+ const unsignedSplitNodeOutput = {
24368
+ script: splitNodeDirectOutput.script,
24369
+ amount: splitNodeDirectOutput.amount
24370
+ };
24371
+ const { nodeTx: newNodeTx, directNodeTx: newDirectNodeTx } = createInitialTimelockNodeTx(splitNodeTx);
24372
+ signingJobs.push({
24373
+ signingPublicKey,
24374
+ rawTx: newNodeTx.toBytes(),
24375
+ signingNonceCommitment: await this.config.signer.getRandomSigningCommitment(),
24376
+ type: "node",
24377
+ parentTxOut: splitNodeOutput,
24378
+ leafId: node.id,
24133
24379
  keyDerivation,
24134
- publicKey: signingPublicKey,
24135
- verifyingKey: response.refundTxSigningResult.verifyingKey,
24136
- selfCommitment: newCpfpRefundSigningJob.signingNonceCommitment,
24137
- statechainCommitments: response.refundTxSigningResult.signingResult?.signingNonceCommitments,
24138
- adaptorPubKey: new Uint8Array()
24380
+ verifyingKey: node.verifyingPublicKey
24139
24381
  });
24140
- const cpfpRefundSig = await this.config.signer.aggregateFrost({
24141
- message: cpfpRefundSighash,
24142
- statechainSignatures: response.refundTxSigningResult.signingResult?.signatureShares,
24143
- statechainPublicKeys: response.refundTxSigningResult.signingResult?.publicKeys,
24144
- verifyingKey: response.refundTxSigningResult.verifyingKey,
24145
- statechainCommitments: response.refundTxSigningResult.signingResult?.signingNonceCommitments,
24146
- selfCommitment: newCpfpRefundSigningJob.signingNonceCommitment,
24147
- publicKey: signingPublicKey,
24148
- selfSignature: cpfpRefundUserSig,
24149
- adaptorPubKey: new Uint8Array()
24150
- });
24151
- let directRefundSig;
24152
- if (directRefundSighash && newDirectRefundSigningJob && response.directRefundTxSigningResult) {
24153
- const directRefundUserSig = await this.config.signer.signFrost({
24154
- message: directRefundSighash,
24155
- keyDerivation,
24156
- publicKey: signingPublicKey,
24157
- verifyingKey: response.directRefundTxSigningResult.verifyingKey,
24158
- selfCommitment: newDirectRefundSigningJob.signingNonceCommitment,
24159
- statechainCommitments: response.directRefundTxSigningResult.signingResult?.signingNonceCommitments,
24160
- adaptorPubKey: new Uint8Array()
24161
- });
24162
- directRefundSig = await this.config.signer.aggregateFrost({
24163
- message: directRefundSighash,
24164
- statechainSignatures: response.directRefundTxSigningResult.signingResult?.signatureShares,
24165
- statechainPublicKeys: response.directRefundTxSigningResult.signingResult?.publicKeys,
24166
- verifyingKey: response.directRefundTxSigningResult.verifyingKey,
24167
- statechainCommitments: response.directRefundTxSigningResult.signingResult?.signingNonceCommitments,
24168
- selfCommitment: newDirectRefundSigningJob.signingNonceCommitment,
24169
- publicKey: signingPublicKey,
24170
- selfSignature: directRefundUserSig,
24171
- adaptorPubKey: new Uint8Array()
24172
- });
24173
- }
24174
- let directFromCpfpRefundSig;
24175
- if (directFromCpfpRefundSighash && newDirectFromCpfpRefundSigningJob && response.directFromCpfpRefundTxSigningResult) {
24176
- const directFromCpfpRefundUserSig = await this.config.signer.signFrost({
24177
- message: directFromCpfpRefundSighash,
24382
+ if (newDirectNodeTx) {
24383
+ signingJobs.push({
24384
+ signingPublicKey,
24385
+ rawTx: newDirectNodeTx.toBytes(),
24386
+ signingNonceCommitment: await this.config.signer.getRandomSigningCommitment(),
24387
+ type: "directNode",
24388
+ parentTxOut: splitNodeOutput,
24389
+ leafId: node.id,
24178
24390
  keyDerivation,
24179
- publicKey: signingPublicKey,
24180
- verifyingKey: response.directFromCpfpRefundTxSigningResult.verifyingKey,
24181
- selfCommitment: newDirectFromCpfpRefundSigningJob.signingNonceCommitment,
24182
- statechainCommitments: response.directFromCpfpRefundTxSigningResult.signingResult?.signingNonceCommitments,
24183
- adaptorPubKey: new Uint8Array()
24184
- });
24185
- directFromCpfpRefundSig = await this.config.signer.aggregateFrost({
24186
- message: directFromCpfpRefundSighash,
24187
- statechainSignatures: response.directFromCpfpRefundTxSigningResult.signingResult?.signatureShares,
24188
- statechainPublicKeys: response.directFromCpfpRefundTxSigningResult.signingResult?.publicKeys,
24189
- verifyingKey: response.directFromCpfpRefundTxSigningResult.verifyingKey,
24190
- statechainCommitments: response.directFromCpfpRefundTxSigningResult.signingResult?.signingNonceCommitments,
24191
- selfCommitment: newDirectFromCpfpRefundSigningJob.signingNonceCommitment,
24192
- publicKey: signingPublicKey,
24193
- selfSignature: directFromCpfpRefundUserSig,
24194
- adaptorPubKey: new Uint8Array()
24195
- });
24196
- }
24197
- return await sparkClient.finalize_node_signatures_v2({
24198
- intent: 4 /* EXTEND */,
24199
- nodeSignatures: [
24200
- {
24201
- nodeId: response.leafId,
24202
- nodeTxSignature: nodeSig,
24203
- directNodeTxSignature: directNodeSig,
24204
- refundTxSignature: cpfpRefundSig,
24205
- directRefundTxSignature: directRefundSig,
24206
- directFromCpfpRefundTxSignature: directFromCpfpRefundSig
24207
- }
24208
- ]
24209
- });
24210
- }
24211
- async testonly_expireTimeLockNodeTx(node, parentNode) {
24212
- return await this.refreshTimelockNodesInternal(node, parentNode, true);
24213
- }
24214
- async testonly_expireTimeLockRefundtx(node) {
24215
- const nodeTx = getTxFromRawTxBytes(node.nodeTx);
24216
- const directNodeTx = node.directTx.length > 0 ? getTxFromRawTxBytes(node.directTx) : void 0;
24217
- const cpfpRefundTx = getTxFromRawTxBytes(node.refundTx);
24218
- const currSequence = cpfpRefundTx.getInput(0).sequence || 0;
24219
- const currTimelock = getCurrentTimelock(currSequence);
24220
- if (currTimelock <= 100) {
24221
- throw new ValidationError("Cannot expire timelock below 100", {
24222
- field: "currTimelock",
24223
- value: currTimelock,
24224
- expected: "Timelock greater than 100"
24391
+ verifyingKey: node.verifyingPublicKey
24225
24392
  });
24226
24393
  }
24227
- const nextSequence = TEST_UNILATERAL_SEQUENCE;
24228
- const nextDirectSequence = TEST_UNILATERAL_SEQUENCE + DIRECT_TIMELOCK_OFFSET;
24229
- const nodeOutput = nodeTx.getOutput(0);
24230
- if (!nodeOutput) {
24231
- throw Error("Could not get node output");
24232
- }
24233
- const keyDerivation = {
24234
- type: "leaf" /* LEAF */,
24235
- path: node.id
24236
- };
24237
- const signingPublicKey = await this.config.signer.getPublicKeyFromDerivation(keyDerivation);
24238
- const cpfpRefundOutPoint = {
24239
- txid: (0, import_utils15.hexToBytes)(getTxId(nodeTx)),
24240
- index: 0
24241
- };
24242
- let directRefundOutPoint;
24243
- if (directNodeTx) {
24244
- directRefundOutPoint = {
24245
- txid: (0, import_utils15.hexToBytes)(getTxId(directNodeTx)),
24246
- index: 0
24247
- };
24394
+ const newCpfpNodeOutput = newNodeTx.getOutput(0);
24395
+ if (!newCpfpNodeOutput) {
24396
+ throw Error("Could not get new cpfp node output");
24248
24397
  }
24398
+ const newDirectNodeOutput = newDirectNodeTx?.getOutput(0);
24249
24399
  const {
24250
- cpfpRefundTx: newCpfpRefundTx,
24400
+ cpfpRefundTx: newRefundTx,
24251
24401
  directRefundTx: newDirectRefundTx,
24252
24402
  directFromCpfpRefundTx: newDirectFromCpfpRefundTx
24253
- } = createRefundTxs({
24254
- sequence: nextSequence,
24255
- directSequence: nextDirectSequence,
24256
- input: cpfpRefundOutPoint,
24257
- directInput: directRefundOutPoint,
24258
- amountSats: nodeOutput.amount,
24403
+ } = createInitialTimelockRefundTxs({
24404
+ nodeTx: newNodeTx,
24405
+ directNodeTx: newDirectNodeTx,
24259
24406
  receivingPubkey: signingPublicKey,
24260
24407
  network: this.config.getNetwork()
24261
24408
  });
24262
- const signingJobs = [];
24263
24409
  signingJobs.push({
24264
24410
  signingPublicKey,
24265
- rawTx: newCpfpRefundTx.toBytes(),
24411
+ rawTx: newRefundTx.toBytes(),
24266
24412
  signingNonceCommitment: await this.config.signer.getRandomSigningCommitment(),
24267
24413
  type: "cpfp",
24268
- parentTxOut: nodeOutput
24414
+ parentTxOut: newCpfpNodeOutput,
24415
+ leafId: node.id,
24416
+ keyDerivation,
24417
+ verifyingKey: node.verifyingPublicKey
24269
24418
  });
24270
- const directNodeTxOut = directNodeTx?.getOutput(0);
24271
- if (newDirectRefundTx && directNodeTxOut) {
24419
+ if (newDirectRefundTx && newDirectNodeOutput) {
24272
24420
  signingJobs.push({
24273
24421
  signingPublicKey,
24274
24422
  rawTx: newDirectRefundTx.toBytes(),
24275
24423
  signingNonceCommitment: await this.config.signer.getRandomSigningCommitment(),
24276
24424
  type: "direct",
24277
- parentTxOut: directNodeTxOut
24425
+ parentTxOut: newDirectNodeOutput,
24426
+ leafId: node.id,
24427
+ keyDerivation,
24428
+ verifyingKey: node.verifyingPublicKey
24278
24429
  });
24279
24430
  }
24280
- if (newDirectFromCpfpRefundTx) {
24431
+ if (newDirectFromCpfpRefundTx && newDirectNodeOutput) {
24281
24432
  signingJobs.push({
24282
24433
  signingPublicKey,
24283
24434
  rawTx: newDirectFromCpfpRefundTx.toBytes(),
24284
24435
  signingNonceCommitment: await this.config.signer.getRandomSigningCommitment(),
24285
24436
  type: "directFromCpfp",
24286
- parentTxOut: nodeOutput
24437
+ parentTxOut: newCpfpNodeOutput,
24438
+ leafId: node.id,
24439
+ keyDerivation,
24440
+ verifyingKey: node.verifyingPublicKey
24287
24441
  });
24288
24442
  }
24443
+ return signingJobs;
24444
+ }
24445
+ async renewZeroTimelockNodeTxn(node) {
24289
24446
  const sparkClient = await this.connectionManager.createSparkClient(
24290
24447
  this.config.getCoordinatorAddress()
24291
24448
  );
24292
- const response = await sparkClient.refresh_timelock_v2({
24293
- leafId: node.id,
24294
- ownerIdentityPublicKey: await this.config.signer.getIdentityPublicKey(),
24295
- signingJobs: signingJobs.map(getSigningJobProto)
24449
+ const signingJobs = await this.createRenewZeroTimelockNodeSigningJobs(node);
24450
+ const statechainCommitments = await sparkClient.get_signing_commitments({
24451
+ nodeIds: [node.id],
24452
+ count: signingJobs.length
24296
24453
  });
24297
- if (response.signingResults.length !== signingJobs.length) {
24298
- throw Error(
24299
- `Expected ${signingJobs.length} signing results, got ${response.signingResults.length}`
24300
- );
24301
- }
24302
- let cpfpRefundSignature;
24303
- let directRefundSignature;
24304
- let directFromCpfpRefundSignature;
24305
- for (const [i, signingJob] of signingJobs.entries()) {
24306
- const signingResult = response.signingResults[i];
24307
- if (!signingResult) {
24308
- throw Error("Signing result does not exist");
24454
+ const mappedSigningJobs = signingJobs.map((signingJob, index) => {
24455
+ const signingNonceCommitments = statechainCommitments.signingCommitments[index]?.signingNonceCommitments;
24456
+ if (!signingNonceCommitments) {
24457
+ throw new ValidationError("Signing nonce commitments not found", {
24458
+ field: "signingNonceCommitments",
24459
+ value: signingNonceCommitments
24460
+ });
24309
24461
  }
24310
- const rawTx = getTxFromRawTxBytes(signingJob.rawTx);
24311
- const txOut = signingJob.parentTxOut;
24312
- const rawTxSighash = getSigHashFromTx(rawTx, 0, txOut);
24313
- const userSignature = await this.config.signer.signFrost({
24314
- message: rawTxSighash,
24315
- keyDerivation,
24316
- publicKey: signingPublicKey,
24317
- verifyingKey: signingResult.verifyingKey,
24318
- selfCommitment: signingJob.signingNonceCommitment,
24319
- statechainCommitments: signingResult.signingResult?.signingNonceCommitments,
24320
- adaptorPubKey: new Uint8Array()
24321
- });
24322
- const signature = await this.config.signer.aggregateFrost({
24323
- message: rawTxSighash,
24324
- statechainSignatures: signingResult.signingResult?.signatureShares,
24325
- statechainPublicKeys: signingResult.signingResult?.publicKeys,
24326
- verifyingKey: signingResult.verifyingKey,
24327
- statechainCommitments: signingResult.signingResult?.signingNonceCommitments,
24328
- selfCommitment: signingJob.signingNonceCommitment,
24329
- publicKey: signingPublicKey,
24330
- selfSignature: userSignature,
24331
- adaptorPubKey: new Uint8Array()
24332
- });
24333
- if (signingJob.type === "cpfp") {
24334
- cpfpRefundSignature = signature;
24335
- } else if (signingJob.type === "direct") {
24336
- directRefundSignature = signature;
24337
- } else if (signingJob.type === "directFromCpfp") {
24338
- directFromCpfpRefundSignature = signature;
24462
+ return {
24463
+ ...signingJob,
24464
+ signingNonceCommitments
24465
+ };
24466
+ });
24467
+ const userSignedTxSigningJobs = await this.signingService.signSigningJobs(mappedSigningJobs);
24468
+ const renewZeroTimelockNodeSigningJob = {
24469
+ nodeTxSigningJob: userSignedTxSigningJobs.get("node"),
24470
+ refundTxSigningJob: userSignedTxSigningJobs.get("cpfp"),
24471
+ directNodeTxSigningJob: userSignedTxSigningJobs.get("directNode"),
24472
+ directRefundTxSigningJob: void 0,
24473
+ directFromCpfpRefundTxSigningJob: userSignedTxSigningJobs.get("directFromCpfp")
24474
+ };
24475
+ const response = await sparkClient.renew_leaf({
24476
+ leafId: node.id,
24477
+ signingJobs: {
24478
+ $case: "renewNodeZeroTimelockSigningJob",
24479
+ renewNodeZeroTimelockSigningJob: renewZeroTimelockNodeSigningJob
24339
24480
  }
24481
+ });
24482
+ if (response.renewResult?.$case !== "renewNodeZeroTimelockResult" || !response.renewResult?.renewNodeZeroTimelockResult.node) {
24483
+ throw new ValidationError("Unexpected renew result", {
24484
+ field: "renewResult",
24485
+ value: response.renewResult
24486
+ });
24340
24487
  }
24341
- const result = await sparkClient.finalize_node_signatures_v2({
24342
- intent: 3 /* REFRESH */,
24343
- nodeSignatures: [
24344
- {
24345
- nodeId: node.id,
24346
- nodeTxSignature: new Uint8Array(),
24347
- directNodeTxSignature: new Uint8Array(),
24348
- refundTxSignature: cpfpRefundSignature,
24349
- directRefundTxSignature: directRefundSignature,
24350
- directFromCpfpRefundTxSignature: directFromCpfpRefundSignature
24351
- }
24352
- ]
24488
+ return response.renewResult.renewNodeZeroTimelockResult.node;
24489
+ }
24490
+ async createRenewZeroTimelockNodeSigningJobs(node) {
24491
+ const signingJobs = [];
24492
+ const keyDerivation = {
24493
+ type: "leaf" /* LEAF */,
24494
+ path: node.id
24495
+ };
24496
+ const signingPublicKey = await this.config.signer.getPublicKeyFromDerivation(keyDerivation);
24497
+ const nodeTx = getTxFromRawTxBytes(node.nodeTx);
24498
+ const { nodeTx: newNodeTx, directNodeTx: newDirectNodeTx } = createZeroTimelockNodeTx(nodeTx);
24499
+ signingJobs.push({
24500
+ signingPublicKey,
24501
+ rawTx: newNodeTx.toBytes(),
24502
+ signingNonceCommitment: await this.config.signer.getRandomSigningCommitment(),
24503
+ type: "node",
24504
+ parentTxOut: nodeTx.getOutput(0),
24505
+ leafId: node.id,
24506
+ keyDerivation,
24507
+ verifyingKey: node.verifyingPublicKey
24353
24508
  });
24354
- return result;
24509
+ signingJobs.push({
24510
+ signingPublicKey,
24511
+ rawTx: newDirectNodeTx.toBytes(),
24512
+ signingNonceCommitment: await this.config.signer.getRandomSigningCommitment(),
24513
+ type: "directNode",
24514
+ parentTxOut: nodeTx.getOutput(0),
24515
+ leafId: node.id,
24516
+ keyDerivation,
24517
+ verifyingKey: node.verifyingPublicKey
24518
+ });
24519
+ const { cpfpRefundTx, directFromCpfpRefundTx } = createInitialTimelockRefundTxs({
24520
+ nodeTx: newNodeTx,
24521
+ directNodeTx: newDirectNodeTx,
24522
+ receivingPubkey: signingPublicKey,
24523
+ network: this.config.getNetwork()
24524
+ });
24525
+ signingJobs.push({
24526
+ signingPublicKey,
24527
+ rawTx: cpfpRefundTx.toBytes(),
24528
+ signingNonceCommitment: await this.config.signer.getRandomSigningCommitment(),
24529
+ type: "cpfp",
24530
+ parentTxOut: newNodeTx.getOutput(0),
24531
+ leafId: node.id,
24532
+ keyDerivation,
24533
+ verifyingKey: node.verifyingPublicKey
24534
+ });
24535
+ if (!directFromCpfpRefundTx) {
24536
+ throw new Error("Could not create direct refund transactions");
24537
+ }
24538
+ signingJobs.push({
24539
+ signingPublicKey,
24540
+ rawTx: directFromCpfpRefundTx.toBytes(),
24541
+ signingNonceCommitment: await this.config.signer.getRandomSigningCommitment(),
24542
+ type: "directFromCpfp",
24543
+ parentTxOut: newNodeTx.getOutput(0),
24544
+ leafId: node.id,
24545
+ keyDerivation,
24546
+ verifyingKey: node.verifyingPublicKey
24547
+ });
24548
+ return signingJobs;
24355
24549
  }
24356
24550
  };
24357
24551
 
@@ -24393,71 +24587,6 @@ var CoopExitService = class extends BaseTransferService {
24393
24587
  directFromCpfpSignaturesMap
24394
24588
  };
24395
24589
  }
24396
- createConnectorRefundTransactions(sequence, directSequence, cpfpNodeOutPoint, directNodeOutPoint, connectorOutput, amountSats, receiverPubKey) {
24397
- const cpfpRefundTx = new import_btc_signer3.Transaction();
24398
- if (!cpfpNodeOutPoint.txid || cpfpNodeOutPoint.index === void 0) {
24399
- throw new ValidationError("Invalid CPFP node outpoint", {
24400
- field: "cpfpNodeOutPoint",
24401
- value: { txid: cpfpNodeOutPoint.txid, index: cpfpNodeOutPoint.index },
24402
- expected: "Both txid and index must be defined"
24403
- });
24404
- }
24405
- cpfpRefundTx.addInput({
24406
- txid: cpfpNodeOutPoint.txid,
24407
- index: cpfpNodeOutPoint.index,
24408
- sequence
24409
- });
24410
- cpfpRefundTx.addInput(connectorOutput);
24411
- const receiverScript = getP2TRScriptFromPublicKey(
24412
- receiverPubKey,
24413
- this.config.getNetwork()
24414
- );
24415
- cpfpRefundTx.addOutput({
24416
- script: receiverScript,
24417
- amount: amountSats
24418
- });
24419
- let directRefundTx;
24420
- let directFromCpfpRefundTx;
24421
- if (directNodeOutPoint) {
24422
- if (!directNodeOutPoint.txid || directNodeOutPoint.index === void 0) {
24423
- throw new ValidationError("Invalid direct node outpoint", {
24424
- field: "directNodeOutPoint",
24425
- value: {
24426
- txid: directNodeOutPoint.txid,
24427
- index: directNodeOutPoint.index
24428
- },
24429
- expected: "Both txid and index must be defined"
24430
- });
24431
- }
24432
- directRefundTx = new import_btc_signer3.Transaction();
24433
- directRefundTx.addInput({
24434
- txid: directNodeOutPoint.txid,
24435
- index: directNodeOutPoint.index,
24436
- sequence: directSequence
24437
- });
24438
- directRefundTx.addInput(connectorOutput);
24439
- directRefundTx.addOutput({
24440
- script: receiverScript,
24441
- amount: maybeApplyFee(amountSats)
24442
- });
24443
- directFromCpfpRefundTx = new import_btc_signer3.Transaction();
24444
- directFromCpfpRefundTx.addInput({
24445
- txid: cpfpNodeOutPoint.txid,
24446
- index: cpfpNodeOutPoint.index,
24447
- sequence: directSequence
24448
- });
24449
- directFromCpfpRefundTx.addInput(connectorOutput);
24450
- directFromCpfpRefundTx.addOutput({
24451
- script: receiverScript,
24452
- amount: maybeApplyFee(amountSats)
24453
- });
24454
- }
24455
- return {
24456
- cpfpRefundTx,
24457
- directRefundTx,
24458
- directFromCpfpRefundTx
24459
- };
24460
- }
24461
24590
  async signCoopExitRefunds(leaves, exitTxId, connectorOutputs, receiverPubKey, transferId) {
24462
24591
  if (leaves.length !== connectorOutputs.length) {
24463
24592
  throw new ValidationError(
@@ -24491,29 +24620,39 @@ var CoopExitService = class extends BaseTransferService {
24491
24620
  expected: "Valid connector output"
24492
24621
  });
24493
24622
  }
24623
+ const nodeTx = getTxFromRawTxBytes(leaf.leaf.nodeTx);
24624
+ let directNodeTx;
24625
+ if (leaf.leaf.directTx.length > 0) {
24626
+ directNodeTx = getTxFromRawTxBytes(leaf.leaf.directTx);
24627
+ }
24494
24628
  const currentRefundTx = getTxFromRawTxBytes(leaf.leaf.refundTx);
24495
- const sequence = currentRefundTx.getInput(0).sequence;
24496
- if (!sequence) {
24629
+ if (!currentRefundTx) {
24630
+ throw new ValidationError("Invalid refund transaction", {
24631
+ field: "currentRefundTx",
24632
+ value: currentRefundTx,
24633
+ expected: "Non-null refund transaction"
24634
+ });
24635
+ }
24636
+ const currentSequence = currentRefundTx.getInput(0).sequence;
24637
+ if (!currentSequence) {
24497
24638
  throw new ValidationError("Invalid refund transaction", {
24498
24639
  field: "sequence",
24499
24640
  value: currentRefundTx.getInput(0),
24500
24641
  expected: "Non-null sequence"
24501
24642
  });
24502
24643
  }
24503
- const { nextSequence, nextDirectSequence } = getNextTransactionSequence(sequence);
24504
24644
  let currentDirectRefundTx;
24505
24645
  if (leaf.leaf.directRefundTx.length > 0) {
24506
24646
  currentDirectRefundTx = getTxFromRawTxBytes(leaf.leaf.directRefundTx);
24507
24647
  }
24508
- const { cpfpRefundTx, directRefundTx, directFromCpfpRefundTx } = this.createConnectorRefundTransactions(
24509
- nextSequence,
24510
- nextDirectSequence,
24511
- currentRefundTx.getInput(0),
24512
- currentDirectRefundTx?.getInput(0),
24648
+ const { cpfpRefundTx, directRefundTx, directFromCpfpRefundTx } = createConnectorRefundTxs({
24649
+ nodeTx,
24650
+ directNodeTx,
24651
+ sequence: currentSequence,
24513
24652
  connectorOutput,
24514
- BigInt(leaf.leaf.value),
24515
- receiverPubKey
24516
- );
24653
+ receivingPubkey: receiverPubKey,
24654
+ network: this.config.getNetwork()
24655
+ });
24517
24656
  const signingNonceCommitment = await this.config.signer.getRandomSigningCommitment();
24518
24657
  const directSigningNonceCommitment = await this.config.signer.getRandomSigningCommitment();
24519
24658
  const directFromCpfpSigningNonceCommitment = await this.config.signer.getRandomSigningCommitment();
@@ -24620,9 +24759,9 @@ var CoopExitService = class extends BaseTransferService {
24620
24759
  init_buffer();
24621
24760
  var import_secp256k110 = require("@noble/curves/secp256k1");
24622
24761
  var import_sha29 = require("@noble/hashes/sha2");
24623
- var import_utils16 = require("@noble/hashes/utils");
24624
- var import_btc_signer4 = require("@scure/btc-signer");
24625
- var import_utils17 = require("@scure/btc-signer/utils");
24762
+ var import_utils17 = require("@noble/hashes/utils");
24763
+ var import_btc_signer2 = require("@scure/btc-signer");
24764
+ var import_utils18 = require("@scure/btc-signer/utils");
24626
24765
  var DepositService = class {
24627
24766
  constructor(config, connectionManager) {
24628
24767
  __publicField(this, "config");
@@ -24650,7 +24789,7 @@ var DepositService = class {
24650
24789
  operatorPubkey,
24651
24790
  address.address
24652
24791
  );
24653
- const taprootKey = (0, import_btc_signer4.p2tr)(
24792
+ const taprootKey = (0, import_btc_signer2.p2tr)(
24654
24793
  operatorPubkey.slice(1, 33),
24655
24794
  void 0,
24656
24795
  getNetwork(this.config.getNetwork())
@@ -24674,7 +24813,7 @@ var DepositService = class {
24674
24813
  if (operator.identifier === this.config.getCoordinatorIdentifier() && !verifyCoordinatorProof) {
24675
24814
  continue;
24676
24815
  }
24677
- const operatorPubkey2 = (0, import_utils16.hexToBytes)(operator.identityPublicKey);
24816
+ const operatorPubkey2 = (0, import_utils17.hexToBytes)(operator.identityPublicKey);
24678
24817
  const operatorSig = address.depositAddressProof.addressSignatures[operator.identifier];
24679
24818
  if (!operatorSig) {
24680
24819
  throw new ValidationError("Operator signature not found", {
@@ -24793,38 +24932,18 @@ var DepositService = class {
24793
24932
  expected: "Valid output index"
24794
24933
  });
24795
24934
  }
24796
- const script = output.script;
24797
- const amount = output.amount;
24798
- if (!script || !amount) {
24799
- throw new ValidationError("No script or amount found in deposit tx", {
24800
- field: "output",
24801
- value: output,
24802
- expected: "Output with script and amount"
24803
- });
24804
- }
24805
- const depositOutPoint = {
24806
- txid: (0, import_utils16.hexToBytes)(getTxId(depositTx)),
24807
- index: vout
24808
- };
24809
- const depositTxOut = {
24810
- script,
24811
- amount
24812
- };
24813
- const [cpfpRootTx, directRootTx] = createRootTx(
24814
- depositOutPoint,
24815
- depositTxOut
24935
+ const { nodeTx: cpfpRootTx, directNodeTx: directRootTx } = createRootNodeTx(
24936
+ depositTx,
24937
+ vout
24816
24938
  );
24817
24939
  const cpfpRootNonceCommitment = await this.config.signer.getRandomSigningCommitment();
24818
24940
  const directRootNonceCommitment = await this.config.signer.getRandomSigningCommitment();
24819
24941
  const cpfpRootTxSighash = getSigHashFromTx(cpfpRootTx, 0, output);
24820
24942
  const directRootTxSighash = getSigHashFromTx(directRootTx, 0, output);
24821
24943
  const signingPubKey = await this.config.signer.getPublicKeyFromDerivation(keyDerivation);
24822
- const { cpfpRefundTx, directRefundTx, directFromCpfpRefundTx } = createRefundTxs({
24823
- sequence: INITIAL_SEQUENCE,
24824
- directSequence: INITIAL_DIRECT_SEQUENCE,
24825
- input: { txid: (0, import_utils16.hexToBytes)(getTxId(cpfpRootTx)), index: 0 },
24826
- directInput: { txid: (0, import_utils16.hexToBytes)(getTxId(directRootTx)), index: 0 },
24827
- amountSats: amount,
24944
+ const { cpfpRefundTx, directRefundTx, directFromCpfpRefundTx } = createInitialTimelockRefundTxs({
24945
+ nodeTx: cpfpRootTx,
24946
+ directNodeTx: directRootTx,
24828
24947
  receivingPubkey: signingPubKey,
24829
24948
  network: this.config.getNetwork()
24830
24949
  });
@@ -24953,7 +25072,7 @@ var DepositService = class {
24953
25072
  }
24954
25073
  );
24955
25074
  }
24956
- if (!(0, import_utils17.equalBytes)(treeResp.rootNodeSignatureShares.verifyingKey, verifyingKey)) {
25075
+ if (!(0, import_utils18.equalBytes)(treeResp.rootNodeSignatureShares.verifyingKey, verifyingKey)) {
24957
25076
  throw new ValidationError("Verifying key mismatch", {
24958
25077
  field: "verifyingKey",
24959
25078
  value: treeResp.rootNodeSignatureShares.verifyingKey,
@@ -25116,22 +25235,12 @@ var DepositService = class {
25116
25235
  expected: "Output with script and amount"
25117
25236
  });
25118
25237
  }
25119
- const depositOutPoint = {
25120
- txid: (0, import_utils16.hexToBytes)(getTxId(depositTx)),
25121
- index: vout
25122
- };
25123
- const depositTxOut = {
25124
- script,
25125
- amount
25126
- };
25127
- const [cpfpRootTx, _] = createRootTx(depositOutPoint, depositTxOut);
25238
+ const { nodeTx: cpfpRootTx } = createRootNodeTx(depositTx, vout);
25128
25239
  const cpfpRootNonceCommitment = await this.config.signer.getRandomSigningCommitment();
25129
25240
  const cpfpRootTxSighash = getSigHashFromTx(cpfpRootTx, 0, output);
25130
25241
  const signingPubKey = await this.config.signer.getPublicKeyFromDerivation(keyDerivation);
25131
- const { cpfpRefundTx } = createRefundTxs({
25132
- sequence: INITIAL_SEQUENCE,
25133
- input: { txid: (0, import_utils16.hexToBytes)(getTxId(cpfpRootTx)), index: 0 },
25134
- amountSats: amount,
25242
+ const { cpfpRefundTx } = createInitialTimelockRefundTxs({
25243
+ nodeTx: cpfpRootTx,
25135
25244
  receivingPubkey: signingPubKey,
25136
25245
  network: this.config.getNetwork()
25137
25246
  });
@@ -25200,7 +25309,7 @@ var DepositService = class {
25200
25309
  }
25201
25310
  );
25202
25311
  }
25203
- if (!(0, import_utils17.equalBytes)(treeResp.rootNodeSignatureShares.verifyingKey, verifyingKey)) {
25312
+ if (!(0, import_utils18.equalBytes)(treeResp.rootNodeSignatureShares.verifyingKey, verifyingKey)) {
25204
25313
  throw new ValidationError("Verifying key mismatch", {
25205
25314
  field: "verifyingKey",
25206
25315
  value: treeResp.rootNodeSignatureShares.verifyingKey,
@@ -25277,7 +25386,7 @@ var DepositService = class {
25277
25386
  // src/services/lightning.ts
25278
25387
  init_buffer();
25279
25388
  var import_secp256k111 = require("@noble/curves/secp256k1");
25280
- var import_utils18 = require("@noble/curves/utils");
25389
+ var import_utils19 = require("@noble/curves/utils");
25281
25390
  var import_sha210 = require("@noble/hashes/sha2");
25282
25391
  var import_uuidv74 = require("uuidv7");
25283
25392
 
@@ -25363,8 +25472,8 @@ var LightningService = class {
25363
25472
  }) {
25364
25473
  const crypto = getCrypto();
25365
25474
  const randBytes = crypto.getRandomValues(new Uint8Array(32));
25366
- const preimage = (0, import_utils18.numberToBytesBE)(
25367
- (0, import_utils18.bytesToNumberBE)(randBytes) % import_secp256k111.secp256k1.CURVE.n,
25475
+ const preimage = (0, import_utils19.numberToBytesBE)(
25476
+ (0, import_utils19.bytesToNumberBE)(randBytes) % import_secp256k111.secp256k1.CURVE.n,
25368
25477
  32
25369
25478
  );
25370
25479
  return await this.createLightningInvoiceWithPreImage({
@@ -25419,12 +25528,12 @@ var LightningService = class {
25419
25528
  const sparkClient = await this.connectionManager.createSparkClient(
25420
25529
  operator.address
25421
25530
  );
25422
- const userIdentityPublicKey = receiverIdentityPubkey ? (0, import_utils18.hexToBytes)(receiverIdentityPubkey) : await this.config.signer.getIdentityPublicKey();
25531
+ const userIdentityPublicKey = receiverIdentityPubkey ? (0, import_utils19.hexToBytes)(receiverIdentityPubkey) : await this.config.signer.getIdentityPublicKey();
25423
25532
  try {
25424
25533
  await sparkClient.store_preimage_share({
25425
25534
  paymentHash,
25426
25535
  preimageShare: {
25427
- secretShare: (0, import_utils18.numberToBytesBE)(share.share, 32),
25536
+ secretShare: (0, import_utils19.numberToBytesBE)(share.share, 32),
25428
25537
  proofs: share.proofs
25429
25538
  },
25430
25539
  threshold: this.config.getThreshold(),
@@ -25642,8 +25751,8 @@ var LightningService = class {
25642
25751
 
25643
25752
  // src/services/token-transactions.ts
25644
25753
  init_buffer();
25645
- var import_utils19 = require("@noble/curves/utils");
25646
- var import_utils20 = require("@noble/hashes/utils");
25754
+ var import_utils20 = require("@noble/curves/utils");
25755
+ var import_utils21 = require("@noble/hashes/utils");
25647
25756
 
25648
25757
  // src/utils/token-hashing.ts
25649
25758
  init_buffer();
@@ -29788,14 +29897,14 @@ var TokenTransactionService = class {
29788
29897
  }
29789
29898
  if (receiverAddress.sparkInvoiceFields) {
29790
29899
  return {
29791
- receiverPublicKey: (0, import_utils20.hexToBytes)(receiverAddress.identityPublicKey),
29900
+ receiverPublicKey: (0, import_utils21.hexToBytes)(receiverAddress.identityPublicKey),
29792
29901
  rawTokenIdentifier,
29793
29902
  tokenAmount: transfer.tokenAmount,
29794
29903
  sparkInvoice: transfer.receiverSparkAddress
29795
29904
  };
29796
29905
  }
29797
29906
  return {
29798
- receiverPublicKey: (0, import_utils20.hexToBytes)(receiverAddress.identityPublicKey),
29907
+ receiverPublicKey: (0, import_utils21.hexToBytes)(receiverAddress.identityPublicKey),
29799
29908
  rawTokenIdentifier,
29800
29909
  tokenAmount: transfer.tokenAmount
29801
29910
  };
@@ -29825,7 +29934,7 @@ var TokenTransactionService = class {
29825
29934
  (output) => ({
29826
29935
  ownerPublicKey: output.receiverPublicKey,
29827
29936
  tokenIdentifier: output.rawTokenIdentifier,
29828
- tokenAmount: (0, import_utils19.numberToBytesBE)(output.tokenAmount, 16)
29937
+ tokenAmount: (0, import_utils20.numberToBytesBE)(output.tokenAmount, 16)
29829
29938
  })
29830
29939
  );
29831
29940
  if (availableTokenAmount > totalRequestedAmount) {
@@ -29834,7 +29943,7 @@ var TokenTransactionService = class {
29834
29943
  tokenOutputs.push({
29835
29944
  ownerPublicKey: await this.config.signer.getIdentityPublicKey(),
29836
29945
  tokenIdentifier: firstTokenIdentifierBytes,
29837
- tokenAmount: (0, import_utils19.numberToBytesBE)(changeAmount, 16)
29946
+ tokenAmount: (0, import_utils20.numberToBytesBE)(changeAmount, 16)
29838
29947
  });
29839
29948
  }
29840
29949
  return {
@@ -29861,7 +29970,7 @@ var TokenTransactionService = class {
29861
29970
  for (const [_, operator] of Object.entries(
29862
29971
  this.config.getSigningOperators()
29863
29972
  )) {
29864
- operatorKeys.push((0, import_utils20.hexToBytes)(operator.identityPublicKey));
29973
+ operatorKeys.push((0, import_utils21.hexToBytes)(operator.identityPublicKey));
29865
29974
  }
29866
29975
  return operatorKeys;
29867
29976
  }
@@ -29878,7 +29987,7 @@ var TokenTransactionService = class {
29878
29987
  finalTokenTransactionHash,
29879
29988
  signingOperators
29880
29989
  );
29881
- return (0, import_utils19.bytesToHex)(finalTokenTransactionHash);
29990
+ return (0, import_utils20.bytesToHex)(finalTokenTransactionHash);
29882
29991
  }
29883
29992
  async startTokenTransaction(tokenTransaction, signingOperators, outputsToSpendSigningPublicKeys, outputsToSpendCommitments) {
29884
29993
  const sparkClient = await this.connectionManager.createSparkTokenClient(
@@ -30053,10 +30162,10 @@ var TokenTransactionService = class {
30053
30162
  });
30054
30163
  }
30055
30164
  for (const ownerPublicKey of ownerPublicKeys) {
30056
- isValidPublicKey((0, import_utils19.bytesToHex)(ownerPublicKey));
30165
+ isValidPublicKey((0, import_utils20.bytesToHex)(ownerPublicKey));
30057
30166
  }
30058
30167
  for (const issuerPublicKey of issuerPublicKeys) {
30059
- isValidPublicKey((0, import_utils19.bytesToHex)(issuerPublicKey));
30168
+ isValidPublicKey((0, import_utils20.bytesToHex)(issuerPublicKey));
30060
30169
  }
30061
30170
  for (const tokenIdentifier of tokenIdentifiers) {
30062
30171
  if (tokenIdentifier.length !== 32) {
@@ -30124,8 +30233,8 @@ var TokenTransactionService = class {
30124
30233
  this.config.getCoordinatorAddress()
30125
30234
  );
30126
30235
  let queryParams = {
30127
- issuerPublicKeys: issuerPublicKeys?.map(import_utils20.hexToBytes),
30128
- ownerPublicKeys: ownerPublicKeys?.map(import_utils20.hexToBytes),
30236
+ issuerPublicKeys: issuerPublicKeys?.map(import_utils21.hexToBytes),
30237
+ ownerPublicKeys: ownerPublicKeys?.map(import_utils21.hexToBytes),
30129
30238
  tokenIdentifiers: tokenIdentifiers?.map((identifier) => {
30130
30239
  const { tokenIdentifier } = decodeBech32mTokenIdentifier(
30131
30240
  identifier,
@@ -30133,7 +30242,7 @@ var TokenTransactionService = class {
30133
30242
  );
30134
30243
  return tokenIdentifier;
30135
30244
  }),
30136
- tokenTransactionHashes: tokenTransactionHashes?.map(import_utils20.hexToBytes),
30245
+ tokenTransactionHashes: tokenTransactionHashes?.map(import_utils21.hexToBytes),
30137
30246
  outputIds: outputIds || [],
30138
30247
  limit: pageSize,
30139
30248
  offset
@@ -30168,7 +30277,7 @@ var TokenTransactionService = class {
30168
30277
  });
30169
30278
  }
30170
30279
  const exactMatch = tokenOutputs.find(
30171
- (item) => (0, import_utils19.bytesToNumberBE)(item.output.tokenAmount) === tokenAmount
30280
+ (item) => (0, import_utils20.bytesToNumberBE)(item.output.tokenAmount) === tokenAmount
30172
30281
  );
30173
30282
  if (exactMatch) {
30174
30283
  return [exactMatch];
@@ -30179,7 +30288,7 @@ var TokenTransactionService = class {
30179
30288
  for (const outputWithPreviousTransactionData of tokenOutputs) {
30180
30289
  if (remainingAmount <= 0n) break;
30181
30290
  selectedOutputs.push(outputWithPreviousTransactionData);
30182
- remainingAmount -= (0, import_utils19.bytesToNumberBE)(
30291
+ remainingAmount -= (0, import_utils20.bytesToNumberBE)(
30183
30292
  outputWithPreviousTransactionData.output.tokenAmount
30184
30293
  );
30185
30294
  }
@@ -30194,14 +30303,14 @@ var TokenTransactionService = class {
30194
30303
  sortTokenOutputsByStrategy(tokenOutputs, strategy) {
30195
30304
  if (strategy === "SMALL_FIRST") {
30196
30305
  tokenOutputs.sort((a, b) => {
30197
- const amountA = (0, import_utils19.bytesToNumberBE)(a.output.tokenAmount);
30198
- const amountB = (0, import_utils19.bytesToNumberBE)(b.output.tokenAmount);
30306
+ const amountA = (0, import_utils20.bytesToNumberBE)(a.output.tokenAmount);
30307
+ const amountB = (0, import_utils20.bytesToNumberBE)(b.output.tokenAmount);
30199
30308
  return amountA < amountB ? -1 : amountA > amountB ? 1 : 0;
30200
30309
  });
30201
30310
  } else {
30202
30311
  tokenOutputs.sort((a, b) => {
30203
- const amountA = (0, import_utils19.bytesToNumberBE)(a.output.tokenAmount);
30204
- const amountB = (0, import_utils19.bytesToNumberBE)(b.output.tokenAmount);
30312
+ const amountA = (0, import_utils20.bytesToNumberBE)(a.output.tokenAmount);
30313
+ const amountB = (0, import_utils20.bytesToNumberBE)(b.output.tokenAmount);
30205
30314
  return amountB < amountA ? -1 : amountB > amountA ? 1 : 0;
30206
30315
  });
30207
30316
  }
@@ -30209,7 +30318,7 @@ var TokenTransactionService = class {
30209
30318
  // Helper function for deciding if the signer public key is the identity public key
30210
30319
  async signMessageWithKey(message, publicKey) {
30211
30320
  const tokenSignatures = this.config.getTokenSignatures();
30212
- if ((0, import_utils19.bytesToHex)(publicKey) === (0, import_utils19.bytesToHex)(await this.config.signer.getIdentityPublicKey())) {
30321
+ if ((0, import_utils20.bytesToHex)(publicKey) === (0, import_utils20.bytesToHex)(await this.config.signer.getIdentityPublicKey())) {
30213
30322
  if (tokenSignatures === "SCHNORR") {
30214
30323
  return await this.config.signer.signSchnorrWithIdentityKey(message);
30215
30324
  } else {
@@ -30218,8 +30327,8 @@ var TokenTransactionService = class {
30218
30327
  } else {
30219
30328
  throw new ValidationError("Invalid public key", {
30220
30329
  field: "publicKey",
30221
- value: (0, import_utils19.bytesToHex)(publicKey),
30222
- expected: (0, import_utils19.bytesToHex)(await this.config.signer.getIdentityPublicKey())
30330
+ value: (0, import_utils20.bytesToHex)(publicKey),
30331
+ expected: (0, import_utils20.bytesToHex)(await this.config.signer.getIdentityPublicKey())
30223
30332
  });
30224
30333
  }
30225
30334
  }
@@ -30238,7 +30347,7 @@ var TokenTransactionService = class {
30238
30347
  }
30239
30348
  const payload = {
30240
30349
  finalTokenTransactionHash,
30241
- operatorIdentityPublicKey: (0, import_utils20.hexToBytes)(operator.identityPublicKey)
30350
+ operatorIdentityPublicKey: (0, import_utils21.hexToBytes)(operator.identityPublicKey)
30242
30351
  };
30243
30352
  const payloadHash = await hashOperatorSpecificTokenTransactionSignablePayload(payload);
30244
30353
  const ownerSignature = await this.signMessageWithKey(
@@ -30260,7 +30369,7 @@ var TokenTransactionService = class {
30260
30369
  }
30261
30370
  const payload = {
30262
30371
  finalTokenTransactionHash,
30263
- operatorIdentityPublicKey: (0, import_utils20.hexToBytes)(operator.identityPublicKey)
30372
+ operatorIdentityPublicKey: (0, import_utils21.hexToBytes)(operator.identityPublicKey)
30264
30373
  };
30265
30374
  const payloadHash = await hashOperatorSpecificTokenTransactionSignablePayload(payload);
30266
30375
  const ownerSignature = await this.signMessageWithKey(
@@ -30276,7 +30385,7 @@ var TokenTransactionService = class {
30276
30385
  for (let i = 0; i < transferInput.outputsToSpend.length; i++) {
30277
30386
  const payload = {
30278
30387
  finalTokenTransactionHash,
30279
- operatorIdentityPublicKey: (0, import_utils20.hexToBytes)(operator.identityPublicKey)
30388
+ operatorIdentityPublicKey: (0, import_utils21.hexToBytes)(operator.identityPublicKey)
30280
30389
  };
30281
30390
  const payloadHash = await hashOperatorSpecificTokenTransactionSignablePayload(payload);
30282
30391
  let ownerSignature;
@@ -30293,7 +30402,7 @@ var TokenTransactionService = class {
30293
30402
  }
30294
30403
  inputTtxoSignaturesPerOperator.push({
30295
30404
  ttxoSignatures,
30296
- operatorIdentityPublicKey: (0, import_utils20.hexToBytes)(operator.identityPublicKey)
30405
+ operatorIdentityPublicKey: (0, import_utils21.hexToBytes)(operator.identityPublicKey)
30297
30406
  });
30298
30407
  }
30299
30408
  return inputTtxoSignaturesPerOperator;
@@ -30309,13 +30418,12 @@ var import_nice_grpc_common2 = require("nice-grpc-common");
30309
30418
 
30310
30419
  // src/services/signing.ts
30311
30420
  init_buffer();
30312
- var import_utils22 = require("@noble/curves/utils");
30313
30421
 
30314
30422
  // src/utils/htlc-transactions.ts
30315
30423
  init_buffer();
30316
- var import_btc_signer5 = require("@scure/btc-signer");
30424
+ var import_btc_signer3 = require("@scure/btc-signer");
30317
30425
  var import_secp256k112 = require("@noble/curves/secp256k1");
30318
- var import_utils21 = require("@noble/curves/utils");
30426
+ var import_utils22 = require("@noble/curves/utils");
30319
30427
  var PUB_KEY_BYTES = "0250929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0";
30320
30428
  function numsPoint() {
30321
30429
  const withdrawalPubKeyPoint = import_secp256k112.secp256k1.Point.fromHex(PUB_KEY_BYTES);
@@ -30393,10 +30501,10 @@ function createLightningHTLCTransaction({
30393
30501
  outAmount = maybeApplyFee(outAmount);
30394
30502
  }
30395
30503
  const input = {
30396
- txid: (0, import_utils21.hexToBytes)(getTxId(nodeTx)),
30504
+ txid: (0, import_utils22.hexToBytes)(getTxId(nodeTx)),
30397
30505
  index: 0
30398
30506
  };
30399
- const htlcTransaction = new import_btc_signer5.Transaction({
30507
+ const htlcTransaction = new import_btc_signer3.Transaction({
30400
30508
  version: 3,
30401
30509
  allowUnknownOutputs: true
30402
30510
  });
@@ -30435,12 +30543,12 @@ function createHTLCTaprootAddress({
30435
30543
  );
30436
30544
  const hashLockLeaf = { leafVersion: 192, script: hashLockScript };
30437
30545
  const sequenceLockLeaf = { leafVersion: 192, script: sequenceLockScript };
30438
- const scriptTree = (0, import_btc_signer5.taprootListToTree)([hashLockLeaf, sequenceLockLeaf]);
30439
- const p2trScript = (0, import_btc_signer5.p2tr)(numsKey, scriptTree, network, true).script;
30546
+ const scriptTree = (0, import_btc_signer3.taprootListToTree)([hashLockLeaf, sequenceLockLeaf]);
30547
+ const p2trScript = (0, import_btc_signer3.p2tr)(numsKey, scriptTree, network, true).script;
30440
30548
  return p2trScript;
30441
30549
  }
30442
30550
  function createHashLockScript(hash, pubkey) {
30443
- const result = import_btc_signer5.Script.encode([
30551
+ const result = import_btc_signer3.Script.encode([
30444
30552
  "SHA256",
30445
30553
  hash,
30446
30554
  "EQUALVERIFY",
@@ -30450,8 +30558,8 @@ function createHashLockScript(hash, pubkey) {
30450
30558
  return result;
30451
30559
  }
30452
30560
  function createSequenceLockScript(sequence, sequenceLockDestinationPubkey) {
30453
- const result = import_btc_signer5.Script.encode([
30454
- (0, import_btc_signer5.ScriptNum)().encode(BigInt(sequence)),
30561
+ const result = import_btc_signer3.Script.encode([
30562
+ (0, import_btc_signer3.ScriptNum)().encode(BigInt(sequence)),
30455
30563
  "CHECKSEQUENCEVERIFY",
30456
30564
  "DROP",
30457
30565
  sequenceLockDestinationPubkey.slice(1, 33),
@@ -30515,20 +30623,7 @@ var SigningService = class {
30515
30623
  });
30516
30624
  }
30517
30625
  const nodeTx = getTxFromRawTxBytes(leaf.leaf.nodeTx);
30518
- const cpfpNodeOutPoint = {
30519
- txid: (0, import_utils22.hexToBytes)(getTxId(nodeTx)),
30520
- index: 0
30521
- };
30522
30626
  const currRefundTx = getTxFromRawTxBytes(leaf.leaf.refundTx);
30523
- const sequence = currRefundTx.getInput(0).sequence;
30524
- if (!sequence) {
30525
- throw new ValidationError("Invalid refund transaction", {
30526
- field: "sequence",
30527
- value: currRefundTx.getInput(0),
30528
- expected: "Non-null sequence"
30529
- });
30530
- }
30531
- const { nextSequence, nextDirectSequence } = getNextTransactionSequence(sequence);
30532
30627
  const amountSats = currRefundTx.getOutput(0).amount;
30533
30628
  if (amountSats === void 0) {
30534
30629
  throw new ValidationError("Invalid refund transaction", {
@@ -30538,20 +30633,21 @@ var SigningService = class {
30538
30633
  });
30539
30634
  }
30540
30635
  let directNodeTx;
30541
- let directNodeOutPoint;
30542
30636
  if (leaf.leaf.directTx.length > 0) {
30543
30637
  directNodeTx = getTxFromRawTxBytes(leaf.leaf.directTx);
30544
- directNodeOutPoint = {
30545
- txid: (0, import_utils22.hexToBytes)(getTxId(directNodeTx)),
30546
- index: 0
30547
- };
30548
30638
  }
30549
- const { cpfpRefundTx, directRefundTx, directFromCpfpRefundTx } = createRefundTxs({
30550
- sequence: nextSequence,
30551
- directSequence: nextDirectSequence,
30552
- input: cpfpNodeOutPoint,
30553
- directInput: directNodeOutPoint,
30554
- amountSats,
30639
+ const currentSequence = currRefundTx.getInput(0).sequence;
30640
+ if (!currentSequence) {
30641
+ throw new ValidationError("Invalid refund transaction", {
30642
+ field: "sequence",
30643
+ value: currRefundTx.getInput(0),
30644
+ expected: "Non-null sequence"
30645
+ });
30646
+ }
30647
+ const { cpfpRefundTx, directRefundTx, directFromCpfpRefundTx } = createDecrementedTimelockRefundTxs({
30648
+ nodeTx,
30649
+ directNodeTx,
30650
+ sequence: currentSequence,
30555
30651
  receivingPubkey: receiverIdentityPubkey,
30556
30652
  network: this.config.getNetwork()
30557
30653
  });
@@ -30567,7 +30663,8 @@ var SigningService = class {
30567
30663
  cpfpSigningCommitments[i]?.signingNonceCommitments
30568
30664
  );
30569
30665
  cpfpLeafSigningJobs.push(...signingJobs);
30570
- if (directRefundTx) {
30666
+ const isZeroNode = getCurrentTimelock(nodeTx.getInput(0).sequence);
30667
+ if (directRefundTx && !isZeroNode) {
30571
30668
  if (!directNodeTx) {
30572
30669
  throw new ValidationError(
30573
30670
  "Direct node transaction undefined while direct refund transaction is defined",
@@ -30592,16 +30689,6 @@ var SigningService = class {
30592
30689
  directLeafSigningJobs.push(...signingJobs2);
30593
30690
  }
30594
30691
  if (directFromCpfpRefundTx) {
30595
- if (!directNodeTx) {
30596
- throw new ValidationError(
30597
- "Direct node transaction undefined while direct from CPFP refund transaction is defined",
30598
- {
30599
- field: "directNodeTx",
30600
- value: directNodeTx,
30601
- expected: "Non-null direct node transaction"
30602
- }
30603
- );
30604
- }
30605
30692
  const refundSighash2 = getSigHashFromTx(
30606
30693
  directFromCpfpRefundTx,
30607
30694
  0,
@@ -30728,6 +30815,35 @@ var SigningService = class {
30728
30815
  directFromCpfpLeafSigningJobs
30729
30816
  };
30730
30817
  }
30818
+ async signSigningJobs(signingJobs) {
30819
+ const userSignedTxSigningJobs = /* @__PURE__ */ new Map();
30820
+ for (const signingJob of signingJobs) {
30821
+ const rawTx = getTxFromRawTxBytes(signingJob.rawTx);
30822
+ const txOut = signingJob.parentTxOut;
30823
+ const rawTxSighash = getSigHashFromTx(rawTx, 0, txOut);
30824
+ const userSignature = await this.config.signer.signFrost({
30825
+ message: rawTxSighash,
30826
+ keyDerivation: signingJob.keyDerivation,
30827
+ publicKey: signingJob.signingPublicKey,
30828
+ verifyingKey: signingJob.verifyingKey,
30829
+ selfCommitment: signingJob.signingNonceCommitment,
30830
+ statechainCommitments: signingJob.signingNonceCommitments,
30831
+ adaptorPubKey: new Uint8Array()
30832
+ });
30833
+ const userSignedTxSigningJob = {
30834
+ leafId: signingJob.leafId,
30835
+ signingPublicKey: signingJob.signingPublicKey,
30836
+ rawTx: rawTx.toBytes(),
30837
+ signingNonceCommitment: signingJob.signingNonceCommitment.commitment,
30838
+ signingCommitments: {
30839
+ signingCommitments: signingJob.signingNonceCommitments
30840
+ },
30841
+ userSignature
30842
+ };
30843
+ userSignedTxSigningJobs.set(signingJob.type, userSignedTxSigningJob);
30844
+ }
30845
+ return userSignedTxSigningJobs;
30846
+ }
30731
30847
  };
30732
30848
 
30733
30849
  // src/tests/utils/test-faucet.ts
@@ -30735,7 +30851,7 @@ init_buffer();
30735
30851
  var import_secp256k113 = require("@noble/curves/secp256k1");
30736
30852
  var import_utils23 = require("@noble/curves/utils");
30737
30853
  var btc5 = __toESM(require("@scure/btc-signer"), 1);
30738
- var import_btc_signer6 = require("@scure/btc-signer");
30854
+ var import_btc_signer4 = require("@scure/btc-signer");
30739
30855
  var import_utils24 = require("@scure/btc-signer/utils");
30740
30856
  var STATIC_FAUCET_KEY = (0, import_utils23.hexToBytes)(
30741
30857
  "deadbeef1337cafe4242424242424242deadbeef1337cafe4242424242424242"
@@ -30822,7 +30938,7 @@ var _BitcoinFaucet = class _BitcoinFaucet {
30822
30938
  );
30823
30939
  await this.generateToAddress(1, address);
30824
30940
  const fundingTxRaw = await this.getRawTransaction(fundingTxid);
30825
- const fundingTx = import_btc_signer6.Transaction.fromRaw((0, import_utils23.hexToBytes)(fundingTxRaw.hex));
30941
+ const fundingTx = import_btc_signer4.Transaction.fromRaw((0, import_utils23.hexToBytes)(fundingTxRaw.hex));
30826
30942
  for (let i = 0; i < fundingTx.outputsLength; i++) {
30827
30943
  const output = fundingTx.getOutput(i);
30828
30944
  if (!output.script || !output.amount) continue;
@@ -30853,7 +30969,7 @@ var _BitcoinFaucet = class _BitcoinFaucet {
30853
30969
  `Selected UTXO (${selectedUtxoAmountSats} sats) is too small to create even one faucet coin of ${COIN_AMOUNT} sats`
30854
30970
  );
30855
30971
  }
30856
- const splitTx = new import_btc_signer6.Transaction();
30972
+ const splitTx = new import_btc_signer4.Transaction();
30857
30973
  splitTx.addInput({
30858
30974
  txid: selectedUtxo.txid,
30859
30975
  index: selectedUtxo.vout
@@ -30896,7 +31012,7 @@ var _BitcoinFaucet = class _BitcoinFaucet {
30896
31012
  }
30897
31013
  }
30898
31014
  async sendFaucetCoinToP2WPKHAddress(pubKey) {
30899
- const sendToPubKeyTx = new import_btc_signer6.Transaction();
31015
+ const sendToPubKeyTx = new import_btc_signer4.Transaction();
30900
31016
  const p2wpkhAddress = btc5.p2wpkh(pubKey, getNetwork(4 /* LOCAL */)).address;
30901
31017
  if (!p2wpkhAddress) {
30902
31018
  throw new Error("Invalid P2WPKH address");
@@ -30932,7 +31048,7 @@ var _BitcoinFaucet = class _BitcoinFaucet {
30932
31048
  const sighash = unsignedTx.preimageWitnessV1(
30933
31049
  0,
30934
31050
  new Array(unsignedTx.inputsLength).fill(script),
30935
- import_btc_signer6.SigHash.DEFAULT,
31051
+ import_btc_signer4.SigHash.DEFAULT,
30936
31052
  new Array(unsignedTx.inputsLength).fill(fundingTxOut.amount)
30937
31053
  );
30938
31054
  const merkleRoot = new Uint8Array();
@@ -30951,6 +31067,14 @@ var _BitcoinFaucet = class _BitcoinFaucet {
30951
31067
  async mineBlocks(numBlocks) {
30952
31068
  return await this.generateToAddress(numBlocks, this.miningAddress);
30953
31069
  }
31070
+ async mineBlocksAndWaitForMiningToComplete(numBlocks) {
31071
+ const startBlock = await this.getBlockCount();
31072
+ await this.mineBlocks(numBlocks);
31073
+ await this.waitForBlocksMined({
31074
+ startBlock,
31075
+ expectedIncrease: numBlocks
31076
+ });
31077
+ }
30954
31078
  async call(method, params) {
30955
31079
  try {
30956
31080
  const { fetch, Headers: Headers2 } = getFetch();
@@ -31003,27 +31127,62 @@ var _BitcoinFaucet = class _BitcoinFaucet {
31003
31127
  async getBlock(blockHash) {
31004
31128
  return await this.call("getblock", [blockHash, 2]);
31005
31129
  }
31130
+ async getBlockCount() {
31131
+ return await this.call("getblockcount", []);
31132
+ }
31133
+ async waitForBlocksMined({
31134
+ startBlock,
31135
+ expectedIncrease,
31136
+ timeoutMs = 3e4,
31137
+ intervalMs = 5e3
31138
+ }) {
31139
+ const deadline = Date.now() + timeoutMs;
31140
+ await new Promise((r) => setTimeout(r, intervalMs));
31141
+ const start = startBlock;
31142
+ const target = start + expectedIncrease;
31143
+ while (Date.now() < deadline) {
31144
+ const currentBlock = await this.getBlockCount();
31145
+ if (currentBlock >= target) return currentBlock;
31146
+ await new Promise((r) => setTimeout(r, intervalMs));
31147
+ }
31148
+ throw new Error(
31149
+ `Timed out waiting for ${expectedIncrease} blocks (target height ${target})`
31150
+ );
31151
+ }
31006
31152
  async broadcastTx(txHex) {
31007
31153
  let response = await this.call("sendrawtransaction", [txHex, 0]);
31008
31154
  return response;
31009
31155
  }
31156
+ async submitPackage(txHexs) {
31157
+ let response = await this.call("submitpackage", [txHexs]);
31158
+ return response;
31159
+ }
31010
31160
  async getNewAddress() {
31011
31161
  const key = import_secp256k113.secp256k1.utils.randomPrivateKey();
31012
31162
  const pubKey = import_secp256k113.secp256k1.getPublicKey(key);
31013
31163
  return getP2TRAddressFromPublicKey(pubKey, 4 /* LOCAL */);
31014
31164
  }
31165
+ async getNewExternalWallet() {
31166
+ const key = import_secp256k113.secp256k1.utils.randomPrivateKey();
31167
+ const pubKey = import_secp256k113.secp256k1.getPublicKey(key);
31168
+ return {
31169
+ address: getP2TRAddressFromPublicKey(pubKey, 4 /* LOCAL */),
31170
+ key,
31171
+ pubKey
31172
+ };
31173
+ }
31015
31174
  async sendToAddress(address, amount, blocksToGenerate = 1) {
31016
31175
  const coin = await this.fund();
31017
31176
  if (!coin) {
31018
31177
  throw new Error("No coins available");
31019
31178
  }
31020
- const tx = new import_btc_signer6.Transaction();
31179
+ const tx = new import_btc_signer4.Transaction();
31021
31180
  tx.addInput(coin.outpoint);
31022
31181
  const availableAmount = COIN_AMOUNT - FEE_AMOUNT;
31023
- const destinationAddress = (0, import_btc_signer6.Address)(getNetwork(4 /* LOCAL */)).decode(
31182
+ const destinationAddress = (0, import_btc_signer4.Address)(getNetwork(4 /* LOCAL */)).decode(
31024
31183
  address
31025
31184
  );
31026
- const destinationScript = import_btc_signer6.OutScript.encode(destinationAddress);
31185
+ const destinationScript = import_btc_signer4.OutScript.encode(destinationAddress);
31027
31186
  tx.addOutput({
31028
31187
  script: destinationScript,
31029
31188
  amount
@@ -31070,76 +31229,6 @@ function chunkArray(arr, size) {
31070
31229
  return chunks;
31071
31230
  }
31072
31231
 
31073
- // src/utils/optimize.ts
31074
- init_buffer();
31075
- var DENOMINATIONS = Array.from({ length: 28 }, (_, i) => 2 ** i);
31076
- function assert(condition, message) {
31077
- if (!condition) {
31078
- throw new InternalValidationError(message || "Assertion failed");
31079
- }
31080
- }
31081
- function sum(arr) {
31082
- return arr.reduce((a, b) => a + b, 0);
31083
- }
31084
- function sorted(arr) {
31085
- return [...arr].sort((a, b) => a - b);
31086
- }
31087
- function equals(a, b) {
31088
- return a.length === b.length && a.every((val, index) => val === b[index]);
31089
- }
31090
- function greedyLeaves(amount) {
31091
- const leaves = [];
31092
- let remaining = amount;
31093
- for (let i = DENOMINATIONS.length - 1; i >= 0; i--) {
31094
- const leaf = DENOMINATIONS[i];
31095
- if (typeof leaf === "number" && leaf > 0) {
31096
- while (remaining >= leaf) {
31097
- remaining -= leaf;
31098
- leaves.push(leaf);
31099
- }
31100
- }
31101
- }
31102
- assert(sum(leaves) === amount, "greedy_leaves: sum mismatch");
31103
- return sorted(leaves);
31104
- }
31105
- var Swap = class {
31106
- constructor(inLeaves, outLeaves) {
31107
- __publicField(this, "inLeaves");
31108
- __publicField(this, "outLeaves");
31109
- this.inLeaves = [...inLeaves];
31110
- this.outLeaves = [...outLeaves];
31111
- assert(
31112
- sum(this.inLeaves) === sum(this.outLeaves),
31113
- "Swap in/out leaves must sum to same value for swap: " + this.toString()
31114
- );
31115
- }
31116
- toString() {
31117
- return `Swap(in=${JSON.stringify(this.inLeaves)}, out=${JSON.stringify(this.outLeaves)})`;
31118
- }
31119
- };
31120
- function maximizeUnilateralExit(inputLeaves, maxLeavesPerSwap = 64) {
31121
- const swaps = [];
31122
- let batch = [];
31123
- let leaves = sorted(inputLeaves);
31124
- while (leaves.length > 0) {
31125
- batch.push(leaves.shift());
31126
- const target = greedyLeaves(sum(batch));
31127
- if (batch.length >= maxLeavesPerSwap || target.length >= maxLeavesPerSwap) {
31128
- if (!equals(target, batch)) {
31129
- swaps.push(new Swap([...batch], target));
31130
- }
31131
- batch = [];
31132
- }
31133
- }
31134
- if (batch.length > 0) {
31135
- const target = greedyLeaves(sum(batch));
31136
- if (!equals(target, batch)) {
31137
- swaps.push(new Swap([...batch], target));
31138
- }
31139
- }
31140
- return swaps;
31141
- }
31142
-
31143
31232
  // src/utils/retry.ts
31144
31233
  init_buffer();
31145
31234
  var DEFAULT_RETRY_CONFIG = {
@@ -31218,6 +31307,200 @@ var SparkWalletEvent = {
31218
31307
  StreamReconnecting: "stream:reconnecting"
31219
31308
  };
31220
31309
 
31310
+ // src/utils/optimize.ts
31311
+ init_buffer();
31312
+ var DENOMINATIONS = Array.from({ length: 28 }, (_, i) => 2 ** i);
31313
+ function assert(condition, message) {
31314
+ if (!condition) {
31315
+ throw new InternalValidationError(message || "Assertion failed");
31316
+ }
31317
+ }
31318
+ function sum(arr) {
31319
+ return arr.reduce((a, b) => a + b, 0);
31320
+ }
31321
+ function sorted(arr) {
31322
+ return [...arr].sort((a, b) => a - b);
31323
+ }
31324
+ function equals(a, b) {
31325
+ return a.length === b.length && a.every((val, index) => val === b[index]);
31326
+ }
31327
+ function countOccurrences(arr) {
31328
+ const map = /* @__PURE__ */ new Map();
31329
+ for (const x of arr) {
31330
+ map.set(x, (map.get(x) ?? 0) + 1);
31331
+ }
31332
+ return map;
31333
+ }
31334
+ function subtractCounters(a, b) {
31335
+ const result = /* @__PURE__ */ new Map();
31336
+ for (const [key, value] of a.entries()) {
31337
+ const diff = value - (b.get(key) ?? 0);
31338
+ if (diff > 0) {
31339
+ result.set(key, diff);
31340
+ }
31341
+ }
31342
+ return result;
31343
+ }
31344
+ function counterToFlatArray(counter) {
31345
+ const arr = [];
31346
+ for (const [k, v] of Array.from(counter.entries()).sort(
31347
+ (a, b) => a[0] - b[0]
31348
+ )) {
31349
+ for (let i = 0; i < v; i++) {
31350
+ arr.push(k);
31351
+ }
31352
+ }
31353
+ return arr;
31354
+ }
31355
+ function greedyLeaves(amount) {
31356
+ const leaves = [];
31357
+ let remaining = amount;
31358
+ for (let i = DENOMINATIONS.length - 1; i >= 0; i--) {
31359
+ const leaf = DENOMINATIONS[i];
31360
+ if (typeof leaf === "number" && leaf > 0) {
31361
+ while (remaining >= leaf) {
31362
+ remaining -= leaf;
31363
+ leaves.push(leaf);
31364
+ }
31365
+ }
31366
+ }
31367
+ assert(sum(leaves) === amount, "greedy_leaves: sum mismatch");
31368
+ return sorted(leaves);
31369
+ }
31370
+ function swapMinimizingLeaves(amount, multiplicity = 1) {
31371
+ const leaves = [];
31372
+ let remaining = amount;
31373
+ assert(multiplicity > 0, "multiplicity must be > 0");
31374
+ for (const leaf of DENOMINATIONS) {
31375
+ if (typeof leaf === "number" && leaf > 0) {
31376
+ for (let i = 0; i < multiplicity; i++) {
31377
+ if (remaining >= leaf) {
31378
+ remaining -= leaf;
31379
+ leaves.push(leaf);
31380
+ }
31381
+ }
31382
+ }
31383
+ }
31384
+ leaves.push(...greedyLeaves(remaining));
31385
+ assert(sum(leaves) === amount, "swap_minimizing_leaves: sum mismatch");
31386
+ return sorted(leaves);
31387
+ }
31388
+ var Swap = class {
31389
+ constructor(inLeaves, outLeaves) {
31390
+ __publicField(this, "inLeaves");
31391
+ __publicField(this, "outLeaves");
31392
+ this.inLeaves = [...inLeaves];
31393
+ this.outLeaves = [...outLeaves];
31394
+ assert(
31395
+ sum(this.inLeaves) === sum(this.outLeaves),
31396
+ "Swap in/out leaves must sum to same value for swap: " + this.toString()
31397
+ );
31398
+ }
31399
+ toString() {
31400
+ return `Swap(in=${JSON.stringify(this.inLeaves)}, out=${JSON.stringify(this.outLeaves)})`;
31401
+ }
31402
+ };
31403
+ function maximizeUnilateralExit(inputLeaves, maxLeavesPerSwap = 64) {
31404
+ const swaps = [];
31405
+ let batch = [];
31406
+ let leaves = sorted(inputLeaves);
31407
+ while (leaves.length > 0) {
31408
+ batch.push(leaves.shift());
31409
+ const target = greedyLeaves(sum(batch));
31410
+ if (batch.length >= maxLeavesPerSwap || target.length >= maxLeavesPerSwap) {
31411
+ if (!equals(target, batch)) {
31412
+ swaps.push(new Swap([...batch], target));
31413
+ }
31414
+ batch = [];
31415
+ }
31416
+ }
31417
+ if (batch.length > 0) {
31418
+ const target = greedyLeaves(sum(batch));
31419
+ if (!equals(target, batch)) {
31420
+ swaps.push(new Swap([...batch], target));
31421
+ }
31422
+ }
31423
+ return swaps;
31424
+ }
31425
+ function minimizeTransferSwap(inputLeaves, multiplicity = 1, maxLeavesPerSwap = 64) {
31426
+ const balance = sum(inputLeaves);
31427
+ const optimalLeaves = swapMinimizingLeaves(balance, multiplicity);
31428
+ const walletCounter = countOccurrences(inputLeaves);
31429
+ const optimalCounter = countOccurrences(optimalLeaves);
31430
+ const leavesToGive = subtractCounters(walletCounter, optimalCounter);
31431
+ const leavesToReceive = subtractCounters(optimalCounter, walletCounter);
31432
+ const leavesToGiveFlat = counterToFlatArray(leavesToGive);
31433
+ const leavesToReceiveFlat = counterToFlatArray(leavesToReceive);
31434
+ const swaps = [];
31435
+ let toGiveBatch = [];
31436
+ let toReceiveBatch = [];
31437
+ let give = [...leavesToGiveFlat];
31438
+ let receive = [...leavesToReceiveFlat];
31439
+ while (give.length > 0 || receive.length > 0) {
31440
+ if (sum(toGiveBatch) > sum(toReceiveBatch)) {
31441
+ if (receive.length === 0) break;
31442
+ toReceiveBatch.push(receive.shift());
31443
+ } else {
31444
+ if (give.length === 0) break;
31445
+ toGiveBatch.push(give.shift());
31446
+ }
31447
+ if (toGiveBatch.length > 0 && toReceiveBatch.length > 0 && sum(toGiveBatch) === sum(toReceiveBatch)) {
31448
+ if (toGiveBatch.length > maxLeavesPerSwap) {
31449
+ for (let i = 0; i < toGiveBatch.length; i += maxLeavesPerSwap) {
31450
+ const subset = toGiveBatch.slice(i, i + maxLeavesPerSwap);
31451
+ swaps.push(new Swap(subset, greedyLeaves(sum(subset))));
31452
+ }
31453
+ } else if (toReceiveBatch.length > maxLeavesPerSwap) {
31454
+ for (let cutoff = maxLeavesPerSwap; cutoff > 0; cutoff--) {
31455
+ const sumCut = sum(toReceiveBatch.slice(0, cutoff));
31456
+ const remainder = sum(toGiveBatch) - sumCut;
31457
+ const alternateBatch = [
31458
+ ...toReceiveBatch.slice(0, cutoff),
31459
+ ...greedyLeaves(remainder)
31460
+ ];
31461
+ if (alternateBatch.length <= maxLeavesPerSwap) {
31462
+ swaps.push(new Swap([...toGiveBatch], alternateBatch));
31463
+ break;
31464
+ }
31465
+ }
31466
+ } else {
31467
+ swaps.push(new Swap([...toGiveBatch], [...toReceiveBatch]));
31468
+ }
31469
+ toGiveBatch = [];
31470
+ toReceiveBatch = [];
31471
+ }
31472
+ }
31473
+ return swaps;
31474
+ }
31475
+ function shouldOptimize(inputLeaves, multiplicity = 1, maxLeavesPerSwap = 64) {
31476
+ if (multiplicity == 0) {
31477
+ const swaps = maximizeUnilateralExit(inputLeaves, maxLeavesPerSwap);
31478
+ const numInputs = sum(swaps.map((swap) => swap.inLeaves.length));
31479
+ const numOutputs = sum(swaps.map((swap) => swap.outLeaves.length));
31480
+ return numOutputs * 5 < numInputs;
31481
+ } else {
31482
+ const swaps = minimizeTransferSwap(
31483
+ inputLeaves,
31484
+ multiplicity,
31485
+ maxLeavesPerSwap
31486
+ );
31487
+ const inputCounter = countOccurrences(
31488
+ swaps.flatMap((swap) => swap.inLeaves)
31489
+ );
31490
+ const outputCounter = countOccurrences(
31491
+ swaps.flatMap((swap) => swap.outLeaves)
31492
+ );
31493
+ return Math.abs(inputCounter.size - outputCounter.size) > 1;
31494
+ }
31495
+ }
31496
+ function optimize(inputLeaves, multiplicity = 1, maxLeavesPerSwap = 64) {
31497
+ if (multiplicity == 0) {
31498
+ return maximizeUnilateralExit(inputLeaves, maxLeavesPerSwap);
31499
+ } else {
31500
+ return minimizeTransferSwap(inputLeaves, multiplicity, maxLeavesPerSwap);
31501
+ }
31502
+ }
31503
+
31221
31504
  // src/spark-wallet/spark-wallet.ts
31222
31505
  var SparkWallet = class extends import_eventemitter3.EventEmitter {
31223
31506
  constructor(options, signerArg) {
@@ -31322,16 +31605,13 @@ var SparkWallet = class extends import_eventemitter3.EventEmitter {
31322
31605
  if (event.transfer.transfer && !(0, import_utils25.equalBytes)(senderIdentityPublicKey, receiverIdentityPublicKey)) {
31323
31606
  await this.claimTransfer({
31324
31607
  transfer: event.transfer.transfer,
31325
- emit: true,
31326
- optimize: true
31608
+ emit: true
31327
31609
  });
31328
31610
  }
31329
31611
  } else if (isDepositStreamEvent(event)) {
31330
31612
  const deposit = event.deposit.deposit;
31331
- const newLeaf = await this.transferService.extendTimelock(deposit);
31332
- await this.transferLeavesToSelf(newLeaf.nodes, {
31333
- type: "leaf" /* LEAF */,
31334
- path: deposit.id
31613
+ await this.withLeaves(async () => {
31614
+ this.leaves.push(deposit);
31335
31615
  });
31336
31616
  this.emit(
31337
31617
  SparkWalletEvent.DepositConfirmed,
@@ -31507,19 +31787,6 @@ var SparkWallet = class extends import_eventemitter3.EventEmitter {
31507
31787
  }
31508
31788
  return availableLeaves.filter(([_, node]) => !leavesToIgnore.has(node.id)).map(([_, node]) => node);
31509
31789
  }
31510
- async checkExtendLeaves(leaves) {
31511
- await this.withLeaves(async () => {
31512
- for (const leaf of leaves) {
31513
- if (!leaf.parentNodeId && leaf.status === "AVAILABLE") {
31514
- const res = await this.transferService.extendTimelock(leaf);
31515
- await this.transferLeavesToSelf(res.nodes, {
31516
- type: "leaf" /* LEAF */,
31517
- path: leaf.id
31518
- });
31519
- }
31520
- }
31521
- });
31522
- }
31523
31790
  verifyKey(pubkey1, pubkey2, verifyingKey) {
31524
31791
  return (0, import_utils25.equalBytes)(addPublicKeys(pubkey1, pubkey2), verifyingKey);
31525
31792
  }
@@ -31629,75 +31896,84 @@ var SparkWallet = class extends import_eventemitter3.EventEmitter {
31629
31896
  }
31630
31897
  return nodes;
31631
31898
  }
31632
- areLeavesInefficient() {
31633
- const totalAmount = this.getInternalBalance();
31634
- if (this.leaves.length <= 1) {
31635
- return false;
31636
- }
31637
- const nextLowerPowerOfTwo = 31 - Math.clz32(totalAmount);
31638
- let remainingAmount = totalAmount;
31639
- let optimalLeavesLength = 0;
31640
- for (let i = nextLowerPowerOfTwo; i >= 0; i--) {
31641
- const denomination = 2 ** i;
31642
- while (remainingAmount >= denomination) {
31643
- remainingAmount -= denomination;
31644
- optimalLeavesLength++;
31645
- }
31899
+ async *optimizeLeaves(multiplicity = void 0) {
31900
+ const multiplicityValue = multiplicity ?? this.config.getOptimizationOptions().multiplicity ?? 0;
31901
+ if (multiplicityValue < 0) {
31902
+ throw new ValidationError("Multiplicity cannot be negative");
31903
+ } else if (multiplicityValue > 5) {
31904
+ throw new ValidationError("Multiplicity cannot be greater than 5");
31646
31905
  }
31647
- return this.leaves.length > optimalLeavesLength * 5;
31648
- }
31649
- async optimizeLeaves() {
31650
- if (this.optimizationInProgress || !this.areLeavesInefficient()) {
31906
+ if (this.optimizationInProgress || !shouldOptimize(
31907
+ this.leaves.map((leaf) => leaf.value),
31908
+ multiplicityValue
31909
+ )) {
31651
31910
  return;
31652
31911
  }
31653
- await this.withLeaves(async () => {
31912
+ const controller = new AbortController();
31913
+ const release = await this.leavesMutex.acquire();
31914
+ try {
31654
31915
  this.optimizationInProgress = true;
31655
- try {
31656
- this.leaves = await this.getLeaves();
31657
- const swaps = maximizeUnilateralExit(
31658
- this.leaves.map((leaf) => leaf.value)
31659
- );
31660
- const valueToNodes = /* @__PURE__ */ new Map();
31661
- this.leaves.forEach((leaf) => {
31662
- if (!valueToNodes.has(leaf.value)) {
31663
- valueToNodes.set(leaf.value, []);
31664
- }
31665
- valueToNodes.get(leaf.value).push(leaf);
31666
- });
31667
- for (const swap of swaps) {
31668
- const leavesToSend = [];
31669
- for (const leafValue of swap.inLeaves) {
31670
- const nodes = valueToNodes.get(leafValue);
31671
- if (nodes && nodes.length > 0) {
31672
- const node = nodes.shift();
31673
- leavesToSend.push(node);
31674
- } else {
31675
- throw new InternalValidationError(
31676
- `No unused leaf with value ${leafValue} found in leaves`
31677
- );
31678
- }
31916
+ this.leaves = await this.getLeaves();
31917
+ const swaps = optimize(
31918
+ this.leaves.map((leaf) => leaf.value),
31919
+ multiplicityValue
31920
+ );
31921
+ if (swaps.length === 0) {
31922
+ return;
31923
+ }
31924
+ yield {
31925
+ step: 0,
31926
+ total: swaps.length,
31927
+ controller
31928
+ };
31929
+ const valueToNodes = /* @__PURE__ */ new Map();
31930
+ this.leaves.forEach((leaf) => {
31931
+ if (!valueToNodes.has(leaf.value)) {
31932
+ valueToNodes.set(leaf.value, []);
31933
+ }
31934
+ valueToNodes.get(leaf.value).push(leaf);
31935
+ });
31936
+ for (const swap of swaps) {
31937
+ if (controller.signal.aborted) {
31938
+ break;
31939
+ }
31940
+ const leavesToSend = [];
31941
+ for (const leafValue of swap.inLeaves) {
31942
+ const nodes = valueToNodes.get(leafValue);
31943
+ if (nodes && nodes.length > 0) {
31944
+ const node = nodes.shift();
31945
+ leavesToSend.push(node);
31946
+ } else {
31947
+ throw new InternalValidationError(
31948
+ `No unused leaf with value ${leafValue} found in leaves`
31949
+ );
31679
31950
  }
31680
- await this.requestLeavesSwap({
31681
- leaves: leavesToSend,
31682
- targetAmounts: swap.outLeaves
31683
- });
31684
31951
  }
31685
- this.leaves = await this.getLeaves();
31686
- } finally {
31687
- this.optimizationInProgress = false;
31952
+ await this.requestLeavesSwap({
31953
+ leaves: leavesToSend,
31954
+ targetAmounts: swap.outLeaves
31955
+ });
31956
+ yield {
31957
+ step: swaps.indexOf(swap) + 1,
31958
+ total: swaps.length,
31959
+ controller
31960
+ };
31688
31961
  }
31689
- });
31962
+ this.leaves = await this.getLeaves();
31963
+ } finally {
31964
+ this.optimizationInProgress = false;
31965
+ release();
31966
+ }
31690
31967
  }
31691
31968
  async syncWallet() {
31692
31969
  await this.syncTokenOutputs();
31693
31970
  let leaves = await this.getLeaves();
31694
- leaves = await this.checkRefreshTimelockNodes(leaves);
31695
- leaves = await this.checkExtendTimeLockNodes(leaves);
31971
+ leaves = await this.checkRenewLeaves(leaves);
31696
31972
  this.leaves = leaves;
31697
- this.checkExtendLeaves(leaves);
31698
- this.optimizeLeaves().catch((e) => {
31699
- console.error("Failed to optimize leaves", e);
31700
- });
31973
+ if (this.config.getOptimizationOptions().auto) {
31974
+ for await (const _ of this.optimizeLeaves()) {
31975
+ }
31976
+ }
31701
31977
  }
31702
31978
  async withLeaves(operation) {
31703
31979
  const release = await this.leavesMutex.acquire();
@@ -32280,8 +32556,7 @@ var SparkWallet = class extends import_eventemitter3.EventEmitter {
32280
32556
  }
32281
32557
  return await this.claimTransfer({
32282
32558
  transfer: incomingTransfer,
32283
- emit: false,
32284
- optimize: false
32559
+ emit: false
32285
32560
  });
32286
32561
  } catch (e) {
32287
32562
  console.error("[processSwapBatch] Error details:", {
@@ -32675,16 +32950,16 @@ var SparkWallet = class extends import_eventemitter3.EventEmitter {
32675
32950
  }
32676
32951
  );
32677
32952
  }
32678
- const tx = new import_btc_signer7.Transaction();
32953
+ const tx = new import_btc_signer5.Transaction();
32679
32954
  tx.addInput({
32680
32955
  txid: depositTransactionId,
32681
32956
  index: outputIndex,
32682
32957
  witnessScript: new Uint8Array()
32683
32958
  });
32684
- const addressDecoded = (0, import_btc_signer7.Address)(getNetwork(network)).decode(
32959
+ const addressDecoded = (0, import_btc_signer5.Address)(getNetwork(network)).decode(
32685
32960
  destinationAddress
32686
32961
  );
32687
- const outputScript = import_btc_signer7.OutScript.encode(addressDecoded);
32962
+ const outputScript = import_btc_signer5.OutScript.encode(addressDecoded);
32688
32963
  tx.addOutput({
32689
32964
  script: outputScript,
32690
32965
  amount: BigInt(creditAmountSats)
@@ -32868,8 +33143,8 @@ var SparkWallet = class extends import_eventemitter3.EventEmitter {
32868
33143
  if (!output) {
32869
33144
  continue;
32870
33145
  }
32871
- const parsedScript = import_btc_signer7.OutScript.decode(output.script);
32872
- const address = (0, import_btc_signer7.Address)(getNetwork(this.config.getNetwork())).encode(
33146
+ const parsedScript = import_btc_signer5.OutScript.decode(output.script);
33147
+ const address = (0, import_btc_signer5.Address)(getNetwork(this.config.getNetwork())).encode(
32873
33148
  parsedScript
32874
33149
  );
32875
33150
  if (staticDepositAddresses.has(address)) {
@@ -32946,26 +33221,7 @@ var SparkWallet = class extends import_eventemitter3.EventEmitter {
32946
33221
  depositTx,
32947
33222
  vout
32948
33223
  });
32949
- const resultingNodes = [];
32950
- for (const node of res.nodes) {
32951
- if (node.status === "AVAILABLE") {
32952
- const { nodes } = await this.transferService.extendTimelock(node);
32953
- for (const n of nodes) {
32954
- if (n.status === "AVAILABLE") {
32955
- const transfer = await this.transferLeavesToSelf([n], {
32956
- type: "leaf" /* LEAF */,
32957
- path: node.id
32958
- });
32959
- resultingNodes.push(...transfer);
32960
- } else {
32961
- resultingNodes.push(n);
32962
- }
32963
- }
32964
- } else {
32965
- resultingNodes.push(node);
32966
- }
32967
- }
32968
- return resultingNodes;
33224
+ return res.nodes;
32969
33225
  }
32970
33226
  /**
32971
33227
  * Gets all unused deposit addresses for the wallet.
@@ -33074,8 +33330,8 @@ var SparkWallet = class extends import_eventemitter3.EventEmitter {
33074
33330
  if (!output) {
33075
33331
  continue;
33076
33332
  }
33077
- const parsedScript = import_btc_signer7.OutScript.decode(output.script);
33078
- const address = (0, import_btc_signer7.Address)(getNetwork(this.config.getNetwork())).encode(
33333
+ const parsedScript = import_btc_signer5.OutScript.decode(output.script);
33334
+ const address = (0, import_btc_signer5.Address)(getNetwork(this.config.getNetwork())).encode(
33079
33335
  parsedScript
33080
33336
  );
33081
33337
  if (unusedDepositAddresses.has(address)) {
@@ -33107,6 +33363,9 @@ var SparkWallet = class extends import_eventemitter3.EventEmitter {
33107
33363
  depositTx,
33108
33364
  vout
33109
33365
  });
33366
+ await this.withLeaves(async () => {
33367
+ this.leaves.push(...nodes2);
33368
+ });
33110
33369
  return nodes2;
33111
33370
  });
33112
33371
  this.mutexes.delete(txid);
@@ -33135,8 +33394,8 @@ var SparkWallet = class extends import_eventemitter3.EventEmitter {
33135
33394
  if (!output) {
33136
33395
  continue;
33137
33396
  }
33138
- const parsedScript = import_btc_signer7.OutScript.decode(output.script);
33139
- const address = (0, import_btc_signer7.Address)(getNetwork(this.config.getNetwork())).encode(
33397
+ const parsedScript = import_btc_signer5.OutScript.decode(output.script);
33398
+ const address = (0, import_btc_signer5.Address)(getNetwork(this.config.getNetwork())).encode(
33140
33399
  parsedScript
33141
33400
  );
33142
33401
  const unusedDepositAddress = unusedDepositAddresses.get(address);
@@ -33283,8 +33542,7 @@ var SparkWallet = class extends import_eventemitter3.EventEmitter {
33283
33542
  `TreeNode group at index ${groupIndex} not found for amount ${amount} after selection`
33284
33543
  );
33285
33544
  }
33286
- let available = await this.checkRefreshTimelockNodes(group);
33287
- available = await this.checkExtendTimeLockNodes(available);
33545
+ const available = await this.checkRenewLeaves(group);
33288
33546
  if (available.length < group.length) {
33289
33547
  throw new Error(
33290
33548
  `Not enough available nodes after refresh/extend. Expected ${group.length}, got ${available.length}`
@@ -33327,7 +33585,7 @@ var SparkWallet = class extends import_eventemitter3.EventEmitter {
33327
33585
  transfer.id
33328
33586
  );
33329
33587
  if (pending) {
33330
- await this.claimTransfer({ transfer: pending, optimize: true });
33588
+ await this.claimTransfer({ transfer: pending });
33331
33589
  }
33332
33590
  }
33333
33591
  return {
@@ -33377,75 +33635,45 @@ var SparkWallet = class extends import_eventemitter3.EventEmitter {
33377
33635
  newKeyDerivation: { type: "random" /* RANDOM */ }
33378
33636
  };
33379
33637
  }
33380
- async checkExtendTimeLockNodes(nodes) {
33381
- const nodesToExtend = [];
33638
+ async checkRenewLeaves(nodes) {
33639
+ const nodesToRenewNode = [];
33640
+ const nodesToRenewRefund = [];
33641
+ const nodesToRenewZeroTimelock = [];
33382
33642
  const nodeIds = [];
33383
33643
  const validNodes = [];
33384
33644
  for (const node of nodes) {
33385
33645
  const nodeTx = getTxFromRawTxBytes(node.nodeTx);
33386
- const sequence = nodeTx.getInput(0).sequence;
33387
- if (!sequence) {
33646
+ const refundTx = getTxFromRawTxBytes(node.refundTx);
33647
+ const nodeSequence = nodeTx.getInput(0).sequence;
33648
+ const refundSequence = refundTx.getInput(0).sequence;
33649
+ if (nodeSequence === void 0) {
33388
33650
  throw new ValidationError("Invalid node transaction", {
33389
33651
  field: "sequence",
33390
33652
  value: nodeTx.getInput(0),
33391
33653
  expected: "Non-null sequence"
33392
33654
  });
33393
33655
  }
33394
- const needsRefresh = doesLeafNeedRefresh(sequence, true);
33395
- if (needsRefresh) {
33396
- nodesToExtend.push(node);
33397
- nodeIds.push(node.id);
33398
- } else {
33399
- validNodes.push(node);
33400
- }
33401
- }
33402
- if (nodesToExtend.length === 0) {
33403
- return validNodes;
33404
- }
33405
- const nodesToAdd = [];
33406
- for (const node of nodesToExtend) {
33407
- const { nodes: nodes2 } = await this.transferService.extendTimelock(node);
33408
- this.leaves = this.leaves.filter((leaf) => leaf.id !== node.id);
33409
- const newNodes = await this.transferLeavesToSelf(nodes2, {
33410
- type: "leaf" /* LEAF */,
33411
- path: node.id
33412
- });
33413
- nodesToAdd.push(...newNodes);
33414
- }
33415
- this.updateLeaves(nodeIds, nodesToAdd);
33416
- validNodes.push(...nodesToAdd);
33417
- return validNodes;
33418
- }
33419
- /**
33420
- * Internal method to refresh timelock nodes.
33421
- *
33422
- * @param {string} nodeId - The optional ID of the node to refresh. If not provided, all nodes will be checked.
33423
- * @returns {Promise<void>}
33424
- * @private
33425
- */
33426
- async checkRefreshTimelockNodes(nodes) {
33427
- const nodesToRefresh = [];
33428
- const nodeIds = [];
33429
- const validNodes = [];
33430
- for (const node of nodes) {
33431
- const refundTx = getTxFromRawTxBytes(node.refundTx);
33432
- const sequence = refundTx.getInput(0).sequence;
33433
- if (!sequence) {
33656
+ if (!refundSequence) {
33434
33657
  throw new ValidationError("Invalid refund transaction", {
33435
33658
  field: "sequence",
33436
33659
  value: refundTx.getInput(0),
33437
33660
  expected: "Non-null sequence"
33438
33661
  });
33439
33662
  }
33440
- const needsRefresh = doesLeafNeedRefresh(sequence);
33441
- if (needsRefresh) {
33442
- nodesToRefresh.push(node);
33663
+ if (doesTxnNeedRenewed(refundSequence)) {
33664
+ if (isZeroTimelock(nodeSequence)) {
33665
+ nodesToRenewZeroTimelock.push(node);
33666
+ } else if (doesTxnNeedRenewed(nodeSequence)) {
33667
+ nodesToRenewNode.push(node);
33668
+ } else {
33669
+ nodesToRenewRefund.push(node);
33670
+ }
33443
33671
  nodeIds.push(node.id);
33444
33672
  } else {
33445
33673
  validNodes.push(node);
33446
33674
  }
33447
33675
  }
33448
- if (nodesToRefresh.length === 0) {
33676
+ if (nodesToRenewNode.length === 0 && nodesToRenewRefund.length === 0 && nodesToRenewZeroTimelock.length === 0) {
33449
33677
  return validNodes;
33450
33678
  }
33451
33679
  const nodesResp = await this.queryNodes({
@@ -33463,7 +33691,7 @@ var SparkWallet = class extends import_eventemitter3.EventEmitter {
33463
33691
  nodesMap.set(node.id, node);
33464
33692
  }
33465
33693
  const nodesToAdd = [];
33466
- for (const node of nodesToRefresh) {
33694
+ for (const node of nodesToRenewNode) {
33467
33695
  if (!node.parentNodeId) {
33468
33696
  throw new Error(`node ${node.id} has no parent`);
33469
33697
  }
@@ -33471,17 +33699,25 @@ var SparkWallet = class extends import_eventemitter3.EventEmitter {
33471
33699
  if (!parentNode) {
33472
33700
  throw new Error(`parent node ${node.parentNodeId} not found`);
33473
33701
  }
33474
- const { nodes: nodes2 } = await this.transferService.refreshTimelockNodes(
33702
+ const newNode = await this.transferService.renewNodeTxn(node, parentNode);
33703
+ nodesToAdd.push(newNode);
33704
+ }
33705
+ for (const node of nodesToRenewRefund) {
33706
+ if (!node.parentNodeId) {
33707
+ throw new Error(`node ${node.id} has no parent`);
33708
+ }
33709
+ const parentNode = nodesMap.get(node.parentNodeId);
33710
+ if (!parentNode) {
33711
+ throw new Error(`parent node ${node.parentNodeId} not found`);
33712
+ }
33713
+ const newNode = await this.transferService.renewRefundTxn(
33475
33714
  node,
33476
33715
  parentNode
33477
33716
  );
33478
- if (nodes2.length !== 1) {
33479
- throw new Error(`expected 1 node, got ${nodes2.length}`);
33480
- }
33481
- const newNode = nodes2[0];
33482
- if (!newNode) {
33483
- throw new Error("Failed to refresh timelock node");
33484
- }
33717
+ nodesToAdd.push(newNode);
33718
+ }
33719
+ for (const node of nodesToRenewZeroTimelock) {
33720
+ const newNode = await this.transferService.renewZeroTimelockNodeTxn(node);
33485
33721
  nodesToAdd.push(newNode);
33486
33722
  }
33487
33723
  this.updateLeaves(nodeIds, nodesToAdd);
@@ -33522,14 +33758,14 @@ var SparkWallet = class extends import_eventemitter3.EventEmitter {
33522
33758
  return response.nodes;
33523
33759
  });
33524
33760
  }
33525
- async processClaimedTransferResults(result, transfer, emit, optimize) {
33526
- result = await this.checkRefreshTimelockNodes(result);
33527
- result = await this.checkExtendTimeLockNodes(result);
33761
+ async processClaimedTransferResults(result, transfer, emit) {
33762
+ result = await this.checkRenewLeaves(result);
33528
33763
  const existingIds = new Set(this.leaves.map((leaf) => leaf.id));
33529
33764
  const uniqueResults = result.filter((node) => !existingIds.has(node.id));
33530
33765
  this.leaves.push(...uniqueResults);
33531
- if (optimize && transfer.type !== 40 /* COUNTER_SWAP */) {
33532
- await this.optimizeLeaves();
33766
+ if (this.config.getOptimizationOptions().auto && transfer.type !== 40 /* COUNTER_SWAP */) {
33767
+ for await (const _ of this.optimizeLeaves()) {
33768
+ }
33533
33769
  }
33534
33770
  if (emit) {
33535
33771
  this.emit(
@@ -33548,8 +33784,7 @@ var SparkWallet = class extends import_eventemitter3.EventEmitter {
33548
33784
  */
33549
33785
  async claimTransfer({
33550
33786
  transfer,
33551
- emit,
33552
- optimize
33787
+ emit
33553
33788
  }) {
33554
33789
  const onError = async (context) => {
33555
33790
  const error = context.error;
@@ -33594,12 +33829,7 @@ var SparkWallet = class extends import_eventemitter3.EventEmitter {
33594
33829
  if (result.length === 0) {
33595
33830
  return [];
33596
33831
  }
33597
- return await this.processClaimedTransferResults(
33598
- result,
33599
- transfer,
33600
- emit,
33601
- optimize
33602
- );
33832
+ return await this.processClaimedTransferResults(result, transfer, emit);
33603
33833
  } catch (error) {
33604
33834
  console.warn(
33605
33835
  `Failed to claim transfer after all retries. Please try reinitializing your wallet in a few minutes. Transfer ID: ${transfer.id}`,
@@ -33632,7 +33862,7 @@ var SparkWallet = class extends import_eventemitter3.EventEmitter {
33632
33862
  continue;
33633
33863
  }
33634
33864
  promises.push(
33635
- this.claimTransfer({ transfer, emit, optimize: true }).then(() => transfer.id).catch((error) => {
33865
+ this.claimTransfer({ transfer, emit }).then(() => transfer.id).catch((error) => {
33636
33866
  console.warn(`Failed to claim transfer ${transfer.id}:`, error);
33637
33867
  return null;
33638
33868
  })
@@ -33903,8 +34133,7 @@ var SparkWallet = class extends import_eventemitter3.EventEmitter {
33903
34133
  selectedLeaves,
33904
34134
  `no leaves for ${totalAmount}`
33905
34135
  );
33906
- leaves = await this.checkRefreshTimelockNodes(leaves);
33907
- leaves = await this.checkExtendTimeLockNodes(leaves);
34136
+ leaves = await this.checkRenewLeaves(leaves);
33908
34137
  const leavesToSend = await Promise.all(
33909
34138
  leaves.map(async (leaf) => ({
33910
34139
  leaf,
@@ -34235,10 +34464,8 @@ var SparkWallet = class extends import_eventemitter3.EventEmitter {
34235
34464
  leavesToSendToSsp = leavesForTargetAmount;
34236
34465
  leavesToSendToSE = leavesForFee;
34237
34466
  }
34238
- leavesToSendToSsp = await this.checkRefreshTimelockNodes(leavesToSendToSsp);
34239
- leavesToSendToSsp = await this.checkExtendTimeLockNodes(leavesToSendToSsp);
34240
- leavesToSendToSE = await this.checkRefreshTimelockNodes(leavesToSendToSE);
34241
- leavesToSendToSE = await this.checkExtendTimeLockNodes(leavesToSendToSE);
34467
+ leavesToSendToSsp = await this.checkRenewLeaves(leavesToSendToSsp);
34468
+ leavesToSendToSE = await this.checkRenewLeaves(leavesToSendToSE);
34242
34469
  const leafKeyTweaks = await Promise.all(
34243
34470
  [...leavesToSendToSE, ...leavesToSendToSsp].map(async (leaf) => ({
34244
34471
  leaf,
@@ -34324,8 +34551,7 @@ var SparkWallet = class extends import_eventemitter3.EventEmitter {
34324
34551
  (await this.selectLeaves([amountSats])).get(amountSats),
34325
34552
  `no leaves for ${amountSats}`
34326
34553
  );
34327
- leaves = await this.checkRefreshTimelockNodes(leaves);
34328
- leaves = await this.checkExtendTimeLockNodes(leaves);
34554
+ leaves = await this.checkRenewLeaves(leaves);
34329
34555
  const feeEstimate = await sspClient.getCoopExitFeeQuote({
34330
34556
  leafExternalIds: leaves.map((leaf) => leaf.id),
34331
34557
  withdrawalAddress
@@ -34613,7 +34839,7 @@ var SparkWallet = class extends import_eventemitter3.EventEmitter {
34613
34839
  */
34614
34840
  async signTransaction(txHex, keyType = "auto-detect") {
34615
34841
  try {
34616
- const tx = import_btc_signer7.Transaction.fromRaw((0, import_utils25.hexToBytes)(txHex));
34842
+ const tx = import_btc_signer5.Transaction.fromRaw((0, import_utils25.hexToBytes)(txHex));
34617
34843
  let publicKey;
34618
34844
  switch (keyType.toLowerCase()) {
34619
34845
  case "identity":
@@ -34820,15 +35046,6 @@ var SparkWallet = class extends import_eventemitter3.EventEmitter {
34820
35046
  }
34821
35047
  );
34822
35048
  }
34823
- if (!nodeInput.sequence) {
34824
- throw new ValidationError(
34825
- `Node transaction has no sequence for ${isRootNode ? "root" : "non-root"} node`,
34826
- {
34827
- field: "sequence",
34828
- value: nodeInput.sequence
34829
- }
34830
- );
34831
- }
34832
35049
  const refundInput = refundTx.getInput(0);
34833
35050
  if (!refundInput) {
34834
35051
  throw new ValidationError(
@@ -34864,89 +35081,6 @@ var SparkWallet = class extends import_eventemitter3.EventEmitter {
34864
35081
  );
34865
35082
  }
34866
35083
  }
34867
- /**
34868
- * Refresh the timelock of a specific node.
34869
- *
34870
- * @param {string} nodeId - The ID of the node to refresh
34871
- * @returns {Promise<void>} Promise that resolves when the timelock is refreshed
34872
- */
34873
- async testOnly_expireTimelock(nodeId) {
34874
- const sparkClient = await this.connectionManager.createSparkClient(
34875
- this.config.getCoordinatorAddress()
34876
- );
34877
- try {
34878
- const response = await sparkClient.query_nodes({
34879
- source: {
34880
- $case: "nodeIds",
34881
- nodeIds: {
34882
- nodeIds: [nodeId]
34883
- }
34884
- },
34885
- includeParents: true
34886
- });
34887
- let leaf = response.nodes[nodeId];
34888
- if (!leaf) {
34889
- throw new ValidationError("Node not found", {
34890
- field: "nodeId",
34891
- value: nodeId
34892
- });
34893
- }
34894
- let parentNode;
34895
- let hasParentNode = false;
34896
- if (!leaf.parentNodeId) {
34897
- } else {
34898
- hasParentNode = true;
34899
- parentNode = response.nodes[leaf.parentNodeId];
34900
- if (!parentNode) {
34901
- throw new ValidationError("Parent node not found", {
34902
- field: "parentNodeId",
34903
- value: leaf.parentNodeId
34904
- });
34905
- }
34906
- }
34907
- const nodeTx = getTxFromRawTxBytes(leaf.nodeTx);
34908
- const refundTx = getTxFromRawTxBytes(leaf.refundTx);
34909
- if (hasParentNode) {
34910
- const nodeTimelock = getCurrentTimelock(nodeTx.getInput(0).sequence);
34911
- if (nodeTimelock > 100) {
34912
- const expiredNodeTxLeaf = await this.transferService.testonly_expireTimeLockNodeTx(
34913
- leaf,
34914
- parentNode
34915
- );
34916
- if (!expiredNodeTxLeaf.nodes[0]) {
34917
- throw new ValidationError("No expired node tx leaf", {
34918
- field: "expiredNodeTxLeaf",
34919
- value: expiredNodeTxLeaf
34920
- });
34921
- }
34922
- leaf = expiredNodeTxLeaf.nodes[0];
34923
- }
34924
- }
34925
- const refundTimelock = getCurrentTimelock(refundTx.getInput(0).sequence);
34926
- if (refundTimelock > 100) {
34927
- const expiredTxLeaf = await this.transferService.testonly_expireTimeLockRefundtx(leaf);
34928
- if (!expiredTxLeaf.nodes[0]) {
34929
- throw new ValidationError("No expired tx leaf", {
34930
- field: "expiredTxLeaf",
34931
- value: expiredTxLeaf
34932
- });
34933
- }
34934
- leaf = expiredTxLeaf.nodes[0];
34935
- }
34936
- const leafIndex = this.leaves.findIndex((leaf2) => leaf2.id === leaf2.id);
34937
- if (leafIndex !== -1) {
34938
- this.leaves[leafIndex] = leaf;
34939
- }
34940
- } catch (error) {
34941
- throw new NetworkError(
34942
- "Failed to refresh timelock",
34943
- {
34944
- method: "refresh_timelock"
34945
- },
34946
- error
34947
- );
34948
- }
34949
- }
34950
35084
  cleanup() {
34951
35085
  if (this.claimTransfersInterval) {
34952
35086
  clearInterval(this.claimTransfersInterval);
@@ -35101,8 +35235,7 @@ var SparkWallet = class extends import_eventemitter3.EventEmitter {
35101
35235
  "getLightningReceiveRequest",
35102
35236
  "getLightningSendRequest",
35103
35237
  "getCoopExitRequest",
35104
- "checkTimelock",
35105
- "testOnly_expireTimelock"
35238
+ "checkTimelock"
35106
35239
  ];
35107
35240
  methods.forEach((m) => this.wrapPublicSparkWalletMethodWithOtelSpan(m));
35108
35241
  this.initWallet = this.wrapWithOtelSpan(
@@ -36070,7 +36203,6 @@ setCrypto(globalThis.crypto);
36070
36203
  DIRECT_TIMELOCK_OFFSET,
36071
36204
  DefaultSparkSigner,
36072
36205
  HTLC_TIMELOCK_OFFSET,
36073
- INITIAL_DIRECT_SEQUENCE,
36074
36206
  INITIAL_SEQUENCE,
36075
36207
  InternalValidationError,
36076
36208
  LOGGER_NAMES,
@@ -36080,12 +36212,14 @@ setCrypto(globalThis.crypto);
36080
36212
  NotImplementedError,
36081
36213
  RPCError,
36082
36214
  ReactNativeSparkSigner,
36215
+ ReactNativeTaprootSparkSigner,
36083
36216
  SparkSDKError,
36084
36217
  SparkSdkLogger,
36085
36218
  SparkWallet,
36086
36219
  SparkWalletEvent,
36087
36220
  TEST_UNILATERAL_DIRECT_SEQUENCE,
36088
36221
  TEST_UNILATERAL_SEQUENCE,
36222
+ TaprootSparkSigner,
36089
36223
  TokenTransactionService,
36090
36224
  ValidationError,
36091
36225
  WalletConfig,
@@ -36104,21 +36238,24 @@ setCrypto(globalThis.crypto);
36104
36238
  constructFeeBumpTx,
36105
36239
  constructUnilateralExitFeeBumpPackages,
36106
36240
  constructUnilateralExitTxs,
36107
- createConnectorRefundTransactions,
36108
- createLeafNodeTx,
36109
- createNodeTx,
36110
- createNodeTxs,
36111
- createRefundTx,
36112
- createRefundTxs,
36113
- createRootTx,
36241
+ createConnectorRefundTxs,
36242
+ createCurrentTimelockRefundTxs,
36243
+ createDecrementedTimelockNodeTx,
36244
+ createDecrementedTimelockRefundTxs,
36245
+ createInitialTimelockNodeTx,
36246
+ createInitialTimelockRefundTxs,
36247
+ createRootNodeTx,
36114
36248
  createSigningCommitment,
36115
36249
  createSigningNonce,
36116
- createSplitTx,
36250
+ createTestUnilateralRefundTxs,
36251
+ createTestUnilateralTimelockNodeTx,
36252
+ createZeroTimelockNodeTx,
36117
36253
  decodeBech32mTokenIdentifier,
36118
36254
  decodeBytesToSigningCommitment,
36119
36255
  decodeBytesToSigningNonce,
36120
36256
  decodeSparkAddress,
36121
36257
  doesLeafNeedRefresh,
36258
+ doesTxnNeedRenewed,
36122
36259
  encodeBech32mTokenIdentifier,
36123
36260
  encodeSigningCommitmentToBytes,
36124
36261
  encodeSigningNonceToBytes,
@@ -36156,12 +36293,14 @@ setCrypto(globalThis.crypto);
36156
36293
  getTxFromRawTxHex,
36157
36294
  getTxId,
36158
36295
  getTxIdNoReverse,
36296
+ hash160,
36159
36297
  isEphemeralAnchorOutput,
36160
36298
  isLegacySparkAddress,
36161
36299
  isSafeForNumber,
36162
36300
  isTxBroadcast,
36163
36301
  isValidPublicKey,
36164
36302
  isValidSparkAddress,
36303
+ isZeroTimelock,
36165
36304
  lastKeyWithTarget,
36166
36305
  maybeApplyFee,
36167
36306
  modInverse,