@buildonspark/spark-sdk 0.0.15 → 0.0.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. package/dist/services/wallet-config.d.ts +1 -0
  2. package/dist/services/wallet-config.js +1 -0
  3. package/dist/services/wallet-config.js.map +1 -1
  4. package/dist/spark-sdk.d.ts +1 -1
  5. package/dist/spark-sdk.js +3 -3
  6. package/dist/spark-sdk.js.map +1 -1
  7. package/package.json +4 -3
  8. package/src/examples/example.js +247 -0
  9. package/src/examples/example.ts +207 -0
  10. package/src/graphql/client.ts +282 -0
  11. package/src/graphql/mutations/CompleteCoopExit.ts +19 -0
  12. package/src/graphql/mutations/CompleteLeavesSwap.ts +17 -0
  13. package/src/graphql/mutations/RequestCoopExit.ts +20 -0
  14. package/src/graphql/mutations/RequestLightningReceive.ts +26 -0
  15. package/src/graphql/mutations/RequestLightningSend.ts +17 -0
  16. package/src/graphql/mutations/RequestSwapLeaves.ts +24 -0
  17. package/src/graphql/objects/BitcoinNetwork.ts +22 -0
  18. package/src/graphql/objects/CompleteCoopExitInput.ts +41 -0
  19. package/src/graphql/objects/CompleteCoopExitOutput.ts +45 -0
  20. package/src/graphql/objects/CompleteLeavesSwapInput.ts +45 -0
  21. package/src/graphql/objects/CompleteLeavesSwapOutput.ts +45 -0
  22. package/src/graphql/objects/CompleteSeedReleaseInput.ts +41 -0
  23. package/src/graphql/objects/CompleteSeedReleaseOutput.ts +43 -0
  24. package/src/graphql/objects/Connection.ts +90 -0
  25. package/src/graphql/objects/CoopExitFeeEstimateInput.ts +41 -0
  26. package/src/graphql/objects/CoopExitFeeEstimateOutput.ts +52 -0
  27. package/src/graphql/objects/CoopExitRequest.ts +118 -0
  28. package/src/graphql/objects/CurrencyAmount.ts +74 -0
  29. package/src/graphql/objects/CurrencyUnit.ts +32 -0
  30. package/src/graphql/objects/Entity.ts +202 -0
  31. package/src/graphql/objects/GetChallengeInput.ts +37 -0
  32. package/src/graphql/objects/GetChallengeOutput.ts +43 -0
  33. package/src/graphql/objects/Invoice.ts +83 -0
  34. package/src/graphql/objects/Leaf.ts +59 -0
  35. package/src/graphql/objects/LeavesSwapFeeEstimateInput.ts +37 -0
  36. package/src/graphql/objects/LeavesSwapFeeEstimateOutput.ts +52 -0
  37. package/src/graphql/objects/LeavesSwapRequest.ts +192 -0
  38. package/src/graphql/objects/LightningReceiveFeeEstimateInput.ts +41 -0
  39. package/src/graphql/objects/LightningReceiveFeeEstimateOutput.ts +52 -0
  40. package/src/graphql/objects/LightningReceiveRequest.ts +147 -0
  41. package/src/graphql/objects/LightningReceiveRequestStatus.ts +34 -0
  42. package/src/graphql/objects/LightningSendFeeEstimateInput.ts +37 -0
  43. package/src/graphql/objects/LightningSendFeeEstimateOutput.ts +52 -0
  44. package/src/graphql/objects/LightningSendRequest.ts +134 -0
  45. package/src/graphql/objects/LightningSendRequestStatus.ts +28 -0
  46. package/src/graphql/objects/NotifyReceiverTransferInput.ts +41 -0
  47. package/src/graphql/objects/PageInfo.ts +58 -0
  48. package/src/graphql/objects/Provider.ts +41 -0
  49. package/src/graphql/objects/RequestCoopExitInput.ts +41 -0
  50. package/src/graphql/objects/RequestCoopExitOutput.ts +45 -0
  51. package/src/graphql/objects/RequestLeavesSwapInput.ts +55 -0
  52. package/src/graphql/objects/RequestLeavesSwapOutput.ts +45 -0
  53. package/src/graphql/objects/RequestLightningReceiveInput.ts +58 -0
  54. package/src/graphql/objects/RequestLightningReceiveOutput.ts +45 -0
  55. package/src/graphql/objects/RequestLightningSendInput.ts +41 -0
  56. package/src/graphql/objects/RequestLightningSendOutput.ts +45 -0
  57. package/src/graphql/objects/SparkCoopExitRequestStatus.ts +20 -0
  58. package/src/graphql/objects/SparkLeavesSwapRequestStatus.ts +20 -0
  59. package/src/graphql/objects/SparkTransferToLeavesConnection.ts +79 -0
  60. package/src/graphql/objects/SparkWalletUser.ts +86 -0
  61. package/src/graphql/objects/StartSeedReleaseInput.ts +37 -0
  62. package/src/graphql/objects/SwapLeaf.ts +53 -0
  63. package/src/graphql/objects/Transfer.ts +98 -0
  64. package/src/graphql/objects/UserLeafInput.ts +28 -0
  65. package/src/graphql/objects/VerifyChallengeInput.ts +51 -0
  66. package/src/graphql/objects/VerifyChallengeOutput.ts +43 -0
  67. package/src/graphql/objects/WalletUserIdentityPublicKeyInput.ts +37 -0
  68. package/src/graphql/objects/WalletUserIdentityPublicKeyOutput.ts +43 -0
  69. package/src/graphql/objects/index.ts +67 -0
  70. package/src/graphql/queries/CoopExitFeeEstimate.ts +18 -0
  71. package/src/graphql/queries/CurrentUser.ts +10 -0
  72. package/src/graphql/queries/LightningReceiveFeeEstimate.ts +18 -0
  73. package/src/graphql/queries/LightningSendFeeEstimate.ts +16 -0
  74. package/src/proto/common.ts +431 -0
  75. package/src/proto/google/protobuf/descriptor.ts +6625 -0
  76. package/src/proto/google/protobuf/duration.ts +197 -0
  77. package/src/proto/google/protobuf/empty.ts +83 -0
  78. package/src/proto/google/protobuf/timestamp.ts +226 -0
  79. package/src/proto/mock.ts +151 -0
  80. package/src/proto/spark.ts +12727 -0
  81. package/src/proto/spark_authn.ts +673 -0
  82. package/src/proto/validate/validate.ts +6047 -0
  83. package/src/services/config.ts +71 -0
  84. package/src/services/connection.ts +264 -0
  85. package/src/services/coop-exit.ts +190 -0
  86. package/src/services/deposit.ts +327 -0
  87. package/src/services/lightning.ts +341 -0
  88. package/src/services/lrc20.ts +42 -0
  89. package/src/services/token-transactions.ts +499 -0
  90. package/src/services/transfer.ts +1188 -0
  91. package/src/services/tree-creation.ts +618 -0
  92. package/src/services/wallet-config.ts +141 -0
  93. package/src/signer/signer.ts +531 -0
  94. package/src/spark-sdk.ts +1644 -0
  95. package/src/tests/adaptor-signature.test.ts +64 -0
  96. package/src/tests/bitcoin.test.ts +122 -0
  97. package/src/tests/coop-exit.test.ts +233 -0
  98. package/src/tests/deposit.test.ts +98 -0
  99. package/src/tests/keys.test.ts +82 -0
  100. package/src/tests/lightning.test.ts +307 -0
  101. package/src/tests/secret-sharing.test.ts +63 -0
  102. package/src/tests/swap.test.ts +252 -0
  103. package/src/tests/test-util.ts +92 -0
  104. package/src/tests/tokens.test.ts +47 -0
  105. package/src/tests/transfer.test.ts +371 -0
  106. package/src/tests/tree-creation.test.ts +56 -0
  107. package/src/tests/utils/spark-testing-wallet.ts +37 -0
  108. package/src/tests/utils/test-faucet.ts +257 -0
  109. package/src/types/grpc.ts +8 -0
  110. package/src/types/index.ts +3 -0
  111. package/src/utils/adaptor-signature.ts +189 -0
  112. package/src/utils/bitcoin.ts +138 -0
  113. package/src/utils/crypto.ts +14 -0
  114. package/src/utils/index.ts +12 -0
  115. package/src/utils/keys.ts +92 -0
  116. package/src/utils/mempool.ts +42 -0
  117. package/src/utils/network.ts +70 -0
  118. package/src/utils/proof.ts +17 -0
  119. package/src/utils/response-validation.ts +26 -0
  120. package/src/utils/secret-sharing.ts +263 -0
  121. package/src/utils/signing.ts +96 -0
  122. package/src/utils/token-hashing.ts +163 -0
  123. package/src/utils/token-keyshares.ts +31 -0
  124. package/src/utils/token-transactions.ts +71 -0
  125. package/src/utils/transaction.ts +45 -0
  126. package/src/utils/wasm-wrapper.ts +57 -0
  127. package/src/utils/wasm.ts +154 -0
  128. package/src/wasm/spark_bindings.d.ts +208 -0
  129. package/src/wasm/spark_bindings.js +1161 -0
  130. package/src/wasm/spark_bindings_bg.wasm +0 -0
  131. package/src/wasm/spark_bindings_bg.wasm.d.ts +136 -0
