@buildonspark/spark-sdk 0.1.43 → 0.1.45

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 (153) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/{RequestLightningSendInput-D7fZdT4A.d.ts → RequestLightningSendInput-DEPd_fPO.d.ts} +43 -4
  3. package/dist/{RequestLightningSendInput-Na1mHdWg.d.cts → RequestLightningSendInput-Du0z7Om7.d.cts} +43 -4
  4. package/dist/address/index.cjs +2 -2
  5. package/dist/address/index.d.cts +2 -2
  6. package/dist/address/index.d.ts +2 -2
  7. package/dist/address/index.js +2 -2
  8. package/dist/{chunk-IRW5TWMH.js → chunk-5FUB65LX.js} +7 -9
  9. package/dist/{chunk-BUTZWYBW.js → chunk-6264CGDM.js} +4 -4
  10. package/dist/{chunk-VFJQNBFX.js → chunk-7V6N75CC.js} +5 -2
  11. package/dist/{chunk-M6A4KFIG.js → chunk-BGGEVUJK.js} +1505 -445
  12. package/dist/{chunk-DQYKQJRZ.js → chunk-C2S227QR.js} +675 -52
  13. package/dist/{chunk-GYQR4B4P.js → chunk-GZ5IPPJ2.js} +2 -2
  14. package/dist/{chunk-6AFUC5M2.js → chunk-HWJWKEIU.js} +8 -2
  15. package/dist/{chunk-TOSP3INR.js → chunk-I54FARY2.js} +4 -2
  16. package/dist/{chunk-WWOTVNPP.js → chunk-J2IE4Z7Y.js} +544 -431
  17. package/dist/{chunk-O4RYNJNB.js → chunk-KMUMFYFX.js} +3 -3
  18. package/dist/chunk-LHRD2WT6.js +2374 -0
  19. package/dist/{chunk-ABZA6R5S.js → chunk-NTFKFRQ2.js} +1 -1
  20. package/dist/{chunk-MIVX3GHD.js → chunk-OBFKIEMP.js} +1 -1
  21. package/dist/{chunk-HRQRRDSS.js → chunk-PQN3C2MF.js} +15 -15
  22. package/dist/{chunk-DOA6QXYQ.js → chunk-R5PXJZQS.js} +3 -1
  23. package/dist/{chunk-TIUBYNN5.js → chunk-YUPMXTCJ.js} +4 -4
  24. package/dist/graphql/objects/index.d.cts +6 -43
  25. package/dist/graphql/objects/index.d.ts +6 -43
  26. package/dist/graphql/objects/index.js +1 -1
  27. package/dist/index-B2AwKW5J.d.cts +214 -0
  28. package/dist/index-CJDi1HWc.d.ts +214 -0
  29. package/dist/index.cjs +4150 -1026
  30. package/dist/index.d.cts +764 -19
  31. package/dist/index.d.ts +764 -19
  32. package/dist/index.js +17 -21
  33. package/dist/index.node.cjs +4153 -1033
  34. package/dist/index.node.d.cts +10 -8
  35. package/dist/index.node.d.ts +10 -8
  36. package/dist/index.node.js +20 -28
  37. package/dist/native/index.cjs +4166 -1042
  38. package/dist/native/index.d.cts +369 -108
  39. package/dist/native/index.d.ts +369 -108
  40. package/dist/native/index.js +4138 -1015
  41. package/dist/{network-xkBSpaTn.d.ts → network-BTJl-Sul.d.ts} +1 -1
  42. package/dist/{network-D5lKssVl.d.cts → network-CqgsdUF2.d.cts} +1 -1
  43. package/dist/proto/lrc20.cjs +222 -19
  44. package/dist/proto/lrc20.d.cts +1 -1
  45. package/dist/proto/lrc20.d.ts +1 -1
  46. package/dist/proto/lrc20.js +2 -2
  47. package/dist/proto/spark.cjs +1502 -442
  48. package/dist/proto/spark.d.cts +1 -1
  49. package/dist/proto/spark.d.ts +1 -1
  50. package/dist/proto/spark.js +5 -5
  51. package/dist/proto/spark_token.cjs +1515 -56
  52. package/dist/proto/spark_token.d.cts +153 -15
  53. package/dist/proto/spark_token.d.ts +153 -15
  54. package/dist/proto/spark_token.js +40 -4
  55. package/dist/{sdk-types-B-q9py_P.d.cts → sdk-types-B0SwjolI.d.cts} +1 -1
  56. package/dist/{sdk-types-BPoPgzda.d.ts → sdk-types-Cc4l4kb1.d.ts} +1 -1
  57. package/dist/services/config.cjs +7 -3
  58. package/dist/services/config.d.cts +5 -4
  59. package/dist/services/config.d.ts +5 -4
  60. package/dist/services/config.js +6 -6
  61. package/dist/services/connection.cjs +2938 -646
  62. package/dist/services/connection.d.cts +5 -4
  63. package/dist/services/connection.d.ts +5 -4
  64. package/dist/services/connection.js +4 -4
  65. package/dist/services/index.cjs +6381 -3461
  66. package/dist/services/index.d.cts +7 -6
  67. package/dist/services/index.d.ts +7 -6
  68. package/dist/services/index.js +15 -13
  69. package/dist/services/lrc-connection.cjs +227 -21
  70. package/dist/services/lrc-connection.d.cts +5 -4
  71. package/dist/services/lrc-connection.d.ts +5 -4
  72. package/dist/services/lrc-connection.js +4 -4
  73. package/dist/services/token-transactions.cjs +868 -244
  74. package/dist/services/token-transactions.d.cts +25 -7
  75. package/dist/services/token-transactions.d.ts +25 -7
  76. package/dist/services/token-transactions.js +5 -4
  77. package/dist/services/wallet-config.cjs +4 -1
  78. package/dist/services/wallet-config.d.cts +7 -5
  79. package/dist/services/wallet-config.d.ts +7 -5
  80. package/dist/services/wallet-config.js +3 -1
  81. package/dist/signer/signer.cjs +5 -2
  82. package/dist/signer/signer.d.cts +3 -2
  83. package/dist/signer/signer.d.ts +3 -2
  84. package/dist/signer/signer.js +2 -2
  85. package/dist/{signer-wqesWifN.d.ts → signer-BocS_J6B.d.ts} +2 -6
  86. package/dist/{signer-IO3oMRNj.d.cts → signer-DKS0AJkw.d.cts} +2 -6
  87. package/dist/{spark-CDm4gqS6.d.cts → spark-dM7EYXYQ.d.cts} +138 -42
  88. package/dist/{spark-CDm4gqS6.d.ts → spark-dM7EYXYQ.d.ts} +138 -42
  89. package/dist/spark_bindings/native/index.cjs +183 -0
  90. package/dist/spark_bindings/native/index.d.cts +14 -0
  91. package/dist/spark_bindings/native/index.d.ts +14 -0
  92. package/dist/spark_bindings/native/index.js +141 -0
  93. package/dist/spark_bindings/wasm/index.cjs +1093 -0
  94. package/dist/spark_bindings/wasm/index.d.cts +47 -0
  95. package/dist/spark_bindings/wasm/index.d.ts +47 -0
  96. package/dist/{chunk-K4C4W5FC.js → spark_bindings/wasm/index.js} +7 -6
  97. package/dist/types/index.cjs +1503 -443
  98. package/dist/types/index.d.cts +6 -5
  99. package/dist/types/index.d.ts +6 -5
  100. package/dist/types/index.js +3 -3
  101. package/dist/types-C-Rp0Oo7.d.cts +46 -0
  102. package/dist/types-C-Rp0Oo7.d.ts +46 -0
  103. package/dist/utils/index.cjs +358 -36
  104. package/dist/utils/index.d.cts +14 -134
  105. package/dist/utils/index.d.ts +14 -134
  106. package/dist/utils/index.js +8 -8
  107. package/package.json +21 -1
  108. package/src/constants.ts +5 -1
  109. package/src/graphql/client.ts +28 -0
  110. package/src/graphql/mutations/RequestCoopExit.ts +6 -0
  111. package/src/graphql/mutations/RequestSwapLeaves.ts +2 -0
  112. package/src/graphql/queries/GetCoopExitFeeQuote.ts +20 -0
  113. package/src/index.node.ts +0 -1
  114. package/src/index.ts +0 -1
  115. package/src/native/index.ts +1 -2
  116. package/src/proto/common.ts +5 -5
  117. package/src/proto/google/protobuf/descriptor.ts +34 -34
  118. package/src/proto/google/protobuf/duration.ts +2 -2
  119. package/src/proto/google/protobuf/empty.ts +2 -2
  120. package/src/proto/google/protobuf/timestamp.ts +2 -2
  121. package/src/proto/mock.ts +4 -4
  122. package/src/proto/spark.ts +1924 -525
  123. package/src/proto/spark_authn.ts +7 -7
  124. package/src/proto/spark_token.ts +1668 -105
  125. package/src/proto/validate/validate.ts +24 -24
  126. package/src/services/bolt11-spark.ts +62 -187
  127. package/src/services/coop-exit.ts +3 -0
  128. package/src/services/lrc20.ts +1 -1
  129. package/src/services/token-transactions.ts +209 -9
  130. package/src/services/transfer.ts +22 -3
  131. package/src/services/tree-creation.ts +13 -0
  132. package/src/services/wallet-config.ts +2 -1
  133. package/src/spark-wallet/spark-wallet.node.ts +3 -7
  134. package/src/spark-wallet/spark-wallet.ts +376 -232
  135. package/src/spark-wallet/types.ts +39 -3
  136. package/src/tests/bolt11-spark.test.ts +7 -15
  137. package/src/tests/integration/deposit.test.ts +16 -0
  138. package/src/tests/integration/ssp/coop-exit.test.ts +85 -21
  139. package/src/tests/integration/ssp/swap.test.ts +47 -0
  140. package/src/tests/integration/swap.test.ts +453 -433
  141. package/src/tests/integration/transfer.test.ts +261 -248
  142. package/src/tests/token-identifier.test.ts +54 -0
  143. package/src/tests/tokens.test.ts +218 -22
  144. package/src/utils/token-hashing.ts +346 -52
  145. package/src/utils/token-identifier.ts +88 -0
  146. package/src/utils/token-transaction-validation.ts +350 -5
  147. package/src/utils/token-transactions.ts +12 -8
  148. package/src/utils/transaction.ts +2 -8
  149. package/dist/chunk-VA7MV4MZ.js +0 -1073
  150. package/dist/index-7RYRH5wc.d.ts +0 -815
  151. package/dist/index-BJOc8Ur-.d.cts +0 -815
  152. package/dist/wasm-7OWFHDMS.js +0 -21
  153. package/src/logger.ts +0 -3
