@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.
- package/CHANGELOG.md +18 -0
- package/android/build.gradle +1 -1
- package/android/src/main/java/uniffi/uniffi/spark_frost/spark_frost.kt +1361 -1367
- package/android/src/main/jniLibs/arm64-v8a/libuniffi_spark_frost.so +0 -0
- package/android/src/main/jniLibs/armeabi-v7a/libuniffi_spark_frost.so +0 -0
- package/android/src/main/jniLibs/x86/libuniffi_spark_frost.so +0 -0
- package/android/src/main/jniLibs/x86_64/libuniffi_spark_frost.so +0 -0
- package/dist/bare/index.cjs +1342 -1346
- package/dist/bare/index.d.cts +114 -68
- package/dist/bare/index.d.ts +114 -68
- package/dist/bare/index.js +1266 -1279
- package/dist/{chunk-FXIESWE6.js → chunk-27ILUWDJ.js} +1 -1
- package/dist/{chunk-5ASXVNTM.js → chunk-4YFT7DAE.js} +1 -1
- package/dist/{chunk-FP2CRVQH.js → chunk-G3LHXHF3.js} +1045 -1308
- package/dist/{chunk-XI6FCNYG.js → chunk-JLF6WJ7K.js} +1 -1
- package/dist/{chunk-3LPEQGVJ.js → chunk-LOXWCMZL.js} +1 -1
- package/dist/{chunk-5HU5W56H.js → chunk-WICAF6BS.js} +2 -2
- package/dist/{chunk-VFN34EOX.js → chunk-YEBEN7XD.js} +258 -0
- package/dist/{client-pNpGP15j.d.cts → client-BIqiUNy4.d.cts} +1 -1
- package/dist/{client-By-N7oJS.d.ts → client-BaQf-5gD.d.ts} +1 -1
- package/dist/debug.cjs +1330 -1336
- package/dist/debug.d.cts +20 -16
- package/dist/debug.d.ts +20 -16
- package/dist/debug.js +5 -5
- package/dist/graphql/objects/index.d.cts +3 -3
- package/dist/graphql/objects/index.d.ts +3 -3
- package/dist/index.cjs +1363 -1365
- package/dist/index.d.cts +7 -7
- package/dist/index.d.ts +7 -7
- package/dist/index.js +32 -24
- package/dist/index.node.cjs +1363 -1365
- package/dist/index.node.d.cts +7 -7
- package/dist/index.node.d.ts +7 -7
- package/dist/index.node.js +31 -23
- package/dist/{logging-DMFVY384.d.ts → logging-BNGm6dBp.d.ts} +42 -37
- package/dist/{logging-DxLp34Xm.d.cts → logging-D3IfXfHG.d.cts} +42 -37
- package/dist/native/index.react-native.cjs +1505 -1366
- package/dist/native/index.react-native.d.cts +112 -58
- package/dist/native/index.react-native.d.ts +112 -58
- package/dist/native/index.react-native.js +1415 -1289
- package/dist/proto/spark.cjs +258 -0
- package/dist/proto/spark.d.cts +1 -1
- package/dist/proto/spark.d.ts +1 -1
- package/dist/proto/spark.js +5 -1
- package/dist/proto/spark_token.d.cts +1 -1
- package/dist/proto/spark_token.d.ts +1 -1
- package/dist/proto/spark_token.js +2 -2
- package/dist/{spark-By6yHsrk.d.cts → spark-DOpheE8_.d.cts} +39 -2
- package/dist/{spark-By6yHsrk.d.ts → spark-DOpheE8_.d.ts} +39 -2
- package/dist/{spark-wallet.browser-C1dQknVj.d.ts → spark-wallet.browser-B2rGwjuM.d.ts} +2 -2
- package/dist/{spark-wallet.browser-CNMo3IvO.d.cts → spark-wallet.browser-Ck9No4Ks.d.cts} +2 -2
- package/dist/{spark-wallet.node-Og6__NMh.d.ts → spark-wallet.node-BqmKsGPs.d.ts} +2 -2
- package/dist/{spark-wallet.node-BZJhJZKq.d.cts → spark-wallet.node-C2TIkyt4.d.cts} +2 -2
- package/dist/tests/test-utils.cjs +1304 -1236
- package/dist/tests/test-utils.d.cts +18 -4
- package/dist/tests/test-utils.d.ts +18 -4
- package/dist/tests/test-utils.js +7 -7
- package/dist/{token-transactions-CLR3rnYi.d.cts → token-transactions-Db8mkjnU.d.cts} +2 -2
- package/dist/{token-transactions-C7yefB2S.d.ts → token-transactions-DoMcrxXQ.d.ts} +2 -2
- package/dist/types/index.cjs +256 -0
- package/dist/types/index.d.cts +2 -2
- package/dist/types/index.d.ts +2 -2
- package/dist/types/index.js +2 -2
- package/dist/{wallet-config-BoyMVa6n.d.ts → wallet-config-Bg3kWltL.d.ts} +42 -35
- package/dist/{wallet-config-xom-9UFF.d.cts → wallet-config-CuZKNo9S.d.cts} +42 -35
- package/ios/spark_frostFFI.xcframework/ios-arm64/SparkFrost +0 -0
- package/ios/spark_frostFFI.xcframework/ios-arm64/spark_frostFFI.framework/spark_frostFFI +0 -0
- package/ios/spark_frostFFI.xcframework/ios-arm64_x86_64-simulator/SparkFrost +0 -0
- package/ios/spark_frostFFI.xcframework/ios-arm64_x86_64-simulator/spark_frostFFI.framework/spark_frostFFI +0 -0
- package/ios/spark_frostFFI.xcframework/macos-arm64_x86_64/spark_frostFFI.framework/spark_frostFFI +0 -0
- package/package.json +1 -1
- package/src/index.react-native.ts +8 -2
- package/src/proto/spark.ts +348 -4
- package/src/services/config.ts +5 -0
- package/src/services/coop-exit.ts +26 -107
- package/src/services/deposit.ts +12 -48
- package/src/services/signing.ts +62 -49
- package/src/services/transfer.ts +437 -722
- package/src/services/wallet-config.ts +10 -0
- package/src/services/xhr-transport.ts +13 -3
- package/src/signer/signer.react-native.ts +73 -1
- package/src/spark-wallet/proto-descriptors.ts +1 -1
- package/src/spark-wallet/spark-wallet.ts +162 -315
- package/src/spark-wallet/types.ts +2 -2
- package/src/spark_descriptors.pb +0 -0
- package/src/tests/integration/lightning.test.ts +1 -27
- package/src/tests/integration/static_deposit.test.ts +6 -9
- package/src/tests/integration/unilateral-exit.test.ts +117 -0
- package/src/tests/optimize.test.ts +31 -1
- package/src/tests/utils/signing.ts +33 -0
- package/src/tests/utils/test-faucet.ts +61 -0
- package/src/utils/optimize.ts +42 -0
- package/src/utils/transaction.ts +250 -249
- package/src/utils/unilateral-exit.ts +1 -40
package/dist/bare/index.js
CHANGED
|
@@ -170,11 +170,11 @@ import {
|
|
|
170
170
|
bytesToHex as bytesToHex11,
|
|
171
171
|
bytesToNumberBE as bytesToNumberBE8,
|
|
172
172
|
equalBytes as equalBytes6,
|
|
173
|
-
hexToBytes as
|
|
173
|
+
hexToBytes as hexToBytes11
|
|
174
174
|
} from "@noble/curves/utils";
|
|
175
175
|
import { validateMnemonic } from "@scure/bip39";
|
|
176
176
|
import { wordlist as wordlist2 } from "@scure/bip39/wordlists/english";
|
|
177
|
-
import { Address as Address4, OutScript as OutScript3, Transaction as
|
|
177
|
+
import { Address as Address4, OutScript as OutScript3, Transaction as Transaction6 } from "@scure/btc-signer";
|
|
178
178
|
import { Mutex } from "async-mutex";
|
|
179
179
|
import { uuidv7 as uuidv74 } from "uuidv7";
|
|
180
180
|
|
|
@@ -4627,6 +4627,12 @@ var RenewLeafRequest = {
|
|
|
4627
4627
|
writer.uint32(26).fork()
|
|
4628
4628
|
).join();
|
|
4629
4629
|
break;
|
|
4630
|
+
case "renewNodeZeroTimelockSigningJob":
|
|
4631
|
+
RenewNodeZeroTimelockSigningJob.encode(
|
|
4632
|
+
message.signingJobs.renewNodeZeroTimelockSigningJob,
|
|
4633
|
+
writer.uint32(34).fork()
|
|
4634
|
+
).join();
|
|
4635
|
+
break;
|
|
4630
4636
|
}
|
|
4631
4637
|
return writer;
|
|
4632
4638
|
},
|
|
@@ -4664,6 +4670,16 @@ var RenewLeafRequest = {
|
|
|
4664
4670
|
};
|
|
4665
4671
|
continue;
|
|
4666
4672
|
}
|
|
4673
|
+
case 4: {
|
|
4674
|
+
if (tag !== 34) {
|
|
4675
|
+
break;
|
|
4676
|
+
}
|
|
4677
|
+
message.signingJobs = {
|
|
4678
|
+
$case: "renewNodeZeroTimelockSigningJob",
|
|
4679
|
+
renewNodeZeroTimelockSigningJob: RenewNodeZeroTimelockSigningJob.decode(reader, reader.uint32())
|
|
4680
|
+
};
|
|
4681
|
+
continue;
|
|
4682
|
+
}
|
|
4667
4683
|
}
|
|
4668
4684
|
if ((tag & 7) === 4 || tag === 0) {
|
|
4669
4685
|
break;
|
|
@@ -4681,6 +4697,11 @@ var RenewLeafRequest = {
|
|
|
4681
4697
|
} : isSet3(object.renewRefundTimelockSigningJob) ? {
|
|
4682
4698
|
$case: "renewRefundTimelockSigningJob",
|
|
4683
4699
|
renewRefundTimelockSigningJob: RenewRefundTimelockSigningJob.fromJSON(object.renewRefundTimelockSigningJob)
|
|
4700
|
+
} : isSet3(object.renewNodeZeroTimelockSigningJob) ? {
|
|
4701
|
+
$case: "renewNodeZeroTimelockSigningJob",
|
|
4702
|
+
renewNodeZeroTimelockSigningJob: RenewNodeZeroTimelockSigningJob.fromJSON(
|
|
4703
|
+
object.renewNodeZeroTimelockSigningJob
|
|
4704
|
+
)
|
|
4684
4705
|
} : void 0
|
|
4685
4706
|
};
|
|
4686
4707
|
},
|
|
@@ -4697,6 +4718,10 @@ var RenewLeafRequest = {
|
|
|
4697
4718
|
obj.renewRefundTimelockSigningJob = RenewRefundTimelockSigningJob.toJSON(
|
|
4698
4719
|
message.signingJobs.renewRefundTimelockSigningJob
|
|
4699
4720
|
);
|
|
4721
|
+
} else if (message.signingJobs?.$case === "renewNodeZeroTimelockSigningJob") {
|
|
4722
|
+
obj.renewNodeZeroTimelockSigningJob = RenewNodeZeroTimelockSigningJob.toJSON(
|
|
4723
|
+
message.signingJobs.renewNodeZeroTimelockSigningJob
|
|
4724
|
+
);
|
|
4700
4725
|
}
|
|
4701
4726
|
return obj;
|
|
4702
4727
|
},
|
|
@@ -4729,6 +4754,17 @@ var RenewLeafRequest = {
|
|
|
4729
4754
|
}
|
|
4730
4755
|
break;
|
|
4731
4756
|
}
|
|
4757
|
+
case "renewNodeZeroTimelockSigningJob": {
|
|
4758
|
+
if (object.signingJobs?.renewNodeZeroTimelockSigningJob !== void 0 && object.signingJobs?.renewNodeZeroTimelockSigningJob !== null) {
|
|
4759
|
+
message.signingJobs = {
|
|
4760
|
+
$case: "renewNodeZeroTimelockSigningJob",
|
|
4761
|
+
renewNodeZeroTimelockSigningJob: RenewNodeZeroTimelockSigningJob.fromPartial(
|
|
4762
|
+
object.signingJobs.renewNodeZeroTimelockSigningJob
|
|
4763
|
+
)
|
|
4764
|
+
};
|
|
4765
|
+
}
|
|
4766
|
+
break;
|
|
4767
|
+
}
|
|
4732
4768
|
}
|
|
4733
4769
|
return message;
|
|
4734
4770
|
}
|
|
@@ -5003,6 +5039,125 @@ var RenewRefundTimelockSigningJob = {
|
|
|
5003
5039
|
return message;
|
|
5004
5040
|
}
|
|
5005
5041
|
};
|
|
5042
|
+
function createBaseRenewNodeZeroTimelockSigningJob() {
|
|
5043
|
+
return {
|
|
5044
|
+
nodeTxSigningJob: void 0,
|
|
5045
|
+
refundTxSigningJob: void 0,
|
|
5046
|
+
directNodeTxSigningJob: void 0,
|
|
5047
|
+
directRefundTxSigningJob: void 0,
|
|
5048
|
+
directFromCpfpRefundTxSigningJob: void 0
|
|
5049
|
+
};
|
|
5050
|
+
}
|
|
5051
|
+
var RenewNodeZeroTimelockSigningJob = {
|
|
5052
|
+
encode(message, writer = new BinaryWriter4()) {
|
|
5053
|
+
if (message.nodeTxSigningJob !== void 0) {
|
|
5054
|
+
UserSignedTxSigningJob.encode(message.nodeTxSigningJob, writer.uint32(10).fork()).join();
|
|
5055
|
+
}
|
|
5056
|
+
if (message.refundTxSigningJob !== void 0) {
|
|
5057
|
+
UserSignedTxSigningJob.encode(message.refundTxSigningJob, writer.uint32(18).fork()).join();
|
|
5058
|
+
}
|
|
5059
|
+
if (message.directNodeTxSigningJob !== void 0) {
|
|
5060
|
+
UserSignedTxSigningJob.encode(message.directNodeTxSigningJob, writer.uint32(26).fork()).join();
|
|
5061
|
+
}
|
|
5062
|
+
if (message.directRefundTxSigningJob !== void 0) {
|
|
5063
|
+
UserSignedTxSigningJob.encode(message.directRefundTxSigningJob, writer.uint32(34).fork()).join();
|
|
5064
|
+
}
|
|
5065
|
+
if (message.directFromCpfpRefundTxSigningJob !== void 0) {
|
|
5066
|
+
UserSignedTxSigningJob.encode(message.directFromCpfpRefundTxSigningJob, writer.uint32(42).fork()).join();
|
|
5067
|
+
}
|
|
5068
|
+
return writer;
|
|
5069
|
+
},
|
|
5070
|
+
decode(input, length) {
|
|
5071
|
+
const reader = input instanceof BinaryReader4 ? input : new BinaryReader4(input);
|
|
5072
|
+
const end = length === void 0 ? reader.len : reader.pos + length;
|
|
5073
|
+
const message = createBaseRenewNodeZeroTimelockSigningJob();
|
|
5074
|
+
while (reader.pos < end) {
|
|
5075
|
+
const tag = reader.uint32();
|
|
5076
|
+
switch (tag >>> 3) {
|
|
5077
|
+
case 1: {
|
|
5078
|
+
if (tag !== 10) {
|
|
5079
|
+
break;
|
|
5080
|
+
}
|
|
5081
|
+
message.nodeTxSigningJob = UserSignedTxSigningJob.decode(reader, reader.uint32());
|
|
5082
|
+
continue;
|
|
5083
|
+
}
|
|
5084
|
+
case 2: {
|
|
5085
|
+
if (tag !== 18) {
|
|
5086
|
+
break;
|
|
5087
|
+
}
|
|
5088
|
+
message.refundTxSigningJob = UserSignedTxSigningJob.decode(reader, reader.uint32());
|
|
5089
|
+
continue;
|
|
5090
|
+
}
|
|
5091
|
+
case 3: {
|
|
5092
|
+
if (tag !== 26) {
|
|
5093
|
+
break;
|
|
5094
|
+
}
|
|
5095
|
+
message.directNodeTxSigningJob = UserSignedTxSigningJob.decode(reader, reader.uint32());
|
|
5096
|
+
continue;
|
|
5097
|
+
}
|
|
5098
|
+
case 4: {
|
|
5099
|
+
if (tag !== 34) {
|
|
5100
|
+
break;
|
|
5101
|
+
}
|
|
5102
|
+
message.directRefundTxSigningJob = UserSignedTxSigningJob.decode(reader, reader.uint32());
|
|
5103
|
+
continue;
|
|
5104
|
+
}
|
|
5105
|
+
case 5: {
|
|
5106
|
+
if (tag !== 42) {
|
|
5107
|
+
break;
|
|
5108
|
+
}
|
|
5109
|
+
message.directFromCpfpRefundTxSigningJob = UserSignedTxSigningJob.decode(reader, reader.uint32());
|
|
5110
|
+
continue;
|
|
5111
|
+
}
|
|
5112
|
+
}
|
|
5113
|
+
if ((tag & 7) === 4 || tag === 0) {
|
|
5114
|
+
break;
|
|
5115
|
+
}
|
|
5116
|
+
reader.skip(tag & 7);
|
|
5117
|
+
}
|
|
5118
|
+
return message;
|
|
5119
|
+
},
|
|
5120
|
+
fromJSON(object) {
|
|
5121
|
+
return {
|
|
5122
|
+
nodeTxSigningJob: isSet3(object.nodeTxSigningJob) ? UserSignedTxSigningJob.fromJSON(object.nodeTxSigningJob) : void 0,
|
|
5123
|
+
refundTxSigningJob: isSet3(object.refundTxSigningJob) ? UserSignedTxSigningJob.fromJSON(object.refundTxSigningJob) : void 0,
|
|
5124
|
+
directNodeTxSigningJob: isSet3(object.directNodeTxSigningJob) ? UserSignedTxSigningJob.fromJSON(object.directNodeTxSigningJob) : void 0,
|
|
5125
|
+
directRefundTxSigningJob: isSet3(object.directRefundTxSigningJob) ? UserSignedTxSigningJob.fromJSON(object.directRefundTxSigningJob) : void 0,
|
|
5126
|
+
directFromCpfpRefundTxSigningJob: isSet3(object.directFromCpfpRefundTxSigningJob) ? UserSignedTxSigningJob.fromJSON(object.directFromCpfpRefundTxSigningJob) : void 0
|
|
5127
|
+
};
|
|
5128
|
+
},
|
|
5129
|
+
toJSON(message) {
|
|
5130
|
+
const obj = {};
|
|
5131
|
+
if (message.nodeTxSigningJob !== void 0) {
|
|
5132
|
+
obj.nodeTxSigningJob = UserSignedTxSigningJob.toJSON(message.nodeTxSigningJob);
|
|
5133
|
+
}
|
|
5134
|
+
if (message.refundTxSigningJob !== void 0) {
|
|
5135
|
+
obj.refundTxSigningJob = UserSignedTxSigningJob.toJSON(message.refundTxSigningJob);
|
|
5136
|
+
}
|
|
5137
|
+
if (message.directNodeTxSigningJob !== void 0) {
|
|
5138
|
+
obj.directNodeTxSigningJob = UserSignedTxSigningJob.toJSON(message.directNodeTxSigningJob);
|
|
5139
|
+
}
|
|
5140
|
+
if (message.directRefundTxSigningJob !== void 0) {
|
|
5141
|
+
obj.directRefundTxSigningJob = UserSignedTxSigningJob.toJSON(message.directRefundTxSigningJob);
|
|
5142
|
+
}
|
|
5143
|
+
if (message.directFromCpfpRefundTxSigningJob !== void 0) {
|
|
5144
|
+
obj.directFromCpfpRefundTxSigningJob = UserSignedTxSigningJob.toJSON(message.directFromCpfpRefundTxSigningJob);
|
|
5145
|
+
}
|
|
5146
|
+
return obj;
|
|
5147
|
+
},
|
|
5148
|
+
create(base) {
|
|
5149
|
+
return RenewNodeZeroTimelockSigningJob.fromPartial(base ?? {});
|
|
5150
|
+
},
|
|
5151
|
+
fromPartial(object) {
|
|
5152
|
+
const message = createBaseRenewNodeZeroTimelockSigningJob();
|
|
5153
|
+
message.nodeTxSigningJob = object.nodeTxSigningJob !== void 0 && object.nodeTxSigningJob !== null ? UserSignedTxSigningJob.fromPartial(object.nodeTxSigningJob) : void 0;
|
|
5154
|
+
message.refundTxSigningJob = object.refundTxSigningJob !== void 0 && object.refundTxSigningJob !== null ? UserSignedTxSigningJob.fromPartial(object.refundTxSigningJob) : void 0;
|
|
5155
|
+
message.directNodeTxSigningJob = object.directNodeTxSigningJob !== void 0 && object.directNodeTxSigningJob !== null ? UserSignedTxSigningJob.fromPartial(object.directNodeTxSigningJob) : void 0;
|
|
5156
|
+
message.directRefundTxSigningJob = object.directRefundTxSigningJob !== void 0 && object.directRefundTxSigningJob !== null ? UserSignedTxSigningJob.fromPartial(object.directRefundTxSigningJob) : void 0;
|
|
5157
|
+
message.directFromCpfpRefundTxSigningJob = object.directFromCpfpRefundTxSigningJob !== void 0 && object.directFromCpfpRefundTxSigningJob !== null ? UserSignedTxSigningJob.fromPartial(object.directFromCpfpRefundTxSigningJob) : void 0;
|
|
5158
|
+
return message;
|
|
5159
|
+
}
|
|
5160
|
+
};
|
|
5006
5161
|
function createBaseRenewLeafResponse() {
|
|
5007
5162
|
return { renewResult: void 0 };
|
|
5008
5163
|
}
|
|
@@ -5015,6 +5170,9 @@ var RenewLeafResponse = {
|
|
|
5015
5170
|
case "renewRefundTimelockResult":
|
|
5016
5171
|
RenewRefundTimelockResult.encode(message.renewResult.renewRefundTimelockResult, writer.uint32(18).fork()).join();
|
|
5017
5172
|
break;
|
|
5173
|
+
case "renewNodeZeroTimelockResult":
|
|
5174
|
+
RenewNodeZeroTimelockResult.encode(message.renewResult.renewNodeZeroTimelockResult, writer.uint32(26).fork()).join();
|
|
5175
|
+
break;
|
|
5018
5176
|
}
|
|
5019
5177
|
return writer;
|
|
5020
5178
|
},
|
|
@@ -5045,6 +5203,16 @@ var RenewLeafResponse = {
|
|
|
5045
5203
|
};
|
|
5046
5204
|
continue;
|
|
5047
5205
|
}
|
|
5206
|
+
case 3: {
|
|
5207
|
+
if (tag !== 26) {
|
|
5208
|
+
break;
|
|
5209
|
+
}
|
|
5210
|
+
message.renewResult = {
|
|
5211
|
+
$case: "renewNodeZeroTimelockResult",
|
|
5212
|
+
renewNodeZeroTimelockResult: RenewNodeZeroTimelockResult.decode(reader, reader.uint32())
|
|
5213
|
+
};
|
|
5214
|
+
continue;
|
|
5215
|
+
}
|
|
5048
5216
|
}
|
|
5049
5217
|
if ((tag & 7) === 4 || tag === 0) {
|
|
5050
5218
|
break;
|
|
@@ -5061,6 +5229,9 @@ var RenewLeafResponse = {
|
|
|
5061
5229
|
} : isSet3(object.renewRefundTimelockResult) ? {
|
|
5062
5230
|
$case: "renewRefundTimelockResult",
|
|
5063
5231
|
renewRefundTimelockResult: RenewRefundTimelockResult.fromJSON(object.renewRefundTimelockResult)
|
|
5232
|
+
} : isSet3(object.renewNodeZeroTimelockResult) ? {
|
|
5233
|
+
$case: "renewNodeZeroTimelockResult",
|
|
5234
|
+
renewNodeZeroTimelockResult: RenewNodeZeroTimelockResult.fromJSON(object.renewNodeZeroTimelockResult)
|
|
5064
5235
|
} : void 0
|
|
5065
5236
|
};
|
|
5066
5237
|
},
|
|
@@ -5070,6 +5241,10 @@ var RenewLeafResponse = {
|
|
|
5070
5241
|
obj.renewNodeTimelockResult = RenewNodeTimelockResult.toJSON(message.renewResult.renewNodeTimelockResult);
|
|
5071
5242
|
} else if (message.renewResult?.$case === "renewRefundTimelockResult") {
|
|
5072
5243
|
obj.renewRefundTimelockResult = RenewRefundTimelockResult.toJSON(message.renewResult.renewRefundTimelockResult);
|
|
5244
|
+
} else if (message.renewResult?.$case === "renewNodeZeroTimelockResult") {
|
|
5245
|
+
obj.renewNodeZeroTimelockResult = RenewNodeZeroTimelockResult.toJSON(
|
|
5246
|
+
message.renewResult.renewNodeZeroTimelockResult
|
|
5247
|
+
);
|
|
5073
5248
|
}
|
|
5074
5249
|
return obj;
|
|
5075
5250
|
},
|
|
@@ -5099,6 +5274,17 @@ var RenewLeafResponse = {
|
|
|
5099
5274
|
}
|
|
5100
5275
|
break;
|
|
5101
5276
|
}
|
|
5277
|
+
case "renewNodeZeroTimelockResult": {
|
|
5278
|
+
if (object.renewResult?.renewNodeZeroTimelockResult !== void 0 && object.renewResult?.renewNodeZeroTimelockResult !== null) {
|
|
5279
|
+
message.renewResult = {
|
|
5280
|
+
$case: "renewNodeZeroTimelockResult",
|
|
5281
|
+
renewNodeZeroTimelockResult: RenewNodeZeroTimelockResult.fromPartial(
|
|
5282
|
+
object.renewResult.renewNodeZeroTimelockResult
|
|
5283
|
+
)
|
|
5284
|
+
};
|
|
5285
|
+
}
|
|
5286
|
+
break;
|
|
5287
|
+
}
|
|
5102
5288
|
}
|
|
5103
5289
|
return message;
|
|
5104
5290
|
}
|
|
@@ -5222,6 +5408,74 @@ var RenewRefundTimelockResult = {
|
|
|
5222
5408
|
return message;
|
|
5223
5409
|
}
|
|
5224
5410
|
};
|
|
5411
|
+
function createBaseRenewNodeZeroTimelockResult() {
|
|
5412
|
+
return { splitNode: void 0, node: void 0 };
|
|
5413
|
+
}
|
|
5414
|
+
var RenewNodeZeroTimelockResult = {
|
|
5415
|
+
encode(message, writer = new BinaryWriter4()) {
|
|
5416
|
+
if (message.splitNode !== void 0) {
|
|
5417
|
+
TreeNode.encode(message.splitNode, writer.uint32(10).fork()).join();
|
|
5418
|
+
}
|
|
5419
|
+
if (message.node !== void 0) {
|
|
5420
|
+
TreeNode.encode(message.node, writer.uint32(18).fork()).join();
|
|
5421
|
+
}
|
|
5422
|
+
return writer;
|
|
5423
|
+
},
|
|
5424
|
+
decode(input, length) {
|
|
5425
|
+
const reader = input instanceof BinaryReader4 ? input : new BinaryReader4(input);
|
|
5426
|
+
const end = length === void 0 ? reader.len : reader.pos + length;
|
|
5427
|
+
const message = createBaseRenewNodeZeroTimelockResult();
|
|
5428
|
+
while (reader.pos < end) {
|
|
5429
|
+
const tag = reader.uint32();
|
|
5430
|
+
switch (tag >>> 3) {
|
|
5431
|
+
case 1: {
|
|
5432
|
+
if (tag !== 10) {
|
|
5433
|
+
break;
|
|
5434
|
+
}
|
|
5435
|
+
message.splitNode = TreeNode.decode(reader, reader.uint32());
|
|
5436
|
+
continue;
|
|
5437
|
+
}
|
|
5438
|
+
case 2: {
|
|
5439
|
+
if (tag !== 18) {
|
|
5440
|
+
break;
|
|
5441
|
+
}
|
|
5442
|
+
message.node = TreeNode.decode(reader, reader.uint32());
|
|
5443
|
+
continue;
|
|
5444
|
+
}
|
|
5445
|
+
}
|
|
5446
|
+
if ((tag & 7) === 4 || tag === 0) {
|
|
5447
|
+
break;
|
|
5448
|
+
}
|
|
5449
|
+
reader.skip(tag & 7);
|
|
5450
|
+
}
|
|
5451
|
+
return message;
|
|
5452
|
+
},
|
|
5453
|
+
fromJSON(object) {
|
|
5454
|
+
return {
|
|
5455
|
+
splitNode: isSet3(object.splitNode) ? TreeNode.fromJSON(object.splitNode) : void 0,
|
|
5456
|
+
node: isSet3(object.node) ? TreeNode.fromJSON(object.node) : void 0
|
|
5457
|
+
};
|
|
5458
|
+
},
|
|
5459
|
+
toJSON(message) {
|
|
5460
|
+
const obj = {};
|
|
5461
|
+
if (message.splitNode !== void 0) {
|
|
5462
|
+
obj.splitNode = TreeNode.toJSON(message.splitNode);
|
|
5463
|
+
}
|
|
5464
|
+
if (message.node !== void 0) {
|
|
5465
|
+
obj.node = TreeNode.toJSON(message.node);
|
|
5466
|
+
}
|
|
5467
|
+
return obj;
|
|
5468
|
+
},
|
|
5469
|
+
create(base) {
|
|
5470
|
+
return RenewNodeZeroTimelockResult.fromPartial(base ?? {});
|
|
5471
|
+
},
|
|
5472
|
+
fromPartial(object) {
|
|
5473
|
+
const message = createBaseRenewNodeZeroTimelockResult();
|
|
5474
|
+
message.splitNode = object.splitNode !== void 0 && object.splitNode !== null ? TreeNode.fromPartial(object.splitNode) : void 0;
|
|
5475
|
+
message.node = object.node !== void 0 && object.node !== null ? TreeNode.fromPartial(object.node) : void 0;
|
|
5476
|
+
return message;
|
|
5477
|
+
}
|
|
5478
|
+
};
|
|
5225
5479
|
function createBaseNodeSignatureShares() {
|
|
5226
5480
|
return {
|
|
5227
5481
|
nodeId: "",
|
|
@@ -17976,7 +18230,11 @@ var BASE_CONFIG = {
|
|
|
17976
18230
|
console: {
|
|
17977
18231
|
otel: false
|
|
17978
18232
|
},
|
|
17979
|
-
events: {}
|
|
18233
|
+
events: {},
|
|
18234
|
+
optimizationOptions: {
|
|
18235
|
+
auto: true,
|
|
18236
|
+
multiplicity: 0
|
|
18237
|
+
}
|
|
17980
18238
|
};
|
|
17981
18239
|
var LOCAL_WALLET_CONFIG = {
|
|
17982
18240
|
...BASE_CONFIG,
|
|
@@ -18187,10 +18445,12 @@ var WalletConfigService = class {
|
|
|
18187
18445
|
getEvents() {
|
|
18188
18446
|
return this.config.events;
|
|
18189
18447
|
}
|
|
18448
|
+
getOptimizationOptions() {
|
|
18449
|
+
return this.config.optimizationOptions;
|
|
18450
|
+
}
|
|
18190
18451
|
};
|
|
18191
18452
|
|
|
18192
18453
|
// src/services/coop-exit.ts
|
|
18193
|
-
import { Transaction as Transaction4 } from "@scure/btc-signer";
|
|
18194
18454
|
import { uuidv7 as uuidv72 } from "uuidv7";
|
|
18195
18455
|
|
|
18196
18456
|
// src/utils/bitcoin.ts
|
|
@@ -18345,6 +18605,7 @@ function getTxEstimatedVbytesSizeByNumberOfInputsOutputs(numInputs, numOutputs)
|
|
|
18345
18605
|
}
|
|
18346
18606
|
|
|
18347
18607
|
// src/utils/transaction.ts
|
|
18608
|
+
import { hexToBytes as hexToBytes2 } from "@noble/hashes/utils";
|
|
18348
18609
|
import { Transaction as Transaction2 } from "@scure/btc-signer";
|
|
18349
18610
|
var INITIAL_TIMELOCK = 2e3;
|
|
18350
18611
|
var TEST_UNILATERAL_TIMELOCK = 100;
|
|
@@ -18353,9 +18614,9 @@ var DIRECT_TIMELOCK_OFFSET = 50;
|
|
|
18353
18614
|
var HTLC_TIMELOCK_OFFSET = 70;
|
|
18354
18615
|
var DIRECT_HTLC_TIMELOCK_OFFSET = 85;
|
|
18355
18616
|
var INITIAL_SEQUENCE = 1 << 30 | INITIAL_TIMELOCK;
|
|
18356
|
-
var INITIAL_DIRECT_SEQUENCE = 1 << 30 | INITIAL_TIMELOCK + DIRECT_TIMELOCK_OFFSET;
|
|
18357
18617
|
var TEST_UNILATERAL_SEQUENCE = 1 << 30 | TEST_UNILATERAL_TIMELOCK;
|
|
18358
18618
|
var TEST_UNILATERAL_DIRECT_SEQUENCE = 1 << 30 | TEST_UNILATERAL_TIMELOCK + DIRECT_TIMELOCK_OFFSET;
|
|
18619
|
+
var INITIAL_ROOT_NODE_SEQUENCE = 1 << 30 | 0;
|
|
18359
18620
|
var ESTIMATED_TX_SIZE = 191;
|
|
18360
18621
|
var DEFAULT_SATS_PER_VBYTE = 5;
|
|
18361
18622
|
var DEFAULT_FEE_SATS = ESTIMATED_TX_SIZE * DEFAULT_SATS_PER_VBYTE;
|
|
@@ -18365,63 +18626,8 @@ function maybeApplyFee(amount) {
|
|
|
18365
18626
|
}
|
|
18366
18627
|
return amount;
|
|
18367
18628
|
}
|
|
18368
|
-
function createRootTx(depositOutPoint, depositTxOut) {
|
|
18369
|
-
const cpfpRootTx = new Transaction2({
|
|
18370
|
-
version: 3,
|
|
18371
|
-
allowUnknownOutputs: true
|
|
18372
|
-
});
|
|
18373
|
-
cpfpRootTx.addInput(depositOutPoint);
|
|
18374
|
-
cpfpRootTx.addOutput(depositTxOut);
|
|
18375
|
-
cpfpRootTx.addOutput(getEphemeralAnchorOutput());
|
|
18376
|
-
const directRootTx = new Transaction2({
|
|
18377
|
-
version: 3,
|
|
18378
|
-
allowUnknownOutputs: true
|
|
18379
|
-
});
|
|
18380
|
-
directRootTx.addInput(depositOutPoint);
|
|
18381
|
-
directRootTx.addOutput({
|
|
18382
|
-
script: depositTxOut.script,
|
|
18383
|
-
amount: maybeApplyFee(depositTxOut.amount ?? 0n)
|
|
18384
|
-
});
|
|
18385
|
-
return [cpfpRootTx, directRootTx];
|
|
18386
|
-
}
|
|
18387
|
-
function createSplitTx(parentOutPoint, childTxOuts) {
|
|
18388
|
-
const cpfpSplitTx = new Transaction2({
|
|
18389
|
-
version: 3,
|
|
18390
|
-
allowUnknownOutputs: true
|
|
18391
|
-
});
|
|
18392
|
-
cpfpSplitTx.addInput(parentOutPoint);
|
|
18393
|
-
for (const txOut of childTxOuts) {
|
|
18394
|
-
cpfpSplitTx.addOutput(txOut);
|
|
18395
|
-
}
|
|
18396
|
-
cpfpSplitTx.addOutput(getEphemeralAnchorOutput());
|
|
18397
|
-
const directSplitTx = new Transaction2({
|
|
18398
|
-
version: 3,
|
|
18399
|
-
allowUnknownOutputs: true
|
|
18400
|
-
});
|
|
18401
|
-
directSplitTx.addInput(parentOutPoint);
|
|
18402
|
-
let totalOutputAmount = 0n;
|
|
18403
|
-
for (const txOut of childTxOuts) {
|
|
18404
|
-
totalOutputAmount += txOut.amount ?? 0n;
|
|
18405
|
-
}
|
|
18406
|
-
if (totalOutputAmount > BigInt(DEFAULT_FEE_SATS)) {
|
|
18407
|
-
const feeRatio = Number(DEFAULT_FEE_SATS) / Number(totalOutputAmount);
|
|
18408
|
-
for (const txOut of childTxOuts) {
|
|
18409
|
-
const adjustedAmount = BigInt(
|
|
18410
|
-
Math.floor(Number(txOut.amount ?? 0n) * (1 - feeRatio))
|
|
18411
|
-
);
|
|
18412
|
-
directSplitTx.addOutput({
|
|
18413
|
-
script: txOut.script,
|
|
18414
|
-
amount: adjustedAmount
|
|
18415
|
-
});
|
|
18416
|
-
}
|
|
18417
|
-
} else {
|
|
18418
|
-
for (const txOut of childTxOuts) {
|
|
18419
|
-
directSplitTx.addOutput(txOut);
|
|
18420
|
-
}
|
|
18421
|
-
}
|
|
18422
|
-
return [cpfpSplitTx, directSplitTx];
|
|
18423
|
-
}
|
|
18424
18629
|
function createNodeTx({
|
|
18630
|
+
sequence,
|
|
18425
18631
|
txOut,
|
|
18426
18632
|
parentOutPoint,
|
|
18427
18633
|
applyFee,
|
|
@@ -18431,7 +18637,10 @@ function createNodeTx({
|
|
|
18431
18637
|
version: 3,
|
|
18432
18638
|
allowUnknownOutputs: true
|
|
18433
18639
|
});
|
|
18434
|
-
nodeTx.addInput(
|
|
18640
|
+
nodeTx.addInput({
|
|
18641
|
+
...parentOutPoint,
|
|
18642
|
+
sequence
|
|
18643
|
+
});
|
|
18435
18644
|
if (applyFee) {
|
|
18436
18645
|
nodeTx.addOutput({
|
|
18437
18646
|
script: txOut.script,
|
|
@@ -18445,52 +18654,92 @@ function createNodeTx({
|
|
|
18445
18654
|
}
|
|
18446
18655
|
return nodeTx;
|
|
18447
18656
|
}
|
|
18448
|
-
function createNodeTxs(
|
|
18449
|
-
|
|
18450
|
-
|
|
18451
|
-
|
|
18452
|
-
|
|
18453
|
-
|
|
18454
|
-
|
|
18455
|
-
if (
|
|
18456
|
-
|
|
18457
|
-
|
|
18458
|
-
|
|
18459
|
-
includeAnchor: false,
|
|
18460
|
-
applyFee: true
|
|
18657
|
+
function createNodeTxs({
|
|
18658
|
+
parentTx,
|
|
18659
|
+
sequence,
|
|
18660
|
+
directSequence,
|
|
18661
|
+
vout
|
|
18662
|
+
}) {
|
|
18663
|
+
const parentOutput = parentTx.getOutput(vout);
|
|
18664
|
+
if (!parentOutput.amount || !parentOutput.script) {
|
|
18665
|
+
throw new ValidationError("Parent output amount or script not found", {
|
|
18666
|
+
field: "parentOutput",
|
|
18667
|
+
value: parentOutput
|
|
18461
18668
|
});
|
|
18462
18669
|
}
|
|
18463
|
-
|
|
18670
|
+
const output = {
|
|
18671
|
+
script: parentOutput.script,
|
|
18672
|
+
amount: parentOutput.amount
|
|
18673
|
+
};
|
|
18674
|
+
const input = {
|
|
18675
|
+
txid: hexToBytes2(getTxId(parentTx)),
|
|
18676
|
+
index: vout
|
|
18677
|
+
};
|
|
18678
|
+
const nodeTx = createNodeTx({
|
|
18679
|
+
sequence,
|
|
18680
|
+
txOut: output,
|
|
18681
|
+
parentOutPoint: input,
|
|
18682
|
+
includeAnchor: true
|
|
18683
|
+
});
|
|
18684
|
+
const directNodeTx = createNodeTx({
|
|
18685
|
+
sequence: directSequence ?? sequence + DIRECT_TIMELOCK_OFFSET,
|
|
18686
|
+
txOut: output,
|
|
18687
|
+
parentOutPoint: input,
|
|
18688
|
+
includeAnchor: false,
|
|
18689
|
+
applyFee: true
|
|
18690
|
+
});
|
|
18691
|
+
return { nodeTx, directNodeTx };
|
|
18464
18692
|
}
|
|
18465
|
-
function
|
|
18466
|
-
|
|
18467
|
-
|
|
18468
|
-
|
|
18693
|
+
function createRootNodeTx(parentTx, vout) {
|
|
18694
|
+
return createNodeTxs({
|
|
18695
|
+
parentTx,
|
|
18696
|
+
sequence: INITIAL_ROOT_NODE_SEQUENCE,
|
|
18697
|
+
vout
|
|
18469
18698
|
});
|
|
18470
|
-
|
|
18471
|
-
|
|
18472
|
-
|
|
18699
|
+
}
|
|
18700
|
+
function createZeroTimelockNodeTx(parentTx) {
|
|
18701
|
+
return createNodeTxs({
|
|
18702
|
+
parentTx,
|
|
18703
|
+
sequence: INITIAL_ROOT_NODE_SEQUENCE,
|
|
18704
|
+
directSequence: DIRECT_TIMELOCK_OFFSET,
|
|
18705
|
+
vout: 0
|
|
18473
18706
|
});
|
|
18474
|
-
|
|
18475
|
-
|
|
18476
|
-
|
|
18477
|
-
|
|
18478
|
-
|
|
18707
|
+
}
|
|
18708
|
+
function createInitialTimelockNodeTx(parentTx) {
|
|
18709
|
+
return createNodeTxs({
|
|
18710
|
+
parentTx,
|
|
18711
|
+
sequence: INITIAL_SEQUENCE,
|
|
18712
|
+
vout: 0
|
|
18479
18713
|
});
|
|
18480
|
-
|
|
18481
|
-
|
|
18482
|
-
|
|
18714
|
+
}
|
|
18715
|
+
function createDecrementedTimelockNodeTx(parentTx, currentTx) {
|
|
18716
|
+
const currentSequence = currentTx.getInput(0).sequence;
|
|
18717
|
+
if (!currentSequence) {
|
|
18718
|
+
throw new ValidationError("Current sequence not found", {
|
|
18719
|
+
field: "currentSequence",
|
|
18720
|
+
value: currentSequence
|
|
18721
|
+
});
|
|
18722
|
+
}
|
|
18723
|
+
return createNodeTxs({
|
|
18724
|
+
parentTx,
|
|
18725
|
+
sequence: getNextTransactionSequence(currentSequence).nextSequence,
|
|
18726
|
+
vout: 0
|
|
18483
18727
|
});
|
|
18484
|
-
|
|
18485
|
-
|
|
18486
|
-
|
|
18487
|
-
|
|
18728
|
+
}
|
|
18729
|
+
function createTestUnilateralTimelockNodeTx(parentTx, nodeTx) {
|
|
18730
|
+
const sequence = nodeTx.getInput(0).sequence;
|
|
18731
|
+
if (!sequence) {
|
|
18732
|
+
throw new ValidationError("Sequence not found", {
|
|
18733
|
+
field: "sequence",
|
|
18734
|
+
value: sequence
|
|
18735
|
+
});
|
|
18488
18736
|
}
|
|
18489
|
-
|
|
18490
|
-
|
|
18491
|
-
|
|
18737
|
+
const isBit30Defined = (sequence || 0) & 1 << 30;
|
|
18738
|
+
return createNodeTxs({
|
|
18739
|
+
parentTx,
|
|
18740
|
+
sequence: isBit30Defined | TEST_UNILATERAL_TIMELOCK,
|
|
18741
|
+
vout: 0
|
|
18492
18742
|
});
|
|
18493
|
-
return [cpfpLeafTx, directLeafTx];
|
|
18494
18743
|
}
|
|
18495
18744
|
function createRefundTx({
|
|
18496
18745
|
sequence,
|
|
@@ -18546,110 +18795,109 @@ function getNextHTLCTransactionSequence(currSequence, isNodeTx) {
|
|
|
18546
18795
|
};
|
|
18547
18796
|
}
|
|
18548
18797
|
function createRefundTxs({
|
|
18549
|
-
|
|
18550
|
-
|
|
18551
|
-
input,
|
|
18552
|
-
directInput,
|
|
18553
|
-
amountSats,
|
|
18798
|
+
nodeTx,
|
|
18799
|
+
directNodeTx,
|
|
18554
18800
|
receivingPubkey,
|
|
18555
|
-
network
|
|
18801
|
+
network,
|
|
18802
|
+
sequence
|
|
18556
18803
|
}) {
|
|
18557
|
-
const
|
|
18558
|
-
|
|
18559
|
-
|
|
18560
|
-
|
|
18561
|
-
|
|
18562
|
-
|
|
18563
|
-
|
|
18564
|
-
|
|
18565
|
-
|
|
18804
|
+
const refundInput = {
|
|
18805
|
+
txid: hexToBytes2(getTxId(nodeTx)),
|
|
18806
|
+
index: 0
|
|
18807
|
+
};
|
|
18808
|
+
const nodeAmountSats = nodeTx.getOutput(0).amount;
|
|
18809
|
+
if (nodeAmountSats === void 0) {
|
|
18810
|
+
throw new ValidationError("Node amount not found", {
|
|
18811
|
+
field: "nodeAmountSats",
|
|
18812
|
+
value: nodeAmountSats
|
|
18813
|
+
});
|
|
18814
|
+
}
|
|
18566
18815
|
let directRefundTx;
|
|
18567
|
-
|
|
18568
|
-
|
|
18816
|
+
if (directNodeTx) {
|
|
18817
|
+
const directRefundInput = {
|
|
18818
|
+
txid: hexToBytes2(getTxId(directNodeTx)),
|
|
18819
|
+
index: 0
|
|
18820
|
+
};
|
|
18821
|
+
const directAmountSats = directNodeTx.getOutput(0).amount;
|
|
18822
|
+
if (directAmountSats === void 0) {
|
|
18823
|
+
throw new ValidationError("Direct amount not found", {
|
|
18824
|
+
field: "directAmountSats",
|
|
18825
|
+
value: directAmountSats
|
|
18826
|
+
});
|
|
18827
|
+
}
|
|
18569
18828
|
directRefundTx = createRefundTx({
|
|
18570
|
-
sequence:
|
|
18571
|
-
input:
|
|
18572
|
-
amountSats,
|
|
18573
|
-
receivingPubkey,
|
|
18574
|
-
network,
|
|
18575
|
-
shouldCalculateFee: true,
|
|
18576
|
-
includeAnchor: false
|
|
18577
|
-
});
|
|
18578
|
-
directFromCpfpRefundTx = createRefundTx({
|
|
18579
|
-
sequence: directSequence,
|
|
18580
|
-
input,
|
|
18581
|
-
amountSats,
|
|
18829
|
+
sequence: sequence + DIRECT_TIMELOCK_OFFSET,
|
|
18830
|
+
input: directRefundInput,
|
|
18831
|
+
amountSats: directAmountSats,
|
|
18582
18832
|
receivingPubkey,
|
|
18583
18833
|
network,
|
|
18584
18834
|
shouldCalculateFee: true,
|
|
18585
18835
|
includeAnchor: false
|
|
18586
18836
|
});
|
|
18587
|
-
} else if (directInput && !directSequence) {
|
|
18588
|
-
throw new ValidationError(
|
|
18589
|
-
"directSequence must be provided if directInput is",
|
|
18590
|
-
{
|
|
18591
|
-
field: "directSequence",
|
|
18592
|
-
value: directSequence
|
|
18593
|
-
}
|
|
18594
|
-
);
|
|
18595
18837
|
}
|
|
18596
|
-
|
|
18597
|
-
|
|
18598
|
-
|
|
18599
|
-
|
|
18600
|
-
|
|
18601
|
-
|
|
18838
|
+
const cpfpRefundTx = createRefundTx({
|
|
18839
|
+
sequence,
|
|
18840
|
+
input: refundInput,
|
|
18841
|
+
amountSats: nodeAmountSats,
|
|
18842
|
+
receivingPubkey,
|
|
18843
|
+
network,
|
|
18844
|
+
shouldCalculateFee: false,
|
|
18845
|
+
includeAnchor: true
|
|
18602
18846
|
});
|
|
18603
|
-
|
|
18604
|
-
|
|
18605
|
-
|
|
18847
|
+
const directFromCpfpRefundTx = createRefundTx({
|
|
18848
|
+
sequence: sequence + DIRECT_TIMELOCK_OFFSET,
|
|
18849
|
+
input: refundInput,
|
|
18850
|
+
amountSats: nodeAmountSats,
|
|
18851
|
+
receivingPubkey,
|
|
18852
|
+
network,
|
|
18853
|
+
shouldCalculateFee: true,
|
|
18854
|
+
includeAnchor: false
|
|
18606
18855
|
});
|
|
18607
|
-
cpfpRefundTx
|
|
18608
|
-
|
|
18609
|
-
|
|
18610
|
-
|
|
18611
|
-
|
|
18856
|
+
return { cpfpRefundTx, directRefundTx, directFromCpfpRefundTx };
|
|
18857
|
+
}
|
|
18858
|
+
function createInitialTimelockRefundTxs(params) {
|
|
18859
|
+
return createRefundTxs({
|
|
18860
|
+
...params,
|
|
18861
|
+
sequence: INITIAL_SEQUENCE
|
|
18612
18862
|
});
|
|
18613
|
-
|
|
18614
|
-
|
|
18615
|
-
|
|
18863
|
+
}
|
|
18864
|
+
function createDecrementedTimelockRefundTxs(params) {
|
|
18865
|
+
const nextSequence = getNextTransactionSequence(params.sequence).nextSequence;
|
|
18866
|
+
return createRefundTxs({
|
|
18867
|
+
...params,
|
|
18868
|
+
sequence: nextSequence
|
|
18616
18869
|
});
|
|
18617
|
-
|
|
18618
|
-
|
|
18619
|
-
|
|
18870
|
+
}
|
|
18871
|
+
function createCurrentTimelockRefundTxs(params) {
|
|
18872
|
+
return createRefundTxs(params);
|
|
18873
|
+
}
|
|
18874
|
+
function createTestUnilateralRefundTxs(params) {
|
|
18875
|
+
return createRefundTxs({
|
|
18876
|
+
...params,
|
|
18877
|
+
sequence: TEST_UNILATERAL_SEQUENCE
|
|
18620
18878
|
});
|
|
18621
|
-
|
|
18622
|
-
|
|
18623
|
-
|
|
18624
|
-
|
|
18879
|
+
}
|
|
18880
|
+
function createConnectorRefundTxs(params) {
|
|
18881
|
+
const { connectorOutput, ...baseParams } = params;
|
|
18882
|
+
const { cpfpRefundTx, directRefundTx, directFromCpfpRefundTx } = createDecrementedTimelockRefundTxs(baseParams);
|
|
18883
|
+
cpfpRefundTx.addInput(connectorOutput);
|
|
18884
|
+
if (directRefundTx) {
|
|
18885
|
+
directRefundTx.addInput(connectorOutput);
|
|
18625
18886
|
}
|
|
18626
|
-
|
|
18627
|
-
|
|
18628
|
-
|
|
18629
|
-
}
|
|
18630
|
-
const directFromCpfpTx = new Transaction2({
|
|
18631
|
-
version: 3,
|
|
18632
|
-
allowUnknownOutputs: true
|
|
18633
|
-
});
|
|
18634
|
-
directFromCpfpTx.addInput({
|
|
18635
|
-
...cpfpNodeOutPoint,
|
|
18636
|
-
sequence
|
|
18637
|
-
});
|
|
18638
|
-
directFromCpfpTx.addInput(connectorOutput);
|
|
18639
|
-
directFromCpfpTx.addOutput({
|
|
18640
|
-
script: receiverScript,
|
|
18641
|
-
amount: outputAmount
|
|
18642
|
-
});
|
|
18643
|
-
return [cpfpRefundTx, directRefundTx, directFromCpfpTx];
|
|
18887
|
+
if (directFromCpfpRefundTx) {
|
|
18888
|
+
directFromCpfpRefundTx.addInput(connectorOutput);
|
|
18889
|
+
}
|
|
18890
|
+
return { cpfpRefundTx, directRefundTx, directFromCpfpRefundTx };
|
|
18644
18891
|
}
|
|
18645
18892
|
function getCurrentTimelock(currSequence) {
|
|
18646
18893
|
return (currSequence || 0) & 65535;
|
|
18647
18894
|
}
|
|
18648
18895
|
function getTransactionSequence(currSequence) {
|
|
18649
18896
|
const timelock = getCurrentTimelock(currSequence);
|
|
18897
|
+
const isBit30Defined = (currSequence || 0) & 1 << 30;
|
|
18650
18898
|
return {
|
|
18651
|
-
nextSequence:
|
|
18652
|
-
nextDirectSequence:
|
|
18899
|
+
nextSequence: isBit30Defined | timelock,
|
|
18900
|
+
nextDirectSequence: isBit30Defined | timelock + DIRECT_TIMELOCK_OFFSET
|
|
18653
18901
|
};
|
|
18654
18902
|
}
|
|
18655
18903
|
function checkIfValidSequence(currSequence) {
|
|
@@ -18668,6 +18916,13 @@ function checkIfValidSequence(currSequence) {
|
|
|
18668
18916
|
});
|
|
18669
18917
|
}
|
|
18670
18918
|
}
|
|
18919
|
+
function isZeroTimelock(currSequence) {
|
|
18920
|
+
return getCurrentTimelock(currSequence) === 0;
|
|
18921
|
+
}
|
|
18922
|
+
function doesTxnNeedRenewed(currSequence) {
|
|
18923
|
+
const currentTimelock = getCurrentTimelock(currSequence);
|
|
18924
|
+
return currentTimelock <= 100;
|
|
18925
|
+
}
|
|
18671
18926
|
function doesLeafNeedRefresh(currSequence, isNodeTx) {
|
|
18672
18927
|
const currentTimelock = getCurrentTimelock(currSequence);
|
|
18673
18928
|
if (isNodeTx) {
|
|
@@ -18678,6 +18933,7 @@ function doesLeafNeedRefresh(currSequence, isNodeTx) {
|
|
|
18678
18933
|
function getNextTransactionSequence(currSequence, isNodeTx) {
|
|
18679
18934
|
const currentTimelock = getCurrentTimelock(currSequence);
|
|
18680
18935
|
const nextTimelock = currentTimelock - TIME_LOCK_INTERVAL;
|
|
18936
|
+
const isBit30Defined = (currSequence || 0) & 1 << 30;
|
|
18681
18937
|
if (isNodeTx && nextTimelock < 0) {
|
|
18682
18938
|
throw new ValidationError("timelock interval is less than 0", {
|
|
18683
18939
|
field: "nextTimelock",
|
|
@@ -18692,8 +18948,8 @@ function getNextTransactionSequence(currSequence, isNodeTx) {
|
|
|
18692
18948
|
});
|
|
18693
18949
|
}
|
|
18694
18950
|
return {
|
|
18695
|
-
nextSequence:
|
|
18696
|
-
nextDirectSequence:
|
|
18951
|
+
nextSequence: isBit30Defined | nextTimelock,
|
|
18952
|
+
nextDirectSequence: isBit30Defined | nextTimelock + DIRECT_TIMELOCK_OFFSET
|
|
18697
18953
|
};
|
|
18698
18954
|
}
|
|
18699
18955
|
function getEphemeralAnchorOutput() {
|
|
@@ -18706,19 +18962,13 @@ function getEphemeralAnchorOutput() {
|
|
|
18706
18962
|
|
|
18707
18963
|
// src/services/transfer.ts
|
|
18708
18964
|
import { secp256k1 as secp256k12 } from "@noble/curves/secp256k1";
|
|
18709
|
-
import {
|
|
18710
|
-
bytesToHex as bytesToHex4,
|
|
18711
|
-
equalBytes,
|
|
18712
|
-
hexToBytes as hexToBytes3,
|
|
18713
|
-
numberToBytesBE
|
|
18714
|
-
} from "@noble/curves/utils";
|
|
18965
|
+
import { bytesToHex as bytesToHex4, equalBytes, numberToBytesBE } from "@noble/curves/utils";
|
|
18715
18966
|
import { sha256 as sha2564 } from "@noble/hashes/sha2";
|
|
18716
|
-
import { Transaction as Transaction3 } from "@scure/btc-signer";
|
|
18717
18967
|
import * as ecies from "eciesjs";
|
|
18718
18968
|
import { uuidv7 } from "uuidv7";
|
|
18719
18969
|
|
|
18720
18970
|
// src/utils/transfer_package.ts
|
|
18721
|
-
import { hexToBytes as
|
|
18971
|
+
import { hexToBytes as hexToBytes3 } from "@noble/curves/utils";
|
|
18722
18972
|
import { sha256 as sha2563 } from "@noble/hashes/sha2";
|
|
18723
18973
|
function getTransferPackageSigningPayload(transferID, transferPackage) {
|
|
18724
18974
|
const encryptedPayload = transferPackage.keyTweakPackage;
|
|
@@ -18727,7 +18977,7 @@ function getTransferPackageSigningPayload(transferID, transferPackage) {
|
|
|
18727
18977
|
).map(([key, value]) => ({ key, value }));
|
|
18728
18978
|
pairs.sort((a, b) => a.key.localeCompare(b.key));
|
|
18729
18979
|
const encoder = new TextEncoder();
|
|
18730
|
-
let message =
|
|
18980
|
+
let message = hexToBytes3(transferID.replaceAll("-", ""));
|
|
18731
18981
|
for (const pair of pairs) {
|
|
18732
18982
|
const keyPart = encoder.encode(pair.key + ":");
|
|
18733
18983
|
const separator = encoder.encode(";");
|
|
@@ -18742,13 +18992,6 @@ function getTransferPackageSigningPayload(transferID, transferPackage) {
|
|
|
18742
18992
|
}
|
|
18743
18993
|
|
|
18744
18994
|
// src/services/transfer.ts
|
|
18745
|
-
function getSigningJobProto(signingJob) {
|
|
18746
|
-
return {
|
|
18747
|
-
signingPublicKey: signingJob.signingPublicKey,
|
|
18748
|
-
rawTx: signingJob.rawTx,
|
|
18749
|
-
signingNonceCommitment: signingJob.signingNonceCommitment.commitment
|
|
18750
|
-
};
|
|
18751
|
-
}
|
|
18752
18995
|
var BaseTransferService = class {
|
|
18753
18996
|
config;
|
|
18754
18997
|
connectionManager;
|
|
@@ -19430,42 +19673,27 @@ var TransferService = class extends BaseTransferService {
|
|
|
19430
19673
|
throw new Error(`Leaf data not found for leaf ${leaf.leaf.id}`);
|
|
19431
19674
|
}
|
|
19432
19675
|
const nodeTx = getTxFromRawTxBytes(leaf.leaf.nodeTx);
|
|
19433
|
-
const cpfpNodeOutPoint = {
|
|
19434
|
-
txid: hexToBytes3(getTxId(nodeTx)),
|
|
19435
|
-
index: 0
|
|
19436
|
-
};
|
|
19437
19676
|
let directNodeTx;
|
|
19438
|
-
let directNodeOutPoint;
|
|
19439
19677
|
if (leaf.leaf.directTx.length > 0) {
|
|
19440
19678
|
directNodeTx = getTxFromRawTxBytes(leaf.leaf.directTx);
|
|
19441
|
-
directNodeOutPoint = {
|
|
19442
|
-
txid: hexToBytes3(getTxId(directNodeTx)),
|
|
19443
|
-
index: 0
|
|
19444
|
-
};
|
|
19445
19679
|
}
|
|
19446
19680
|
const currRefundTx = getTxFromRawTxBytes(leaf.leaf.refundTx);
|
|
19447
|
-
const
|
|
19448
|
-
if (!
|
|
19681
|
+
const currentSequence = currRefundTx.getInput(0).sequence;
|
|
19682
|
+
if (!currentSequence) {
|
|
19449
19683
|
throw new ValidationError("Invalid refund transaction", {
|
|
19450
19684
|
field: "sequence",
|
|
19451
19685
|
value: currRefundTx.getInput(0),
|
|
19452
19686
|
expected: "Non-null sequence"
|
|
19453
19687
|
});
|
|
19454
19688
|
}
|
|
19455
|
-
const
|
|
19456
|
-
|
|
19457
|
-
|
|
19458
|
-
|
|
19459
|
-
}
|
|
19460
|
-
const { cpfpRefundTx, directRefundTx, directFromCpfpRefundTx } = createRefundTxs({
|
|
19461
|
-
sequence: nextSequence,
|
|
19462
|
-
directSequence: nextDirectSequence,
|
|
19463
|
-
input: cpfpNodeOutPoint,
|
|
19464
|
-
directInput: directNodeOutPoint,
|
|
19465
|
-
amountSats,
|
|
19689
|
+
const refundTxsParams = {
|
|
19690
|
+
nodeTx,
|
|
19691
|
+
directNodeTx,
|
|
19692
|
+
sequence: currentSequence,
|
|
19466
19693
|
receivingPubkey: refundSigningData.receivingPubkey,
|
|
19467
19694
|
network: this.config.getNetwork()
|
|
19468
|
-
}
|
|
19695
|
+
};
|
|
19696
|
+
const { cpfpRefundTx, directRefundTx, directFromCpfpRefundTx } = isForClaim ? createCurrentTimelockRefundTxs(refundTxsParams) : createDecrementedTimelockRefundTxs(refundTxsParams);
|
|
19469
19697
|
refundSigningData.refundTx = cpfpRefundTx;
|
|
19470
19698
|
refundSigningData.directRefundTx = directRefundTx;
|
|
19471
19699
|
refundSigningData.directFromCpfpRefundTx = directFromCpfpRefundTx;
|
|
@@ -19678,71 +19906,127 @@ var TransferService = class extends BaseTransferService {
|
|
|
19678
19906
|
throw new Error(`Error querying pending transfers by sender: ${error}`);
|
|
19679
19907
|
}
|
|
19680
19908
|
}
|
|
19681
|
-
async
|
|
19682
|
-
const
|
|
19683
|
-
|
|
19684
|
-
|
|
19685
|
-
|
|
19686
|
-
|
|
19909
|
+
async renewRefundTxn(node, parentNode) {
|
|
19910
|
+
const sparkClient = await this.connectionManager.createSparkClient(
|
|
19911
|
+
this.config.getCoordinatorAddress()
|
|
19912
|
+
);
|
|
19913
|
+
const signingJobs = await this.createRenewRefundSigningJobs(
|
|
19914
|
+
node,
|
|
19915
|
+
parentNode
|
|
19916
|
+
);
|
|
19917
|
+
const statechainCommitments = await sparkClient.get_signing_commitments({
|
|
19918
|
+
nodeIds: [node.id],
|
|
19919
|
+
count: signingJobs.length
|
|
19920
|
+
});
|
|
19921
|
+
const mappedSigningJobs = signingJobs.map((signingJob, index) => {
|
|
19922
|
+
const signingNonceCommitments = statechainCommitments.signingCommitments[index]?.signingNonceCommitments;
|
|
19923
|
+
if (!signingNonceCommitments) {
|
|
19924
|
+
throw new Error("Signing nonce commitments not found");
|
|
19925
|
+
}
|
|
19926
|
+
return {
|
|
19927
|
+
...signingJob,
|
|
19928
|
+
signingNonceCommitments
|
|
19929
|
+
};
|
|
19930
|
+
});
|
|
19931
|
+
const userSignedTxSigningJobs = await this.signingService.signSigningJobs(mappedSigningJobs);
|
|
19932
|
+
const renewRefundTimelockSigningJob = {
|
|
19933
|
+
nodeTxSigningJob: userSignedTxSigningJobs.get("node"),
|
|
19934
|
+
refundTxSigningJob: userSignedTxSigningJobs.get("cpfp"),
|
|
19935
|
+
directNodeTxSigningJob: userSignedTxSigningJobs.get("directNode"),
|
|
19936
|
+
directRefundTxSigningJob: userSignedTxSigningJobs.get("direct"),
|
|
19937
|
+
directFromCpfpRefundTxSigningJob: userSignedTxSigningJobs.get("directFromCpfp")
|
|
19938
|
+
};
|
|
19939
|
+
const response = await sparkClient.renew_leaf({
|
|
19940
|
+
leafId: node.id,
|
|
19941
|
+
signingJobs: {
|
|
19942
|
+
$case: "renewRefundTimelockSigningJob",
|
|
19943
|
+
renewRefundTimelockSigningJob
|
|
19944
|
+
}
|
|
19945
|
+
});
|
|
19946
|
+
if (response.renewResult?.$case !== "renewRefundTimelockResult" || !response.renewResult?.renewRefundTimelockResult.node) {
|
|
19947
|
+
throw new ValidationError("Unexpected renew result", {
|
|
19948
|
+
field: "renewResult",
|
|
19949
|
+
value: response.renewResult
|
|
19950
|
+
});
|
|
19687
19951
|
}
|
|
19688
|
-
|
|
19689
|
-
|
|
19690
|
-
|
|
19691
|
-
|
|
19692
|
-
|
|
19693
|
-
|
|
19694
|
-
|
|
19695
|
-
|
|
19696
|
-
|
|
19697
|
-
|
|
19698
|
-
|
|
19699
|
-
|
|
19700
|
-
|
|
19701
|
-
|
|
19702
|
-
|
|
19703
|
-
|
|
19704
|
-
|
|
19705
|
-
|
|
19952
|
+
return response.renewResult?.renewRefundTimelockResult.node;
|
|
19953
|
+
}
|
|
19954
|
+
async renewNodeTxn(node, parentNode) {
|
|
19955
|
+
const sparkClient = await this.connectionManager.createSparkClient(
|
|
19956
|
+
this.config.getCoordinatorAddress()
|
|
19957
|
+
);
|
|
19958
|
+
const signingJobs = await this.createRenewNodeSigningJobs(node, parentNode);
|
|
19959
|
+
const statechainCommitments = await sparkClient.get_signing_commitments({
|
|
19960
|
+
nodeIds: [node.id],
|
|
19961
|
+
count: signingJobs.length
|
|
19962
|
+
});
|
|
19963
|
+
const mappedSigningJobs = signingJobs.map((signingJob, index) => {
|
|
19964
|
+
const signingNonceCommitments = statechainCommitments.signingCommitments[index]?.signingNonceCommitments;
|
|
19965
|
+
if (!signingNonceCommitments) {
|
|
19966
|
+
throw new Error("Signing nonce commitments not found");
|
|
19967
|
+
}
|
|
19968
|
+
return {
|
|
19969
|
+
...signingJob,
|
|
19970
|
+
signingNonceCommitments
|
|
19971
|
+
};
|
|
19972
|
+
});
|
|
19973
|
+
const userSignedTxSigningJobs = await this.signingService.signSigningJobs(mappedSigningJobs);
|
|
19974
|
+
const response = await sparkClient.renew_leaf({
|
|
19975
|
+
leafId: node.id,
|
|
19976
|
+
signingJobs: {
|
|
19977
|
+
$case: "renewNodeTimelockSigningJob",
|
|
19978
|
+
renewNodeTimelockSigningJob: {
|
|
19979
|
+
splitNodeTxSigningJob: userSignedTxSigningJobs.get("split"),
|
|
19980
|
+
splitNodeDirectTxSigningJob: userSignedTxSigningJobs.get("directSplit"),
|
|
19981
|
+
nodeTxSigningJob: userSignedTxSigningJobs.get("node"),
|
|
19982
|
+
directNodeTxSigningJob: userSignedTxSigningJobs.get("directNode"),
|
|
19983
|
+
refundTxSigningJob: userSignedTxSigningJobs.get("cpfp"),
|
|
19984
|
+
directRefundTxSigningJob: userSignedTxSigningJobs.get("direct"),
|
|
19985
|
+
directFromCpfpRefundTxSigningJob: userSignedTxSigningJobs.get("directFromCpfp")
|
|
19986
|
+
}
|
|
19987
|
+
}
|
|
19988
|
+
});
|
|
19989
|
+
if (response.renewResult?.$case !== "renewNodeTimelockResult" || !response.renewResult?.renewNodeTimelockResult.node) {
|
|
19990
|
+
throw new ValidationError("Unexpected renew result", {
|
|
19991
|
+
field: "renewResult",
|
|
19992
|
+
value: response.renewResult
|
|
19706
19993
|
});
|
|
19707
19994
|
}
|
|
19708
|
-
|
|
19709
|
-
|
|
19710
|
-
|
|
19995
|
+
return response.renewResult.renewNodeTimelockResult.node;
|
|
19996
|
+
}
|
|
19997
|
+
async createRenewRefundSigningJobs(node, parentNode) {
|
|
19998
|
+
const signingJobs = [];
|
|
19999
|
+
const parentTx = getTxFromRawTxBytes(parentNode.nodeTx);
|
|
20000
|
+
const parentNodeOutput = getTxFromRawTxBytes(parentNode.nodeTx).getOutput(
|
|
20001
|
+
0
|
|
19711
20002
|
);
|
|
19712
|
-
|
|
20003
|
+
if (!parentNodeOutput) {
|
|
20004
|
+
throw new Error("Parent node output not found");
|
|
20005
|
+
}
|
|
20006
|
+
const unsignedParentNodeOutput = {
|
|
19713
20007
|
script: parentNodeOutput.script,
|
|
19714
20008
|
amount: parentNodeOutput.amount
|
|
19715
20009
|
};
|
|
19716
|
-
const
|
|
19717
|
-
txid: nodeInput.txid,
|
|
19718
|
-
index: nodeInput.index,
|
|
19719
|
-
sequence: useTestUnilateralSequence ? TEST_UNILATERAL_SEQUENCE : nextSequence
|
|
19720
|
-
};
|
|
19721
|
-
const newDirectInput = directNodeTx && directNodeInput ? {
|
|
19722
|
-
txid: directNodeInput.txid,
|
|
19723
|
-
index: directNodeInput.index,
|
|
19724
|
-
sequence: useTestUnilateralSequence ? TEST_UNILATERAL_DIRECT_SEQUENCE : nextDirectSequence
|
|
19725
|
-
} : void 0;
|
|
19726
|
-
const { cpfpNodeTx, directNodeTx: newDirectNodeTx } = createNodeTxs(
|
|
19727
|
-
output,
|
|
19728
|
-
newNodeInput,
|
|
19729
|
-
newDirectInput
|
|
19730
|
-
);
|
|
19731
|
-
const newCpfpNodeOutput = cpfpNodeTx.getOutput(0);
|
|
19732
|
-
if (!newCpfpNodeOutput) {
|
|
19733
|
-
throw Error("Could not get new cpfp node output");
|
|
19734
|
-
}
|
|
19735
|
-
const newDirectNodeOutput = newDirectNodeTx?.getOutput(0);
|
|
19736
|
-
const signingPublicKey = await this.config.signer.getPublicKeyFromDerivation({
|
|
20010
|
+
const keyDerivation = {
|
|
19737
20011
|
type: "leaf" /* LEAF */,
|
|
19738
20012
|
path: node.id
|
|
19739
|
-
}
|
|
20013
|
+
};
|
|
20014
|
+
const signingPublicKey = await this.config.signer.getPublicKeyFromDerivation(keyDerivation);
|
|
20015
|
+
const nodeTx = getTxFromRawTxBytes(node.nodeTx);
|
|
20016
|
+
const refundTx = getTxFromRawTxBytes(node.refundTx);
|
|
20017
|
+
const { nodeTx: newNodeTx, directNodeTx: newDirectNodeTx } = createDecrementedTimelockNodeTx(parentTx, nodeTx);
|
|
19740
20018
|
signingJobs.push({
|
|
19741
20019
|
signingPublicKey,
|
|
19742
|
-
rawTx:
|
|
20020
|
+
rawTx: newNodeTx.toBytes(),
|
|
19743
20021
|
signingNonceCommitment: await this.config.signer.getRandomSigningCommitment(),
|
|
19744
20022
|
type: "node",
|
|
19745
|
-
parentTxOut:
|
|
20023
|
+
parentTxOut: unsignedParentNodeOutput,
|
|
20024
|
+
leafId: node.id,
|
|
20025
|
+
keyDerivation: {
|
|
20026
|
+
type: "leaf" /* LEAF */,
|
|
20027
|
+
path: node.id
|
|
20028
|
+
},
|
|
20029
|
+
verifyingKey: node.verifyingPublicKey
|
|
19746
20030
|
});
|
|
19747
20031
|
if (newDirectNodeTx) {
|
|
19748
20032
|
signingJobs.push({
|
|
@@ -19750,537 +20034,299 @@ var TransferService = class extends BaseTransferService {
|
|
|
19750
20034
|
rawTx: newDirectNodeTx.toBytes(),
|
|
19751
20035
|
signingNonceCommitment: await this.config.signer.getRandomSigningCommitment(),
|
|
19752
20036
|
type: "directNode",
|
|
19753
|
-
parentTxOut:
|
|
20037
|
+
parentTxOut: unsignedParentNodeOutput,
|
|
20038
|
+
leafId: node.id,
|
|
20039
|
+
keyDerivation: {
|
|
20040
|
+
type: "leaf" /* LEAF */,
|
|
20041
|
+
path: node.id
|
|
20042
|
+
},
|
|
20043
|
+
verifyingKey: node.verifyingPublicKey
|
|
19754
20044
|
});
|
|
19755
20045
|
}
|
|
19756
|
-
const
|
|
19757
|
-
|
|
19758
|
-
|
|
19759
|
-
};
|
|
19760
|
-
let newDirectRefundOutPoint;
|
|
19761
|
-
if (newDirectNodeTx) {
|
|
19762
|
-
newDirectRefundOutPoint = {
|
|
19763
|
-
txid: hexToBytes3(getTxId(newDirectNodeTx)),
|
|
19764
|
-
index: 0
|
|
19765
|
-
};
|
|
20046
|
+
const newCpfpNodeOutput = newNodeTx.getOutput(0);
|
|
20047
|
+
if (!newCpfpNodeOutput) {
|
|
20048
|
+
throw Error("Could not get new cpfp node output");
|
|
19766
20049
|
}
|
|
19767
|
-
const
|
|
19768
|
-
|
|
19769
|
-
|
|
19770
|
-
|
|
19771
|
-
|
|
19772
|
-
|
|
19773
|
-
|
|
19774
|
-
|
|
19775
|
-
|
|
19776
|
-
|
|
20050
|
+
const newDirectNodeOutput = newDirectNodeTx?.getOutput(0);
|
|
20051
|
+
const amountSats = refundTx.getOutput(0).amount;
|
|
20052
|
+
if (amountSats === void 0) {
|
|
20053
|
+
throw new Error("Amount not found in extendTimelock");
|
|
20054
|
+
}
|
|
20055
|
+
const directAmountSats = newDirectNodeOutput?.amount;
|
|
20056
|
+
if (directAmountSats === void 0) {
|
|
20057
|
+
throw new Error("Amount not found in extendTimelock");
|
|
20058
|
+
}
|
|
20059
|
+
const {
|
|
20060
|
+
cpfpRefundTx: newRefundTx,
|
|
20061
|
+
directRefundTx: newDirectRefundTx,
|
|
20062
|
+
directFromCpfpRefundTx: newDirectFromCpfpRefundTx
|
|
20063
|
+
} = createInitialTimelockRefundTxs({
|
|
20064
|
+
nodeTx: newNodeTx,
|
|
20065
|
+
directNodeTx: newDirectNodeTx,
|
|
20066
|
+
receivingPubkey: signingPublicKey,
|
|
19777
20067
|
network: this.config.getNetwork()
|
|
19778
20068
|
});
|
|
19779
20069
|
signingJobs.push({
|
|
19780
20070
|
signingPublicKey,
|
|
19781
|
-
rawTx:
|
|
20071
|
+
rawTx: newRefundTx.toBytes(),
|
|
19782
20072
|
signingNonceCommitment: await this.config.signer.getRandomSigningCommitment(),
|
|
19783
20073
|
type: "cpfp",
|
|
19784
|
-
parentTxOut: newCpfpNodeOutput
|
|
20074
|
+
parentTxOut: newCpfpNodeOutput,
|
|
20075
|
+
leafId: node.id,
|
|
20076
|
+
keyDerivation,
|
|
20077
|
+
verifyingKey: node.verifyingPublicKey
|
|
19785
20078
|
});
|
|
19786
|
-
if (
|
|
20079
|
+
if (newDirectRefundTx && newDirectNodeOutput) {
|
|
19787
20080
|
signingJobs.push({
|
|
19788
20081
|
signingPublicKey,
|
|
19789
|
-
rawTx:
|
|
20082
|
+
rawTx: newDirectRefundTx.toBytes(),
|
|
19790
20083
|
signingNonceCommitment: await this.config.signer.getRandomSigningCommitment(),
|
|
19791
20084
|
type: "direct",
|
|
19792
|
-
parentTxOut: newDirectNodeOutput
|
|
20085
|
+
parentTxOut: newDirectNodeOutput,
|
|
20086
|
+
leafId: node.id,
|
|
20087
|
+
keyDerivation,
|
|
20088
|
+
verifyingKey: node.verifyingPublicKey
|
|
19793
20089
|
});
|
|
19794
20090
|
}
|
|
19795
|
-
if (
|
|
20091
|
+
if (newDirectFromCpfpRefundTx && newDirectNodeOutput) {
|
|
19796
20092
|
signingJobs.push({
|
|
19797
20093
|
signingPublicKey,
|
|
19798
|
-
rawTx:
|
|
20094
|
+
rawTx: newDirectFromCpfpRefundTx.toBytes(),
|
|
19799
20095
|
signingNonceCommitment: await this.config.signer.getRandomSigningCommitment(),
|
|
19800
20096
|
type: "directFromCpfp",
|
|
19801
|
-
parentTxOut: newCpfpNodeOutput
|
|
20097
|
+
parentTxOut: newCpfpNodeOutput,
|
|
20098
|
+
leafId: node.id,
|
|
20099
|
+
keyDerivation,
|
|
20100
|
+
verifyingKey: node.verifyingPublicKey
|
|
19802
20101
|
});
|
|
19803
20102
|
}
|
|
19804
|
-
|
|
19805
|
-
this.config.getCoordinatorAddress()
|
|
19806
|
-
);
|
|
19807
|
-
const response = await sparkClient.refresh_timelock_v2({
|
|
19808
|
-
leafId: node.id,
|
|
19809
|
-
ownerIdentityPublicKey: await this.config.signer.getIdentityPublicKey(),
|
|
19810
|
-
signingJobs: signingJobs.map(getSigningJobProto)
|
|
19811
|
-
});
|
|
19812
|
-
if (signingJobs.length !== response.signingResults.length) {
|
|
19813
|
-
throw Error(
|
|
19814
|
-
`number of signing jobs and signing results do not match: ${signingJobs.length} !== ${response.signingResults.length}`
|
|
19815
|
-
);
|
|
19816
|
-
}
|
|
19817
|
-
let nodeSignatures = [];
|
|
19818
|
-
let leafCpfpSignature;
|
|
19819
|
-
let leafDirectSignature;
|
|
19820
|
-
let cpfpRefundSignature;
|
|
19821
|
-
let directRefundSignature;
|
|
19822
|
-
let directFromCpfpRefundSignature;
|
|
19823
|
-
for (const [i, signingResult] of response.signingResults.entries()) {
|
|
19824
|
-
const signingJob = signingJobs[i];
|
|
19825
|
-
if (!signingJob || !signingResult) {
|
|
19826
|
-
throw Error("Signing job does not exist");
|
|
19827
|
-
}
|
|
19828
|
-
const rawTx = getTxFromRawTxBytes(signingJob.rawTx);
|
|
19829
|
-
const txOut = signingJob.parentTxOut;
|
|
19830
|
-
if (!txOut) {
|
|
19831
|
-
throw Error("Could not get tx out");
|
|
19832
|
-
}
|
|
19833
|
-
const rawTxSighash = getSigHashFromTx(rawTx, 0, txOut);
|
|
19834
|
-
const userSignature = await this.config.signer.signFrost({
|
|
19835
|
-
message: rawTxSighash,
|
|
19836
|
-
keyDerivation: {
|
|
19837
|
-
type: "leaf" /* LEAF */,
|
|
19838
|
-
path: node.id
|
|
19839
|
-
},
|
|
19840
|
-
publicKey: signingJob.signingPublicKey,
|
|
19841
|
-
verifyingKey: signingResult.verifyingKey,
|
|
19842
|
-
selfCommitment: signingJob.signingNonceCommitment,
|
|
19843
|
-
statechainCommitments: signingResult.signingResult?.signingNonceCommitments,
|
|
19844
|
-
adaptorPubKey: new Uint8Array()
|
|
19845
|
-
});
|
|
19846
|
-
const signature = await this.config.signer.aggregateFrost({
|
|
19847
|
-
message: rawTxSighash,
|
|
19848
|
-
statechainSignatures: signingResult.signingResult?.signatureShares,
|
|
19849
|
-
statechainPublicKeys: signingResult.signingResult?.publicKeys,
|
|
19850
|
-
verifyingKey: signingResult.verifyingKey,
|
|
19851
|
-
statechainCommitments: signingResult.signingResult?.signingNonceCommitments,
|
|
19852
|
-
selfCommitment: signingJob.signingNonceCommitment,
|
|
19853
|
-
publicKey: signingJob.signingPublicKey,
|
|
19854
|
-
selfSignature: userSignature,
|
|
19855
|
-
adaptorPubKey: new Uint8Array()
|
|
19856
|
-
});
|
|
19857
|
-
if (signingJob.type === "node") {
|
|
19858
|
-
leafCpfpSignature = signature;
|
|
19859
|
-
} else if (signingJob.type === "directNode") {
|
|
19860
|
-
leafDirectSignature = signature;
|
|
19861
|
-
} else if (signingJob.type === "cpfp") {
|
|
19862
|
-
cpfpRefundSignature = signature;
|
|
19863
|
-
} else if (signingJob.type === "direct") {
|
|
19864
|
-
directRefundSignature = signature;
|
|
19865
|
-
} else if (signingJob.type === "directFromCpfp") {
|
|
19866
|
-
directFromCpfpRefundSignature = signature;
|
|
19867
|
-
}
|
|
19868
|
-
}
|
|
19869
|
-
nodeSignatures.push({
|
|
19870
|
-
nodeId: node.id,
|
|
19871
|
-
nodeTxSignature: leafCpfpSignature || new Uint8Array(),
|
|
19872
|
-
directNodeTxSignature: leafDirectSignature || new Uint8Array(),
|
|
19873
|
-
refundTxSignature: cpfpRefundSignature || new Uint8Array(),
|
|
19874
|
-
directRefundTxSignature: directRefundSignature || new Uint8Array(),
|
|
19875
|
-
directFromCpfpRefundTxSignature: directFromCpfpRefundSignature || new Uint8Array()
|
|
19876
|
-
});
|
|
19877
|
-
const result = await sparkClient.finalize_node_signatures_v2({
|
|
19878
|
-
intent: 3 /* REFRESH */,
|
|
19879
|
-
nodeSignatures
|
|
19880
|
-
});
|
|
19881
|
-
return result;
|
|
19882
|
-
}
|
|
19883
|
-
async refreshTimelockNodes(node, parentNode) {
|
|
19884
|
-
return await this.refreshTimelockNodesInternal(node, parentNode);
|
|
20103
|
+
return signingJobs;
|
|
19885
20104
|
}
|
|
19886
|
-
async
|
|
19887
|
-
const
|
|
19888
|
-
const
|
|
19889
|
-
const
|
|
19890
|
-
|
|
19891
|
-
txid: hexToBytes3(getTxId(nodeTx)),
|
|
19892
|
-
index: 0
|
|
19893
|
-
};
|
|
19894
|
-
const {
|
|
19895
|
-
nextSequence: newNodeSequence,
|
|
19896
|
-
nextDirectSequence: newDirectNodeSequence
|
|
19897
|
-
} = getNextTransactionSequence(refundSequence);
|
|
19898
|
-
const newNodeTx = new Transaction3({
|
|
19899
|
-
version: 3,
|
|
19900
|
-
allowUnknownOutputs: true
|
|
19901
|
-
});
|
|
19902
|
-
newNodeTx.addInput({ ...newNodeOutPoint, sequence: newNodeSequence });
|
|
19903
|
-
const originalOutput = nodeTx.getOutput(0);
|
|
19904
|
-
if (!originalOutput) {
|
|
19905
|
-
throw Error("Could not get original node output");
|
|
19906
|
-
}
|
|
19907
|
-
newNodeTx.addOutput({
|
|
19908
|
-
script: originalOutput.script,
|
|
19909
|
-
amount: originalOutput.amount
|
|
19910
|
-
});
|
|
19911
|
-
newNodeTx.addOutput(getEphemeralAnchorOutput());
|
|
19912
|
-
let newDirectNodeTx;
|
|
19913
|
-
if (node.directTx.length > 0) {
|
|
19914
|
-
newDirectNodeTx = new Transaction3({
|
|
19915
|
-
version: 3,
|
|
19916
|
-
allowUnknownOutputs: true
|
|
19917
|
-
});
|
|
19918
|
-
newDirectNodeTx.addInput({
|
|
19919
|
-
...newNodeOutPoint,
|
|
19920
|
-
sequence: newDirectNodeSequence
|
|
19921
|
-
});
|
|
19922
|
-
newDirectNodeTx.addOutput({
|
|
19923
|
-
script: originalOutput.script,
|
|
19924
|
-
amount: maybeApplyFee(originalOutput.amount)
|
|
19925
|
-
});
|
|
19926
|
-
}
|
|
19927
|
-
const newCpfpRefundOutPoint = {
|
|
19928
|
-
txid: hexToBytes3(getTxId(newNodeTx)),
|
|
19929
|
-
index: 0
|
|
19930
|
-
};
|
|
19931
|
-
let newDirectRefundOutPoint;
|
|
19932
|
-
if (newDirectNodeTx) {
|
|
19933
|
-
newDirectRefundOutPoint = {
|
|
19934
|
-
txid: hexToBytes3(getTxId(newDirectNodeTx)),
|
|
19935
|
-
index: 0
|
|
19936
|
-
};
|
|
19937
|
-
}
|
|
19938
|
-
const amountSats = refundTx.getOutput(0).amount;
|
|
19939
|
-
if (amountSats === void 0) {
|
|
19940
|
-
throw new Error("Amount not found in extendTimelock");
|
|
19941
|
-
}
|
|
19942
|
-
const signingPublicKey = await this.config.signer.getPublicKeyFromDerivation({
|
|
19943
|
-
type: "leaf" /* LEAF */,
|
|
19944
|
-
path: node.id
|
|
19945
|
-
});
|
|
19946
|
-
const {
|
|
19947
|
-
cpfpRefundTx: newCpfpRefundTx,
|
|
19948
|
-
directRefundTx: newDirectRefundTx,
|
|
19949
|
-
directFromCpfpRefundTx: newDirectFromCpfpRefundTx
|
|
19950
|
-
} = createRefundTxs({
|
|
19951
|
-
sequence: INITIAL_SEQUENCE,
|
|
19952
|
-
directSequence: INITIAL_DIRECT_SEQUENCE,
|
|
19953
|
-
input: newCpfpRefundOutPoint,
|
|
19954
|
-
directInput: newDirectRefundOutPoint,
|
|
19955
|
-
amountSats,
|
|
19956
|
-
receivingPubkey: signingPublicKey,
|
|
19957
|
-
network: this.config.getNetwork()
|
|
19958
|
-
});
|
|
19959
|
-
if (!newCpfpRefundTx) {
|
|
19960
|
-
throw new ValidationError(
|
|
19961
|
-
"Failed to create refund transactions in extendTimelock"
|
|
19962
|
-
);
|
|
19963
|
-
}
|
|
19964
|
-
const nodeSighash = getSigHashFromTx(newNodeTx, 0, nodeTx.getOutput(0));
|
|
19965
|
-
const directNodeSighash = newDirectNodeTx ? getSigHashFromTx(newDirectNodeTx, 0, nodeTx.getOutput(0)) : void 0;
|
|
19966
|
-
const cpfpRefundSighash = getSigHashFromTx(
|
|
19967
|
-
newCpfpRefundTx,
|
|
19968
|
-
0,
|
|
19969
|
-
newNodeTx.getOutput(0)
|
|
20105
|
+
async createRenewNodeSigningJobs(node, parentNode) {
|
|
20106
|
+
const signingJobs = [];
|
|
20107
|
+
const parentTx = getTxFromRawTxBytes(parentNode.nodeTx);
|
|
20108
|
+
const parentNodeOutput = getTxFromRawTxBytes(parentNode.nodeTx).getOutput(
|
|
20109
|
+
0
|
|
19970
20110
|
);
|
|
19971
|
-
const
|
|
19972
|
-
|
|
19973
|
-
|
|
19974
|
-
signingPublicKey,
|
|
19975
|
-
rawTx: newNodeTx.toBytes(),
|
|
19976
|
-
signingNonceCommitment: await this.config.signer.getRandomSigningCommitment()
|
|
19977
|
-
};
|
|
19978
|
-
const newDirectNodeSigningJob = newDirectNodeTx ? {
|
|
19979
|
-
signingPublicKey,
|
|
19980
|
-
rawTx: newDirectNodeTx.toBytes(),
|
|
19981
|
-
signingNonceCommitment: await this.config.signer.getRandomSigningCommitment()
|
|
19982
|
-
} : void 0;
|
|
19983
|
-
const newCpfpRefundSigningJob = {
|
|
19984
|
-
signingPublicKey,
|
|
19985
|
-
rawTx: newCpfpRefundTx.toBytes(),
|
|
19986
|
-
signingNonceCommitment: await this.config.signer.getRandomSigningCommitment()
|
|
20111
|
+
const unsignedParentNodeOutput = {
|
|
20112
|
+
script: parentNodeOutput.script,
|
|
20113
|
+
amount: parentNodeOutput.amount
|
|
19987
20114
|
};
|
|
19988
|
-
const newDirectRefundSigningJob = newDirectRefundTx ? {
|
|
19989
|
-
signingPublicKey,
|
|
19990
|
-
rawTx: newDirectRefundTx.toBytes(),
|
|
19991
|
-
signingNonceCommitment: await this.config.signer.getRandomSigningCommitment()
|
|
19992
|
-
} : void 0;
|
|
19993
|
-
const newDirectFromCpfpRefundSigningJob = newDirectFromCpfpRefundTx ? {
|
|
19994
|
-
signingPublicKey,
|
|
19995
|
-
rawTx: newDirectFromCpfpRefundTx.toBytes(),
|
|
19996
|
-
signingNonceCommitment: await this.config.signer.getRandomSigningCommitment()
|
|
19997
|
-
} : void 0;
|
|
19998
|
-
const sparkClient = await this.connectionManager.createSparkClient(
|
|
19999
|
-
this.config.getCoordinatorAddress()
|
|
20000
|
-
);
|
|
20001
|
-
const response = await sparkClient.extend_leaf_v2({
|
|
20002
|
-
leafId: node.id,
|
|
20003
|
-
ownerIdentityPublicKey: await this.config.signer.getIdentityPublicKey(),
|
|
20004
|
-
nodeTxSigningJob: getSigningJobProto(newNodeSigningJob),
|
|
20005
|
-
directNodeTxSigningJob: newDirectNodeSigningJob ? getSigningJobProto(newDirectNodeSigningJob) : void 0,
|
|
20006
|
-
refundTxSigningJob: getSigningJobProto(newCpfpRefundSigningJob),
|
|
20007
|
-
directRefundTxSigningJob: newDirectRefundSigningJob ? getSigningJobProto(newDirectRefundSigningJob) : void 0,
|
|
20008
|
-
directFromCpfpRefundTxSigningJob: newDirectFromCpfpRefundSigningJob ? getSigningJobProto(newDirectFromCpfpRefundSigningJob) : void 0
|
|
20009
|
-
});
|
|
20010
|
-
if (!response.nodeTxSigningResult || !response.refundTxSigningResult) {
|
|
20011
|
-
throw new Error("Signing result does not exist");
|
|
20012
|
-
}
|
|
20013
20115
|
const keyDerivation = {
|
|
20014
20116
|
type: "leaf" /* LEAF */,
|
|
20015
20117
|
path: node.id
|
|
20016
20118
|
};
|
|
20017
|
-
const
|
|
20018
|
-
|
|
20119
|
+
const signingPublicKey = await this.config.signer.getPublicKeyFromDerivation(keyDerivation);
|
|
20120
|
+
const { nodeTx: splitNodeTx, directNodeTx: splitNodeDirectTx } = createZeroTimelockNodeTx(parentTx);
|
|
20121
|
+
signingJobs.push({
|
|
20122
|
+
signingPublicKey,
|
|
20123
|
+
rawTx: splitNodeTx.toBytes(),
|
|
20124
|
+
signingNonceCommitment: await this.config.signer.getRandomSigningCommitment(),
|
|
20125
|
+
type: "split",
|
|
20126
|
+
parentTxOut: unsignedParentNodeOutput,
|
|
20127
|
+
leafId: node.id,
|
|
20019
20128
|
keyDerivation,
|
|
20020
|
-
|
|
20021
|
-
verifyingKey: response.nodeTxSigningResult.verifyingKey,
|
|
20022
|
-
selfCommitment: newNodeSigningJob.signingNonceCommitment,
|
|
20023
|
-
statechainCommitments: response.nodeTxSigningResult.signingResult?.signingNonceCommitments,
|
|
20024
|
-
adaptorPubKey: new Uint8Array()
|
|
20025
|
-
});
|
|
20026
|
-
const nodeSig = await this.config.signer.aggregateFrost({
|
|
20027
|
-
message: nodeSighash,
|
|
20028
|
-
statechainSignatures: response.nodeTxSigningResult.signingResult?.signatureShares,
|
|
20029
|
-
statechainPublicKeys: response.nodeTxSigningResult.signingResult?.publicKeys,
|
|
20030
|
-
verifyingKey: response.nodeTxSigningResult.verifyingKey,
|
|
20031
|
-
statechainCommitments: response.nodeTxSigningResult.signingResult?.signingNonceCommitments,
|
|
20032
|
-
selfCommitment: newNodeSigningJob.signingNonceCommitment,
|
|
20033
|
-
publicKey: signingPublicKey,
|
|
20034
|
-
selfSignature: nodeUserSig,
|
|
20035
|
-
adaptorPubKey: new Uint8Array()
|
|
20129
|
+
verifyingKey: node.verifyingPublicKey
|
|
20036
20130
|
});
|
|
20037
|
-
|
|
20038
|
-
|
|
20039
|
-
|
|
20040
|
-
|
|
20131
|
+
if (splitNodeDirectTx) {
|
|
20132
|
+
signingJobs.push({
|
|
20133
|
+
signingPublicKey,
|
|
20134
|
+
rawTx: splitNodeDirectTx.toBytes(),
|
|
20135
|
+
signingNonceCommitment: await this.config.signer.getRandomSigningCommitment(),
|
|
20136
|
+
type: "directSplit",
|
|
20137
|
+
parentTxOut: unsignedParentNodeOutput,
|
|
20138
|
+
leafId: node.id,
|
|
20041
20139
|
keyDerivation,
|
|
20042
|
-
|
|
20043
|
-
verifyingKey: response.directNodeTxSigningResult.verifyingKey,
|
|
20044
|
-
selfCommitment: newDirectNodeSigningJob.signingNonceCommitment,
|
|
20045
|
-
statechainCommitments: response.directNodeTxSigningResult.signingResult?.signingNonceCommitments,
|
|
20046
|
-
adaptorPubKey: new Uint8Array()
|
|
20047
|
-
});
|
|
20048
|
-
directNodeSig = await this.config.signer.aggregateFrost({
|
|
20049
|
-
message: directNodeSighash,
|
|
20050
|
-
statechainSignatures: response.directNodeTxSigningResult.signingResult?.signatureShares,
|
|
20051
|
-
statechainPublicKeys: response.directNodeTxSigningResult.signingResult?.publicKeys,
|
|
20052
|
-
verifyingKey: response.directNodeTxSigningResult.verifyingKey,
|
|
20053
|
-
statechainCommitments: response.directNodeTxSigningResult.signingResult?.signingNonceCommitments,
|
|
20054
|
-
selfCommitment: newDirectNodeSigningJob.signingNonceCommitment,
|
|
20055
|
-
publicKey: signingPublicKey,
|
|
20056
|
-
selfSignature: directNodeUserSig,
|
|
20057
|
-
adaptorPubKey: new Uint8Array()
|
|
20140
|
+
verifyingKey: node.verifyingPublicKey
|
|
20058
20141
|
});
|
|
20059
20142
|
}
|
|
20060
|
-
const
|
|
20061
|
-
|
|
20143
|
+
const splitNodeOutput = splitNodeTx.getOutput(0);
|
|
20144
|
+
const splitNodeDirectOutput = splitNodeDirectTx.getOutput(0);
|
|
20145
|
+
if (!splitNodeDirectOutput.amount || !splitNodeDirectOutput.script) {
|
|
20146
|
+
throw new Error("Could not get split node output");
|
|
20147
|
+
}
|
|
20148
|
+
const unsignedSplitNodeOutput = {
|
|
20149
|
+
script: splitNodeDirectOutput.script,
|
|
20150
|
+
amount: splitNodeDirectOutput.amount
|
|
20151
|
+
};
|
|
20152
|
+
const { nodeTx: newNodeTx, directNodeTx: newDirectNodeTx } = createInitialTimelockNodeTx(splitNodeTx);
|
|
20153
|
+
signingJobs.push({
|
|
20154
|
+
signingPublicKey,
|
|
20155
|
+
rawTx: newNodeTx.toBytes(),
|
|
20156
|
+
signingNonceCommitment: await this.config.signer.getRandomSigningCommitment(),
|
|
20157
|
+
type: "node",
|
|
20158
|
+
parentTxOut: splitNodeOutput,
|
|
20159
|
+
leafId: node.id,
|
|
20062
20160
|
keyDerivation,
|
|
20063
|
-
|
|
20064
|
-
verifyingKey: response.refundTxSigningResult.verifyingKey,
|
|
20065
|
-
selfCommitment: newCpfpRefundSigningJob.signingNonceCommitment,
|
|
20066
|
-
statechainCommitments: response.refundTxSigningResult.signingResult?.signingNonceCommitments,
|
|
20067
|
-
adaptorPubKey: new Uint8Array()
|
|
20161
|
+
verifyingKey: node.verifyingPublicKey
|
|
20068
20162
|
});
|
|
20069
|
-
|
|
20070
|
-
|
|
20071
|
-
|
|
20072
|
-
|
|
20073
|
-
|
|
20074
|
-
|
|
20075
|
-
|
|
20076
|
-
|
|
20077
|
-
selfSignature: cpfpRefundUserSig,
|
|
20078
|
-
adaptorPubKey: new Uint8Array()
|
|
20079
|
-
});
|
|
20080
|
-
let directRefundSig;
|
|
20081
|
-
if (directRefundSighash && newDirectRefundSigningJob && response.directRefundTxSigningResult) {
|
|
20082
|
-
const directRefundUserSig = await this.config.signer.signFrost({
|
|
20083
|
-
message: directRefundSighash,
|
|
20084
|
-
keyDerivation,
|
|
20085
|
-
publicKey: signingPublicKey,
|
|
20086
|
-
verifyingKey: response.directRefundTxSigningResult.verifyingKey,
|
|
20087
|
-
selfCommitment: newDirectRefundSigningJob.signingNonceCommitment,
|
|
20088
|
-
statechainCommitments: response.directRefundTxSigningResult.signingResult?.signingNonceCommitments,
|
|
20089
|
-
adaptorPubKey: new Uint8Array()
|
|
20090
|
-
});
|
|
20091
|
-
directRefundSig = await this.config.signer.aggregateFrost({
|
|
20092
|
-
message: directRefundSighash,
|
|
20093
|
-
statechainSignatures: response.directRefundTxSigningResult.signingResult?.signatureShares,
|
|
20094
|
-
statechainPublicKeys: response.directRefundTxSigningResult.signingResult?.publicKeys,
|
|
20095
|
-
verifyingKey: response.directRefundTxSigningResult.verifyingKey,
|
|
20096
|
-
statechainCommitments: response.directRefundTxSigningResult.signingResult?.signingNonceCommitments,
|
|
20097
|
-
selfCommitment: newDirectRefundSigningJob.signingNonceCommitment,
|
|
20098
|
-
publicKey: signingPublicKey,
|
|
20099
|
-
selfSignature: directRefundUserSig,
|
|
20100
|
-
adaptorPubKey: new Uint8Array()
|
|
20101
|
-
});
|
|
20102
|
-
}
|
|
20103
|
-
let directFromCpfpRefundSig;
|
|
20104
|
-
if (directFromCpfpRefundSighash && newDirectFromCpfpRefundSigningJob && response.directFromCpfpRefundTxSigningResult) {
|
|
20105
|
-
const directFromCpfpRefundUserSig = await this.config.signer.signFrost({
|
|
20106
|
-
message: directFromCpfpRefundSighash,
|
|
20163
|
+
if (newDirectNodeTx) {
|
|
20164
|
+
signingJobs.push({
|
|
20165
|
+
signingPublicKey,
|
|
20166
|
+
rawTx: newDirectNodeTx.toBytes(),
|
|
20167
|
+
signingNonceCommitment: await this.config.signer.getRandomSigningCommitment(),
|
|
20168
|
+
type: "directNode",
|
|
20169
|
+
parentTxOut: splitNodeOutput,
|
|
20170
|
+
leafId: node.id,
|
|
20107
20171
|
keyDerivation,
|
|
20108
|
-
|
|
20109
|
-
verifyingKey: response.directFromCpfpRefundTxSigningResult.verifyingKey,
|
|
20110
|
-
selfCommitment: newDirectFromCpfpRefundSigningJob.signingNonceCommitment,
|
|
20111
|
-
statechainCommitments: response.directFromCpfpRefundTxSigningResult.signingResult?.signingNonceCommitments,
|
|
20112
|
-
adaptorPubKey: new Uint8Array()
|
|
20113
|
-
});
|
|
20114
|
-
directFromCpfpRefundSig = await this.config.signer.aggregateFrost({
|
|
20115
|
-
message: directFromCpfpRefundSighash,
|
|
20116
|
-
statechainSignatures: response.directFromCpfpRefundTxSigningResult.signingResult?.signatureShares,
|
|
20117
|
-
statechainPublicKeys: response.directFromCpfpRefundTxSigningResult.signingResult?.publicKeys,
|
|
20118
|
-
verifyingKey: response.directFromCpfpRefundTxSigningResult.verifyingKey,
|
|
20119
|
-
statechainCommitments: response.directFromCpfpRefundTxSigningResult.signingResult?.signingNonceCommitments,
|
|
20120
|
-
selfCommitment: newDirectFromCpfpRefundSigningJob.signingNonceCommitment,
|
|
20121
|
-
publicKey: signingPublicKey,
|
|
20122
|
-
selfSignature: directFromCpfpRefundUserSig,
|
|
20123
|
-
adaptorPubKey: new Uint8Array()
|
|
20124
|
-
});
|
|
20125
|
-
}
|
|
20126
|
-
return await sparkClient.finalize_node_signatures_v2({
|
|
20127
|
-
intent: 4 /* EXTEND */,
|
|
20128
|
-
nodeSignatures: [
|
|
20129
|
-
{
|
|
20130
|
-
nodeId: response.leafId,
|
|
20131
|
-
nodeTxSignature: nodeSig,
|
|
20132
|
-
directNodeTxSignature: directNodeSig,
|
|
20133
|
-
refundTxSignature: cpfpRefundSig,
|
|
20134
|
-
directRefundTxSignature: directRefundSig,
|
|
20135
|
-
directFromCpfpRefundTxSignature: directFromCpfpRefundSig
|
|
20136
|
-
}
|
|
20137
|
-
]
|
|
20138
|
-
});
|
|
20139
|
-
}
|
|
20140
|
-
async testonly_expireTimeLockNodeTx(node, parentNode) {
|
|
20141
|
-
return await this.refreshTimelockNodesInternal(node, parentNode, true);
|
|
20142
|
-
}
|
|
20143
|
-
async testonly_expireTimeLockRefundtx(node) {
|
|
20144
|
-
const nodeTx = getTxFromRawTxBytes(node.nodeTx);
|
|
20145
|
-
const directNodeTx = node.directTx.length > 0 ? getTxFromRawTxBytes(node.directTx) : void 0;
|
|
20146
|
-
const cpfpRefundTx = getTxFromRawTxBytes(node.refundTx);
|
|
20147
|
-
const currSequence = cpfpRefundTx.getInput(0).sequence || 0;
|
|
20148
|
-
const currTimelock = getCurrentTimelock(currSequence);
|
|
20149
|
-
if (currTimelock <= 100) {
|
|
20150
|
-
throw new ValidationError("Cannot expire timelock below 100", {
|
|
20151
|
-
field: "currTimelock",
|
|
20152
|
-
value: currTimelock,
|
|
20153
|
-
expected: "Timelock greater than 100"
|
|
20172
|
+
verifyingKey: node.verifyingPublicKey
|
|
20154
20173
|
});
|
|
20155
20174
|
}
|
|
20156
|
-
const
|
|
20157
|
-
|
|
20158
|
-
|
|
20159
|
-
if (!nodeOutput) {
|
|
20160
|
-
throw Error("Could not get node output");
|
|
20161
|
-
}
|
|
20162
|
-
const keyDerivation = {
|
|
20163
|
-
type: "leaf" /* LEAF */,
|
|
20164
|
-
path: node.id
|
|
20165
|
-
};
|
|
20166
|
-
const signingPublicKey = await this.config.signer.getPublicKeyFromDerivation(keyDerivation);
|
|
20167
|
-
const cpfpRefundOutPoint = {
|
|
20168
|
-
txid: hexToBytes3(getTxId(nodeTx)),
|
|
20169
|
-
index: 0
|
|
20170
|
-
};
|
|
20171
|
-
let directRefundOutPoint;
|
|
20172
|
-
if (directNodeTx) {
|
|
20173
|
-
directRefundOutPoint = {
|
|
20174
|
-
txid: hexToBytes3(getTxId(directNodeTx)),
|
|
20175
|
-
index: 0
|
|
20176
|
-
};
|
|
20175
|
+
const newCpfpNodeOutput = newNodeTx.getOutput(0);
|
|
20176
|
+
if (!newCpfpNodeOutput) {
|
|
20177
|
+
throw Error("Could not get new cpfp node output");
|
|
20177
20178
|
}
|
|
20179
|
+
const newDirectNodeOutput = newDirectNodeTx?.getOutput(0);
|
|
20178
20180
|
const {
|
|
20179
|
-
cpfpRefundTx:
|
|
20181
|
+
cpfpRefundTx: newRefundTx,
|
|
20180
20182
|
directRefundTx: newDirectRefundTx,
|
|
20181
20183
|
directFromCpfpRefundTx: newDirectFromCpfpRefundTx
|
|
20182
|
-
} =
|
|
20183
|
-
|
|
20184
|
-
|
|
20185
|
-
input: cpfpRefundOutPoint,
|
|
20186
|
-
directInput: directRefundOutPoint,
|
|
20187
|
-
amountSats: nodeOutput.amount,
|
|
20184
|
+
} = createInitialTimelockRefundTxs({
|
|
20185
|
+
nodeTx: newNodeTx,
|
|
20186
|
+
directNodeTx: newDirectNodeTx,
|
|
20188
20187
|
receivingPubkey: signingPublicKey,
|
|
20189
20188
|
network: this.config.getNetwork()
|
|
20190
20189
|
});
|
|
20191
|
-
const signingJobs = [];
|
|
20192
20190
|
signingJobs.push({
|
|
20193
20191
|
signingPublicKey,
|
|
20194
|
-
rawTx:
|
|
20192
|
+
rawTx: newRefundTx.toBytes(),
|
|
20195
20193
|
signingNonceCommitment: await this.config.signer.getRandomSigningCommitment(),
|
|
20196
20194
|
type: "cpfp",
|
|
20197
|
-
parentTxOut:
|
|
20195
|
+
parentTxOut: newCpfpNodeOutput,
|
|
20196
|
+
leafId: node.id,
|
|
20197
|
+
keyDerivation,
|
|
20198
|
+
verifyingKey: node.verifyingPublicKey
|
|
20198
20199
|
});
|
|
20199
|
-
|
|
20200
|
-
if (newDirectRefundTx && directNodeTxOut) {
|
|
20200
|
+
if (newDirectRefundTx && newDirectNodeOutput) {
|
|
20201
20201
|
signingJobs.push({
|
|
20202
20202
|
signingPublicKey,
|
|
20203
20203
|
rawTx: newDirectRefundTx.toBytes(),
|
|
20204
20204
|
signingNonceCommitment: await this.config.signer.getRandomSigningCommitment(),
|
|
20205
20205
|
type: "direct",
|
|
20206
|
-
parentTxOut:
|
|
20206
|
+
parentTxOut: newDirectNodeOutput,
|
|
20207
|
+
leafId: node.id,
|
|
20208
|
+
keyDerivation,
|
|
20209
|
+
verifyingKey: node.verifyingPublicKey
|
|
20207
20210
|
});
|
|
20208
20211
|
}
|
|
20209
|
-
if (newDirectFromCpfpRefundTx) {
|
|
20212
|
+
if (newDirectFromCpfpRefundTx && newDirectNodeOutput) {
|
|
20210
20213
|
signingJobs.push({
|
|
20211
20214
|
signingPublicKey,
|
|
20212
20215
|
rawTx: newDirectFromCpfpRefundTx.toBytes(),
|
|
20213
20216
|
signingNonceCommitment: await this.config.signer.getRandomSigningCommitment(),
|
|
20214
20217
|
type: "directFromCpfp",
|
|
20215
|
-
parentTxOut:
|
|
20218
|
+
parentTxOut: newCpfpNodeOutput,
|
|
20219
|
+
leafId: node.id,
|
|
20220
|
+
keyDerivation,
|
|
20221
|
+
verifyingKey: node.verifyingPublicKey
|
|
20216
20222
|
});
|
|
20217
20223
|
}
|
|
20224
|
+
return signingJobs;
|
|
20225
|
+
}
|
|
20226
|
+
async renewZeroTimelockNodeTxn(node) {
|
|
20218
20227
|
const sparkClient = await this.connectionManager.createSparkClient(
|
|
20219
20228
|
this.config.getCoordinatorAddress()
|
|
20220
20229
|
);
|
|
20221
|
-
const
|
|
20222
|
-
|
|
20223
|
-
|
|
20224
|
-
|
|
20230
|
+
const signingJobs = await this.createRenewZeroTimelockNodeSigningJobs(node);
|
|
20231
|
+
const statechainCommitments = await sparkClient.get_signing_commitments({
|
|
20232
|
+
nodeIds: [node.id],
|
|
20233
|
+
count: signingJobs.length
|
|
20225
20234
|
});
|
|
20226
|
-
|
|
20227
|
-
|
|
20228
|
-
|
|
20229
|
-
|
|
20230
|
-
|
|
20231
|
-
|
|
20232
|
-
|
|
20233
|
-
let directFromCpfpRefundSignature;
|
|
20234
|
-
for (const [i, signingJob] of signingJobs.entries()) {
|
|
20235
|
-
const signingResult = response.signingResults[i];
|
|
20236
|
-
if (!signingResult) {
|
|
20237
|
-
throw Error("Signing result does not exist");
|
|
20235
|
+
const mappedSigningJobs = signingJobs.map((signingJob, index) => {
|
|
20236
|
+
const signingNonceCommitments = statechainCommitments.signingCommitments[index]?.signingNonceCommitments;
|
|
20237
|
+
if (!signingNonceCommitments) {
|
|
20238
|
+
throw new ValidationError("Signing nonce commitments not found", {
|
|
20239
|
+
field: "signingNonceCommitments",
|
|
20240
|
+
value: signingNonceCommitments
|
|
20241
|
+
});
|
|
20238
20242
|
}
|
|
20239
|
-
|
|
20240
|
-
|
|
20241
|
-
|
|
20242
|
-
|
|
20243
|
-
|
|
20244
|
-
|
|
20245
|
-
|
|
20246
|
-
|
|
20247
|
-
|
|
20248
|
-
|
|
20249
|
-
|
|
20250
|
-
|
|
20251
|
-
|
|
20252
|
-
|
|
20253
|
-
|
|
20254
|
-
|
|
20255
|
-
|
|
20256
|
-
|
|
20257
|
-
selfCommitment: signingJob.signingNonceCommitment,
|
|
20258
|
-
publicKey: signingPublicKey,
|
|
20259
|
-
selfSignature: userSignature,
|
|
20260
|
-
adaptorPubKey: new Uint8Array()
|
|
20261
|
-
});
|
|
20262
|
-
if (signingJob.type === "cpfp") {
|
|
20263
|
-
cpfpRefundSignature = signature;
|
|
20264
|
-
} else if (signingJob.type === "direct") {
|
|
20265
|
-
directRefundSignature = signature;
|
|
20266
|
-
} else if (signingJob.type === "directFromCpfp") {
|
|
20267
|
-
directFromCpfpRefundSignature = signature;
|
|
20243
|
+
return {
|
|
20244
|
+
...signingJob,
|
|
20245
|
+
signingNonceCommitments
|
|
20246
|
+
};
|
|
20247
|
+
});
|
|
20248
|
+
const userSignedTxSigningJobs = await this.signingService.signSigningJobs(mappedSigningJobs);
|
|
20249
|
+
const renewZeroTimelockNodeSigningJob = {
|
|
20250
|
+
nodeTxSigningJob: userSignedTxSigningJobs.get("node"),
|
|
20251
|
+
refundTxSigningJob: userSignedTxSigningJobs.get("cpfp"),
|
|
20252
|
+
directNodeTxSigningJob: userSignedTxSigningJobs.get("directNode"),
|
|
20253
|
+
directRefundTxSigningJob: void 0,
|
|
20254
|
+
directFromCpfpRefundTxSigningJob: userSignedTxSigningJobs.get("directFromCpfp")
|
|
20255
|
+
};
|
|
20256
|
+
const response = await sparkClient.renew_leaf({
|
|
20257
|
+
leafId: node.id,
|
|
20258
|
+
signingJobs: {
|
|
20259
|
+
$case: "renewNodeZeroTimelockSigningJob",
|
|
20260
|
+
renewNodeZeroTimelockSigningJob: renewZeroTimelockNodeSigningJob
|
|
20268
20261
|
}
|
|
20262
|
+
});
|
|
20263
|
+
if (response.renewResult?.$case !== "renewNodeZeroTimelockResult" || !response.renewResult?.renewNodeZeroTimelockResult.node) {
|
|
20264
|
+
throw new ValidationError("Unexpected renew result", {
|
|
20265
|
+
field: "renewResult",
|
|
20266
|
+
value: response.renewResult
|
|
20267
|
+
});
|
|
20269
20268
|
}
|
|
20270
|
-
|
|
20271
|
-
|
|
20272
|
-
|
|
20273
|
-
|
|
20274
|
-
|
|
20275
|
-
|
|
20276
|
-
|
|
20277
|
-
|
|
20278
|
-
|
|
20279
|
-
|
|
20280
|
-
|
|
20281
|
-
|
|
20269
|
+
return response.renewResult.renewNodeZeroTimelockResult.node;
|
|
20270
|
+
}
|
|
20271
|
+
async createRenewZeroTimelockNodeSigningJobs(node) {
|
|
20272
|
+
const signingJobs = [];
|
|
20273
|
+
const keyDerivation = {
|
|
20274
|
+
type: "leaf" /* LEAF */,
|
|
20275
|
+
path: node.id
|
|
20276
|
+
};
|
|
20277
|
+
const signingPublicKey = await this.config.signer.getPublicKeyFromDerivation(keyDerivation);
|
|
20278
|
+
const nodeTx = getTxFromRawTxBytes(node.nodeTx);
|
|
20279
|
+
const { nodeTx: newNodeTx, directNodeTx: newDirectNodeTx } = createZeroTimelockNodeTx(nodeTx);
|
|
20280
|
+
signingJobs.push({
|
|
20281
|
+
signingPublicKey,
|
|
20282
|
+
rawTx: newNodeTx.toBytes(),
|
|
20283
|
+
signingNonceCommitment: await this.config.signer.getRandomSigningCommitment(),
|
|
20284
|
+
type: "node",
|
|
20285
|
+
parentTxOut: nodeTx.getOutput(0),
|
|
20286
|
+
leafId: node.id,
|
|
20287
|
+
keyDerivation,
|
|
20288
|
+
verifyingKey: node.verifyingPublicKey
|
|
20282
20289
|
});
|
|
20283
|
-
|
|
20290
|
+
signingJobs.push({
|
|
20291
|
+
signingPublicKey,
|
|
20292
|
+
rawTx: newDirectNodeTx.toBytes(),
|
|
20293
|
+
signingNonceCommitment: await this.config.signer.getRandomSigningCommitment(),
|
|
20294
|
+
type: "directNode",
|
|
20295
|
+
parentTxOut: nodeTx.getOutput(0),
|
|
20296
|
+
leafId: node.id,
|
|
20297
|
+
keyDerivation,
|
|
20298
|
+
verifyingKey: node.verifyingPublicKey
|
|
20299
|
+
});
|
|
20300
|
+
const { cpfpRefundTx, directFromCpfpRefundTx } = createInitialTimelockRefundTxs({
|
|
20301
|
+
nodeTx: newNodeTx,
|
|
20302
|
+
directNodeTx: newDirectNodeTx,
|
|
20303
|
+
receivingPubkey: signingPublicKey,
|
|
20304
|
+
network: this.config.getNetwork()
|
|
20305
|
+
});
|
|
20306
|
+
signingJobs.push({
|
|
20307
|
+
signingPublicKey,
|
|
20308
|
+
rawTx: cpfpRefundTx.toBytes(),
|
|
20309
|
+
signingNonceCommitment: await this.config.signer.getRandomSigningCommitment(),
|
|
20310
|
+
type: "cpfp",
|
|
20311
|
+
parentTxOut: newNodeTx.getOutput(0),
|
|
20312
|
+
leafId: node.id,
|
|
20313
|
+
keyDerivation,
|
|
20314
|
+
verifyingKey: node.verifyingPublicKey
|
|
20315
|
+
});
|
|
20316
|
+
if (!directFromCpfpRefundTx) {
|
|
20317
|
+
throw new Error("Could not create direct refund transactions");
|
|
20318
|
+
}
|
|
20319
|
+
signingJobs.push({
|
|
20320
|
+
signingPublicKey,
|
|
20321
|
+
rawTx: directFromCpfpRefundTx.toBytes(),
|
|
20322
|
+
signingNonceCommitment: await this.config.signer.getRandomSigningCommitment(),
|
|
20323
|
+
type: "directFromCpfp",
|
|
20324
|
+
parentTxOut: newNodeTx.getOutput(0),
|
|
20325
|
+
leafId: node.id,
|
|
20326
|
+
keyDerivation,
|
|
20327
|
+
verifyingKey: node.verifyingPublicKey
|
|
20328
|
+
});
|
|
20329
|
+
return signingJobs;
|
|
20284
20330
|
}
|
|
20285
20331
|
};
|
|
20286
20332
|
|
|
@@ -20322,71 +20368,6 @@ var CoopExitService = class extends BaseTransferService {
|
|
|
20322
20368
|
directFromCpfpSignaturesMap
|
|
20323
20369
|
};
|
|
20324
20370
|
}
|
|
20325
|
-
createConnectorRefundTransactions(sequence, directSequence, cpfpNodeOutPoint, directNodeOutPoint, connectorOutput, amountSats, receiverPubKey) {
|
|
20326
|
-
const cpfpRefundTx = new Transaction4();
|
|
20327
|
-
if (!cpfpNodeOutPoint.txid || cpfpNodeOutPoint.index === void 0) {
|
|
20328
|
-
throw new ValidationError("Invalid CPFP node outpoint", {
|
|
20329
|
-
field: "cpfpNodeOutPoint",
|
|
20330
|
-
value: { txid: cpfpNodeOutPoint.txid, index: cpfpNodeOutPoint.index },
|
|
20331
|
-
expected: "Both txid and index must be defined"
|
|
20332
|
-
});
|
|
20333
|
-
}
|
|
20334
|
-
cpfpRefundTx.addInput({
|
|
20335
|
-
txid: cpfpNodeOutPoint.txid,
|
|
20336
|
-
index: cpfpNodeOutPoint.index,
|
|
20337
|
-
sequence
|
|
20338
|
-
});
|
|
20339
|
-
cpfpRefundTx.addInput(connectorOutput);
|
|
20340
|
-
const receiverScript = getP2TRScriptFromPublicKey(
|
|
20341
|
-
receiverPubKey,
|
|
20342
|
-
this.config.getNetwork()
|
|
20343
|
-
);
|
|
20344
|
-
cpfpRefundTx.addOutput({
|
|
20345
|
-
script: receiverScript,
|
|
20346
|
-
amount: amountSats
|
|
20347
|
-
});
|
|
20348
|
-
let directRefundTx;
|
|
20349
|
-
let directFromCpfpRefundTx;
|
|
20350
|
-
if (directNodeOutPoint) {
|
|
20351
|
-
if (!directNodeOutPoint.txid || directNodeOutPoint.index === void 0) {
|
|
20352
|
-
throw new ValidationError("Invalid direct node outpoint", {
|
|
20353
|
-
field: "directNodeOutPoint",
|
|
20354
|
-
value: {
|
|
20355
|
-
txid: directNodeOutPoint.txid,
|
|
20356
|
-
index: directNodeOutPoint.index
|
|
20357
|
-
},
|
|
20358
|
-
expected: "Both txid and index must be defined"
|
|
20359
|
-
});
|
|
20360
|
-
}
|
|
20361
|
-
directRefundTx = new Transaction4();
|
|
20362
|
-
directRefundTx.addInput({
|
|
20363
|
-
txid: directNodeOutPoint.txid,
|
|
20364
|
-
index: directNodeOutPoint.index,
|
|
20365
|
-
sequence: directSequence
|
|
20366
|
-
});
|
|
20367
|
-
directRefundTx.addInput(connectorOutput);
|
|
20368
|
-
directRefundTx.addOutput({
|
|
20369
|
-
script: receiverScript,
|
|
20370
|
-
amount: maybeApplyFee(amountSats)
|
|
20371
|
-
});
|
|
20372
|
-
directFromCpfpRefundTx = new Transaction4();
|
|
20373
|
-
directFromCpfpRefundTx.addInput({
|
|
20374
|
-
txid: cpfpNodeOutPoint.txid,
|
|
20375
|
-
index: cpfpNodeOutPoint.index,
|
|
20376
|
-
sequence: directSequence
|
|
20377
|
-
});
|
|
20378
|
-
directFromCpfpRefundTx.addInput(connectorOutput);
|
|
20379
|
-
directFromCpfpRefundTx.addOutput({
|
|
20380
|
-
script: receiverScript,
|
|
20381
|
-
amount: maybeApplyFee(amountSats)
|
|
20382
|
-
});
|
|
20383
|
-
}
|
|
20384
|
-
return {
|
|
20385
|
-
cpfpRefundTx,
|
|
20386
|
-
directRefundTx,
|
|
20387
|
-
directFromCpfpRefundTx
|
|
20388
|
-
};
|
|
20389
|
-
}
|
|
20390
20371
|
async signCoopExitRefunds(leaves, exitTxId, connectorOutputs, receiverPubKey, transferId) {
|
|
20391
20372
|
if (leaves.length !== connectorOutputs.length) {
|
|
20392
20373
|
throw new ValidationError(
|
|
@@ -20420,29 +20401,39 @@ var CoopExitService = class extends BaseTransferService {
|
|
|
20420
20401
|
expected: "Valid connector output"
|
|
20421
20402
|
});
|
|
20422
20403
|
}
|
|
20404
|
+
const nodeTx = getTxFromRawTxBytes(leaf.leaf.nodeTx);
|
|
20405
|
+
let directNodeTx;
|
|
20406
|
+
if (leaf.leaf.directTx.length > 0) {
|
|
20407
|
+
directNodeTx = getTxFromRawTxBytes(leaf.leaf.directTx);
|
|
20408
|
+
}
|
|
20423
20409
|
const currentRefundTx = getTxFromRawTxBytes(leaf.leaf.refundTx);
|
|
20424
|
-
|
|
20425
|
-
|
|
20410
|
+
if (!currentRefundTx) {
|
|
20411
|
+
throw new ValidationError("Invalid refund transaction", {
|
|
20412
|
+
field: "currentRefundTx",
|
|
20413
|
+
value: currentRefundTx,
|
|
20414
|
+
expected: "Non-null refund transaction"
|
|
20415
|
+
});
|
|
20416
|
+
}
|
|
20417
|
+
const currentSequence = currentRefundTx.getInput(0).sequence;
|
|
20418
|
+
if (!currentSequence) {
|
|
20426
20419
|
throw new ValidationError("Invalid refund transaction", {
|
|
20427
20420
|
field: "sequence",
|
|
20428
20421
|
value: currentRefundTx.getInput(0),
|
|
20429
20422
|
expected: "Non-null sequence"
|
|
20430
20423
|
});
|
|
20431
20424
|
}
|
|
20432
|
-
const { nextSequence, nextDirectSequence } = getNextTransactionSequence(sequence);
|
|
20433
20425
|
let currentDirectRefundTx;
|
|
20434
20426
|
if (leaf.leaf.directRefundTx.length > 0) {
|
|
20435
20427
|
currentDirectRefundTx = getTxFromRawTxBytes(leaf.leaf.directRefundTx);
|
|
20436
20428
|
}
|
|
20437
|
-
const { cpfpRefundTx, directRefundTx, directFromCpfpRefundTx } =
|
|
20438
|
-
|
|
20439
|
-
|
|
20440
|
-
|
|
20441
|
-
currentDirectRefundTx?.getInput(0),
|
|
20429
|
+
const { cpfpRefundTx, directRefundTx, directFromCpfpRefundTx } = createConnectorRefundTxs({
|
|
20430
|
+
nodeTx,
|
|
20431
|
+
directNodeTx,
|
|
20432
|
+
sequence: currentSequence,
|
|
20442
20433
|
connectorOutput,
|
|
20443
|
-
|
|
20444
|
-
|
|
20445
|
-
);
|
|
20434
|
+
receivingPubkey: receiverPubKey,
|
|
20435
|
+
network: this.config.getNetwork()
|
|
20436
|
+
});
|
|
20446
20437
|
const signingNonceCommitment = await this.config.signer.getRandomSigningCommitment();
|
|
20447
20438
|
const directSigningNonceCommitment = await this.config.signer.getRandomSigningCommitment();
|
|
20448
20439
|
const directFromCpfpSigningNonceCommitment = await this.config.signer.getRandomSigningCommitment();
|
|
@@ -20834,38 +20825,18 @@ var DepositService = class {
|
|
|
20834
20825
|
expected: "Valid output index"
|
|
20835
20826
|
});
|
|
20836
20827
|
}
|
|
20837
|
-
const
|
|
20838
|
-
|
|
20839
|
-
|
|
20840
|
-
throw new ValidationError("No script or amount found in deposit tx", {
|
|
20841
|
-
field: "output",
|
|
20842
|
-
value: output,
|
|
20843
|
-
expected: "Output with script and amount"
|
|
20844
|
-
});
|
|
20845
|
-
}
|
|
20846
|
-
const depositOutPoint = {
|
|
20847
|
-
txid: hexToBytes4(getTxId(depositTx)),
|
|
20848
|
-
index: vout
|
|
20849
|
-
};
|
|
20850
|
-
const depositTxOut = {
|
|
20851
|
-
script,
|
|
20852
|
-
amount
|
|
20853
|
-
};
|
|
20854
|
-
const [cpfpRootTx, directRootTx] = createRootTx(
|
|
20855
|
-
depositOutPoint,
|
|
20856
|
-
depositTxOut
|
|
20828
|
+
const { nodeTx: cpfpRootTx, directNodeTx: directRootTx } = createRootNodeTx(
|
|
20829
|
+
depositTx,
|
|
20830
|
+
vout
|
|
20857
20831
|
);
|
|
20858
20832
|
const cpfpRootNonceCommitment = await this.config.signer.getRandomSigningCommitment();
|
|
20859
20833
|
const directRootNonceCommitment = await this.config.signer.getRandomSigningCommitment();
|
|
20860
20834
|
const cpfpRootTxSighash = getSigHashFromTx(cpfpRootTx, 0, output);
|
|
20861
20835
|
const directRootTxSighash = getSigHashFromTx(directRootTx, 0, output);
|
|
20862
20836
|
const signingPubKey = await this.config.signer.getPublicKeyFromDerivation(keyDerivation);
|
|
20863
|
-
const { cpfpRefundTx, directRefundTx, directFromCpfpRefundTx } =
|
|
20864
|
-
|
|
20865
|
-
|
|
20866
|
-
input: { txid: hexToBytes4(getTxId(cpfpRootTx)), index: 0 },
|
|
20867
|
-
directInput: { txid: hexToBytes4(getTxId(directRootTx)), index: 0 },
|
|
20868
|
-
amountSats: amount,
|
|
20837
|
+
const { cpfpRefundTx, directRefundTx, directFromCpfpRefundTx } = createInitialTimelockRefundTxs({
|
|
20838
|
+
nodeTx: cpfpRootTx,
|
|
20839
|
+
directNodeTx: directRootTx,
|
|
20869
20840
|
receivingPubkey: signingPubKey,
|
|
20870
20841
|
network: this.config.getNetwork()
|
|
20871
20842
|
});
|
|
@@ -21157,22 +21128,12 @@ var DepositService = class {
|
|
|
21157
21128
|
expected: "Output with script and amount"
|
|
21158
21129
|
});
|
|
21159
21130
|
}
|
|
21160
|
-
const
|
|
21161
|
-
txid: hexToBytes4(getTxId(depositTx)),
|
|
21162
|
-
index: vout
|
|
21163
|
-
};
|
|
21164
|
-
const depositTxOut = {
|
|
21165
|
-
script,
|
|
21166
|
-
amount
|
|
21167
|
-
};
|
|
21168
|
-
const [cpfpRootTx, _] = createRootTx(depositOutPoint, depositTxOut);
|
|
21131
|
+
const { nodeTx: cpfpRootTx } = createRootNodeTx(depositTx, vout);
|
|
21169
21132
|
const cpfpRootNonceCommitment = await this.config.signer.getRandomSigningCommitment();
|
|
21170
21133
|
const cpfpRootTxSighash = getSigHashFromTx(cpfpRootTx, 0, output);
|
|
21171
21134
|
const signingPubKey = await this.config.signer.getPublicKeyFromDerivation(keyDerivation);
|
|
21172
|
-
const { cpfpRefundTx } =
|
|
21173
|
-
|
|
21174
|
-
input: { txid: hexToBytes4(getTxId(cpfpRootTx)), index: 0 },
|
|
21175
|
-
amountSats: amount,
|
|
21135
|
+
const { cpfpRefundTx } = createInitialTimelockRefundTxs({
|
|
21136
|
+
nodeTx: cpfpRootTx,
|
|
21176
21137
|
receivingPubkey: signingPubKey,
|
|
21177
21138
|
network: this.config.getNetwork()
|
|
21178
21139
|
});
|
|
@@ -27186,7 +27147,7 @@ var isWebExtension = (
|
|
|
27186
27147
|
"chrome" in globalThis && globalThis.chrome.runtime?.id
|
|
27187
27148
|
);
|
|
27188
27149
|
var userAgent = "navigator" in globalThis ? globalThis.navigator.userAgent || "unknown-user-agent" : void 0;
|
|
27189
|
-
var packageVersion = true ? "0.
|
|
27150
|
+
var packageVersion = true ? "0.4.0" : "unknown";
|
|
27190
27151
|
var baseEnvStr = "unknown";
|
|
27191
27152
|
if (isBun) {
|
|
27192
27153
|
const bunVersion = "version" in globalThis.Bun ? globalThis.Bun.version : "unknown-version";
|
|
@@ -27207,12 +27168,9 @@ if (isBun) {
|
|
|
27207
27168
|
}
|
|
27208
27169
|
var clientEnv = `js-spark-sdk/${packageVersion} ${baseEnvStr}`;
|
|
27209
27170
|
|
|
27210
|
-
// src/services/signing.ts
|
|
27211
|
-
import { hexToBytes as hexToBytes9 } from "@noble/curves/utils";
|
|
27212
|
-
|
|
27213
27171
|
// src/utils/htlc-transactions.ts
|
|
27214
27172
|
import {
|
|
27215
|
-
Transaction as
|
|
27173
|
+
Transaction as Transaction4,
|
|
27216
27174
|
Script,
|
|
27217
27175
|
taprootListToTree,
|
|
27218
27176
|
p2tr as p2tr3,
|
|
@@ -27300,7 +27258,7 @@ function createLightningHTLCTransaction({
|
|
|
27300
27258
|
txid: hexToBytes8(getTxId(nodeTx)),
|
|
27301
27259
|
index: 0
|
|
27302
27260
|
};
|
|
27303
|
-
const htlcTransaction = new
|
|
27261
|
+
const htlcTransaction = new Transaction4({
|
|
27304
27262
|
version: 3,
|
|
27305
27263
|
allowUnknownOutputs: true
|
|
27306
27264
|
});
|
|
@@ -27419,20 +27377,7 @@ var SigningService = class {
|
|
|
27419
27377
|
});
|
|
27420
27378
|
}
|
|
27421
27379
|
const nodeTx = getTxFromRawTxBytes(leaf.leaf.nodeTx);
|
|
27422
|
-
const cpfpNodeOutPoint = {
|
|
27423
|
-
txid: hexToBytes9(getTxId(nodeTx)),
|
|
27424
|
-
index: 0
|
|
27425
|
-
};
|
|
27426
27380
|
const currRefundTx = getTxFromRawTxBytes(leaf.leaf.refundTx);
|
|
27427
|
-
const sequence = currRefundTx.getInput(0).sequence;
|
|
27428
|
-
if (!sequence) {
|
|
27429
|
-
throw new ValidationError("Invalid refund transaction", {
|
|
27430
|
-
field: "sequence",
|
|
27431
|
-
value: currRefundTx.getInput(0),
|
|
27432
|
-
expected: "Non-null sequence"
|
|
27433
|
-
});
|
|
27434
|
-
}
|
|
27435
|
-
const { nextSequence, nextDirectSequence } = getNextTransactionSequence(sequence);
|
|
27436
27381
|
const amountSats = currRefundTx.getOutput(0).amount;
|
|
27437
27382
|
if (amountSats === void 0) {
|
|
27438
27383
|
throw new ValidationError("Invalid refund transaction", {
|
|
@@ -27442,20 +27387,21 @@ var SigningService = class {
|
|
|
27442
27387
|
});
|
|
27443
27388
|
}
|
|
27444
27389
|
let directNodeTx;
|
|
27445
|
-
let directNodeOutPoint;
|
|
27446
27390
|
if (leaf.leaf.directTx.length > 0) {
|
|
27447
27391
|
directNodeTx = getTxFromRawTxBytes(leaf.leaf.directTx);
|
|
27448
|
-
directNodeOutPoint = {
|
|
27449
|
-
txid: hexToBytes9(getTxId(directNodeTx)),
|
|
27450
|
-
index: 0
|
|
27451
|
-
};
|
|
27452
27392
|
}
|
|
27453
|
-
const
|
|
27454
|
-
|
|
27455
|
-
|
|
27456
|
-
|
|
27457
|
-
|
|
27458
|
-
|
|
27393
|
+
const currentSequence = currRefundTx.getInput(0).sequence;
|
|
27394
|
+
if (!currentSequence) {
|
|
27395
|
+
throw new ValidationError("Invalid refund transaction", {
|
|
27396
|
+
field: "sequence",
|
|
27397
|
+
value: currRefundTx.getInput(0),
|
|
27398
|
+
expected: "Non-null sequence"
|
|
27399
|
+
});
|
|
27400
|
+
}
|
|
27401
|
+
const { cpfpRefundTx, directRefundTx, directFromCpfpRefundTx } = createDecrementedTimelockRefundTxs({
|
|
27402
|
+
nodeTx,
|
|
27403
|
+
directNodeTx,
|
|
27404
|
+
sequence: currentSequence,
|
|
27459
27405
|
receivingPubkey: receiverIdentityPubkey,
|
|
27460
27406
|
network: this.config.getNetwork()
|
|
27461
27407
|
});
|
|
@@ -27471,7 +27417,8 @@ var SigningService = class {
|
|
|
27471
27417
|
cpfpSigningCommitments[i]?.signingNonceCommitments
|
|
27472
27418
|
);
|
|
27473
27419
|
cpfpLeafSigningJobs.push(...signingJobs);
|
|
27474
|
-
|
|
27420
|
+
const isZeroNode = getCurrentTimelock(nodeTx.getInput(0).sequence);
|
|
27421
|
+
if (directRefundTx && !isZeroNode) {
|
|
27475
27422
|
if (!directNodeTx) {
|
|
27476
27423
|
throw new ValidationError(
|
|
27477
27424
|
"Direct node transaction undefined while direct refund transaction is defined",
|
|
@@ -27496,16 +27443,6 @@ var SigningService = class {
|
|
|
27496
27443
|
directLeafSigningJobs.push(...signingJobs2);
|
|
27497
27444
|
}
|
|
27498
27445
|
if (directFromCpfpRefundTx) {
|
|
27499
|
-
if (!directNodeTx) {
|
|
27500
|
-
throw new ValidationError(
|
|
27501
|
-
"Direct node transaction undefined while direct from CPFP refund transaction is defined",
|
|
27502
|
-
{
|
|
27503
|
-
field: "directNodeTx",
|
|
27504
|
-
value: directNodeTx,
|
|
27505
|
-
expected: "Non-null direct node transaction"
|
|
27506
|
-
}
|
|
27507
|
-
);
|
|
27508
|
-
}
|
|
27509
27446
|
const refundSighash2 = getSigHashFromTx(
|
|
27510
27447
|
directFromCpfpRefundTx,
|
|
27511
27448
|
0,
|
|
@@ -27632,6 +27569,35 @@ var SigningService = class {
|
|
|
27632
27569
|
directFromCpfpLeafSigningJobs
|
|
27633
27570
|
};
|
|
27634
27571
|
}
|
|
27572
|
+
async signSigningJobs(signingJobs) {
|
|
27573
|
+
const userSignedTxSigningJobs = /* @__PURE__ */ new Map();
|
|
27574
|
+
for (const signingJob of signingJobs) {
|
|
27575
|
+
const rawTx = getTxFromRawTxBytes(signingJob.rawTx);
|
|
27576
|
+
const txOut = signingJob.parentTxOut;
|
|
27577
|
+
const rawTxSighash = getSigHashFromTx(rawTx, 0, txOut);
|
|
27578
|
+
const userSignature = await this.config.signer.signFrost({
|
|
27579
|
+
message: rawTxSighash,
|
|
27580
|
+
keyDerivation: signingJob.keyDerivation,
|
|
27581
|
+
publicKey: signingJob.signingPublicKey,
|
|
27582
|
+
verifyingKey: signingJob.verifyingKey,
|
|
27583
|
+
selfCommitment: signingJob.signingNonceCommitment,
|
|
27584
|
+
statechainCommitments: signingJob.signingNonceCommitments,
|
|
27585
|
+
adaptorPubKey: new Uint8Array()
|
|
27586
|
+
});
|
|
27587
|
+
const userSignedTxSigningJob = {
|
|
27588
|
+
leafId: signingJob.leafId,
|
|
27589
|
+
signingPublicKey: signingJob.signingPublicKey,
|
|
27590
|
+
rawTx: rawTx.toBytes(),
|
|
27591
|
+
signingNonceCommitment: signingJob.signingNonceCommitment.commitment,
|
|
27592
|
+
signingCommitments: {
|
|
27593
|
+
signingCommitments: signingJob.signingNonceCommitments
|
|
27594
|
+
},
|
|
27595
|
+
userSignature
|
|
27596
|
+
};
|
|
27597
|
+
userSignedTxSigningJobs.set(signingJob.type, userSignedTxSigningJob);
|
|
27598
|
+
}
|
|
27599
|
+
return userSignedTxSigningJobs;
|
|
27600
|
+
}
|
|
27635
27601
|
};
|
|
27636
27602
|
|
|
27637
27603
|
// src/signer/signer.ts
|
|
@@ -27641,7 +27607,7 @@ import {
|
|
|
27641
27607
|
bytesToHex as bytesToHex8,
|
|
27642
27608
|
bytesToNumberBE as bytesToNumberBE7,
|
|
27643
27609
|
equalBytes as equalBytes5,
|
|
27644
|
-
hexToBytes as
|
|
27610
|
+
hexToBytes as hexToBytes9
|
|
27645
27611
|
} from "@noble/curves/utils";
|
|
27646
27612
|
import { sha256 as sha25610 } from "@noble/hashes/sha2";
|
|
27647
27613
|
import { HDKey } from "@scure/bip32";
|
|
@@ -28295,7 +28261,7 @@ var DefaultSparkSigner = class {
|
|
|
28295
28261
|
}
|
|
28296
28262
|
async createSparkWalletFromSeed(seed, accountNumber) {
|
|
28297
28263
|
if (typeof seed === "string") {
|
|
28298
|
-
seed =
|
|
28264
|
+
seed = hexToBytes9(seed);
|
|
28299
28265
|
}
|
|
28300
28266
|
const {
|
|
28301
28267
|
identityKey,
|
|
@@ -28434,14 +28400,14 @@ var TaprootSparkSigner = class extends DefaultSparkSigner {
|
|
|
28434
28400
|
|
|
28435
28401
|
// src/tests/utils/test-faucet.ts
|
|
28436
28402
|
import { schnorr as schnorr6, secp256k1 as secp256k112 } from "@noble/curves/secp256k1";
|
|
28437
|
-
import { bytesToHex as bytesToHex9, hexToBytes as
|
|
28403
|
+
import { bytesToHex as bytesToHex9, hexToBytes as hexToBytes10 } from "@noble/curves/utils";
|
|
28438
28404
|
import * as btc3 from "@scure/btc-signer";
|
|
28439
|
-
import { Address as Address3, OutScript as OutScript2, SigHash as SigHash2, Transaction as
|
|
28405
|
+
import { Address as Address3, OutScript as OutScript2, SigHash as SigHash2, Transaction as Transaction5 } from "@scure/btc-signer";
|
|
28440
28406
|
import { taprootTweakPrivKey as taprootTweakPrivKey2 } from "@scure/btc-signer/utils";
|
|
28441
|
-
var STATIC_FAUCET_KEY =
|
|
28407
|
+
var STATIC_FAUCET_KEY = hexToBytes10(
|
|
28442
28408
|
"deadbeef1337cafe4242424242424242deadbeef1337cafe4242424242424242"
|
|
28443
28409
|
);
|
|
28444
|
-
var STATIC_MINING_KEY =
|
|
28410
|
+
var STATIC_MINING_KEY = hexToBytes10(
|
|
28445
28411
|
"1337cafe4242deadbeef4242424242421337cafe4242deadbeef424242424242"
|
|
28446
28412
|
);
|
|
28447
28413
|
var SATS_PER_BTC = 1e8;
|
|
@@ -28524,7 +28490,7 @@ var BitcoinFaucet = class _BitcoinFaucet {
|
|
|
28524
28490
|
);
|
|
28525
28491
|
await this.generateToAddress(1, address);
|
|
28526
28492
|
const fundingTxRaw = await this.getRawTransaction(fundingTxid);
|
|
28527
|
-
const fundingTx =
|
|
28493
|
+
const fundingTx = Transaction5.fromRaw(hexToBytes10(fundingTxRaw.hex));
|
|
28528
28494
|
for (let i = 0; i < fundingTx.outputsLength; i++) {
|
|
28529
28495
|
const output = fundingTx.getOutput(i);
|
|
28530
28496
|
if (!output.script || !output.amount) continue;
|
|
@@ -28555,7 +28521,7 @@ var BitcoinFaucet = class _BitcoinFaucet {
|
|
|
28555
28521
|
`Selected UTXO (${selectedUtxoAmountSats} sats) is too small to create even one faucet coin of ${COIN_AMOUNT} sats`
|
|
28556
28522
|
);
|
|
28557
28523
|
}
|
|
28558
|
-
const splitTx = new
|
|
28524
|
+
const splitTx = new Transaction5();
|
|
28559
28525
|
splitTx.addInput({
|
|
28560
28526
|
txid: selectedUtxo.txid,
|
|
28561
28527
|
index: selectedUtxo.vout
|
|
@@ -28590,7 +28556,7 @@ var BitcoinFaucet = class _BitcoinFaucet {
|
|
|
28590
28556
|
this.coins.push({
|
|
28591
28557
|
key: STATIC_FAUCET_KEY,
|
|
28592
28558
|
outpoint: {
|
|
28593
|
-
txid:
|
|
28559
|
+
txid: hexToBytes10(splitTxId),
|
|
28594
28560
|
index: i
|
|
28595
28561
|
},
|
|
28596
28562
|
txout: signedSplitTx.getOutput(i)
|
|
@@ -28598,7 +28564,7 @@ var BitcoinFaucet = class _BitcoinFaucet {
|
|
|
28598
28564
|
}
|
|
28599
28565
|
}
|
|
28600
28566
|
async sendFaucetCoinToP2WPKHAddress(pubKey) {
|
|
28601
|
-
const sendToPubKeyTx = new
|
|
28567
|
+
const sendToPubKeyTx = new Transaction5();
|
|
28602
28568
|
const p2wpkhAddress = btc3.p2wpkh(pubKey, getNetwork(4 /* LOCAL */)).address;
|
|
28603
28569
|
if (!p2wpkhAddress) {
|
|
28604
28570
|
throw new Error("Invalid P2WPKH address");
|
|
@@ -28653,6 +28619,14 @@ var BitcoinFaucet = class _BitcoinFaucet {
|
|
|
28653
28619
|
async mineBlocks(numBlocks) {
|
|
28654
28620
|
return await this.generateToAddress(numBlocks, this.miningAddress);
|
|
28655
28621
|
}
|
|
28622
|
+
async mineBlocksAndWaitForMiningToComplete(numBlocks) {
|
|
28623
|
+
const startBlock = await this.getBlockCount();
|
|
28624
|
+
await this.mineBlocks(numBlocks);
|
|
28625
|
+
await this.waitForBlocksMined({
|
|
28626
|
+
startBlock,
|
|
28627
|
+
expectedIncrease: numBlocks
|
|
28628
|
+
});
|
|
28629
|
+
}
|
|
28656
28630
|
async call(method, params) {
|
|
28657
28631
|
try {
|
|
28658
28632
|
const { fetch, Headers: Headers3 } = getFetch();
|
|
@@ -28705,21 +28679,56 @@ var BitcoinFaucet = class _BitcoinFaucet {
|
|
|
28705
28679
|
async getBlock(blockHash) {
|
|
28706
28680
|
return await this.call("getblock", [blockHash, 2]);
|
|
28707
28681
|
}
|
|
28682
|
+
async getBlockCount() {
|
|
28683
|
+
return await this.call("getblockcount", []);
|
|
28684
|
+
}
|
|
28685
|
+
async waitForBlocksMined({
|
|
28686
|
+
startBlock,
|
|
28687
|
+
expectedIncrease,
|
|
28688
|
+
timeoutMs = 3e4,
|
|
28689
|
+
intervalMs = 5e3
|
|
28690
|
+
}) {
|
|
28691
|
+
const deadline = Date.now() + timeoutMs;
|
|
28692
|
+
await new Promise((r) => setTimeout(r, intervalMs));
|
|
28693
|
+
const start = startBlock;
|
|
28694
|
+
const target = start + expectedIncrease;
|
|
28695
|
+
while (Date.now() < deadline) {
|
|
28696
|
+
const currentBlock = await this.getBlockCount();
|
|
28697
|
+
if (currentBlock >= target) return currentBlock;
|
|
28698
|
+
await new Promise((r) => setTimeout(r, intervalMs));
|
|
28699
|
+
}
|
|
28700
|
+
throw new Error(
|
|
28701
|
+
`Timed out waiting for ${expectedIncrease} blocks (target height ${target})`
|
|
28702
|
+
);
|
|
28703
|
+
}
|
|
28708
28704
|
async broadcastTx(txHex) {
|
|
28709
28705
|
let response = await this.call("sendrawtransaction", [txHex, 0]);
|
|
28710
28706
|
return response;
|
|
28711
28707
|
}
|
|
28708
|
+
async submitPackage(txHexs) {
|
|
28709
|
+
let response = await this.call("submitpackage", [txHexs]);
|
|
28710
|
+
return response;
|
|
28711
|
+
}
|
|
28712
28712
|
async getNewAddress() {
|
|
28713
28713
|
const key = secp256k112.utils.randomPrivateKey();
|
|
28714
28714
|
const pubKey = secp256k112.getPublicKey(key);
|
|
28715
28715
|
return getP2TRAddressFromPublicKey(pubKey, 4 /* LOCAL */);
|
|
28716
28716
|
}
|
|
28717
|
+
async getNewExternalWallet() {
|
|
28718
|
+
const key = secp256k112.utils.randomPrivateKey();
|
|
28719
|
+
const pubKey = secp256k112.getPublicKey(key);
|
|
28720
|
+
return {
|
|
28721
|
+
address: getP2TRAddressFromPublicKey(pubKey, 4 /* LOCAL */),
|
|
28722
|
+
key,
|
|
28723
|
+
pubKey
|
|
28724
|
+
};
|
|
28725
|
+
}
|
|
28717
28726
|
async sendToAddress(address, amount, blocksToGenerate = 1) {
|
|
28718
28727
|
const coin = await this.fund();
|
|
28719
28728
|
if (!coin) {
|
|
28720
28729
|
throw new Error("No coins available");
|
|
28721
28730
|
}
|
|
28722
|
-
const tx = new
|
|
28731
|
+
const tx = new Transaction5();
|
|
28723
28732
|
tx.addInput(coin.outpoint);
|
|
28724
28733
|
const availableAmount = COIN_AMOUNT - FEE_AMOUNT;
|
|
28725
28734
|
const destinationAddress = Address3(getNetwork(4 /* LOCAL */)).decode(
|
|
@@ -28814,75 +28823,6 @@ function chunkArray(arr, size) {
|
|
|
28814
28823
|
return chunks;
|
|
28815
28824
|
}
|
|
28816
28825
|
|
|
28817
|
-
// src/utils/optimize.ts
|
|
28818
|
-
var DENOMINATIONS = Array.from({ length: 28 }, (_, i) => 2 ** i);
|
|
28819
|
-
function assert(condition, message) {
|
|
28820
|
-
if (!condition) {
|
|
28821
|
-
throw new InternalValidationError(message || "Assertion failed");
|
|
28822
|
-
}
|
|
28823
|
-
}
|
|
28824
|
-
function sum(arr) {
|
|
28825
|
-
return arr.reduce((a, b) => a + b, 0);
|
|
28826
|
-
}
|
|
28827
|
-
function sorted(arr) {
|
|
28828
|
-
return [...arr].sort((a, b) => a - b);
|
|
28829
|
-
}
|
|
28830
|
-
function equals(a, b) {
|
|
28831
|
-
return a.length === b.length && a.every((val, index) => val === b[index]);
|
|
28832
|
-
}
|
|
28833
|
-
function greedyLeaves(amount) {
|
|
28834
|
-
const leaves = [];
|
|
28835
|
-
let remaining = amount;
|
|
28836
|
-
for (let i = DENOMINATIONS.length - 1; i >= 0; i--) {
|
|
28837
|
-
const leaf = DENOMINATIONS[i];
|
|
28838
|
-
if (typeof leaf === "number" && leaf > 0) {
|
|
28839
|
-
while (remaining >= leaf) {
|
|
28840
|
-
remaining -= leaf;
|
|
28841
|
-
leaves.push(leaf);
|
|
28842
|
-
}
|
|
28843
|
-
}
|
|
28844
|
-
}
|
|
28845
|
-
assert(sum(leaves) === amount, "greedy_leaves: sum mismatch");
|
|
28846
|
-
return sorted(leaves);
|
|
28847
|
-
}
|
|
28848
|
-
var Swap = class {
|
|
28849
|
-
inLeaves;
|
|
28850
|
-
outLeaves;
|
|
28851
|
-
constructor(inLeaves, outLeaves) {
|
|
28852
|
-
this.inLeaves = [...inLeaves];
|
|
28853
|
-
this.outLeaves = [...outLeaves];
|
|
28854
|
-
assert(
|
|
28855
|
-
sum(this.inLeaves) === sum(this.outLeaves),
|
|
28856
|
-
"Swap in/out leaves must sum to same value for swap: " + this.toString()
|
|
28857
|
-
);
|
|
28858
|
-
}
|
|
28859
|
-
toString() {
|
|
28860
|
-
return `Swap(in=${JSON.stringify(this.inLeaves)}, out=${JSON.stringify(this.outLeaves)})`;
|
|
28861
|
-
}
|
|
28862
|
-
};
|
|
28863
|
-
function maximizeUnilateralExit(inputLeaves, maxLeavesPerSwap = 64) {
|
|
28864
|
-
const swaps = [];
|
|
28865
|
-
let batch = [];
|
|
28866
|
-
let leaves = sorted(inputLeaves);
|
|
28867
|
-
while (leaves.length > 0) {
|
|
28868
|
-
batch.push(leaves.shift());
|
|
28869
|
-
const target = greedyLeaves(sum(batch));
|
|
28870
|
-
if (batch.length >= maxLeavesPerSwap || target.length >= maxLeavesPerSwap) {
|
|
28871
|
-
if (!equals(target, batch)) {
|
|
28872
|
-
swaps.push(new Swap([...batch], target));
|
|
28873
|
-
}
|
|
28874
|
-
batch = [];
|
|
28875
|
-
}
|
|
28876
|
-
}
|
|
28877
|
-
if (batch.length > 0) {
|
|
28878
|
-
const target = greedyLeaves(sum(batch));
|
|
28879
|
-
if (!equals(target, batch)) {
|
|
28880
|
-
swaps.push(new Swap([...batch], target));
|
|
28881
|
-
}
|
|
28882
|
-
}
|
|
28883
|
-
return swaps;
|
|
28884
|
-
}
|
|
28885
|
-
|
|
28886
28826
|
// src/utils/retry.ts
|
|
28887
28827
|
var DEFAULT_RETRY_CONFIG = {
|
|
28888
28828
|
maxAttempts: 5,
|
|
@@ -28959,6 +28899,199 @@ var SparkWalletEvent = {
|
|
|
28959
28899
|
StreamReconnecting: "stream:reconnecting"
|
|
28960
28900
|
};
|
|
28961
28901
|
|
|
28902
|
+
// src/utils/optimize.ts
|
|
28903
|
+
var DENOMINATIONS = Array.from({ length: 28 }, (_, i) => 2 ** i);
|
|
28904
|
+
function assert(condition, message) {
|
|
28905
|
+
if (!condition) {
|
|
28906
|
+
throw new InternalValidationError(message || "Assertion failed");
|
|
28907
|
+
}
|
|
28908
|
+
}
|
|
28909
|
+
function sum(arr) {
|
|
28910
|
+
return arr.reduce((a, b) => a + b, 0);
|
|
28911
|
+
}
|
|
28912
|
+
function sorted(arr) {
|
|
28913
|
+
return [...arr].sort((a, b) => a - b);
|
|
28914
|
+
}
|
|
28915
|
+
function equals(a, b) {
|
|
28916
|
+
return a.length === b.length && a.every((val, index) => val === b[index]);
|
|
28917
|
+
}
|
|
28918
|
+
function countOccurrences(arr) {
|
|
28919
|
+
const map = /* @__PURE__ */ new Map();
|
|
28920
|
+
for (const x of arr) {
|
|
28921
|
+
map.set(x, (map.get(x) ?? 0) + 1);
|
|
28922
|
+
}
|
|
28923
|
+
return map;
|
|
28924
|
+
}
|
|
28925
|
+
function subtractCounters(a, b) {
|
|
28926
|
+
const result = /* @__PURE__ */ new Map();
|
|
28927
|
+
for (const [key, value] of a.entries()) {
|
|
28928
|
+
const diff = value - (b.get(key) ?? 0);
|
|
28929
|
+
if (diff > 0) {
|
|
28930
|
+
result.set(key, diff);
|
|
28931
|
+
}
|
|
28932
|
+
}
|
|
28933
|
+
return result;
|
|
28934
|
+
}
|
|
28935
|
+
function counterToFlatArray(counter) {
|
|
28936
|
+
const arr = [];
|
|
28937
|
+
for (const [k, v] of Array.from(counter.entries()).sort(
|
|
28938
|
+
(a, b) => a[0] - b[0]
|
|
28939
|
+
)) {
|
|
28940
|
+
for (let i = 0; i < v; i++) {
|
|
28941
|
+
arr.push(k);
|
|
28942
|
+
}
|
|
28943
|
+
}
|
|
28944
|
+
return arr;
|
|
28945
|
+
}
|
|
28946
|
+
function greedyLeaves(amount) {
|
|
28947
|
+
const leaves = [];
|
|
28948
|
+
let remaining = amount;
|
|
28949
|
+
for (let i = DENOMINATIONS.length - 1; i >= 0; i--) {
|
|
28950
|
+
const leaf = DENOMINATIONS[i];
|
|
28951
|
+
if (typeof leaf === "number" && leaf > 0) {
|
|
28952
|
+
while (remaining >= leaf) {
|
|
28953
|
+
remaining -= leaf;
|
|
28954
|
+
leaves.push(leaf);
|
|
28955
|
+
}
|
|
28956
|
+
}
|
|
28957
|
+
}
|
|
28958
|
+
assert(sum(leaves) === amount, "greedy_leaves: sum mismatch");
|
|
28959
|
+
return sorted(leaves);
|
|
28960
|
+
}
|
|
28961
|
+
function swapMinimizingLeaves(amount, multiplicity = 1) {
|
|
28962
|
+
const leaves = [];
|
|
28963
|
+
let remaining = amount;
|
|
28964
|
+
assert(multiplicity > 0, "multiplicity must be > 0");
|
|
28965
|
+
for (const leaf of DENOMINATIONS) {
|
|
28966
|
+
if (typeof leaf === "number" && leaf > 0) {
|
|
28967
|
+
for (let i = 0; i < multiplicity; i++) {
|
|
28968
|
+
if (remaining >= leaf) {
|
|
28969
|
+
remaining -= leaf;
|
|
28970
|
+
leaves.push(leaf);
|
|
28971
|
+
}
|
|
28972
|
+
}
|
|
28973
|
+
}
|
|
28974
|
+
}
|
|
28975
|
+
leaves.push(...greedyLeaves(remaining));
|
|
28976
|
+
assert(sum(leaves) === amount, "swap_minimizing_leaves: sum mismatch");
|
|
28977
|
+
return sorted(leaves);
|
|
28978
|
+
}
|
|
28979
|
+
var Swap = class {
|
|
28980
|
+
inLeaves;
|
|
28981
|
+
outLeaves;
|
|
28982
|
+
constructor(inLeaves, outLeaves) {
|
|
28983
|
+
this.inLeaves = [...inLeaves];
|
|
28984
|
+
this.outLeaves = [...outLeaves];
|
|
28985
|
+
assert(
|
|
28986
|
+
sum(this.inLeaves) === sum(this.outLeaves),
|
|
28987
|
+
"Swap in/out leaves must sum to same value for swap: " + this.toString()
|
|
28988
|
+
);
|
|
28989
|
+
}
|
|
28990
|
+
toString() {
|
|
28991
|
+
return `Swap(in=${JSON.stringify(this.inLeaves)}, out=${JSON.stringify(this.outLeaves)})`;
|
|
28992
|
+
}
|
|
28993
|
+
};
|
|
28994
|
+
function maximizeUnilateralExit(inputLeaves, maxLeavesPerSwap = 64) {
|
|
28995
|
+
const swaps = [];
|
|
28996
|
+
let batch = [];
|
|
28997
|
+
let leaves = sorted(inputLeaves);
|
|
28998
|
+
while (leaves.length > 0) {
|
|
28999
|
+
batch.push(leaves.shift());
|
|
29000
|
+
const target = greedyLeaves(sum(batch));
|
|
29001
|
+
if (batch.length >= maxLeavesPerSwap || target.length >= maxLeavesPerSwap) {
|
|
29002
|
+
if (!equals(target, batch)) {
|
|
29003
|
+
swaps.push(new Swap([...batch], target));
|
|
29004
|
+
}
|
|
29005
|
+
batch = [];
|
|
29006
|
+
}
|
|
29007
|
+
}
|
|
29008
|
+
if (batch.length > 0) {
|
|
29009
|
+
const target = greedyLeaves(sum(batch));
|
|
29010
|
+
if (!equals(target, batch)) {
|
|
29011
|
+
swaps.push(new Swap([...batch], target));
|
|
29012
|
+
}
|
|
29013
|
+
}
|
|
29014
|
+
return swaps;
|
|
29015
|
+
}
|
|
29016
|
+
function minimizeTransferSwap(inputLeaves, multiplicity = 1, maxLeavesPerSwap = 64) {
|
|
29017
|
+
const balance = sum(inputLeaves);
|
|
29018
|
+
const optimalLeaves = swapMinimizingLeaves(balance, multiplicity);
|
|
29019
|
+
const walletCounter = countOccurrences(inputLeaves);
|
|
29020
|
+
const optimalCounter = countOccurrences(optimalLeaves);
|
|
29021
|
+
const leavesToGive = subtractCounters(walletCounter, optimalCounter);
|
|
29022
|
+
const leavesToReceive = subtractCounters(optimalCounter, walletCounter);
|
|
29023
|
+
const leavesToGiveFlat = counterToFlatArray(leavesToGive);
|
|
29024
|
+
const leavesToReceiveFlat = counterToFlatArray(leavesToReceive);
|
|
29025
|
+
const swaps = [];
|
|
29026
|
+
let toGiveBatch = [];
|
|
29027
|
+
let toReceiveBatch = [];
|
|
29028
|
+
let give = [...leavesToGiveFlat];
|
|
29029
|
+
let receive = [...leavesToReceiveFlat];
|
|
29030
|
+
while (give.length > 0 || receive.length > 0) {
|
|
29031
|
+
if (sum(toGiveBatch) > sum(toReceiveBatch)) {
|
|
29032
|
+
if (receive.length === 0) break;
|
|
29033
|
+
toReceiveBatch.push(receive.shift());
|
|
29034
|
+
} else {
|
|
29035
|
+
if (give.length === 0) break;
|
|
29036
|
+
toGiveBatch.push(give.shift());
|
|
29037
|
+
}
|
|
29038
|
+
if (toGiveBatch.length > 0 && toReceiveBatch.length > 0 && sum(toGiveBatch) === sum(toReceiveBatch)) {
|
|
29039
|
+
if (toGiveBatch.length > maxLeavesPerSwap) {
|
|
29040
|
+
for (let i = 0; i < toGiveBatch.length; i += maxLeavesPerSwap) {
|
|
29041
|
+
const subset = toGiveBatch.slice(i, i + maxLeavesPerSwap);
|
|
29042
|
+
swaps.push(new Swap(subset, greedyLeaves(sum(subset))));
|
|
29043
|
+
}
|
|
29044
|
+
} else if (toReceiveBatch.length > maxLeavesPerSwap) {
|
|
29045
|
+
for (let cutoff = maxLeavesPerSwap; cutoff > 0; cutoff--) {
|
|
29046
|
+
const sumCut = sum(toReceiveBatch.slice(0, cutoff));
|
|
29047
|
+
const remainder = sum(toGiveBatch) - sumCut;
|
|
29048
|
+
const alternateBatch = [
|
|
29049
|
+
...toReceiveBatch.slice(0, cutoff),
|
|
29050
|
+
...greedyLeaves(remainder)
|
|
29051
|
+
];
|
|
29052
|
+
if (alternateBatch.length <= maxLeavesPerSwap) {
|
|
29053
|
+
swaps.push(new Swap([...toGiveBatch], alternateBatch));
|
|
29054
|
+
break;
|
|
29055
|
+
}
|
|
29056
|
+
}
|
|
29057
|
+
} else {
|
|
29058
|
+
swaps.push(new Swap([...toGiveBatch], [...toReceiveBatch]));
|
|
29059
|
+
}
|
|
29060
|
+
toGiveBatch = [];
|
|
29061
|
+
toReceiveBatch = [];
|
|
29062
|
+
}
|
|
29063
|
+
}
|
|
29064
|
+
return swaps;
|
|
29065
|
+
}
|
|
29066
|
+
function shouldOptimize(inputLeaves, multiplicity = 1, maxLeavesPerSwap = 64) {
|
|
29067
|
+
if (multiplicity == 0) {
|
|
29068
|
+
const swaps = maximizeUnilateralExit(inputLeaves, maxLeavesPerSwap);
|
|
29069
|
+
const numInputs = sum(swaps.map((swap) => swap.inLeaves.length));
|
|
29070
|
+
const numOutputs = sum(swaps.map((swap) => swap.outLeaves.length));
|
|
29071
|
+
return numOutputs * 5 < numInputs;
|
|
29072
|
+
} else {
|
|
29073
|
+
const swaps = minimizeTransferSwap(
|
|
29074
|
+
inputLeaves,
|
|
29075
|
+
multiplicity,
|
|
29076
|
+
maxLeavesPerSwap
|
|
29077
|
+
);
|
|
29078
|
+
const inputCounter = countOccurrences(
|
|
29079
|
+
swaps.flatMap((swap) => swap.inLeaves)
|
|
29080
|
+
);
|
|
29081
|
+
const outputCounter = countOccurrences(
|
|
29082
|
+
swaps.flatMap((swap) => swap.outLeaves)
|
|
29083
|
+
);
|
|
29084
|
+
return Math.abs(inputCounter.size - outputCounter.size) > 1;
|
|
29085
|
+
}
|
|
29086
|
+
}
|
|
29087
|
+
function optimize(inputLeaves, multiplicity = 1, maxLeavesPerSwap = 64) {
|
|
29088
|
+
if (multiplicity == 0) {
|
|
29089
|
+
return maximizeUnilateralExit(inputLeaves, maxLeavesPerSwap);
|
|
29090
|
+
} else {
|
|
29091
|
+
return minimizeTransferSwap(inputLeaves, multiplicity, maxLeavesPerSwap);
|
|
29092
|
+
}
|
|
29093
|
+
}
|
|
29094
|
+
|
|
28962
29095
|
// src/spark-wallet/spark-wallet.ts
|
|
28963
29096
|
var SparkWallet = class extends EventEmitter {
|
|
28964
29097
|
config;
|
|
@@ -29063,16 +29196,13 @@ var SparkWallet = class extends EventEmitter {
|
|
|
29063
29196
|
if (event.transfer.transfer && !equalBytes6(senderIdentityPublicKey, receiverIdentityPublicKey)) {
|
|
29064
29197
|
await this.claimTransfer({
|
|
29065
29198
|
transfer: event.transfer.transfer,
|
|
29066
|
-
emit: true
|
|
29067
|
-
optimize: true
|
|
29199
|
+
emit: true
|
|
29068
29200
|
});
|
|
29069
29201
|
}
|
|
29070
29202
|
} else if (isDepositStreamEvent(event)) {
|
|
29071
29203
|
const deposit = event.deposit.deposit;
|
|
29072
|
-
|
|
29073
|
-
|
|
29074
|
-
type: "leaf" /* LEAF */,
|
|
29075
|
-
path: deposit.id
|
|
29204
|
+
await this.withLeaves(async () => {
|
|
29205
|
+
this.leaves.push(deposit);
|
|
29076
29206
|
});
|
|
29077
29207
|
this.emit(
|
|
29078
29208
|
SparkWalletEvent.DepositConfirmed,
|
|
@@ -29248,19 +29378,6 @@ var SparkWallet = class extends EventEmitter {
|
|
|
29248
29378
|
}
|
|
29249
29379
|
return availableLeaves.filter(([_, node]) => !leavesToIgnore.has(node.id)).map(([_, node]) => node);
|
|
29250
29380
|
}
|
|
29251
|
-
async checkExtendLeaves(leaves) {
|
|
29252
|
-
await this.withLeaves(async () => {
|
|
29253
|
-
for (const leaf of leaves) {
|
|
29254
|
-
if (!leaf.parentNodeId && leaf.status === "AVAILABLE") {
|
|
29255
|
-
const res = await this.transferService.extendTimelock(leaf);
|
|
29256
|
-
await this.transferLeavesToSelf(res.nodes, {
|
|
29257
|
-
type: "leaf" /* LEAF */,
|
|
29258
|
-
path: leaf.id
|
|
29259
|
-
});
|
|
29260
|
-
}
|
|
29261
|
-
}
|
|
29262
|
-
});
|
|
29263
|
-
}
|
|
29264
29381
|
verifyKey(pubkey1, pubkey2, verifyingKey) {
|
|
29265
29382
|
return equalBytes6(addPublicKeys(pubkey1, pubkey2), verifyingKey);
|
|
29266
29383
|
}
|
|
@@ -29370,75 +29487,84 @@ var SparkWallet = class extends EventEmitter {
|
|
|
29370
29487
|
}
|
|
29371
29488
|
return nodes;
|
|
29372
29489
|
}
|
|
29373
|
-
|
|
29374
|
-
const
|
|
29375
|
-
if (
|
|
29376
|
-
|
|
29490
|
+
async *optimizeLeaves(multiplicity = void 0) {
|
|
29491
|
+
const multiplicityValue = multiplicity ?? this.config.getOptimizationOptions().multiplicity ?? 0;
|
|
29492
|
+
if (multiplicityValue < 0) {
|
|
29493
|
+
throw new ValidationError("Multiplicity cannot be negative");
|
|
29494
|
+
} else if (multiplicityValue > 5) {
|
|
29495
|
+
throw new ValidationError("Multiplicity cannot be greater than 5");
|
|
29377
29496
|
}
|
|
29378
|
-
|
|
29379
|
-
|
|
29380
|
-
|
|
29381
|
-
|
|
29382
|
-
const denomination = 2 ** i;
|
|
29383
|
-
while (remainingAmount >= denomination) {
|
|
29384
|
-
remainingAmount -= denomination;
|
|
29385
|
-
optimalLeavesLength++;
|
|
29386
|
-
}
|
|
29387
|
-
}
|
|
29388
|
-
return this.leaves.length > optimalLeavesLength * 5;
|
|
29389
|
-
}
|
|
29390
|
-
async optimizeLeaves() {
|
|
29391
|
-
if (this.optimizationInProgress || !this.areLeavesInefficient()) {
|
|
29497
|
+
if (this.optimizationInProgress || !shouldOptimize(
|
|
29498
|
+
this.leaves.map((leaf) => leaf.value),
|
|
29499
|
+
multiplicityValue
|
|
29500
|
+
)) {
|
|
29392
29501
|
return;
|
|
29393
29502
|
}
|
|
29394
|
-
|
|
29503
|
+
const controller = new AbortController();
|
|
29504
|
+
const release = await this.leavesMutex.acquire();
|
|
29505
|
+
try {
|
|
29395
29506
|
this.optimizationInProgress = true;
|
|
29396
|
-
|
|
29397
|
-
|
|
29398
|
-
|
|
29399
|
-
|
|
29400
|
-
|
|
29401
|
-
|
|
29402
|
-
|
|
29403
|
-
|
|
29404
|
-
|
|
29405
|
-
|
|
29406
|
-
|
|
29407
|
-
|
|
29408
|
-
|
|
29409
|
-
|
|
29410
|
-
|
|
29411
|
-
|
|
29412
|
-
|
|
29413
|
-
|
|
29414
|
-
|
|
29415
|
-
|
|
29416
|
-
|
|
29417
|
-
|
|
29418
|
-
|
|
29419
|
-
|
|
29507
|
+
this.leaves = await this.getLeaves();
|
|
29508
|
+
const swaps = optimize(
|
|
29509
|
+
this.leaves.map((leaf) => leaf.value),
|
|
29510
|
+
multiplicityValue
|
|
29511
|
+
);
|
|
29512
|
+
if (swaps.length === 0) {
|
|
29513
|
+
return;
|
|
29514
|
+
}
|
|
29515
|
+
yield {
|
|
29516
|
+
step: 0,
|
|
29517
|
+
total: swaps.length,
|
|
29518
|
+
controller
|
|
29519
|
+
};
|
|
29520
|
+
const valueToNodes = /* @__PURE__ */ new Map();
|
|
29521
|
+
this.leaves.forEach((leaf) => {
|
|
29522
|
+
if (!valueToNodes.has(leaf.value)) {
|
|
29523
|
+
valueToNodes.set(leaf.value, []);
|
|
29524
|
+
}
|
|
29525
|
+
valueToNodes.get(leaf.value).push(leaf);
|
|
29526
|
+
});
|
|
29527
|
+
for (const swap of swaps) {
|
|
29528
|
+
if (controller.signal.aborted) {
|
|
29529
|
+
break;
|
|
29530
|
+
}
|
|
29531
|
+
const leavesToSend = [];
|
|
29532
|
+
for (const leafValue of swap.inLeaves) {
|
|
29533
|
+
const nodes = valueToNodes.get(leafValue);
|
|
29534
|
+
if (nodes && nodes.length > 0) {
|
|
29535
|
+
const node = nodes.shift();
|
|
29536
|
+
leavesToSend.push(node);
|
|
29537
|
+
} else {
|
|
29538
|
+
throw new InternalValidationError(
|
|
29539
|
+
`No unused leaf with value ${leafValue} found in leaves`
|
|
29540
|
+
);
|
|
29420
29541
|
}
|
|
29421
|
-
await this.requestLeavesSwap({
|
|
29422
|
-
leaves: leavesToSend,
|
|
29423
|
-
targetAmounts: swap.outLeaves
|
|
29424
|
-
});
|
|
29425
29542
|
}
|
|
29426
|
-
|
|
29427
|
-
|
|
29428
|
-
|
|
29543
|
+
await this.requestLeavesSwap({
|
|
29544
|
+
leaves: leavesToSend,
|
|
29545
|
+
targetAmounts: swap.outLeaves
|
|
29546
|
+
});
|
|
29547
|
+
yield {
|
|
29548
|
+
step: swaps.indexOf(swap) + 1,
|
|
29549
|
+
total: swaps.length,
|
|
29550
|
+
controller
|
|
29551
|
+
};
|
|
29429
29552
|
}
|
|
29430
|
-
|
|
29553
|
+
this.leaves = await this.getLeaves();
|
|
29554
|
+
} finally {
|
|
29555
|
+
this.optimizationInProgress = false;
|
|
29556
|
+
release();
|
|
29557
|
+
}
|
|
29431
29558
|
}
|
|
29432
29559
|
async syncWallet() {
|
|
29433
29560
|
await this.syncTokenOutputs();
|
|
29434
29561
|
let leaves = await this.getLeaves();
|
|
29435
|
-
leaves = await this.
|
|
29436
|
-
leaves = await this.checkExtendTimeLockNodes(leaves);
|
|
29562
|
+
leaves = await this.checkRenewLeaves(leaves);
|
|
29437
29563
|
this.leaves = leaves;
|
|
29438
|
-
this.
|
|
29439
|
-
|
|
29440
|
-
|
|
29441
|
-
}
|
|
29564
|
+
if (this.config.getOptimizationOptions().auto) {
|
|
29565
|
+
for await (const _ of this.optimizeLeaves()) {
|
|
29566
|
+
}
|
|
29567
|
+
}
|
|
29442
29568
|
}
|
|
29443
29569
|
async withLeaves(operation) {
|
|
29444
29570
|
const release = await this.leavesMutex.acquire();
|
|
@@ -29555,7 +29681,7 @@ var SparkWallet = class extends EventEmitter {
|
|
|
29555
29681
|
mnemonic = mnemonicOrSeed;
|
|
29556
29682
|
seed = await this.config.signer.mnemonicToSeed(mnemonicOrSeed);
|
|
29557
29683
|
} else {
|
|
29558
|
-
seed =
|
|
29684
|
+
seed = hexToBytes11(mnemonicOrSeed);
|
|
29559
29685
|
}
|
|
29560
29686
|
}
|
|
29561
29687
|
await this.initWalletFromSeed(seed, accountNumber);
|
|
@@ -29698,7 +29824,7 @@ var SparkWallet = class extends EventEmitter {
|
|
|
29698
29824
|
directFromCpfpSignatureMap
|
|
29699
29825
|
} = await this.transferService.startSwapSignRefund(
|
|
29700
29826
|
leafKeyTweaks,
|
|
29701
|
-
|
|
29827
|
+
hexToBytes11(this.config.getSspIdentityPublicKey()),
|
|
29702
29828
|
new Date(Date.now() + 2 * 60 * 1e3)
|
|
29703
29829
|
);
|
|
29704
29830
|
try {
|
|
@@ -29913,7 +30039,7 @@ var SparkWallet = class extends EventEmitter {
|
|
|
29913
30039
|
throw new Error(`Leaf not found for node ${nodeId}`);
|
|
29914
30040
|
}
|
|
29915
30041
|
const cpfpNodeTx = getTxFromRawTxBytes(node.nodeTx);
|
|
29916
|
-
const cpfpRefundTxBytes =
|
|
30042
|
+
const cpfpRefundTxBytes = hexToBytes11(leaf.rawUnsignedRefundTransaction);
|
|
29917
30043
|
const cpfpRefundTx = getTxFromRawTxBytes(cpfpRefundTxBytes);
|
|
29918
30044
|
const cpfpSighash = getSigHashFromTx(
|
|
29919
30045
|
cpfpRefundTx,
|
|
@@ -29922,7 +30048,7 @@ var SparkWallet = class extends EventEmitter {
|
|
|
29922
30048
|
);
|
|
29923
30049
|
const nodePublicKey = node.verifyingPublicKey;
|
|
29924
30050
|
const taprootKey = computeTaprootKeyNoScript(nodePublicKey.slice(1));
|
|
29925
|
-
const cpfpAdaptorSignatureBytes =
|
|
30051
|
+
const cpfpAdaptorSignatureBytes = hexToBytes11(
|
|
29926
30052
|
leaf.adaptorSignedSignature
|
|
29927
30053
|
);
|
|
29928
30054
|
applyAdaptorToSignature(
|
|
@@ -29933,7 +30059,7 @@ var SparkWallet = class extends EventEmitter {
|
|
|
29933
30059
|
);
|
|
29934
30060
|
if (leaf.directRawUnsignedRefundTransaction) {
|
|
29935
30061
|
const directNodeTx = getTxFromRawTxBytes(node.directTx);
|
|
29936
|
-
const directRefundTxBytes =
|
|
30062
|
+
const directRefundTxBytes = hexToBytes11(
|
|
29937
30063
|
leaf.directRawUnsignedRefundTransaction
|
|
29938
30064
|
);
|
|
29939
30065
|
const directRefundTx = getTxFromRawTxBytes(directRefundTxBytes);
|
|
@@ -29947,7 +30073,7 @@ var SparkWallet = class extends EventEmitter {
|
|
|
29947
30073
|
`Direct adaptor signed signature missing for node ${nodeId}`
|
|
29948
30074
|
);
|
|
29949
30075
|
}
|
|
29950
|
-
const directAdaptorSignatureBytes =
|
|
30076
|
+
const directAdaptorSignatureBytes = hexToBytes11(
|
|
29951
30077
|
leaf.directAdaptorSignedSignature
|
|
29952
30078
|
);
|
|
29953
30079
|
applyAdaptorToSignature(
|
|
@@ -29958,7 +30084,7 @@ var SparkWallet = class extends EventEmitter {
|
|
|
29958
30084
|
);
|
|
29959
30085
|
}
|
|
29960
30086
|
if (leaf.directFromCpfpRawUnsignedRefundTransaction) {
|
|
29961
|
-
const directFromCpfpRefundTxBytes =
|
|
30087
|
+
const directFromCpfpRefundTxBytes = hexToBytes11(
|
|
29962
30088
|
leaf.directFromCpfpRawUnsignedRefundTransaction
|
|
29963
30089
|
);
|
|
29964
30090
|
const directFromCpfpRefundTx = getTxFromRawTxBytes(
|
|
@@ -29974,7 +30100,7 @@ var SparkWallet = class extends EventEmitter {
|
|
|
29974
30100
|
`Direct adaptor signed signature missing for node ${nodeId}`
|
|
29975
30101
|
);
|
|
29976
30102
|
}
|
|
29977
|
-
const directFromCpfpAdaptorSignatureBytes =
|
|
30103
|
+
const directFromCpfpAdaptorSignatureBytes = hexToBytes11(
|
|
29978
30104
|
leaf.directFromCpfpAdaptorSignedSignature
|
|
29979
30105
|
);
|
|
29980
30106
|
applyAdaptorToSignature(
|
|
@@ -30021,8 +30147,7 @@ var SparkWallet = class extends EventEmitter {
|
|
|
30021
30147
|
}
|
|
30022
30148
|
return await this.claimTransfer({
|
|
30023
30149
|
transfer: incomingTransfer,
|
|
30024
|
-
emit: false
|
|
30025
|
-
optimize: false
|
|
30150
|
+
emit: false
|
|
30026
30151
|
});
|
|
30027
30152
|
} catch (e) {
|
|
30028
30153
|
console.error("[processSwapBatch] Error details:", {
|
|
@@ -30416,7 +30541,7 @@ var SparkWallet = class extends EventEmitter {
|
|
|
30416
30541
|
}
|
|
30417
30542
|
);
|
|
30418
30543
|
}
|
|
30419
|
-
const tx = new
|
|
30544
|
+
const tx = new Transaction6();
|
|
30420
30545
|
tx.addInput({
|
|
30421
30546
|
txid: depositTransactionId,
|
|
30422
30547
|
index: outputIndex,
|
|
@@ -30456,7 +30581,7 @@ var SparkWallet = class extends EventEmitter {
|
|
|
30456
30581
|
);
|
|
30457
30582
|
const swapResponse = await sparkClient.initiate_static_deposit_utxo_refund({
|
|
30458
30583
|
onChainUtxo: {
|
|
30459
|
-
txid:
|
|
30584
|
+
txid: hexToBytes11(depositTransactionId),
|
|
30460
30585
|
vout: outputIndex,
|
|
30461
30586
|
network: networkType
|
|
30462
30587
|
},
|
|
@@ -30583,7 +30708,7 @@ var SparkWallet = class extends EventEmitter {
|
|
|
30583
30708
|
creditAmountView.setUint32(0, lowerHalf, true);
|
|
30584
30709
|
creditAmountView.setUint32(4, upperHalf, true);
|
|
30585
30710
|
parts.push(new Uint8Array(creditAmountBuffer));
|
|
30586
|
-
parts.push(
|
|
30711
|
+
parts.push(hexToBytes11(sspSignature));
|
|
30587
30712
|
const totalLength = parts.reduce((sum2, part) => sum2 + part.length, 0);
|
|
30588
30713
|
const payload = new Uint8Array(totalLength);
|
|
30589
30714
|
let offset = 0;
|
|
@@ -30687,26 +30812,7 @@ var SparkWallet = class extends EventEmitter {
|
|
|
30687
30812
|
depositTx,
|
|
30688
30813
|
vout
|
|
30689
30814
|
});
|
|
30690
|
-
|
|
30691
|
-
for (const node of res.nodes) {
|
|
30692
|
-
if (node.status === "AVAILABLE") {
|
|
30693
|
-
const { nodes } = await this.transferService.extendTimelock(node);
|
|
30694
|
-
for (const n of nodes) {
|
|
30695
|
-
if (n.status === "AVAILABLE") {
|
|
30696
|
-
const transfer = await this.transferLeavesToSelf([n], {
|
|
30697
|
-
type: "leaf" /* LEAF */,
|
|
30698
|
-
path: node.id
|
|
30699
|
-
});
|
|
30700
|
-
resultingNodes.push(...transfer);
|
|
30701
|
-
} else {
|
|
30702
|
-
resultingNodes.push(n);
|
|
30703
|
-
}
|
|
30704
|
-
}
|
|
30705
|
-
} else {
|
|
30706
|
-
resultingNodes.push(node);
|
|
30707
|
-
}
|
|
30708
|
-
}
|
|
30709
|
-
return resultingNodes;
|
|
30815
|
+
return res.nodes;
|
|
30710
30816
|
}
|
|
30711
30817
|
/**
|
|
30712
30818
|
* Gets all unused deposit addresses for the wallet.
|
|
@@ -30848,6 +30954,9 @@ var SparkWallet = class extends EventEmitter {
|
|
|
30848
30954
|
depositTx,
|
|
30849
30955
|
vout
|
|
30850
30956
|
});
|
|
30957
|
+
await this.withLeaves(async () => {
|
|
30958
|
+
this.leaves.push(...nodes2);
|
|
30959
|
+
});
|
|
30851
30960
|
return nodes2;
|
|
30852
30961
|
});
|
|
30853
30962
|
this.mutexes.delete(txid);
|
|
@@ -30977,7 +31086,7 @@ var SparkWallet = class extends EventEmitter {
|
|
|
30977
31086
|
const [outcome] = await this.transferWithInvoice([
|
|
30978
31087
|
{
|
|
30979
31088
|
amountSats,
|
|
30980
|
-
receiverIdentityPubkey:
|
|
31089
|
+
receiverIdentityPubkey: hexToBytes11(receiverAddress.identityPublicKey)
|
|
30981
31090
|
}
|
|
30982
31091
|
]);
|
|
30983
31092
|
if (!outcome) throw new Error("no transfer created");
|
|
@@ -31024,8 +31133,7 @@ var SparkWallet = class extends EventEmitter {
|
|
|
31024
31133
|
`TreeNode group at index ${groupIndex} not found for amount ${amount} after selection`
|
|
31025
31134
|
);
|
|
31026
31135
|
}
|
|
31027
|
-
|
|
31028
|
-
available = await this.checkExtendTimeLockNodes(available);
|
|
31136
|
+
const available = await this.checkRenewLeaves(group);
|
|
31029
31137
|
if (available.length < group.length) {
|
|
31030
31138
|
throw new Error(
|
|
31031
31139
|
`Not enough available nodes after refresh/extend. Expected ${group.length}, got ${available.length}`
|
|
@@ -31068,7 +31176,7 @@ var SparkWallet = class extends EventEmitter {
|
|
|
31068
31176
|
transfer.id
|
|
31069
31177
|
);
|
|
31070
31178
|
if (pending) {
|
|
31071
|
-
await this.claimTransfer({ transfer: pending
|
|
31179
|
+
await this.claimTransfer({ transfer: pending });
|
|
31072
31180
|
}
|
|
31073
31181
|
}
|
|
31074
31182
|
return {
|
|
@@ -31118,75 +31226,45 @@ var SparkWallet = class extends EventEmitter {
|
|
|
31118
31226
|
newKeyDerivation: { type: "random" /* RANDOM */ }
|
|
31119
31227
|
};
|
|
31120
31228
|
}
|
|
31121
|
-
async
|
|
31122
|
-
const
|
|
31229
|
+
async checkRenewLeaves(nodes) {
|
|
31230
|
+
const nodesToRenewNode = [];
|
|
31231
|
+
const nodesToRenewRefund = [];
|
|
31232
|
+
const nodesToRenewZeroTimelock = [];
|
|
31123
31233
|
const nodeIds = [];
|
|
31124
31234
|
const validNodes = [];
|
|
31125
31235
|
for (const node of nodes) {
|
|
31126
31236
|
const nodeTx = getTxFromRawTxBytes(node.nodeTx);
|
|
31127
|
-
const
|
|
31128
|
-
|
|
31237
|
+
const refundTx = getTxFromRawTxBytes(node.refundTx);
|
|
31238
|
+
const nodeSequence = nodeTx.getInput(0).sequence;
|
|
31239
|
+
const refundSequence = refundTx.getInput(0).sequence;
|
|
31240
|
+
if (nodeSequence === void 0) {
|
|
31129
31241
|
throw new ValidationError("Invalid node transaction", {
|
|
31130
31242
|
field: "sequence",
|
|
31131
31243
|
value: nodeTx.getInput(0),
|
|
31132
31244
|
expected: "Non-null sequence"
|
|
31133
31245
|
});
|
|
31134
31246
|
}
|
|
31135
|
-
|
|
31136
|
-
if (needsRefresh) {
|
|
31137
|
-
nodesToExtend.push(node);
|
|
31138
|
-
nodeIds.push(node.id);
|
|
31139
|
-
} else {
|
|
31140
|
-
validNodes.push(node);
|
|
31141
|
-
}
|
|
31142
|
-
}
|
|
31143
|
-
if (nodesToExtend.length === 0) {
|
|
31144
|
-
return validNodes;
|
|
31145
|
-
}
|
|
31146
|
-
const nodesToAdd = [];
|
|
31147
|
-
for (const node of nodesToExtend) {
|
|
31148
|
-
const { nodes: nodes2 } = await this.transferService.extendTimelock(node);
|
|
31149
|
-
this.leaves = this.leaves.filter((leaf) => leaf.id !== node.id);
|
|
31150
|
-
const newNodes = await this.transferLeavesToSelf(nodes2, {
|
|
31151
|
-
type: "leaf" /* LEAF */,
|
|
31152
|
-
path: node.id
|
|
31153
|
-
});
|
|
31154
|
-
nodesToAdd.push(...newNodes);
|
|
31155
|
-
}
|
|
31156
|
-
this.updateLeaves(nodeIds, nodesToAdd);
|
|
31157
|
-
validNodes.push(...nodesToAdd);
|
|
31158
|
-
return validNodes;
|
|
31159
|
-
}
|
|
31160
|
-
/**
|
|
31161
|
-
* Internal method to refresh timelock nodes.
|
|
31162
|
-
*
|
|
31163
|
-
* @param {string} nodeId - The optional ID of the node to refresh. If not provided, all nodes will be checked.
|
|
31164
|
-
* @returns {Promise<void>}
|
|
31165
|
-
* @private
|
|
31166
|
-
*/
|
|
31167
|
-
async checkRefreshTimelockNodes(nodes) {
|
|
31168
|
-
const nodesToRefresh = [];
|
|
31169
|
-
const nodeIds = [];
|
|
31170
|
-
const validNodes = [];
|
|
31171
|
-
for (const node of nodes) {
|
|
31172
|
-
const refundTx = getTxFromRawTxBytes(node.refundTx);
|
|
31173
|
-
const sequence = refundTx.getInput(0).sequence;
|
|
31174
|
-
if (!sequence) {
|
|
31247
|
+
if (!refundSequence) {
|
|
31175
31248
|
throw new ValidationError("Invalid refund transaction", {
|
|
31176
31249
|
field: "sequence",
|
|
31177
31250
|
value: refundTx.getInput(0),
|
|
31178
31251
|
expected: "Non-null sequence"
|
|
31179
31252
|
});
|
|
31180
31253
|
}
|
|
31181
|
-
|
|
31182
|
-
|
|
31183
|
-
|
|
31254
|
+
if (doesTxnNeedRenewed(refundSequence)) {
|
|
31255
|
+
if (isZeroTimelock(nodeSequence)) {
|
|
31256
|
+
nodesToRenewZeroTimelock.push(node);
|
|
31257
|
+
} else if (doesTxnNeedRenewed(nodeSequence)) {
|
|
31258
|
+
nodesToRenewNode.push(node);
|
|
31259
|
+
} else {
|
|
31260
|
+
nodesToRenewRefund.push(node);
|
|
31261
|
+
}
|
|
31184
31262
|
nodeIds.push(node.id);
|
|
31185
31263
|
} else {
|
|
31186
31264
|
validNodes.push(node);
|
|
31187
31265
|
}
|
|
31188
31266
|
}
|
|
31189
|
-
if (
|
|
31267
|
+
if (nodesToRenewNode.length === 0 && nodesToRenewRefund.length === 0 && nodesToRenewZeroTimelock.length === 0) {
|
|
31190
31268
|
return validNodes;
|
|
31191
31269
|
}
|
|
31192
31270
|
const nodesResp = await this.queryNodes({
|
|
@@ -31204,7 +31282,18 @@ var SparkWallet = class extends EventEmitter {
|
|
|
31204
31282
|
nodesMap.set(node.id, node);
|
|
31205
31283
|
}
|
|
31206
31284
|
const nodesToAdd = [];
|
|
31207
|
-
for (const node of
|
|
31285
|
+
for (const node of nodesToRenewNode) {
|
|
31286
|
+
if (!node.parentNodeId) {
|
|
31287
|
+
throw new Error(`node ${node.id} has no parent`);
|
|
31288
|
+
}
|
|
31289
|
+
const parentNode = nodesMap.get(node.parentNodeId);
|
|
31290
|
+
if (!parentNode) {
|
|
31291
|
+
throw new Error(`parent node ${node.parentNodeId} not found`);
|
|
31292
|
+
}
|
|
31293
|
+
const newNode = await this.transferService.renewNodeTxn(node, parentNode);
|
|
31294
|
+
nodesToAdd.push(newNode);
|
|
31295
|
+
}
|
|
31296
|
+
for (const node of nodesToRenewRefund) {
|
|
31208
31297
|
if (!node.parentNodeId) {
|
|
31209
31298
|
throw new Error(`node ${node.id} has no parent`);
|
|
31210
31299
|
}
|
|
@@ -31212,17 +31301,14 @@ var SparkWallet = class extends EventEmitter {
|
|
|
31212
31301
|
if (!parentNode) {
|
|
31213
31302
|
throw new Error(`parent node ${node.parentNodeId} not found`);
|
|
31214
31303
|
}
|
|
31215
|
-
const
|
|
31304
|
+
const newNode = await this.transferService.renewRefundTxn(
|
|
31216
31305
|
node,
|
|
31217
31306
|
parentNode
|
|
31218
31307
|
);
|
|
31219
|
-
|
|
31220
|
-
|
|
31221
|
-
|
|
31222
|
-
const newNode =
|
|
31223
|
-
if (!newNode) {
|
|
31224
|
-
throw new Error("Failed to refresh timelock node");
|
|
31225
|
-
}
|
|
31308
|
+
nodesToAdd.push(newNode);
|
|
31309
|
+
}
|
|
31310
|
+
for (const node of nodesToRenewZeroTimelock) {
|
|
31311
|
+
const newNode = await this.transferService.renewZeroTimelockNodeTxn(node);
|
|
31226
31312
|
nodesToAdd.push(newNode);
|
|
31227
31313
|
}
|
|
31228
31314
|
this.updateLeaves(nodeIds, nodesToAdd);
|
|
@@ -31263,14 +31349,14 @@ var SparkWallet = class extends EventEmitter {
|
|
|
31263
31349
|
return response.nodes;
|
|
31264
31350
|
});
|
|
31265
31351
|
}
|
|
31266
|
-
async processClaimedTransferResults(result, transfer, emit
|
|
31267
|
-
result = await this.
|
|
31268
|
-
result = await this.checkExtendTimeLockNodes(result);
|
|
31352
|
+
async processClaimedTransferResults(result, transfer, emit) {
|
|
31353
|
+
result = await this.checkRenewLeaves(result);
|
|
31269
31354
|
const existingIds = new Set(this.leaves.map((leaf) => leaf.id));
|
|
31270
31355
|
const uniqueResults = result.filter((node) => !existingIds.has(node.id));
|
|
31271
31356
|
this.leaves.push(...uniqueResults);
|
|
31272
|
-
if (
|
|
31273
|
-
await this.optimizeLeaves()
|
|
31357
|
+
if (this.config.getOptimizationOptions().auto && transfer.type !== 40 /* COUNTER_SWAP */) {
|
|
31358
|
+
for await (const _ of this.optimizeLeaves()) {
|
|
31359
|
+
}
|
|
31274
31360
|
}
|
|
31275
31361
|
if (emit) {
|
|
31276
31362
|
this.emit(
|
|
@@ -31289,8 +31375,7 @@ var SparkWallet = class extends EventEmitter {
|
|
|
31289
31375
|
*/
|
|
31290
31376
|
async claimTransfer({
|
|
31291
31377
|
transfer,
|
|
31292
|
-
emit
|
|
31293
|
-
optimize
|
|
31378
|
+
emit
|
|
31294
31379
|
}) {
|
|
31295
31380
|
const onError = async (context) => {
|
|
31296
31381
|
const error = context.error;
|
|
@@ -31335,12 +31420,7 @@ var SparkWallet = class extends EventEmitter {
|
|
|
31335
31420
|
if (result.length === 0) {
|
|
31336
31421
|
return [];
|
|
31337
31422
|
}
|
|
31338
|
-
return await this.processClaimedTransferResults(
|
|
31339
|
-
result,
|
|
31340
|
-
transfer,
|
|
31341
|
-
emit,
|
|
31342
|
-
optimize
|
|
31343
|
-
);
|
|
31423
|
+
return await this.processClaimedTransferResults(result, transfer, emit);
|
|
31344
31424
|
} catch (error) {
|
|
31345
31425
|
console.warn(
|
|
31346
31426
|
`Failed to claim transfer after all retries. Please try reinitializing your wallet in a few minutes. Transfer ID: ${transfer.id}`,
|
|
@@ -31373,7 +31453,7 @@ var SparkWallet = class extends EventEmitter {
|
|
|
31373
31453
|
continue;
|
|
31374
31454
|
}
|
|
31375
31455
|
promises.push(
|
|
31376
|
-
this.claimTransfer({ transfer, emit
|
|
31456
|
+
this.claimTransfer({ transfer, emit }).then(() => transfer.id).catch((error) => {
|
|
31377
31457
|
console.warn(`Failed to claim transfer ${transfer.id}:`, error);
|
|
31378
31458
|
return null;
|
|
31379
31459
|
})
|
|
@@ -31599,7 +31679,7 @@ var SparkWallet = class extends EventEmitter {
|
|
|
31599
31679
|
const sparkFallbackAddress = decodedInvoice.fallbackAddress;
|
|
31600
31680
|
const paymentHash = decodedInvoice.paymentHash;
|
|
31601
31681
|
if (preferSpark) {
|
|
31602
|
-
if (sparkFallbackAddress === void 0 || isValidSparkFallback(
|
|
31682
|
+
if (sparkFallbackAddress === void 0 || isValidSparkFallback(hexToBytes11(sparkFallbackAddress)) === false) {
|
|
31603
31683
|
console.warn(
|
|
31604
31684
|
"No valid spark address found in invoice. Defaulting to lightning."
|
|
31605
31685
|
);
|
|
@@ -31644,8 +31724,7 @@ var SparkWallet = class extends EventEmitter {
|
|
|
31644
31724
|
selectedLeaves,
|
|
31645
31725
|
`no leaves for ${totalAmount}`
|
|
31646
31726
|
);
|
|
31647
|
-
leaves = await this.
|
|
31648
|
-
leaves = await this.checkExtendTimeLockNodes(leaves);
|
|
31727
|
+
leaves = await this.checkRenewLeaves(leaves);
|
|
31649
31728
|
const leavesToSend = await Promise.all(
|
|
31650
31729
|
leaves.map(async (leaf) => ({
|
|
31651
31730
|
leaf,
|
|
@@ -31661,17 +31740,17 @@ var SparkWallet = class extends EventEmitter {
|
|
|
31661
31740
|
const transferID = uuidv74();
|
|
31662
31741
|
const startTransferRequest = await this.transferService.prepareTransferForLightning(
|
|
31663
31742
|
leavesToSend,
|
|
31664
|
-
|
|
31665
|
-
|
|
31743
|
+
hexToBytes11(this.config.getSspIdentityPublicKey()),
|
|
31744
|
+
hexToBytes11(paymentHash),
|
|
31666
31745
|
expiryTime,
|
|
31667
31746
|
transferID
|
|
31668
31747
|
);
|
|
31669
31748
|
const swapResponse = await this.lightningService.swapNodesForPreimage({
|
|
31670
31749
|
leaves: leavesToSend,
|
|
31671
|
-
receiverIdentityPubkey:
|
|
31750
|
+
receiverIdentityPubkey: hexToBytes11(
|
|
31672
31751
|
this.config.getSspIdentityPublicKey()
|
|
31673
31752
|
),
|
|
31674
|
-
paymentHash:
|
|
31753
|
+
paymentHash: hexToBytes11(paymentHash),
|
|
31675
31754
|
isInboundPayment: false,
|
|
31676
31755
|
invoiceString: invoice,
|
|
31677
31756
|
feeSats: feeEstimate,
|
|
@@ -31774,7 +31853,7 @@ var SparkWallet = class extends EventEmitter {
|
|
|
31774
31853
|
}
|
|
31775
31854
|
satsInvoices.push({
|
|
31776
31855
|
amountSats: encodedAmount ?? Number(amount),
|
|
31777
|
-
receiverIdentityPubkey:
|
|
31856
|
+
receiverIdentityPubkey: hexToBytes11(addressData.identityPublicKey),
|
|
31778
31857
|
sparkInvoice: invoice
|
|
31779
31858
|
});
|
|
31780
31859
|
} else if (fields.paymentType?.type === "tokens") {
|
|
@@ -31976,10 +32055,8 @@ var SparkWallet = class extends EventEmitter {
|
|
|
31976
32055
|
leavesToSendToSsp = leavesForTargetAmount;
|
|
31977
32056
|
leavesToSendToSE = leavesForFee;
|
|
31978
32057
|
}
|
|
31979
|
-
leavesToSendToSsp = await this.
|
|
31980
|
-
|
|
31981
|
-
leavesToSendToSE = await this.checkRefreshTimelockNodes(leavesToSendToSE);
|
|
31982
|
-
leavesToSendToSE = await this.checkExtendTimeLockNodes(leavesToSendToSE);
|
|
32058
|
+
leavesToSendToSsp = await this.checkRenewLeaves(leavesToSendToSsp);
|
|
32059
|
+
leavesToSendToSE = await this.checkRenewLeaves(leavesToSendToSE);
|
|
31983
32060
|
const leafKeyTweaks = await Promise.all(
|
|
31984
32061
|
[...leavesToSendToSE, ...leavesToSendToSsp].map(async (leaf) => ({
|
|
31985
32062
|
leaf,
|
|
@@ -32024,11 +32101,11 @@ var SparkWallet = class extends EventEmitter {
|
|
|
32024
32101
|
const connectorOutputs = [];
|
|
32025
32102
|
for (let i = 0; i < connectorTx.outputsLength - 1; i++) {
|
|
32026
32103
|
connectorOutputs.push({
|
|
32027
|
-
txid:
|
|
32104
|
+
txid: hexToBytes11(connectorTxId),
|
|
32028
32105
|
index: i
|
|
32029
32106
|
});
|
|
32030
32107
|
}
|
|
32031
|
-
const sspPubIdentityKey =
|
|
32108
|
+
const sspPubIdentityKey = hexToBytes11(this.config.getSspIdentityPublicKey());
|
|
32032
32109
|
const transfer = await this.coopExitService.getConnectorRefundSignatures({
|
|
32033
32110
|
leaves: leafKeyTweaks,
|
|
32034
32111
|
exitTxId: coopExitTxId,
|
|
@@ -32065,8 +32142,7 @@ var SparkWallet = class extends EventEmitter {
|
|
|
32065
32142
|
(await this.selectLeaves([amountSats])).get(amountSats),
|
|
32066
32143
|
`no leaves for ${amountSats}`
|
|
32067
32144
|
);
|
|
32068
|
-
leaves = await this.
|
|
32069
|
-
leaves = await this.checkExtendTimeLockNodes(leaves);
|
|
32145
|
+
leaves = await this.checkRenewLeaves(leaves);
|
|
32070
32146
|
const feeEstimate = await sspClient.getCoopExitFeeQuote({
|
|
32071
32147
|
leafExternalIds: leaves.map((leaf) => leaf.id),
|
|
32072
32148
|
withdrawalAddress
|
|
@@ -32341,7 +32417,7 @@ var SparkWallet = class extends EventEmitter {
|
|
|
32341
32417
|
async validateMessageWithIdentityKey(message, signature) {
|
|
32342
32418
|
const hash = sha25611(message);
|
|
32343
32419
|
if (typeof signature === "string") {
|
|
32344
|
-
signature =
|
|
32420
|
+
signature = hexToBytes11(signature);
|
|
32345
32421
|
}
|
|
32346
32422
|
return this.config.signer.validateMessageWithIdentityKey(hash, signature);
|
|
32347
32423
|
}
|
|
@@ -32354,7 +32430,7 @@ var SparkWallet = class extends EventEmitter {
|
|
|
32354
32430
|
*/
|
|
32355
32431
|
async signTransaction(txHex, keyType = "auto-detect") {
|
|
32356
32432
|
try {
|
|
32357
|
-
const tx =
|
|
32433
|
+
const tx = Transaction6.fromRaw(hexToBytes11(txHex));
|
|
32358
32434
|
let publicKey;
|
|
32359
32435
|
switch (keyType.toLowerCase()) {
|
|
32360
32436
|
case "identity":
|
|
@@ -32561,15 +32637,6 @@ var SparkWallet = class extends EventEmitter {
|
|
|
32561
32637
|
}
|
|
32562
32638
|
);
|
|
32563
32639
|
}
|
|
32564
|
-
if (!nodeInput.sequence) {
|
|
32565
|
-
throw new ValidationError(
|
|
32566
|
-
`Node transaction has no sequence for ${isRootNode ? "root" : "non-root"} node`,
|
|
32567
|
-
{
|
|
32568
|
-
field: "sequence",
|
|
32569
|
-
value: nodeInput.sequence
|
|
32570
|
-
}
|
|
32571
|
-
);
|
|
32572
|
-
}
|
|
32573
32640
|
const refundInput = refundTx.getInput(0);
|
|
32574
32641
|
if (!refundInput) {
|
|
32575
32642
|
throw new ValidationError(
|
|
@@ -32605,89 +32672,6 @@ var SparkWallet = class extends EventEmitter {
|
|
|
32605
32672
|
);
|
|
32606
32673
|
}
|
|
32607
32674
|
}
|
|
32608
|
-
/**
|
|
32609
|
-
* Refresh the timelock of a specific node.
|
|
32610
|
-
*
|
|
32611
|
-
* @param {string} nodeId - The ID of the node to refresh
|
|
32612
|
-
* @returns {Promise<void>} Promise that resolves when the timelock is refreshed
|
|
32613
|
-
*/
|
|
32614
|
-
async testOnly_expireTimelock(nodeId) {
|
|
32615
|
-
const sparkClient = await this.connectionManager.createSparkClient(
|
|
32616
|
-
this.config.getCoordinatorAddress()
|
|
32617
|
-
);
|
|
32618
|
-
try {
|
|
32619
|
-
const response = await sparkClient.query_nodes({
|
|
32620
|
-
source: {
|
|
32621
|
-
$case: "nodeIds",
|
|
32622
|
-
nodeIds: {
|
|
32623
|
-
nodeIds: [nodeId]
|
|
32624
|
-
}
|
|
32625
|
-
},
|
|
32626
|
-
includeParents: true
|
|
32627
|
-
});
|
|
32628
|
-
let leaf = response.nodes[nodeId];
|
|
32629
|
-
if (!leaf) {
|
|
32630
|
-
throw new ValidationError("Node not found", {
|
|
32631
|
-
field: "nodeId",
|
|
32632
|
-
value: nodeId
|
|
32633
|
-
});
|
|
32634
|
-
}
|
|
32635
|
-
let parentNode;
|
|
32636
|
-
let hasParentNode = false;
|
|
32637
|
-
if (!leaf.parentNodeId) {
|
|
32638
|
-
} else {
|
|
32639
|
-
hasParentNode = true;
|
|
32640
|
-
parentNode = response.nodes[leaf.parentNodeId];
|
|
32641
|
-
if (!parentNode) {
|
|
32642
|
-
throw new ValidationError("Parent node not found", {
|
|
32643
|
-
field: "parentNodeId",
|
|
32644
|
-
value: leaf.parentNodeId
|
|
32645
|
-
});
|
|
32646
|
-
}
|
|
32647
|
-
}
|
|
32648
|
-
const nodeTx = getTxFromRawTxBytes(leaf.nodeTx);
|
|
32649
|
-
const refundTx = getTxFromRawTxBytes(leaf.refundTx);
|
|
32650
|
-
if (hasParentNode) {
|
|
32651
|
-
const nodeTimelock = getCurrentTimelock(nodeTx.getInput(0).sequence);
|
|
32652
|
-
if (nodeTimelock > 100) {
|
|
32653
|
-
const expiredNodeTxLeaf = await this.transferService.testonly_expireTimeLockNodeTx(
|
|
32654
|
-
leaf,
|
|
32655
|
-
parentNode
|
|
32656
|
-
);
|
|
32657
|
-
if (!expiredNodeTxLeaf.nodes[0]) {
|
|
32658
|
-
throw new ValidationError("No expired node tx leaf", {
|
|
32659
|
-
field: "expiredNodeTxLeaf",
|
|
32660
|
-
value: expiredNodeTxLeaf
|
|
32661
|
-
});
|
|
32662
|
-
}
|
|
32663
|
-
leaf = expiredNodeTxLeaf.nodes[0];
|
|
32664
|
-
}
|
|
32665
|
-
}
|
|
32666
|
-
const refundTimelock = getCurrentTimelock(refundTx.getInput(0).sequence);
|
|
32667
|
-
if (refundTimelock > 100) {
|
|
32668
|
-
const expiredTxLeaf = await this.transferService.testonly_expireTimeLockRefundtx(leaf);
|
|
32669
|
-
if (!expiredTxLeaf.nodes[0]) {
|
|
32670
|
-
throw new ValidationError("No expired tx leaf", {
|
|
32671
|
-
field: "expiredTxLeaf",
|
|
32672
|
-
value: expiredTxLeaf
|
|
32673
|
-
});
|
|
32674
|
-
}
|
|
32675
|
-
leaf = expiredTxLeaf.nodes[0];
|
|
32676
|
-
}
|
|
32677
|
-
const leafIndex = this.leaves.findIndex((leaf2) => leaf2.id === leaf2.id);
|
|
32678
|
-
if (leafIndex !== -1) {
|
|
32679
|
-
this.leaves[leafIndex] = leaf;
|
|
32680
|
-
}
|
|
32681
|
-
} catch (error) {
|
|
32682
|
-
throw new NetworkError(
|
|
32683
|
-
"Failed to refresh timelock",
|
|
32684
|
-
{
|
|
32685
|
-
method: "refresh_timelock"
|
|
32686
|
-
},
|
|
32687
|
-
error
|
|
32688
|
-
);
|
|
32689
|
-
}
|
|
32690
|
-
}
|
|
32691
32675
|
cleanup() {
|
|
32692
32676
|
if (this.claimTransfersInterval) {
|
|
32693
32677
|
clearInterval(this.claimTransfersInterval);
|
|
@@ -32842,8 +32826,7 @@ var SparkWallet = class extends EventEmitter {
|
|
|
32842
32826
|
"getLightningReceiveRequest",
|
|
32843
32827
|
"getLightningSendRequest",
|
|
32844
32828
|
"getCoopExitRequest",
|
|
32845
|
-
"checkTimelock"
|
|
32846
|
-
"testOnly_expireTimelock"
|
|
32829
|
+
"checkTimelock"
|
|
32847
32830
|
];
|
|
32848
32831
|
methods.forEach((m) => this.wrapPublicSparkWalletMethodWithOtelSpan(m));
|
|
32849
32832
|
this.initWallet = this.wrapWithOtelSpan(
|
|
@@ -33905,7 +33888,7 @@ function collectResponses(responses) {
|
|
|
33905
33888
|
}
|
|
33906
33889
|
|
|
33907
33890
|
// src/utils/unilateral-exit.ts
|
|
33908
|
-
import { bytesToHex as bytesToHex12, hexToBytes as
|
|
33891
|
+
import { bytesToHex as bytesToHex12, hexToBytes as hexToBytes12 } from "@noble/curves/utils";
|
|
33909
33892
|
import { ripemd160 } from "@noble/hashes/legacy";
|
|
33910
33893
|
import { sha256 as sha25613 } from "@noble/hashes/sha2";
|
|
33911
33894
|
import * as btc4 from "@scure/btc-signer";
|
|
@@ -33920,7 +33903,7 @@ function isEphemeralAnchorOutput(script, amount) {
|
|
|
33920
33903
|
}
|
|
33921
33904
|
async function constructUnilateralExitTxs(nodeHexStrings, sparkClient, network) {
|
|
33922
33905
|
const result = [];
|
|
33923
|
-
const nodes = nodeHexStrings.map((hex) => TreeNode.decode(
|
|
33906
|
+
const nodes = nodeHexStrings.map((hex) => TreeNode.decode(hexToBytes12(hex)));
|
|
33924
33907
|
const nodeMap = /* @__PURE__ */ new Map();
|
|
33925
33908
|
for (const node of nodes) {
|
|
33926
33909
|
nodeMap.set(node.id, node);
|
|
@@ -34009,7 +33992,7 @@ async function constructUnilateralExitFeeBumpPackages(nodeHexStrings, utxos, fee
|
|
|
34009
33992
|
`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.`
|
|
34010
33993
|
);
|
|
34011
33994
|
}
|
|
34012
|
-
const nodeBytes =
|
|
33995
|
+
const nodeBytes = hexToBytes12(hex);
|
|
34013
33996
|
const node = TreeNode.decode(nodeBytes);
|
|
34014
33997
|
if (!node.id) {
|
|
34015
33998
|
throw new Error(
|
|
@@ -34123,7 +34106,7 @@ async function constructUnilateralExitFeeBumpPackages(nodeHexStrings, utxos, fee
|
|
|
34123
34106
|
usedUtxos,
|
|
34124
34107
|
correctedParentTx
|
|
34125
34108
|
} = constructFeeBumpTx(nodeTxHex, availableUtxos, feeRate, void 0);
|
|
34126
|
-
const feeBumpTx = btc4.Transaction.fromPSBT(
|
|
34109
|
+
const feeBumpTx = btc4.Transaction.fromPSBT(hexToBytes12(nodeFeeBumpPsbt));
|
|
34127
34110
|
var feeBumpOut = feeBumpTx.outputsLength === 1 ? feeBumpTx.getOutput(0) : null;
|
|
34128
34111
|
var feeBumpOutPubKey = null;
|
|
34129
34112
|
for (const usedUtxo of usedUtxos) {
|
|
@@ -34178,7 +34161,7 @@ async function constructUnilateralExitFeeBumpPackages(nodeHexStrings, utxos, fee
|
|
|
34178
34161
|
void 0
|
|
34179
34162
|
);
|
|
34180
34163
|
const feeBumpTx2 = btc4.Transaction.fromPSBT(
|
|
34181
|
-
|
|
34164
|
+
hexToBytes12(refundFeeBump.feeBumpPsbt)
|
|
34182
34165
|
);
|
|
34183
34166
|
var feeBumpOut = feeBumpTx2.outputsLength === 1 ? feeBumpTx2.getOutput(0) : null;
|
|
34184
34167
|
var feeBumpOutPubKey = null;
|
|
@@ -34293,9 +34276,9 @@ function constructFeeBumpTx(txHex, utxos, feeRate, previousFeeBumpTx) {
|
|
|
34293
34276
|
if (!fundingUtxo) {
|
|
34294
34277
|
throw new Error(`UTXO at index ${i} is undefined`);
|
|
34295
34278
|
}
|
|
34296
|
-
const pubKeyHash = hash160(
|
|
34279
|
+
const pubKeyHash = hash160(hexToBytes12(fundingUtxo.publicKey));
|
|
34297
34280
|
const scriptToUse = new Uint8Array([0, 20, ...pubKeyHash]);
|
|
34298
|
-
const providedScript =
|
|
34281
|
+
const providedScript = hexToBytes12(fundingUtxo.script);
|
|
34299
34282
|
if (bytesToHex12(scriptToUse) !== bytesToHex12(providedScript)) {
|
|
34300
34283
|
throw new Error(
|
|
34301
34284
|
`\u274C Derived script doesn't match provided script for UTXO ${i + 1}.`
|
|
@@ -34423,7 +34406,6 @@ export {
|
|
|
34423
34406
|
DIRECT_TIMELOCK_OFFSET,
|
|
34424
34407
|
DefaultSparkSigner,
|
|
34425
34408
|
HTLC_TIMELOCK_OFFSET,
|
|
34426
|
-
INITIAL_DIRECT_SEQUENCE,
|
|
34427
34409
|
INITIAL_SEQUENCE,
|
|
34428
34410
|
InternalValidationError,
|
|
34429
34411
|
LOGGER_NAMES,
|
|
@@ -34456,21 +34438,24 @@ export {
|
|
|
34456
34438
|
constructFeeBumpTx,
|
|
34457
34439
|
constructUnilateralExitFeeBumpPackages,
|
|
34458
34440
|
constructUnilateralExitTxs,
|
|
34459
|
-
|
|
34460
|
-
|
|
34461
|
-
|
|
34462
|
-
|
|
34463
|
-
|
|
34464
|
-
|
|
34465
|
-
|
|
34441
|
+
createConnectorRefundTxs,
|
|
34442
|
+
createCurrentTimelockRefundTxs,
|
|
34443
|
+
createDecrementedTimelockNodeTx,
|
|
34444
|
+
createDecrementedTimelockRefundTxs,
|
|
34445
|
+
createInitialTimelockNodeTx,
|
|
34446
|
+
createInitialTimelockRefundTxs,
|
|
34447
|
+
createRootNodeTx,
|
|
34466
34448
|
createSigningCommitment,
|
|
34467
34449
|
createSigningNonce,
|
|
34468
|
-
|
|
34450
|
+
createTestUnilateralRefundTxs,
|
|
34451
|
+
createTestUnilateralTimelockNodeTx,
|
|
34452
|
+
createZeroTimelockNodeTx,
|
|
34469
34453
|
decodeBech32mTokenIdentifier,
|
|
34470
34454
|
decodeBytesToSigningCommitment,
|
|
34471
34455
|
decodeBytesToSigningNonce,
|
|
34472
34456
|
decodeSparkAddress,
|
|
34473
34457
|
doesLeafNeedRefresh,
|
|
34458
|
+
doesTxnNeedRenewed,
|
|
34474
34459
|
encodeBech32mTokenIdentifier,
|
|
34475
34460
|
encodeSigningCommitmentToBytes,
|
|
34476
34461
|
encodeSigningNonceToBytes,
|
|
@@ -34508,12 +34493,14 @@ export {
|
|
|
34508
34493
|
getTxFromRawTxHex,
|
|
34509
34494
|
getTxId,
|
|
34510
34495
|
getTxIdNoReverse,
|
|
34496
|
+
hash160,
|
|
34511
34497
|
isEphemeralAnchorOutput,
|
|
34512
34498
|
isLegacySparkAddress,
|
|
34513
34499
|
isSafeForNumber,
|
|
34514
34500
|
isTxBroadcast,
|
|
34515
34501
|
isValidPublicKey,
|
|
34516
34502
|
isValidSparkAddress,
|
|
34503
|
+
isZeroTimelock,
|
|
34517
34504
|
lastKeyWithTarget,
|
|
34518
34505
|
maybeApplyFee,
|
|
34519
34506
|
modInverse,
|