@@ -0,0 +1,618 @@
1
+ import { Address, OutScript, Transaction } from "@scure/btc-signer";
2
+ import { sha256 } from "@scure/btc-signer/utils";
3
+ import {
4
+ AddressNode,
5
+ AddressRequestNode,
6
+ CreateTreeRequest,
7
+ CreateTreeResponse,
8
+ CreationNode,
9
+ CreationResponseNode,
10
+ FinalizeNodeSignaturesResponse,
11
+ NodeSignatures,
12
+ PrepareTreeAddressRequest,
13
+ PrepareTreeAddressResponse,
14
+ SigningJob,
15
+ TreeNode,
16
+ } from "../proto/spark.js";
17
+ import { SigningCommitment } from "../signer/signer.js";
18
+ import {
19
+ getP2TRAddressFromPublicKey,
20
+ getSigHashFromTx,
21
+ getTxFromRawTxBytes,
22
+ getTxId,
23
+ } from "../utils/bitcoin.js";
24
+ import { getNetwork, Network } from "../utils/network.js";
25
+ import { getEphemeralAnchorOutput } from "../utils/transaction.js";
26
+ import { WalletConfigService } from "./config.js";
27
+ import { ConnectionManager } from "./connection.js";
28
+
29
+ export type DepositAddressTree = {
30
+ address?: string | undefined;
31
+ signingPublicKey: Uint8Array;
32
+ verificationKey?: Uint8Array | undefined;
33
+ children: DepositAddressTree[];
34
+ };
35
+
36
+ export type CreationNodeWithNonces = CreationNode & {
37
+ nodeTxSigningCommitment?: SigningCommitment | undefined;
38
+ refundTxSigningCommitment?: SigningCommitment | undefined;
39
+ };
40
+
41
+ const INITIAL_TIME_LOCK = 2000;
42
+
43
+ export class TreeCreationService {
44
+ private readonly config: WalletConfigService;
45
+ private readonly connectionManager: ConnectionManager;
46
+
47
+ constructor(
48
+ config: WalletConfigService,
49
+ connectionManager: ConnectionManager,
50
+ ) {
51
+ this.config = config;
52
+ this.connectionManager = connectionManager;
53
+ }
54
+
55
+ async generateDepositAddressForTree(
56
+ vout: number,
57
+ parentSigningPublicKey: Uint8Array,
58
+ parentTx?: Transaction,
59
+ parentNode?: TreeNode,
60
+ ): Promise<DepositAddressTree> {
61
+ if (!parentTx && !parentNode) {
62
+ throw new Error("No parent tx or parent node provided");
63
+ }
64
+
65
+ const id = parentNode?.id ?? getTxId(parentTx!);
66
+
67
+ const tree = await this.createDepositAddressTree(
68
+ parentSigningPublicKey,
69
+ id,
70
+ );
71
+
72
+ const addressRequestNodes =
73
+ this.createAddressRequestNodeFromTreeNodes(tree);
74
+ const sparkClient = await this.connectionManager.createSparkClient(
75
+ this.config.getCoordinatorAddress(),
76
+ );
77
+
78
+ const request: PrepareTreeAddressRequest = {
79
+ userIdentityPublicKey: await this.config.signer.getIdentityPublicKey(),
80
+ node: undefined,
81
+ };
82
+ if (parentNode) {
83
+ if (!parentNode.parentNodeId) {
84
+ throw new Error("Parent node ID is undefined");
85
+ }
86
+ request.source = {
87
+ $case: "parentNodeOutput",
88
+ parentNodeOutput: {
89
+ nodeId: parentNode.parentNodeId,
90
+ vout: vout,
91
+ },
92
+ };
93
+ } else if (parentTx) {
94
+ request.source = {
95
+ $case: "onChainUtxo",
96
+ onChainUtxo: {
97
+ vout: vout,
98
+ rawTx: parentTx.toBytes(),
99
+ network: this.config.getNetworkProto(),
100
+ },
101
+ };
102
+ } else {
103
+ throw new Error("No parent node or parent tx provided");
104
+ }
105
+
106
+ request.node = {
107
+ userPublicKey: parentSigningPublicKey,
108
+ children: addressRequestNodes,
109
+ };
110
+
111
+ const root: DepositAddressTree = {
112
+ address: undefined,
113
+ signingPublicKey: parentSigningPublicKey,
114
+ children: tree,
115
+ };
116
+
117
+ let response: PrepareTreeAddressResponse;
118
+ try {
119
+ response = await sparkClient.prepare_tree_address(request);
120
+ } catch (error) {
121
+ throw new Error(`Error preparing tree address: ${error}`);
122
+ }
123
+
124
+ if (!response.node) {
125
+ throw new Error("No node found in response");
126
+ }
127
+
128
+ this.applyAddressNodesToTree([root], [response.node]);
129
+
130
+ return root;
131
+ }
132
+
133
+ async createTree(
134
+ vout: number,
135
+ root: DepositAddressTree,
136
+ createLeaves: boolean,
137
+ parentTx?: Transaction,
138
+ parentNode?: TreeNode,
139
+ ): Promise<FinalizeNodeSignaturesResponse> {
140
+ const request: CreateTreeRequest = {
141
+ userIdentityPublicKey: await this.config.signer.getIdentityPublicKey(),
142
+ node: undefined,
143
+ };
144
+
145
+ let tx: Transaction | undefined;
146
+ if (parentTx) {
147
+ tx = parentTx;
148
+ request.source = {
149
+ $case: "onChainUtxo",
150
+ onChainUtxo: {
151
+ vout: vout,
152
+ rawTx: parentTx.toBytes(),
153
+ network: this.config.getNetworkProto(),
154
+ },
155
+ };
156
+ } else if (parentNode) {
157
+ tx = getTxFromRawTxBytes(parentNode.nodeTx);
158
+ if (!parentNode.parentNodeId) {
159
+ throw new Error("Parent node ID is undefined");
160
+ }
161
+ request.source = {
162
+ $case: "parentNodeOutput",
163
+ parentNodeOutput: {
164
+ nodeId: parentNode.parentNodeId,
165
+ vout: vout,
166
+ },
167
+ };
168
+ } else {
169
+ throw new Error("No parent node or parent tx provided");
170
+ }
171
+
172
+ const rootCreationNode = await this.buildCreationNodesFromTree(
173
+ vout,
174
+ createLeaves,
175
+ this.config.getNetwork(),
176
+ root,
177
+ tx,
178
+ );
179
+
180
+ request.node = rootCreationNode;
181
+
182
+ const sparkClient = await this.connectionManager.createSparkClient(
183
+ this.config.getCoordinatorAddress(),
184
+ );
185
+
186
+ let response: CreateTreeResponse;
187
+ try {
188
+ response = await sparkClient.create_tree(request);
189
+ } catch (error) {
190
+ throw new Error(`Error creating tree: ${error}`);
191
+ }
192
+
193
+ if (!response.node) {
194
+ throw new Error("No node found in response");
195
+ }
196
+
197
+ const creationResultTreeRoot = response.node;
198
+
199
+ const nodeSignatures = await this.signTreeCreation(
200
+ tx,
201
+ vout,
202
+ root,
203
+ rootCreationNode,
204
+ creationResultTreeRoot,
205
+ );
206
+
207
+ let finalizeResp: FinalizeNodeSignaturesResponse;
208
+ try {
209
+ finalizeResp = await sparkClient.finalize_node_signatures({
210
+ nodeSignatures: nodeSignatures,
211
+ });
212
+ } catch (error) {
213
+ throw new Error(
214
+ `Error finalizing node signatures in tree creation: ${error}`,
215
+ );
216
+ }
217
+
218
+ return finalizeResp;
219
+ }
220
+
221
+ private async createDepositAddressTree(
222
+ targetSigningPublicKey: Uint8Array,
223
+ nodeId: string,
224
+ ): Promise<DepositAddressTree[]> {
225
+ const leftKey = await this.config.signer.generatePublicKey(sha256(nodeId));
226
+ const leftNode: DepositAddressTree = {
227
+ signingPublicKey: leftKey,
228
+ children: [],
229
+ };
230
+
231
+ const rightKey =
232
+ await this.config.signer.subtractPrivateKeysGivenPublicKeys(
233
+ targetSigningPublicKey,
234
+ leftKey,
235
+ );
236
+
237
+ const rightNode: DepositAddressTree = {
238
+ signingPublicKey: rightKey,
239
+ children: [],
240
+ };
241
+ return [leftNode, rightNode];
242
+ }
243
+
244
+ private createAddressRequestNodeFromTreeNodes(
245
+ treeNodes: DepositAddressTree[],
246
+ ): AddressRequestNode[] {
247
+ const results: AddressRequestNode[] = [];
248
+ for (const node of treeNodes) {
249
+ const result: AddressRequestNode = {
250
+ userPublicKey: node.signingPublicKey,
251
+ children: this.createAddressRequestNodeFromTreeNodes(node.children),
252
+ };
253
+ results.push(result);
254
+ }
255
+ return results;
256
+ }
257
+
258
+ private applyAddressNodesToTree(
259
+ tree: DepositAddressTree[],
260
+ addressNodes: AddressNode[],
261
+ ) {
262
+ for (let i = 0; i < tree.length; i++) {
263
+ if (!tree[i]) {
264
+ throw new Error("Tree or address node is undefined");
265
+ }
266
+ if (!addressNodes[i]) {
267
+ throw new Error("Address node is undefined");
268
+ }
269
+ // @ts-ignore
270
+ tree[i].address = addressNodes[i].address?.address;
271
+ // @ts-ignore
272
+ tree[i].verificationKey = addressNodes[i].address?.verifyingKey;
273
+ // @ts-ignore
274
+ this.applyAddressNodesToTree(tree[i].children, addressNodes[i].children);
275
+ }
276
+ }
277
+
278
+ private async buildChildCreationNode(
279
+ node: DepositAddressTree,
280
+ parentTx: Transaction,
281
+ vout: number,
282
+ network: Network,
283
+ ): Promise<CreationNodeWithNonces> {
284
+ // internal node
285
+ const internalCreationNode: CreationNodeWithNonces = {
286
+ nodeTxSigningJob: undefined,
287
+ refundTxSigningJob: undefined,
288
+ children: [],
289
+ };
290
+
291
+ const tx = new Transaction();
292
+ tx.addInput({
293
+ txid: getTxId(parentTx),
294
+ index: vout,
295
+ });
296
+
297
+ const parentTxOut = parentTx.getOutput(vout);
298
+ if (!parentTxOut?.script || !parentTxOut?.amount) {
299
+ throw new Error("parentTxOut is undefined");
300
+ }
301
+
302
+ tx.addOutput({
303
+ script: parentTxOut.script,
304
+ amount: parentTxOut.amount,
305
+ });
306
+
307
+ // Add ephemeral anchor
308
+ tx.addOutput(getEphemeralAnchorOutput());
309
+
310
+ const signingNonceCommitment =
311
+ await this.config.signer.getRandomSigningCommitment();
312
+ const signingJob: SigningJob = {
313
+ signingPublicKey: node.signingPublicKey,
314
+ rawTx: tx.toBytes(),
315
+ signingNonceCommitment: signingNonceCommitment,
316
+ };
317
+
318
+ internalCreationNode.nodeTxSigningCommitment = signingNonceCommitment;
319
+ internalCreationNode.nodeTxSigningJob = signingJob;
320
+
321
+ // leaf node
322
+ const sequence = (1 << 30) | INITIAL_TIME_LOCK;
323
+
324
+ const childCreationNode: CreationNodeWithNonces = {
325
+ nodeTxSigningJob: undefined,
326
+ refundTxSigningJob: undefined,
327
+ children: [],
328
+ };
329
+
330
+ const childTx = new Transaction();
331
+ childTx.addInput({
332
+ txid: getTxId(tx),
333
+ index: 0,
334
+ sequence,
335
+ });
336
+
337
+ childTx.addOutput({
338
+ script: parentTxOut.script,
339
+ amount: parentTxOut.amount,
340
+ });
341
+
342
+ // Add ephemeral anchor
343
+ childTx.addOutput(getEphemeralAnchorOutput());
344
+
345
+ const childSigningNonceCommitment =
346
+ await this.config.signer.getRandomSigningCommitment();
347
+ const childSigningJob: SigningJob = {
348
+ signingPublicKey: node.signingPublicKey,
349
+ rawTx: childTx.toBytes(),
350
+ signingNonceCommitment: childSigningNonceCommitment,
351
+ };
352
+
353
+ childCreationNode.nodeTxSigningCommitment = childSigningNonceCommitment;
354
+ childCreationNode.nodeTxSigningJob = childSigningJob;
355
+
356
+ const refundTx = new Transaction();
357
+ refundTx.addInput({
358
+ txid: getTxId(childTx),
359
+ index: 0,
360
+ sequence,
361
+ });
362
+
363
+ const refundP2trAddress = getP2TRAddressFromPublicKey(
364
+ node.signingPublicKey,
365
+ network,
366
+ );
367
+ const refundAddress = Address(getNetwork(network)).decode(
368
+ refundP2trAddress,
369
+ );
370
+ const refundPkScript = OutScript.encode(refundAddress);
371
+ refundTx.addOutput({
372
+ script: refundPkScript,
373
+ amount: parentTxOut.amount,
374
+ });
375
+
376
+ const refundSigningNonceCommitment =
377
+ await this.config.signer.getRandomSigningCommitment();
378
+
379
+ const refundSigningJob: SigningJob = {
380
+ signingPublicKey: node.signingPublicKey,
381
+ rawTx: refundTx.toBytes(),
382
+ signingNonceCommitment: refundSigningNonceCommitment,
383
+ };
384
+ childCreationNode.refundTxSigningCommitment = refundSigningNonceCommitment;
385
+ childCreationNode.refundTxSigningJob = refundSigningJob;
386
+
387
+ internalCreationNode.children.push(childCreationNode);
388
+
389
+ return internalCreationNode;
390
+ }
391
+
392
+ private async buildCreationNodesFromTree(
393
+ vout: number,
394
+ createLeaves: boolean,
395
+ network: Network,
396
+ root: DepositAddressTree,
397
+ parentTx: Transaction,
398
+ ): Promise<CreationNodeWithNonces> {
399
+ const parentTxOutput = parentTx.getOutput(vout);
400
+ if (!parentTxOutput?.script || !parentTxOutput?.amount) {
401
+ throw new Error("parentTxOutput is undefined");
402
+ }
403
+ const rootNodeTx = new Transaction();
404
+ rootNodeTx.addInput({
405
+ txid: getTxId(parentTx),
406
+ index: vout,
407
+ });
408
+
409
+ for (let i = 0; i < root.children.length; i++) {
410
+ const child = root.children[i];
411
+ if (!child || !child.address) {
412
+ throw new Error("child address is undefined");
413
+ }
414
+ const childAddress = Address(getNetwork(network)).decode(child.address);
415
+ const childPkScript = OutScript.encode(childAddress);
416
+ rootNodeTx.addOutput({
417
+ script: childPkScript,
418
+ amount: parentTxOutput.amount / 2n,
419
+ });
420
+ }
421
+
422
+ // Add ephemeral anchor output
423
+ const anchor = getEphemeralAnchorOutput();
424
+ rootNodeTx.addOutput(anchor);
425
+
426
+ const rootNodeSigningCommitment =
427
+ await this.config.signer.getRandomSigningCommitment();
428
+ const rootNodeSigningJob: SigningJob = {
429
+ signingPublicKey: root.signingPublicKey,
430
+ rawTx: rootNodeTx.toBytes(),
431
+ signingNonceCommitment: rootNodeSigningCommitment,
432
+ };
433
+ const rootCreationNode: CreationNodeWithNonces = {
434
+ nodeTxSigningJob: rootNodeSigningJob,
435
+ refundTxSigningJob: undefined,
436
+ children: [],
437
+ };
438
+ rootCreationNode.nodeTxSigningCommitment = rootNodeSigningCommitment;
439
+
440
+ const leftChild = root.children[0];
441
+ const rightChild = root.children[1];
442
+ if (!leftChild || !rightChild) {
443
+ throw new Error("Root children are undefined");
444
+ }
445
+
446
+ const leftChildCreationNode = await this.buildChildCreationNode(
447
+ leftChild,
448
+ rootNodeTx,
449
+ 0,
450
+ network,
451
+ );
452
+ const rightChildCreationNode = await this.buildChildCreationNode(
453
+ rightChild,
454
+ rootNodeTx,
455
+ 1,
456
+ network,
457
+ );
458
+
459
+ rootCreationNode.children.push(leftChildCreationNode);
460
+ rootCreationNode.children.push(rightChildCreationNode);
461
+
462
+ return rootCreationNode;
463
+ }
464
+
465
+ private async signNodeCreation(
466
+ parentTx: Transaction,
467
+ vout: number,
468
+ internalNode: DepositAddressTree,
469
+ creationNode: CreationNodeWithNonces,
470
+ creationResponseNode: CreationResponseNode,
471
+ ): Promise<{ tx: Transaction; signature: NodeSignatures }> {
472
+ if (
473
+ !creationNode.nodeTxSigningJob?.signingPublicKey ||
474
+ !internalNode.verificationKey
475
+ ) {
476
+ throw new Error("signingPublicKey or verificationKey is undefined");
477
+ }
478
+
479
+ const parentTxOutput = parentTx.getOutput(vout);
480
+ if (!parentTxOutput) {
481
+ throw new Error("parentTxOutput is undefined");
482
+ }
483
+
484
+ const tx = getTxFromRawTxBytes(creationNode.nodeTxSigningJob.rawTx);
485
+ const txSighash = getSigHashFromTx(tx, 0, parentTxOutput);
486
+
487
+ let nodeTxSignature: Uint8Array = new Uint8Array();
488
+ if (creationNode.nodeTxSigningCommitment) {
489
+ const userSignature = await this.config.signer.signFrost({
490
+ message: txSighash,
491
+ publicKey: creationNode.nodeTxSigningJob.signingPublicKey,
492
+ privateAsPubKey: internalNode.signingPublicKey,
493
+ selfCommitment: creationNode.nodeTxSigningCommitment,
494
+ statechainCommitments:
495
+ creationResponseNode.nodeTxSigningResult?.signingNonceCommitments,
496
+ verifyingKey: internalNode.verificationKey,
497
+ });
498
+
499
+ nodeTxSignature = await this.config.signer.aggregateFrost({
500
+ message: txSighash,
501
+ statechainSignatures:
502
+ creationResponseNode.nodeTxSigningResult?.signatureShares,
503
+ statechainPublicKeys:
504
+ creationResponseNode.nodeTxSigningResult?.publicKeys,
505
+ verifyingKey: internalNode.verificationKey,
506
+ statechainCommitments:
507
+ creationResponseNode.nodeTxSigningResult?.signingNonceCommitments,
508
+ selfCommitment: creationNode.nodeTxSigningCommitment,
509
+ selfSignature: userSignature,
510
+ publicKey: internalNode.signingPublicKey,
511
+ });
512
+ }
513
+
514
+ let refundTxSignature: Uint8Array = new Uint8Array();
515
+ if (creationNode.refundTxSigningCommitment) {
516
+ const rawTx = creationNode.refundTxSigningJob?.rawTx;
517
+ if (!rawTx) {
518
+ throw new Error("rawTx is undefined");
519
+ }
520
+ if (!creationNode.refundTxSigningJob?.signingPublicKey) {
521
+ throw new Error("signingPublicKey is undefined");
522
+ }
523
+ const refundTx = getTxFromRawTxBytes(rawTx);
524
+ const refundTxSighash = getSigHashFromTx(refundTx, 0, parentTxOutput);
525
+
526
+ const refundSigningResponse = await this.config.signer.signFrost({
527
+ message: refundTxSighash,
528
+ publicKey: creationNode.refundTxSigningJob.signingPublicKey,
529
+ privateAsPubKey: internalNode.signingPublicKey,
530
+ selfCommitment: creationNode.refundTxSigningCommitment,
531
+ statechainCommitments:
532
+ creationResponseNode.refundTxSigningResult?.signingNonceCommitments,
533
+ verifyingKey: internalNode.verificationKey,
534
+ });
535
+
536
+ refundTxSignature = await this.config.signer.aggregateFrost({
537
+ message: refundTxSighash,
538
+ statechainSignatures:
539
+ creationResponseNode.refundTxSigningResult?.signatureShares,
540
+ statechainPublicKeys:
541
+ creationResponseNode.refundTxSigningResult?.publicKeys,
542
+ verifyingKey: internalNode.verificationKey,
543
+ statechainCommitments:
544
+ creationResponseNode.refundTxSigningResult?.signingNonceCommitments,
545
+ selfCommitment: creationNode.refundTxSigningCommitment,
546
+ selfSignature: refundSigningResponse,
547
+ publicKey: internalNode.signingPublicKey,
548
+ });
549
+ }
550
+
551
+ return {
552
+ tx: tx,
553
+ signature: {
554
+ nodeId: creationResponseNode.nodeId,
555
+ nodeTxSignature: nodeTxSignature,
556
+ refundTxSignature: refundTxSignature,
557
+ },
558
+ };
559
+ }
560
+
561
+ private async signTreeCreation(
562
+ tx: Transaction,
563
+ vout: number,
564
+ root: DepositAddressTree,
565
+ rootCreationNode: CreationNodeWithNonces,
566
+ creationResultTreeRoot: CreationResponseNode,
567
+ ): Promise<NodeSignatures[]> {
568
+ const rootSignature = await this.signNodeCreation(
569
+ tx,
570
+ vout,
571
+ root,
572
+ rootCreationNode,
573
+ creationResultTreeRoot,
574
+ );
575
+
576
+ const firstRootChild = root.children[0];
577
+ const secondRootChild = root.children[1];
578
+ const firstRootChildCreationNode = rootCreationNode.children[0];
579
+ const secondRootChildCreationNode = rootCreationNode.children[1];
580
+ const firstRootChildCreationResult = creationResultTreeRoot.children[0];
581
+ const secondRootChildCreationResult = creationResultTreeRoot.children[1];
582
+ if (!firstRootChild || !secondRootChild) {
583
+ throw new Error("Root children are undefined");
584
+ }
585
+
586
+ if (!firstRootChildCreationNode || !secondRootChildCreationNode) {
587
+ throw new Error("Root child creation nodes are undefined");
588
+ }
589
+
590
+ if (!firstRootChildCreationResult || !secondRootChildCreationResult) {
591
+ throw new Error("Root child creation results are undefined");
592
+ }
593
+
594
+ const leftChildSignature = await this.signNodeCreation(
595
+ rootSignature.tx,
596
+ 0,
597
+ firstRootChild,
598
+ firstRootChildCreationNode,
599
+ firstRootChildCreationResult,
600
+ );
601
+
602
+ const rightChildSignature = await this.signNodeCreation(
603
+ rootSignature.tx,
604
+ 1,
605
+ secondRootChild,
606
+ secondRootChildCreationNode,
607
+ secondRootChildCreationResult,
608
+ );
609
+
610
+ const signatures = [
611
+ rootSignature.signature,
612
+ leftChildSignature.signature,
613
+ rightChildSignature.signature,
614
+ ];
615
+
616
+ return signatures;
617
+ }
618
+ }