@@ -142,6 +142,215 @@ var InternalValidationError = class extends SparkSDKError {
142
142
  }
143
143
  };
144
144
 
145
+ // src/proto/spark_token.ts
146
+ var import_wire5 = require("@bufbuild/protobuf/wire");
147
+
148
+ // src/proto/google/protobuf/timestamp.ts
149
+ var import_wire = require("@bufbuild/protobuf/wire");
150
+
151
+ // src/proto/spark.ts
152
+ var import_wire4 = require("@bufbuild/protobuf/wire");
153
+
154
+ // src/proto/common.ts
155
+ var import_wire2 = require("@bufbuild/protobuf/wire");
156
+
157
+ // src/proto/google/protobuf/empty.ts
158
+ var import_wire3 = require("@bufbuild/protobuf/wire");
159
+
160
+ // src/proto/spark.ts
161
+ function createBaseSparkAddress() {
162
+ return { identityPublicKey: new Uint8Array(0), paymentIntentFields: void 0 };
163
+ }
164
+ var SparkAddress = {
165
+ encode(message, writer = new import_wire4.BinaryWriter()) {
166
+ if (message.identityPublicKey.length !== 0) {
167
+ writer.uint32(10).bytes(message.identityPublicKey);
168
+ }
169
+ if (message.paymentIntentFields !== void 0) {
170
+ PaymentIntentFields.encode(message.paymentIntentFields, writer.uint32(18).fork()).join();
171
+ }
172
+ return writer;
173
+ },
174
+ decode(input, length) {
175
+ const reader = input instanceof import_wire4.BinaryReader ? input : new import_wire4.BinaryReader(input);
176
+ const end = length === void 0 ? reader.len : reader.pos + length;
177
+ const message = createBaseSparkAddress();
178
+ while (reader.pos < end) {
179
+ const tag = reader.uint32();
180
+ switch (tag >>> 3) {
181
+ case 1: {
182
+ if (tag !== 10) {
183
+ break;
184
+ }
185
+ message.identityPublicKey = reader.bytes();
186
+ continue;
187
+ }
188
+ case 2: {
189
+ if (tag !== 18) {
190
+ break;
191
+ }
192
+ message.paymentIntentFields = PaymentIntentFields.decode(reader, reader.uint32());
193
+ continue;
194
+ }
195
+ }
196
+ if ((tag & 7) === 4 || tag === 0) {
197
+ break;
198
+ }
199
+ reader.skip(tag & 7);
200
+ }
201
+ return message;
202
+ },
203
+ fromJSON(object) {
204
+ return {
205
+ identityPublicKey: isSet(object.identityPublicKey) ? bytesFromBase64(object.identityPublicKey) : new Uint8Array(0),
206
+ paymentIntentFields: isSet(object.paymentIntentFields) ? PaymentIntentFields.fromJSON(object.paymentIntentFields) : void 0
207
+ };
208
+ },
209
+ toJSON(message) {
210
+ const obj = {};
211
+ if (message.identityPublicKey.length !== 0) {
212
+ obj.identityPublicKey = base64FromBytes(message.identityPublicKey);
213
+ }
214
+ if (message.paymentIntentFields !== void 0) {
215
+ obj.paymentIntentFields = PaymentIntentFields.toJSON(message.paymentIntentFields);
216
+ }
217
+ return obj;
218
+ },
219
+ create(base) {
220
+ return SparkAddress.fromPartial(base ?? {});
221
+ },
222
+ fromPartial(object) {
223
+ const message = createBaseSparkAddress();
224
+ message.identityPublicKey = object.identityPublicKey ?? new Uint8Array(0);
225
+ message.paymentIntentFields = object.paymentIntentFields !== void 0 && object.paymentIntentFields !== null ? PaymentIntentFields.fromPartial(object.paymentIntentFields) : void 0;
226
+ return message;
227
+ }
228
+ };
229
+ function createBasePaymentIntentFields() {
230
+ return { id: new Uint8Array(0), assetIdentifier: void 0, assetAmount: new Uint8Array(0), memo: void 0 };
231
+ }
232
+ var PaymentIntentFields = {
233
+ encode(message, writer = new import_wire4.BinaryWriter()) {
234
+ if (message.id.length !== 0) {
235
+ writer.uint32(10).bytes(message.id);
236
+ }
237
+ if (message.assetIdentifier !== void 0) {
238
+ writer.uint32(18).bytes(message.assetIdentifier);
239
+ }
240
+ if (message.assetAmount.length !== 0) {
241
+ writer.uint32(26).bytes(message.assetAmount);
242
+ }
243
+ if (message.memo !== void 0) {
244
+ writer.uint32(34).string(message.memo);
245
+ }
246
+ return writer;
247
+ },
248
+ decode(input, length) {
249
+ const reader = input instanceof import_wire4.BinaryReader ? input : new import_wire4.BinaryReader(input);
250
+ const end = length === void 0 ? reader.len : reader.pos + length;
251
+ const message = createBasePaymentIntentFields();
252
+ while (reader.pos < end) {
253
+ const tag = reader.uint32();
254
+ switch (tag >>> 3) {
255
+ case 1: {
256
+ if (tag !== 10) {
257
+ break;
258
+ }
259
+ message.id = reader.bytes();
260
+ continue;
261
+ }
262
+ case 2: {
263
+ if (tag !== 18) {
264
+ break;
265
+ }
266
+ message.assetIdentifier = reader.bytes();
267
+ continue;
268
+ }
269
+ case 3: {
270
+ if (tag !== 26) {
271
+ break;
272
+ }
273
+ message.assetAmount = reader.bytes();
274
+ continue;
275
+ }
276
+ case 4: {
277
+ if (tag !== 34) {
278
+ break;
279
+ }
280
+ message.memo = reader.string();
281
+ continue;
282
+ }
283
+ }
284
+ if ((tag & 7) === 4 || tag === 0) {
285
+ break;
286
+ }
287
+ reader.skip(tag & 7);
288
+ }
289
+ return message;
290
+ },
291
+ fromJSON(object) {
292
+ return {
293
+ id: isSet(object.id) ? bytesFromBase64(object.id) : new Uint8Array(0),
294
+ assetIdentifier: isSet(object.assetIdentifier) ? bytesFromBase64(object.assetIdentifier) : void 0,
295
+ assetAmount: isSet(object.assetAmount) ? bytesFromBase64(object.assetAmount) : new Uint8Array(0),
296
+ memo: isSet(object.memo) ? globalThis.String(object.memo) : void 0
297
+ };
298
+ },
299
+ toJSON(message) {
300
+ const obj = {};
301
+ if (message.id.length !== 0) {
302
+ obj.id = base64FromBytes(message.id);
303
+ }
304
+ if (message.assetIdentifier !== void 0) {
305
+ obj.assetIdentifier = base64FromBytes(message.assetIdentifier);
306
+ }
307
+ if (message.assetAmount.length !== 0) {
308
+ obj.assetAmount = base64FromBytes(message.assetAmount);
309
+ }
310
+ if (message.memo !== void 0) {
311
+ obj.memo = message.memo;
312
+ }
313
+ return obj;
314
+ },
315
+ create(base) {
316
+ return PaymentIntentFields.fromPartial(base ?? {});
317
+ },
318
+ fromPartial(object) {
319
+ const message = createBasePaymentIntentFields();
320
+ message.id = object.id ?? new Uint8Array(0);
321
+ message.assetIdentifier = object.assetIdentifier ?? void 0;
322
+ message.assetAmount = object.assetAmount ?? new Uint8Array(0);
323
+ message.memo = object.memo ?? void 0;
324
+ return message;
325
+ }
326
+ };
327
+ function bytesFromBase64(b64) {
328
+ if (globalThis.Buffer) {
329
+ return Uint8Array.from(globalThis.Buffer.from(b64, "base64"));
330
+ } else {
331
+ const bin = globalThis.atob(b64);
332
+ const arr = new Uint8Array(bin.length);
333
+ for (let i = 0; i < bin.length; ++i) {
334
+ arr[i] = bin.charCodeAt(i);
335
+ }
336
+ return arr;
337
+ }
338
+ }
339
+ function base64FromBytes(arr) {
340
+ if (globalThis.Buffer) {
341
+ return globalThis.Buffer.from(arr).toString("base64");
342
+ } else {
343
+ const bin = [];
344
+ arr.forEach((byte) => {
345
+ bin.push(globalThis.String.fromCharCode(byte));
346
+ });
347
+ return globalThis.btoa(bin.join(""));
348
+ }
349
+ }
350
+ function isSet(value) {
351
+ return value !== null && value !== void 0;
352
+ }
353
+
145
354
  // src/utils/token-hashing.ts
