@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
@@ -2,10 +2,10 @@ import {
2
2
  calculateAvailableTokenAmount,
3
3
  checkIfSelectedOutputsAreAvailable,
4
4
  collectResponses
5
- } from "./chunk-6AFUC5M2.js";
5
+ } from "./chunk-HWJWKEIU.js";
6
6
  import {
7
7
  decodeSparkAddress
8
- } from "./chunk-O4RYNJNB.js";
8
+ } from "./chunk-KMUMFYFX.js";
9
9
  import {
10
10
  bigIntToPrivateKey,
11
11
  recoverSecret
@@ -110,13 +110,21 @@ function hashTokenTransactionV0(tokenTransaction, partialHash = false) {
110
110
  });
111
111
  }
112
112
  hashObj2.update(issuerPubKey);
113
- if (tokenTransaction.tokenInputs.mintInput.issuerProvidedTimestamp != 0) {
113
+ let timestampValue = 0;
114
+ const mintInput = tokenTransaction.tokenInputs.mintInput;
115
+ if ("issuerProvidedTimestamp" in mintInput) {
116
+ const v0MintInput = mintInput;
117
+ if (v0MintInput.issuerProvidedTimestamp != 0) {
118
+ timestampValue = v0MintInput.issuerProvidedTimestamp;
119
+ }
120
+ } else if ("clientCreatedTimestamp" in tokenTransaction && tokenTransaction.clientCreatedTimestamp) {
121
+ timestampValue = tokenTransaction.clientCreatedTimestamp.getTime();
122
+ }
123
+ if (timestampValue != 0) {
114
124
  const timestampBytes = new Uint8Array(8);
115
125
  new DataView(timestampBytes.buffer).setBigUint64(
116
126
  0,
117
- BigInt(
118
- tokenTransaction.tokenInputs.mintInput.issuerProvidedTimestamp
119
- ),
127
+ BigInt(timestampValue),
120
128
  true
121
129
  // true for little-endian to match Go implementation
122
130
  );
@@ -125,12 +133,95 @@ function hashTokenTransactionV0(tokenTransaction, partialHash = false) {
125
133
  allHashes.push(hashObj2.digest());
126
134
  }
127
135
  }
136
+ if (tokenTransaction.tokenInputs?.$case === "createInput") {
137
+ const issuerPubKeyHashObj = sha256.create();
138
+ const createInput = tokenTransaction.tokenInputs.createInput;
139
+ if (!createInput.issuerPublicKey || createInput.issuerPublicKey.length === 0) {
140
+ throw new ValidationError("issuer public key cannot be nil or empty", {
141
+ field: "tokenInputs.createInput.issuerPublicKey"
142
+ });
143
+ }
144
+ issuerPubKeyHashObj.update(createInput.issuerPublicKey);
145
+ allHashes.push(issuerPubKeyHashObj.digest());
146
+ const tokenNameHashObj = sha256.create();
147
+ if (!createInput.tokenName || createInput.tokenName.length === 0) {
148
+ throw new ValidationError("token name cannot be empty", {
149
+ field: "tokenInputs.createInput.tokenName"
150
+ });
151
+ }
152
+ if (createInput.tokenName.length > 20) {
153
+ throw new ValidationError("token name cannot be longer than 20 bytes", {
154
+ field: "tokenInputs.createInput.tokenName",
155
+ value: createInput.tokenName,
156
+ expectedLength: 20,
157
+ actualLength: createInput.tokenName.length
158
+ });
159
+ }
160
+ const tokenNameBytes = new Uint8Array(20);
161
+ const tokenNameEncoder = new TextEncoder();
162
+ tokenNameBytes.set(tokenNameEncoder.encode(createInput.tokenName));
163
+ tokenNameHashObj.update(tokenNameBytes);
164
+ allHashes.push(tokenNameHashObj.digest());
165
+ const tokenTickerHashObj = sha256.create();
166
+ if (!createInput.tokenTicker || createInput.tokenTicker.length === 0) {
167
+ throw new ValidationError("token ticker cannot be empty", {
168
+ field: "tokenInputs.createInput.tokenTicker"
169
+ });
170
+ }
171
+ if (createInput.tokenTicker.length > 6) {
172
+ throw new ValidationError("token ticker cannot be longer than 6 bytes", {
173
+ field: "tokenInputs.createInput.tokenTicker",
174
+ value: createInput.tokenTicker,
175
+ expectedLength: 6,
176
+ actualLength: createInput.tokenTicker.length
177
+ });
178
+ }
179
+ const tokenTickerBytes = new Uint8Array(6);
180
+ const tokenTickerEncoder = new TextEncoder();
181
+ tokenTickerBytes.set(tokenTickerEncoder.encode(createInput.tokenTicker));
182
+ tokenTickerHashObj.update(tokenTickerBytes);
183
+ allHashes.push(tokenTickerHashObj.digest());
184
+ const decimalsHashObj = sha256.create();
185
+ const decimalsBytes = new Uint8Array(4);
186
+ new DataView(decimalsBytes.buffer).setUint32(
187
+ 0,
188
+ createInput.decimals,
189
+ false
190
+ );
191
+ decimalsHashObj.update(decimalsBytes);
192
+ allHashes.push(decimalsHashObj.digest());
193
+ const maxSupplyHashObj = sha256.create();
194
+ if (!createInput.maxSupply) {
195
+ throw new ValidationError("max supply cannot be nil", {
196
+ field: "tokenInputs.createInput.maxSupply"
197
+ });
198
+ }
199
+ if (createInput.maxSupply.length !== 16) {
200
+ throw new ValidationError("max supply must be exactly 16 bytes", {
201
+ field: "tokenInputs.createInput.maxSupply",
202
+ value: createInput.maxSupply,
203
+ expectedLength: 16,
204
+ actualLength: createInput.maxSupply.length
205
+ });
206
+ }
207
+ maxSupplyHashObj.update(createInput.maxSupply);
208
+ allHashes.push(maxSupplyHashObj.digest());
209
+ const isFreezableHashObj = sha256.create();
210
+ const isFreezableByte = new Uint8Array([createInput.isFreezable ? 1 : 0]);
211
+ isFreezableHashObj.update(isFreezableByte);
212
+ allHashes.push(isFreezableHashObj.digest());
213
+ const creationEntityHashObj = sha256.create();
214
+ if (!partialHash && createInput.creationEntityPublicKey) {
215
+ creationEntityHashObj.update(createInput.creationEntityPublicKey);
216
+ }
217
+ allHashes.push(creationEntityHashObj.digest());
218
+ }
128
219
  if (!tokenTransaction.tokenOutputs) {
129
220
  throw new ValidationError("token outputs cannot be null", {
130
221
  field: "tokenOutputs"
131
222
  });
132
223
  }
133
- if (tokenTransaction.tokenOutputs.length === 0) {
224
+ if (tokenTransaction.tokenOutputs.length === 0 && tokenTransaction.tokenInputs?.$case !== "createInput") {
134
225
  throw new ValidationError("token outputs cannot be empty", {
135
226
  field: "tokenOutputs"
136
227
  });
@@ -307,6 +398,26 @@ function hashTokenTransactionV1(tokenTransaction, partialHash = false) {
307
398
  );
308
399
  versionHashObj.update(versionBytes);
309
400
  allHashes.push(versionHashObj.digest());
401
+ const typeHashObj = sha256.create();
402
+ const typeBytes = new Uint8Array(4);
403
+ let transactionType = 0;
404
+ if (tokenTransaction.tokenInputs?.$case === "mintInput") {
405
+ transactionType = 2 /* TOKEN_TRANSACTION_TYPE_MINT */;
406
+ } else if (tokenTransaction.tokenInputs?.$case === "transferInput") {
407
+ transactionType = 3 /* TOKEN_TRANSACTION_TYPE_TRANSFER */;
408
+ } else if (tokenTransaction.tokenInputs?.$case === "createInput") {
409
+ transactionType = 1 /* TOKEN_TRANSACTION_TYPE_CREATE */;
410
+ } else {
411
+ throw new ValidationError(
412
+ "token transaction must have exactly one input type",
413
+ {
414
+ field: "tokenInputs"
415
+ }
416
+ );
417
+ }
418
+ new DataView(typeBytes.buffer).setUint32(0, transactionType, false);
419
+ typeHashObj.update(typeBytes);
420
+ allHashes.push(typeHashObj.digest());
310
421
  if (tokenTransaction.tokenInputs?.$case === "transferInput") {
311
422
  if (!tokenTransaction.tokenInputs.transferInput.outputsToSpend) {
312
423
  throw new ValidationError("outputs to spend cannot be null", {
@@ -318,6 +429,15 @@ function hashTokenTransactionV1(tokenTransaction, partialHash = false) {
318
429
  field: "tokenInputs.transferInput.outputsToSpend"
319
430
  });
320
431
  }
432
+ const outputsLenHashObj2 = sha256.create();
433
+ const outputsLenBytes2 = new Uint8Array(4);
434
+ new DataView(outputsLenBytes2.buffer).setUint32(
435
+ 0,
436
+ tokenTransaction.tokenInputs.transferInput.outputsToSpend.length,
437
+ false
438
+ );
439
+ outputsLenHashObj2.update(outputsLenBytes2);
440
+ allHashes.push(outputsLenHashObj2.digest());
321
441
  for (const [
322
442
  i,
323
443
  output
@@ -354,8 +474,7 @@ function hashTokenTransactionV1(tokenTransaction, partialHash = false) {
354
474
  hashObj2.update(voutBytes);
355
475
  allHashes.push(hashObj2.digest());
356
476
  }
357
- }
358
- if (tokenTransaction.tokenInputs?.$case === "mintInput") {
477
+ } else if (tokenTransaction.tokenInputs?.$case === "mintInput") {
359
478
  const hashObj2 = sha256.create();
360
479
  if (tokenTransaction.tokenInputs.mintInput.issuerPublicKey) {
361
480
  const issuerPubKey = tokenTransaction.tokenInputs.mintInput.issuerPublicKey;
@@ -368,31 +487,113 @@ function hashTokenTransactionV1(tokenTransaction, partialHash = false) {
368
487
  });
369
488
  }
370
489
  hashObj2.update(issuerPubKey);
371
- if (tokenTransaction.tokenInputs.mintInput.issuerProvidedTimestamp != 0) {
372
- const timestampBytes = new Uint8Array(8);
373
- new DataView(timestampBytes.buffer).setBigUint64(
374
- 0,
375
- BigInt(
376
- tokenTransaction.tokenInputs.mintInput.issuerProvidedTimestamp
377
- ),
378
- true
379
- // true for little-endian to match Go implementation
490
+ allHashes.push(hashObj2.digest());
491
+ const tokenIdentifierHashObj = sha256.create();
492
+ if (tokenTransaction.tokenInputs.mintInput.tokenIdentifier) {
493
+ tokenIdentifierHashObj.update(
494
+ tokenTransaction.tokenInputs.mintInput.tokenIdentifier
380
495
  );
381
- hashObj2.update(timestampBytes);
496
+ } else {
497
+ tokenIdentifierHashObj.update(new Uint8Array(32));
382
498
  }
383
- allHashes.push(hashObj2.digest());
499
+ allHashes.push(tokenIdentifierHashObj.digest());
500
+ }
501
+ } else if (tokenTransaction.tokenInputs?.$case === "createInput") {
502
+ const createInput = tokenTransaction.tokenInputs.createInput;
503
+ const issuerPubKeyHashObj = sha256.create();
504
+ if (!createInput.issuerPublicKey || createInput.issuerPublicKey.length === 0) {
505
+ throw new ValidationError("issuer public key cannot be nil or empty", {
506
+ field: "tokenInputs.createInput.issuerPublicKey"
507
+ });
508
+ }
509
+ issuerPubKeyHashObj.update(createInput.issuerPublicKey);
510
+ allHashes.push(issuerPubKeyHashObj.digest());
511
+ const tokenNameHashObj = sha256.create();
512
+ if (!createInput.tokenName || createInput.tokenName.length === 0) {
513
+ throw new ValidationError("token name cannot be empty", {
514
+ field: "tokenInputs.createInput.tokenName"
515
+ });
516
+ }
517
+ if (createInput.tokenName.length > 20) {
518
+ throw new ValidationError("token name cannot be longer than 20 bytes", {
519
+ field: "tokenInputs.createInput.tokenName",
520
+ value: createInput.tokenName,
521
+ expectedLength: 20,
522
+ actualLength: createInput.tokenName.length
523
+ });
524
+ }
525
+ const tokenNameEncoder = new TextEncoder();
526
+ tokenNameHashObj.update(tokenNameEncoder.encode(createInput.tokenName));
527
+ allHashes.push(tokenNameHashObj.digest());
528
+ const tokenTickerHashObj = sha256.create();
529
+ if (!createInput.tokenTicker || createInput.tokenTicker.length === 0) {
530
+ throw new ValidationError("token ticker cannot be empty", {
531
+ field: "tokenInputs.createInput.tokenTicker"
532
+ });
533
+ }
534
+ if (createInput.tokenTicker.length > 6) {
535
+ throw new ValidationError("token ticker cannot be longer than 6 bytes", {
536
+ field: "tokenInputs.createInput.tokenTicker",
537
+ value: createInput.tokenTicker,
538
+ expectedLength: 6,
539
+ actualLength: createInput.tokenTicker.length
540
+ });
541
+ }
542
+ const tokenTickerEncoder = new TextEncoder();
543
+ tokenTickerHashObj.update(
544
+ tokenTickerEncoder.encode(createInput.tokenTicker)
545
+ );
546
+ allHashes.push(tokenTickerHashObj.digest());
547
+ const decimalsHashObj = sha256.create();
548
+ const decimalsBytes = new Uint8Array(4);
549
+ new DataView(decimalsBytes.buffer).setUint32(
550
+ 0,
551
+ createInput.decimals,
552
+ false
553
+ );
554
+ decimalsHashObj.update(decimalsBytes);
555
+ allHashes.push(decimalsHashObj.digest());
556
+ const maxSupplyHashObj = sha256.create();
557
+ if (!createInput.maxSupply) {
558
+ throw new ValidationError("max supply cannot be nil", {
559
+ field: "tokenInputs.createInput.maxSupply"
560
+ });
384
561
  }
562
+ if (createInput.maxSupply.length !== 16) {
563
+ throw new ValidationError("max supply must be exactly 16 bytes", {
564
+ field: "tokenInputs.createInput.maxSupply",
565
+ value: createInput.maxSupply,
566
+ expectedLength: 16,
567
+ actualLength: createInput.maxSupply.length
568
+ });
569
+ }
570
+ maxSupplyHashObj.update(createInput.maxSupply);
571
+ allHashes.push(maxSupplyHashObj.digest());
572
+ const isFreezableHashObj = sha256.create();
573
+ isFreezableHashObj.update(
574
+ new Uint8Array([createInput.isFreezable ? 1 : 0])
575
+ );
576
+ allHashes.push(isFreezableHashObj.digest());
577
+ const creationEntityHashObj = sha256.create();
578
+ if (!partialHash && createInput.creationEntityPublicKey) {
579
+ creationEntityHashObj.update(createInput.creationEntityPublicKey);
580
+ }
581
+ allHashes.push(creationEntityHashObj.digest());
385
582
  }
386
583
  if (!tokenTransaction.tokenOutputs) {
387
584
  throw new ValidationError("token outputs cannot be null", {
388
585
  field: "tokenOutputs"
389
586
  });
390
587
  }
391
- if (tokenTransaction.tokenOutputs.length === 0) {
392
- throw new ValidationError("token outputs cannot be empty", {
393
- field: "tokenOutputs"
394
- });
395
- }
588
+ const outputsLenHashObj = sha256.create();
589
+ const outputsLenBytes = new Uint8Array(4);
590
+ new DataView(outputsLenBytes.buffer).setUint32(
591
+ 0,
592
+ tokenTransaction.tokenOutputs.length,
593
+ false
594
+ );
595
+ outputsLenHashObj.update(outputsLenBytes);
596
+ allHashes.push(outputsLenHashObj.digest());
396
597
  for (const [i, output] of tokenTransaction.tokenOutputs.entries()) {
397
598
  if (!output) {
398
599
  throw new ValidationError(`output cannot be null at index ${i}`, {
@@ -451,18 +652,16 @@ function hashTokenTransactionV1(tokenTransaction, partialHash = false) {
451
652
  );
452
653
  hashObj2.update(locktimeBytes);
453
654
  }
454
- if (output.tokenPublicKey) {
455
- if (output.tokenPublicKey.length === 0) {
456
- throw new ValidationError(
457
- `token public key at index ${i} cannot be empty`,
458
- {
459
- field: `tokenOutputs[${i}].tokenPublicKey`,
460
- index: i
461
- }
462
- );
463
- }
655
+ if (!output.tokenPublicKey || output.tokenPublicKey.length === 0) {
656
+ hashObj2.update(new Uint8Array(33));
657
+ } else {
464
658
  hashObj2.update(output.tokenPublicKey);
465
659
  }
660
+ if (!output.tokenIdentifier || output.tokenIdentifier.length === 0) {
661
+ hashObj2.update(new Uint8Array(32));
662
+ } else {
663
+ hashObj2.update(output.tokenIdentifier);
664
+ }
466
665
  if (output.tokenAmount) {
467
666
  if (output.tokenAmount.length === 0) {
468
667
  throw new ValidationError(
@@ -503,6 +702,15 @@ function hashTokenTransactionV1(tokenTransaction, partialHash = false) {
503
702
  }
504
703
  return a.length - b.length;
505
704
  });
705
+ const operatorLenHashObj = sha256.create();
706
+ const operatorLenBytes = new Uint8Array(4);
707
+ new DataView(operatorLenBytes.buffer).setUint32(
708
+ 0,
709
+ sortedPubKeys.length,
710
+ false
711
+ );
712
+ operatorLenHashObj.update(operatorLenBytes);
713
+ allHashes.push(operatorLenHashObj.digest());
506
714
  for (const [i, pubKey] of sortedPubKeys.entries()) {
507
715
  if (!pubKey) {
508
716
  throw new ValidationError(
@@ -536,17 +744,38 @@ function hashTokenTransactionV1(tokenTransaction, partialHash = false) {
536
744
  );
537
745
  hashObj.update(networkBytes);
538
746
  allHashes.push(hashObj.digest());
539
- const expiryHashObj = sha256.create();
540
- const validityDurationBytes = new Uint8Array(8);
541
- const expiryUnixTime = tokenTransaction.expiryTime ? Math.floor(tokenTransaction.expiryTime.getTime() / 1e3) : 0;
542
- new DataView(validityDurationBytes.buffer).setBigUint64(
747
+ const clientTimestampHashObj = sha256.create();
748
+ const clientCreatedTs = tokenTransaction.clientCreatedTimestamp;
749
+ if (!clientCreatedTs) {
750
+ throw new ValidationError(
751
+ "client created timestamp cannot be null for V1 token transactions",
752
+ {
753
+ field: "clientCreatedTimestamp"
754
+ }
755
+ );
756
+ }
757
+ const clientUnixTime = clientCreatedTs.getTime();
758
+ const clientTimestampBytes = new Uint8Array(8);
759
+ new DataView(clientTimestampBytes.buffer).setBigUint64(
543
760
  0,
544
- BigInt(expiryUnixTime),
761
+ BigInt(clientUnixTime),
545
762
  false
546
- // false for big-endian
547
763
  );
548
- expiryHashObj.update(validityDurationBytes);
549
- allHashes.push(expiryHashObj.digest());
764
+ clientTimestampHashObj.update(clientTimestampBytes);
765
+ allHashes.push(clientTimestampHashObj.digest());
766
+ if (!partialHash) {
767
+ const expiryHashObj = sha256.create();
768
+ const expiryTimeBytes = new Uint8Array(8);
769
+ const expiryUnixTime = tokenTransaction.expiryTime ? Math.floor(tokenTransaction.expiryTime.getTime() / 1e3) : 0;
770
+ new DataView(expiryTimeBytes.buffer).setBigUint64(
771
+ 0,
772
+ BigInt(expiryUnixTime),
773
+ false
774
+ // false for big-endian
775
+ );
776
+ expiryHashObj.update(expiryTimeBytes);
777
+ allHashes.push(expiryHashObj.digest());
778
+ }
550
779
  const finalHashObj = sha256.create();
551
780
  const concatenatedHashes = new Uint8Array(
552
781
  allHashes.reduce((sum, hash) => sum + hash.length, 0)
@@ -618,7 +847,7 @@ function areByteArraysEqual(a, b) {
618
847
  function hasDuplicates(array) {
619
848
  return new Set(array).size !== array.length;
620
849
  }
621
- function validateTokenTransaction(finalTokenTransaction, partialTokenTransaction, signingOperators, keyshareInfo, expectedWithdrawBondSats, expectedWithdrawRelativeBlockLocktime, expectedThreshold) {
850
+ function validateTokenTransactionV0(finalTokenTransaction, partialTokenTransaction, signingOperators, keyshareInfo, expectedWithdrawBondSats, expectedWithdrawRelativeBlockLocktime, expectedThreshold) {
622
851
  if (finalTokenTransaction.network !== partialTokenTransaction.network) {
623
852
  throw new InternalValidationError(
624
853
  "Network mismatch in response token transaction",
@@ -775,7 +1004,251 @@ function validateTokenTransaction(finalTokenTransaction, partialTokenTransaction
775
1004
  }
776
1005
  );
777
1006
  }
1007
+ if (finalOutput.tokenPublicKey !== void 0 && partialOutput.tokenPublicKey !== void 0 && !areByteArraysEqual(
1008
+ finalOutput.tokenPublicKey,
1009
+ partialOutput.tokenPublicKey
1010
+ )) {
1011
+ throw new InternalValidationError(
1012
+ "Token public key mismatch in token output",
1013
+ {
1014
+ outputIndex: i,
1015
+ value: finalOutput.tokenPublicKey?.toString(),
1016
+ expected: partialOutput.tokenPublicKey?.toString()
1017
+ }
1018
+ );
1019
+ }
1020
+ if (!areByteArraysEqual(finalOutput.tokenAmount, partialOutput.tokenAmount)) {
1021
+ throw new InternalValidationError(
1022
+ "Token amount mismatch in token output",
1023
+ {
1024
+ outputIndex: i,
1025
+ value: finalOutput.tokenAmount.toString(),
1026
+ expected: partialOutput.tokenAmount.toString()
1027
+ }
1028
+ );
1029
+ }
1030
+ if (finalOutput.withdrawBondSats !== void 0) {
1031
+ if (finalOutput.withdrawBondSats !== expectedWithdrawBondSats) {
1032
+ throw new InternalValidationError(
1033
+ "Withdraw bond sats mismatch in token output",
1034
+ {
1035
+ outputIndex: i,
1036
+ value: finalOutput.withdrawBondSats,
1037
+ expected: expectedWithdrawBondSats
1038
+ }
1039
+ );
1040
+ }
1041
+ }
1042
+ if (finalOutput.withdrawRelativeBlockLocktime !== void 0) {
1043
+ if (finalOutput.withdrawRelativeBlockLocktime !== expectedWithdrawRelativeBlockLocktime) {
1044
+ throw new InternalValidationError(
1045
+ "Withdraw relative block locktime mismatch in token output",
1046
+ {
1047
+ outputIndex: i,
1048
+ value: finalOutput.withdrawRelativeBlockLocktime,
1049
+ expected: expectedWithdrawRelativeBlockLocktime
1050
+ }
1051
+ );
1052
+ }
1053
+ }
1054
+ if (keyshareInfo.threshold !== expectedThreshold) {
1055
+ throw new InternalValidationError(
1056
+ "Threshold mismatch: expected " + expectedThreshold + " but got " + keyshareInfo.threshold,
1057
+ {
1058
+ field: "threshold",
1059
+ value: keyshareInfo.threshold,
1060
+ expected: expectedThreshold
1061
+ }
1062
+ );
1063
+ }
1064
+ }
1065
+ if (keyshareInfo.ownerIdentifiers.length !== Object.keys(signingOperators).length) {
1066
+ throw new InternalValidationError(
1067
+ `Keyshare operator count (${keyshareInfo.ownerIdentifiers.length}) does not match signing operator count (${Object.keys(signingOperators).length})`,
1068
+ {
1069
+ keyshareInfo: keyshareInfo.ownerIdentifiers.length,
1070
+ signingOperators: Object.keys(signingOperators).length
1071
+ }
1072
+ );
1073
+ }
1074
+ if (hasDuplicates(keyshareInfo.ownerIdentifiers)) {
1075
+ throw new InternalValidationError(
1076
+ "Duplicate ownerIdentifiers found in keyshareInfo",
1077
+ {
1078
+ keyshareInfo: keyshareInfo.ownerIdentifiers
1079
+ }
1080
+ );
1081
+ }
1082
+ for (const identifier of keyshareInfo.ownerIdentifiers) {
1083
+ if (!signingOperators[identifier]) {
1084
+ throw new InternalValidationError(
1085
+ `Keyshare operator ${identifier} not found in signing operator list`,
1086
+ {
1087
+ keyshareInfo: identifier,
1088
+ signingOperators: Object.keys(signingOperators)
1089
+ }
1090
+ );
1091
+ }
1092
+ }
1093
+ }
1094
+ function validateTokenTransaction(finalTokenTransaction, partialTokenTransaction, signingOperators, keyshareInfo, expectedWithdrawBondSats, expectedWithdrawRelativeBlockLocktime, expectedThreshold) {
1095
+ if (finalTokenTransaction.network !== partialTokenTransaction.network) {
1096
+ throw new InternalValidationError(
1097
+ "Network mismatch in response token transaction",
1098
+ {
1099
+ value: finalTokenTransaction.network,
1100
+ expected: partialTokenTransaction.network
1101
+ }
1102
+ );
1103
+ }
1104
+ if (!finalTokenTransaction.tokenInputs) {
1105
+ throw new InternalValidationError(
1106
+ "Token inputs missing in final transaction",
1107
+ {
1108
+ value: finalTokenTransaction
1109
+ }
1110
+ );
1111
+ }
1112
+ if (!partialTokenTransaction.tokenInputs) {
1113
+ throw new InternalValidationError(
1114
+ "Token inputs missing in partial transaction",
1115
+ {
1116
+ value: partialTokenTransaction
1117
+ }
1118
+ );
1119
+ }
1120
+ if (finalTokenTransaction.tokenInputs.$case !== partialTokenTransaction.tokenInputs.$case) {
1121
+ throw new InternalValidationError(
1122
+ `Transaction type mismatch: final transaction has ${finalTokenTransaction.tokenInputs.$case}, partial transaction has ${partialTokenTransaction.tokenInputs.$case}`,
1123
+ {
1124
+ value: finalTokenTransaction.tokenInputs.$case,
1125
+ expected: partialTokenTransaction.tokenInputs.$case
1126
+ }
1127
+ );
1128
+ }
1129
+ if (finalTokenTransaction.sparkOperatorIdentityPublicKeys.length !== partialTokenTransaction.sparkOperatorIdentityPublicKeys.length) {
1130
+ throw new InternalValidationError(
1131
+ "Spark operator identity public keys count mismatch",
1132
+ {
1133
+ value: finalTokenTransaction.sparkOperatorIdentityPublicKeys.length,
1134
+ expected: partialTokenTransaction.sparkOperatorIdentityPublicKeys.length
1135
+ }
1136
+ );
1137
+ }
1138
+ if (partialTokenTransaction.tokenInputs.$case === "mintInput" && finalTokenTransaction.tokenInputs.$case === "mintInput") {
1139
+ const finalMintInput = finalTokenTransaction.tokenInputs.mintInput;
1140
+ const partialMintInput = partialTokenTransaction.tokenInputs.mintInput;
1141
+ if (!areByteArraysEqual(
1142
+ finalMintInput.issuerPublicKey,
1143
+ partialMintInput.issuerPublicKey
1144
+ )) {
1145
+ throw new InternalValidationError(
1146
+ "Issuer public key mismatch in mint input",
1147
+ {
1148
+ value: finalMintInput.issuerPublicKey.toString(),
1149
+ expected: partialMintInput.issuerPublicKey.toString()
1150
+ }
1151
+ );
1152
+ }
1153
+ } else if (partialTokenTransaction.tokenInputs.$case === "transferInput" && finalTokenTransaction.tokenInputs.$case === "transferInput") {
1154
+ const finalTransferInput = finalTokenTransaction.tokenInputs.transferInput;
1155
+ const partialTransferInput = partialTokenTransaction.tokenInputs.transferInput;
1156
+ if (finalTransferInput.outputsToSpend.length !== partialTransferInput.outputsToSpend.length) {
1157
+ throw new InternalValidationError(
1158
+ "Outputs to spend count mismatch in transfer input",
1159
+ {
1160
+ value: finalTransferInput.outputsToSpend.length,
1161
+ expected: partialTransferInput.outputsToSpend.length
1162
+ }
1163
+ );
1164
+ }
1165
+ for (let i = 0; i < finalTransferInput.outputsToSpend.length; i++) {
1166
+ const finalOutput = finalTransferInput.outputsToSpend[i];
1167
+ const partialOutput = partialTransferInput.outputsToSpend[i];
1168
+ if (!finalOutput) {
1169
+ throw new InternalValidationError(
1170
+ "Token output to spend missing in final transaction",
1171
+ {
1172
+ outputIndex: i,
1173
+ value: finalOutput
1174
+ }
1175
+ );
1176
+ }
1177
+ if (!partialOutput) {
1178
+ throw new InternalValidationError(
1179
+ "Token output to spend missing in partial transaction",
1180
+ {
1181
+ outputIndex: i,
1182
+ value: partialOutput
1183
+ }
1184
+ );
1185
+ }
1186
+ if (!areByteArraysEqual(
1187
+ finalOutput.prevTokenTransactionHash,
1188
+ partialOutput.prevTokenTransactionHash
1189
+ )) {
1190
+ throw new InternalValidationError(
1191
+ "Previous token transaction hash mismatch in transfer input",
1192
+ {
1193
+ outputIndex: i,
1194
+ value: finalOutput.prevTokenTransactionHash.toString(),
1195
+ expected: partialOutput.prevTokenTransactionHash.toString()
1196
+ }
1197
+ );
1198
+ }
1199
+ if (finalOutput.prevTokenTransactionVout !== partialOutput.prevTokenTransactionVout) {
1200
+ throw new InternalValidationError(
1201
+ "Previous token transaction vout mismatch in transfer input",
1202
+ {
1203
+ outputIndex: i,
1204
+ value: finalOutput.prevTokenTransactionVout,
1205
+ expected: partialOutput.prevTokenTransactionVout
1206
+ }
1207
+ );
1208
+ }
1209
+ }
1210
+ }
1211
+ if (finalTokenTransaction.tokenOutputs.length !== partialTokenTransaction.tokenOutputs.length) {
1212
+ throw new InternalValidationError("Token outputs count mismatch", {
1213
+ value: finalTokenTransaction.tokenOutputs.length,
1214
+ expected: partialTokenTransaction.tokenOutputs.length
1215
+ });
1216
+ }
1217
+ for (let i = 0; i < finalTokenTransaction.tokenOutputs.length; i++) {
1218
+ const finalOutput = finalTokenTransaction.tokenOutputs[i];
1219
+ const partialOutput = partialTokenTransaction.tokenOutputs[i];
1220
+ if (!finalOutput) {
1221
+ throw new InternalValidationError(
1222
+ "Token output missing in final transaction",
1223
+ {
1224
+ outputIndex: i,
1225
+ value: finalOutput
1226
+ }
1227
+ );
1228
+ }
1229
+ if (!partialOutput) {
1230
+ throw new InternalValidationError(
1231
+ "Token output missing in partial transaction",
1232
+ {
1233
+ outputIndex: i,
1234
+ value: partialOutput
1235
+ }
1236
+ );
1237
+ }
778
1238
  if (!areByteArraysEqual(
1239
+ finalOutput.ownerPublicKey,
1240
+ partialOutput.ownerPublicKey
1241
+ )) {
1242
+ throw new InternalValidationError(
1243
+ "Owner public key mismatch in token output",
1244
+ {
1245
+ outputIndex: i,
1246
+ value: finalOutput.ownerPublicKey.toString(),
1247
+ expected: partialOutput.ownerPublicKey.toString()
1248
+ }
1249
+ );
1250
+ }
1251
+ if (finalOutput.tokenPublicKey !== void 0 && partialOutput.tokenPublicKey !== void 0 && !areByteArraysEqual(
779
1252
  finalOutput.tokenPublicKey,
780
1253
  partialOutput.tokenPublicKey
781
1254
  )) {
@@ -861,6 +1334,12 @@ function validateTokenTransaction(finalTokenTransaction, partialTokenTransaction
861
1334
  );
862
1335
  }
863
1336
  }
1337
+ if (finalTokenTransaction.clientCreatedTimestamp.getTime() !== partialTokenTransaction.clientCreatedTimestamp.getTime()) {
1338
+ throw new InternalValidationError("Client created timestamp mismatch", {
1339
+ value: finalTokenTransaction.clientCreatedTimestamp,
1340
+ expected: partialTokenTransaction.clientCreatedTimestamp
1341
+ });
1342
+ }
864
1343
  }
865
1344
 
866
1345
  // src/services/token-transactions.ts
@@ -976,6 +1455,9 @@ var TokenTransactionService = class {
976
1455
  return txId;
977
1456
  }
978
1457
  async constructTransferTokenTransactionV0(selectedOutputs, tokenOutputData) {
1458
+ selectedOutputs.sort(
1459
+ (a, b) => a.previousTransactionVout - b.previousTransactionVout
1460
+ );
979
1461
  const availableTokenAmount = calculateAvailableTokenAmount(selectedOutputs);
980
1462
  const totalRequestedAmount = tokenOutputData.reduce(
981
1463
  (sum, output) => sum + output.tokenAmount,
@@ -1011,6 +1493,9 @@ var TokenTransactionService = class {
1011
1493
  };
1012
1494
  }
1013
1495
  async constructTransferTokenTransaction(selectedOutputs, tokenOutputData) {
1496
+ selectedOutputs.sort(
1497
+ (a, b) => a.previousTransactionVout - b.previousTransactionVout
1498
+ );
1014
1499
  const availableTokenAmount = calculateAvailableTokenAmount(selectedOutputs);
1015
1500
  const totalRequestedAmount = tokenOutputData.reduce(
1016
1501
  (sum, output) => sum + output.tokenAmount,
@@ -1044,7 +1529,8 @@ var TokenTransactionService = class {
1044
1529
  },
1045
1530
  tokenOutputs,
1046
1531
  sparkOperatorIdentityPublicKeys: this.collectOperatorIdentityPublicKeys(),
1047
- expiryTime: void 0
1532
+ expiryTime: void 0,
1533
+ clientCreatedTimestamp: /* @__PURE__ */ new Date()
1048
1534
  };
1049
1535
  }
1050
1536
  collectOperatorIdentityPublicKeys() {
@@ -1253,7 +1739,7 @@ var TokenTransactionService = class {
1253
1739
  if (!startResponse.keyshareInfo) {
1254
1740
  throw new Error("Keyshare info missing in start response");
1255
1741
  }
1256
- validateTokenTransaction(
1742
+ validateTokenTransactionV0(
1257
1743
  startResponse.finalTokenTransaction,
1258
1744
  tokenTransaction,
1259
1745
  signingOperators,
@@ -1477,6 +1963,7 @@ var TokenTransactionService = class {
1477
1963
  await coordinatorClient.commit_transaction(
1478
1964
  {
1479
1965
  finalTokenTransaction,
1966
+ finalTokenTransactionHash,
1480
1967
  inputTtxoSignaturesPerOperator,
1481
1968
  ownerIdentityPublicKey: await this.config.signer.getIdentityPublicKey()
1482
1969
  },
@@ -1503,7 +1990,26 @@ var TokenTransactionService = class {
1503
1990
  );
1504
1991
  }
1505
1992
  }
1506
- async fetchOwnedTokenOutputs(ownerPublicKeys, tokenPublicKeys) {
1993
+ async fetchOwnedTokenOutputs(params) {
1994
+ if (this.config.getTokenTransactionVersion() === "V0") {
1995
+ return this.fetchOwnedTokenOutputsV0(params);
1996
+ } else {
1997
+ return this.fetchOwnedTokenOutputsV1(params);
1998
+ }
1999
+ }
2000
+ async queryTokenTransactions(params) {
2001
+ if (this.config.getTokenTransactionVersion() === "V0") {
2002
+ return this.queryTokenTransactionsV0(params);
2003
+ } else {
2004
+ return this.queryTokenTransactionsV1(params);
2005
+ }
2006
+ }
2007
+ async fetchOwnedTokenOutputsV0(params) {
2008
+ const {
2009
+ ownerPublicKeys,
2010
+ issuerPublicKeys: tokenPublicKeys = [],
2011
+ tokenIdentifiers = []
2012
+ } = params;
1507
2013
  const sparkClient = await this.connectionManager.createSparkClient(
1508
2014
  this.config.getCoordinatorAddress()
1509
2015
  );
@@ -1511,6 +2017,7 @@ var TokenTransactionService = class {
1511
2017
  const result = await sparkClient.query_token_outputs({
1512
2018
  ownerPublicKeys,
1513
2019
  tokenPublicKeys,
2020
+ tokenIdentifiers,
1514
2021
  network: this.config.getNetworkProto()
1515
2022
  });
1516
2023
  return result.outputsWithPreviousTransactionData;
@@ -1518,7 +2025,7 @@ var TokenTransactionService = class {
1518
2025
  throw new NetworkError(
1519
2026
  "Failed to fetch owned token outputs",
1520
2027
  {
1521
- operation: "query_token_outputs",
2028
+ operation: "spark.query_token_outputs",
1522
2029
  errorCount: 1,
1523
2030
  errors: error instanceof Error ? error.message : String(error)
1524
2031
  },
@@ -1526,11 +2033,127 @@ var TokenTransactionService = class {
1526
2033
  );
1527
2034
  }
1528
2035
  }
1529
- async syncTokenOutputs(tokenOutputs) {
1530
- const unsortedTokenOutputs = await this.fetchOwnedTokenOutputs(
1531
- await this.config.signer.getTrackedPublicKeys(),
1532
- []
2036
+ async fetchOwnedTokenOutputsV1(params) {
2037
+ const {
2038
+ ownerPublicKeys,
2039
+ issuerPublicKeys = [],
2040
+ tokenIdentifiers = []
2041
+ } = params;
2042
+ const tokenClient = await this.connectionManager.createSparkTokenClient(
2043
+ this.config.getCoordinatorAddress()
1533
2044
  );
2045
+ try {
2046
+ const result = await tokenClient.query_token_outputs({
2047
+ ownerPublicKeys,
2048
+ issuerPublicKeys,
2049
+ tokenIdentifiers,
2050
+ network: this.config.getNetworkProto()
2051
+ });
2052
+ return result.outputsWithPreviousTransactionData;
2053
+ } catch (error) {
2054
+ throw new NetworkError(
2055
+ "Failed to fetch owned token outputs",
2056
+ {
2057
+ operation: "spark_token.query_token_outputs",
2058
+ errorCount: 1,
2059
+ errors: error instanceof Error ? error.message : String(error)
2060
+ },
2061
+ error
2062
+ );
2063
+ }
2064
+ }
2065
+ async queryTokenTransactionsV0(params) {
2066
+ const {
2067
+ ownerPublicKeys,
2068
+ issuerPublicKeys,
2069
+ tokenTransactionHashes,
2070
+ tokenIdentifiers,
2071
+ outputIds
2072
+ } = params;
2073
+ const sparkClient = await this.connectionManager.createSparkClient(
2074
+ this.config.getCoordinatorAddress()
2075
+ );
2076
+ let queryParams = {
2077
+ tokenPublicKeys: issuerPublicKeys?.map(hexToBytes),
2078
+ ownerPublicKeys: ownerPublicKeys?.map(hexToBytes),
2079
+ tokenIdentifiers: tokenIdentifiers?.map(hexToBytes),
2080
+ tokenTransactionHashes: tokenTransactionHashes?.map(hexToBytes),
2081
+ outputIds: outputIds || [],
2082
+ limit: 100,
2083
+ offset: 0
2084
+ };
2085
+ try {
2086
+ const response = await sparkClient.query_token_transactions(queryParams);
2087
+ return response.tokenTransactionsWithStatus.map((tx) => {
2088
+ const v1TokenTransaction = {
2089
+ version: 1,
2090
+ network: tx.tokenTransaction.network,
2091
+ tokenInputs: tx.tokenTransaction.tokenInputs,
2092
+ tokenOutputs: tx.tokenTransaction.tokenOutputs,
2093
+ sparkOperatorIdentityPublicKeys: tx.tokenTransaction.sparkOperatorIdentityPublicKeys,
2094
+ expiryTime: void 0,
2095
+ // V0 doesn't have expiry time
2096
+ clientCreatedTimestamp: tx.tokenTransaction?.tokenInputs?.$case === "mintInput" ? new Date(
2097
+ tx.tokenTransaction.tokenInputs.mintInput.issuerProvidedTimestamp * 1e3
2098
+ ) : /* @__PURE__ */ new Date()
2099
+ };
2100
+ return {
2101
+ tokenTransaction: v1TokenTransaction,
2102
+ status: tx.status,
2103
+ confirmationMetadata: tx.confirmationMetadata
2104
+ };
2105
+ });
2106
+ } catch (error) {
2107
+ throw new NetworkError(
2108
+ "Failed to query token transactions",
2109
+ {
2110
+ operation: "spark.query_token_transactions",
2111
+ errorCount: 1,
2112
+ errors: error instanceof Error ? error.message : String(error)
2113
+ },
2114
+ error
2115
+ );
2116
+ }
2117
+ }
2118
+ async queryTokenTransactionsV1(params) {
2119
+ const {
2120
+ ownerPublicKeys,
2121
+ issuerPublicKeys,
2122
+ tokenTransactionHashes,
2123
+ tokenIdentifiers,
2124
+ outputIds
2125
+ } = params;
2126
+ const tokenClient = await this.connectionManager.createSparkTokenClient(
2127
+ this.config.getCoordinatorAddress()
2128
+ );
2129
+ let queryParams = {
2130
+ issuerPublicKeys: issuerPublicKeys?.map(hexToBytes),
2131
+ ownerPublicKeys: ownerPublicKeys?.map(hexToBytes),
2132
+ tokenIdentifiers: tokenIdentifiers?.map(hexToBytes),
2133
+ tokenTransactionHashes: tokenTransactionHashes?.map(hexToBytes),
2134
+ outputIds: outputIds || [],
2135
+ limit: 100,
2136
+ offset: 0
2137
+ };
2138
+ try {
2139
+ const response = await tokenClient.query_token_transactions(queryParams);
2140
+ return response.tokenTransactionsWithStatus;
2141
+ } catch (error) {
2142
+ throw new NetworkError(
2143
+ "Failed to query token transactions",
2144
+ {
2145
+ operation: "spark_token.query_token_transactions",
2146
+ errorCount: 1,
2147
+ errors: error instanceof Error ? error.message : String(error)
2148
+ },
2149
+ error
2150
+ );
2151
+ }
2152
+ }
2153
+ async syncTokenOutputs(tokenOutputs) {
2154
+ const unsortedTokenOutputs = await this.fetchOwnedTokenOutputs({
2155
+ ownerPublicKeys: await this.config.signer.getTrackedPublicKeys()
2156
+ });
1534
2157
  unsortedTokenOutputs.forEach((output) => {
1535
2158
  const tokenKey = bytesToHex(output.output.tokenPublicKey);
1536
2159
  const index = output.previousTransactionVout;