@buildonspark/spark-sdk 0.1.45 → 0.1.47

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 (146) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/dist/{chunk-I54FARY2.js → chunk-EAP3U3CW.js} +14 -14
  3. package/dist/chunk-GWFQ7EBA.js +3773 -0
  4. package/dist/{chunk-J2IE4Z7Y.js → chunk-NNX4OK44.js} +3487 -934
  5. package/dist/{RequestLightningSendInput-Du0z7Om7.d.cts → client-CvpTRpcw.d.cts} +422 -212
  6. package/dist/{RequestLightningSendInput-DEPd_fPO.d.ts → client-D7KgLN44.d.ts} +422 -212
  7. package/dist/graphql/objects/index.d.cts +5 -9
  8. package/dist/graphql/objects/index.d.ts +5 -9
  9. package/dist/graphql/objects/index.js +1 -1
  10. package/dist/index.cjs +20461 -23377
  11. package/dist/index.d.cts +15 -769
  12. package/dist/index.d.ts +15 -769
  13. package/dist/index.js +81 -71
  14. package/dist/index.node.cjs +21994 -25018
  15. package/dist/index.node.d.cts +312 -34
  16. package/dist/index.node.d.ts +312 -34
  17. package/dist/index.node.js +82 -176
  18. package/dist/native/index.cjs +22847 -25841
  19. package/dist/native/index.d.cts +974 -1138
  20. package/dist/native/index.d.ts +974 -1138
  21. package/dist/native/index.js +10604 -13592
  22. package/dist/proto/lrc20.d.cts +2 -2
  23. package/dist/proto/lrc20.d.ts +2 -2
  24. package/dist/proto/lrc20.js +3098 -46
  25. package/dist/proto/spark.d.cts +1 -1
  26. package/dist/proto/spark.d.ts +1 -1
  27. package/dist/proto/spark_token.d.cts +1 -1
  28. package/dist/proto/spark_token.d.ts +1 -1
  29. package/dist/{sdk-types-Cc4l4kb1.d.ts → sdk-types-BGCeea0G.d.ts} +1 -1
  30. package/dist/{sdk-types-B0SwjolI.d.cts → sdk-types-XUeQMLFP.d.cts} +1 -1
  31. package/dist/{spark-dM7EYXYQ.d.cts → spark-BbUrbvZz.d.cts} +1 -1
  32. package/dist/{spark-dM7EYXYQ.d.ts → spark-BbUrbvZz.d.ts} +1 -1
  33. package/dist/spark-wallet-BAFPpPtY.d.cts +923 -0
  34. package/dist/spark-wallet-CJkQW8pK.d.ts +923 -0
  35. package/dist/spark_bindings/native/index.d.cts +1 -1
  36. package/dist/spark_bindings/native/index.d.ts +1 -1
  37. package/dist/spark_bindings/wasm/index.d.cts +1 -1
  38. package/dist/spark_bindings/wasm/index.d.ts +1 -1
  39. package/dist/{services/index.cjs → tests/test-utils.cjs} +2512 -4380
  40. package/dist/tests/test-utils.d.cts +79 -0
  41. package/dist/tests/test-utils.d.ts +79 -0
  42. package/dist/tests/test-utils.js +85 -0
  43. package/dist/types/index.d.cts +5 -9
  44. package/dist/types/index.d.ts +5 -9
  45. package/dist/types/index.js +5 -5
  46. package/dist/{types-C-Rp0Oo7.d.cts → types-BADxR3bm.d.cts} +1 -1
  47. package/dist/{types-C-Rp0Oo7.d.ts → types-BADxR3bm.d.ts} +1 -1
  48. package/package.json +7 -35
  49. package/src/graphql/client.ts +59 -20
  50. package/src/index.node.ts +28 -2
  51. package/src/index.ts +31 -1
  52. package/src/native/index.ts +16 -2
  53. package/src/services/config.ts +4 -6
  54. package/src/services/connection.ts +131 -64
  55. package/src/services/lightning.ts +1 -2
  56. package/src/services/token-transactions.ts +7 -7
  57. package/src/services/transfer.ts +1 -1
  58. package/src/services/tree-creation.ts +1 -1
  59. package/src/services/wallet-config.ts +18 -10
  60. package/src/signer/signer.react-native.ts +2 -5
  61. package/src/signer/signer.ts +138 -64
  62. package/src/signer/types.ts +52 -0
  63. package/src/spark-wallet/spark-wallet.ts +79 -36
  64. package/src/spark-wallet/types.ts +4 -4
  65. package/src/tests/integration/coop-exit.test.ts +2 -1
  66. package/src/tests/integration/lightning.test.ts +2 -2
  67. package/src/tests/integration/swap.test.ts +1 -1
  68. package/src/tests/integration/transfer.test.ts +5 -5
  69. package/src/tests/integration/tree-creation.test.ts +1 -1
  70. package/src/tests/integration/wallet.test.ts +1 -0
  71. package/src/tests/isHermeticTest.ts +3 -24
  72. package/src/tests/{test-util.ts → test-utils.ts} +3 -7
  73. package/src/tests/wrapWithOtelSpan.test.ts +1 -1
  74. package/src/{address → utils}/address.ts +1 -1
  75. package/src/utils/crypto.ts +19 -9
  76. package/src/utils/index.ts +2 -0
  77. package/src/utils/network.ts +17 -0
  78. package/src/utils/secret-sharing.ts +1 -2
  79. package/src/utils/signing.ts +1 -1
  80. package/src/utils/token-transactions.ts +3 -3
  81. package/src/utils/unilateral-exit.ts +32 -0
  82. package/src/utils/xchain-address.ts +1 -1
  83. package/dist/BitcoinNetwork-TnABML0T.d.cts +0 -18
  84. package/dist/BitcoinNetwork-TnABML0T.d.ts +0 -18
  85. package/dist/LightningSendFeeEstimateInput-BgOhEAI-.d.cts +0 -10
  86. package/dist/LightningSendFeeEstimateInput-BgOhEAI-.d.ts +0 -10
  87. package/dist/address/index.cjs +0 -458
  88. package/dist/address/index.d.cts +0 -32
  89. package/dist/address/index.d.ts +0 -32
  90. package/dist/address/index.js +0 -17
  91. package/dist/chunk-5FUB65LX.js +0 -838
  92. package/dist/chunk-6264CGDM.js +0 -113
  93. package/dist/chunk-7V6N75CC.js +0 -24
  94. package/dist/chunk-C2S227QR.js +0 -2336
  95. package/dist/chunk-GSI4OLXZ.js +0 -117
  96. package/dist/chunk-GZ5IPPJ2.js +0 -170
  97. package/dist/chunk-HWJWKEIU.js +0 -75
  98. package/dist/chunk-KMUMFYFX.js +0 -137
  99. package/dist/chunk-L3EHBOUX.js +0 -0
  100. package/dist/chunk-NSJF5F5O.js +0 -325
  101. package/dist/chunk-NTFKFRQ2.js +0 -3146
  102. package/dist/chunk-PQN3C2MF.js +0 -1122
  103. package/dist/chunk-QNNSEJ4P.js +0 -232
  104. package/dist/chunk-R5PXJZQS.js +0 -277
  105. package/dist/chunk-VTUGIIWI.js +0 -0
  106. package/dist/chunk-YUPMXTCJ.js +0 -622
  107. package/dist/chunk-Z5HIAYFT.js +0 -84
  108. package/dist/index-B2AwKW5J.d.cts +0 -214
  109. package/dist/index-CJDi1HWc.d.ts +0 -214
  110. package/dist/network-BTJl-Sul.d.ts +0 -46
  111. package/dist/network-CqgsdUF2.d.cts +0 -46
  112. package/dist/services/config.cjs +0 -2354
  113. package/dist/services/config.d.cts +0 -42
  114. package/dist/services/config.d.ts +0 -42
  115. package/dist/services/config.js +0 -17
  116. package/dist/services/connection.cjs +0 -17691
  117. package/dist/services/connection.d.cts +0 -95
  118. package/dist/services/connection.d.ts +0 -95
  119. package/dist/services/connection.js +0 -11
  120. package/dist/services/index.d.cts +0 -21
  121. package/dist/services/index.d.ts +0 -21
  122. package/dist/services/index.js +0 -58
  123. package/dist/services/lrc-connection.cjs +0 -4713
  124. package/dist/services/lrc-connection.d.cts +0 -34
  125. package/dist/services/lrc-connection.d.ts +0 -34
  126. package/dist/services/lrc-connection.js +0 -11
  127. package/dist/services/token-transactions.cjs +0 -2877
  128. package/dist/services/token-transactions.d.cts +0 -75
  129. package/dist/services/token-transactions.d.ts +0 -75
  130. package/dist/services/token-transactions.js +0 -15
  131. package/dist/services/wallet-config.cjs +0 -340
  132. package/dist/services/wallet-config.d.cts +0 -56
  133. package/dist/services/wallet-config.d.ts +0 -56
  134. package/dist/services/wallet-config.js +0 -33
  135. package/dist/signer/signer.cjs +0 -2004
  136. package/dist/signer/signer.d.cts +0 -10
  137. package/dist/signer/signer.d.ts +0 -10
  138. package/dist/signer/signer.js +0 -24
  139. package/dist/signer-BocS_J6B.d.ts +0 -187
  140. package/dist/signer-DKS0AJkw.d.cts +0 -187
  141. package/dist/utils/index.cjs +0 -2947
  142. package/dist/utils/index.d.cts +0 -18
  143. package/dist/utils/index.d.ts +0 -18
  144. package/dist/utils/index.js +0 -157
  145. package/src/address/index.ts +0 -1
  146. package/src/services/lrc-connection.ts +0 -215