146
355
  function hashTokenTransaction(tokenTransaction, partialHash = false) {
147
356
  switch (tokenTransaction.version) {
@@ -224,13 +433,21 @@ function hashTokenTransactionV0(tokenTransaction, partialHash = false) {
224
433
  });
225
434
  }
226
435
  hashObj2.update(issuerPubKey);
227
- if (tokenTransaction.tokenInputs.mintInput.issuerProvidedTimestamp != 0) {
436
+ let timestampValue = 0;
437
+ const mintInput = tokenTransaction.tokenInputs.mintInput;
438
+ if ("issuerProvidedTimestamp" in mintInput) {
439
+ const v0MintInput = mintInput;
440
+ if (v0MintInput.issuerProvidedTimestamp != 0) {
441
+ timestampValue = v0MintInput.issuerProvidedTimestamp;
442
+ }
443
+ } else if ("clientCreatedTimestamp" in tokenTransaction && tokenTransaction.clientCreatedTimestamp) {
444
+ timestampValue = tokenTransaction.clientCreatedTimestamp.getTime();
445
+ }
446
+ if (timestampValue != 0) {
228
447
  const timestampBytes = new Uint8Array(8);
229
448
  new DataView(timestampBytes.buffer).setBigUint64(
230
449
  0,
231
- BigInt(
232
- tokenTransaction.tokenInputs.mintInput.issuerProvidedTimestamp
233
- ),
450
+ BigInt(timestampValue),
234
451
  true
235
452
  // true for little-endian to match Go implementation
236
453
  );
@@ -239,12 +456,95 @@ function hashTokenTransactionV0(tokenTransaction, partialHash = false) {
239
456
  allHashes.push(hashObj2.digest());
240
457
  }
241
458
  }
459
+ if (tokenTransaction.tokenInputs?.$case === "createInput") {
460
+ const issuerPubKeyHashObj = import_sha2.sha256.create();
461
+ const createInput = tokenTransaction.tokenInputs.createInput;
462
+ if (!createInput.issuerPublicKey || createInput.issuerPublicKey.length === 0) {
463
+ throw new ValidationError("issuer public key cannot be nil or empty", {
464
+ field: "tokenInputs.createInput.issuerPublicKey"
465
+ });
466
+ }
467
+ issuerPubKeyHashObj.update(createInput.issuerPublicKey);
468
+ allHashes.push(issuerPubKeyHashObj.digest());
469
+ const tokenNameHashObj = import_sha2.sha256.create();
470
+ if (!createInput.tokenName || createInput.tokenName.length === 0) {
471
+ throw new ValidationError("token name cannot be empty", {
472
+ field: "tokenInputs.createInput.tokenName"
473
+ });
474
+ }
475
+ if (createInput.tokenName.length > 20) {
476
+ throw new ValidationError("token name cannot be longer than 20 bytes", {
477
+ field: "tokenInputs.createInput.tokenName",
478
+ value: createInput.tokenName,
479
+ expectedLength: 20,
480
+ actualLength: createInput.tokenName.length
481
+ });
482
+ }
483
+ const tokenNameBytes = new Uint8Array(20);
484
+ const tokenNameEncoder = new TextEncoder();
485
+ tokenNameBytes.set(tokenNameEncoder.encode(createInput.tokenName));
486
+ tokenNameHashObj.update(tokenNameBytes);
487
+ allHashes.push(tokenNameHashObj.digest());
488
+ const tokenTickerHashObj = import_sha2.sha256.create();
489
+ if (!createInput.tokenTicker || createInput.tokenTicker.length === 0) {
490
+ throw new ValidationError("token ticker cannot be empty", {
491
+ field: "tokenInputs.createInput.tokenTicker"
492
+ });
493
+ }
494
+ if (createInput.tokenTicker.length > 6) {
495
+ throw new ValidationError("token ticker cannot be longer than 6 bytes", {
496
+ field: "tokenInputs.createInput.tokenTicker",
497
+ value: createInput.tokenTicker,
498
+ expectedLength: 6,
499
+ actualLength: createInput.tokenTicker.length
500
+ });
501
+ }
502
+ const tokenTickerBytes = new Uint8Array(6);
503
+ const tokenTickerEncoder = new TextEncoder();
504
+ tokenTickerBytes.set(tokenTickerEncoder.encode(createInput.tokenTicker));
505
+ tokenTickerHashObj.update(tokenTickerBytes);
506
+ allHashes.push(tokenTickerHashObj.digest());
507
+ const decimalsHashObj = import_sha2.sha256.create();
508
+ const decimalsBytes = new Uint8Array(4);
509
+ new DataView(decimalsBytes.buffer).setUint32(
510
+ 0,
511
+ createInput.decimals,
512
+ false
513
+ );
514
+ decimalsHashObj.update(decimalsBytes);
515
+ allHashes.push(decimalsHashObj.digest());
516
+ const maxSupplyHashObj = import_sha2.sha256.create();
517
+ if (!createInput.maxSupply) {
518
+ throw new ValidationError("max supply cannot be nil", {
519
+ field: "tokenInputs.createInput.maxSupply"
520
+ });
521
+ }
522
+ if (createInput.maxSupply.length !== 16) {
523
+ throw new ValidationError("max supply must be exactly 16 bytes", {
524
+ field: "tokenInputs.createInput.maxSupply",
525
+ value: createInput.maxSupply,
526
+ expectedLength: 16,
527
+ actualLength: createInput.maxSupply.length
528
+ });
529
+ }
530
+ maxSupplyHashObj.update(createInput.maxSupply);
531
+ allHashes.push(maxSupplyHashObj.digest());
532
+ const isFreezableHashObj = import_sha2.sha256.create();
533
+ const isFreezableByte = new Uint8Array([createInput.isFreezable ? 1 : 0]);
534
+ isFreezableHashObj.update(isFreezableByte);
535
+ allHashes.push(isFreezableHashObj.digest());
536
+ const creationEntityHashObj = import_sha2.sha256.create();
537
+ if (!partialHash && createInput.creationEntityPublicKey) {
538
+ creationEntityHashObj.update(createInput.creationEntityPublicKey);
539
+ }
540
+ allHashes.push(creationEntityHashObj.digest());
541
+ }
242
542
  if (!tokenTransaction.tokenOutputs) {
243
543
  throw new ValidationError("token outputs cannot be null", {
244
544
  field: "tokenOutputs"
245
545
  });
246
546
  }
247
- if (tokenTransaction.tokenOutputs.length === 0) {
547
+ if (tokenTransaction.tokenOutputs.length === 0 && tokenTransaction.tokenInputs?.$case !== "createInput") {
248
548
  throw new ValidationError("token outputs cannot be empty", {
249
549
  field: "tokenOutputs"
250
550
  });
@@ -421,6 +721,26 @@ function hashTokenTransactionV1(tokenTransaction, partialHash = false) {
421
721
  );
422
722
  versionHashObj.update(versionBytes);
423
723
  allHashes.push(versionHashObj.digest());
724
+ const typeHashObj = import_sha2.sha256.create();
725
+ const typeBytes = new Uint8Array(4);
726
+ let transactionType = 0;
727
+ if (tokenTransaction.tokenInputs?.$case === "mintInput") {
728
+ transactionType = 2 /* TOKEN_TRANSACTION_TYPE_MINT */;
729
+ } else if (tokenTransaction.tokenInputs?.$case === "transferInput") {
730
+ transactionType = 3 /* TOKEN_TRANSACTION_TYPE_TRANSFER */;
731
+ } else if (tokenTransaction.tokenInputs?.$case === "createInput") {
732
+ transactionType = 1 /* TOKEN_TRANSACTION_TYPE_CREATE */;
733
+ } else {
734
+ throw new ValidationError(
735
+ "token transaction must have exactly one input type",
736
+ {
737
+ field: "tokenInputs"
738
+ }
739
+ );
740
+ }
741
+ new DataView(typeBytes.buffer).setUint32(0, transactionType, false);
742
+ typeHashObj.update(typeBytes);
743
+ allHashes.push(typeHashObj.digest());
424
744
  if (tokenTransaction.tokenInputs?.$case === "transferInput") {
425
745
  if (!tokenTransaction.tokenInputs.transferInput.outputsToSpend) {
426
746
  throw new ValidationError("outputs to spend cannot be null", {
@@ -432,6 +752,15 @@ function hashTokenTransactionV1(tokenTransaction, partialHash = false) {
432
752
  field: "tokenInputs.transferInput.outputsToSpend"
433
753
  });
434
754
  }
755
+ const outputsLenHashObj2 = import_sha2.sha256.create();
756
+ const outputsLenBytes2 = new Uint8Array(4);
757
+ new DataView(outputsLenBytes2.buffer).setUint32(
758
+ 0,
759
+ tokenTransaction.tokenInputs.transferInput.outputsToSpend.length,
760
+ false
761
+ );
762
+ outputsLenHashObj2.update(outputsLenBytes2);
763
+ allHashes.push(outputsLenHashObj2.digest());
435
764
  for (const [
436
765
  i,
437
766
  output
@@ -468,8 +797,7 @@ function hashTokenTransactionV1(tokenTransaction, partialHash = false) {
468
797
  hashObj2.update(voutBytes);
469
798
  allHashes.push(hashObj2.digest());
470
799
  }
471
- }
472
- if (tokenTransaction.tokenInputs?.$case === "mintInput") {
800
+ } else if (tokenTransaction.tokenInputs?.$case === "mintInput") {
473
801
  const hashObj2 = import_sha2.sha256.create();
474
802
  if (tokenTransaction.tokenInputs.mintInput.issuerPublicKey) {
475
803
  const issuerPubKey = tokenTransaction.tokenInputs.mintInput.issuerPublicKey;
@@ -482,31 +810,113 @@ function hashTokenTransactionV1(tokenTransaction, partialHash = false) {
482
810
  });
483
811
  }
484
812
  hashObj2.update(issuerPubKey);
485
- if (tokenTransaction.tokenInputs.mintInput.issuerProvidedTimestamp != 0) {
486
- const timestampBytes = new Uint8Array(8);
487
- new DataView(timestampBytes.buffer).setBigUint64(
488
- 0,
489
- BigInt(
490
- tokenTransaction.tokenInputs.mintInput.issuerProvidedTimestamp
491
- ),
492
- true
493
- // true for little-endian to match Go implementation
813
+ allHashes.push(hashObj2.digest());
814
+ const tokenIdentifierHashObj = import_sha2.sha256.create();
815
+ if (tokenTransaction.tokenInputs.mintInput.tokenIdentifier) {
816
+ tokenIdentifierHashObj.update(
817
+ tokenTransaction.tokenInputs.mintInput.tokenIdentifier
494
818
  );
495
- hashObj2.update(timestampBytes);
819
+ } else {
820
+ tokenIdentifierHashObj.update(new Uint8Array(32));
496
821
  }
497
- allHashes.push(hashObj2.digest());
822
+ allHashes.push(tokenIdentifierHashObj.digest());
823
+ }
824
+ } else if (tokenTransaction.tokenInputs?.$case === "createInput") {
825
+ const createInput = tokenTransaction.tokenInputs.createInput;
826
+ const issuerPubKeyHashObj = import_sha2.sha256.create();
827
+ if (!createInput.issuerPublicKey || createInput.issuerPublicKey.length === 0) {
828
+ throw new ValidationError("issuer public key cannot be nil or empty", {
829
+ field: "tokenInputs.createInput.issuerPublicKey"
830
+ });
831
+ }
832
+ issuerPubKeyHashObj.update(createInput.issuerPublicKey);
833
+ allHashes.push(issuerPubKeyHashObj.digest());
834
+ const tokenNameHashObj = import_sha2.sha256.create();
835
+ if (!createInput.tokenName || createInput.tokenName.length === 0) {
836
+ throw new ValidationError("token name cannot be empty", {
837
+ field: "tokenInputs.createInput.tokenName"
838
+ });
839
+ }
840
+ if (createInput.tokenName.length > 20) {
841
+ throw new ValidationError("token name cannot be longer than 20 bytes", {
842
+ field: "tokenInputs.createInput.tokenName",
843
+ value: createInput.tokenName,
844
+ expectedLength: 20,
845
+ actualLength: createInput.tokenName.length
846
+ });
847
+ }
848
+ const tokenNameEncoder = new TextEncoder();
849
+ tokenNameHashObj.update(tokenNameEncoder.encode(createInput.tokenName));
850
+ allHashes.push(tokenNameHashObj.digest());
851
+ const tokenTickerHashObj = import_sha2.sha256.create();
852
+ if (!createInput.tokenTicker || createInput.tokenTicker.length === 0) {
853
+ throw new ValidationError("token ticker cannot be empty", {
854
+ field: "tokenInputs.createInput.tokenTicker"
855
+ });
498
856
  }
857
+ if (createInput.tokenTicker.length > 6) {
858
+ throw new ValidationError("token ticker cannot be longer than 6 bytes", {
859
+ field: "tokenInputs.createInput.tokenTicker",
860
+ value: createInput.tokenTicker,
861
+ expectedLength: 6,
862
+ actualLength: createInput.tokenTicker.length
863
+ });
864
+ }
865
+ const tokenTickerEncoder = new TextEncoder();
866
+ tokenTickerHashObj.update(
867
+ tokenTickerEncoder.encode(createInput.tokenTicker)
868
+ );
869
+ allHashes.push(tokenTickerHashObj.digest());
870
+ const decimalsHashObj = import_sha2.sha256.create();
871
+ const decimalsBytes = new Uint8Array(4);
872
+ new DataView(decimalsBytes.buffer).setUint32(
873
+ 0,
874
+ createInput.decimals,
875
+ false
876
+ );
877
+ decimalsHashObj.update(decimalsBytes);
878
+ allHashes.push(decimalsHashObj.digest());
879
+ const maxSupplyHashObj = import_sha2.sha256.create();
880
+ if (!createInput.maxSupply) {
881
+ throw new ValidationError("max supply cannot be nil", {
882
+ field: "tokenInputs.createInput.maxSupply"
883
+ });
884
+ }
885
+ if (createInput.maxSupply.length !== 16) {
886
+ throw new ValidationError("max supply must be exactly 16 bytes", {
887
+ field: "tokenInputs.createInput.maxSupply",
888
+ value: createInput.maxSupply,
889
+ expectedLength: 16,
890
+ actualLength: createInput.maxSupply.length
891
+ });
892
+ }
893
+ maxSupplyHashObj.update(createInput.maxSupply);
894
+ allHashes.push(maxSupplyHashObj.digest());
895
+ const isFreezableHashObj = import_sha2.sha256.create();
896
+ isFreezableHashObj.update(
897
+ new Uint8Array([createInput.isFreezable ? 1 : 0])
898
+ );
899
+ allHashes.push(isFreezableHashObj.digest());
900
+ const creationEntityHashObj = import_sha2.sha256.create();
901
+ if (!partialHash && createInput.creationEntityPublicKey) {
902
+ creationEntityHashObj.update(createInput.creationEntityPublicKey);
903
+ }
904
+ allHashes.push(creationEntityHashObj.digest());
499
905
  }
500
906
  if (!tokenTransaction.tokenOutputs) {
501
907
  throw new ValidationError("token outputs cannot be null", {
502
908
  field: "tokenOutputs"
503
909
  });
504
910
  }
505
- if (tokenTransaction.tokenOutputs.length === 0) {
506
- throw new ValidationError("token outputs cannot be empty", {
507
- field: "tokenOutputs"
508
- });
509
- }
911
+ const outputsLenHashObj = import_sha2.sha256.create();
912
+ const outputsLenBytes = new Uint8Array(4);
913
+ new DataView(outputsLenBytes.buffer).setUint32(
914
+ 0,
915
+ tokenTransaction.tokenOutputs.length,
916
+ false
917
+ );
918
+ outputsLenHashObj.update(outputsLenBytes);
919
+ allHashes.push(outputsLenHashObj.digest());
510
920
  for (const [i, output] of tokenTransaction.tokenOutputs.entries()) {
511
921
  if (!output) {
512
922
  throw new ValidationError(`output cannot be null at index ${i}`, {
@@ -565,18 +975,16 @@ function hashTokenTransactionV1(tokenTransaction, partialHash = false) {
565
975
  );
566
976
  hashObj2.update(locktimeBytes);
567
977
  }
568
- if (output.tokenPublicKey) {
569
- if (output.tokenPublicKey.length === 0) {
570
- throw new ValidationError(
571
- `token public key at index ${i} cannot be empty`,
572
- {
573
- field: `tokenOutputs[${i}].tokenPublicKey`,
574
- index: i
575
- }
576
- );
577
- }
978
+ if (!output.tokenPublicKey || output.tokenPublicKey.length === 0) {
979
+ hashObj2.update(new Uint8Array(33));
980
+ } else {
578
981
  hashObj2.update(output.tokenPublicKey);
579
982
  }
983
+ if (!output.tokenIdentifier || output.tokenIdentifier.length === 0) {
984
+ hashObj2.update(new Uint8Array(32));
985
+ } else {
986
+ hashObj2.update(output.tokenIdentifier);
987
+ }
580
988
  if (output.tokenAmount) {
581
989
  if (output.tokenAmount.length === 0) {
582
990
  throw new ValidationError(
@@ -617,6 +1025,15 @@ function hashTokenTransactionV1(tokenTransaction, partialHash = false) {
617
1025
  }
618
1026
  return a.length - b.length;
619
1027
  });
1028
+ const operatorLenHashObj = import_sha2.sha256.create();
1029
+ const operatorLenBytes = new Uint8Array(4);
1030
+ new DataView(operatorLenBytes.buffer).setUint32(
1031
+ 0,
1032
+ sortedPubKeys.length,
1033
+ false
1034
+ );
1035
+ operatorLenHashObj.update(operatorLenBytes);
1036
+ allHashes.push(operatorLenHashObj.digest());
620
1037
  for (const [i, pubKey] of sortedPubKeys.entries()) {
621
1038
  if (!pubKey) {
622
1039
  throw new ValidationError(
@@ -650,17 +1067,38 @@ function hashTokenTransactionV1(tokenTransaction, partialHash = false) {
650
1067
  );
651
1068
  hashObj.update(networkBytes);
652
1069
  allHashes.push(hashObj.digest());
653
- const expiryHashObj = import_sha2.sha256.create();
654
- const validityDurationBytes = new Uint8Array(8);
655
- const expiryUnixTime = tokenTransaction.expiryTime ? Math.floor(tokenTransaction.expiryTime.getTime() / 1e3) : 0;
656
- new DataView(validityDurationBytes.buffer).setBigUint64(
1070
+ const clientTimestampHashObj = import_sha2.sha256.create();
1071
+ const clientCreatedTs = tokenTransaction.clientCreatedTimestamp;
1072
+ if (!clientCreatedTs) {
1073
+ throw new ValidationError(
1074
+ "client created timestamp cannot be null for V1 token transactions",
1075
+ {
1076
+ field: "clientCreatedTimestamp"
1077
+ }
1078
+ );
1079
+ }
1080
+ const clientUnixTime = clientCreatedTs.getTime();
1081
+ const clientTimestampBytes = new Uint8Array(8);
1082
+ new DataView(clientTimestampBytes.buffer).setBigUint64(
657
1083
  0,
658
- BigInt(expiryUnixTime),
1084
+ BigInt(clientUnixTime),
659
1085
  false
660
- // false for big-endian
661
1086
  );
662
- expiryHashObj.update(validityDurationBytes);
663
- allHashes.push(expiryHashObj.digest());
1087
+ clientTimestampHashObj.update(clientTimestampBytes);
1088
+ allHashes.push(clientTimestampHashObj.digest());
1089
+ if (!partialHash) {
1090
+ const expiryHashObj = import_sha2.sha256.create();
1091
+ const expiryTimeBytes = new Uint8Array(8);
1092
+ const expiryUnixTime = tokenTransaction.expiryTime ? Math.floor(tokenTransaction.expiryTime.getTime() / 1e3) : 0;
1093
+ new DataView(expiryTimeBytes.buffer).setBigUint64(
1094
+ 0,
1095
+ BigInt(expiryUnixTime),
1096
+ false
1097
+ // false for big-endian
1098
+ );
1099
+ expiryHashObj.update(expiryTimeBytes);
1100
+ allHashes.push(expiryHashObj.digest());
1101
+ }
664
1102
  const finalHashObj = import_sha2.sha256.create();
665
1103
  const concatenatedHashes = new Uint8Array(
666
1104
  allHashes.reduce((sum, hash) => sum + hash.length, 0)
@@ -760,7 +1198,7 @@ function areByteArraysEqual(a, b) {
760
1198
  function hasDuplicates(array) {
761
1199
  return new Set(array).size !== array.length;
762
1200
  }
763
- function validateTokenTransaction(finalTokenTransaction, partialTokenTransaction, signingOperators, keyshareInfo, expectedWithdrawBondSats, expectedWithdrawRelativeBlockLocktime, expectedThreshold) {
1201
+ function validateTokenTransactionV0(finalTokenTransaction, partialTokenTransaction, signingOperators, keyshareInfo, expectedWithdrawBondSats, expectedWithdrawRelativeBlockLocktime, expectedThreshold) {
764
1202
  if (finalTokenTransaction.network !== partialTokenTransaction.network) {
765
1203
  throw new InternalValidationError(
766
1204
  "Network mismatch in response token transaction",
@@ -917,7 +1355,7 @@ function validateTokenTransaction(finalTokenTransaction, partialTokenTransaction
917
1355
  }
918
1356
  );
919
1357
  }
920
- if (!areByteArraysEqual(
1358
+ if (finalOutput.tokenPublicKey !== void 0 && partialOutput.tokenPublicKey !== void 0 && !areByteArraysEqual(
921
1359
  finalOutput.tokenPublicKey,
922
1360
  partialOutput.tokenPublicKey
923
1361
  )) {
@@ -925,8 +1363,8 @@ function validateTokenTransaction(finalTokenTransaction, partialTokenTransaction
925
1363
  "Token public key mismatch in token output",
926
1364
  {
927
1365
  outputIndex: i,
928
- value: finalOutput.tokenPublicKey.toString(),
929
- expected: partialOutput.tokenPublicKey.toString()
1366
+ value: finalOutput.tokenPublicKey?.toString(),
1367
+ expected: partialOutput.tokenPublicKey?.toString()
930
1368
  }
931
1369
  );
932
1370
  }
@@ -1004,222 +1442,264 @@ function validateTokenTransaction(finalTokenTransaction, partialTokenTransaction
1004
1442
  }
1005
1443
  }
1006
1444
  }
1007
-
1008
- // src/services/token-transactions.ts
1009
- var import_utils7 = require("@noble/hashes/utils");
1010
-
1011
- // src/address/address.ts
1012
- var import_secp256k1 = require("@noble/curves/secp256k1");
1013
- var import_utils3 = require("@noble/hashes/utils");
1014
- var import_base2 = require("@scure/base");
1015
-
1016
- // src/proto/spark.ts
1017
- var import_wire4 = require("@bufbuild/protobuf/wire");
1018
-
1019
- // src/proto/common.ts
1020
- var import_wire = require("@bufbuild/protobuf/wire");
1021
-
1022
- // src/proto/google/protobuf/empty.ts
1023
- var import_wire2 = require("@bufbuild/protobuf/wire");
1024
-
1025
- // src/proto/google/protobuf/timestamp.ts
1026
- var import_wire3 = require("@bufbuild/protobuf/wire");
1027
-
1028
- // src/proto/spark.ts
1029
- function createBaseSparkAddress() {
1030
- return { identityPublicKey: new Uint8Array(0), paymentIntentFields: void 0 };
1031
- }
1032
- var SparkAddress = {
1033
- encode(message, writer = new import_wire4.BinaryWriter()) {
1034
- if (message.identityPublicKey.length !== 0) {
1035
- writer.uint32(10).bytes(message.identityPublicKey);
1445
+ function validateTokenTransaction(finalTokenTransaction, partialTokenTransaction, signingOperators, keyshareInfo, expectedWithdrawBondSats, expectedWithdrawRelativeBlockLocktime, expectedThreshold) {
1446
+ if (finalTokenTransaction.network !== partialTokenTransaction.network) {
1447
+ throw new InternalValidationError(
1448
+ "Network mismatch in response token transaction",
1449
+ {
1450
+ value: finalTokenTransaction.network,
1451
+ expected: partialTokenTransaction.network
1452
+ }
1453
+ );
1454
+ }
1455
+ if (!finalTokenTransaction.tokenInputs) {
1456
+ throw new InternalValidationError(
1457
+ "Token inputs missing in final transaction",
1458
+ {
1459
+ value: finalTokenTransaction
1460
+ }
1461
+ );
1462
+ }
1463
+ if (!partialTokenTransaction.tokenInputs) {
1464
+ throw new InternalValidationError(
1465
+ "Token inputs missing in partial transaction",
1466
+ {
1467
+ value: partialTokenTransaction
1468
+ }
1469
+ );
1470
+ }
1471
+ if (finalTokenTransaction.tokenInputs.$case !== partialTokenTransaction.tokenInputs.$case) {
1472
+ throw new InternalValidationError(
1473
+ `Transaction type mismatch: final transaction has ${finalTokenTransaction.tokenInputs.$case}, partial transaction has ${partialTokenTransaction.tokenInputs.$case}`,
1474
+ {
1475
+ value: finalTokenTransaction.tokenInputs.$case,
1476
+ expected: partialTokenTransaction.tokenInputs.$case
1477
+ }
1478
+ );
1479
+ }
1480
+ if (finalTokenTransaction.sparkOperatorIdentityPublicKeys.length !== partialTokenTransaction.sparkOperatorIdentityPublicKeys.length) {
1481
+ throw new InternalValidationError(
1482
+ "Spark operator identity public keys count mismatch",
1483
+ {
1484
+ value: finalTokenTransaction.sparkOperatorIdentityPublicKeys.length,
1485
+ expected: partialTokenTransaction.sparkOperatorIdentityPublicKeys.length
1486
+ }
1487
+ );
1488
+ }
1489
+ if (partialTokenTransaction.tokenInputs.$case === "mintInput" && finalTokenTransaction.tokenInputs.$case === "mintInput") {
1490
+ const finalMintInput = finalTokenTransaction.tokenInputs.mintInput;
1491
+ const partialMintInput = partialTokenTransaction.tokenInputs.mintInput;
1492
+ if (!areByteArraysEqual(
1493
+ finalMintInput.issuerPublicKey,
1494
+ partialMintInput.issuerPublicKey
1495
+ )) {
1496
+ throw new InternalValidationError(
1497
+ "Issuer public key mismatch in mint input",
1498
+ {
1499
+ value: finalMintInput.issuerPublicKey.toString(),
1500
+ expected: partialMintInput.issuerPublicKey.toString()
1501
+ }
1502
+ );
1036
1503
  }
1037
- if (message.paymentIntentFields !== void 0) {
1038
- PaymentIntentFields.encode(message.paymentIntentFields, writer.uint32(18).fork()).join();
1504
+ } else if (partialTokenTransaction.tokenInputs.$case === "transferInput" && finalTokenTransaction.tokenInputs.$case === "transferInput") {
1505
+ const finalTransferInput = finalTokenTransaction.tokenInputs.transferInput;
1506
+ const partialTransferInput = partialTokenTransaction.tokenInputs.transferInput;
1507
+ if (finalTransferInput.outputsToSpend.length !== partialTransferInput.outputsToSpend.length) {
1508
+ throw new InternalValidationError(
1509
+ "Outputs to spend count mismatch in transfer input",
1510
+ {
1511
+ value: finalTransferInput.outputsToSpend.length,
1512
+ expected: partialTransferInput.outputsToSpend.length
1513
+ }
1514
+ );
1039
1515
  }
1040
- return writer;
1041
- },
1042
- decode(input, length) {
1043
- const reader = input instanceof import_wire4.BinaryReader ? input : new import_wire4.BinaryReader(input);
1044
- let end = length === void 0 ? reader.len : reader.pos + length;
1045
- const message = createBaseSparkAddress();
1046
- while (reader.pos < end) {
1047
- const tag = reader.uint32();
1048
- switch (tag >>> 3) {
1049
- case 1: {
1050
- if (tag !== 10) {
1051
- break;
1516
+ for (let i = 0; i < finalTransferInput.outputsToSpend.length; i++) {
1517
+ const finalOutput = finalTransferInput.outputsToSpend[i];
1518
+ const partialOutput = partialTransferInput.outputsToSpend[i];
1519
+ if (!finalOutput) {
1520
+ throw new InternalValidationError(
1521
+ "Token output to spend missing in final transaction",
1522
+ {
1523
+ outputIndex: i,
1524
+ value: finalOutput
1052
1525
  }
1053
- message.identityPublicKey = reader.bytes();
1054
- continue;
1055
- }
1056
- case 2: {
1057
- if (tag !== 18) {
1058
- break;
1526
+ );
1527
+ }
1528
+ if (!partialOutput) {
1529
+ throw new InternalValidationError(
1530
+ "Token output to spend missing in partial transaction",
1531
+ {
1532
+ outputIndex: i,
1533
+ value: partialOutput
1059
1534
  }
1060
- message.paymentIntentFields = PaymentIntentFields.decode(reader, reader.uint32());
1061
- continue;
1062
- }
1535
+ );
1063
1536
  }
1064
- if ((tag & 7) === 4 || tag === 0) {
1065
- break;
1537
+ if (!areByteArraysEqual(
1538
+ finalOutput.prevTokenTransactionHash,
1539
+ partialOutput.prevTokenTransactionHash
1540
+ )) {
1541
+ throw new InternalValidationError(
1542
+ "Previous token transaction hash mismatch in transfer input",
1543
+ {
1544
+ outputIndex: i,
1545
+ value: finalOutput.prevTokenTransactionHash.toString(),
1546
+ expected: partialOutput.prevTokenTransactionHash.toString()
1547
+ }
1548
+ );
1549
+ }
1550
+ if (finalOutput.prevTokenTransactionVout !== partialOutput.prevTokenTransactionVout) {
1551
+ throw new InternalValidationError(
1552
+ "Previous token transaction vout mismatch in transfer input",
1553
+ {
1554
+ outputIndex: i,
1555
+ value: finalOutput.prevTokenTransactionVout,
1556
+ expected: partialOutput.prevTokenTransactionVout
1557
+ }
1558
+ );
1066
1559
  }
1067
- reader.skip(tag & 7);
1068
- }
1069
- return message;
1070
- },
1071
- fromJSON(object) {
1072
- return {
1073
- identityPublicKey: isSet(object.identityPublicKey) ? bytesFromBase64(object.identityPublicKey) : new Uint8Array(0),
1074
- paymentIntentFields: isSet(object.paymentIntentFields) ? PaymentIntentFields.fromJSON(object.paymentIntentFields) : void 0
1075
- };
1076
- },
1077
- toJSON(message) {
1078
- const obj = {};
1079
- if (message.identityPublicKey.length !== 0) {
1080
- obj.identityPublicKey = base64FromBytes(message.identityPublicKey);
1081
- }
1082
- if (message.paymentIntentFields !== void 0) {
1083
- obj.paymentIntentFields = PaymentIntentFields.toJSON(message.paymentIntentFields);
1084
1560
  }
1085
- return obj;
1086
- },
1087
- create(base) {
1088
- return SparkAddress.fromPartial(base ?? {});
1089
- },
1090
- fromPartial(object) {
1091
- const message = createBaseSparkAddress();
1092
- message.identityPublicKey = object.identityPublicKey ?? new Uint8Array(0);
1093
- message.paymentIntentFields = object.paymentIntentFields !== void 0 && object.paymentIntentFields !== null ? PaymentIntentFields.fromPartial(object.paymentIntentFields) : void 0;
1094
- return message;
1095
1561
  }
1096
- };
1097
- function createBasePaymentIntentFields() {
1098
- return { id: new Uint8Array(0), assetIdentifier: void 0, assetAmount: new Uint8Array(0), memo: void 0 };
1099
- }
1100
- var PaymentIntentFields = {
1101
- encode(message, writer = new import_wire4.BinaryWriter()) {
1102
- if (message.id.length !== 0) {
1103
- writer.uint32(10).bytes(message.id);
1104
- }
1105
- if (message.assetIdentifier !== void 0) {
1106
- writer.uint32(18).bytes(message.assetIdentifier);
1107
- }
1108
- if (message.assetAmount.length !== 0) {
1109
- writer.uint32(26).bytes(message.assetAmount);
1110
- }
1111
- if (message.memo !== void 0) {
1112
- writer.uint32(34).string(message.memo);
1113
- }
1114
- return writer;
1115
- },
1116
- decode(input, length) {
1117
- const reader = input instanceof import_wire4.BinaryReader ? input : new import_wire4.BinaryReader(input);
1118
- let end = length === void 0 ? reader.len : reader.pos + length;
1119
- const message = createBasePaymentIntentFields();
1120
- while (reader.pos < end) {
1121
- const tag = reader.uint32();
1122
- switch (tag >>> 3) {
1123
- case 1: {
1124
- if (tag !== 10) {
1125
- break;
1126
- }
1127
- message.id = reader.bytes();
1128
- continue;
1562
+ if (finalTokenTransaction.tokenOutputs.length !== partialTokenTransaction.tokenOutputs.length) {
1563
+ throw new InternalValidationError("Token outputs count mismatch", {
1564
+ value: finalTokenTransaction.tokenOutputs.length,
1565
+ expected: partialTokenTransaction.tokenOutputs.length
1566
+ });
1567
+ }
1568
+ for (let i = 0; i < finalTokenTransaction.tokenOutputs.length; i++) {
1569
+ const finalOutput = finalTokenTransaction.tokenOutputs[i];
1570
+ const partialOutput = partialTokenTransaction.tokenOutputs[i];
1571
+ if (!finalOutput) {
1572
+ throw new InternalValidationError(
1573
+ "Token output missing in final transaction",
1574
+ {
1575
+ outputIndex: i,
1576
+ value: finalOutput
1129
1577
  }
1130
- case 2: {
1131
- if (tag !== 18) {
1132
- break;
1133
- }
1134
- message.assetIdentifier = reader.bytes();
1135
- continue;
1578
+ );
1579
+ }
1580
+ if (!partialOutput) {
1581
+ throw new InternalValidationError(
1582
+ "Token output missing in partial transaction",
1583
+ {
1584
+ outputIndex: i,
1585
+ value: partialOutput
1136
1586
  }
1137
- case 3: {
1138
- if (tag !== 26) {
1139
- break;
1140
- }
1141
- message.assetAmount = reader.bytes();
1142
- continue;
1587
+ );
1588
+ }
1589
+ if (!areByteArraysEqual(
1590
+ finalOutput.ownerPublicKey,
1591
+ partialOutput.ownerPublicKey
1592
+ )) {
1593
+ throw new InternalValidationError(
1594
+ "Owner public key mismatch in token output",
1595
+ {
1596
+ outputIndex: i,
1597
+ value: finalOutput.ownerPublicKey.toString(),
1598
+ expected: partialOutput.ownerPublicKey.toString()
1143
1599
  }
1144
- case 4: {
1145
- if (tag !== 34) {
1146
- break;
1147
- }
1148
- message.memo = reader.string();
1149
- continue;
1600
+ );
1601
+ }
1602
+ if (finalOutput.tokenPublicKey !== void 0 && partialOutput.tokenPublicKey !== void 0 && !areByteArraysEqual(
1603
+ finalOutput.tokenPublicKey,
1604
+ partialOutput.tokenPublicKey
1605
+ )) {
1606
+ throw new InternalValidationError(
1607
+ "Token public key mismatch in token output",
1608
+ {
1609
+ outputIndex: i,
1610
+ value: finalOutput.tokenPublicKey.toString(),
1611
+ expected: partialOutput.tokenPublicKey.toString()
1150
1612
  }
1151
- }
1152
- if ((tag & 7) === 4 || tag === 0) {
1153
- break;
1154
- }
1155
- reader.skip(tag & 7);
1613
+ );
1156
1614
  }
1157
- return message;
1158
- },
1159
- fromJSON(object) {
1160
- return {
1161
- id: isSet(object.id) ? bytesFromBase64(object.id) : new Uint8Array(0),
1162
- assetIdentifier: isSet(object.assetIdentifier) ? bytesFromBase64(object.assetIdentifier) : void 0,
1163
- assetAmount: isSet(object.assetAmount) ? bytesFromBase64(object.assetAmount) : new Uint8Array(0),
1164
- memo: isSet(object.memo) ? globalThis.String(object.memo) : void 0
1165
- };
1166
- },
1167
- toJSON(message) {
1168
- const obj = {};
1169
- if (message.id.length !== 0) {
1170
- obj.id = base64FromBytes(message.id);
1615
+ if (!areByteArraysEqual(finalOutput.tokenAmount, partialOutput.tokenAmount)) {
1616
+ throw new InternalValidationError(
1617
+ "Token amount mismatch in token output",
1618
+ {
1619
+ outputIndex: i,
1620
+ value: finalOutput.tokenAmount.toString(),
1621
+ expected: partialOutput.tokenAmount.toString()
1622
+ }
1623
+ );
1171
1624
  }
1172
- if (message.assetIdentifier !== void 0) {
1173
- obj.assetIdentifier = base64FromBytes(message.assetIdentifier);
1625
+ if (finalOutput.withdrawBondSats !== void 0) {
1626
+ if (finalOutput.withdrawBondSats !== expectedWithdrawBondSats) {
1627
+ throw new InternalValidationError(
1628
+ "Withdraw bond sats mismatch in token output",
1629
+ {
1630
+ outputIndex: i,
1631
+ value: finalOutput.withdrawBondSats,
1632
+ expected: expectedWithdrawBondSats
1633
+ }
1634
+ );
1635
+ }
1174
1636
  }
1175
- if (message.assetAmount.length !== 0) {
1176
- obj.assetAmount = base64FromBytes(message.assetAmount);
1637
+ if (finalOutput.withdrawRelativeBlockLocktime !== void 0) {
1638
+ if (finalOutput.withdrawRelativeBlockLocktime !== expectedWithdrawRelativeBlockLocktime) {
1639
+ throw new InternalValidationError(
1640
+ "Withdraw relative block locktime mismatch in token output",
1641
+ {
1642
+ outputIndex: i,
1643
+ value: finalOutput.withdrawRelativeBlockLocktime,
1644
+ expected: expectedWithdrawRelativeBlockLocktime
1645
+ }
1646
+ );
1647
+ }
1177
1648
  }
1178
- if (message.memo !== void 0) {
1179
- obj.memo = message.memo;
1649
+ if (keyshareInfo.threshold !== expectedThreshold) {
1650
+ throw new InternalValidationError(
1651
+ "Threshold mismatch: expected " + expectedThreshold + " but got " + keyshareInfo.threshold,
1652
+ {
1653
+ field: "threshold",
1654
+ value: keyshareInfo.threshold,
1655
+ expected: expectedThreshold
1656
+ }
1657
+ );
1180
1658
  }
1181
- return obj;
1182
- },
1183
- create(base) {
1184
- return PaymentIntentFields.fromPartial(base ?? {});
1185
- },
1186
- fromPartial(object) {
1187
- const message = createBasePaymentIntentFields();
1188
- message.id = object.id ?? new Uint8Array(0);
1189
- message.assetIdentifier = object.assetIdentifier ?? void 0;
1190
- message.assetAmount = object.assetAmount ?? new Uint8Array(0);
1191
- message.memo = object.memo ?? void 0;
1192
- return message;
1193
1659
  }
1194
- };
1195
- function bytesFromBase64(b64) {
1196
- if (globalThis.Buffer) {
1197
- return Uint8Array.from(globalThis.Buffer.from(b64, "base64"));
1198
- } else {
1199
- const bin = globalThis.atob(b64);
1200
- const arr = new Uint8Array(bin.length);
1201
- for (let i = 0; i < bin.length; ++i) {
1202
- arr[i] = bin.charCodeAt(i);
1660
+ if (keyshareInfo.ownerIdentifiers.length !== Object.keys(signingOperators).length) {
1661
+ throw new InternalValidationError(
1662
+ `Keyshare operator count (${keyshareInfo.ownerIdentifiers.length}) does not match signing operator count (${Object.keys(signingOperators).length})`,
1663
+ {
1664
+ keyshareInfo: keyshareInfo.ownerIdentifiers.length,
1665
+ signingOperators: Object.keys(signingOperators).length
1666
+ }
1667
+ );
1668
+ }
1669
+ if (hasDuplicates(keyshareInfo.ownerIdentifiers)) {
1670
+ throw new InternalValidationError(
1671
+ "Duplicate ownerIdentifiers found in keyshareInfo",
1672
+ {
1673
+ keyshareInfo: keyshareInfo.ownerIdentifiers
1674
+ }
1675
+ );
1676
+ }
1677
+ for (const identifier of keyshareInfo.ownerIdentifiers) {
1678
+ if (!signingOperators[identifier]) {
1679
+ throw new InternalValidationError(
1680
+ `Keyshare operator ${identifier} not found in signing operator list`,
1681
+ {
1682
+ keyshareInfo: identifier,
1683
+ signingOperators: Object.keys(signingOperators)
1684
+ }
1685
+ );
1203
1686
  }
1204
- return arr;
1205
1687
  }
1206
- }
1207
- function base64FromBytes(arr) {
1208
- if (globalThis.Buffer) {
1209
- return globalThis.Buffer.from(arr).toString("base64");
1210
- } else {
1211
- const bin = [];
1212
- arr.forEach((byte) => {
1213
- bin.push(globalThis.String.fromCharCode(byte));
1688
+ if (finalTokenTransaction.clientCreatedTimestamp.getTime() !== partialTokenTransaction.clientCreatedTimestamp.getTime()) {
1689
+ throw new InternalValidationError("Client created timestamp mismatch", {
1690
+ value: finalTokenTransaction.clientCreatedTimestamp,
1691
+ expected: partialTokenTransaction.clientCreatedTimestamp
1214
1692
  });
1215
- return globalThis.btoa(bin.join(""));
1216
1693
  }
1217
1694
  }
1218
- function isSet(value) {
1219
- return value !== null && value !== void 0;
1220
- }
1695
+
1696
+ // src/services/token-transactions.ts
1697
+ var import_utils7 = require("@noble/hashes/utils");
1221
1698
 
1222
1699
  // src/address/address.ts
1700
+ var import_secp256k1 = require("@noble/curves/secp256k1");
1701
+ var import_utils3 = require("@noble/hashes/utils");
1702
+ var import_base2 = require("@scure/base");
1223
1703
  var import_uuidv7 = require("uuidv7");
1224
1704
  var import_utils4 = require("@noble/curves/abstract/utils");
1225
1705
  var AddressNetwork = {
@@ -1516,6 +1996,9 @@ var TokenTransactionService = class {
1516
1996
  return txId;
1517
1997
  }
1518
1998
  async constructTransferTokenTransactionV0(selectedOutputs, tokenOutputData) {
1999
+ selectedOutputs.sort(
2000
+ (a, b) => a.previousTransactionVout - b.previousTransactionVout
2001
+ );
1519
2002
  const availableTokenAmount = calculateAvailableTokenAmount(selectedOutputs);
1520
2003
  const totalRequestedAmount = tokenOutputData.reduce(
1521
2004
  (sum, output) => sum + output.tokenAmount,
@@ -1551,6 +2034,9 @@ var TokenTransactionService = class {
1551
2034
  };
1552
2035
  }
1553
2036
  async constructTransferTokenTransaction(selectedOutputs, tokenOutputData) {
2037
+ selectedOutputs.sort(
2038
+ (a, b) => a.previousTransactionVout - b.previousTransactionVout
2039
+ );
1554
2040
  const availableTokenAmount = calculateAvailableTokenAmount(selectedOutputs);
1555
2041
  const totalRequestedAmount = tokenOutputData.reduce(
1556
2042
  (sum, output) => sum + output.tokenAmount,
@@ -1584,7 +2070,8 @@ var TokenTransactionService = class {
1584
2070
  },
1585
2071
  tokenOutputs,
1586
2072
  sparkOperatorIdentityPublicKeys: this.collectOperatorIdentityPublicKeys(),
1587
- expiryTime: void 0
2073
+ expiryTime: void 0,
2074
+ clientCreatedTimestamp: /* @__PURE__ */ new Date()
1588
2075
  };
1589
2076
  }
1590
2077
  collectOperatorIdentityPublicKeys() {
@@ -1793,7 +2280,7 @@ var TokenTransactionService = class {
1793
2280
  if (!startResponse.keyshareInfo) {
1794
2281
  throw new Error("Keyshare info missing in start response");
1795
2282
  }
1796
- validateTokenTransaction(
2283
+ validateTokenTransactionV0(
1797
2284
  startResponse.finalTokenTransaction,
1798
2285
  tokenTransaction,
1799
2286
  signingOperators,
@@ -2017,6 +2504,7 @@ var TokenTransactionService = class {
2017
2504
  await coordinatorClient.commit_transaction(
2018
2505
  {
2019
2506
  finalTokenTransaction,
2507
+ finalTokenTransactionHash,
2020
2508
  inputTtxoSignaturesPerOperator,
2021
2509
  ownerIdentityPublicKey: await this.config.signer.getIdentityPublicKey()
2022
2510
  },
@@ -2043,7 +2531,26 @@ var TokenTransactionService = class {
2043
2531
  );
2044
2532
  }
2045
2533
  }
2046
- async fetchOwnedTokenOutputs(ownerPublicKeys, tokenPublicKeys) {
2534
+ async fetchOwnedTokenOutputs(params) {
2535
+ if (this.config.getTokenTransactionVersion() === "V0") {
2536
+ return this.fetchOwnedTokenOutputsV0(params);
2537
+ } else {
2538
+ return this.fetchOwnedTokenOutputsV1(params);
2539
+ }
2540
+ }
2541
+ async queryTokenTransactions(params) {
2542
+ if (this.config.getTokenTransactionVersion() === "V0") {
2543
+ return this.queryTokenTransactionsV0(params);
2544
+ } else {
2545
+ return this.queryTokenTransactionsV1(params);
2546
+ }
2547
+ }
2548
+ async fetchOwnedTokenOutputsV0(params) {
2549
+ const {
2550
+ ownerPublicKeys,
2551
+ issuerPublicKeys: tokenPublicKeys = [],
2552
+ tokenIdentifiers = []
2553
+ } = params;
2047
2554
  const sparkClient = await this.connectionManager.createSparkClient(
2048
2555
  this.config.getCoordinatorAddress()
2049
2556
  );
@@ -2051,6 +2558,7 @@ var TokenTransactionService = class {
2051
2558
  const result = await sparkClient.query_token_outputs({
2052
2559
  ownerPublicKeys,
2053
2560
  tokenPublicKeys,
2561
+ tokenIdentifiers,
2054
2562
  network: this.config.getNetworkProto()
2055
2563
  });
2056
2564
  return result.outputsWithPreviousTransactionData;
@@ -2058,7 +2566,7 @@ var TokenTransactionService = class {
2058
2566
  throw new NetworkError(
2059
2567
  "Failed to fetch owned token outputs",
2060
2568
  {
2061
- operation: "query_token_outputs",
2569
+ operation: "spark.query_token_outputs",
2062
2570
  errorCount: 1,
2063
2571
  errors: error instanceof Error ? error.message : String(error)
2064
2572
  },
@@ -2066,11 +2574,127 @@ var TokenTransactionService = class {
2066
2574
  );
2067
2575
  }
2068
2576
  }
2069
- async syncTokenOutputs(tokenOutputs) {
2070
- const unsortedTokenOutputs = await this.fetchOwnedTokenOutputs(
2071
- await this.config.signer.getTrackedPublicKeys(),
2072
- []
2577
+ async fetchOwnedTokenOutputsV1(params) {
2578
+ const {
2579
+ ownerPublicKeys,
2580
+ issuerPublicKeys = [],
2581
+ tokenIdentifiers = []
2582
+ } = params;
2583
+ const tokenClient = await this.connectionManager.createSparkTokenClient(
2584
+ this.config.getCoordinatorAddress()
2585
+ );
2586
+ try {
2587
+ const result = await tokenClient.query_token_outputs({
2588
+ ownerPublicKeys,
2589
+ issuerPublicKeys,
2590
+ tokenIdentifiers,
2591
+ network: this.config.getNetworkProto()
2592
+ });
2593
+ return result.outputsWithPreviousTransactionData;
2594
+ } catch (error) {
2595
+ throw new NetworkError(
2596
+ "Failed to fetch owned token outputs",
2597
+ {
2598
+ operation: "spark_token.query_token_outputs",
2599
+ errorCount: 1,
2600
+ errors: error instanceof Error ? error.message : String(error)
2601
+ },
2602
+ error
2603
+ );
2604
+ }
2605
+ }
2606
+ async queryTokenTransactionsV0(params) {
2607
+ const {
2608
+ ownerPublicKeys,
2609
+ issuerPublicKeys,
2610
+ tokenTransactionHashes,
2611
+ tokenIdentifiers,
2612
+ outputIds
2613
+ } = params;
2614
+ const sparkClient = await this.connectionManager.createSparkClient(
2615
+ this.config.getCoordinatorAddress()
2616
+ );
2617
+ let queryParams = {
2618
+ tokenPublicKeys: issuerPublicKeys?.map(import_utils7.hexToBytes),
2619
+ ownerPublicKeys: ownerPublicKeys?.map(import_utils7.hexToBytes),
2620
+ tokenIdentifiers: tokenIdentifiers?.map(import_utils7.hexToBytes),
2621
+ tokenTransactionHashes: tokenTransactionHashes?.map(import_utils7.hexToBytes),
2622
+ outputIds: outputIds || [],
2623
+ limit: 100,
2624
+ offset: 0
2625
+ };
2626
+ try {
2627
+ const response = await sparkClient.query_token_transactions(queryParams);
2628
+ return response.tokenTransactionsWithStatus.map((tx) => {
2629
+ const v1TokenTransaction = {
2630
+ version: 1,
2631
+ network: tx.tokenTransaction.network,
2632
+ tokenInputs: tx.tokenTransaction.tokenInputs,
2633
+ tokenOutputs: tx.tokenTransaction.tokenOutputs,
2634
+ sparkOperatorIdentityPublicKeys: tx.tokenTransaction.sparkOperatorIdentityPublicKeys,
2635
+ expiryTime: void 0,
2636
+ // V0 doesn't have expiry time
2637
+ clientCreatedTimestamp: tx.tokenTransaction?.tokenInputs?.$case === "mintInput" ? new Date(
2638
+ tx.tokenTransaction.tokenInputs.mintInput.issuerProvidedTimestamp * 1e3
2639
+ ) : /* @__PURE__ */ new Date()
2640
+ };
2641
+ return {
2642
+ tokenTransaction: v1TokenTransaction,
2643
+ status: tx.status,
2644
+ confirmationMetadata: tx.confirmationMetadata
2645
+ };
2646
+ });
2647
+ } catch (error) {
2648
+ throw new NetworkError(
2649
+ "Failed to query token transactions",
2650
+ {
2651
+ operation: "spark.query_token_transactions",
2652
+ errorCount: 1,
2653
+ errors: error instanceof Error ? error.message : String(error)
2654
+ },
2655
+ error
2656
+ );
2657
+ }
2658
+ }
2659
+ async queryTokenTransactionsV1(params) {
2660
+ const {
2661
+ ownerPublicKeys,
2662
+ issuerPublicKeys,
2663
+ tokenTransactionHashes,
2664
+ tokenIdentifiers,
2665
+ outputIds
2666
+ } = params;
2667
+ const tokenClient = await this.connectionManager.createSparkTokenClient(
2668
+ this.config.getCoordinatorAddress()
2073
2669
  );
2670
+ let queryParams = {
2671
+ issuerPublicKeys: issuerPublicKeys?.map(import_utils7.hexToBytes),
2672
+ ownerPublicKeys: ownerPublicKeys?.map(import_utils7.hexToBytes),
2673
+ tokenIdentifiers: tokenIdentifiers?.map(import_utils7.hexToBytes),
2674
+ tokenTransactionHashes: tokenTransactionHashes?.map(import_utils7.hexToBytes),
2675
+ outputIds: outputIds || [],
2676
+ limit: 100,
2677
+ offset: 0
2678
+ };
2679
+ try {
2680
+ const response = await tokenClient.query_token_transactions(queryParams);
2681
+ return response.tokenTransactionsWithStatus;
2682
+ } catch (error) {
2683
+ throw new NetworkError(
2684
+ "Failed to query token transactions",
2685
+ {
2686
+ operation: "spark_token.query_token_transactions",
2687
+ errorCount: 1,
2688
+ errors: error instanceof Error ? error.message : String(error)
2689
+ },
2690
+ error
2691
+ );
2692
+ }
2693
+ }
2694
+ async syncTokenOutputs(tokenOutputs) {
2695
+ const unsortedTokenOutputs = await this.fetchOwnedTokenOutputs({
2696
+ ownerPublicKeys: await this.config.signer.getTrackedPublicKeys()
2697
+ });
2074
2698
  unsortedTokenOutputs.forEach((output) => {
2075
2699
  const tokenKey = (0, import_utils6.bytesToHex)(output.output.tokenPublicKey);
2076
2700
  const index = output.previousTransactionVout;