@@ -0,0 +1,3773 @@
1
+ import {
2
+ SparkTokenServiceDefinition
3
+ } from "./chunk-LHRD2WT6.js";
4
+ import {
5
+ Empty,
6
+ SparkServiceDefinition
7
+ } from "./chunk-BGGEVUJK.js";
8
+ import {
9
+ Buffer
10
+ } from "./chunk-MVRQ5US7.js";
11
+
12
+ // src/utils/crypto.ts
13
+ var cryptoImpl = globalThis.crypto ?? null;
14
+ var getCrypto = () => {
15
+ if (!cryptoImpl) {
16
+ throw new Error(
17
+ "Crypto implementation is not set. Please set it using setCrypto()."
18
+ );
19
+ }
20
+ return cryptoImpl;
21
+ };
22
+ var setCrypto = (cryptoImplParam) => {
23
+ cryptoImpl = cryptoImplParam;
24
+ };
25
+
26
+ // src/errors/base.ts
27
+ import { bytesToHex } from "@noble/hashes/utils";
28
+ var SparkSDKError = class extends Error {
29
+ context;
30
+ originalError;
31
+ constructor(message, context = {}, originalError) {
32
+ const msg = getMessage(message, context, originalError);
33
+ super(msg);
34
+ this.name = this.constructor.name;
35
+ this.context = context;
36
+ this.originalError = originalError;
37
+ if (Error.captureStackTrace) {
38
+ Error.captureStackTrace(this, this.constructor);
39
+ }
40
+ }
41
+ toString() {
42
+ return this.message;
43
+ }
44
+ toJSON() {
45
+ return {
46
+ name: this.name,
47
+ message: this.message,
48
+ context: this.context,
49
+ originalError: this.originalError ? {
50
+ name: this.originalError.name,
51
+ message: this.originalError.message,
52
+ stack: this.originalError.stack
53
+ } : void 0,
54
+ stack: this.stack
55
+ };
56
+ }
57
+ };
58
+ function getMessage(message, context = {}, originalError) {
59
+ const contextStr = Object.entries(context).map(([key, value]) => `${key}: ${safeStringify(value)}`).join(", ");
60
+ const originalErrorStr = originalError ? `
61
+ Original Error: ${originalError.message}` : "";
62
+ return `SparkSDKError: ${message}${contextStr ? `
63
+ Context: ${contextStr}` : ""}${originalErrorStr}`;
64
+ }
65
+ function safeStringify(value) {
66
+ const replacer = (_, v) => {
67
+ if (typeof v === "bigint") {
68
+ return v.toString();
69
+ }
70
+ if (v instanceof Uint8Array) {
71
+ return formatUint8Array(v);
72
+ }
73
+ return v;
74
+ };
75
+ if (typeof value === "bigint") {
76
+ return `"${value.toString()}"`;
77
+ }
78
+ if (value instanceof Uint8Array) {
79
+ return `"${formatUint8Array(value)}"`;
80
+ }
81
+ try {
82
+ const result = JSON.stringify(value, replacer);
83
+ return result === void 0 ? String(value) : result;
84
+ } catch {
85
+ try {
86
+ return String(value);
87
+ } catch {
88
+ return "[Unserializable]";
89
+ }
90
+ }
91
+ }
92
+ function formatUint8Array(arr) {
93
+ return `Uint8Array(0x${bytesToHex(arr)})`;
94
+ }
95
+
96
+ // src/errors/types.ts
97
+ var NetworkError = class extends SparkSDKError {
98
+ constructor(message, context = {}, originalError) {
99
+ super(message, context, originalError);
100
+ }
101
+ };
102
+ var ValidationError = class extends SparkSDKError {
103
+ constructor(message, context = {}, originalError) {
104
+ super(message, context, originalError);
105
+ }
106
+ };
107
+ var InternalValidationError = class extends SparkSDKError {
108
+ constructor(message, context = {}, originalError) {
109
+ super(message, context, originalError);
110
+ }
111
+ };
112
+ var AuthenticationError = class extends SparkSDKError {
113
+ constructor(message, context = {}, originalError) {
114
+ super(message, context, originalError);
115
+ }
116
+ };
117
+ var RPCError = class extends SparkSDKError {
118
+ constructor(message, context = {}, originalError) {
119
+ super(message, context, originalError);
120
+ }
121
+ };
122
+ var ConfigurationError = class extends SparkSDKError {
123
+ constructor(message, context = {}, originalError) {
124
+ super(message, context, originalError);
125
+ }
126
+ };
127
+ var NotImplementedError = class extends SparkSDKError {
128
+ constructor(message, context, originalError) {
129
+ super(message, context, originalError);
130
+ }
131
+ };
132
+
133
+ // src/utils/adaptor-signature.ts
134
+ import { mod } from "@noble/curves/abstract/modular";
135
+ import { bytesToNumberBE, numberToBytesBE } from "@noble/curves/abstract/utils";
136
+ import { schnorr, secp256k1 } from "@noble/curves/secp256k1";
137
+ function generateSignatureFromExistingAdaptor(signature, adaptorPrivateKeyBytes) {
138
+ const { r, s } = parseSignature(signature);
139
+ const sBigInt = bytesToNumberBE(s);
140
+ const tBigInt = bytesToNumberBE(adaptorPrivateKeyBytes);
141
+ const newS = mod(sBigInt - tBigInt, secp256k1.CURVE.n);
142
+ const newSignature = new Uint8Array([...r, ...numberToBytesBE(newS, 32)]);
143
+ return newSignature;
144
+ }
145
+ function generateAdaptorFromSignature(signature) {
146
+ const adaptorPrivateKey = secp256k1.utils.randomPrivateKey();
147
+ const { r, s } = parseSignature(signature);
148
+ const sBigInt = bytesToNumberBE(s);
149
+ const tBigInt = bytesToNumberBE(adaptorPrivateKey);
150
+ const newS = mod(sBigInt - tBigInt, secp256k1.CURVE.n);
151
+ const newSignature = new Uint8Array([...r, ...numberToBytesBE(newS, 32)]);
152
+ return {
153
+ adaptorSignature: newSignature,
154
+ adaptorPrivateKey
155
+ };
156
+ }
157
+ function validateOutboundAdaptorSignature(pubkey, hash, signature, adaptorPubkey) {
158
+ return schnorrVerifyWithAdaptor(
159
+ signature,
160
+ hash,
161
+ pubkey,
162
+ adaptorPubkey,
163
+ false
164
+ );
165
+ }
166
+ function applyAdaptorToSignature(pubkey, hash, signature, adaptorPrivateKeyBytes) {
167
+ const { r, s } = parseSignature(signature);
168
+ const sBigInt = bytesToNumberBE(s);
169
+ const adaptorPrivateKey = bytesToNumberBE(adaptorPrivateKeyBytes);
170
+ const newS = mod(sBigInt + adaptorPrivateKey, secp256k1.CURVE.n);
171
+ const newSig = new Uint8Array([...r, ...numberToBytesBE(newS, 32)]);
172
+ if (schnorr.verify(newSig, hash, pubkey)) {
173
+ return newSig;
174
+ }
175
+ const altS = mod(sBigInt - adaptorPrivateKey, secp256k1.CURVE.n);
176
+ const altSig = new Uint8Array([...r, ...numberToBytesBE(altS, 32)]);
177
+ if (schnorr.verify(altSig, hash, pubkey)) {
178
+ return altSig;
179
+ }
180
+ throw new Error("Cannot apply adaptor to signature");
181
+ }
182
+ function schnorrVerifyWithAdaptor(signature, hash, pubKeyBytes, adaptorPubkey, inbound) {
183
+ if (hash.length !== 32) {
184
+ throw new Error(`wrong size for message (got ${hash.length}, want 32)`);
185
+ }
186
+ const pubKey = schnorr.utils.lift_x(bytesToNumberBE(pubKeyBytes));
187
+ pubKey.assertValidity();
188
+ const { r, s } = parseSignature(signature);
189
+ const commitmenet = schnorr.utils.taggedHash(
190
+ "BIP0340/challenge",
191
+ r,
192
+ pubKey.toRawBytes().slice(1),
193
+ hash
194
+ );
195
+ if (commitmenet.length > 32) {
196
+ throw new Error("hash of (r || P || m) too big");
197
+ }
198
+ const e = mod(bytesToNumberBE(commitmenet), secp256k1.CURVE.n);
199
+ const negE = mod(-e, secp256k1.CURVE.n);
200
+ const R = secp256k1.ProjectivePoint.BASE.multiplyAndAddUnsafe(
201
+ pubKey,
202
+ bytesToNumberBE(s),
203
+ negE
204
+ );
205
+ if (!R) {
206
+ throw new Error("R is undefined");
207
+ }
208
+ R.assertValidity();
209
+ const adaptorPoint = secp256k1.ProjectivePoint.fromHex(adaptorPubkey);
210
+ const newR = R.add(adaptorPoint);
211
+ if (!inbound && newR.equals(secp256k1.ProjectivePoint.ZERO)) {
212
+ throw new Error("calculated R point is the point at infinity");
213
+ }
214
+ newR.assertValidity();
215
+ if (!newR.hasEvenY()) {
216
+ throw new Error("calculated R y-value is odd");
217
+ }
218
+ const rNum = bytesToNumberBE(r);
219
+ if (newR.toAffine().x !== rNum) {
220
+ throw new Error("calculated R point was not given R");
221
+ }
222
+ return true;
223
+ }
224
+ function parseSignature(signature) {
225
+ if (signature.length < 64) {
226
+ throw new ValidationError("Signature too short", {
227
+ expectedLength: 64,
228
+ actualLength: signature.length
229
+ });
230
+ }
231
+ if (signature.length > 64) {
232
+ throw new ValidationError("Signature too long", {
233
+ expectedLength: 64,
234
+ actualLength: signature.length
235
+ });
236
+ }
237
+ const r = signature.slice(0, 32);
238
+ const s = signature.slice(32, 64);
239
+ if (bytesToNumberBE(r) >= secp256k1.CURVE.Fp.ORDER) {
240
+ throw new ValidationError("Invalid signature: r >= field prime", {
241
+ rValue: bytesToNumberBE(r),
242
+ fieldPrime: secp256k1.CURVE.Fp.ORDER
243
+ });
244
+ }
245
+ if (bytesToNumberBE(s) >= secp256k1.CURVE.n) {
246
+ throw new ValidationError("Invalid signature: s >= group order", {
247
+ sValue: bytesToNumberBE(s),
248
+ groupOrder: secp256k1.CURVE.n
249
+ });
250
+ }
251
+ return { r, s };
252
+ }
253
+
254
+ // src/utils/network.ts
255
+ import { NetworkType as Lrc20NetworkType } from "@buildonspark/lrc20-sdk";
256
+ import * as btc from "@scure/btc-signer";
257
+ import * as bitcoin from "bitcoinjs-lib";
258
+ var Network2 = /* @__PURE__ */ ((Network4) => {
259
+ Network4[Network4["MAINNET"] = 0] = "MAINNET";
260
+ Network4[Network4["TESTNET"] = 1] = "TESTNET";
261
+ Network4[Network4["SIGNET"] = 2] = "SIGNET";
262
+ Network4[Network4["REGTEST"] = 3] = "REGTEST";
263
+ Network4[Network4["LOCAL"] = 4] = "LOCAL";
264
+ return Network4;
265
+ })(Network2 || {});
266
+ var NetworkToProto = {
267
+ [0 /* MAINNET */]: 1 /* MAINNET */,
268
+ [1 /* TESTNET */]: 3 /* TESTNET */,
269
+ [2 /* SIGNET */]: 4 /* SIGNET */,
270
+ [3 /* REGTEST */]: 2 /* REGTEST */,
271
+ [4 /* LOCAL */]: 2 /* REGTEST */
272
+ };
273
+ var protoToNetwork = (protoNetwork) => {
274
+ switch (protoNetwork) {
275
+ case 1 /* MAINNET */:
276
+ return 0 /* MAINNET */;
277
+ case 3 /* TESTNET */:
278
+ return 1 /* TESTNET */;
279
+ case 4 /* SIGNET */:
280
+ return 2 /* SIGNET */;
281
+ case 2 /* REGTEST */:
282
+ return 3 /* REGTEST */;
283
+ default:
284
+ return void 0;
285
+ }
286
+ };
287
+ var NetworkConfig = {
288
+ [0 /* MAINNET */]: btc.NETWORK,
289
+ [1 /* TESTNET */]: btc.TEST_NETWORK,
290
+ [2 /* SIGNET */]: btc.TEST_NETWORK,
291
+ [3 /* REGTEST */]: { ...btc.TEST_NETWORK, bech32: "bcrt" },
292
+ [4 /* LOCAL */]: { ...btc.TEST_NETWORK, bech32: "bcrt" }
293
+ };
294
+ var getNetwork = (network) => NetworkConfig[network];
295
+ var LRC_WALLET_NETWORK = Object.freeze({
296
+ [0 /* MAINNET */]: bitcoin.networks.bitcoin,
297
+ [1 /* TESTNET */]: bitcoin.networks.testnet,
298
+ [2 /* SIGNET */]: bitcoin.networks.testnet,
299
+ [3 /* REGTEST */]: bitcoin.networks.regtest,
300
+ [4 /* LOCAL */]: bitcoin.networks.regtest
301
+ });
302
+ var LRC_WALLET_NETWORK_TYPE = Object.freeze({
303
+ [0 /* MAINNET */]: Lrc20NetworkType.MAINNET,
304
+ [1 /* TESTNET */]: Lrc20NetworkType.TESTNET,
305
+ [2 /* SIGNET */]: Lrc20NetworkType.TESTNET,
306
+ [3 /* REGTEST */]: Lrc20NetworkType.REGTEST,
307
+ [4 /* LOCAL */]: Lrc20NetworkType.LOCAL
308
+ });
309
+ function getNetworkFromAddress(address2) {
310
+ try {
311
+ const decoded = bitcoin.address.fromBech32(address2);
312
+ if (decoded.prefix === "bc") {
313
+ return "MAINNET" /* MAINNET */;
314
+ } else if (decoded.prefix === "bcrt") {
315
+ return "REGTEST" /* REGTEST */;
316
+ }
317
+ } catch (err) {
318
+ throw new ValidationError(
319
+ "Invalid Bitcoin address",
320
+ {
321
+ field: "address",
322
+ value: address2,
323
+ expected: "Valid Bech32 address with prefix 'bc' or 'bcrt'"
324
+ },
325
+ err instanceof Error ? err : void 0
326
+ );
327
+ }
328
+ return null;
329
+ }
330
+ function getNetworkFromString(network) {
331
+ const net = (network ?? "REGTEST").toUpperCase();
332
+ if (net === "MAINNET") return 0 /* MAINNET */;
333
+ if (net === "TESTNET") return 1 /* TESTNET */;
334
+ if (net === "SIGNET") return 2 /* SIGNET */;
335
+ if (net === "LOCAL") return 4 /* LOCAL */;
336
+ return 3 /* REGTEST */;
337
+ }
338
+
339
+ // src/utils/bitcoin.ts
340
+ import {
341
+ bytesToHex as bytesToHex2,
342
+ bytesToNumberBE as bytesToNumberBE2,
343
+ hexToBytes
344
+ } from "@noble/curves/abstract/utils";
345
+ import { schnorr as schnorr2, secp256k1 as secp256k12 } from "@noble/curves/secp256k1";
346
+ import { sha256 } from "@noble/hashes/sha2";
347
+ import * as btc2 from "@scure/btc-signer";
348
+ function computeTaprootKeyNoScript(pubkey) {
349
+ if (pubkey.length !== 32) {
350
+ throw new ValidationError("Public key must be 32 bytes", {
351
+ field: "pubkey",
352
+ value: pubkey.length,
353
+ expected: 32
354
+ });
355
+ }
356
+ const taggedHash = schnorr2.utils.taggedHash("TapTweak", pubkey);
357
+ const tweak = bytesToNumberBE2(taggedHash);
358
+ const P = schnorr2.utils.lift_x(schnorr2.utils.bytesToNumberBE(pubkey));
359
+ const Q = P.add(secp256k12.ProjectivePoint.fromPrivateKey(tweak));
360
+ return Q.toRawBytes();
361
+ }
362
+ function getP2TRScriptFromPublicKey(pubKey, network) {
363
+ if (pubKey.length !== 33) {
364
+ throw new ValidationError("Public key must be 33 bytes", {
365
+ field: "pubKey",
366
+ value: pubKey.length,
367
+ expected: 33
368
+ });
369
+ }
370
+ const internalKey = secp256k12.ProjectivePoint.fromHex(pubKey);
371
+ const script = btc2.p2tr(
372
+ internalKey.toRawBytes().slice(1, 33),
373
+ void 0,
374
+ getNetwork(network)
375
+ ).script;
376
+ if (!script) {
377
+ throw new ValidationError("Failed to get P2TR script", {
378
+ field: "script",
379
+ value: "null"
380
+ });
381
+ }
382
+ return script;
383
+ }
384
+ function getP2TRAddressFromPublicKey(pubKey, network) {
385
+ if (pubKey.length !== 33) {
386
+ throw new ValidationError("Public key must be 33 bytes", {
387
+ field: "pubKey",
388
+ value: pubKey.length,
389
+ expected: 33
390
+ });
391
+ }
392
+ const internalKey = secp256k12.ProjectivePoint.fromHex(pubKey);
393
+ const address2 = btc2.p2tr(
394
+ internalKey.toRawBytes().slice(1, 33),
395
+ void 0,
396
+ getNetwork(network)
397
+ ).address;
398
+ if (!address2) {
399
+ throw new ValidationError("Failed to get P2TR address", {
400
+ field: "address",
401
+ value: "null"
402
+ });
403
+ }
404
+ return address2;
405
+ }
406
+ function getP2TRAddressFromPkScript(pkScript, network) {
407
+ if (pkScript.length !== 34 || pkScript[0] !== 81 || pkScript[1] !== 32) {
408
+ throw new ValidationError("Invalid pkscript", {
409
+ field: "pkScript",
410
+ value: bytesToHex2(pkScript),
411
+ expected: "34 bytes starting with 0x51 0x20"
412
+ });
413
+ }
414
+ const parsedScript = btc2.OutScript.decode(pkScript);
415
+ return btc2.Address(getNetwork(network)).encode(parsedScript);
416
+ }
417
+ function getP2WPKHAddressFromPublicKey(pubKey, network) {
418
+ if (pubKey.length !== 33) {
419
+ throw new ValidationError("Public key must be 33 bytes", {
420
+ field: "pubKey",
421
+ value: pubKey.length,
422
+ expected: 33
423
+ });
424
+ }
425
+ const address2 = btc2.p2wpkh(pubKey, getNetwork(network)).address;
426
+ if (!address2) {
427
+ throw new ValidationError("Failed to get P2WPKH address", {
428
+ field: "address",
429
+ value: "null"
430
+ });
431
+ }
432
+ return address2;
433
+ }
434
+ function getTxFromRawTxHex(rawTxHex) {
435
+ const txBytes = hexToBytes(rawTxHex);
436
+ const tx = btc2.Transaction.fromRaw(txBytes, {
437
+ allowUnknownOutputs: true
438
+ });
439
+ if (!tx) {
440
+ throw new ValidationError("Failed to parse transaction", {
441
+ field: "tx",
442
+ value: "null"
443
+ });
444
+ }
445
+ return tx;
446
+ }
447
+ function getTxFromRawTxBytes(rawTxBytes) {
448
+ const tx = btc2.Transaction.fromRaw(rawTxBytes, {
449
+ allowUnknownOutputs: true
450
+ });
451
+ if (!tx) {
452
+ throw new ValidationError("Failed to parse transaction", {
453
+ field: "tx",
454
+ value: "null"
455
+ });
456
+ }
457
+ return tx;
458
+ }
459
+ function getSigHashFromTx(tx, inputIndex, prevOutput) {
460
+ const prevScript = prevOutput.script;
461
+ if (!prevScript) {
462
+ throw new ValidationError("No script found in prevOutput", {
463
+ field: "prevScript",
464
+ value: "null"
465
+ });
466
+ }
467
+ const amount = prevOutput.amount;
468
+ if (!amount) {
469
+ throw new ValidationError("No amount found in prevOutput", {
470
+ field: "amount",
471
+ value: "null"
472
+ });
473
+ }
474
+ return tx.preimageWitnessV1(
475
+ inputIndex,
476
+ new Array(tx.inputsLength).fill(prevScript),
477
+ btc2.SigHash.DEFAULT,
478
+ new Array(tx.inputsLength).fill(amount)
479
+ );
480
+ }
481
+ function getTxId(tx) {
482
+ return bytesToHex2(sha256(sha256(tx.toBytes(true))).reverse());
483
+ }
484
+ function getTxIdNoReverse(tx) {
485
+ return bytesToHex2(sha256(sha256(tx.toBytes(true))));
486
+ }
487
+
488
+ // src/utils/keys.ts
489
+ import { numberToBytesBE as numberToBytesBE2 } from "@noble/curves/abstract/utils";
490
+ import { secp256k1 as secp256k13 } from "@noble/curves/secp256k1";
491
+ function addPublicKeys(a, b) {
492
+ if (a.length !== 33 || b.length !== 33) {
493
+ throw new ValidationError("Public keys must be 33 bytes", {
494
+ field: "publicKeys",
495
+ value: `a: ${a.length}, b: ${b.length}`,
496
+ expected: 33
497
+ });
498
+ }
499
+ const pubkeyA = secp256k13.ProjectivePoint.fromHex(a);
500
+ const pubkeyB = secp256k13.ProjectivePoint.fromHex(b);
501
+ return pubkeyA.add(pubkeyB).toRawBytes(true);
502
+ }
503
+ function applyAdditiveTweakToPublicKey(pubkey, tweak) {
504
+ if (pubkey.length !== 33) {
505
+ throw new ValidationError("Public key must be 33 bytes", {
506
+ field: "pubkey",
507
+ value: pubkey.length,
508
+ expected: 33
509
+ });
510
+ }
511
+ if (tweak.length !== 32) {
512
+ throw new ValidationError("Tweak must be 32 bytes", {
513
+ field: "tweak",
514
+ value: tweak.length,
515
+ expected: 32
516
+ });
517
+ }
518
+ const pubkeyPoint = secp256k13.ProjectivePoint.fromHex(pubkey);
519
+ const privTweek = secp256k13.utils.normPrivateKeyToScalar(tweak);
520
+ const pubTweek = secp256k13.getPublicKey(privTweek, true);
521
+ const tweekPoint = secp256k13.ProjectivePoint.fromHex(pubTweek);
522
+ return pubkeyPoint.add(tweekPoint).toRawBytes(true);
523
+ }
524
+ function subtractPublicKeys(a, b) {
525
+ if (a.length !== 33 || b.length !== 33) {
526
+ throw new ValidationError("Public keys must be 33 bytes", {
527
+ field: "publicKeys",
528
+ value: `a: ${a.length}, b: ${b.length}`,
529
+ expected: 33
530
+ });
531
+ }
532
+ const pubkeyA = secp256k13.ProjectivePoint.fromHex(a);
533
+ const pubkeyB = secp256k13.ProjectivePoint.fromHex(b);
534
+ return pubkeyA.subtract(pubkeyB).toRawBytes(true);
535
+ }
536
+ function addPrivateKeys(a, b) {
537
+ if (a.length !== 32 || b.length !== 32) {
538
+ throw new ValidationError("Private keys must be 32 bytes", {
539
+ field: "privateKeys",
540
+ value: `a: ${a.length}, b: ${b.length}`,
541
+ expected: 32
542
+ });
543
+ }
544
+ const privA = secp256k13.utils.normPrivateKeyToScalar(a);
545
+ const privB = secp256k13.utils.normPrivateKeyToScalar(b);
546
+ const sum = (privA + privB) % secp256k13.CURVE.n;
547
+ return numberToBytesBE2(sum, 32);
548
+ }
549
+ function subtractPrivateKeys(a, b) {
550
+ if (a.length !== 32 || b.length !== 32) {
551
+ throw new ValidationError("Private keys must be 32 bytes", {
552
+ field: "privateKeys",
553
+ value: `a: ${a.length}, b: ${b.length}`,
554
+ expected: 32
555
+ });
556
+ }
557
+ const privA = secp256k13.utils.normPrivateKeyToScalar(a);
558
+ const privB = secp256k13.utils.normPrivateKeyToScalar(b);
559
+ const sum = (secp256k13.CURVE.n - privB + privA) % secp256k13.CURVE.n;
560
+ return numberToBytesBE2(sum, 32);
561
+ }
562
+ function sumOfPrivateKeys(keys) {
563
+ return keys.reduce((sum, key) => {
564
+ if (key.length !== 32) {
565
+ throw new ValidationError("Private keys must be 32 bytes", {
566
+ field: "privateKey",
567
+ value: key.length,
568
+ expected: 32
569
+ });
570
+ }
571
+ return addPrivateKeys(sum, key);
572
+ });
573
+ }
574
+ function lastKeyWithTarget(target, keys) {
575
+ if (target.length !== 32) {
576
+ throw new ValidationError("Target must be 32 bytes", {
577
+ field: "target",
578
+ value: target.length,
579
+ expected: 32
580
+ });
581
+ }
582
+ const sum = sumOfPrivateKeys(keys);
583
+ return subtractPrivateKeys(target, sum);
584
+ }
585
+
586
+ // src/tests/isHermeticTest.ts
587
+ var isHermeticTest = Boolean(
588
+ typeof process !== "undefined" && process?.env?.HERMETIC_TEST === "true"
589
+ );
590
+
591
+ // src/services/wallet-config.ts
592
+ var SSP_IDENTITY_PUBLIC_KEYS = {
593
+ LOCAL: "028c094a432d46a0ac95349d792c2e3730bd60c29188db716f56a99e39b95338b4",
594
+ REGTEST: {
595
+ PROD: "022bf283544b16c0622daecb79422007d167eca6ce9f0c98c0c49833b1f7170bfe"
596
+ },
597
+ MAINNET: {
598
+ PROD: "023e33e2920326f64ea31058d44777442d97d7d5cbfcf54e3060bc1695e5261c93"
599
+ }
600
+ };
601
+ var URL_CONFIG = {
602
+ LOCAL: {
603
+ SSP: "http://127.0.0.1:5000",
604
+ ELECTRS: "http://127.0.0.1:30000",
605
+ LRC20: "http://127.0.0.1:18530",
606
+ LRC20_NODE: "http://127.0.0.1:18332"
607
+ },
608
+ REGTEST: {
609
+ PROD: {
610
+ SSP: "https://api.lightspark.com",
611
+ ELECTRS: "https://regtest-mempool.us-west-2.sparkinfra.net/api",
612
+ LRC20: "https://regtest.lrc20.lightspark.com:443",
613
+ LRC20_NODE: "https://regtest.lrc20.lightspark.com"
614
+ }
615
+ },
616
+ MAINNET: {
617
+ PROD: {
618
+ SSP: "https://api.lightspark.com",
619
+ ELECTRS: "https://mempool.space/api",
620
+ LRC20: "https://mainnet.lrc20.lightspark.com:443",
621
+ LRC20_NODE: "https://mainnet.lrc20.lightspark.com"
622
+ }
623
+ }
624
+ };
625
+ var ELECTRS_CREDENTIALS = {
626
+ username: "spark-sdk",
627
+ password: "mCMk1JqlBNtetUNy"
628
+ };
629
+ function getElectrsUrl(network) {
630
+ switch (network) {
631
+ case "LOCAL":
632
+ return isHermeticTest ? "http://mempool.minikube.local/api" : URL_CONFIG.LOCAL.ELECTRS;
633
+ case "REGTEST":
634
+ return URL_CONFIG.REGTEST.PROD.ELECTRS;
635
+ case "MAINNET":
636
+ return URL_CONFIG.MAINNET.PROD.ELECTRS;
637
+ default:
638
+ return URL_CONFIG.LOCAL.ELECTRS;
639
+ }
640
+ }
641
+ function getLrc20Url(network) {
642
+ switch (network) {
643
+ case "LOCAL":
644
+ return URL_CONFIG.LOCAL.LRC20;
645
+ case "REGTEST":
646
+ return URL_CONFIG.REGTEST.PROD.LRC20;
647
+ case "MAINNET":
648
+ return URL_CONFIG.MAINNET.PROD.LRC20;
649
+ default:
650
+ return URL_CONFIG.LOCAL.LRC20;
651
+ }
652
+ }
653
+ function getLrc20NodeUrl(network) {
654
+ switch (network) {
655
+ case "LOCAL":
656
+ return URL_CONFIG.LOCAL.LRC20_NODE;
657
+ case "REGTEST":
658
+ return URL_CONFIG.REGTEST.PROD.LRC20_NODE;
659
+ case "MAINNET":
660
+ return URL_CONFIG.MAINNET.PROD.LRC20_NODE;
661
+ default:
662
+ return URL_CONFIG.LOCAL.LRC20_NODE;
663
+ }
664
+ }
665
+ function getSspIdentityPublicKey(network) {
666
+ switch (network) {
667
+ case "LOCAL":
668
+ return SSP_IDENTITY_PUBLIC_KEYS.LOCAL;
669
+ case "REGTEST":
670
+ return SSP_IDENTITY_PUBLIC_KEYS.REGTEST.PROD;
671
+ case "MAINNET":
672
+ return SSP_IDENTITY_PUBLIC_KEYS.MAINNET.PROD;
673
+ default:
674
+ return SSP_IDENTITY_PUBLIC_KEYS.LOCAL;
675
+ }
676
+ }
677
+ function getSspUrl(network) {
678
+ switch (network) {
679
+ case "LOCAL":
680
+ return isHermeticTest ? "http://app.minikube.local" : URL_CONFIG.LOCAL.SSP;
681
+ case "REGTEST":
682
+ return URL_CONFIG.REGTEST.PROD.SSP;
683
+ case "MAINNET":
684
+ return URL_CONFIG.MAINNET.PROD.SSP;
685
+ default:
686
+ return URL_CONFIG.LOCAL.SSP;
687
+ }
688
+ }
689
+ function getSspSchemaEndpoint(network) {
690
+ switch (network) {
691
+ case "LOCAL":
692
+ return "graphql/spark/rc";
693
+ }
694
+ return;
695
+ }
696
+ var PROD_PUBKEYS = [
697
+ "03dfbdff4b6332c220f8fa2ba8ed496c698ceada563fa01b67d9983bfc5c95e763",
698
+ "03e625e9768651c9be268e287245cc33f96a68ce9141b0b4769205db027ee8ed77",
699
+ "022eda13465a59205413086130a65dc0ed1b8f8e51937043161f8be0c369b1a410"
700
+ ];
701
+ function getLocalFrostSignerAddress() {
702
+ return isHermeticTest ? "localhost:9999" : "unix:///tmp/frost_0.sock";
703
+ }
704
+ var BASE_CONFIG = {
705
+ network: "LOCAL",
706
+ lrc20Address: getLrc20Url("LOCAL"),
707
+ coodinatorIdentifier: "0000000000000000000000000000000000000000000000000000000000000001",
708
+ frostSignerAddress: getLocalFrostSignerAddress(),
709
+ threshold: 2,
710
+ signingOperators: getLocalSigningOperators(),
711
+ tokenSignatures: "SCHNORR",
712
+ tokenTransactionVersion: "V1",
713
+ tokenValidityDurationSeconds: 180,
714
+ electrsUrl: getElectrsUrl("LOCAL"),
715
+ expectedWithdrawBondSats: 1e4,
716
+ expectedWithdrawRelativeBlockLocktime: 1e3,
717
+ lrc20ApiConfig: {
718
+ electrsUrl: getElectrsUrl("LOCAL"),
719
+ lrc20NodeUrl: getLrc20NodeUrl("LOCAL"),
720
+ electrsCredentials: ELECTRS_CREDENTIALS
721
+ },
722
+ sspClientOptions: {
723
+ baseUrl: getSspUrl("LOCAL"),
724
+ identityPublicKey: getSspIdentityPublicKey("LOCAL"),
725
+ schemaEndpoint: getSspSchemaEndpoint("LOCAL")
726
+ }
727
+ };
728
+ var LOCAL_WALLET_CONFIG = {
729
+ ...BASE_CONFIG,
730
+ threshold: 3
731
+ };
732
+ var LOCAL_WALLET_CONFIG_SCHNORR = {
733
+ ...LOCAL_WALLET_CONFIG,
734
+ threshold: 3
735
+ // 3 for issuance tests.
736
+ };
737
+ var LOCAL_WALLET_CONFIG_ECDSA = {
738
+ ...LOCAL_WALLET_CONFIG,
739
+ tokenSignatures: "ECDSA",
740
+ threshold: 3
741
+ // 3 for issuance tests.
742
+ };
743
+ var REGTEST_WALLET_CONFIG = {
744
+ ...BASE_CONFIG,
745
+ network: "REGTEST",
746
+ lrc20Address: getLrc20Url("REGTEST"),
747
+ signingOperators: getSigningOperators(),
748
+ electrsUrl: getElectrsUrl("REGTEST"),
749
+ lrc20ApiConfig: {
750
+ electrsUrl: getElectrsUrl("REGTEST"),
751
+ lrc20NodeUrl: getLrc20NodeUrl("REGTEST"),
752
+ electrsCredentials: ELECTRS_CREDENTIALS
753
+ },
754
+ expectedWithdrawBondSats: 1e4,
755
+ expectedWithdrawRelativeBlockLocktime: 1e3,
756
+ sspClientOptions: {
757
+ baseUrl: getSspUrl("REGTEST"),
758
+ identityPublicKey: getSspIdentityPublicKey("REGTEST")
759
+ }
760
+ };
761
+ var MAINNET_WALLET_CONFIG = {
762
+ ...BASE_CONFIG,
763
+ network: "MAINNET",
764
+ lrc20Address: getLrc20Url("MAINNET"),
765
+ signingOperators: getSigningOperators(),
766
+ electrsUrl: getElectrsUrl("MAINNET"),
767
+ lrc20ApiConfig: {
768
+ electrsUrl: getElectrsUrl("MAINNET"),
769
+ lrc20NodeUrl: getLrc20NodeUrl("MAINNET")
770
+ },
771
+ expectedWithdrawBondSats: 1e4,
772
+ expectedWithdrawRelativeBlockLocktime: 1e3,
773
+ sspClientOptions: {
774
+ baseUrl: getSspUrl("MAINNET"),
775
+ identityPublicKey: getSspIdentityPublicKey("MAINNET")
776
+ }
777
+ };
778
+ var WalletConfig = {
779
+ LOCAL: LOCAL_WALLET_CONFIG,
780
+ LOCAL_SCHNORR: LOCAL_WALLET_CONFIG_SCHNORR,
781
+ LOCAL_ECDSA: LOCAL_WALLET_CONFIG_ECDSA,
782
+ REGTEST: REGTEST_WALLET_CONFIG,
783
+ MAINNET: MAINNET_WALLET_CONFIG
784
+ };
785
+ function getSigningOperators() {
786
+ return {
787
+ "0000000000000000000000000000000000000000000000000000000000000001": {
788
+ id: 0,
789
+ identifier: "0000000000000000000000000000000000000000000000000000000000000001",
790
+ address: "https://0.spark.lightspark.com",
791
+ identityPublicKey: PROD_PUBKEYS[0]
792
+ },
793
+ "0000000000000000000000000000000000000000000000000000000000000002": {
794
+ id: 1,
795
+ identifier: "0000000000000000000000000000000000000000000000000000000000000002",
796
+ address: "https://1.spark.lightspark.com",
797
+ identityPublicKey: PROD_PUBKEYS[1]
798
+ },
799
+ "0000000000000000000000000000000000000000000000000000000000000003": {
800
+ id: 2,
801
+ identifier: "0000000000000000000000000000000000000000000000000000000000000003",
802
+ address: "https://2.spark.flashnet.xyz",
803
+ identityPublicKey: PROD_PUBKEYS[2]
804
+ }
805
+ };
806
+ }
807
+ function getLocalSigningOperators() {
808
+ const pubkeys = [
809
+ "0322ca18fc489ae25418a0e768273c2c61cabb823edfb14feb891e9bec62016510",
810
+ "0341727a6c41b168f07eb50865ab8c397a53c7eef628ac1020956b705e43b6cb27",
811
+ "0305ab8d485cc752394de4981f8a5ae004f2becfea6f432c9a59d5022d8764f0a6",
812
+ "0352aef4d49439dedd798ac4aef1e7ebef95f569545b647a25338398c1247ffdea",
813
+ "02c05c88cc8fc181b1ba30006df6a4b0597de6490e24514fbdd0266d2b9cd3d0ba"
814
+ ];
815
+ return {
816
+ "0000000000000000000000000000000000000000000000000000000000000001": {
817
+ id: 0,
818
+ identifier: "0000000000000000000000000000000000000000000000000000000000000001",
819
+ address: "https://localhost:8535",
820
+ identityPublicKey: pubkeys[0]
821
+ },
822
+ "0000000000000000000000000000000000000000000000000000000000000002": {
823
+ id: 1,
824
+ identifier: "0000000000000000000000000000000000000000000000000000000000000002",
825
+ address: "https://localhost:8536",
826
+ identityPublicKey: pubkeys[1]
827
+ },
828
+ "0000000000000000000000000000000000000000000000000000000000000003": {
829
+ id: 2,
830
+ identifier: "0000000000000000000000000000000000000000000000000000000000000003",
831
+ address: "https://localhost:8537",
832
+ identityPublicKey: pubkeys[2]
833
+ },
834
+ "0000000000000000000000000000000000000000000000000000000000000004": {
835
+ id: 3,
836
+ identifier: "0000000000000000000000000000000000000000000000000000000000000004",
837
+ address: "https://localhost:8538",
838
+ identityPublicKey: pubkeys[3]
839
+ },
840
+ "0000000000000000000000000000000000000000000000000000000000000005": {
841
+ id: 4,
842
+ identifier: "0000000000000000000000000000000000000000000000000000000000000005",
843
+ address: "https://localhost:8539",
844
+ identityPublicKey: pubkeys[4]
845
+ }
846
+ };
847
+ }
848
+
849
+ // src/utils/proof.ts
850
+ import { sha256 as sha2562 } from "@noble/hashes/sha2";
851
+ function proofOfPossessionMessageHashForDepositAddress(userPubkey, operatorPubkey, depositAddress) {
852
+ const encoder = new TextEncoder();
853
+ const depositAddressBytes = encoder.encode(depositAddress);
854
+ const proofMsg = new Uint8Array([
855
+ ...userPubkey,
856
+ ...operatorPubkey,
857
+ ...depositAddressBytes
858
+ ]);
859
+ return sha2562(proofMsg);
860
+ }
861
+
862
+ // src/utils/secret-sharing.ts
863
+ import { bytesToHex as bytesToHex3, equalBytes } from "@noble/curves/abstract/utils";
864
+ import { secp256k1 as secp256k14 } from "@noble/curves/secp256k1";
865
+ function getRandomBigInt(max) {
866
+ const byteLength = max.toString(2).length + 7 >> 3;
867
+ const maxBigInt = max;
868
+ const mask = (1n << BigInt(max.toString(2).length)) - 1n;
869
+ while (true) {
870
+ const crypto = getCrypto();
871
+ const randBytes = crypto.getRandomValues(new Uint8Array(byteLength + 1));
872
+ const randValue = BigInt("0x" + bytesToHex3(randBytes)) & mask;
873
+ if (randValue < maxBigInt) {
874
+ return randValue;
875
+ }
876
+ }
877
+ }
878
+ function modInverse(a, m) {
879
+ a = (a % m + m) % m;
880
+ let [old_r, r] = [a, m];
881
+ let [old_s, s] = [1n, 0n];
882
+ let [old_t, t] = [0n, 1n];
883
+ while (r !== 0n) {
884
+ const quotient = old_r / r;
885
+ [old_r, r] = [r, old_r - quotient * r];
886
+ [old_s, s] = [s, old_s - quotient * s];
887
+ [old_t, t] = [t, old_t - quotient * t];
888
+ }
889
+ if (old_r !== 1n) {
890
+ throw new ValidationError("Modular inverse does not exist", {
891
+ field: "modInverse",
892
+ value: `a: ${a}, m: ${m}`,
893
+ expected: "a and m must be coprime"
894
+ });
895
+ }
896
+ return (old_s % m + m) % m;
897
+ }
898
+ function evaluatePolynomial(polynomial, x) {
899
+ let result = 0n;
900
+ for (let i = 0; i < polynomial.coefficients.length; i++) {
901
+ const coeff = polynomial.coefficients[i];
902
+ if (!coeff) {
903
+ throw new ValidationError("Coefficient is undefined", {
904
+ field: "coefficient",
905
+ value: "undefined",
906
+ expected: "A valid bigint coefficient"
907
+ });
908
+ }
909
+ const xPow = x ** BigInt(i) % polynomial.fieldModulus;
910
+ result = (result + xPow * coeff) % polynomial.fieldModulus;
911
+ }
912
+ return result;
913
+ }
914
+ function fieldDiv(numerator, denominator, fieldModulus) {
915
+ if (denominator === 0n) {
916
+ throw new ValidationError("Division by zero", {
917
+ field: "denominator",
918
+ value: "0",
919
+ expected: "Non-zero value"
920
+ });
921
+ }
922
+ const inverse = modInverse(denominator, fieldModulus);
923
+ return numerator * inverse % fieldModulus;
924
+ }
925
+ function computerLagrangeCoefficients(index, points) {
926
+ let numerator = 1n;
927
+ let denominator = 1n;
928
+ let fieldModulus = points[0]?.fieldModulus;
929
+ if (!fieldModulus) {
930
+ throw new ValidationError("Field modulus is undefined", {
931
+ field: "fieldModulus",
932
+ value: "undefined",
933
+ expected: "A valid field modulus"
934
+ });
935
+ }
936
+ for (const point of points) {
937
+ if (point.index === index) {
938
+ continue;
939
+ }
940
+ numerator = numerator * point.index;
941
+ const value = point.index - index;
942
+ denominator = denominator * value;
943
+ }
944
+ return fieldDiv(numerator, denominator, fieldModulus);
945
+ }
946
+ function generatePolynomialForSecretSharing(fieldModulus, secret, degree) {
947
+ const coefficients = new Array(degree);
948
+ const proofs = new Array(degree);
949
+ coefficients[0] = secret;
950
+ proofs[0] = secp256k14.ProjectivePoint.fromPrivateKey(secret).toRawBytes(true);
951
+ for (let i = 1; i < degree; i++) {
952
+ const coefficient = getRandomBigInt(fieldModulus);
953
+ coefficients[i] = coefficient;
954
+ proofs[i] = secp256k14.ProjectivePoint.fromPrivateKey(coefficient).toRawBytes(true);
955
+ }
956
+ return {
957
+ fieldModulus,
958
+ coefficients,
959
+ proofs
960
+ };
961
+ }
962
+ function splitSecret(fieldModulus, secret, threshold, numberOfShares) {
963
+ const polynomial = generatePolynomialForSecretSharing(
964
+ fieldModulus,
965
+ secret,
966
+ threshold
967
+ );
968
+ const shares = [];
969
+ for (let i = 1; i <= numberOfShares; i++) {
970
+ const share = evaluatePolynomial(polynomial, BigInt(i));
971
+ shares.push({
972
+ fieldModulus,
973
+ threshold,
974
+ index: BigInt(i),
975
+ share
976
+ });
977
+ }
978
+ return shares;
979
+ }
980
+ function splitSecretWithProofs(secret, fieldModulus, threshold, numberOfShares) {
981
+ const polynomial = generatePolynomialForSecretSharing(
982
+ fieldModulus,
983
+ secret,
984
+ threshold
985
+ );
986
+ const shares = [];
987
+ for (let i = 1; i <= numberOfShares; i++) {
988
+ const share = evaluatePolynomial(polynomial, BigInt(i));
989
+ shares.push({
990
+ fieldModulus,
991
+ threshold,
992
+ index: BigInt(i),
993
+ share,
994
+ proofs: polynomial.proofs
995
+ });
996
+ }
997
+ return shares;
998
+ }
999
+ function recoverSecret(shares) {
1000
+ if (shares.length === 0) return 0n;
1001
+ const threshold = shares[0]?.threshold;
1002
+ const fieldModulus = shares[0]?.fieldModulus;
1003
+ if (!threshold || !fieldModulus) {
1004
+ throw new ValidationError("Shares are not valid", {
1005
+ field: "shares",
1006
+ value: "Missing threshold or fieldModulus",
1007
+ expected: "Valid shares with threshold and fieldModulus"
1008
+ });
1009
+ }
1010
+ if (shares.length < threshold) {
1011
+ throw new ValidationError("Not enough shares to recover secret", {
1012
+ field: "shares",
1013
+ value: shares.length,
1014
+ expected: `At least ${threshold} shares`
1015
+ });
1016
+ }
1017
+ let result = 0n;
1018
+ for (const share of shares) {
1019
+ const coeff = computerLagrangeCoefficients(share.index, shares);
1020
+ const item = share.share * coeff % fieldModulus;
1021
+ result = (result + item) % fieldModulus;
1022
+ }
1023
+ return result;
1024
+ }
1025
+ function validateShare(share) {
1026
+ const targetPubkey = secp256k14.ProjectivePoint.fromPrivateKey(
1027
+ share.share
1028
+ ).toRawBytes(true);
1029
+ let resultPubkey = share.proofs[0];
1030
+ if (!resultPubkey) {
1031
+ throw new ValidationError("Result pubkey is not valid", {
1032
+ field: "resultPubkey",
1033
+ value: "null",
1034
+ expected: "Valid public key bytes"
1035
+ });
1036
+ }
1037
+ for (let i = 1; i < share.proofs.length; i++) {
1038
+ const pubkey = share.proofs[i];
1039
+ if (!pubkey) {
1040
+ throw new ValidationError("Pubkey is not valid", {
1041
+ field: "pubkey",
1042
+ value: "null",
1043
+ expected: "Valid public key bytes"
1044
+ });
1045
+ }
1046
+ const value = share.index ** BigInt(i) % share.fieldModulus;
1047
+ const scaledPoint = secp256k14.ProjectivePoint.fromHex(pubkey).multiply(value);
1048
+ resultPubkey = secp256k14.ProjectivePoint.fromHex(resultPubkey).add(scaledPoint).toRawBytes(true);
1049
+ }
1050
+ if (!equalBytes(resultPubkey, targetPubkey)) {
1051
+ throw new ValidationError("Share is not valid", {
1052
+ field: "share",
1053
+ value: "Invalid proof",
1054
+ expected: "Valid share with matching proofs"
1055
+ });
1056
+ }
1057
+ }
1058
+ function bigIntToPrivateKey(value) {
1059
+ const hex = value.toString(16).padStart(64, "0");
1060
+ const bytes = new Uint8Array(32);
1061
+ for (let i = 0; i < 32; i++) {
1062
+ bytes[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
1063
+ }
1064
+ return bytes;
1065
+ }
1066
+
1067
+ // src/utils/signing.ts
1068
+ import { secp256k1 as secp256k15 } from "@noble/curves/secp256k1";
1069
+ function getRandomSigningNonce() {
1070
+ const binding = secp256k15.utils.randomPrivateKey();
1071
+ const hiding = secp256k15.utils.randomPrivateKey();
1072
+ return createSigningNonce(binding, hiding);
1073
+ }
1074
+ function createSigningNonce(binding, hiding) {
1075
+ if (binding.length !== 32 || hiding.length !== 32) {
1076
+ throw new ValidationError("Invalid nonce length", {
1077
+ field: "nonce",
1078
+ value: `binding: ${binding.length}, hiding: ${hiding.length}`,
1079
+ expected: "Both binding and hiding should be 32 bytes"
1080
+ });
1081
+ }
1082
+ return {
1083
+ binding,
1084
+ hiding
1085
+ };
1086
+ }
1087
+ function getSigningCommitmentFromNonce(nonce) {
1088
+ const bindingPubKey = secp256k15.getPublicKey(nonce.binding, true);
1089
+ const hidingPubKey = secp256k15.getPublicKey(nonce.hiding, true);
1090
+ return {
1091
+ binding: bindingPubKey,
1092
+ hiding: hidingPubKey
1093
+ };
1094
+ }
1095
+ function encodeSigningNonceToBytes(nonce) {
1096
+ return new Uint8Array([...nonce.binding, ...nonce.hiding]);
1097
+ }
1098
+ function decodeBytesToSigningNonce(bytes) {
1099
+ if (bytes.length !== 64) {
1100
+ throw new ValidationError("Invalid nonce length", {
1101
+ field: "bytes",
1102
+ value: bytes.length,
1103
+ expected: "64 bytes (32 bytes for binding + 32 bytes for hiding)"
1104
+ });
1105
+ }
1106
+ return {
1107
+ binding: bytes.slice(32, 64),
1108
+ hiding: bytes.slice(0, 32)
1109
+ };
1110
+ }
1111
+ function createSigningCommitment(binding, hiding) {
1112
+ if (binding.length !== 33 || hiding.length !== 33) {
1113
+ throw new ValidationError("Invalid nonce commitment length", {
1114
+ field: "commitment",
1115
+ value: `binding: ${binding.length}, hiding: ${hiding.length}`,
1116
+ expected: "Both binding and hiding should be 33 bytes (compressed public keys)"
1117
+ });
1118
+ }
1119
+ return {
1120
+ binding,
1121
+ hiding
1122
+ };
1123
+ }
1124
+ function encodeSigningCommitmentToBytes(commitment) {
1125
+ if (commitment.binding.length !== 33 || commitment.hiding.length !== 33) {
1126
+ throw new ValidationError("Invalid nonce commitment length", {
1127
+ field: "commitment",
1128
+ value: `binding: ${commitment.binding.length}, hiding: ${commitment.hiding.length}`,
1129
+ expected: "Both binding and hiding should be 33 bytes (compressed public keys)"
1130
+ });
1131
+ }
1132
+ return new Uint8Array([...commitment.binding, ...commitment.hiding]);
1133
+ }
1134
+ function decodeBytesToSigningCommitment(bytes) {
1135
+ if (bytes.length !== 66) {
1136
+ throw new ValidationError("Invalid nonce commitment length", {
1137
+ field: "bytes",
1138
+ value: bytes.length,
1139
+ expected: "66 bytes (33 bytes for binding + 33 bytes for hiding)"
1140
+ });
1141
+ }
1142
+ return {
1143
+ binding: bytes.slice(33, 66),
1144
+ hiding: bytes.slice(0, 33)
1145
+ };
1146
+ }
1147
+
1148
+ // src/utils/transaction.ts
1149
+ import { Transaction as Transaction2 } from "@scure/btc-signer";
1150
+ var TIME_LOCK_INTERVAL = 100;
1151
+ var ESTIMATED_TX_SIZE = 191;
1152
+ var DEFAULT_SATS_PER_VBYTE = 5;
1153
+ var DEFAULT_FEE_SATS = ESTIMATED_TX_SIZE * DEFAULT_SATS_PER_VBYTE;
1154
+ function maybeApplyFee(amount) {
1155
+ if (amount > BigInt(DEFAULT_FEE_SATS)) {
1156
+ return amount - BigInt(DEFAULT_FEE_SATS);
1157
+ }
1158
+ return amount;
1159
+ }
1160
+ function createRefundTx(sequence, nodeOutPoint, amountSats, receivingPubkey, network) {
1161
+ const newRefundTx = new Transaction2({
1162
+ version: 3,
1163
+ allowUnknownOutputs: true
1164
+ });
1165
+ newRefundTx.addInput({
1166
+ ...nodeOutPoint,
1167
+ sequence
1168
+ });
1169
+ const refundPkScript = getP2TRScriptFromPublicKey(receivingPubkey, network);
1170
+ newRefundTx.addOutput({
1171
+ script: refundPkScript,
1172
+ amount: amountSats
1173
+ });
1174
+ newRefundTx.addOutput(getEphemeralAnchorOutput());
1175
+ return newRefundTx;
1176
+ }
1177
+ function getCurrentTimelock(currSequence) {
1178
+ return (currSequence || 0) & 65535;
1179
+ }
1180
+ function getTransactionSequence(currSequence) {
1181
+ const timelock = getCurrentTimelock(currSequence);
1182
+ return 1 << 30 | timelock;
1183
+ }
1184
+ function checkIfValidSequence(currSequence) {
1185
+ const TIME_LOCK_ACTIVE = (currSequence || 0) & 2147483648;
1186
+ if (TIME_LOCK_ACTIVE !== 0) {
1187
+ throw new ValidationError("Timelock not active", {
1188
+ field: "currSequence",
1189
+ value: currSequence
1190
+ });
1191
+ }
1192
+ const RELATIVE_TIME_LOCK_ACTIVE = (currSequence || 0) & 4194304;
1193
+ if (RELATIVE_TIME_LOCK_ACTIVE !== 0) {
1194
+ throw new ValidationError("Block based timelock not active", {
1195
+ field: "currSequence",
1196
+ value: currSequence
1197
+ });
1198
+ }
1199
+ }
1200
+ function getNextTransactionSequence(currSequence, forRefresh) {
1201
+ const currentTimelock = getCurrentTimelock(currSequence);
1202
+ const nextTimelock = currentTimelock - TIME_LOCK_INTERVAL;
1203
+ if (forRefresh && nextTimelock <= 100 && currentTimelock > 0) {
1204
+ return {
1205
+ nextSequence: 1 << 30 | nextTimelock,
1206
+ needRefresh: true
1207
+ };
1208
+ }
1209
+ if (nextTimelock < 0) {
1210
+ throw new ValidationError("timelock interval is less than 0", {
1211
+ field: "nextTimelock",
1212
+ value: nextTimelock
1213
+ });
1214
+ }
1215
+ return {
1216
+ nextSequence: 1 << 30 | nextTimelock,
1217
+ needRefresh: nextTimelock <= 100
1218
+ };
1219
+ }
1220
+ function getEphemeralAnchorOutput() {
1221
+ return {
1222
+ script: new Uint8Array([81, 2, 78, 115]),
1223
+ // Pay-to-anchor (P2A) ephemeral anchor output
1224
+ amount: 0n
1225
+ };
1226
+ }
1227
+
1228
+ // src/signer/signer.ts
1229
+ import {
1230
+ bytesToHex as bytesToHex4,
1231
+ bytesToNumberBE as bytesToNumberBE3,
1232
+ equalBytes as equalBytes2,
1233
+ hexToBytes as hexToBytes2
1234
+ } from "@noble/curves/abstract/utils";
1235
+ import { schnorr as schnorr3, secp256k1 as secp256k16 } from "@noble/curves/secp256k1";
1236
+ import { HDKey } from "@scure/bip32";
1237
+ import { generateMnemonic, mnemonicToSeed } from "@scure/bip39";
1238
+ import { wordlist } from "@scure/bip39/wordlists/english";
1239
+ import * as ecies from "eciesjs";
1240
+
1241
+ // src/constants.ts
1242
+ import { isNode } from "@lightsparkdev/core";
1243
+ var isReactNative = typeof navigator !== "undefined" && navigator.product === "ReactNative";
1244
+ var isBun = globalThis.Bun !== void 0;
1245
+ var packageVersion = true ? "0.1.47" : "unknown";
1246
+ var baseEnvStr = "unknown";
1247
+ if (isBun) {
1248
+ const bunVersion = "version" in globalThis.Bun ? globalThis.Bun.version : "unknown-version";
1249
+ baseEnvStr = `bun/${bunVersion}`;
1250
+ } else if (isNode) {
1251
+ baseEnvStr = `node/${process.version}`;
1252
+ } else if (isReactNative) {
1253
+ baseEnvStr = "react-native";
1254
+ } else {
1255
+ const userAgent = typeof navigator !== "undefined" && navigator.userAgent || "unknown-user-agent";
1256
+ baseEnvStr = `browser/${userAgent}`;
1257
+ }
1258
+ var clientEnv = `js-spark-sdk/${packageVersion} ${baseEnvStr}`;
1259
+
1260
+ // src/signer/signer.ts
1261
+ import { privateAdd, privateNegate } from "@bitcoinerlab/secp256k1";
1262
+ import {
1263
+ fromPrivateKey,
1264
+ PARITY,
1265
+ Receipt
1266
+ } from "@buildonspark/lrc20-sdk";
1267
+ import { sha256 as sha2563 } from "@noble/hashes/sha2";
1268
+ import { taprootTweakPrivKey } from "@scure/btc-signer/utils";
1269
+ var sparkFrostModule = void 0;
1270
+ var getSparkFrostModule = async () => {
1271
+ if (isReactNative) {
1272
+ return void 0;
1273
+ }
1274
+ if (!sparkFrostModule) {
1275
+ sparkFrostModule = await import("./spark_bindings/wasm/index.js");
1276
+ }
1277
+ return sparkFrostModule;
1278
+ };
1279
+ var HARDENED_OFFSET = 2147483648;
1280
+ var DefaultSparkKeysGenerator = class {
1281
+ async deriveKeysFromSeed(seed, accountNumber) {
1282
+ const hdkey = HDKey.fromMasterSeed(seed);
1283
+ if (!hdkey.privateKey || !hdkey.publicKey) {
1284
+ throw new ValidationError("Failed to derive keys from seed", {
1285
+ field: "hdkey",
1286
+ value: seed
1287
+ });
1288
+ }
1289
+ const identityKey = hdkey.derive(`m/8797555'/${accountNumber}'/0'`);
1290
+ const signingKey = hdkey.derive(`m/8797555'/${accountNumber}'/1'`);
1291
+ const depositKey = hdkey.derive(`m/8797555'/${accountNumber}'/2'`);
1292
+ const staticDepositKey = hdkey.derive(`m/8797555'/${accountNumber}'/3'`);
1293
+ if (!identityKey.privateKey || !depositKey.privateKey || !signingKey.privateKey || !identityKey.publicKey || !depositKey.publicKey || !signingKey.publicKey || !staticDepositKey.privateKey || !staticDepositKey.publicKey) {
1294
+ throw new ValidationError(
1295
+ "Failed to derive all required keys from seed",
1296
+ {
1297
+ field: "derivedKeys"
1298
+ }
1299
+ );
1300
+ }
1301
+ return {
1302
+ masterPublicKey: hdkey.publicKey,
1303
+ identityKey: {
1304
+ privateKey: identityKey.privateKey,
1305
+ publicKey: identityKey.publicKey
1306
+ },
1307
+ signingHDKey: {
1308
+ hdKey: signingKey,
1309
+ privateKey: signingKey.privateKey,
1310
+ publicKey: signingKey.publicKey
1311
+ },
1312
+ depositKey: {
1313
+ privateKey: depositKey.privateKey,
1314
+ publicKey: depositKey.publicKey
1315
+ },
1316
+ staticDepositHDKey: {
1317
+ hdKey: staticDepositKey,
1318
+ privateKey: staticDepositKey.privateKey,
1319
+ publicKey: staticDepositKey.publicKey
1320
+ }
1321
+ };
1322
+ }
1323
+ };
1324
+ var TaprootOutputKeysGenerator = class {
1325
+ constructor(useAddressIndex = false) {
1326
+ this.useAddressIndex = useAddressIndex;
1327
+ }
1328
+ async deriveKeysFromSeed(seed, accountNumber) {
1329
+ const hdkey = HDKey.fromMasterSeed(seed);
1330
+ if (!hdkey.privateKey || !hdkey.publicKey) {
1331
+ throw new ValidationError("Failed to derive keys from seed", {
1332
+ field: "hdkey",
1333
+ value: seed
1334
+ });
1335
+ }
1336
+ const derivationPath = this.useAddressIndex ? `m/86'/0'/0'/0/${accountNumber}` : `m/86'/0'/${accountNumber}'/0/0`;
1337
+ const taprootInternalKey = hdkey.derive(derivationPath);
1338
+ let tweakedPrivateKey = taprootTweakPrivKey(taprootInternalKey.privateKey);
1339
+ let tweakedPublicKey = secp256k16.getPublicKey(tweakedPrivateKey);
1340
+ if (tweakedPublicKey[0] === 3) {
1341
+ tweakedPrivateKey = privateNegate(tweakedPrivateKey);
1342
+ tweakedPublicKey = secp256k16.getPublicKey(tweakedPrivateKey);
1343
+ }
1344
+ const identityKey = {
1345
+ publicKey: tweakedPublicKey,
1346
+ privateKey: tweakedPrivateKey
1347
+ };
1348
+ const signingKey = hdkey.derive(`${derivationPath}/1'`);
1349
+ const depositKey = hdkey.derive(`${derivationPath}/2'`);
1350
+ const staticDepositKey = hdkey.derive(`${derivationPath}/3'`);
1351
+ if (!signingKey.privateKey || !signingKey.publicKey || !depositKey.privateKey || !depositKey.publicKey || !staticDepositKey.privateKey || !staticDepositKey.publicKey) {
1352
+ throw new ValidationError(
1353
+ "Failed to derive all required keys from seed",
1354
+ {
1355
+ field: "derivedKeys"
1356
+ }
1357
+ );
1358
+ }
1359
+ return {
1360
+ masterPublicKey: hdkey.publicKey,
1361
+ identityKey: {
1362
+ privateKey: identityKey.privateKey,
1363
+ publicKey: identityKey.publicKey
1364
+ },
1365
+ signingHDKey: {
1366
+ hdKey: signingKey,
1367
+ privateKey: signingKey.privateKey,
1368
+ publicKey: signingKey.publicKey
1369
+ },
1370
+ depositKey: {
1371
+ privateKey: depositKey.privateKey,
1372
+ publicKey: depositKey.publicKey
1373
+ },
1374
+ staticDepositHDKey: {
1375
+ hdKey: staticDepositKey,
1376
+ privateKey: staticDepositKey.privateKey,
1377
+ publicKey: staticDepositKey.publicKey
1378
+ }
1379
+ };
1380
+ }
1381
+ };
1382
+ var DefaultSparkSigner = class {
1383
+ masterPublicKey = null;
1384
+ identityKey = null;
1385
+ signingKey = null;
1386
+ depositKey = null;
1387
+ staticDepositKey = null;
1388
+ staticDepositKeyMap = /* @__PURE__ */ new Map();
1389
+ // <hex, hex>
1390
+ publicKeyToPrivateKeyMap = /* @__PURE__ */ new Map();
1391
+ commitmentToNonceMap = /* @__PURE__ */ new Map();
1392
+ keysGenerator;
1393
+ constructor({
1394
+ sparkKeysGenerator
1395
+ } = {}) {
1396
+ this.keysGenerator = sparkKeysGenerator ?? new DefaultSparkKeysGenerator();
1397
+ }
1398
+ deriveSigningKey(hash) {
1399
+ if (!this.signingKey) {
1400
+ throw new ValidationError("Private key not initialized", {
1401
+ field: "signingKey"
1402
+ });
1403
+ }
1404
+ const view = new DataView(hash.buffer);
1405
+ const amount = view.getUint32(0, false) % HARDENED_OFFSET + HARDENED_OFFSET;
1406
+ const newPrivateKey = this.signingKey?.deriveChild(amount).privateKey;
1407
+ if (!newPrivateKey) {
1408
+ throw new ValidationError("Failed to recover signing key", {
1409
+ field: "privateKey"
1410
+ });
1411
+ }
1412
+ return newPrivateKey;
1413
+ }
1414
+ async restoreSigningKeysFromLeafs(leafs) {
1415
+ if (!this.signingKey) {
1416
+ throw new ValidationError("Signing key is not set", {
1417
+ field: "signingKey"
1418
+ });
1419
+ }
1420
+ for (const leaf of leafs) {
1421
+ const hash = sha2563(leaf.id);
1422
+ const privateKey = this.deriveSigningKey(hash);
1423
+ const publicKey = secp256k16.getPublicKey(privateKey);
1424
+ this.publicKeyToPrivateKeyMap.set(
1425
+ bytesToHex4(publicKey),
1426
+ bytesToHex4(privateKey)
1427
+ );
1428
+ }
1429
+ }
1430
+ async getSchnorrPublicKey(publicKey) {
1431
+ const privateKey = this.publicKeyToPrivateKeyMap.get(bytesToHex4(publicKey));
1432
+ if (!privateKey) {
1433
+ throw new ValidationError("Private key is not set", {
1434
+ field: "privateKey"
1435
+ });
1436
+ }
1437
+ return schnorr3.getPublicKey(hexToBytes2(privateKey));
1438
+ }
1439
+ async signSchnorr(message, publicKey) {
1440
+ const privateKey = this.publicKeyToPrivateKeyMap.get(bytesToHex4(publicKey));
1441
+ if (!privateKey) {
1442
+ throw new ValidationError("Private key is not set", {
1443
+ field: "privateKey"
1444
+ });
1445
+ }
1446
+ return schnorr3.sign(message, hexToBytes2(privateKey));
1447
+ }
1448
+ async signSchnorrWithIdentityKey(message) {
1449
+ if (!this.identityKey?.privateKey) {
1450
+ throw new ValidationError("Private key not set", {
1451
+ field: "identityKey"
1452
+ });
1453
+ }
1454
+ const signature = schnorr3.sign(message, this.identityKey.privateKey);
1455
+ return signature;
1456
+ }
1457
+ async getIdentityPublicKey() {
1458
+ if (!this.identityKey?.publicKey) {
1459
+ throw new ValidationError("Private key is not set", {
1460
+ field: "identityKey"
1461
+ });
1462
+ }
1463
+ return this.identityKey.publicKey;
1464
+ }
1465
+ async getDepositSigningKey() {
1466
+ if (!this.depositKey?.publicKey) {
1467
+ throw new ValidationError("Deposit key is not set", {
1468
+ field: "depositKey"
1469
+ });
1470
+ }
1471
+ return this.depositKey.publicKey;
1472
+ }
1473
+ async generateStaticDepositKey(idx) {
1474
+ if (!this.staticDepositKey?.privateKey) {
1475
+ throw new ValidationError("Static deposit key is not set", {
1476
+ field: "staticDepositKey"
1477
+ });
1478
+ }
1479
+ if (this.staticDepositKeyMap.has(idx)) {
1480
+ const staticDepositKey2 = this.staticDepositKeyMap.get(idx);
1481
+ return staticDepositKey2?.publicKey;
1482
+ }
1483
+ const staticDepositKey = this.staticDepositKey.deriveChild(
1484
+ HARDENED_OFFSET + idx
1485
+ );
1486
+ this.staticDepositKeyMap.set(idx, staticDepositKey);
1487
+ this.publicKeyToPrivateKeyMap.set(
1488
+ bytesToHex4(staticDepositKey.publicKey),
1489
+ bytesToHex4(staticDepositKey.privateKey)
1490
+ );
1491
+ return staticDepositKey.publicKey;
1492
+ }
1493
+ async getStaticDepositSigningKey(idx) {
1494
+ if (!this.staticDepositKey) {
1495
+ throw new ValidationError("Static deposit key is not set", {
1496
+ field: "staticDepositKey"
1497
+ });
1498
+ }
1499
+ if (!this.staticDepositKeyMap.has(idx)) {
1500
+ await this.generateStaticDepositKey(idx);
1501
+ }
1502
+ const staticDepositKey = this.staticDepositKeyMap.get(idx);
1503
+ if (!staticDepositKey?.publicKey) {
1504
+ throw new ValidationError("Static deposit key is not set", {
1505
+ field: "staticDepositKey"
1506
+ });
1507
+ }
1508
+ return staticDepositKey.publicKey;
1509
+ }
1510
+ async getStaticDepositSecretKey(idx) {
1511
+ if (!this.staticDepositKey) {
1512
+ throw new ValidationError("Static deposit key is not set", {
1513
+ field: "staticDepositKey"
1514
+ });
1515
+ }
1516
+ if (!this.staticDepositKeyMap.has(idx)) {
1517
+ await this.generateStaticDepositKey(idx);
1518
+ }
1519
+ const staticDepositKey = this.staticDepositKeyMap.get(idx);
1520
+ if (!staticDepositKey?.privateKey) {
1521
+ throw new ValidationError("Static deposit key is not set", {
1522
+ field: "staticDepositKey"
1523
+ });
1524
+ }
1525
+ return staticDepositKey.privateKey;
1526
+ }
1527
+ async generateMnemonic() {
1528
+ return generateMnemonic(wordlist);
1529
+ }
1530
+ async mnemonicToSeed(mnemonic) {
1531
+ return await mnemonicToSeed(mnemonic);
1532
+ }
1533
+ async getTrackedPublicKeys() {
1534
+ return Array.from(this.publicKeyToPrivateKeyMap.keys()).map(hexToBytes2);
1535
+ }
1536
+ async generatePublicKey(hash) {
1537
+ if (!this.signingKey) {
1538
+ throw new ValidationError("Private key is not set", {
1539
+ field: "signingKey"
1540
+ });
1541
+ }
1542
+ let newPrivateKey = null;
1543
+ if (hash) {
1544
+ newPrivateKey = this.deriveSigningKey(hash);
1545
+ } else {
1546
+ newPrivateKey = secp256k16.utils.randomPrivateKey();
1547
+ }
1548
+ if (!newPrivateKey) {
1549
+ throw new ValidationError("Failed to generate new private key", {
1550
+ field: "privateKey"
1551
+ });
1552
+ }
1553
+ const publicKey = secp256k16.getPublicKey(newPrivateKey);
1554
+ const pubKeyHex = bytesToHex4(publicKey);
1555
+ const privKeyHex = bytesToHex4(newPrivateKey);
1556
+ this.publicKeyToPrivateKeyMap.set(pubKeyHex, privKeyHex);
1557
+ return publicKey;
1558
+ }
1559
+ async removePublicKey(publicKey) {
1560
+ this.publicKeyToPrivateKeyMap.delete(bytesToHex4(publicKey));
1561
+ }
1562
+ async subtractPrivateKeysGivenPublicKeys(first, second) {
1563
+ const firstPubKeyHex = bytesToHex4(first);
1564
+ const secondPubKeyHex = bytesToHex4(second);
1565
+ const firstPrivateKeyHex = this.publicKeyToPrivateKeyMap.get(firstPubKeyHex);
1566
+ const secondPrivateKeyHex = this.publicKeyToPrivateKeyMap.get(secondPubKeyHex);
1567
+ if (!firstPrivateKeyHex || !secondPrivateKeyHex) {
1568
+ throw new Error("Private key is not set");
1569
+ }
1570
+ const firstPrivateKey = hexToBytes2(firstPrivateKeyHex);
1571
+ const secondPrivateKey = hexToBytes2(secondPrivateKeyHex);
1572
+ const resultPrivKey = subtractPrivateKeys(
1573
+ firstPrivateKey,
1574
+ secondPrivateKey
1575
+ );
1576
+ const resultPubKey = secp256k16.getPublicKey(resultPrivKey);
1577
+ const resultPrivKeyHex = bytesToHex4(resultPrivKey);
1578
+ const resultPubKeyHex = bytesToHex4(resultPubKey);
1579
+ this.publicKeyToPrivateKeyMap.set(resultPubKeyHex, resultPrivKeyHex);
1580
+ return resultPubKey;
1581
+ }
1582
+ async splitSecretWithProofs({
1583
+ secret,
1584
+ curveOrder,
1585
+ threshold,
1586
+ numShares,
1587
+ isSecretPubkey = false
1588
+ }) {
1589
+ if (isSecretPubkey) {
1590
+ const pubKeyHex = bytesToHex4(secret);
1591
+ const privateKey = this.publicKeyToPrivateKeyMap.get(pubKeyHex);
1592
+ if (!privateKey) {
1593
+ throw new Error("Private key is not set");
1594
+ }
1595
+ secret = hexToBytes2(privateKey);
1596
+ }
1597
+ const secretAsInt = bytesToNumberBE3(secret);
1598
+ return splitSecretWithProofs(secretAsInt, curveOrder, threshold, numShares);
1599
+ }
1600
+ async signFrost({
1601
+ message,
1602
+ privateAsPubKey,
1603
+ publicKey,
1604
+ verifyingKey,
1605
+ selfCommitment,
1606
+ statechainCommitments,
1607
+ adaptorPubKey
1608
+ }) {
1609
+ const SparkFrost = await getSparkFrostModule();
1610
+ if (!SparkFrost) {
1611
+ throw new ValidationError("SparkFrost module not found", {
1612
+ field: "SparkFrost"
1613
+ });
1614
+ }
1615
+ const privateAsPubKeyHex = bytesToHex4(privateAsPubKey);
1616
+ const signingPrivateKey = this.publicKeyToPrivateKeyMap.get(privateAsPubKeyHex);
1617
+ if (!signingPrivateKey) {
1618
+ throw new ValidationError("Private key not found for public key", {
1619
+ field: "privateKey"
1620
+ });
1621
+ }
1622
+ const nonce = this.commitmentToNonceMap.get(selfCommitment);
1623
+ if (!nonce) {
1624
+ throw new ValidationError("Nonce not found for commitment", {
1625
+ field: "nonce"
1626
+ });
1627
+ }
1628
+ const keyPackage = {
1629
+ secretKey: hexToBytes2(signingPrivateKey),
1630
+ publicKey,
1631
+ verifyingKey
1632
+ };
1633
+ return SparkFrost.signFrost({
1634
+ message,
1635
+ keyPackage,
1636
+ nonce,
1637
+ selfCommitment,
1638
+ statechainCommitments,
1639
+ adaptorPubKey
1640
+ });
1641
+ }
1642
+ async aggregateFrost({
1643
+ message,
1644
+ publicKey,
1645
+ verifyingKey,
1646
+ selfCommitment,
1647
+ statechainCommitments,
1648
+ adaptorPubKey,
1649
+ selfSignature,
1650
+ statechainSignatures,
1651
+ statechainPublicKeys
1652
+ }) {
1653
+ const SparkFrost = await getSparkFrostModule();
1654
+ if (!SparkFrost) {
1655
+ throw new ValidationError("SparkFrost module not found", {
1656
+ field: "SparkFrost"
1657
+ });
1658
+ }
1659
+ return SparkFrost.aggregateFrost({
1660
+ message,
1661
+ statechainSignatures,
1662
+ statechainPublicKeys,
1663
+ verifyingKey,
1664
+ statechainCommitments,
1665
+ selfCommitment,
1666
+ selfPublicKey: publicKey,
1667
+ selfSignature,
1668
+ adaptorPubKey
1669
+ });
1670
+ }
1671
+ async createSparkWalletFromSeed(seed, accountNumber) {
1672
+ if (typeof seed === "string") {
1673
+ seed = hexToBytes2(seed);
1674
+ }
1675
+ const {
1676
+ masterPublicKey,
1677
+ identityKey,
1678
+ signingHDKey: signingKey,
1679
+ depositKey,
1680
+ staticDepositHDKey: staticDepositKey
1681
+ } = await this.keysGenerator.deriveKeysFromSeed(seed, accountNumber ?? 0);
1682
+ this.masterPublicKey = masterPublicKey;
1683
+ this.identityKey = identityKey;
1684
+ this.depositKey = depositKey;
1685
+ this.signingKey = signingKey.hdKey;
1686
+ this.staticDepositKey = staticDepositKey.hdKey;
1687
+ this.publicKeyToPrivateKeyMap.set(
1688
+ bytesToHex4(identityKey.publicKey),
1689
+ bytesToHex4(identityKey.privateKey)
1690
+ );
1691
+ this.publicKeyToPrivateKeyMap.set(
1692
+ bytesToHex4(depositKey.publicKey),
1693
+ bytesToHex4(depositKey.privateKey)
1694
+ );
1695
+ this.publicKeyToPrivateKeyMap.set(
1696
+ bytesToHex4(staticDepositKey.publicKey),
1697
+ bytesToHex4(staticDepositKey.privateKey)
1698
+ );
1699
+ return bytesToHex4(identityKey.publicKey);
1700
+ }
1701
+ async signMessageWithPublicKey(message, publicKey, compact) {
1702
+ const privateKey = this.publicKeyToPrivateKeyMap.get(bytesToHex4(publicKey));
1703
+ if (!privateKey) {
1704
+ throw new ValidationError("Private key not found for public key", {
1705
+ field: "privateKey",
1706
+ value: bytesToHex4(publicKey)
1707
+ });
1708
+ }
1709
+ const signature = secp256k16.sign(message, hexToBytes2(privateKey));
1710
+ if (compact) {
1711
+ return signature.toCompactRawBytes();
1712
+ }
1713
+ return signature.toDERRawBytes();
1714
+ }
1715
+ async signMessageWithIdentityKey(message, compact) {
1716
+ if (!this.identityKey?.privateKey) {
1717
+ throw new ConfigurationError("Identity key not initialized", {
1718
+ configKey: "identityKey"
1719
+ });
1720
+ }
1721
+ const signature = secp256k16.sign(message, this.identityKey.privateKey);
1722
+ if (compact) {
1723
+ return signature.toCompactRawBytes();
1724
+ }
1725
+ return signature.toDERRawBytes();
1726
+ }
1727
+ async encryptLeafPrivateKeyEcies(receiverPublicKey, publicKey) {
1728
+ const publicKeyHex = bytesToHex4(publicKey);
1729
+ const privateKey = this.publicKeyToPrivateKeyMap.get(publicKeyHex);
1730
+ if (!privateKey) {
1731
+ throw new Error("Private key is not set");
1732
+ }
1733
+ return ecies.encrypt(receiverPublicKey, hexToBytes2(privateKey));
1734
+ }
1735
+ async decryptEcies(ciphertext) {
1736
+ if (!this.identityKey?.privateKey) {
1737
+ throw new ConfigurationError("Identity key not initialized", {
1738
+ configKey: "identityKey"
1739
+ });
1740
+ }
1741
+ const receiverEciesPrivKey = ecies.PrivateKey.fromHex(
1742
+ bytesToHex4(this.identityKey.privateKey)
1743
+ );
1744
+ const privateKey = ecies.decrypt(receiverEciesPrivKey.toHex(), ciphertext);
1745
+ const publicKey = secp256k16.getPublicKey(privateKey);
1746
+ const publicKeyHex = bytesToHex4(publicKey);
1747
+ const privateKeyHex = bytesToHex4(privateKey);
1748
+ this.publicKeyToPrivateKeyMap.set(publicKeyHex, privateKeyHex);
1749
+ return publicKey;
1750
+ }
1751
+ async getRandomSigningCommitment() {
1752
+ const nonce = getRandomSigningNonce();
1753
+ const commitment = getSigningCommitmentFromNonce(nonce);
1754
+ this.commitmentToNonceMap.set(commitment, nonce);
1755
+ return commitment;
1756
+ }
1757
+ async hashRandomPrivateKey() {
1758
+ return sha2563(secp256k16.utils.randomPrivateKey());
1759
+ }
1760
+ async generateAdaptorFromSignature(signature) {
1761
+ const adaptor = generateAdaptorFromSignature(signature);
1762
+ const adaptorPublicKey = secp256k16.getPublicKey(adaptor.adaptorPrivateKey);
1763
+ this.publicKeyToPrivateKeyMap.set(
1764
+ bytesToHex4(adaptorPublicKey),
1765
+ bytesToHex4(adaptor.adaptorPrivateKey)
1766
+ );
1767
+ return {
1768
+ adaptorSignature: signature,
1769
+ adaptorPublicKey
1770
+ };
1771
+ }
1772
+ async getMasterPublicKey() {
1773
+ if (!this.masterPublicKey) {
1774
+ throw new Error("Private key is not set");
1775
+ }
1776
+ return this.masterPublicKey;
1777
+ }
1778
+ async validateMessageWithIdentityKey(message, signature) {
1779
+ if (!this.identityKey?.publicKey) {
1780
+ throw new ConfigurationError("Identity key not initialized", {
1781
+ configKey: "identityKey"
1782
+ });
1783
+ }
1784
+ return secp256k16.verify(signature, message, this.identityKey.publicKey);
1785
+ }
1786
+ async signPsbt(psbt, input, sighashTypes, receipt) {
1787
+ if (!this.identityKey?.privateKey) {
1788
+ throw new ConfigurationError("Identity key not initialized", {
1789
+ configKey: "identityKey"
1790
+ });
1791
+ }
1792
+ if (receipt) {
1793
+ const receiptPrivateKey = this.getReceiptPrivateKey(receipt);
1794
+ const tweakedKeyPair = fromPrivateKey(Buffer.from(receiptPrivateKey));
1795
+ psbt.signInput(input, tweakedKeyPair, sighashTypes);
1796
+ return psbt;
1797
+ }
1798
+ const keypair = fromPrivateKey(Buffer.from(this.identityKey.privateKey));
1799
+ psbt.signInput(input, keypair, sighashTypes);
1800
+ return psbt;
1801
+ }
1802
+ getReceiptPrivateKey(receipt) {
1803
+ const pxh = Receipt.receiptHash(receipt);
1804
+ let innerKey = this.identityKey.publicKey;
1805
+ let privateKey = this.identityKey.privateKey;
1806
+ if (innerKey[0] === 3) {
1807
+ innerKey = Buffer.concat([PARITY, innerKey.slice(1)]);
1808
+ privateKey = Buffer.from(privateNegate(privateKey));
1809
+ }
1810
+ const pxhPubkey = sha2563(Buffer.concat([pxh, innerKey]));
1811
+ const receiptProof = privateAdd(privateKey, pxhPubkey);
1812
+ return Buffer.from(receiptProof);
1813
+ }
1814
+ signTransactionIndex(tx, index, publicKey) {
1815
+ let privateKey;
1816
+ if (equalBytes2(publicKey, this.identityKey?.publicKey ?? new Uint8Array())) {
1817
+ privateKey = this.identityKey?.privateKey;
1818
+ } else if (equalBytes2(publicKey, this.depositKey?.publicKey ?? new Uint8Array())) {
1819
+ privateKey = this.depositKey?.privateKey;
1820
+ } else {
1821
+ privateKey = hexToBytes2(
1822
+ this.publicKeyToPrivateKeyMap.get(bytesToHex4(publicKey)) ?? ""
1823
+ );
1824
+ }
1825
+ if (!privateKey) {
1826
+ throw new ValidationError("Private key not found for public key", {
1827
+ field: "privateKey",
1828
+ value: bytesToHex4(publicKey)
1829
+ });
1830
+ }
1831
+ tx.signIdx(privateKey, index);
1832
+ }
1833
+ };
1834
+ var TaprootSparkSigner = class extends DefaultSparkSigner {
1835
+ constructor(useAddressIndex = false) {
1836
+ super({
1837
+ sparkKeysGenerator: new TaprootOutputKeysGenerator(useAddressIndex)
1838
+ });
1839
+ }
1840
+ };
1841
+
1842
+ // src/services/config.ts
1843
+ var WalletConfigService = class {
1844
+ config;
1845
+ signer;
1846
+ lrc20ApiConfig;
1847
+ sspClientOptions;
1848
+ constructor(options, signer) {
1849
+ const network = options?.network ?? "REGTEST";
1850
+ this.config = {
1851
+ ...this.getDefaultConfig(Network2[network]),
1852
+ ...options
1853
+ };
1854
+ this.signer = signer ?? new DefaultSparkSigner();
1855
+ this.lrc20ApiConfig = this.config.lrc20ApiConfig;
1856
+ this.sspClientOptions = this.config.sspClientOptions;
1857
+ }
1858
+ getDefaultConfig(network) {
1859
+ switch (network) {
1860
+ case 0 /* MAINNET */:
1861
+ return WalletConfig.MAINNET;
1862
+ case 3 /* REGTEST */:
1863
+ return WalletConfig.REGTEST;
1864
+ default:
1865
+ return WalletConfig.LOCAL;
1866
+ }
1867
+ }
1868
+ getCoordinatorAddress() {
1869
+ const coordinator = this.config.signingOperators[this.config.coodinatorIdentifier];
1870
+ if (!coordinator) {
1871
+ throw new ConfigurationError(
1872
+ "Coordinator not found in signing operators",
1873
+ {
1874
+ configKey: "signingOperators"
1875
+ }
1876
+ );
1877
+ }
1878
+ return coordinator.address;
1879
+ }
1880
+ getLrc20Address() {
1881
+ return this.config.lrc20Address;
1882
+ }
1883
+ getSigningOperators() {
1884
+ return this.config.signingOperators;
1885
+ }
1886
+ getThreshold() {
1887
+ return this.config.threshold;
1888
+ }
1889
+ getCoordinatorIdentifier() {
1890
+ return this.config.coodinatorIdentifier;
1891
+ }
1892
+ getExpectedWithdrawBondSats() {
1893
+ return this.config.expectedWithdrawBondSats;
1894
+ }
1895
+ getExpectedWithdrawRelativeBlockLocktime() {
1896
+ return this.config.expectedWithdrawRelativeBlockLocktime;
1897
+ }
1898
+ getSspNetwork() {
1899
+ if (this.config.network === "MAINNET") {
1900
+ return "MAINNET" /* MAINNET */;
1901
+ } else if (this.config.network === "REGTEST") {
1902
+ return "REGTEST" /* REGTEST */;
1903
+ } else if (this.config.network === "TESTNET") {
1904
+ return "TESTNET" /* TESTNET */;
1905
+ } else if (this.config.network === "SIGNET") {
1906
+ return "SIGNET" /* SIGNET */;
1907
+ }
1908
+ return "FUTURE_VALUE" /* FUTURE_VALUE */;
1909
+ }
1910
+ getNetwork() {
1911
+ return Network2[this.config.network];
1912
+ }
1913
+ getNetworkType() {
1914
+ return this.config.network;
1915
+ }
1916
+ getNetworkProto() {
1917
+ return NetworkToProto[Network2[this.config.network]];
1918
+ }
1919
+ getTokenSignatures() {
1920
+ return this.config.tokenSignatures;
1921
+ }
1922
+ getTokenTransactionVersion() {
1923
+ return this.config.tokenTransactionVersion;
1924
+ }
1925
+ getTokenValidityDurationSeconds() {
1926
+ return this.config.tokenValidityDurationSeconds;
1927
+ }
1928
+ getElectrsUrl() {
1929
+ return this.config.electrsUrl;
1930
+ }
1931
+ getSspIdentityPublicKey() {
1932
+ return this.config.sspClientOptions.identityPublicKey;
1933
+ }
1934
+ };
1935
+
1936
+ // src/services/connection.ts
1937
+ import { isError, isNode as isNode2 } from "@lightsparkdev/core";
1938
+ import { sha256 as sha2564 } from "@noble/hashes/sha2";
1939
+ import { retryMiddleware } from "nice-grpc-client-middleware-retry";
1940
+ import { Metadata } from "nice-grpc-common";
1941
+
1942
+ // src/proto/mock.ts
1943
+ import { BinaryReader, BinaryWriter } from "@bufbuild/protobuf/wire";
1944
+ function interruptTransferRequest_InterruptTransferActionFromJSON(object) {
1945
+ switch (object) {
1946
+ case 0:
1947
+ case "NONE":
1948
+ return 0 /* NONE */;
1949
+ case 1:
1950
+ case "INTERRUPT":
1951
+ return 1 /* INTERRUPT */;
1952
+ case 2:
1953
+ case "RESUME":
1954
+ return 2 /* RESUME */;
1955
+ case -1:
1956
+ case "UNRECOGNIZED":
1957
+ default:
1958
+ return -1 /* UNRECOGNIZED */;
1959
+ }
1960
+ }
1961
+ function interruptTransferRequest_InterruptTransferActionToJSON(object) {
1962
+ switch (object) {
1963
+ case 0 /* NONE */:
1964
+ return "NONE";
1965
+ case 1 /* INTERRUPT */:
1966
+ return "INTERRUPT";
1967
+ case 2 /* RESUME */:
1968
+ return "RESUME";
1969
+ case -1 /* UNRECOGNIZED */:
1970
+ default:
1971
+ return "UNRECOGNIZED";
1972
+ }
1973
+ }
1974
+ function createBaseCleanUpPreimageShareRequest() {
1975
+ return { paymentHash: new Uint8Array(0) };
1976
+ }
1977
+ var CleanUpPreimageShareRequest = {
1978
+ encode(message, writer = new BinaryWriter()) {
1979
+ if (message.paymentHash.length !== 0) {
1980
+ writer.uint32(10).bytes(message.paymentHash);
1981
+ }
1982
+ return writer;
1983
+ },
1984
+ decode(input, length) {
1985
+ const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
1986
+ const end = length === void 0 ? reader.len : reader.pos + length;
1987
+ const message = createBaseCleanUpPreimageShareRequest();
1988
+ while (reader.pos < end) {
1989
+ const tag = reader.uint32();
1990
+ switch (tag >>> 3) {
1991
+ case 1: {
1992
+ if (tag !== 10) {
1993
+ break;
1994
+ }
1995
+ message.paymentHash = reader.bytes();
1996
+ continue;
1997
+ }
1998
+ }
1999
+ if ((tag & 7) === 4 || tag === 0) {
2000
+ break;
2001
+ }
2002
+ reader.skip(tag & 7);
2003
+ }
2004
+ return message;
2005
+ },
2006
+ fromJSON(object) {
2007
+ return { paymentHash: isSet(object.paymentHash) ? bytesFromBase64(object.paymentHash) : new Uint8Array(0) };
2008
+ },
2009
+ toJSON(message) {
2010
+ const obj = {};
2011
+ if (message.paymentHash.length !== 0) {
2012
+ obj.paymentHash = base64FromBytes(message.paymentHash);
2013
+ }
2014
+ return obj;
2015
+ },
2016
+ create(base) {
2017
+ return CleanUpPreimageShareRequest.fromPartial(base ?? {});
2018
+ },
2019
+ fromPartial(object) {
2020
+ const message = createBaseCleanUpPreimageShareRequest();
2021
+ message.paymentHash = object.paymentHash ?? new Uint8Array(0);
2022
+ return message;
2023
+ }
2024
+ };
2025
+ function createBaseInterruptTransferRequest() {
2026
+ return { action: 0 };
2027
+ }
2028
+ var InterruptTransferRequest = {
2029
+ encode(message, writer = new BinaryWriter()) {
2030
+ if (message.action !== 0) {
2031
+ writer.uint32(8).int32(message.action);
2032
+ }
2033
+ return writer;
2034
+ },
2035
+ decode(input, length) {
2036
+ const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
2037
+ const end = length === void 0 ? reader.len : reader.pos + length;
2038
+ const message = createBaseInterruptTransferRequest();
2039
+ while (reader.pos < end) {
2040
+ const tag = reader.uint32();
2041
+ switch (tag >>> 3) {
2042
+ case 1: {
2043
+ if (tag !== 8) {
2044
+ break;
2045
+ }
2046
+ message.action = reader.int32();
2047
+ continue;
2048
+ }
2049
+ }
2050
+ if ((tag & 7) === 4 || tag === 0) {
2051
+ break;
2052
+ }
2053
+ reader.skip(tag & 7);
2054
+ }
2055
+ return message;
2056
+ },
2057
+ fromJSON(object) {
2058
+ return {
2059
+ action: isSet(object.action) ? interruptTransferRequest_InterruptTransferActionFromJSON(object.action) : 0
2060
+ };
2061
+ },
2062
+ toJSON(message) {
2063
+ const obj = {};
2064
+ if (message.action !== 0) {
2065
+ obj.action = interruptTransferRequest_InterruptTransferActionToJSON(message.action);
2066
+ }
2067
+ return obj;
2068
+ },
2069
+ create(base) {
2070
+ return InterruptTransferRequest.fromPartial(base ?? {});
2071
+ },
2072
+ fromPartial(object) {
2073
+ const message = createBaseInterruptTransferRequest();
2074
+ message.action = object.action ?? 0;
2075
+ return message;
2076
+ }
2077
+ };
2078
+ function createBaseUpdateNodesStatusRequest() {
2079
+ return { nodeIds: [], status: "" };
2080
+ }
2081
+ var UpdateNodesStatusRequest = {
2082
+ encode(message, writer = new BinaryWriter()) {
2083
+ for (const v of message.nodeIds) {
2084
+ writer.uint32(10).string(v);
2085
+ }
2086
+ if (message.status !== "") {
2087
+ writer.uint32(18).string(message.status);
2088
+ }
2089
+ return writer;
2090
+ },
2091
+ decode(input, length) {
2092
+ const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
2093
+ const end = length === void 0 ? reader.len : reader.pos + length;
2094
+ const message = createBaseUpdateNodesStatusRequest();
2095
+ while (reader.pos < end) {
2096
+ const tag = reader.uint32();
2097
+ switch (tag >>> 3) {
2098
+ case 1: {
2099
+ if (tag !== 10) {
2100
+ break;
2101
+ }
2102
+ message.nodeIds.push(reader.string());
2103
+ continue;
2104
+ }
2105
+ case 2: {
2106
+ if (tag !== 18) {
2107
+ break;
2108
+ }
2109
+ message.status = reader.string();
2110
+ continue;
2111
+ }
2112
+ }
2113
+ if ((tag & 7) === 4 || tag === 0) {
2114
+ break;
2115
+ }
2116
+ reader.skip(tag & 7);
2117
+ }
2118
+ return message;
2119
+ },
2120
+ fromJSON(object) {
2121
+ return {
2122
+ nodeIds: globalThis.Array.isArray(object?.nodeIds) ? object.nodeIds.map((e) => globalThis.String(e)) : [],
2123
+ status: isSet(object.status) ? globalThis.String(object.status) : ""
2124
+ };
2125
+ },
2126
+ toJSON(message) {
2127
+ const obj = {};
2128
+ if (message.nodeIds?.length) {
2129
+ obj.nodeIds = message.nodeIds;
2130
+ }
2131
+ if (message.status !== "") {
2132
+ obj.status = message.status;
2133
+ }
2134
+ return obj;
2135
+ },
2136
+ create(base) {
2137
+ return UpdateNodesStatusRequest.fromPartial(base ?? {});
2138
+ },
2139
+ fromPartial(object) {
2140
+ const message = createBaseUpdateNodesStatusRequest();
2141
+ message.nodeIds = object.nodeIds?.map((e) => e) || [];
2142
+ message.status = object.status ?? "";
2143
+ return message;
2144
+ }
2145
+ };
2146
+ var MockServiceDefinition = {
2147
+ name: "MockService",
2148
+ fullName: "mock.MockService",
2149
+ methods: {
2150
+ clean_up_preimage_share: {
2151
+ name: "clean_up_preimage_share",
2152
+ requestType: CleanUpPreimageShareRequest,
2153
+ requestStream: false,
2154
+ responseType: Empty,
2155
+ responseStream: false,
2156
+ options: {}
2157
+ },
2158
+ interrupt_transfer: {
2159
+ name: "interrupt_transfer",
2160
+ requestType: InterruptTransferRequest,
2161
+ requestStream: false,
2162
+ responseType: Empty,
2163
+ responseStream: false,
2164
+ options: {}
2165
+ },
2166
+ update_nodes_status: {
2167
+ name: "update_nodes_status",
2168
+ requestType: UpdateNodesStatusRequest,
2169
+ requestStream: false,
2170
+ responseType: Empty,
2171
+ responseStream: false,
2172
+ options: {}
2173
+ }
2174
+ }
2175
+ };
2176
+ function bytesFromBase64(b64) {
2177
+ if (globalThis.Buffer) {
2178
+ return Uint8Array.from(globalThis.Buffer.from(b64, "base64"));
2179
+ } else {
2180
+ const bin = globalThis.atob(b64);
2181
+ const arr = new Uint8Array(bin.length);
2182
+ for (let i = 0; i < bin.length; ++i) {
2183
+ arr[i] = bin.charCodeAt(i);
2184
+ }
2185
+ return arr;
2186
+ }
2187
+ }
2188
+ function base64FromBytes(arr) {
2189
+ if (globalThis.Buffer) {
2190
+ return globalThis.Buffer.from(arr).toString("base64");
2191
+ } else {
2192
+ const bin = [];
2193
+ arr.forEach((byte) => {
2194
+ bin.push(globalThis.String.fromCharCode(byte));
2195
+ });
2196
+ return globalThis.btoa(bin.join(""));
2197
+ }
2198
+ }
2199
+ function isSet(value) {
2200
+ return value !== null && value !== void 0;
2201
+ }
2202
+
2203
+ // src/proto/spark_authn.ts
2204
+ import { BinaryReader as BinaryReader2, BinaryWriter as BinaryWriter2 } from "@bufbuild/protobuf/wire";
2205
+ function createBaseChallenge() {
2206
+ return { version: 0, timestamp: 0, nonce: new Uint8Array(0), publicKey: new Uint8Array(0) };
2207
+ }
2208
+ var Challenge = {
2209
+ encode(message, writer = new BinaryWriter2()) {
2210
+ if (message.version !== 0) {
2211
+ writer.uint32(8).int32(message.version);
2212
+ }
2213
+ if (message.timestamp !== 0) {
2214
+ writer.uint32(16).int64(message.timestamp);
2215
+ }
2216
+ if (message.nonce.length !== 0) {
2217
+ writer.uint32(26).bytes(message.nonce);
2218
+ }
2219
+ if (message.publicKey.length !== 0) {
2220
+ writer.uint32(34).bytes(message.publicKey);
2221
+ }
2222
+ return writer;
2223
+ },
2224
+ decode(input, length) {
2225
+ const reader = input instanceof BinaryReader2 ? input : new BinaryReader2(input);
2226
+ const end = length === void 0 ? reader.len : reader.pos + length;
2227
+ const message = createBaseChallenge();
2228
+ while (reader.pos < end) {
2229
+ const tag = reader.uint32();
2230
+ switch (tag >>> 3) {
2231
+ case 1: {
2232
+ if (tag !== 8) {
2233
+ break;
2234
+ }
2235
+ message.version = reader.int32();
2236
+ continue;
2237
+ }
2238
+ case 2: {
2239
+ if (tag !== 16) {
2240
+ break;
2241
+ }
2242
+ message.timestamp = longToNumber(reader.int64());
2243
+ continue;
2244
+ }
2245
+ case 3: {
2246
+ if (tag !== 26) {
2247
+ break;
2248
+ }
2249
+ message.nonce = reader.bytes();
2250
+ continue;
2251
+ }
2252
+ case 4: {
2253
+ if (tag !== 34) {
2254
+ break;
2255
+ }
2256
+ message.publicKey = reader.bytes();
2257
+ continue;
2258
+ }
2259
+ }
2260
+ if ((tag & 7) === 4 || tag === 0) {
2261
+ break;
2262
+ }
2263
+ reader.skip(tag & 7);
2264
+ }
2265
+ return message;
2266
+ },
2267
+ fromJSON(object) {
2268
+ return {
2269
+ version: isSet2(object.version) ? globalThis.Number(object.version) : 0,
2270
+ timestamp: isSet2(object.timestamp) ? globalThis.Number(object.timestamp) : 0,
2271
+ nonce: isSet2(object.nonce) ? bytesFromBase642(object.nonce) : new Uint8Array(0),
2272
+ publicKey: isSet2(object.publicKey) ? bytesFromBase642(object.publicKey) : new Uint8Array(0)
2273
+ };
2274
+ },
2275
+ toJSON(message) {
2276
+ const obj = {};
2277
+ if (message.version !== 0) {
2278
+ obj.version = Math.round(message.version);
2279
+ }
2280
+ if (message.timestamp !== 0) {
2281
+ obj.timestamp = Math.round(message.timestamp);
2282
+ }
2283
+ if (message.nonce.length !== 0) {
2284
+ obj.nonce = base64FromBytes2(message.nonce);
2285
+ }
2286
+ if (message.publicKey.length !== 0) {
2287
+ obj.publicKey = base64FromBytes2(message.publicKey);
2288
+ }
2289
+ return obj;
2290
+ },
2291
+ create(base) {
2292
+ return Challenge.fromPartial(base ?? {});
2293
+ },
2294
+ fromPartial(object) {
2295
+ const message = createBaseChallenge();
2296
+ message.version = object.version ?? 0;
2297
+ message.timestamp = object.timestamp ?? 0;
2298
+ message.nonce = object.nonce ?? new Uint8Array(0);
2299
+ message.publicKey = object.publicKey ?? new Uint8Array(0);
2300
+ return message;
2301
+ }
2302
+ };
2303
+ function createBaseProtectedChallenge() {
2304
+ return { version: 0, challenge: void 0, serverHmac: new Uint8Array(0) };
2305
+ }
2306
+ var ProtectedChallenge = {
2307
+ encode(message, writer = new BinaryWriter2()) {
2308
+ if (message.version !== 0) {
2309
+ writer.uint32(8).int32(message.version);
2310
+ }
2311
+ if (message.challenge !== void 0) {
2312
+ Challenge.encode(message.challenge, writer.uint32(18).fork()).join();
2313
+ }
2314
+ if (message.serverHmac.length !== 0) {
2315
+ writer.uint32(26).bytes(message.serverHmac);
2316
+ }
2317
+ return writer;
2318
+ },
2319
+ decode(input, length) {
2320
+ const reader = input instanceof BinaryReader2 ? input : new BinaryReader2(input);
2321
+ const end = length === void 0 ? reader.len : reader.pos + length;
2322
+ const message = createBaseProtectedChallenge();
2323
+ while (reader.pos < end) {
2324
+ const tag = reader.uint32();
2325
+ switch (tag >>> 3) {
2326
+ case 1: {
2327
+ if (tag !== 8) {
2328
+ break;
2329
+ }
2330
+ message.version = reader.int32();
2331
+ continue;
2332
+ }
2333
+ case 2: {
2334
+ if (tag !== 18) {
2335
+ break;
2336
+ }
2337
+ message.challenge = Challenge.decode(reader, reader.uint32());
2338
+ continue;
2339
+ }
2340
+ case 3: {
2341
+ if (tag !== 26) {
2342
+ break;
2343
+ }
2344
+ message.serverHmac = reader.bytes();
2345
+ continue;
2346
+ }
2347
+ }
2348
+ if ((tag & 7) === 4 || tag === 0) {
2349
+ break;
2350
+ }
2351
+ reader.skip(tag & 7);
2352
+ }
2353
+ return message;
2354
+ },
2355
+ fromJSON(object) {
2356
+ return {
2357
+ version: isSet2(object.version) ? globalThis.Number(object.version) : 0,
2358
+ challenge: isSet2(object.challenge) ? Challenge.fromJSON(object.challenge) : void 0,
2359
+ serverHmac: isSet2(object.serverHmac) ? bytesFromBase642(object.serverHmac) : new Uint8Array(0)
2360
+ };
2361
+ },
2362
+ toJSON(message) {
2363
+ const obj = {};
2364
+ if (message.version !== 0) {
2365
+ obj.version = Math.round(message.version);
2366
+ }
2367
+ if (message.challenge !== void 0) {
2368
+ obj.challenge = Challenge.toJSON(message.challenge);
2369
+ }
2370
+ if (message.serverHmac.length !== 0) {
2371
+ obj.serverHmac = base64FromBytes2(message.serverHmac);
2372
+ }
2373
+ return obj;
2374
+ },
2375
+ create(base) {
2376
+ return ProtectedChallenge.fromPartial(base ?? {});
2377
+ },
2378
+ fromPartial(object) {
2379
+ const message = createBaseProtectedChallenge();
2380
+ message.version = object.version ?? 0;
2381
+ message.challenge = object.challenge !== void 0 && object.challenge !== null ? Challenge.fromPartial(object.challenge) : void 0;
2382
+ message.serverHmac = object.serverHmac ?? new Uint8Array(0);
2383
+ return message;
2384
+ }
2385
+ };
2386
+ function createBaseGetChallengeRequest() {
2387
+ return { publicKey: new Uint8Array(0) };
2388
+ }
2389
+ var GetChallengeRequest = {
2390
+ encode(message, writer = new BinaryWriter2()) {
2391
+ if (message.publicKey.length !== 0) {
2392
+ writer.uint32(10).bytes(message.publicKey);
2393
+ }
2394
+ return writer;
2395
+ },
2396
+ decode(input, length) {
2397
+ const reader = input instanceof BinaryReader2 ? input : new BinaryReader2(input);
2398
+ const end = length === void 0 ? reader.len : reader.pos + length;
2399
+ const message = createBaseGetChallengeRequest();
2400
+ while (reader.pos < end) {
2401
+ const tag = reader.uint32();
2402
+ switch (tag >>> 3) {
2403
+ case 1: {
2404
+ if (tag !== 10) {
2405
+ break;
2406
+ }
2407
+ message.publicKey = reader.bytes();
2408
+ continue;
2409
+ }
2410
+ }
2411
+ if ((tag & 7) === 4 || tag === 0) {
2412
+ break;
2413
+ }
2414
+ reader.skip(tag & 7);
2415
+ }
2416
+ return message;
2417
+ },
2418
+ fromJSON(object) {
2419
+ return { publicKey: isSet2(object.publicKey) ? bytesFromBase642(object.publicKey) : new Uint8Array(0) };
2420
+ },
2421
+ toJSON(message) {
2422
+ const obj = {};
2423
+ if (message.publicKey.length !== 0) {
2424
+ obj.publicKey = base64FromBytes2(message.publicKey);
2425
+ }
2426
+ return obj;
2427
+ },
2428
+ create(base) {
2429
+ return GetChallengeRequest.fromPartial(base ?? {});
2430
+ },
2431
+ fromPartial(object) {
2432
+ const message = createBaseGetChallengeRequest();
2433
+ message.publicKey = object.publicKey ?? new Uint8Array(0);
2434
+ return message;
2435
+ }
2436
+ };
2437
+ function createBaseGetChallengeResponse() {
2438
+ return { protectedChallenge: void 0 };
2439
+ }
2440
+ var GetChallengeResponse = {
2441
+ encode(message, writer = new BinaryWriter2()) {
2442
+ if (message.protectedChallenge !== void 0) {
2443
+ ProtectedChallenge.encode(message.protectedChallenge, writer.uint32(10).fork()).join();
2444
+ }
2445
+ return writer;
2446
+ },
2447
+ decode(input, length) {
2448
+ const reader = input instanceof BinaryReader2 ? input : new BinaryReader2(input);
2449
+ const end = length === void 0 ? reader.len : reader.pos + length;
2450
+ const message = createBaseGetChallengeResponse();
2451
+ while (reader.pos < end) {
2452
+ const tag = reader.uint32();
2453
+ switch (tag >>> 3) {
2454
+ case 1: {
2455
+ if (tag !== 10) {
2456
+ break;
2457
+ }
2458
+ message.protectedChallenge = ProtectedChallenge.decode(reader, reader.uint32());
2459
+ continue;
2460
+ }
2461
+ }
2462
+ if ((tag & 7) === 4 || tag === 0) {
2463
+ break;
2464
+ }
2465
+ reader.skip(tag & 7);
2466
+ }
2467
+ return message;
2468
+ },
2469
+ fromJSON(object) {
2470
+ return {
2471
+ protectedChallenge: isSet2(object.protectedChallenge) ? ProtectedChallenge.fromJSON(object.protectedChallenge) : void 0
2472
+ };
2473
+ },
2474
+ toJSON(message) {
2475
+ const obj = {};
2476
+ if (message.protectedChallenge !== void 0) {
2477
+ obj.protectedChallenge = ProtectedChallenge.toJSON(message.protectedChallenge);
2478
+ }
2479
+ return obj;
2480
+ },
2481
+ create(base) {
2482
+ return GetChallengeResponse.fromPartial(base ?? {});
2483
+ },
2484
+ fromPartial(object) {
2485
+ const message = createBaseGetChallengeResponse();
2486
+ message.protectedChallenge = object.protectedChallenge !== void 0 && object.protectedChallenge !== null ? ProtectedChallenge.fromPartial(object.protectedChallenge) : void 0;
2487
+ return message;
2488
+ }
2489
+ };
2490
+ function createBaseVerifyChallengeRequest() {
2491
+ return { protectedChallenge: void 0, signature: new Uint8Array(0), publicKey: new Uint8Array(0) };
2492
+ }
2493
+ var VerifyChallengeRequest = {
2494
+ encode(message, writer = new BinaryWriter2()) {
2495
+ if (message.protectedChallenge !== void 0) {
2496
+ ProtectedChallenge.encode(message.protectedChallenge, writer.uint32(10).fork()).join();
2497
+ }
2498
+ if (message.signature.length !== 0) {
2499
+ writer.uint32(18).bytes(message.signature);
2500
+ }
2501
+ if (message.publicKey.length !== 0) {
2502
+ writer.uint32(26).bytes(message.publicKey);
2503
+ }
2504
+ return writer;
2505
+ },
2506
+ decode(input, length) {
2507
+ const reader = input instanceof BinaryReader2 ? input : new BinaryReader2(input);
2508
+ const end = length === void 0 ? reader.len : reader.pos + length;
2509
+ const message = createBaseVerifyChallengeRequest();
2510
+ while (reader.pos < end) {
2511
+ const tag = reader.uint32();
2512
+ switch (tag >>> 3) {
2513
+ case 1: {
2514
+ if (tag !== 10) {
2515
+ break;
2516
+ }
2517
+ message.protectedChallenge = ProtectedChallenge.decode(reader, reader.uint32());
2518
+ continue;
2519
+ }
2520
+ case 2: {
2521
+ if (tag !== 18) {
2522
+ break;
2523
+ }
2524
+ message.signature = reader.bytes();
2525
+ continue;
2526
+ }
2527
+ case 3: {
2528
+ if (tag !== 26) {
2529
+ break;
2530
+ }
2531
+ message.publicKey = reader.bytes();
2532
+ continue;
2533
+ }
2534
+ }
2535
+ if ((tag & 7) === 4 || tag === 0) {
2536
+ break;
2537
+ }
2538
+ reader.skip(tag & 7);
2539
+ }
2540
+ return message;
2541
+ },
2542
+ fromJSON(object) {
2543
+ return {
2544
+ protectedChallenge: isSet2(object.protectedChallenge) ? ProtectedChallenge.fromJSON(object.protectedChallenge) : void 0,
2545
+ signature: isSet2(object.signature) ? bytesFromBase642(object.signature) : new Uint8Array(0),
2546
+ publicKey: isSet2(object.publicKey) ? bytesFromBase642(object.publicKey) : new Uint8Array(0)
2547
+ };
2548
+ },
2549
+ toJSON(message) {
2550
+ const obj = {};
2551
+ if (message.protectedChallenge !== void 0) {
2552
+ obj.protectedChallenge = ProtectedChallenge.toJSON(message.protectedChallenge);
2553
+ }
2554
+ if (message.signature.length !== 0) {
2555
+ obj.signature = base64FromBytes2(message.signature);
2556
+ }
2557
+ if (message.publicKey.length !== 0) {
2558
+ obj.publicKey = base64FromBytes2(message.publicKey);
2559
+ }
2560
+ return obj;
2561
+ },
2562
+ create(base) {
2563
+ return VerifyChallengeRequest.fromPartial(base ?? {});
2564
+ },
2565
+ fromPartial(object) {
2566
+ const message = createBaseVerifyChallengeRequest();
2567
+ message.protectedChallenge = object.protectedChallenge !== void 0 && object.protectedChallenge !== null ? ProtectedChallenge.fromPartial(object.protectedChallenge) : void 0;
2568
+ message.signature = object.signature ?? new Uint8Array(0);
2569
+ message.publicKey = object.publicKey ?? new Uint8Array(0);
2570
+ return message;
2571
+ }
2572
+ };
2573
+ function createBaseVerifyChallengeResponse() {
2574
+ return { sessionToken: "", expirationTimestamp: 0 };
2575
+ }
2576
+ var VerifyChallengeResponse = {
2577
+ encode(message, writer = new BinaryWriter2()) {
2578
+ if (message.sessionToken !== "") {
2579
+ writer.uint32(10).string(message.sessionToken);
2580
+ }
2581
+ if (message.expirationTimestamp !== 0) {
2582
+ writer.uint32(16).int64(message.expirationTimestamp);
2583
+ }
2584
+ return writer;
2585
+ },
2586
+ decode(input, length) {
2587
+ const reader = input instanceof BinaryReader2 ? input : new BinaryReader2(input);
2588
+ const end = length === void 0 ? reader.len : reader.pos + length;
2589
+ const message = createBaseVerifyChallengeResponse();
2590
+ while (reader.pos < end) {
2591
+ const tag = reader.uint32();
2592
+ switch (tag >>> 3) {
2593
+ case 1: {
2594
+ if (tag !== 10) {
2595
+ break;
2596
+ }
2597
+ message.sessionToken = reader.string();
2598
+ continue;
2599
+ }
2600
+ case 2: {
2601
+ if (tag !== 16) {
2602
+ break;
2603
+ }
2604
+ message.expirationTimestamp = longToNumber(reader.int64());
2605
+ continue;
2606
+ }
2607
+ }
2608
+ if ((tag & 7) === 4 || tag === 0) {
2609
+ break;
2610
+ }
2611
+ reader.skip(tag & 7);
2612
+ }
2613
+ return message;
2614
+ },
2615
+ fromJSON(object) {
2616
+ return {
2617
+ sessionToken: isSet2(object.sessionToken) ? globalThis.String(object.sessionToken) : "",
2618
+ expirationTimestamp: isSet2(object.expirationTimestamp) ? globalThis.Number(object.expirationTimestamp) : 0
2619
+ };
2620
+ },
2621
+ toJSON(message) {
2622
+ const obj = {};
2623
+ if (message.sessionToken !== "") {
2624
+ obj.sessionToken = message.sessionToken;
2625
+ }
2626
+ if (message.expirationTimestamp !== 0) {
2627
+ obj.expirationTimestamp = Math.round(message.expirationTimestamp);
2628
+ }
2629
+ return obj;
2630
+ },
2631
+ create(base) {
2632
+ return VerifyChallengeResponse.fromPartial(base ?? {});
2633
+ },
2634
+ fromPartial(object) {
2635
+ const message = createBaseVerifyChallengeResponse();
2636
+ message.sessionToken = object.sessionToken ?? "";
2637
+ message.expirationTimestamp = object.expirationTimestamp ?? 0;
2638
+ return message;
2639
+ }
2640
+ };
2641
+ var SparkAuthnServiceDefinition = {
2642
+ name: "SparkAuthnService",
2643
+ fullName: "spark_authn.SparkAuthnService",
2644
+ methods: {
2645
+ /** Request a new authentication challenge for a public key */
2646
+ get_challenge: {
2647
+ name: "get_challenge",
2648
+ requestType: GetChallengeRequest,
2649
+ requestStream: false,
2650
+ responseType: GetChallengeResponse,
2651
+ responseStream: false,
2652
+ options: {}
2653
+ },
2654
+ /** Verify a signed challenge and return a session token */
2655
+ verify_challenge: {
2656
+ name: "verify_challenge",
2657
+ requestType: VerifyChallengeRequest,
2658
+ requestStream: false,
2659
+ responseType: VerifyChallengeResponse,
2660
+ responseStream: false,
2661
+ options: {}
2662
+ }
2663
+ }
2664
+ };
2665
+ function bytesFromBase642(b64) {
2666
+ if (globalThis.Buffer) {
2667
+ return Uint8Array.from(globalThis.Buffer.from(b64, "base64"));
2668
+ } else {
2669
+ const bin = globalThis.atob(b64);
2670
+ const arr = new Uint8Array(bin.length);
2671
+ for (let i = 0; i < bin.length; ++i) {
2672
+ arr[i] = bin.charCodeAt(i);
2673
+ }
2674
+ return arr;
2675
+ }
2676
+ }
2677
+ function base64FromBytes2(arr) {
2678
+ if (globalThis.Buffer) {
2679
+ return globalThis.Buffer.from(arr).toString("base64");
2680
+ } else {
2681
+ const bin = [];
2682
+ arr.forEach((byte) => {
2683
+ bin.push(globalThis.String.fromCharCode(byte));
2684
+ });
2685
+ return globalThis.btoa(bin.join(""));
2686
+ }
2687
+ }
2688
+ function longToNumber(int64) {
2689
+ const num = globalThis.Number(int64.toString());
2690
+ if (num > globalThis.Number.MAX_SAFE_INTEGER) {
2691
+ throw new globalThis.Error("Value is larger than Number.MAX_SAFE_INTEGER");
2692
+ }
2693
+ if (num < globalThis.Number.MIN_SAFE_INTEGER) {
2694
+ throw new globalThis.Error("Value is smaller than Number.MIN_SAFE_INTEGER");
2695
+ }
2696
+ return num;
2697
+ }
2698
+ function isSet2(value) {
2699
+ return value !== null && value !== void 0;
2700
+ }
2701
+
2702
+ // src/services/connection.ts
2703
+ var ConnectionManager = class {
2704
+ config;
2705
+ clients = /* @__PURE__ */ new Map();
2706
+ tokenClients = /* @__PURE__ */ new Map();
2707
+ // We are going to .unref() the underlying channels for stream clients
2708
+ // to prevent the stream from keeping the process alive
2709
+ // Using a different map to avoid unforeseen problems with unary calls
2710
+ streamClients = /* @__PURE__ */ new Map();
2711
+ // Tracks in-flight authenticate() promises so concurrent callers share one
2712
+ authPromises = /* @__PURE__ */ new Map();
2713
+ constructor(config) {
2714
+ this.config = config;
2715
+ }
2716
+ // When initializing wallet, go ahead and instantiate all clients
2717
+ async createClients() {
2718
+ await Promise.all(
2719
+ Object.values(this.config.getSigningOperators()).map((operator) => {
2720
+ this.createSparkClient(operator.address);
2721
+ })
2722
+ );
2723
+ }
2724
+ async closeConnections() {
2725
+ await Promise.all(
2726
+ Array.from(this.clients.values()).map(
2727
+ (client) => client.client.close?.()
2728
+ )
2729
+ );
2730
+ this.clients.clear();
2731
+ }
2732
+ async createMockClient(address2) {
2733
+ const channel = await this.createChannelWithTLS(address2);
2734
+ const isNodeChannel = "close" in channel;
2735
+ if (isNode2 && isNodeChannel && !isBun) {
2736
+ const grpcModule = await import("nice-grpc");
2737
+ const { createClient } = "default" in grpcModule ? grpcModule.default : grpcModule;
2738
+ const client = createClient(MockServiceDefinition, channel);
2739
+ return { ...client, close: () => channel.close() };
2740
+ } else if (!isNodeChannel) {
2741
+ const grpcModule = await import("nice-grpc-web");
2742
+ const { createClient } = "default" in grpcModule ? grpcModule.default : grpcModule;
2743
+ const client = createClient(MockServiceDefinition, channel);
2744
+ return { ...client, close: () => {
2745
+ } };
2746
+ } else {
2747
+ throw new Error("Channel does not have close in NodeJS environment");
2748
+ }
2749
+ }
2750
+ async createChannelWithTLS(address2, certPath) {
2751
+ try {
2752
+ if (isNode2 && !isBun) {
2753
+ const grpcModule = await import("nice-grpc");
2754
+ const { ChannelCredentials, createChannel } = "default" in grpcModule ? grpcModule.default : grpcModule;
2755
+ if (certPath) {
2756
+ try {
2757
+ const fs = await import("fs");
2758
+ const cert = fs.readFileSync(certPath);
2759
+ return createChannel(address2, ChannelCredentials.createSsl(cert));
2760
+ } catch (error) {
2761
+ console.error("Error reading certificate:", error);
2762
+ return createChannel(
2763
+ address2,
2764
+ ChannelCredentials.createSsl(null, null, null, {
2765
+ rejectUnauthorized: false
2766
+ })
2767
+ );
2768
+ }
2769
+ } else {
2770
+ return createChannel(
2771
+ address2,
2772
+ ChannelCredentials.createSsl(null, null, null, {
2773
+ rejectUnauthorized: false
2774
+ })
2775
+ );
2776
+ }
2777
+ } else {
2778
+ const grpcModule = await import("nice-grpc-web");
2779
+ const { createChannel, FetchTransport } = "default" in grpcModule ? grpcModule.default : grpcModule;
2780
+ const { XHRTransport } = await import("./xhr-transport-RH6LDRXS.js");
2781
+ return createChannel(
2782
+ address2,
2783
+ isReactNative ? XHRTransport() : FetchTransport()
2784
+ );
2785
+ }
2786
+ } catch (error) {
2787
+ console.error("Channel creation error:", error);
2788
+ throw new NetworkError(
2789
+ "Failed to create channel",
2790
+ {
2791
+ url: address2,
2792
+ operation: "createChannel",
2793
+ errorCount: 1,
2794
+ errors: error instanceof Error ? error.message : String(error)
2795
+ },
2796
+ error
2797
+ );
2798
+ }
2799
+ }
2800
+ async createSparkStreamClient(address2, certPath) {
2801
+ if (this.streamClients.has(address2)) {
2802
+ return this.streamClients.get(address2).client;
2803
+ }
2804
+ const authToken = await this.authenticate(address2);
2805
+ const channel = await this.createChannelWithTLS(address2, certPath);
2806
+ const middleware = this.createMiddleware(address2, authToken);
2807
+ const client = await this.createGrpcClient(
2808
+ SparkServiceDefinition,
2809
+ channel,
2810
+ true,
2811
+ middleware
2812
+ );
2813
+ this.streamClients.set(address2, { client, authToken, channel });
2814
+ return client;
2815
+ }
2816
+ async createSparkClient(address2, certPath) {
2817
+ if (this.clients.has(address2)) {
2818
+ return this.clients.get(address2).client;
2819
+ }
2820
+ const authToken = await this.authenticate(address2);
2821
+ const channel = await this.createChannelWithTLS(address2, certPath);
2822
+ const middleware = this.createMiddleware(address2, authToken);
2823
+ const client = await this.createGrpcClient(
2824
+ SparkServiceDefinition,
2825
+ channel,
2826
+ true,
2827
+ middleware
2828
+ );
2829
+ this.clients.set(address2, { client, authToken });
2830
+ return client;
2831
+ }
2832
+ async createSparkTokenClient(address2, certPath) {
2833
+ if (this.tokenClients.has(address2)) {
2834
+ return this.tokenClients.get(address2).client;
2835
+ }
2836
+ const authToken = await this.authenticate(address2);
2837
+ const channel = await this.createChannelWithTLS(address2, certPath);
2838
+ const middleware = this.createMiddleware(address2, authToken);
2839
+ const tokenClient = await this.createGrpcClient(
2840
+ SparkTokenServiceDefinition,
2841
+ channel,
2842
+ true,
2843
+ middleware
2844
+ );
2845
+ this.tokenClients.set(address2, { client: tokenClient, authToken });
2846
+ return tokenClient;
2847
+ }
2848
+ async getStreamChannel(address2) {
2849
+ return this.streamClients.get(address2)?.channel;
2850
+ }
2851
+ async authenticate(address2, certPath) {
2852
+ const existing = this.authPromises.get(address2);
2853
+ if (existing) {
2854
+ return existing;
2855
+ }
2856
+ const authPromise = (async () => {
2857
+ const MAX_ATTEMPTS = 3;
2858
+ let lastError;
2859
+ for (let attempt = 0; attempt < MAX_ATTEMPTS; attempt++) {
2860
+ let sparkAuthnClient;
2861
+ try {
2862
+ const identityPublicKey = await this.config.signer.getIdentityPublicKey();
2863
+ sparkAuthnClient = await this.createSparkAuthnGrpcConnection(
2864
+ address2,
2865
+ certPath
2866
+ );
2867
+ const challengeResp = await sparkAuthnClient.get_challenge({
2868
+ publicKey: identityPublicKey
2869
+ });
2870
+ if (!challengeResp.protectedChallenge?.challenge) {
2871
+ throw new AuthenticationError("Invalid challenge response", {
2872
+ endpoint: "get_challenge",
2873
+ reason: "Missing challenge in response"
2874
+ });
2875
+ }
2876
+ const challengeBytes = Challenge.encode(
2877
+ challengeResp.protectedChallenge.challenge
2878
+ ).finish();
2879
+ const hash = sha2564(challengeBytes);
2880
+ const derSignatureBytes = await this.config.signer.signMessageWithIdentityKey(hash);
2881
+ const verifyResp = await sparkAuthnClient.verify_challenge({
2882
+ protectedChallenge: challengeResp.protectedChallenge,
2883
+ signature: derSignatureBytes,
2884
+ publicKey: identityPublicKey
2885
+ });
2886
+ sparkAuthnClient.close?.();
2887
+ return verifyResp.sessionToken;
2888
+ } catch (error) {
2889
+ if (isError(error)) {
2890
+ sparkAuthnClient?.close?.();
2891
+ if (error.message.includes("challenge expired")) {
2892
+ console.warn(
2893
+ `Authentication attempt ${attempt + 1} failed due to expired challenge, retrying...`
2894
+ );
2895
+ lastError = error;
2896
+ continue;
2897
+ }
2898
+ throw new AuthenticationError(
2899
+ "Authentication failed",
2900
+ {
2901
+ endpoint: "authenticate",
2902
+ reason: error.message
2903
+ },
2904
+ error
2905
+ );
2906
+ } else {
2907
+ lastError = new Error(
2908
+ `Unknown error during authentication: ${String(error)}`
2909
+ );
2910
+ }
2911
+ }
2912
+ }
2913
+ throw new AuthenticationError(
2914
+ "Authentication failed after retrying expired challenges",
2915
+ {
2916
+ endpoint: "authenticate",
2917
+ reason: lastError?.message ?? "Unknown error"
2918
+ },
2919
+ lastError
2920
+ );
2921
+ })();
2922
+ this.authPromises.set(address2, authPromise);
2923
+ try {
2924
+ return await authPromise;
2925
+ } finally {
2926
+ this.authPromises.delete(address2);
2927
+ }
2928
+ }
2929
+ async createSparkAuthnGrpcConnection(address2, certPath) {
2930
+ const channel = await this.createChannelWithTLS(address2, certPath);
2931
+ const authnMiddleware = this.createAuthnMiddleware();
2932
+ return this.createGrpcClient(
2933
+ SparkAuthnServiceDefinition,
2934
+ channel,
2935
+ false,
2936
+ authnMiddleware
2937
+ );
2938
+ }
2939
+ createAuthnMiddleware() {
2940
+ if (isNode2) {
2941
+ return async function* (call, options) {
2942
+ const metadata = Metadata(options.metadata).set(
2943
+ "X-Client-Env",
2944
+ clientEnv
2945
+ );
2946
+ return yield* call.next(call.request, {
2947
+ ...options,
2948
+ metadata
2949
+ });
2950
+ }.bind(this);
2951
+ } else {
2952
+ return async function* (call, options) {
2953
+ const metadata = Metadata(options.metadata).set("X-Requested-With", "XMLHttpRequest").set("X-Grpc-Web", "1").set("X-Client-Env", clientEnv).set("Content-Type", "application/grpc-web+proto");
2954
+ return yield* call.next(call.request, {
2955
+ ...options,
2956
+ metadata
2957
+ });
2958
+ }.bind(this);
2959
+ }
2960
+ }
2961
+ createMiddleware(address2, authToken) {
2962
+ if (isNode2) {
2963
+ return this.createNodeMiddleware(address2, authToken);
2964
+ } else {
2965
+ return this.createBrowserMiddleware(address2, authToken);
2966
+ }
2967
+ }
2968
+ async *handleMiddlewareError(error, address2, call, metadata, options) {
2969
+ if (isError(error)) {
2970
+ if (error.message.includes("token has expired")) {
2971
+ const newAuthToken = await this.authenticate(address2);
2972
+ const clientData = this.clients.get(address2);
2973
+ if (!clientData) {
2974
+ throw new Error(`No client found for address: ${address2}`);
2975
+ }
2976
+ clientData.authToken = newAuthToken;
2977
+ return yield* call.next(call.request, {
2978
+ ...options,
2979
+ metadata: metadata.set("Authorization", `Bearer ${newAuthToken}`)
2980
+ });
2981
+ }
2982
+ }
2983
+ throw error;
2984
+ }
2985
+ createNodeMiddleware(address2, initialAuthToken) {
2986
+ return async function* (call, options) {
2987
+ const metadata = Metadata(options.metadata).set(
2988
+ "X-Client-Env",
2989
+ clientEnv
2990
+ );
2991
+ try {
2992
+ return yield* call.next(call.request, {
2993
+ ...options,
2994
+ metadata: metadata.set(
2995
+ "Authorization",
2996
+ `Bearer ${this.clients.get(address2)?.authToken || initialAuthToken}`
2997
+ )
2998
+ });
2999
+ } catch (error) {
3000
+ return yield* this.handleMiddlewareError(
3001
+ error,
3002
+ address2,
3003
+ call,
3004
+ metadata,
3005
+ options
3006
+ );
3007
+ }
3008
+ }.bind(this);
3009
+ }
3010
+ createBrowserMiddleware(address2, initialAuthToken) {
3011
+ return async function* (call, options) {
3012
+ const metadata = Metadata(options.metadata).set("X-Requested-With", "XMLHttpRequest").set("X-Grpc-Web", "1").set("X-Client-Env", clientEnv).set("Content-Type", "application/grpc-web+proto");
3013
+ try {
3014
+ return yield* call.next(call.request, {
3015
+ ...options,
3016
+ metadata: metadata.set(
3017
+ "Authorization",
3018
+ `Bearer ${this.clients.get(address2)?.authToken || initialAuthToken}`
3019
+ )
3020
+ });
3021
+ } catch (error) {
3022
+ return yield* this.handleMiddlewareError(
3023
+ error,
3024
+ address2,
3025
+ call,
3026
+ metadata,
3027
+ options
3028
+ );
3029
+ }
3030
+ }.bind(this);
3031
+ }
3032
+ async createGrpcClient(defintion, channel, withRetries, middleware) {
3033
+ let clientFactory;
3034
+ const retryOptions = {
3035
+ retry: true,
3036
+ retryMaxAttempts: 3
3037
+ };
3038
+ let options = {};
3039
+ const isNodeChannel = "close" in channel;
3040
+ if (isNode2 && isNodeChannel && !isBun) {
3041
+ const grpcModule = await import("nice-grpc");
3042
+ const { openTelemetryClientMiddleware } = await import("nice-grpc-opentelemetry");
3043
+ const { createClientFactory } = "default" in grpcModule ? grpcModule.default : grpcModule;
3044
+ clientFactory = createClientFactory();
3045
+ if (withRetries) {
3046
+ options = retryOptions;
3047
+ clientFactory = clientFactory.use(openTelemetryClientMiddleware()).use(retryMiddleware);
3048
+ }
3049
+ if (middleware) {
3050
+ clientFactory = clientFactory.use(middleware);
3051
+ }
3052
+ const client = clientFactory.create(defintion, channel, {
3053
+ "*": options
3054
+ });
3055
+ return {
3056
+ ...client,
3057
+ close: channel.close.bind(channel)
3058
+ };
3059
+ } else if (!isNodeChannel) {
3060
+ const grpcModule = await import("nice-grpc-web");
3061
+ const { createClientFactory } = "default" in grpcModule ? grpcModule.default : grpcModule;
3062
+ clientFactory = createClientFactory();
3063
+ if (withRetries) {
3064
+ options = retryOptions;
3065
+ clientFactory = clientFactory.use(retryMiddleware);
3066
+ }
3067
+ if (middleware) {
3068
+ clientFactory = clientFactory.use(middleware);
3069
+ }
3070
+ const client = clientFactory.create(defintion, channel, {
3071
+ "*": options
3072
+ });
3073
+ return {
3074
+ ...client,
3075
+ close: void 0
3076
+ };
3077
+ } else {
3078
+ throw new Error("Channel does not have close in NodeJS environment");
3079
+ }
3080
+ }
3081
+ };
3082
+
3083
+ // src/services/deposit.ts
3084
+ import { schnorr as schnorr4, secp256k1 as secp256k17 } from "@noble/curves/secp256k1";
3085
+ import { sha256 as sha2565 } from "@noble/hashes/sha2";
3086
+ import { hexToBytes as hexToBytes3 } from "@noble/hashes/utils";
3087
+ import * as btc3 from "@scure/btc-signer";
3088
+ import { p2tr as p2tr2, Transaction as Transaction3 } from "@scure/btc-signer";
3089
+ import { equalBytes as equalBytes3 } from "@scure/btc-signer/utils";
3090
+ var INITIAL_TIME_LOCK = 2e3;
3091
+ var DepositService = class {
3092
+ config;
3093
+ connectionManager;
3094
+ constructor(config, connectionManager) {
3095
+ this.config = config;
3096
+ this.connectionManager = connectionManager;
3097
+ }
3098
+ async validateDepositAddress({
3099
+ address: address2,
3100
+ userPubkey
3101
+ }) {
3102
+ if (!address2.depositAddressProof || !address2.depositAddressProof.proofOfPossessionSignature || !address2.depositAddressProof.addressSignatures) {
3103
+ throw new ValidationError(
3104
+ "Proof of possession signature or address signatures is null",
3105
+ {
3106
+ field: "depositAddressProof",
3107
+ value: address2.depositAddressProof
3108
+ }
3109
+ );
3110
+ }
3111
+ const operatorPubkey = subtractPublicKeys(address2.verifyingKey, userPubkey);
3112
+ const msg = proofOfPossessionMessageHashForDepositAddress(
3113
+ await this.config.signer.getIdentityPublicKey(),
3114
+ operatorPubkey,
3115
+ address2.address
3116
+ );
3117
+ const taprootKey = p2tr2(
3118
+ operatorPubkey.slice(1, 33),
3119
+ void 0,
3120
+ getNetwork(this.config.getNetwork())
3121
+ ).tweakedPubkey;
3122
+ const isVerified = schnorr4.verify(
3123
+ address2.depositAddressProof.proofOfPossessionSignature,
3124
+ msg,
3125
+ taprootKey
3126
+ );
3127
+ if (!isVerified) {
3128
+ throw new ValidationError(
3129
+ "Proof of possession signature verification failed",
3130
+ {
3131
+ field: "proofOfPossessionSignature",
3132
+ value: address2.depositAddressProof.proofOfPossessionSignature
3133
+ }
3134
+ );
3135
+ }
3136
+ const addrHash = sha2565(address2.address);
3137
+ for (const operator of Object.values(this.config.getSigningOperators())) {
3138
+ if (operator.identifier === this.config.getCoordinatorIdentifier()) {
3139
+ continue;
3140
+ }
3141
+ const operatorPubkey2 = hexToBytes3(operator.identityPublicKey);
3142
+ const operatorSig = address2.depositAddressProof.addressSignatures[operator.identifier];
3143
+ if (!operatorSig) {
3144
+ throw new ValidationError("Operator signature not found", {
3145
+ field: "addressSignatures",
3146
+ value: operator.identifier
3147
+ });
3148
+ }
3149
+ const sig = secp256k17.Signature.fromDER(operatorSig);
3150
+ const isVerified2 = secp256k17.verify(sig, addrHash, operatorPubkey2);
3151
+ if (!isVerified2) {
3152
+ throw new ValidationError("Operator signature verification failed", {
3153
+ field: "operatorSignature",
3154
+ value: operatorSig
3155
+ });
3156
+ }
3157
+ }
3158
+ }
3159
+ async generateDepositAddress({
3160
+ signingPubkey,
3161
+ leafId,
3162
+ isStatic = false
3163
+ }) {
3164
+ const sparkClient = await this.connectionManager.createSparkClient(
3165
+ this.config.getCoordinatorAddress()
3166
+ );
3167
+ let depositResp;
3168
+ try {
3169
+ depositResp = await sparkClient.generate_deposit_address({
3170
+ signingPublicKey: signingPubkey,
3171
+ identityPublicKey: await this.config.signer.getIdentityPublicKey(),
3172
+ network: this.config.getNetworkProto(),
3173
+ leafId,
3174
+ isStatic
3175
+ });
3176
+ } catch (error) {
3177
+ throw new NetworkError(
3178
+ "Failed to generate deposit address",
3179
+ {
3180
+ operation: "generate_deposit_address",
3181
+ errorCount: 1,
3182
+ errors: error instanceof Error ? error.message : String(error)
3183
+ },
3184
+ error
3185
+ );
3186
+ }
3187
+ if (!depositResp.depositAddress) {
3188
+ throw new ValidationError(
3189
+ "No deposit address response from coordinator",
3190
+ {
3191
+ field: "depositAddress",
3192
+ value: depositResp
3193
+ }
3194
+ );
3195
+ }
3196
+ await this.validateDepositAddress({
3197
+ address: depositResp.depositAddress,
3198
+ userPubkey: signingPubkey
3199
+ });
3200
+ return depositResp;
3201
+ }
3202
+ async createTreeRoot({
3203
+ signingPubKey,
3204
+ verifyingKey,
3205
+ depositTx,
3206
+ vout
3207
+ }) {
3208
+ const rootTx = new Transaction3({ version: 3 });
3209
+ const output = depositTx.getOutput(vout);
3210
+ if (!output) {
3211
+ throw new ValidationError("Invalid deposit transaction output", {
3212
+ field: "vout",
3213
+ value: vout,
3214
+ expected: "Valid output index"
3215
+ });
3216
+ }
3217
+ const script = output.script;
3218
+ const amount = output.amount;
3219
+ if (!script || !amount) {
3220
+ throw new ValidationError("No script or amount found in deposit tx", {
3221
+ field: "output",
3222
+ value: output,
3223
+ expected: "Output with script and amount"
3224
+ });
3225
+ }
3226
+ let outputAmount = amount;
3227
+ rootTx.addInput({
3228
+ txid: getTxId(depositTx),
3229
+ index: vout
3230
+ });
3231
+ rootTx.addOutput({
3232
+ script,
3233
+ amount: outputAmount
3234
+ });
3235
+ rootTx.addOutput(getEphemeralAnchorOutput());
3236
+ const rootNonceCommitment = await this.config.signer.getRandomSigningCommitment();
3237
+ const rootTxSighash = getSigHashFromTx(rootTx, 0, output);
3238
+ const refundTx = new Transaction3({ version: 3 });
3239
+ const sequence = 1 << 30 | INITIAL_TIME_LOCK;
3240
+ refundTx.addInput({
3241
+ txid: getTxId(rootTx),
3242
+ index: 0,
3243
+ sequence
3244
+ });
3245
+ const refundP2trAddress = getP2TRAddressFromPublicKey(
3246
+ signingPubKey,
3247
+ this.config.getNetwork()
3248
+ );
3249
+ const refundAddress = btc3.Address(getNetwork(this.config.getNetwork())).decode(refundP2trAddress);
3250
+ const refundPkScript = btc3.OutScript.encode(refundAddress);
3251
+ refundTx.addOutput({
3252
+ script: refundPkScript,
3253
+ amount: outputAmount
3254
+ });
3255
+ refundTx.addOutput(getEphemeralAnchorOutput());
3256
+ const refundNonceCommitment = await this.config.signer.getRandomSigningCommitment();
3257
+ const refundTxSighash = getSigHashFromTx(refundTx, 0, rootTx.getOutput(0));
3258
+ const sparkClient = await this.connectionManager.createSparkClient(
3259
+ this.config.getCoordinatorAddress()
3260
+ );
3261
+ let treeResp;
3262
+ try {
3263
+ treeResp = await sparkClient.start_deposit_tree_creation({
3264
+ identityPublicKey: await this.config.signer.getIdentityPublicKey(),
3265
+ onChainUtxo: {
3266
+ vout,
3267
+ rawTx: depositTx.toBytes(true),
3268
+ network: this.config.getNetworkProto()
3269
+ },
3270
+ rootTxSigningJob: {
3271
+ rawTx: rootTx.toBytes(),
3272
+ signingPublicKey: signingPubKey,
3273
+ signingNonceCommitment: rootNonceCommitment
3274
+ },
3275
+ refundTxSigningJob: {
3276
+ rawTx: refundTx.toBytes(),
3277
+ signingPublicKey: signingPubKey,
3278
+ signingNonceCommitment: refundNonceCommitment
3279
+ }
3280
+ });
3281
+ } catch (error) {
3282
+ throw new NetworkError(
3283
+ "Failed to start deposit tree creation",
3284
+ {
3285
+ operation: "start_deposit_tree_creation",
3286
+ errorCount: 1,
3287
+ errors: error instanceof Error ? error.message : String(error)
3288
+ },
3289
+ error
3290
+ );
3291
+ }
3292
+ if (!treeResp.rootNodeSignatureShares?.verifyingKey) {
3293
+ throw new ValidationError("No verifying key found in tree response", {
3294
+ field: "verifyingKey",
3295
+ value: treeResp.rootNodeSignatureShares,
3296
+ expected: "Non-null verifying key"
3297
+ });
3298
+ }
3299
+ if (!treeResp.rootNodeSignatureShares.nodeTxSigningResult?.signingNonceCommitments) {
3300
+ throw new ValidationError(
3301
+ "No signing nonce commitments found in tree response",
3302
+ {
3303
+ field: "nodeTxSigningResult.signingNonceCommitments",
3304
+ value: treeResp.rootNodeSignatureShares.nodeTxSigningResult,
3305
+ expected: "Non-null signing nonce commitments"
3306
+ }
3307
+ );
3308
+ }
3309
+ if (!treeResp.rootNodeSignatureShares.refundTxSigningResult?.signingNonceCommitments) {
3310
+ throw new ValidationError(
3311
+ "No signing nonce commitments found in tree response",
3312
+ {
3313
+ field: "refundTxSigningResult.signingNonceCommitments"
3314
+ }
3315
+ );
3316
+ }
3317
+ if (!equalBytes3(treeResp.rootNodeSignatureShares.verifyingKey, verifyingKey)) {
3318
+ throw new ValidationError("Verifying key mismatch", {
3319
+ field: "verifyingKey",
3320
+ value: treeResp.rootNodeSignatureShares.verifyingKey,
3321
+ expected: verifyingKey
3322
+ });
3323
+ }
3324
+ const rootSignature = await this.config.signer.signFrost({
3325
+ message: rootTxSighash,
3326
+ publicKey: signingPubKey,
3327
+ privateAsPubKey: signingPubKey,
3328
+ verifyingKey,
3329
+ selfCommitment: rootNonceCommitment,
3330
+ statechainCommitments: treeResp.rootNodeSignatureShares.nodeTxSigningResult.signingNonceCommitments,
3331
+ adaptorPubKey: new Uint8Array()
3332
+ });
3333
+ const refundSignature = await this.config.signer.signFrost({
3334
+ message: refundTxSighash,
3335
+ publicKey: signingPubKey,
3336
+ privateAsPubKey: signingPubKey,
3337
+ verifyingKey,
3338
+ selfCommitment: refundNonceCommitment,
3339
+ statechainCommitments: treeResp.rootNodeSignatureShares.refundTxSigningResult.signingNonceCommitments,
3340
+ adaptorPubKey: new Uint8Array()
3341
+ });
3342
+ const rootAggregate = await this.config.signer.aggregateFrost({
3343
+ message: rootTxSighash,
3344
+ statechainSignatures: treeResp.rootNodeSignatureShares.nodeTxSigningResult.signatureShares,
3345
+ statechainPublicKeys: treeResp.rootNodeSignatureShares.nodeTxSigningResult.publicKeys,
3346
+ verifyingKey: treeResp.rootNodeSignatureShares.verifyingKey,
3347
+ statechainCommitments: treeResp.rootNodeSignatureShares.nodeTxSigningResult.signingNonceCommitments,
3348
+ selfCommitment: rootNonceCommitment,
3349
+ publicKey: signingPubKey,
3350
+ selfSignature: rootSignature,
3351
+ adaptorPubKey: new Uint8Array()
3352
+ });
3353
+ const refundAggregate = await this.config.signer.aggregateFrost({
3354
+ message: refundTxSighash,
3355
+ statechainSignatures: treeResp.rootNodeSignatureShares.refundTxSigningResult.signatureShares,
3356
+ statechainPublicKeys: treeResp.rootNodeSignatureShares.refundTxSigningResult.publicKeys,
3357
+ verifyingKey: treeResp.rootNodeSignatureShares.verifyingKey,
3358
+ statechainCommitments: treeResp.rootNodeSignatureShares.refundTxSigningResult.signingNonceCommitments,
3359
+ selfCommitment: refundNonceCommitment,
3360
+ publicKey: signingPubKey,
3361
+ selfSignature: refundSignature,
3362
+ adaptorPubKey: new Uint8Array()
3363
+ });
3364
+ let finalizeResp;
3365
+ try {
3366
+ finalizeResp = await sparkClient.finalize_node_signatures({
3367
+ intent: 0 /* CREATION */,
3368
+ nodeSignatures: [
3369
+ {
3370
+ nodeId: treeResp.rootNodeSignatureShares.nodeId,
3371
+ nodeTxSignature: rootAggregate,
3372
+ refundTxSignature: refundAggregate
3373
+ }
3374
+ ]
3375
+ });
3376
+ } catch (error) {
3377
+ throw new NetworkError(
3378
+ "Failed to finalize node signatures",
3379
+ {
3380
+ operation: "finalize_node_signatures",
3381
+ errorCount: 1,
3382
+ errors: error instanceof Error ? error.message : String(error)
3383
+ },
3384
+ error
3385
+ );
3386
+ }
3387
+ return finalizeResp;
3388
+ }
3389
+ };
3390
+
3391
+ // src/tests/utils/test-faucet.ts
3392
+ import { bytesToHex as bytesToHex5, hexToBytes as hexToBytes4 } from "@noble/curves/abstract/utils";
3393
+ import { schnorr as schnorr5, secp256k1 as secp256k18 } from "@noble/curves/secp256k1";
3394
+ import * as btc4 from "@scure/btc-signer";
3395
+ import { Address as Address3, OutScript as OutScript3, SigHash as SigHash2, Transaction as Transaction4 } from "@scure/btc-signer";
3396
+ import { taprootTweakPrivKey as taprootTweakPrivKey2 } from "@scure/btc-signer/utils";
3397
+ var STATIC_FAUCET_KEY = hexToBytes4(
3398
+ "deadbeef1337cafe4242424242424242deadbeef1337cafe4242424242424242"
3399
+ );
3400
+ var STATIC_MINING_KEY = hexToBytes4(
3401
+ "1337cafe4242deadbeef4242424242421337cafe4242deadbeef424242424242"
3402
+ );
3403
+ var SATS_PER_BTC = 1e8;
3404
+ var COIN_AMOUNT = 10000000n;
3405
+ var FEE_AMOUNT = 1000n;
3406
+ var TARGET_NUM_COINS = 20;
3407
+ var BitcoinFaucet = class _BitcoinFaucet {
3408
+ constructor(url = "http://127.0.0.1:8332", username = "testutil", password = "testutilpassword") {
3409
+ this.url = url;
3410
+ this.username = username;
3411
+ this.password = password;
3412
+ this.miningAddress = getP2TRAddressFromPublicKey(
3413
+ secp256k18.getPublicKey(STATIC_MINING_KEY),
3414
+ 4 /* LOCAL */
3415
+ );
3416
+ }
3417
+ coins = [];
3418
+ static instance = null;
3419
+ miningAddress;
3420
+ lock = Promise.resolve();
3421
+ static getInstance(url = "http://127.0.0.1:8332", username = "testutil", password = "testutilpassword") {
3422
+ if (!_BitcoinFaucet.instance) {
3423
+ _BitcoinFaucet.instance = new _BitcoinFaucet(url, username, password);
3424
+ }
3425
+ return _BitcoinFaucet.instance;
3426
+ }
3427
+ async withLock(operation) {
3428
+ const current = this.lock;
3429
+ let resolve;
3430
+ this.lock = new Promise((r) => resolve = r);
3431
+ await current;
3432
+ try {
3433
+ return await operation();
3434
+ } finally {
3435
+ resolve();
3436
+ }
3437
+ }
3438
+ async fund() {
3439
+ return this.withLock(async () => {
3440
+ if (this.coins.length === 0) {
3441
+ await this.refill();
3442
+ }
3443
+ const coin = this.coins[0];
3444
+ if (!coin) {
3445
+ throw new Error("Failed to get coin from faucet");
3446
+ }
3447
+ this.coins = this.coins.slice(1);
3448
+ return coin;
3449
+ });
3450
+ }
3451
+ async refill() {
3452
+ const minerPubKey = secp256k18.getPublicKey(STATIC_MINING_KEY);
3453
+ const address2 = getP2TRAddressFromPublicKey(minerPubKey, 4 /* LOCAL */);
3454
+ const scanResult = await this.call("scantxoutset", [
3455
+ "start",
3456
+ [`addr(${address2})`]
3457
+ ]);
3458
+ let selectedUtxo;
3459
+ let selectedUtxoAmountSats;
3460
+ if (!scanResult.success || scanResult.unspents.length === 0) {
3461
+ const blockHash = await this.generateToAddress(1, address2);
3462
+ const block = await this.getBlock(blockHash[0]);
3463
+ const fundingTx = Transaction4.fromRaw(hexToBytes4(block.tx[0].hex), {
3464
+ allowUnknownOutputs: true
3465
+ });
3466
+ await this.generateToAddress(100, this.miningAddress);
3467
+ selectedUtxo = {
3468
+ txid: block.tx[0].txid,
3469
+ vout: 0,
3470
+ amount: fundingTx.getOutput(0).amount
3471
+ // Already in sats
3472
+ };
3473
+ selectedUtxoAmountSats = BigInt(selectedUtxo.amount);
3474
+ } else {
3475
+ selectedUtxo = scanResult.unspents.find((utxo) => {
3476
+ const isValueEnough = BigInt(Math.floor(utxo.amount * SATS_PER_BTC)) >= COIN_AMOUNT + FEE_AMOUNT;
3477
+ const isMature = scanResult.height - utxo.height >= 100;
3478
+ return isValueEnough && isMature;
3479
+ });
3480
+ if (!selectedUtxo) {
3481
+ throw new Error("No UTXO large enough to create even one faucet coin");
3482
+ }
3483
+ selectedUtxoAmountSats = BigInt(
3484
+ Math.floor(selectedUtxo.amount * SATS_PER_BTC)
3485
+ );
3486
+ }
3487
+ const maxPossibleCoins = Number(
3488
+ (selectedUtxoAmountSats - FEE_AMOUNT) / COIN_AMOUNT
3489
+ );
3490
+ const numCoinsToCreate = Math.min(maxPossibleCoins, TARGET_NUM_COINS);
3491
+ if (numCoinsToCreate < 1) {
3492
+ throw new Error(
3493
+ `Selected UTXO (${selectedUtxoAmountSats} sats) is too small to create even one faucet coin of ${COIN_AMOUNT} sats`
3494
+ );
3495
+ }
3496
+ const splitTx = new Transaction4();
3497
+ splitTx.addInput({
3498
+ txid: selectedUtxo.txid,
3499
+ index: selectedUtxo.vout
3500
+ });
3501
+ const faucetPubKey = secp256k18.getPublicKey(STATIC_FAUCET_KEY);
3502
+ const script = getP2TRScriptFromPublicKey(faucetPubKey, 4 /* LOCAL */);
3503
+ for (let i = 0; i < numCoinsToCreate; i++) {
3504
+ splitTx.addOutput({
3505
+ script,
3506
+ amount: COIN_AMOUNT
3507
+ });
3508
+ }
3509
+ const remainingValue = selectedUtxoAmountSats - COIN_AMOUNT * BigInt(numCoinsToCreate) - FEE_AMOUNT;
3510
+ const minerScript = getP2TRScriptFromPublicKey(minerPubKey, 4 /* LOCAL */);
3511
+ if (remainingValue > 0n) {
3512
+ splitTx.addOutput({
3513
+ script: minerScript,
3514
+ amount: remainingValue
3515
+ });
3516
+ }
3517
+ const signedSplitTx = await this.signFaucetCoin(
3518
+ splitTx,
3519
+ {
3520
+ amount: selectedUtxoAmountSats,
3521
+ script: minerScript
3522
+ },
3523
+ STATIC_MINING_KEY
3524
+ );
3525
+ await this.broadcastTx(bytesToHex5(signedSplitTx.extract()));
3526
+ const splitTxId = signedSplitTx.id;
3527
+ for (let i = 0; i < numCoinsToCreate; i++) {
3528
+ this.coins.push({
3529
+ key: STATIC_FAUCET_KEY,
3530
+ outpoint: {
3531
+ txid: hexToBytes4(splitTxId),
3532
+ index: i
3533
+ },
3534
+ txout: signedSplitTx.getOutput(i)
3535
+ });
3536
+ }
3537
+ }
3538
+ async sendFaucetCoinToP2WPKHAddress(pubKey) {
3539
+ const sendToPubKeyTx = new Transaction4();
3540
+ const p2wpkhAddress = btc4.p2wpkh(pubKey, getNetwork(4 /* LOCAL */)).address;
3541
+ if (!p2wpkhAddress) {
3542
+ throw new Error("Invalid P2WPKH address");
3543
+ }
3544
+ const coinToSend = await this.fund();
3545
+ if (!coinToSend) {
3546
+ throw new Error("No coins available");
3547
+ }
3548
+ sendToPubKeyTx.addInput(coinToSend.outpoint);
3549
+ sendToPubKeyTx.addOutputAddress(
3550
+ p2wpkhAddress,
3551
+ COIN_AMOUNT - FEE_AMOUNT,
3552
+ getNetwork(4 /* LOCAL */)
3553
+ );
3554
+ const signedTx = await this.signFaucetCoin(
3555
+ sendToPubKeyTx,
3556
+ coinToSend.txout,
3557
+ coinToSend.key
3558
+ );
3559
+ await this.broadcastTx(bytesToHex5(signedTx.extract()));
3560
+ }
3561
+ async signFaucetCoin(unsignedTx, fundingTxOut, key) {
3562
+ const pubKey = secp256k18.getPublicKey(key);
3563
+ const internalKey = pubKey.slice(1);
3564
+ const script = getP2TRScriptFromPublicKey(pubKey, 4 /* LOCAL */);
3565
+ unsignedTx.updateInput(0, {
3566
+ tapInternalKey: internalKey,
3567
+ witnessUtxo: {
3568
+ script,
3569
+ amount: fundingTxOut.amount
3570
+ }
3571
+ });
3572
+ const sighash = unsignedTx.preimageWitnessV1(
3573
+ 0,
3574
+ new Array(unsignedTx.inputsLength).fill(script),
3575
+ SigHash2.DEFAULT,
3576
+ new Array(unsignedTx.inputsLength).fill(fundingTxOut.amount)
3577
+ );
3578
+ const merkleRoot = new Uint8Array();
3579
+ const tweakedKey = taprootTweakPrivKey2(key, merkleRoot);
3580
+ if (!tweakedKey)
3581
+ throw new Error("Invalid private key for taproot tweaking");
3582
+ const signature = schnorr5.sign(sighash, tweakedKey);
3583
+ unsignedTx.updateInput(0, {
3584
+ tapKeySig: signature
3585
+ });
3586
+ unsignedTx.finalize();
3587
+ return unsignedTx;
3588
+ }
3589
+ // MineBlocks mines the specified number of blocks to a random address
3590
+ // and returns the block hashes.
3591
+ async mineBlocks(numBlocks) {
3592
+ return await this.generateToAddress(numBlocks, this.miningAddress);
3593
+ }
3594
+ async call(method, params) {
3595
+ try {
3596
+ const response = await fetch(this.url, {
3597
+ method: "POST",
3598
+ headers: {
3599
+ "Content-Type": "application/json",
3600
+ Authorization: "Basic " + btoa(`${this.username}:${this.password}`)
3601
+ },
3602
+ body: JSON.stringify({
3603
+ jsonrpc: "1.0",
3604
+ id: "spark-js",
3605
+ method,
3606
+ params
3607
+ })
3608
+ });
3609
+ const data = await response.json();
3610
+ if (data.error) {
3611
+ console.error(`RPC Error for method ${method}:`, data.error);
3612
+ throw new RPCError(`Bitcoin RPC error: ${data.error.message}`, {
3613
+ method,
3614
+ params,
3615
+ code: data.error.code
3616
+ });
3617
+ }
3618
+ return data.result;
3619
+ } catch (error) {
3620
+ if (error instanceof RPCError) {
3621
+ throw error;
3622
+ }
3623
+ throw new RPCError(
3624
+ "Failed to call Bitcoin RPC",
3625
+ {
3626
+ method,
3627
+ params
3628
+ },
3629
+ error
3630
+ );
3631
+ }
3632
+ }
3633
+ async generateToAddress(numBlocks, address2) {
3634
+ return await this.call("generatetoaddress", [numBlocks, address2]);
3635
+ }
3636
+ async getBlock(blockHash) {
3637
+ return await this.call("getblock", [blockHash, 2]);
3638
+ }
3639
+ async broadcastTx(txHex) {
3640
+ let response = await this.call("sendrawtransaction", [txHex, 0]);
3641
+ return response;
3642
+ }
3643
+ async getNewAddress() {
3644
+ const key = secp256k18.utils.randomPrivateKey();
3645
+ const pubKey = secp256k18.getPublicKey(key);
3646
+ return getP2TRAddressFromPublicKey(pubKey, 4 /* LOCAL */);
3647
+ }
3648
+ async sendToAddress(address2, amount) {
3649
+ const coin = await this.fund();
3650
+ if (!coin) {
3651
+ throw new Error("No coins available");
3652
+ }
3653
+ const tx = new Transaction4();
3654
+ tx.addInput(coin.outpoint);
3655
+ const availableAmount = COIN_AMOUNT - FEE_AMOUNT;
3656
+ const destinationAddress = Address3(getNetwork(4 /* LOCAL */)).decode(
3657
+ address2
3658
+ );
3659
+ const destinationScript = OutScript3.encode(destinationAddress);
3660
+ tx.addOutput({
3661
+ script: destinationScript,
3662
+ amount
3663
+ });
3664
+ const changeAmount = availableAmount - amount;
3665
+ if (changeAmount > 0) {
3666
+ const changeKey = secp256k18.utils.randomPrivateKey();
3667
+ const changePubKey = secp256k18.getPublicKey(changeKey);
3668
+ const changeScript = getP2TRScriptFromPublicKey(
3669
+ changePubKey,
3670
+ 4 /* LOCAL */
3671
+ );
3672
+ tx.addOutput({
3673
+ script: changeScript,
3674
+ amount: changeAmount
3675
+ });
3676
+ }
3677
+ const signedTx = await this.signFaucetCoin(tx, coin.txout, coin.key);
3678
+ const txHex = bytesToHex5(signedTx.extract());
3679
+ await this.broadcastTx(txHex);
3680
+ const randomKey = secp256k18.utils.randomPrivateKey();
3681
+ const randomPubKey = secp256k18.getPublicKey(randomKey);
3682
+ const randomAddress = getP2TRAddressFromPublicKey(
3683
+ randomPubKey,
3684
+ 4 /* LOCAL */
3685
+ );
3686
+ await this.generateToAddress(1, randomAddress);
3687
+ return signedTx;
3688
+ }
3689
+ async getRawTransaction(txid) {
3690
+ return await this.call("getrawtransaction", [txid, 2]);
3691
+ }
3692
+ };
3693
+
3694
+ export {
3695
+ getCrypto,
3696
+ setCrypto,
3697
+ SparkSDKError,
3698
+ NetworkError,
3699
+ ValidationError,
3700
+ InternalValidationError,
3701
+ AuthenticationError,
3702
+ RPCError,
3703
+ ConfigurationError,
3704
+ NotImplementedError,
3705
+ generateSignatureFromExistingAdaptor,
3706
+ generateAdaptorFromSignature,
3707
+ validateOutboundAdaptorSignature,
3708
+ applyAdaptorToSignature,
3709
+ Network2 as Network,
3710
+ NetworkToProto,
3711
+ protoToNetwork,
3712
+ getNetwork,
3713
+ LRC_WALLET_NETWORK,
3714
+ LRC_WALLET_NETWORK_TYPE,
3715
+ getNetworkFromAddress,
3716
+ getNetworkFromString,
3717
+ computeTaprootKeyNoScript,
3718
+ getP2TRScriptFromPublicKey,
3719
+ getP2TRAddressFromPublicKey,
3720
+ getP2TRAddressFromPkScript,
3721
+ getP2WPKHAddressFromPublicKey,
3722
+ getTxFromRawTxHex,
3723
+ getTxFromRawTxBytes,
3724
+ getSigHashFromTx,
3725
+ getTxId,
3726
+ getTxIdNoReverse,
3727
+ addPublicKeys,
3728
+ applyAdditiveTweakToPublicKey,
3729
+ subtractPublicKeys,
3730
+ addPrivateKeys,
3731
+ subtractPrivateKeys,
3732
+ sumOfPrivateKeys,
3733
+ lastKeyWithTarget,
3734
+ ELECTRS_CREDENTIALS,
3735
+ getElectrsUrl,
3736
+ WalletConfig,
3737
+ proofOfPossessionMessageHashForDepositAddress,
3738
+ getRandomBigInt,
3739
+ modInverse,
3740
+ evaluatePolynomial,
3741
+ fieldDiv,
3742
+ computerLagrangeCoefficients,
3743
+ generatePolynomialForSecretSharing,
3744
+ splitSecret,
3745
+ splitSecretWithProofs,
3746
+ recoverSecret,
3747
+ validateShare,
3748
+ bigIntToPrivateKey,
3749
+ getRandomSigningNonce,
3750
+ createSigningNonce,
3751
+ getSigningCommitmentFromNonce,
3752
+ encodeSigningNonceToBytes,
3753
+ decodeBytesToSigningNonce,
3754
+ createSigningCommitment,
3755
+ encodeSigningCommitmentToBytes,
3756
+ decodeBytesToSigningCommitment,
3757
+ DEFAULT_FEE_SATS,
3758
+ maybeApplyFee,
3759
+ createRefundTx,
3760
+ getCurrentTimelock,
3761
+ getTransactionSequence,
3762
+ checkIfValidSequence,
3763
+ getNextTransactionSequence,
3764
+ getEphemeralAnchorOutput,
3765
+ isReactNative,
3766
+ TaprootOutputKeysGenerator,
3767
+ DefaultSparkSigner,
3768
+ TaprootSparkSigner,
3769
+ WalletConfigService,
3770
+ ConnectionManager,
3771
+ DepositService,
3772
+ BitcoinFaucet
3773
+ };