@buildonspark/spark-sdk 0.3.3 → 0.3.5

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 (72) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/bare/index.cjs +945 -1401
  3. package/dist/bare/index.d.cts +128 -10
  4. package/dist/bare/index.d.ts +128 -10
  5. package/dist/bare/index.js +940 -1399
  6. package/dist/{chunk-55XNR6DM.js → chunk-DIXXHATX.js} +1 -1
  7. package/dist/{chunk-MGCUXELA.js → chunk-IC4IUEOS.js} +931 -125
  8. package/dist/{chunk-MH7BMOLL.js → chunk-J2P3KTQP.js} +1 -1
  9. package/dist/{chunk-SXXM52XH.js → chunk-JE73HB26.js} +409 -1656
  10. package/dist/{chunk-73GJOG5R.js → chunk-XWLR6G5C.js} +1 -1
  11. package/dist/{client-DrjQwET9.d.ts → client-DBZ43pJT.d.ts} +1 -1
  12. package/dist/{client-DUFejFfn.d.cts → client-DWml6sjL.d.cts} +1 -1
  13. package/dist/debug.cjs +949 -1403
  14. package/dist/debug.d.cts +8 -5
  15. package/dist/debug.d.ts +8 -5
  16. package/dist/debug.js +4 -4
  17. package/dist/graphql/objects/index.d.cts +3 -3
  18. package/dist/graphql/objects/index.d.ts +3 -3
  19. package/dist/index.cjs +905 -1362
  20. package/dist/index.d.cts +6 -6
  21. package/dist/index.d.ts +6 -6
  22. package/dist/index.js +9 -5
  23. package/dist/index.node.cjs +905 -1362
  24. package/dist/index.node.d.cts +6 -6
  25. package/dist/index.node.d.ts +6 -6
  26. package/dist/index.node.js +8 -4
  27. package/dist/{logging-CGeEoKYd.d.cts → logging-BUpzk4Z6.d.cts} +3 -3
  28. package/dist/{logging-DpSsvFVM.d.ts → logging-Dt2ooQiP.d.ts} +3 -3
  29. package/dist/native/index.cjs +905 -1362
  30. package/dist/native/index.d.cts +129 -25
  31. package/dist/native/index.d.ts +129 -25
  32. package/dist/native/index.js +904 -1363
  33. package/dist/proto/spark.cjs +931 -125
  34. package/dist/proto/spark.d.cts +1 -1
  35. package/dist/proto/spark.d.ts +1 -1
  36. package/dist/proto/spark.js +17 -1
  37. package/dist/proto/spark_token.d.cts +1 -1
  38. package/dist/proto/spark_token.d.ts +1 -1
  39. package/dist/proto/spark_token.js +2 -2
  40. package/dist/{spark-CLz4-Ln8.d.cts → spark-DasxuVfm.d.cts} +150 -5
  41. package/dist/{spark-CLz4-Ln8.d.ts → spark-DasxuVfm.d.ts} +150 -5
  42. package/dist/{spark-wallet-BVBrWYKL.d.cts → spark-wallet-BoMIOPWW.d.cts} +13 -9
  43. package/dist/{spark-wallet-CFPm6wZs.d.ts → spark-wallet-jlC0XN5f.d.ts} +13 -9
  44. package/dist/{spark-wallet.node-e1gncoIZ.d.ts → spark-wallet.node-07PksUHH.d.cts} +1 -1
  45. package/dist/{spark-wallet.node-B_00X-1j.d.cts → spark-wallet.node-CdWkKMSq.d.ts} +1 -1
  46. package/dist/tests/test-utils.cjs +947 -144
  47. package/dist/tests/test-utils.d.cts +4 -4
  48. package/dist/tests/test-utils.d.ts +4 -4
  49. package/dist/tests/test-utils.js +5 -5
  50. package/dist/{token-transactions-BkAqlmY6.d.ts → token-transactions-BDzCrQSk.d.cts} +5 -19
  51. package/dist/{token-transactions-BZGtwFFM.d.cts → token-transactions-DscJaJOE.d.ts} +5 -19
  52. package/dist/types/index.cjs +923 -125
  53. package/dist/types/index.d.cts +2 -2
  54. package/dist/types/index.d.ts +2 -2
  55. package/dist/types/index.js +2 -2
  56. package/package.json +1 -1
  57. package/src/proto/spark.ts +1167 -103
  58. package/src/services/config.ts +0 -4
  59. package/src/services/token-transactions.ts +11 -703
  60. package/src/services/wallet-config.ts +0 -2
  61. package/src/spark-wallet/proto-descriptors.ts +1 -1
  62. package/src/spark-wallet/spark-wallet.ts +58 -215
  63. package/src/spark_descriptors.pb +0 -0
  64. package/src/tests/address.test.ts +141 -0
  65. package/src/tests/integration/address.test.ts +4 -0
  66. package/src/tests/integration/lightning.test.ts +14 -9
  67. package/src/tests/integration/token-output.test.ts +0 -1
  68. package/src/tests/integration/transfer.test.ts +108 -2
  69. package/src/tests/token-hashing.test.ts +0 -247
  70. package/src/utils/address.ts +58 -35
  71. package/src/utils/token-hashing.ts +1 -420
  72. package/src/utils/token-transaction-validation.ts +0 -330
@@ -4,11 +4,11 @@ import {
4
4
  } from "./chunk-NX5KPN5F.js";
5
5
  import {
6
6
  SparkTokenServiceDefinition
7
- } from "./chunk-73GJOG5R.js";
7
+ } from "./chunk-XWLR6G5C.js";
8
8
  import {
9
9
  mapTransferToWalletTransfer,
10
10
  mapTreeNodeToWalletLeaf
11
- } from "./chunk-MH7BMOLL.js";
11
+ } from "./chunk-J2P3KTQP.js";
12
12
  import {
13
13
  Empty,
14
14
  SatsPayment,
@@ -19,7 +19,7 @@ import {
19
19
  TokensPayment,
20
20
  TreeNode,
21
21
  networkToJSON
22
- } from "./chunk-MGCUXELA.js";
22
+ } from "./chunk-IC4IUEOS.js";
23
23
  import {
24
24
  BitcoinNetwork_default,
25
25
  ClaimStaticDepositFromJson,
@@ -584,7 +584,7 @@ var isWebExtension = (
584
584
  "chrome" in globalThis && globalThis.chrome.runtime?.id
585
585
  );
586
586
  var userAgent = "navigator" in globalThis ? globalThis.navigator.userAgent || "unknown-user-agent" : void 0;
587
- var packageVersion = true ? "0.3.3" : "unknown";
587
+ var packageVersion = true ? "0.3.5" : "unknown";
588
588
  var baseEnvStr = "unknown";
589
589
  if (isBun) {
590
590
  const bunVersion = "version" in globalThis.Bun ? globalThis.Bun.version : "unknown-version";
@@ -1273,7 +1273,6 @@ var BASE_CONFIG = {
1273
1273
  threshold: 2,
1274
1274
  signingOperators: getLocalSigningOperators(),
1275
1275
  tokenSignatures: "SCHNORR",
1276
- tokenTransactionVersion: "V1",
1277
1276
  tokenValidityDurationSeconds: 180,
1278
1277
  electrsUrl: getElectrsUrl("LOCAL"),
1279
1278
  expectedWithdrawBondSats: 1e4,
@@ -1477,9 +1476,6 @@ var WalletConfigService = class {
1477
1476
  getTokenSignatures() {
1478
1477
  return this.config.tokenSignatures;
1479
1478
  }
1480
- getTokenTransactionVersion() {
1481
- return this.config.tokenTransactionVersion;
1482
- }
1483
1479
  getTokenValidityDurationSeconds() {
1484
1480
  return this.config.tokenValidityDurationSeconds;
1485
1481
  }
@@ -4173,6 +4169,13 @@ function uint64be(value) {
4173
4169
  // src/utils/address.ts
4174
4170
  var BECH32M_LIMIT = 1024;
4175
4171
  var AddressNetwork = {
4172
+ MAINNET: "spark",
4173
+ TESTNET: "sparkt",
4174
+ REGTEST: "sparkrt",
4175
+ SIGNET: "sparks",
4176
+ LOCAL: "sparkl"
4177
+ };
4178
+ var LegacyAddressNetwork = {
4176
4179
  MAINNET: "sp",
4177
4180
  TESTNET: "spt",
4178
4181
  REGTEST: "sprt",
@@ -4203,7 +4206,7 @@ function encodeSparkAddressWithSignature(payload, signature) {
4203
4206
  const serializedPayload = w.finish();
4204
4207
  const words = bech32m.toWords(serializedPayload);
4205
4208
  return bech32mEncode(
4206
- AddressNetwork[payload.network],
4209
+ LegacyAddressNetwork[payload.network],
4207
4210
  words
4208
4211
  );
4209
4212
  } catch (error) {
@@ -4219,14 +4222,14 @@ function encodeSparkAddressWithSignature(payload, signature) {
4219
4222
  }
4220
4223
  function decodeSparkAddress(address2, network) {
4221
4224
  try {
4222
- const decoded = bech32mDecode(address2);
4223
- if (decoded.prefix !== AddressNetwork[network]) {
4225
+ if (network !== getNetworkFromSparkAddress(address2)) {
4224
4226
  throw new ValidationError("Invalid Spark address prefix", {
4225
4227
  field: "address",
4226
4228
  value: address2,
4227
- expected: `prefix='${AddressNetwork[network]}'`
4229
+ expected: `prefix='${AddressNetwork[network]}' or '${LegacyAddressNetwork[network]}'`
4228
4230
  });
4229
4231
  }
4232
+ const decoded = bech32mDecode(address2);
4230
4233
  const payload = SparkAddress.decode(bech32m.fromWords(decoded.words));
4231
4234
  const { identityPublicKey, sparkInvoiceFields, signature } = payload;
4232
4235
  const identityPubkeyHex = bytesToHex5(identityPublicKey);
@@ -4270,18 +4273,35 @@ function decodeSparkAddress(address2, network) {
4270
4273
  );
4271
4274
  }
4272
4275
  }
4276
+ var PrefixToNetwork = Object.fromEntries(
4277
+ Object.entries(AddressNetwork).map(([k, v]) => [v, k])
4278
+ );
4279
+ var LegacyPrefixToNetwork = Object.fromEntries(
4280
+ Object.entries(LegacyAddressNetwork).map(([k, v]) => [v, k])
4281
+ );
4282
+ function getNetworkFromSparkAddress(address2) {
4283
+ const { prefix } = bech32mDecode(address2);
4284
+ const network = PrefixToNetwork[prefix] ?? LegacyPrefixToNetwork[prefix];
4285
+ if (!network) {
4286
+ throw new ValidationError("Invalid Spark address prefix", {
4287
+ field: "network",
4288
+ value: address2,
4289
+ expected: "prefix='spark1', 'sparkt1', 'sparkrt1', 'sparks1', 'sparkl1' or legacy ('sp1', 'spt1', 'sprt1', 'sps1', 'spl1')"
4290
+ });
4291
+ }
4292
+ return network;
4293
+ }
4294
+ function isLegacySparkAddress(address2) {
4295
+ try {
4296
+ const { prefix } = bech32mDecode(address2);
4297
+ return prefix in LegacyPrefixToNetwork;
4298
+ } catch (error) {
4299
+ return false;
4300
+ }
4301
+ }
4273
4302
  function isValidSparkAddress(address2) {
4274
4303
  try {
4275
- const network = Object.entries(AddressNetwork).find(
4276
- ([_, prefix]) => address2.startsWith(prefix)
4277
- )?.[0];
4278
- if (!network) {
4279
- throw new ValidationError("Invalid Spark address network", {
4280
- field: "network",
4281
- value: address2,
4282
- expected: Object.values(AddressNetwork)
4283
- });
4284
- }
4304
+ const network = getNetworkFromSparkAddress(address2);
4285
4305
  decodeSparkAddress(address2, network);
4286
4306
  return true;
4287
4307
  } catch (error) {
@@ -4477,25 +4497,16 @@ function validateSparkInvoiceSignature(invoice) {
4477
4497
  );
4478
4498
  }
4479
4499
  }
4480
- function getNetworkFromSparkAddress(address2) {
4481
- const { prefix } = bech32mDecode(address2);
4482
- const network = Object.entries(AddressNetwork).find(
4483
- ([, p]) => p === prefix
4484
- )?.[0];
4485
- if (!network) {
4486
- throw new ValidationError("Invalid Spark address network", {
4487
- field: "network",
4488
- value: address2,
4489
- expected: Object.values(AddressNetwork)
4490
- });
4491
- }
4492
- return network;
4493
- }
4494
4500
  function toProtoTimestamp(date) {
4495
4501
  const ms = date.getTime();
4496
4502
  return { seconds: Math.floor(ms / 1e3), nanos: ms % 1e3 * 1e6 };
4497
4503
  }
4504
+ function assertBech32(s) {
4505
+ const i = s.lastIndexOf("1");
4506
+ if (i <= 0 || i >= s.length - 1) throw new Error("invalid bech32 string");
4507
+ }
4498
4508
  function bech32mDecode(address2) {
4509
+ assertBech32(address2);
4499
4510
  return bech32m.decode(address2, BECH32M_LIMIT);
4500
4511
  }
4501
4512
  function bech32mEncode(prefix, words) {
@@ -4530,27 +4541,6 @@ function isSafeForNumber(bi) {
4530
4541
  return bi >= BigInt(Number.MIN_SAFE_INTEGER) && bi <= BigInt(Number.MAX_SAFE_INTEGER);
4531
4542
  }
4532
4543
 
4533
- // src/utils/response-validation.ts
4534
- function collectResponses(responses) {
4535
- const successfulResponses = responses.filter(
4536
- (result) => result.status === "fulfilled"
4537
- ).map((result) => result.value);
4538
- const failedResponses = responses.filter(
4539
- (result) => result.status === "rejected"
4540
- );
4541
- if (failedResponses.length > 0) {
4542
- const errors = failedResponses.map((result) => result.reason).join("\n");
4543
- throw new NetworkError(
4544
- `${failedResponses.length} out of ${responses.length} requests failed, please try again`,
4545
- {
4546
- errorCount: failedResponses.length,
4547
- errors
4548
- }
4549
- );
4550
- }
4551
- return successfulResponses;
4552
- }
4553
-
4554
4544
  // src/utils/token-identifier.ts
4555
4545
  import { bech32m as bech32m2 } from "@scure/base";
4556
4546
  var Bech32mTokenIdentifierTokenIdentifierNetworkPrefix = {
@@ -4697,7 +4687,6 @@ function filterTokenBalanceForTokenIdentifier(tokenBalances, tokenIdentifier) {
4697
4687
  }
4698
4688
 
4699
4689
  // src/services/token-transactions.ts
4700
- import { secp256k1 as secp256k19 } from "@noble/curves/secp256k1";
4701
4690
  import {
4702
4691
  bytesToHex as bytesToHex6,
4703
4692
  bytesToNumberBE as bytesToNumberBE5,
@@ -4710,8 +4699,6 @@ import { sha256 as sha2568 } from "@noble/hashes/sha2";
4710
4699
  import { bech32m as bech32m3 } from "@scure/base";
4711
4700
  function hashTokenTransaction(tokenTransaction, partialHash = false) {
4712
4701
  switch (tokenTransaction.version) {
4713
- case 0:
4714
- return hashTokenTransactionV0(tokenTransaction, partialHash);
4715
4702
  case 1:
4716
4703
  return hashTokenTransactionV1(tokenTransaction, partialHash);
4717
4704
  case 2:
@@ -4723,13 +4710,43 @@ function hashTokenTransaction(tokenTransaction, partialHash = false) {
4723
4710
  });
4724
4711
  }
4725
4712
  }
4726
- function hashTokenTransactionV0(tokenTransaction, partialHash = false) {
4713
+ function hashTokenTransactionV1(tokenTransaction, partialHash = false) {
4727
4714
  if (!tokenTransaction) {
4728
4715
  throw new ValidationError("token transaction cannot be nil", {
4729
4716
  field: "tokenTransaction"
4730
4717
  });
4731
4718
  }
4732
4719
  let allHashes = [];
4720
+ const versionHashObj = sha2568.create();
4721
+ const versionBytes = new Uint8Array(4);
4722
+ new DataView(versionBytes.buffer).setUint32(
4723
+ 0,
4724
+ tokenTransaction.version,
4725
+ false
4726
+ // false for big-endian
4727
+ );
4728
+ versionHashObj.update(versionBytes);
4729
+ allHashes.push(versionHashObj.digest());
4730
+ const typeHashObj = sha2568.create();
4731
+ const typeBytes = new Uint8Array(4);
4732
+ let transactionType = 0;
4733
+ if (tokenTransaction.tokenInputs?.$case === "mintInput") {
4734
+ transactionType = 2 /* TOKEN_TRANSACTION_TYPE_MINT */;
4735
+ } else if (tokenTransaction.tokenInputs?.$case === "transferInput") {
4736
+ transactionType = 3 /* TOKEN_TRANSACTION_TYPE_TRANSFER */;
4737
+ } else if (tokenTransaction.tokenInputs?.$case === "createInput") {
4738
+ transactionType = 1 /* TOKEN_TRANSACTION_TYPE_CREATE */;
4739
+ } else {
4740
+ throw new ValidationError(
4741
+ "token transaction must have exactly one input type",
4742
+ {
4743
+ field: "tokenInputs"
4744
+ }
4745
+ );
4746
+ }
4747
+ new DataView(typeBytes.buffer).setUint32(0, transactionType, false);
4748
+ typeHashObj.update(typeBytes);
4749
+ allHashes.push(typeHashObj.digest());
4733
4750
  if (tokenTransaction.tokenInputs?.$case === "transferInput") {
4734
4751
  if (!tokenTransaction.tokenInputs.transferInput.outputsToSpend) {
4735
4752
  throw new ValidationError("outputs to spend cannot be null", {
@@ -4741,6 +4758,15 @@ function hashTokenTransactionV0(tokenTransaction, partialHash = false) {
4741
4758
  field: "tokenInputs.transferInput.outputsToSpend"
4742
4759
  });
4743
4760
  }
4761
+ const outputsLenHashObj2 = sha2568.create();
4762
+ const outputsLenBytes2 = new Uint8Array(4);
4763
+ new DataView(outputsLenBytes2.buffer).setUint32(
4764
+ 0,
4765
+ tokenTransaction.tokenInputs.transferInput.outputsToSpend.length,
4766
+ false
4767
+ );
4768
+ outputsLenHashObj2.update(outputsLenBytes2);
4769
+ allHashes.push(outputsLenHashObj2.digest());
4744
4770
  for (const [
4745
4771
  i,
4746
4772
  output
@@ -4777,8 +4803,7 @@ function hashTokenTransactionV0(tokenTransaction, partialHash = false) {
4777
4803
  hashObj2.update(voutBytes);
4778
4804
  allHashes.push(hashObj2.digest());
4779
4805
  }
4780
- }
4781
- if (tokenTransaction.tokenInputs?.$case === "mintInput") {
4806
+ } else if (tokenTransaction.tokenInputs?.$case === "mintInput") {
4782
4807
  const hashObj2 = sha2568.create();
4783
4808
  if (tokenTransaction.tokenInputs.mintInput.issuerPublicKey) {
4784
4809
  const issuerPubKey = tokenTransaction.tokenInputs.mintInput.issuerPublicKey;
@@ -4791,32 +4816,20 @@ function hashTokenTransactionV0(tokenTransaction, partialHash = false) {
4791
4816
  });
4792
4817
  }
4793
4818
  hashObj2.update(issuerPubKey);
4794
- let timestampValue = 0;
4795
- const mintInput = tokenTransaction.tokenInputs.mintInput;
4796
- if ("issuerProvidedTimestamp" in mintInput) {
4797
- const v0MintInput = mintInput;
4798
- if (v0MintInput.issuerProvidedTimestamp != 0) {
4799
- timestampValue = v0MintInput.issuerProvidedTimestamp;
4800
- }
4801
- } else if ("clientCreatedTimestamp" in tokenTransaction && tokenTransaction.clientCreatedTimestamp) {
4802
- timestampValue = tokenTransaction.clientCreatedTimestamp.getTime();
4803
- }
4804
- if (timestampValue != 0) {
4805
- const timestampBytes = new Uint8Array(8);
4806
- new DataView(timestampBytes.buffer).setBigUint64(
4807
- 0,
4808
- BigInt(timestampValue),
4809
- true
4810
- // true for little-endian to match Go implementation
4819
+ allHashes.push(hashObj2.digest());
4820
+ const tokenIdentifierHashObj = sha2568.create();
4821
+ if (tokenTransaction.tokenInputs.mintInput.tokenIdentifier) {
4822
+ tokenIdentifierHashObj.update(
4823
+ tokenTransaction.tokenInputs.mintInput.tokenIdentifier
4811
4824
  );
4812
- hashObj2.update(timestampBytes);
4825
+ } else {
4826
+ tokenIdentifierHashObj.update(new Uint8Array(32));
4813
4827
  }
4814
- allHashes.push(hashObj2.digest());
4828
+ allHashes.push(tokenIdentifierHashObj.digest());
4815
4829
  }
4816
- }
4817
- if (tokenTransaction.tokenInputs?.$case === "createInput") {
4818
- const issuerPubKeyHashObj = sha2568.create();
4830
+ } else if (tokenTransaction.tokenInputs?.$case === "createInput") {
4819
4831
  const createInput = tokenTransaction.tokenInputs.createInput;
4832
+ const issuerPubKeyHashObj = sha2568.create();
4820
4833
  if (!createInput.issuerPublicKey || createInput.issuerPublicKey.length === 0) {
4821
4834
  throw new ValidationError("issuer public key cannot be nil or empty", {
4822
4835
  field: "tokenInputs.createInput.issuerPublicKey"
@@ -4838,10 +4851,8 @@ function hashTokenTransactionV0(tokenTransaction, partialHash = false) {
4838
4851
  actualLength: createInput.tokenName.length
4839
4852
  });
4840
4853
  }
4841
- const tokenNameBytes = new Uint8Array(20);
4842
4854
  const tokenNameEncoder = new TextEncoder();
4843
- tokenNameBytes.set(tokenNameEncoder.encode(createInput.tokenName));
4844
- tokenNameHashObj.update(tokenNameBytes);
4855
+ tokenNameHashObj.update(tokenNameEncoder.encode(createInput.tokenName));
4845
4856
  allHashes.push(tokenNameHashObj.digest());
4846
4857
  const tokenTickerHashObj = sha2568.create();
4847
4858
  if (!createInput.tokenTicker || createInput.tokenTicker.length === 0) {
@@ -4857,10 +4868,10 @@ function hashTokenTransactionV0(tokenTransaction, partialHash = false) {
4857
4868
  actualLength: createInput.tokenTicker.length
4858
4869
  });
4859
4870
  }
4860
- const tokenTickerBytes = new Uint8Array(6);
4861
4871
  const tokenTickerEncoder = new TextEncoder();
4862
- tokenTickerBytes.set(tokenTickerEncoder.encode(createInput.tokenTicker));
4863
- tokenTickerHashObj.update(tokenTickerBytes);
4872
+ tokenTickerHashObj.update(
4873
+ tokenTickerEncoder.encode(createInput.tokenTicker)
4874
+ );
4864
4875
  allHashes.push(tokenTickerHashObj.digest());
4865
4876
  const decimalsHashObj = sha2568.create();
4866
4877
  const decimalsBytes = new Uint8Array(4);
@@ -4888,8 +4899,9 @@ function hashTokenTransactionV0(tokenTransaction, partialHash = false) {
4888
4899
  maxSupplyHashObj.update(createInput.maxSupply);
4889
4900
  allHashes.push(maxSupplyHashObj.digest());
4890
4901
  const isFreezableHashObj = sha2568.create();
4891
- const isFreezableByte = new Uint8Array([createInput.isFreezable ? 1 : 0]);
4892
- isFreezableHashObj.update(isFreezableByte);
4902
+ isFreezableHashObj.update(
4903
+ new Uint8Array([createInput.isFreezable ? 1 : 0])
4904
+ );
4893
4905
  allHashes.push(isFreezableHashObj.digest());
4894
4906
  const creationEntityHashObj = sha2568.create();
4895
4907
  if (!partialHash && createInput.creationEntityPublicKey) {
@@ -4902,11 +4914,15 @@ function hashTokenTransactionV0(tokenTransaction, partialHash = false) {
4902
4914
  field: "tokenOutputs"
4903
4915
  });
4904
4916
  }
4905
- if (tokenTransaction.tokenOutputs.length === 0 && tokenTransaction.tokenInputs?.$case !== "createInput") {
4906
- throw new ValidationError("token outputs cannot be empty", {
4907
- field: "tokenOutputs"
4908
- });
4909
- }
4917
+ const outputsLenHashObj = sha2568.create();
4918
+ const outputsLenBytes = new Uint8Array(4);
4919
+ new DataView(outputsLenBytes.buffer).setUint32(
4920
+ 0,
4921
+ tokenTransaction.tokenOutputs.length,
4922
+ false
4923
+ );
4924
+ outputsLenHashObj.update(outputsLenBytes);
4925
+ allHashes.push(outputsLenHashObj.digest());
4910
4926
  for (const [i, output] of tokenTransaction.tokenOutputs.entries()) {
4911
4927
  if (!output) {
4912
4928
  throw new ValidationError(`output cannot be null at index ${i}`, {
@@ -4965,18 +4981,16 @@ function hashTokenTransactionV0(tokenTransaction, partialHash = false) {
4965
4981
  );
4966
4982
  hashObj2.update(locktimeBytes);
4967
4983
  }
4968
- if (output.tokenPublicKey) {
4969
- if (output.tokenPublicKey.length === 0) {
4970
- throw new ValidationError(
4971
- `token public key at index ${i} cannot be empty`,
4972
- {
4973
- field: `tokenOutputs[${i}].tokenPublicKey`,
4974
- index: i
4975
- }
4976
- );
4977
- }
4984
+ if (!output.tokenPublicKey || output.tokenPublicKey.length === 0) {
4985
+ hashObj2.update(new Uint8Array(33));
4986
+ } else {
4978
4987
  hashObj2.update(output.tokenPublicKey);
4979
4988
  }
4989
+ if (!output.tokenIdentifier || output.tokenIdentifier.length === 0) {
4990
+ hashObj2.update(new Uint8Array(32));
4991
+ } else {
4992
+ hashObj2.update(output.tokenIdentifier);
4993
+ }
4980
4994
  if (output.tokenAmount) {
4981
4995
  if (output.tokenAmount.length === 0) {
4982
4996
  throw new ValidationError(
@@ -5017,6 +5031,15 @@ function hashTokenTransactionV0(tokenTransaction, partialHash = false) {
5017
5031
  }
5018
5032
  return a.length - b.length;
5019
5033
  });
5034
+ const operatorLenHashObj = sha2568.create();
5035
+ const operatorLenBytes = new Uint8Array(4);
5036
+ new DataView(operatorLenBytes.buffer).setUint32(
5037
+ 0,
5038
+ sortedPubKeys.length,
5039
+ false
5040
+ );
5041
+ operatorLenHashObj.update(operatorLenBytes);
5042
+ allHashes.push(operatorLenHashObj.digest());
5020
5043
  for (const [i, pubKey] of sortedPubKeys.entries()) {
5021
5044
  if (!pubKey) {
5022
5045
  throw new ValidationError(
@@ -5050,6 +5073,38 @@ function hashTokenTransactionV0(tokenTransaction, partialHash = false) {
5050
5073
  );
5051
5074
  hashObj.update(networkBytes);
5052
5075
  allHashes.push(hashObj.digest());
5076
+ const clientTimestampHashObj = sha2568.create();
5077
+ const clientCreatedTs = tokenTransaction.clientCreatedTimestamp;
5078
+ if (!clientCreatedTs) {
5079
+ throw new ValidationError(
5080
+ "client created timestamp cannot be null for V1 token transactions",
5081
+ {
5082
+ field: "clientCreatedTimestamp"
5083
+ }
5084
+ );
5085
+ }
5086
+ const clientUnixTime = clientCreatedTs.getTime();
5087
+ const clientTimestampBytes = new Uint8Array(8);
5088
+ new DataView(clientTimestampBytes.buffer).setBigUint64(
5089
+ 0,
5090
+ BigInt(clientUnixTime),
5091
+ false
5092
+ );
5093
+ clientTimestampHashObj.update(clientTimestampBytes);
5094
+ allHashes.push(clientTimestampHashObj.digest());
5095
+ if (!partialHash) {
5096
+ const expiryHashObj = sha2568.create();
5097
+ const expiryTimeBytes = new Uint8Array(8);
5098
+ const expiryUnixTime = tokenTransaction.expiryTime ? Math.floor(tokenTransaction.expiryTime.getTime() / 1e3) : 0;
5099
+ new DataView(expiryTimeBytes.buffer).setBigUint64(
5100
+ 0,
5101
+ BigInt(expiryUnixTime),
5102
+ false
5103
+ // false for big-endian
5104
+ );
5105
+ expiryHashObj.update(expiryTimeBytes);
5106
+ allHashes.push(expiryHashObj.digest());
5107
+ }
5053
5108
  const finalHashObj = sha2568.create();
5054
5109
  const concatenatedHashes = new Uint8Array(
5055
5110
  allHashes.reduce((sum, hash) => sum + hash.length, 0)
@@ -5062,7 +5117,7 @@ function hashTokenTransactionV0(tokenTransaction, partialHash = false) {
5062
5117
  finalHashObj.update(concatenatedHashes);
5063
5118
  return finalHashObj.digest();
5064
5119
  }
5065
- function hashTokenTransactionV1(tokenTransaction, partialHash = false) {
5120
+ function hashTokenTransactionV2(tokenTransaction, partialHash = false) {
5066
5121
  if (!tokenTransaction) {
5067
5122
  throw new ValidationError("token transaction cannot be nil", {
5068
5123
  field: "tokenTransaction"
@@ -5457,6 +5512,72 @@ function hashTokenTransactionV1(tokenTransaction, partialHash = false) {
5457
5512
  expiryHashObj.update(expiryTimeBytes);
5458
5513
  allHashes.push(expiryHashObj.digest());
5459
5514
  }
5515
+ const attachments = tokenTransaction.invoiceAttachments;
5516
+ const lenHash = sha2568.create();
5517
+ const lenBytes = new Uint8Array(4);
5518
+ new DataView(lenBytes.buffer).setUint32(
5519
+ 0,
5520
+ attachments ? attachments.length : 0,
5521
+ false
5522
+ );
5523
+ lenHash.update(lenBytes);
5524
+ allHashes.push(lenHash.digest());
5525
+ const sortedInvoices = [];
5526
+ if (attachments) {
5527
+ for (let i = 0; i < attachments.length; i++) {
5528
+ const attachment = attachments[i];
5529
+ if (!attachment) {
5530
+ throw new ValidationError(
5531
+ `invoice attachment at index ${i} cannot be null`,
5532
+ {
5533
+ field: `invoiceAttachments[${i}]`,
5534
+ index: i
5535
+ }
5536
+ );
5537
+ }
5538
+ const invoice = attachment.sparkInvoice;
5539
+ let idBytes;
5540
+ try {
5541
+ const decoded = bech32m3.decode(invoice, 500);
5542
+ const payload = SparkAddress.decode(bech32m3.fromWords(decoded.words));
5543
+ if (!payload.sparkInvoiceFields || !payload.sparkInvoiceFields.id) {
5544
+ throw new Error("missing spark invoice fields or id");
5545
+ }
5546
+ idBytes = payload.sparkInvoiceFields.id;
5547
+ } catch (err) {
5548
+ throw new ValidationError(
5549
+ `invalid invoice at ${i}`,
5550
+ {
5551
+ field: `invoiceAttachments[${i}].sparkInvoice`,
5552
+ index: i,
5553
+ value: invoice
5554
+ },
5555
+ err
5556
+ );
5557
+ }
5558
+ if (!idBytes || idBytes.length !== 16) {
5559
+ throw new ValidationError(`invalid invoice id at ${i}`, {
5560
+ field: `invoiceAttachments[${i}].sparkInvoice`,
5561
+ index: i
5562
+ });
5563
+ }
5564
+ sortedInvoices.push({ id: idBytes, raw: invoice });
5565
+ }
5566
+ }
5567
+ sortedInvoices.sort((a, b) => {
5568
+ for (let j = 0; j < a.id.length && j < b.id.length; j++) {
5569
+ const av = a.id[j];
5570
+ const bv = b.id[j];
5571
+ if (av !== bv) return av - bv;
5572
+ }
5573
+ return a.id.length - b.id.length;
5574
+ });
5575
+ const encoder = new TextEncoder();
5576
+ for (const k of sortedInvoices) {
5577
+ const h = sha2568.create();
5578
+ h.update(encoder.encode(k.raw));
5579
+ allHashes.push(h.digest());
5580
+ }
5460
5581
  const finalHashObj = sha2568.create();
5461
5582
  const concatenatedHashes = new Uint8Array(
5462
5583
  allHashes.reduce((sum, hash) => sum + hash.length, 0)
@@ -5469,798 +5590,64 @@ function hashTokenTransactionV1(tokenTransaction, partialHash = false) {
5469
5590
  finalHashObj.update(concatenatedHashes);
5470
5591
  return finalHashObj.digest();
5471
5592
  }
5472
- function hashTokenTransactionV2(tokenTransaction, partialHash = false) {
5473
- if (!tokenTransaction) {
5474
- throw new ValidationError("token transaction cannot be nil", {
5475
- field: "tokenTransaction"
5476
- });
5477
- }
5478
- let allHashes = [];
5479
- const versionHashObj = sha2568.create();
5480
- const versionBytes = new Uint8Array(4);
5481
- new DataView(versionBytes.buffer).setUint32(
5482
- 0,
5483
- tokenTransaction.version,
5484
- false
5485
- // false for big-endian
5486
- );
5487
- versionHashObj.update(versionBytes);
5488
- allHashes.push(versionHashObj.digest());
5489
- const typeHashObj = sha2568.create();
5490
- const typeBytes = new Uint8Array(4);
5491
- let transactionType = 0;
5492
- if (tokenTransaction.tokenInputs?.$case === "mintInput") {
5493
- transactionType = 2 /* TOKEN_TRANSACTION_TYPE_MINT */;
5494
- } else if (tokenTransaction.tokenInputs?.$case === "transferInput") {
5495
- transactionType = 3 /* TOKEN_TRANSACTION_TYPE_TRANSFER */;
5496
- } else if (tokenTransaction.tokenInputs?.$case === "createInput") {
5497
- transactionType = 1 /* TOKEN_TRANSACTION_TYPE_CREATE */;
5498
- } else {
5499
- throw new ValidationError(
5500
- "token transaction must have exactly one input type",
5501
- {
5502
- field: "tokenInputs"
5503
- }
5504
- );
5505
- }
5506
- new DataView(typeBytes.buffer).setUint32(0, transactionType, false);
5507
- typeHashObj.update(typeBytes);
5508
- allHashes.push(typeHashObj.digest());
5509
- if (tokenTransaction.tokenInputs?.$case === "transferInput") {
5510
- if (!tokenTransaction.tokenInputs.transferInput.outputsToSpend) {
5511
- throw new ValidationError("outputs to spend cannot be null", {
5512
- field: "tokenInputs.transferInput.outputsToSpend"
5513
- });
5514
- }
5515
- if (tokenTransaction.tokenInputs.transferInput.outputsToSpend.length === 0) {
5516
- throw new ValidationError("outputs to spend cannot be empty", {
5517
- field: "tokenInputs.transferInput.outputsToSpend"
5518
- });
5519
- }
5520
- const outputsLenHashObj2 = sha2568.create();
5521
- const outputsLenBytes2 = new Uint8Array(4);
5522
- new DataView(outputsLenBytes2.buffer).setUint32(
5523
- 0,
5524
- tokenTransaction.tokenInputs.transferInput.outputsToSpend.length,
5525
- false
5526
- );
5527
- outputsLenHashObj2.update(outputsLenBytes2);
5528
- allHashes.push(outputsLenHashObj2.digest());
5529
- for (const [
5530
- i,
5531
- output
5532
- ] of tokenTransaction.tokenInputs.transferInput.outputsToSpend.entries()) {
5533
- if (!output) {
5534
- throw new ValidationError(`output cannot be null at index ${i}`, {
5535
- field: `tokenInputs.transferInput.outputsToSpend[${i}]`,
5536
- index: i
5537
- });
5538
- }
5539
- const hashObj2 = sha2568.create();
5540
- if (output.prevTokenTransactionHash) {
5541
- const prevHash = output.prevTokenTransactionHash;
5542
- if (output.prevTokenTransactionHash.length !== 32) {
5543
- throw new ValidationError(
5544
- `invalid previous transaction hash length at index ${i}`,
5545
- {
5546
- field: `tokenInputs.transferInput.outputsToSpend[${i}].prevTokenTransactionHash`,
5547
- value: prevHash,
5548
- expectedLength: 32,
5549
- actualLength: prevHash.length,
5550
- index: i
5551
- }
5552
- );
5553
- }
5554
- hashObj2.update(output.prevTokenTransactionHash);
5555
- }
5556
- const voutBytes = new Uint8Array(4);
5557
- new DataView(voutBytes.buffer).setUint32(
5558
- 0,
5559
- output.prevTokenTransactionVout,
5560
- false
5561
- );
5562
- hashObj2.update(voutBytes);
5563
- allHashes.push(hashObj2.digest());
5564
- }
5565
- } else if (tokenTransaction.tokenInputs?.$case === "mintInput") {
5566
- const hashObj2 = sha2568.create();
5567
- if (tokenTransaction.tokenInputs.mintInput.issuerPublicKey) {
5568
- const issuerPubKey = tokenTransaction.tokenInputs.mintInput.issuerPublicKey;
5569
- if (issuerPubKey.length === 0) {
5570
- throw new ValidationError("issuer public key cannot be empty", {
5571
- field: "tokenInputs.mintInput.issuerPublicKey",
5572
- value: issuerPubKey,
5573
- expectedLength: 1,
5574
- actualLength: 0
5575
- });
5576
- }
5577
- hashObj2.update(issuerPubKey);
5578
- allHashes.push(hashObj2.digest());
5579
- const tokenIdentifierHashObj = sha2568.create();
5580
- if (tokenTransaction.tokenInputs.mintInput.tokenIdentifier) {
5581
- tokenIdentifierHashObj.update(
5582
- tokenTransaction.tokenInputs.mintInput.tokenIdentifier
5583
- );
5584
- } else {
5585
- tokenIdentifierHashObj.update(new Uint8Array(32));
5586
- }
5587
- allHashes.push(tokenIdentifierHashObj.digest());
5588
- }
5589
- } else if (tokenTransaction.tokenInputs?.$case === "createInput") {
5590
- const createInput = tokenTransaction.tokenInputs.createInput;
5591
- const issuerPubKeyHashObj = sha2568.create();
5592
- if (!createInput.issuerPublicKey || createInput.issuerPublicKey.length === 0) {
5593
- throw new ValidationError("issuer public key cannot be nil or empty", {
5594
- field: "tokenInputs.createInput.issuerPublicKey"
5595
- });
5596
- }
5597
- issuerPubKeyHashObj.update(createInput.issuerPublicKey);
5598
- allHashes.push(issuerPubKeyHashObj.digest());
5599
- const tokenNameHashObj = sha2568.create();
5600
- if (!createInput.tokenName || createInput.tokenName.length === 0) {
5601
- throw new ValidationError("token name cannot be empty", {
5602
- field: "tokenInputs.createInput.tokenName"
5603
- });
5604
- }
5605
- if (createInput.tokenName.length > 20) {
5606
- throw new ValidationError("token name cannot be longer than 20 bytes", {
5607
- field: "tokenInputs.createInput.tokenName",
5608
- value: createInput.tokenName,
5609
- expectedLength: 20,
5610
- actualLength: createInput.tokenName.length
5611
- });
5612
- }
5613
- const tokenNameEncoder = new TextEncoder();
5614
- tokenNameHashObj.update(tokenNameEncoder.encode(createInput.tokenName));
5615
- allHashes.push(tokenNameHashObj.digest());
5616
- const tokenTickerHashObj = sha2568.create();
5617
- if (!createInput.tokenTicker || createInput.tokenTicker.length === 0) {
5618
- throw new ValidationError("token ticker cannot be empty", {
5619
- field: "tokenInputs.createInput.tokenTicker"
5620
- });
5621
- }
5622
- if (createInput.tokenTicker.length > 6) {
5623
- throw new ValidationError("token ticker cannot be longer than 6 bytes", {
5624
- field: "tokenInputs.createInput.tokenTicker",
5625
- value: createInput.tokenTicker,
5626
- expectedLength: 6,
5627
- actualLength: createInput.tokenTicker.length
5628
- });
5629
- }
5630
- const tokenTickerEncoder = new TextEncoder();
5631
- tokenTickerHashObj.update(
5632
- tokenTickerEncoder.encode(createInput.tokenTicker)
5633
- );
5634
- allHashes.push(tokenTickerHashObj.digest());
5635
- const decimalsHashObj = sha2568.create();
5636
- const decimalsBytes = new Uint8Array(4);
5637
- new DataView(decimalsBytes.buffer).setUint32(
5638
- 0,
5639
- createInput.decimals,
5640
- false
5641
- );
5642
- decimalsHashObj.update(decimalsBytes);
5643
- allHashes.push(decimalsHashObj.digest());
5644
- const maxSupplyHashObj = sha2568.create();
5645
- if (!createInput.maxSupply) {
5646
- throw new ValidationError("max supply cannot be nil", {
5647
- field: "tokenInputs.createInput.maxSupply"
5648
- });
5649
- }
5650
- if (createInput.maxSupply.length !== 16) {
5651
- throw new ValidationError("max supply must be exactly 16 bytes", {
5652
- field: "tokenInputs.createInput.maxSupply",
5653
- value: createInput.maxSupply,
5654
- expectedLength: 16,
5655
- actualLength: createInput.maxSupply.length
5656
- });
5657
- }
5658
- maxSupplyHashObj.update(createInput.maxSupply);
5659
- allHashes.push(maxSupplyHashObj.digest());
5660
- const isFreezableHashObj = sha2568.create();
5661
- isFreezableHashObj.update(
5662
- new Uint8Array([createInput.isFreezable ? 1 : 0])
5663
- );
5664
- allHashes.push(isFreezableHashObj.digest());
5665
- const creationEntityHashObj = sha2568.create();
5666
- if (!partialHash && createInput.creationEntityPublicKey) {
5667
- creationEntityHashObj.update(createInput.creationEntityPublicKey);
5668
- }
5669
- allHashes.push(creationEntityHashObj.digest());
5670
- }
5671
- if (!tokenTransaction.tokenOutputs) {
5672
- throw new ValidationError("token outputs cannot be null", {
5673
- field: "tokenOutputs"
5674
- });
5675
- }
5676
- const outputsLenHashObj = sha2568.create();
5677
- const outputsLenBytes = new Uint8Array(4);
5678
- new DataView(outputsLenBytes.buffer).setUint32(
5679
- 0,
5680
- tokenTransaction.tokenOutputs.length,
5681
- false
5682
- );
5683
- outputsLenHashObj.update(outputsLenBytes);
5684
- allHashes.push(outputsLenHashObj.digest());
5685
- for (const [i, output] of tokenTransaction.tokenOutputs.entries()) {
5686
- if (!output) {
5687
- throw new ValidationError(`output cannot be null at index ${i}`, {
5688
- field: `tokenOutputs[${i}]`,
5689
- index: i
5690
- });
5691
- }
5692
- const hashObj2 = sha2568.create();
5693
- if (output.id && !partialHash) {
5694
- if (output.id.length === 0) {
5695
- throw new ValidationError(`output ID at index ${i} cannot be empty`, {
5696
- field: `tokenOutputs[${i}].id`,
5697
- index: i
5698
- });
5699
- }
5700
- hashObj2.update(new TextEncoder().encode(output.id));
5701
- }
5702
- if (output.ownerPublicKey) {
5703
- if (output.ownerPublicKey.length === 0) {
5704
- throw new ValidationError(
5705
- `owner public key at index ${i} cannot be empty`,
5706
- {
5707
- field: `tokenOutputs[${i}].ownerPublicKey`,
5708
- index: i
5709
- }
5710
- );
5711
- }
5712
- hashObj2.update(output.ownerPublicKey);
5713
- }
5714
- if (!partialHash) {
5715
- const revPubKey = output.revocationCommitment;
5716
- if (revPubKey) {
5717
- if (revPubKey.length === 0) {
5718
- throw new ValidationError(
5719
- `revocation commitment at index ${i} cannot be empty`,
5720
- {
5721
- field: `tokenOutputs[${i}].revocationCommitment`,
5722
- index: i
5723
- }
5724
- );
5725
- }
5726
- hashObj2.update(revPubKey);
5727
- }
5728
- const bondBytes = new Uint8Array(8);
5729
- new DataView(bondBytes.buffer).setBigUint64(
5730
- 0,
5731
- BigInt(output.withdrawBondSats),
5732
- false
5733
- );
5734
- hashObj2.update(bondBytes);
5735
- const locktimeBytes = new Uint8Array(8);
5736
- new DataView(locktimeBytes.buffer).setBigUint64(
5737
- 0,
5738
- BigInt(output.withdrawRelativeBlockLocktime),
5739
- false
5740
- );
5741
- hashObj2.update(locktimeBytes);
5742
- }
5743
- if (!output.tokenPublicKey || output.tokenPublicKey.length === 0) {
5744
- hashObj2.update(new Uint8Array(33));
5745
- } else {
5746
- hashObj2.update(output.tokenPublicKey);
5747
- }
5748
- if (!output.tokenIdentifier || output.tokenIdentifier.length === 0) {
5749
- hashObj2.update(new Uint8Array(32));
5750
- } else {
5751
- hashObj2.update(output.tokenIdentifier);
5752
- }
5753
- if (output.tokenAmount) {
5754
- if (output.tokenAmount.length === 0) {
5755
- throw new ValidationError(
5756
- `token amount at index ${i} cannot be empty`,
5757
- {
5758
- field: `tokenOutputs[${i}].tokenAmount`,
5759
- index: i
5760
- }
5761
- );
5762
- }
5763
- if (output.tokenAmount.length > 16) {
5764
- throw new ValidationError(
5765
- `token amount at index ${i} exceeds maximum length`,
5766
- {
5767
- field: `tokenOutputs[${i}].tokenAmount`,
5768
- value: output.tokenAmount,
5769
- expectedLength: 16,
5770
- actualLength: output.tokenAmount.length,
5771
- index: i
5772
- }
5773
- );
5774
- }
5775
- hashObj2.update(output.tokenAmount);
5776
- }
5777
- allHashes.push(hashObj2.digest());
5778
- }
5779
- if (!tokenTransaction.sparkOperatorIdentityPublicKeys) {
5780
- throw new ValidationError(
5781
- "spark operator identity public keys cannot be null",
5782
- {}
5783
- );
5784
- }
5785
- const sortedPubKeys = [
5786
- ...tokenTransaction.sparkOperatorIdentityPublicKeys || []
5787
- ].sort((a, b) => {
5788
- for (let i = 0; i < a.length && i < b.length; i++) {
5789
- if (a[i] !== b[i]) return a[i] - b[i];
5790
- }
5791
- return a.length - b.length;
5792
- });
5793
- const operatorLenHashObj = sha2568.create();
5794
- const operatorLenBytes = new Uint8Array(4);
5795
- new DataView(operatorLenBytes.buffer).setUint32(
5796
- 0,
5797
- sortedPubKeys.length,
5798
- false
5799
- );
5800
- operatorLenHashObj.update(operatorLenBytes);
5801
- allHashes.push(operatorLenHashObj.digest());
5802
- for (const [i, pubKey] of sortedPubKeys.entries()) {
5803
- if (!pubKey) {
5804
- throw new ValidationError(
5805
- `operator public key at index ${i} cannot be null`,
5806
- {
5807
- field: `sparkOperatorIdentityPublicKeys[${i}]`,
5808
- index: i
5809
- }
5810
- );
5811
- }
5812
- if (pubKey.length === 0) {
5813
- throw new ValidationError(
5814
- `operator public key at index ${i} cannot be empty`,
5815
- {
5816
- field: `sparkOperatorIdentityPublicKeys[${i}]`,
5817
- index: i
5818
- }
5819
- );
5820
- }
5821
- const hashObj2 = sha2568.create();
5822
- hashObj2.update(pubKey);
5823
- allHashes.push(hashObj2.digest());
5824
- }
5825
- const hashObj = sha2568.create();
5826
- let networkBytes = new Uint8Array(4);
5827
- new DataView(networkBytes.buffer).setUint32(
5828
- 0,
5829
- tokenTransaction.network.valueOf(),
5830
- false
5831
- // false for big-endian
5832
- );
5833
- hashObj.update(networkBytes);
5834
- allHashes.push(hashObj.digest());
5835
- const clientTimestampHashObj = sha2568.create();
5836
- const clientCreatedTs = tokenTransaction.clientCreatedTimestamp;
5837
- if (!clientCreatedTs) {
5838
- throw new ValidationError(
5839
- "client created timestamp cannot be null for V1 token transactions",
5840
- {
5841
- field: "clientCreatedTimestamp"
5842
- }
5843
- );
5844
- }
5845
- const clientUnixTime = clientCreatedTs.getTime();
5846
- const clientTimestampBytes = new Uint8Array(8);
5847
- new DataView(clientTimestampBytes.buffer).setBigUint64(
5848
- 0,
5849
- BigInt(clientUnixTime),
5850
- false
5851
- );
5852
- clientTimestampHashObj.update(clientTimestampBytes);
5853
- allHashes.push(clientTimestampHashObj.digest());
5854
- if (!partialHash) {
5855
- const expiryHashObj = sha2568.create();
5856
- const expiryTimeBytes = new Uint8Array(8);
5857
- const expiryUnixTime = tokenTransaction.expiryTime ? Math.floor(tokenTransaction.expiryTime.getTime() / 1e3) : 0;
5858
- new DataView(expiryTimeBytes.buffer).setBigUint64(
5859
- 0,
5860
- BigInt(expiryUnixTime),
5861
- false
5862
- // false for big-endian
5863
- );
5864
- expiryHashObj.update(expiryTimeBytes);
5865
- allHashes.push(expiryHashObj.digest());
5866
- }
5867
- const attachments = tokenTransaction.invoiceAttachments;
5868
- const lenHash = sha2568.create();
5869
- const lenBytes = new Uint8Array(4);
5870
- new DataView(lenBytes.buffer).setUint32(
5871
- 0,
5872
- attachments ? attachments.length : 0,
5873
- false
5874
- );
5875
- lenHash.update(lenBytes);
5876
- allHashes.push(lenHash.digest());
5877
- const sortedInvoices = [];
5878
- if (attachments) {
5879
- for (let i = 0; i < attachments.length; i++) {
5880
- const attachment = attachments[i];
5881
- if (!attachment) {
5882
- throw new ValidationError(
5883
- `invoice attachment at index ${i} cannot be null`,
5884
- {
5885
- field: `invoiceAttachments[${i}]`,
5886
- index: i
5887
- }
5888
- );
5889
- }
5890
- const invoice = attachment.sparkInvoice;
5891
- let idBytes;
5892
- try {
5893
- const decoded = bech32m3.decode(invoice, 500);
5894
- const payload = SparkAddress.decode(bech32m3.fromWords(decoded.words));
5895
- if (!payload.sparkInvoiceFields || !payload.sparkInvoiceFields.id) {
5896
- throw new Error("missing spark invoice fields or id");
5897
- }
5898
- idBytes = payload.sparkInvoiceFields.id;
5899
- } catch (err) {
5900
- throw new ValidationError(
5901
- `invalid invoice at ${i}`,
5902
- {
5903
- field: `invoiceAttachments[${i}].sparkInvoice`,
5904
- index: i,
5905
- value: invoice
5906
- },
5907
- err
5908
- );
5909
- }
5910
- if (!idBytes || idBytes.length !== 16) {
5911
- throw new ValidationError(`invalid invoice id at ${i}`, {
5912
- field: `invoiceAttachments[${i}].sparkInvoice`,
5913
- index: i
5914
- });
5915
- }
5916
- sortedInvoices.push({ id: idBytes, raw: invoice });
5917
- }
5918
- }
5919
- sortedInvoices.sort((a, b) => {
5920
- for (let j = 0; j < a.id.length && j < b.id.length; j++) {
5921
- const av = a.id[j];
5922
- const bv = b.id[j];
5923
- if (av !== bv) return av - bv;
5924
- }
5925
- return a.id.length - b.id.length;
5926
- });
5927
- const encoder = new TextEncoder();
5928
- for (const k of sortedInvoices) {
5929
- const h = sha2568.create();
5930
- h.update(encoder.encode(k.raw));
5931
- allHashes.push(h.digest());
5932
- }
5933
- const finalHashObj = sha2568.create();
5934
- const concatenatedHashes = new Uint8Array(
5935
- allHashes.reduce((sum, hash) => sum + hash.length, 0)
5936
- );
5937
- let offset = 0;
5938
- for (const hash of allHashes) {
5939
- concatenatedHashes.set(hash, offset);
5940
- offset += hash.length;
5941
- }
5942
- finalHashObj.update(concatenatedHashes);
5943
- return finalHashObj.digest();
5944
- }
5945
- function hashOperatorSpecificTokenTransactionSignablePayload(payload) {
5946
- if (!payload) {
5947
- throw new ValidationError(
5948
- "operator specific token transaction signable payload cannot be null",
5949
- {
5950
- field: "payload"
5951
- }
5952
- );
5953
- }
5954
- let allHashes = [];
5955
- if (payload.finalTokenTransactionHash) {
5956
- const hashObj2 = sha2568.create();
5957
- if (payload.finalTokenTransactionHash.length !== 32) {
5958
- throw new ValidationError(`invalid final token transaction hash length`, {
5959
- field: "finalTokenTransactionHash",
5960
- value: payload.finalTokenTransactionHash,
5961
- expectedLength: 32,
5962
- actualLength: payload.finalTokenTransactionHash.length
5963
- });
5964
- }
5965
- hashObj2.update(payload.finalTokenTransactionHash);
5966
- allHashes.push(hashObj2.digest());
5967
- }
5968
- if (!payload.operatorIdentityPublicKey) {
5969
- throw new ValidationError("operator identity public key cannot be null", {
5970
- field: "operatorIdentityPublicKey"
5971
- });
5972
- }
5973
- if (payload.operatorIdentityPublicKey.length === 0) {
5974
- throw new ValidationError("operator identity public key cannot be empty", {
5975
- field: "operatorIdentityPublicKey"
5976
- });
5977
- }
5978
- const hashObj = sha2568.create();
5979
- hashObj.update(payload.operatorIdentityPublicKey);
5980
- allHashes.push(hashObj.digest());
5981
- const finalHashObj = sha2568.create();
5982
- const concatenatedHashes = new Uint8Array(
5983
- allHashes.reduce((sum, hash) => sum + hash.length, 0)
5984
- );
5985
- let offset = 0;
5986
- for (const hash of allHashes) {
5987
- concatenatedHashes.set(hash, offset);
5988
- offset += hash.length;
5989
- }
5990
- finalHashObj.update(concatenatedHashes);
5991
- return finalHashObj.digest();
5992
- }
5993
-
5994
- // src/utils/token-keyshares.ts
5995
- import { secp256k1 as secp256k18 } from "@noble/curves/secp256k1";
5996
- function recoverRevocationSecretFromKeyshares(keyshares, threshold) {
5997
- const shares = keyshares.map((keyshare) => ({
5998
- fieldModulus: BigInt("0x" + secp256k18.CURVE.n.toString(16)),
5999
- // secp256k1 curve order
6000
- threshold,
6001
- index: BigInt(keyshare.operatorIndex),
6002
- share: BigInt(
6003
- "0x" + Buffer.from(keyshare.keyshare.keyshare).toString("hex")
6004
- ),
6005
- proofs: []
6006
- }));
6007
- const recoveredSecret = recoverSecret(shares);
6008
- return bigIntToPrivateKey(recoveredSecret);
6009
- }
6010
-
6011
- // src/utils/token-transaction-validation.ts
6012
- function areByteArraysEqual(a, b) {
6013
- if (a.length !== b.length) {
6014
- return false;
6015
- }
6016
- return a.every((byte, index) => byte === b[index]);
6017
- }
6018
- function hasDuplicates(array) {
6019
- return new Set(array).size !== array.length;
6020
- }
6021
- function validateTokenTransactionV0(finalTokenTransaction, partialTokenTransaction, signingOperators, keyshareInfo, expectedWithdrawBondSats, expectedWithdrawRelativeBlockLocktime, expectedThreshold) {
6022
- if (finalTokenTransaction.network !== partialTokenTransaction.network) {
6023
- throw new InternalValidationError(
6024
- "Network mismatch in response token transaction",
6025
- {
6026
- value: finalTokenTransaction.network,
6027
- expected: partialTokenTransaction.network
6028
- }
6029
- );
6030
- }
6031
- if (!finalTokenTransaction.tokenInputs) {
6032
- throw new InternalValidationError(
6033
- "Token inputs missing in final transaction",
6034
- {
6035
- value: finalTokenTransaction
6036
- }
6037
- );
6038
- }
6039
- if (!partialTokenTransaction.tokenInputs) {
6040
- throw new InternalValidationError(
6041
- "Token inputs missing in partial transaction",
6042
- {
6043
- value: partialTokenTransaction
6044
- }
6045
- );
6046
- }
6047
- if (finalTokenTransaction.tokenInputs.$case !== partialTokenTransaction.tokenInputs.$case) {
6048
- throw new InternalValidationError(
6049
- `Transaction type mismatch: final transaction has ${finalTokenTransaction.tokenInputs.$case}, partial transaction has ${partialTokenTransaction.tokenInputs.$case}`,
6050
- {
6051
- value: finalTokenTransaction.tokenInputs.$case,
6052
- expected: partialTokenTransaction.tokenInputs.$case
6053
- }
6054
- );
6055
- }
6056
- if (finalTokenTransaction.sparkOperatorIdentityPublicKeys.length !== partialTokenTransaction.sparkOperatorIdentityPublicKeys.length) {
6057
- throw new InternalValidationError(
6058
- "Spark operator identity public keys count mismatch",
6059
- {
6060
- value: finalTokenTransaction.sparkOperatorIdentityPublicKeys.length,
6061
- expected: partialTokenTransaction.sparkOperatorIdentityPublicKeys.length
6062
- }
6063
- );
6064
- }
6065
- if (partialTokenTransaction.tokenInputs.$case === "mintInput" && finalTokenTransaction.tokenInputs.$case === "mintInput") {
6066
- const finalMintInput = finalTokenTransaction.tokenInputs.mintInput;
6067
- const partialMintInput = partialTokenTransaction.tokenInputs.mintInput;
6068
- if (!areByteArraysEqual(
6069
- finalMintInput.issuerPublicKey,
6070
- partialMintInput.issuerPublicKey
6071
- )) {
6072
- throw new InternalValidationError(
6073
- "Issuer public key mismatch in mint input",
6074
- {
6075
- value: finalMintInput.issuerPublicKey.toString(),
6076
- expected: partialMintInput.issuerPublicKey.toString()
6077
- }
6078
- );
6079
- }
6080
- } else if (partialTokenTransaction.tokenInputs.$case === "transferInput" && finalTokenTransaction.tokenInputs.$case === "transferInput") {
6081
- const finalTransferInput = finalTokenTransaction.tokenInputs.transferInput;
6082
- const partialTransferInput = partialTokenTransaction.tokenInputs.transferInput;
6083
- if (finalTransferInput.outputsToSpend.length !== partialTransferInput.outputsToSpend.length) {
6084
- throw new InternalValidationError(
6085
- "Outputs to spend count mismatch in transfer input",
6086
- {
6087
- value: finalTransferInput.outputsToSpend.length,
6088
- expected: partialTransferInput.outputsToSpend.length
6089
- }
6090
- );
6091
- }
6092
- for (let i = 0; i < finalTransferInput.outputsToSpend.length; i++) {
6093
- const finalOutput = finalTransferInput.outputsToSpend[i];
6094
- const partialOutput = partialTransferInput.outputsToSpend[i];
6095
- if (!finalOutput) {
6096
- throw new InternalValidationError(
6097
- "Token output to spend missing in final transaction",
6098
- {
6099
- outputIndex: i,
6100
- value: finalOutput
6101
- }
6102
- );
6103
- }
6104
- if (!partialOutput) {
6105
- throw new InternalValidationError(
6106
- "Token output to spend missing in partial transaction",
6107
- {
6108
- outputIndex: i,
6109
- value: partialOutput
6110
- }
6111
- );
6112
- }
6113
- if (!areByteArraysEqual(
6114
- finalOutput.prevTokenTransactionHash,
6115
- partialOutput.prevTokenTransactionHash
6116
- )) {
6117
- throw new InternalValidationError(
6118
- "Previous token transaction hash mismatch in transfer input",
6119
- {
6120
- outputIndex: i,
6121
- value: finalOutput.prevTokenTransactionHash.toString(),
6122
- expected: partialOutput.prevTokenTransactionHash.toString()
6123
- }
6124
- );
6125
- }
6126
- if (finalOutput.prevTokenTransactionVout !== partialOutput.prevTokenTransactionVout) {
6127
- throw new InternalValidationError(
6128
- "Previous token transaction vout mismatch in transfer input",
6129
- {
6130
- outputIndex: i,
6131
- value: finalOutput.prevTokenTransactionVout,
6132
- expected: partialOutput.prevTokenTransactionVout
6133
- }
6134
- );
6135
- }
6136
- }
6137
- }
6138
- if (finalTokenTransaction.tokenOutputs.length !== partialTokenTransaction.tokenOutputs.length) {
6139
- throw new InternalValidationError("Token outputs count mismatch", {
6140
- value: finalTokenTransaction.tokenOutputs.length,
6141
- expected: partialTokenTransaction.tokenOutputs.length
6142
- });
6143
- }
6144
- for (let i = 0; i < finalTokenTransaction.tokenOutputs.length; i++) {
6145
- const finalOutput = finalTokenTransaction.tokenOutputs[i];
6146
- const partialOutput = partialTokenTransaction.tokenOutputs[i];
6147
- if (!finalOutput) {
6148
- throw new InternalValidationError(
6149
- "Token output missing in final transaction",
6150
- {
6151
- outputIndex: i,
6152
- value: finalOutput
6153
- }
6154
- );
6155
- }
6156
- if (!partialOutput) {
6157
- throw new InternalValidationError(
6158
- "Token output missing in partial transaction",
6159
- {
6160
- outputIndex: i,
6161
- value: partialOutput
6162
- }
6163
- );
6164
- }
6165
- if (!areByteArraysEqual(
6166
- finalOutput.ownerPublicKey,
6167
- partialOutput.ownerPublicKey
6168
- )) {
6169
- throw new InternalValidationError(
6170
- "Owner public key mismatch in token output",
6171
- {
6172
- outputIndex: i,
6173
- value: finalOutput.ownerPublicKey.toString(),
6174
- expected: partialOutput.ownerPublicKey.toString()
6175
- }
6176
- );
6177
- }
6178
- if (finalOutput.tokenPublicKey !== void 0 && partialOutput.tokenPublicKey !== void 0 && !areByteArraysEqual(
6179
- finalOutput.tokenPublicKey,
6180
- partialOutput.tokenPublicKey
6181
- )) {
6182
- throw new InternalValidationError(
6183
- "Token public key mismatch in token output",
6184
- {
6185
- outputIndex: i,
6186
- value: finalOutput.tokenPublicKey?.toString(),
6187
- expected: partialOutput.tokenPublicKey?.toString()
6188
- }
6189
- );
6190
- }
6191
- if (!areByteArraysEqual(finalOutput.tokenAmount, partialOutput.tokenAmount)) {
6192
- throw new InternalValidationError(
6193
- "Token amount mismatch in token output",
6194
- {
6195
- outputIndex: i,
6196
- value: finalOutput.tokenAmount.toString(),
6197
- expected: partialOutput.tokenAmount.toString()
6198
- }
6199
- );
6200
- }
6201
- if (finalOutput.withdrawBondSats !== void 0) {
6202
- if (finalOutput.withdrawBondSats !== expectedWithdrawBondSats) {
6203
- throw new InternalValidationError(
6204
- "Withdraw bond sats mismatch in token output",
6205
- {
6206
- outputIndex: i,
6207
- value: finalOutput.withdrawBondSats,
6208
- expected: expectedWithdrawBondSats
6209
- }
6210
- );
6211
- }
6212
- }
6213
- if (finalOutput.withdrawRelativeBlockLocktime !== void 0) {
6214
- if (finalOutput.withdrawRelativeBlockLocktime !== expectedWithdrawRelativeBlockLocktime) {
6215
- throw new InternalValidationError(
6216
- "Withdraw relative block locktime mismatch in token output",
6217
- {
6218
- outputIndex: i,
6219
- value: finalOutput.withdrawRelativeBlockLocktime,
6220
- expected: expectedWithdrawRelativeBlockLocktime
6221
- }
6222
- );
6223
- }
6224
- }
6225
- if (keyshareInfo.threshold !== expectedThreshold) {
6226
- throw new InternalValidationError(
6227
- "Threshold mismatch: expected " + expectedThreshold + " but got " + keyshareInfo.threshold,
6228
- {
6229
- field: "threshold",
6230
- value: keyshareInfo.threshold,
6231
- expected: expectedThreshold
6232
- }
6233
- );
6234
- }
6235
- }
6236
- if (keyshareInfo.ownerIdentifiers.length !== Object.keys(signingOperators).length) {
6237
- throw new InternalValidationError(
6238
- `Keyshare operator count (${keyshareInfo.ownerIdentifiers.length}) does not match signing operator count (${Object.keys(signingOperators).length})`,
6239
- {
6240
- keyshareInfo: keyshareInfo.ownerIdentifiers.length,
6241
- signingOperators: Object.keys(signingOperators).length
6242
- }
6243
- );
6244
- }
6245
- if (hasDuplicates(keyshareInfo.ownerIdentifiers)) {
6246
- throw new InternalValidationError(
6247
- "Duplicate ownerIdentifiers found in keyshareInfo",
5593
+ function hashOperatorSpecificTokenTransactionSignablePayload(payload) {
5594
+ if (!payload) {
5595
+ throw new ValidationError(
5596
+ "operator specific token transaction signable payload cannot be null",
6248
5597
  {
6249
- keyshareInfo: keyshareInfo.ownerIdentifiers
5598
+ field: "payload"
6250
5599
  }
6251
5600
  );
6252
5601
  }
6253
- for (const identifier of keyshareInfo.ownerIdentifiers) {
6254
- if (!signingOperators[identifier]) {
6255
- throw new InternalValidationError(
6256
- `Keyshare operator ${identifier} not found in signing operator list`,
6257
- {
6258
- keyshareInfo: identifier,
6259
- signingOperators: Object.keys(signingOperators)
6260
- }
6261
- );
5602
+ let allHashes = [];
5603
+ if (payload.finalTokenTransactionHash) {
5604
+ const hashObj2 = sha2568.create();
5605
+ if (payload.finalTokenTransactionHash.length !== 32) {
5606
+ throw new ValidationError(`invalid final token transaction hash length`, {
5607
+ field: "finalTokenTransactionHash",
5608
+ value: payload.finalTokenTransactionHash,
5609
+ expectedLength: 32,
5610
+ actualLength: payload.finalTokenTransactionHash.length
5611
+ });
6262
5612
  }
5613
+ hashObj2.update(payload.finalTokenTransactionHash);
5614
+ allHashes.push(hashObj2.digest());
5615
+ }
5616
+ if (!payload.operatorIdentityPublicKey) {
5617
+ throw new ValidationError("operator identity public key cannot be null", {
5618
+ field: "operatorIdentityPublicKey"
5619
+ });
5620
+ }
5621
+ if (payload.operatorIdentityPublicKey.length === 0) {
5622
+ throw new ValidationError("operator identity public key cannot be empty", {
5623
+ field: "operatorIdentityPublicKey"
5624
+ });
5625
+ }
5626
+ const hashObj = sha2568.create();
5627
+ hashObj.update(payload.operatorIdentityPublicKey);
5628
+ allHashes.push(hashObj.digest());
5629
+ const finalHashObj = sha2568.create();
5630
+ const concatenatedHashes = new Uint8Array(
5631
+ allHashes.reduce((sum, hash) => sum + hash.length, 0)
5632
+ );
5633
+ let offset = 0;
5634
+ for (const hash of allHashes) {
5635
+ concatenatedHashes.set(hash, offset);
5636
+ offset += hash.length;
5637
+ }
5638
+ finalHashObj.update(concatenatedHashes);
5639
+ return finalHashObj.digest();
5640
+ }
5641
+
5642
+ // src/utils/token-transaction-validation.ts
5643
+ function areByteArraysEqual(a, b) {
5644
+ if (a.length !== b.length) {
5645
+ return false;
6263
5646
  }
5647
+ return a.every((byte, index) => byte === b[index]);
5648
+ }
5649
+ function hasDuplicates(array) {
5650
+ return new Set(array).size !== array.length;
6264
5651
  }
6265
5652
  function validateTokenTransaction(finalTokenTransaction, partialTokenTransaction, signingOperators, keyshareInfo, expectedWithdrawBondSats, expectedWithdrawRelativeBlockLocktime, expectedThreshold) {
6266
5653
  if (finalTokenTransaction.network !== partialTokenTransaction.network) {
@@ -6614,16 +6001,6 @@ var TokenTransactionService = class {
6614
6001
  tokenIdentifier,
6615
6002
  this.config.getNetworkType()
6616
6003
  ).tokenIdentifier;
6617
- let tokenPublicKey;
6618
- if (this.config.getTokenTransactionVersion() === "V0") {
6619
- const tokenClient = await this.connectionManager.createSparkTokenClient(
6620
- this.config.getCoordinatorAddress()
6621
- );
6622
- const tokenMetadata = await tokenClient.query_token_metadata({
6623
- tokenIdentifiers: [rawTokenIdentifier]
6624
- });
6625
- tokenPublicKey = tokenMetadata.tokenMetadata[0].issuerPublicKey;
6626
- }
6627
6004
  let sparkInvoices = [];
6628
6005
  const tokenOutputData = receiverOutputs.map((transfer) => {
6629
6006
  const receiverAddress = decodeSparkAddress(
@@ -6633,7 +6010,7 @@ var TokenTransactionService = class {
6633
6010
  if (receiverAddress.sparkInvoiceFields) {
6634
6011
  sparkInvoices.push(transfer.receiverSparkAddress);
6635
6012
  }
6636
- if (this.config.getTokenTransactionVersion() !== "V0" && receiverAddress.sparkInvoiceFields) {
6013
+ if (receiverAddress.sparkInvoiceFields) {
6637
6014
  return {
6638
6015
  receiverPublicKey: hexToBytes6(receiverAddress.identityPublicKey),
6639
6016
  rawTokenIdentifier,
@@ -6644,24 +6021,14 @@ var TokenTransactionService = class {
6644
6021
  return {
6645
6022
  receiverPublicKey: hexToBytes6(receiverAddress.identityPublicKey),
6646
6023
  rawTokenIdentifier,
6647
- tokenPublicKey,
6648
- // Remove for full v0 deprecation
6649
6024
  tokenAmount: transfer.tokenAmount
6650
6025
  };
6651
6026
  });
6652
- let tokenTransaction;
6653
- if (this.config.getTokenTransactionVersion() === "V0") {
6654
- tokenTransaction = await this.constructTransferTokenTransactionV0(
6655
- outputsToUse,
6656
- tokenOutputData
6657
- );
6658
- } else {
6659
- tokenTransaction = await this.constructTransferTokenTransaction(
6660
- outputsToUse,
6661
- tokenOutputData,
6662
- sparkInvoices
6663
- );
6664
- }
6027
+ const tokenTransaction = await this.constructTransferTokenTransaction(
6028
+ outputsToUse,
6029
+ tokenOutputData,
6030
+ sparkInvoices
6031
+ );
6665
6032
  const txId = await this.broadcastTokenTransaction(
6666
6033
  tokenTransaction,
6667
6034
  outputsToUse.map((output) => output.output.ownerPublicKey),
@@ -6669,44 +6036,6 @@ var TokenTransactionService = class {
6669
6036
  );
6670
6037
  return txId;
6671
6038
  }
6672
- async constructTransferTokenTransactionV0(selectedOutputs, tokenOutputData) {
6673
- selectedOutputs.sort(
6674
- (a, b) => a.previousTransactionVout - b.previousTransactionVout
6675
- );
6676
- const availableTokenAmount = sumAvailableTokens(selectedOutputs);
6677
- const totalRequestedAmount = tokenOutputData.reduce(
6678
- (sum, output) => sum + output.tokenAmount,
6679
- 0n
6680
- );
6681
- const tokenOutputs = tokenOutputData.map((output) => ({
6682
- ownerPublicKey: output.receiverPublicKey,
6683
- tokenPublicKey: output.tokenPublicKey,
6684
- tokenAmount: numberToBytesBE2(output.tokenAmount, 16)
6685
- }));
6686
- if (availableTokenAmount > totalRequestedAmount) {
6687
- const changeAmount = availableTokenAmount - totalRequestedAmount;
6688
- const firstTokenPublicKey = tokenOutputData[0].tokenPublicKey;
6689
- tokenOutputs.push({
6690
- ownerPublicKey: await this.config.signer.getIdentityPublicKey(),
6691
- tokenPublicKey: firstTokenPublicKey,
6692
- tokenAmount: numberToBytesBE2(changeAmount, 16)
6693
- });
6694
- }
6695
- return {
6696
- network: this.config.getNetworkProto(),
6697
- tokenInputs: {
6698
- $case: "transferInput",
6699
- transferInput: {
6700
- outputsToSpend: selectedOutputs.map((output) => ({
6701
- prevTokenTransactionHash: output.previousTransactionHash,
6702
- prevTokenTransactionVout: output.previousTransactionVout
6703
- }))
6704
- }
6705
- },
6706
- tokenOutputs,
6707
- sparkOperatorIdentityPublicKeys: this.collectOperatorIdentityPublicKeys()
6708
- };
6709
- }
6710
6039
  async constructTransferTokenTransaction(selectedOutputs, tokenOutputData, sparkInvoices) {
6711
6040
  selectedOutputs.sort(
6712
6041
  (a, b) => a.previousTransactionVout - b.previousTransactionVout
@@ -6753,229 +6082,27 @@ var TokenTransactionService = class {
6753
6082
  }
6754
6083
  collectOperatorIdentityPublicKeys() {
6755
6084
  const operatorKeys = [];
6756
- for (const [_, operator] of Object.entries(
6757
- this.config.getSigningOperators()
6758
- )) {
6759
- operatorKeys.push(hexToBytes6(operator.identityPublicKey));
6760
- }
6761
- return operatorKeys;
6762
- }
6763
- async broadcastTokenTransaction(tokenTransaction, outputsToSpendSigningPublicKeys, outputsToSpendCommitments) {
6764
- const signingOperators = this.config.getSigningOperators();
6765
- if (!isTokenTransaction(tokenTransaction)) {
6766
- return this.broadcastTokenTransactionV0(
6767
- tokenTransaction,
6768
- signingOperators,
6769
- outputsToSpendSigningPublicKeys,
6770
- outputsToSpendCommitments
6771
- );
6772
- } else {
6773
- return this.broadcastTokenTransactionV1(
6774
- tokenTransaction,
6775
- signingOperators,
6776
- outputsToSpendSigningPublicKeys,
6777
- outputsToSpendCommitments
6778
- );
6779
- }
6780
- }
6781
- async broadcastTokenTransactionV0(tokenTransaction, signingOperators, outputsToSpendSigningPublicKeys, outputsToSpendCommitments) {
6782
- const { finalTokenTransaction, finalTokenTransactionHash, threshold } = await this.startTokenTransactionV0(
6783
- tokenTransaction,
6784
- signingOperators,
6785
- outputsToSpendSigningPublicKeys,
6786
- outputsToSpendCommitments
6787
- );
6788
- const { successfulSignatures } = await this.signTokenTransactionV0(
6789
- finalTokenTransaction,
6790
- finalTokenTransactionHash,
6791
- signingOperators
6792
- );
6793
- if (finalTokenTransaction.tokenInputs.$case === "transferInput") {
6794
- const outputsToSpend = finalTokenTransaction.tokenInputs.transferInput.outputsToSpend;
6795
- const errors = [];
6796
- const revocationSecrets = [];
6797
- for (let outputIndex = 0; outputIndex < outputsToSpend.length; outputIndex++) {
6798
- const outputKeyshares = successfulSignatures.map(({ identifier, response }) => ({
6799
- operatorIndex: parseInt(identifier, 16),
6800
- keyshare: response.revocationKeyshares[outputIndex]
6801
- }));
6802
- if (outputKeyshares.length < threshold) {
6803
- errors.push(
6804
- new ValidationError("Insufficient keyshares", {
6805
- field: "outputKeyshares",
6806
- value: outputKeyshares.length,
6807
- expected: threshold,
6808
- index: outputIndex
6809
- })
6810
- );
6811
- }
6812
- const seenIndices = /* @__PURE__ */ new Set();
6813
- for (const { operatorIndex } of outputKeyshares) {
6814
- if (seenIndices.has(operatorIndex)) {
6815
- errors.push(
6816
- new ValidationError("Duplicate operator index", {
6817
- field: "outputKeyshares",
6818
- value: operatorIndex,
6819
- expected: "Unique operator index",
6820
- index: outputIndex
6821
- })
6822
- );
6823
- }
6824
- seenIndices.add(operatorIndex);
6825
- }
6826
- const revocationSecret = recoverRevocationSecretFromKeyshares(
6827
- outputKeyshares,
6828
- threshold
6829
- );
6830
- const derivedRevocationCommitment = secp256k19.getPublicKey(
6831
- revocationSecret,
6832
- true
6833
- );
6834
- if (!outputsToSpendCommitments || !outputsToSpendCommitments[outputIndex] || !derivedRevocationCommitment.every(
6835
- (byte, i) => byte === outputsToSpendCommitments[outputIndex][i]
6836
- )) {
6837
- errors.push(
6838
- new InternalValidationError(
6839
- "Revocation commitment verification failed",
6840
- {
6841
- field: "revocationCommitment",
6842
- value: derivedRevocationCommitment,
6843
- expected: bytesToHex6(outputsToSpendCommitments[outputIndex]),
6844
- outputIndex
6845
- }
6846
- )
6847
- );
6848
- }
6849
- revocationSecrets.push({
6850
- inputIndex: outputIndex,
6851
- revocationSecret
6852
- });
6853
- }
6854
- if (errors.length > 0) {
6855
- throw new ValidationError(
6856
- "Multiple validation errors occurred across outputs",
6857
- {
6858
- field: "outputValidation",
6859
- value: errors
6860
- }
6861
- );
6862
- }
6863
- await this.finalizeTokenTransaction(
6864
- finalTokenTransaction,
6865
- revocationSecrets,
6866
- threshold
6867
- );
6868
- }
6869
- return bytesToHex6(finalTokenTransactionHash);
6870
- }
6871
- async broadcastTokenTransactionV1(tokenTransaction, signingOperators, outputsToSpendSigningPublicKeys, outputsToSpendCommitments) {
6872
- const { finalTokenTransaction, finalTokenTransactionHash, threshold } = await this.startTokenTransaction(
6873
- tokenTransaction,
6874
- signingOperators,
6875
- outputsToSpendSigningPublicKeys,
6876
- outputsToSpendCommitments
6877
- );
6878
- await this.signTokenTransaction(
6879
- finalTokenTransaction,
6880
- finalTokenTransactionHash,
6881
- signingOperators
6882
- );
6883
- return bytesToHex6(finalTokenTransactionHash);
6884
- }
6885
- async startTokenTransactionV0(tokenTransaction, signingOperators, outputsToSpendSigningPublicKeys, outputsToSpendCommitments) {
6886
- const sparkClient = await this.connectionManager.createSparkClient(
6887
- this.config.getCoordinatorAddress()
6888
- );
6889
- const partialTokenTransactionHash = hashTokenTransactionV0(
6890
- tokenTransaction,
6891
- true
6892
- );
6893
- const ownerSignaturesWithIndex = [];
6894
- if (tokenTransaction.tokenInputs.$case === "mintInput") {
6895
- const issuerPublicKey = tokenTransaction.tokenInputs.mintInput.issuerPublicKey;
6896
- if (!issuerPublicKey) {
6897
- throw new ValidationError("Invalid mint input", {
6898
- field: "issuerPublicKey",
6899
- value: null,
6900
- expected: "Non-null issuer public key"
6901
- });
6902
- }
6903
- const ownerSignature = await this.signMessageWithKey(
6904
- partialTokenTransactionHash,
6905
- issuerPublicKey
6906
- );
6907
- ownerSignaturesWithIndex.push({
6908
- signature: ownerSignature,
6909
- inputIndex: 0
6910
- });
6911
- } else if (tokenTransaction.tokenInputs.$case === "transferInput") {
6912
- if (!outputsToSpendSigningPublicKeys || !outputsToSpendCommitments) {
6913
- throw new ValidationError("Invalid transfer input", {
6914
- field: "outputsToSpend",
6915
- value: {
6916
- signingPublicKeys: outputsToSpendSigningPublicKeys,
6917
- revocationPublicKeys: outputsToSpendCommitments
6918
- },
6919
- expected: "Non-null signing and revocation public keys"
6920
- });
6921
- }
6922
- for (const [i, key] of outputsToSpendSigningPublicKeys.entries()) {
6923
- if (!key) {
6924
- throw new ValidationError("Invalid signing key", {
6925
- field: "outputsToSpendSigningPublicKeys",
6926
- value: i,
6927
- expected: "Non-null signing key"
6928
- });
6929
- }
6930
- const ownerSignature = await this.signMessageWithKey(
6931
- partialTokenTransactionHash,
6932
- key
6933
- );
6934
- ownerSignaturesWithIndex.push({
6935
- signature: ownerSignature,
6936
- inputIndex: i
6937
- });
6938
- }
6939
- }
6940
- const startResponse = await sparkClient.start_token_transaction(
6941
- {
6942
- identityPublicKey: await this.config.signer.getIdentityPublicKey(),
6943
- partialTokenTransaction: tokenTransaction,
6944
- tokenTransactionSignatures: {
6945
- ownerSignatures: ownerSignaturesWithIndex
6946
- }
6947
- },
6948
- {
6949
- retry: true,
6950
- retryableStatuses: ["UNKNOWN", "UNAVAILABLE", "CANCELLED", "INTERNAL"],
6951
- retryMaxAttempts: 3
6952
- }
6953
- );
6954
- if (!startResponse.finalTokenTransaction) {
6955
- throw new Error("Final token transaction missing in start response");
6956
- }
6957
- if (!startResponse.keyshareInfo) {
6958
- throw new Error("Keyshare info missing in start response");
6085
+ for (const [_, operator] of Object.entries(
6086
+ this.config.getSigningOperators()
6087
+ )) {
6088
+ operatorKeys.push(hexToBytes6(operator.identityPublicKey));
6959
6089
  }
6960
- validateTokenTransactionV0(
6961
- startResponse.finalTokenTransaction,
6090
+ return operatorKeys;
6091
+ }
6092
+ async broadcastTokenTransaction(tokenTransaction, outputsToSpendSigningPublicKeys, outputsToSpendCommitments) {
6093
+ const signingOperators = this.config.getSigningOperators();
6094
+ const { finalTokenTransaction, finalTokenTransactionHash, threshold } = await this.startTokenTransaction(
6962
6095
  tokenTransaction,
6963
6096
  signingOperators,
6964
- startResponse.keyshareInfo,
6965
- this.config.getExpectedWithdrawBondSats(),
6966
- this.config.getExpectedWithdrawRelativeBlockLocktime(),
6967
- this.config.getThreshold()
6968
- );
6969
- const finalTokenTransaction = startResponse.finalTokenTransaction;
6970
- const finalTokenTransactionHash = hashTokenTransactionV0(
6971
- finalTokenTransaction,
6972
- false
6097
+ outputsToSpendSigningPublicKeys,
6098
+ outputsToSpendCommitments
6973
6099
  );
6974
- return {
6100
+ await this.signTokenTransaction(
6975
6101
  finalTokenTransaction,
6976
6102
  finalTokenTransactionHash,
6977
- threshold: startResponse.keyshareInfo.threshold
6978
- };
6103
+ signingOperators
6104
+ );
6105
+ return bytesToHex6(finalTokenTransactionHash);
6979
6106
  }
6980
6107
  async startTokenTransaction(tokenTransaction, signingOperators, outputsToSpendSigningPublicKeys, outputsToSpendCommitments) {
6981
6108
  const sparkClient = await this.connectionManager.createSparkTokenClient(
@@ -7096,103 +6223,6 @@ var TokenTransactionService = class {
7096
6223
  threshold: startResponse.keyshareInfo.threshold
7097
6224
  };
7098
6225
  }
7099
- async signTokenTransactionV0(finalTokenTransaction, finalTokenTransactionHash, signingOperators) {
7100
- const soSignatures = await Promise.allSettled(
7101
- Object.entries(signingOperators).map(
7102
- async ([identifier, operator], index) => {
7103
- const internalSparkClient = await this.connectionManager.createSparkClient(operator.address);
7104
- const identityPublicKey = await this.config.signer.getIdentityPublicKey();
7105
- const payload = {
7106
- finalTokenTransactionHash,
7107
- operatorIdentityPublicKey: hexToBytes6(operator.identityPublicKey)
7108
- };
7109
- const payloadHash = await hashOperatorSpecificTokenTransactionSignablePayload(payload);
7110
- let operatorSpecificSignatures = [];
7111
- if (finalTokenTransaction.tokenInputs.$case === "mintInput") {
7112
- const issuerPublicKey = finalTokenTransaction.tokenInputs.mintInput.issuerPublicKey;
7113
- if (!issuerPublicKey) {
7114
- throw new ValidationError("Invalid mint input", {
7115
- field: "issuerPublicKey",
7116
- value: null,
7117
- expected: "Non-null issuer public key"
7118
- });
7119
- }
7120
- const ownerSignature = await this.signMessageWithKey(
7121
- payloadHash,
7122
- issuerPublicKey
7123
- );
7124
- operatorSpecificSignatures.push({
7125
- ownerSignature: {
7126
- signature: ownerSignature,
7127
- inputIndex: 0
7128
- },
7129
- payload
7130
- });
7131
- }
7132
- if (finalTokenTransaction.tokenInputs.$case === "transferInput") {
7133
- const transferInput = finalTokenTransaction.tokenInputs.transferInput;
7134
- for (let i = 0; i < transferInput.outputsToSpend.length; i++) {
7135
- let ownerSignature;
7136
- if (this.config.getTokenSignatures() === "SCHNORR") {
7137
- ownerSignature = await this.config.signer.signSchnorrWithIdentityKey(
7138
- payloadHash
7139
- );
7140
- } else {
7141
- ownerSignature = await this.config.signer.signMessageWithIdentityKey(
7142
- payloadHash
7143
- );
7144
- }
7145
- operatorSpecificSignatures.push({
7146
- ownerSignature: {
7147
- signature: ownerSignature,
7148
- inputIndex: i
7149
- },
7150
- payload
7151
- });
7152
- }
7153
- }
7154
- try {
7155
- const response = await internalSparkClient.sign_token_transaction(
7156
- {
7157
- finalTokenTransaction,
7158
- operatorSpecificSignatures,
7159
- identityPublicKey
7160
- },
7161
- {
7162
- retry: true,
7163
- retryableStatuses: [
7164
- "UNKNOWN",
7165
- "UNAVAILABLE",
7166
- "CANCELLED",
7167
- "INTERNAL"
7168
- ],
7169
- retryMaxAttempts: 3
7170
- }
7171
- );
7172
- return {
7173
- index,
7174
- identifier,
7175
- response
7176
- };
7177
- } catch (error) {
7178
- throw new NetworkError(
7179
- "Failed to sign token transaction",
7180
- {
7181
- operation: "sign_token_transaction",
7182
- errorCount: 1,
7183
- errors: error instanceof Error ? error.message : String(error)
7184
- },
7185
- error
7186
- );
7187
- }
7188
- }
7189
- )
7190
- );
7191
- const successfulSignatures = collectResponses(soSignatures);
7192
- return {
7193
- successfulSignatures
7194
- };
7195
- }
7196
6226
  async signTokenTransaction(finalTokenTransaction, finalTokenTransactionHash, signingOperators) {
7197
6227
  const coordinatorClient = await this.connectionManager.createSparkTokenClient(
7198
6228
  this.config.getCoordinatorAddress()
@@ -7264,54 +6294,6 @@ var TokenTransactionService = class {
7264
6294
  );
7265
6295
  }
7266
6296
  }
7267
- if (this.config.getTokenTransactionVersion() === "V0") {
7268
- return this.fetchOwnedTokenOutputsV0(params);
7269
- } else {
7270
- return this.fetchOwnedTokenOutputsV1(params);
7271
- }
7272
- }
7273
- async queryTokenTransactions(params) {
7274
- if (this.config.getTokenTransactionVersion() === "V0") {
7275
- return this.queryTokenTransactionsV0(params);
7276
- } else {
7277
- return this.queryTokenTransactionsV1(params);
7278
- }
7279
- }
7280
- async fetchOwnedTokenOutputsV0(params) {
7281
- const {
7282
- ownerPublicKeys,
7283
- issuerPublicKeys: tokenPublicKeys = [],
7284
- tokenIdentifiers = []
7285
- } = params;
7286
- const sparkClient = await this.connectionManager.createSparkClient(
7287
- this.config.getCoordinatorAddress()
7288
- );
7289
- try {
7290
- const result = await sparkClient.query_token_outputs({
7291
- ownerPublicKeys,
7292
- tokenPublicKeys,
7293
- tokenIdentifiers,
7294
- network: this.config.getNetworkProto()
7295
- });
7296
- return result.outputsWithPreviousTransactionData;
7297
- } catch (error) {
7298
- throw new NetworkError(
7299
- "Failed to fetch owned token outputs",
7300
- {
7301
- operation: "spark.query_token_outputs",
7302
- errorCount: 1,
7303
- errors: error instanceof Error ? error.message : String(error)
7304
- },
7305
- error
7306
- );
7307
- }
7308
- }
7309
- async fetchOwnedTokenOutputsV1(params) {
7310
- const {
7311
- ownerPublicKeys,
7312
- issuerPublicKeys = [],
7313
- tokenIdentifiers = []
7314
- } = params;
7315
6297
  const tokenClient = await this.connectionManager.createSparkTokenClient(
7316
6298
  this.config.getCoordinatorAddress()
7317
6299
  );
@@ -7352,75 +6334,7 @@ var TokenTransactionService = class {
7352
6334
  );
7353
6335
  }
7354
6336
  }
7355
- async queryTokenTransactionsV0(params) {
7356
- const {
7357
- ownerPublicKeys,
7358
- issuerPublicKeys,
7359
- tokenTransactionHashes,
7360
- tokenIdentifiers,
7361
- outputIds,
7362
- pageSize,
7363
- offset
7364
- } = params;
7365
- const sparkClient = await this.connectionManager.createSparkClient(
7366
- this.config.getCoordinatorAddress()
7367
- );
7368
- let queryParams = {
7369
- tokenPublicKeys: issuerPublicKeys?.map(hexToBytes6),
7370
- ownerPublicKeys: ownerPublicKeys?.map(hexToBytes6),
7371
- tokenIdentifiers: tokenIdentifiers?.map((identifier) => {
7372
- const { tokenIdentifier } = decodeBech32mTokenIdentifier(
7373
- identifier,
7374
- this.config.getNetworkType()
7375
- );
7376
- return tokenIdentifier;
7377
- }),
7378
- tokenTransactionHashes: tokenTransactionHashes?.map(hexToBytes6),
7379
- outputIds: outputIds || [],
7380
- limit: pageSize,
7381
- offset
7382
- };
7383
- try {
7384
- const response = await sparkClient.query_token_transactions(queryParams);
7385
- return {
7386
- tokenTransactionsWithStatus: response.tokenTransactionsWithStatus.map(
7387
- (tx) => {
7388
- const v1TokenTransaction = {
7389
- version: 1,
7390
- network: tx.tokenTransaction.network,
7391
- tokenInputs: tx.tokenTransaction.tokenInputs,
7392
- tokenOutputs: tx.tokenTransaction.tokenOutputs,
7393
- sparkOperatorIdentityPublicKeys: tx.tokenTransaction.sparkOperatorIdentityPublicKeys,
7394
- expiryTime: void 0,
7395
- // V0 doesn't have expiry time
7396
- clientCreatedTimestamp: tx.tokenTransaction?.tokenInputs?.$case === "mintInput" ? new Date(
7397
- tx.tokenTransaction.tokenInputs.mintInput.issuerProvidedTimestamp * 1e3
7398
- ) : /* @__PURE__ */ new Date(),
7399
- invoiceAttachments: []
7400
- };
7401
- return {
7402
- tokenTransaction: v1TokenTransaction,
7403
- status: tx.status,
7404
- confirmationMetadata: tx.confirmationMetadata,
7405
- tokenTransactionHash: tx.tokenTransactionHash
7406
- };
7407
- }
7408
- ),
7409
- offset: response.offset
7410
- };
7411
- } catch (error) {
7412
- throw new NetworkError(
7413
- "Failed to query token transactions",
7414
- {
7415
- operation: "spark.query_token_transactions",
7416
- errorCount: 1,
7417
- errors: error instanceof Error ? error.message : String(error)
7418
- },
7419
- error
7420
- );
7421
- }
7422
- }
7423
- async queryTokenTransactionsV1(params) {
6337
+ async queryTokenTransactions(params) {
7424
6338
  const {
7425
6339
  ownerPublicKeys,
7426
6340
  issuerPublicKeys,
@@ -7533,50 +6447,6 @@ var TokenTransactionService = class {
7533
6447
  });
7534
6448
  }
7535
6449
  }
7536
- async finalizeTokenTransaction(finalTokenTransaction, revocationSecrets, threshold) {
7537
- const signingOperators = this.config.getSigningOperators();
7538
- const soResponses = await Promise.allSettled(
7539
- Object.entries(signingOperators).map(async ([identifier, operator]) => {
7540
- const internalSparkClient = await this.connectionManager.createSparkClient(operator.address);
7541
- const identityPublicKey = await this.config.signer.getIdentityPublicKey();
7542
- try {
7543
- const response = await internalSparkClient.finalize_token_transaction(
7544
- {
7545
- finalTokenTransaction,
7546
- revocationSecrets,
7547
- identityPublicKey
7548
- },
7549
- {
7550
- retry: true,
7551
- retryableStatuses: [
7552
- "UNKNOWN",
7553
- "UNAVAILABLE",
7554
- "CANCELLED",
7555
- "INTERNAL"
7556
- ],
7557
- retryMaxAttempts: 3
7558
- }
7559
- );
7560
- return {
7561
- identifier,
7562
- response
7563
- };
7564
- } catch (error) {
7565
- throw new NetworkError(
7566
- "Failed to finalize token transaction",
7567
- {
7568
- operation: "finalize_token_transaction",
7569
- errorCount: 1,
7570
- errors: error instanceof Error ? error.message : String(error)
7571
- },
7572
- error
7573
- );
7574
- }
7575
- })
7576
- );
7577
- collectResponses(soResponses);
7578
- return finalTokenTransaction;
7579
- }
7580
6450
  async createSignaturesForOperators(finalTokenTransaction, finalTokenTransactionHash, signingOperators) {
7581
6451
  const inputTtxoSignaturesPerOperator = [];
7582
6452
  for (const [_, operator] of Object.entries(signingOperators)) {
@@ -7653,28 +6523,25 @@ var TokenTransactionService = class {
7653
6523
  return inputTtxoSignaturesPerOperator;
7654
6524
  }
7655
6525
  };
7656
- function isTokenTransaction(tokenTransaction) {
7657
- return "version" in tokenTransaction && "expiryTime" in tokenTransaction;
7658
- }
7659
6526
 
7660
6527
  // src/utils/adaptor-signature.ts
7661
6528
  import { mod } from "@noble/curves/abstract/modular";
7662
- import { schnorr as schnorr5, secp256k1 as secp256k110 } from "@noble/curves/secp256k1";
6529
+ import { schnorr as schnorr5, secp256k1 as secp256k18 } from "@noble/curves/secp256k1";
7663
6530
  import { bytesToNumberBE as bytesToNumberBE6, numberToBytesBE as numberToBytesBE3 } from "@noble/curves/utils";
7664
6531
  function generateSignatureFromExistingAdaptor(signature, adaptorPrivateKeyBytes) {
7665
6532
  const { r, s } = parseSignature(signature);
7666
6533
  const sBigInt = bytesToNumberBE6(s);
7667
6534
  const tBigInt = bytesToNumberBE6(adaptorPrivateKeyBytes);
7668
- const newS = mod(sBigInt - tBigInt, secp256k110.CURVE.n);
6535
+ const newS = mod(sBigInt - tBigInt, secp256k18.CURVE.n);
7669
6536
  const newSignature = new Uint8Array([...r, ...numberToBytesBE3(newS, 32)]);
7670
6537
  return newSignature;
7671
6538
  }
7672
6539
  function generateAdaptorFromSignature(signature) {
7673
- const adaptorPrivateKey = secp256k110.utils.randomPrivateKey();
6540
+ const adaptorPrivateKey = secp256k18.utils.randomPrivateKey();
7674
6541
  const { r, s } = parseSignature(signature);
7675
6542
  const sBigInt = bytesToNumberBE6(s);
7676
6543
  const tBigInt = bytesToNumberBE6(adaptorPrivateKey);
7677
- const newS = mod(sBigInt - tBigInt, secp256k110.CURVE.n);
6544
+ const newS = mod(sBigInt - tBigInt, secp256k18.CURVE.n);
7678
6545
  const newSignature = new Uint8Array([...r, ...numberToBytesBE3(newS, 32)]);
7679
6546
  return {
7680
6547
  adaptorSignature: newSignature,
@@ -7694,7 +6561,7 @@ function applyAdaptorToSignature(pubkey, hash, signature, adaptorPrivateKeyBytes
7694
6561
  const { r, s } = parseSignature(signature);
7695
6562
  const sBigInt = bytesToNumberBE6(s);
7696
6563
  const adaptorPrivateKey = bytesToNumberBE6(adaptorPrivateKeyBytes);
7697
- const newS = mod(sBigInt + adaptorPrivateKey, secp256k110.CURVE.n);
6564
+ const newS = mod(sBigInt + adaptorPrivateKey, secp256k18.CURVE.n);
7698
6565
  const newSig = new Uint8Array([...r, ...numberToBytesBE3(newS, 32)]);
7699
6566
  try {
7700
6567
  if (schnorr5.verify(newSig, hash, pubkey)) {
@@ -7703,7 +6570,7 @@ function applyAdaptorToSignature(pubkey, hash, signature, adaptorPrivateKeyBytes
7703
6570
  } catch (e) {
7704
6571
  console.error("[applyAdaptorToSignature] Addition verification failed:", e);
7705
6572
  }
7706
- const altS = mod(sBigInt - adaptorPrivateKey, secp256k110.CURVE.n);
6573
+ const altS = mod(sBigInt - adaptorPrivateKey, secp256k18.CURVE.n);
7707
6574
  const altSig = new Uint8Array([...r, ...numberToBytesBE3(altS, 32)]);
7708
6575
  try {
7709
6576
  if (schnorr5.verify(altSig, hash, pubkey)) {
@@ -7733,18 +6600,18 @@ function schnorrVerifyWithAdaptor(signature, hash, pubKeyBytes, adaptorPubkey, i
7733
6600
  if (commitmenet.length > 32) {
7734
6601
  throw new Error("hash of (r || P || m) too big");
7735
6602
  }
7736
- const e = mod(bytesToNumberBE6(commitmenet), secp256k110.CURVE.n);
7737
- const negE = mod(-e, secp256k110.CURVE.n);
7738
- const sG = secp256k110.Point.BASE.multiplyUnsafe(bytesToNumberBE6(s));
6603
+ const e = mod(bytesToNumberBE6(commitmenet), secp256k18.CURVE.n);
6604
+ const negE = mod(-e, secp256k18.CURVE.n);
6605
+ const sG = secp256k18.Point.BASE.multiplyUnsafe(bytesToNumberBE6(s));
7739
6606
  const eP = pubKey.multiplyUnsafe(negE);
7740
6607
  const R = sG.add(eP);
7741
6608
  if (R.is0()) {
7742
6609
  throw new Error("R is zero");
7743
6610
  }
7744
6611
  R.assertValidity();
7745
- const adaptorPoint = secp256k110.Point.fromHex(adaptorPubkey);
6612
+ const adaptorPoint = secp256k18.Point.fromHex(adaptorPubkey);
7746
6613
  const newR = R.add(adaptorPoint);
7747
- if (!inbound && newR.equals(secp256k110.Point.ZERO)) {
6614
+ if (!inbound && newR.equals(secp256k18.Point.ZERO)) {
7748
6615
  throw new Error("calculated R point is the point at infinity");
7749
6616
  }
7750
6617
  newR.assertValidity();
@@ -7772,23 +6639,23 @@ function parseSignature(signature) {
7772
6639
  }
7773
6640
  const r = signature.slice(0, 32);
7774
6641
  const s = signature.slice(32, 64);
7775
- if (bytesToNumberBE6(r) >= secp256k110.CURVE.Fp.ORDER) {
6642
+ if (bytesToNumberBE6(r) >= secp256k18.CURVE.Fp.ORDER) {
7776
6643
  throw new ValidationError("Invalid signature: r >= field prime", {
7777
6644
  rValue: bytesToNumberBE6(r),
7778
- fieldPrime: secp256k110.CURVE.Fp.ORDER
6645
+ fieldPrime: secp256k18.CURVE.Fp.ORDER
7779
6646
  });
7780
6647
  }
7781
- if (bytesToNumberBE6(s) >= secp256k110.CURVE.n) {
6648
+ if (bytesToNumberBE6(s) >= secp256k18.CURVE.n) {
7782
6649
  throw new ValidationError("Invalid signature: s >= group order", {
7783
6650
  sValue: bytesToNumberBE6(s),
7784
- groupOrder: secp256k110.CURVE.n
6651
+ groupOrder: secp256k18.CURVE.n
7785
6652
  });
7786
6653
  }
7787
6654
  return { r, s };
7788
6655
  }
7789
6656
 
7790
6657
  // src/tests/utils/test-faucet.ts
7791
- import { schnorr as schnorr6, secp256k1 as secp256k111 } from "@noble/curves/secp256k1";
6658
+ import { schnorr as schnorr6, secp256k1 as secp256k19 } from "@noble/curves/secp256k1";
7792
6659
  import { bytesToHex as bytesToHex7, hexToBytes as hexToBytes7 } from "@noble/curves/utils";
7793
6660
  import * as btc3 from "@scure/btc-signer";
7794
6661
  import { Address as Address2, OutScript as OutScript2, SigHash as SigHash2, Transaction as Transaction4 } from "@scure/btc-signer";
@@ -7832,7 +6699,7 @@ var BitcoinFaucet = class _BitcoinFaucet {
7832
6699
  this.username = username;
7833
6700
  this.password = password;
7834
6701
  this.miningAddress = getP2TRAddressFromPublicKey(
7835
- secp256k111.getPublicKey(STATIC_MINING_KEY),
6702
+ secp256k19.getPublicKey(STATIC_MINING_KEY),
7836
6703
  4 /* LOCAL */
7837
6704
  );
7838
6705
  }
@@ -7871,7 +6738,7 @@ var BitcoinFaucet = class _BitcoinFaucet {
7871
6738
  });
7872
6739
  }
7873
6740
  async refill() {
7874
- const minerPubKey = secp256k111.getPublicKey(STATIC_MINING_KEY);
6741
+ const minerPubKey = secp256k19.getPublicKey(STATIC_MINING_KEY);
7875
6742
  const address2 = getP2TRAddressFromPublicKey(minerPubKey, 4 /* LOCAL */);
7876
6743
  const scanResult = await this.call("scantxoutset", [
7877
6744
  "start",
@@ -7920,7 +6787,7 @@ var BitcoinFaucet = class _BitcoinFaucet {
7920
6787
  txid: selectedUtxo.txid,
7921
6788
  index: selectedUtxo.vout
7922
6789
  });
7923
- const faucetPubKey = secp256k111.getPublicKey(STATIC_FAUCET_KEY);
6790
+ const faucetPubKey = secp256k19.getPublicKey(STATIC_FAUCET_KEY);
7924
6791
  const script = getP2TRScriptFromPublicKey(faucetPubKey, 4 /* LOCAL */);
7925
6792
  for (let i = 0; i < numCoinsToCreate; i++) {
7926
6793
  splitTx.addOutput({
@@ -7981,7 +6848,7 @@ var BitcoinFaucet = class _BitcoinFaucet {
7981
6848
  await this.broadcastTx(bytesToHex7(signedTx.extract()));
7982
6849
  }
7983
6850
  async signFaucetCoin(unsignedTx, fundingTxOut, key) {
7984
- const pubKey = secp256k111.getPublicKey(key);
6851
+ const pubKey = secp256k19.getPublicKey(key);
7985
6852
  const internalKey = pubKey.slice(1);
7986
6853
  const script = getP2TRScriptFromPublicKey(pubKey, 4 /* LOCAL */);
7987
6854
  unsignedTx.updateInput(0, {
@@ -8064,8 +6931,8 @@ var BitcoinFaucet = class _BitcoinFaucet {
8064
6931
  return response;
8065
6932
  }
8066
6933
  async getNewAddress() {
8067
- const key = secp256k111.utils.randomPrivateKey();
8068
- const pubKey = secp256k111.getPublicKey(key);
6934
+ const key = secp256k19.utils.randomPrivateKey();
6935
+ const pubKey = secp256k19.getPublicKey(key);
8069
6936
  return getP2TRAddressFromPublicKey(pubKey, 4 /* LOCAL */);
8070
6937
  }
8071
6938
  async sendToAddress(address2, amount, blocksToGenerate = 1) {
@@ -8086,8 +6953,8 @@ var BitcoinFaucet = class _BitcoinFaucet {
8086
6953
  });
8087
6954
  const changeAmount = availableAmount - amount;
8088
6955
  if (changeAmount > 0) {
8089
- const changeKey = secp256k111.utils.randomPrivateKey();
8090
- const changePubKey = secp256k111.getPublicKey(changeKey);
6956
+ const changeKey = secp256k19.utils.randomPrivateKey();
6957
+ const changePubKey = secp256k19.getPublicKey(changeKey);
8091
6958
  const changeScript = getP2TRScriptFromPublicKey(
8092
6959
  changePubKey,
8093
6960
  4 /* LOCAL */
@@ -8100,8 +6967,8 @@ var BitcoinFaucet = class _BitcoinFaucet {
8100
6967
  const signedTx = await this.signFaucetCoin(tx, coin.txout, coin.key);
8101
6968
  const txHex = bytesToHex7(signedTx.extract());
8102
6969
  await this.broadcastTx(txHex);
8103
- const randomKey = secp256k111.utils.randomPrivateKey();
8104
- const randomPubKey = secp256k111.getPublicKey(randomKey);
6970
+ const randomKey = secp256k19.utils.randomPrivateKey();
6971
+ const randomPubKey = secp256k19.getPublicKey(randomKey);
8105
6972
  const randomAddress = getP2TRAddressFromPublicKey(
8106
6973
  randomPubKey,
8107
6974
  4 /* LOCAL */
@@ -8126,19 +6993,18 @@ var SparkWalletEvent = {
8126
6993
 
8127
6994
  // src/spark-wallet/spark-wallet.ts
8128
6995
  import { isNode as isNode3, isObject as isObject2, mapCurrencyAmount } from "@lightsparkdev/core";
8129
- import { secp256k1 as secp256k114 } from "@noble/curves/secp256k1";
6996
+ import { secp256k1 as secp256k112 } from "@noble/curves/secp256k1";
8130
6997
  import {
8131
6998
  bytesToHex as bytesToHex10,
8132
6999
  bytesToNumberBE as bytesToNumberBE8,
8133
7000
  equalBytes as equalBytes6,
8134
- hexToBytes as hexToBytes11,
8135
- numberToVarBytesBE
7001
+ hexToBytes as hexToBytes11
8136
7002
  } from "@noble/curves/utils";
8137
7003
  import { validateMnemonic } from "@scure/bip39";
8138
7004
  import { wordlist as wordlist2 } from "@scure/bip39/wordlists/english";
8139
7005
  import { Address as Address3, OutScript as OutScript3, Transaction as Transaction7 } from "@scure/btc-signer";
8140
7006
  import { Mutex } from "async-mutex";
8141
- import { uuidv7 as uuidv74, uuidv7obj } from "uuidv7";
7007
+ import { uuidv7 as uuidv74 } from "uuidv7";
8142
7008
 
8143
7009
  // src/graphql/client.ts
8144
7010
  import {
@@ -9261,7 +8127,7 @@ import { Transaction as Transaction6 } from "@scure/btc-signer";
9261
8127
  import { uuidv7 as uuidv72 } from "uuidv7";
9262
8128
 
9263
8129
  // src/services/transfer.ts
9264
- import { secp256k1 as secp256k112 } from "@noble/curves/secp256k1";
8130
+ import { secp256k1 as secp256k110 } from "@noble/curves/secp256k1";
9265
8131
  import {
9266
8132
  bytesToHex as bytesToHex9,
9267
8133
  equalBytes as equalBytes5,
@@ -9569,7 +8435,7 @@ var BaseTransferService = class {
9569
8435
  first: leaf.keyDerivation,
9570
8436
  second: leaf.newKeyDerivation,
9571
8437
  receiverPublicKey: receiverEciesPubKey.toBytes(),
9572
- curveOrder: secp256k112.CURVE.n,
8438
+ curveOrder: secp256k110.CURVE.n,
9573
8439
  threshold: this.config.getThreshold(),
9574
8440
  numShares: Object.keys(signingOperators).length
9575
8441
  });
@@ -9579,7 +8445,7 @@ var BaseTransferService = class {
9579
8445
  if (!share) {
9580
8446
  throw new Error(`Share not found for operator ${operator.id}`);
9581
8447
  }
9582
- const pubkeyTweak = secp256k112.getPublicKey(
8448
+ const pubkeyTweak = secp256k110.getPublicKey(
9583
8449
  numberToBytesBE4(share.share, 32),
9584
8450
  true
9585
8451
  );
@@ -9711,7 +8577,7 @@ var TransferService = class extends BaseTransferService {
9711
8577
  ...leaf.secretCipher
9712
8578
  ]);
9713
8579
  const payloadHash = sha25610(payload);
9714
- if (!secp256k112.verify(
8580
+ if (!secp256k110.verify(
9715
8581
  leaf.signature,
9716
8582
  payloadHash,
9717
8583
  transfer.senderIdentityPublicKey
@@ -10005,7 +8871,7 @@ var TransferService = class extends BaseTransferService {
10005
8871
  {
10006
8872
  first: leaf.keyDerivation,
10007
8873
  second: leaf.newKeyDerivation,
10008
- curveOrder: secp256k112.CURVE.n,
8874
+ curveOrder: secp256k110.CURVE.n,
10009
8875
  threshold: this.config.getThreshold(),
10010
8876
  numShares: Object.keys(signingOperators).length
10011
8877
  }
@@ -10016,7 +8882,7 @@ var TransferService = class extends BaseTransferService {
10016
8882
  if (!share) {
10017
8883
  throw new Error(`Share not found for operator ${operator.id}`);
10018
8884
  }
10019
- const pubkeyTweak = secp256k112.getPublicKey(
8885
+ const pubkeyTweak = secp256k110.getPublicKey(
10020
8886
  numberToBytesBE4(share.share, 32)
10021
8887
  );
10022
8888
  pubkeySharesTweak.set(identifier, pubkeyTweak);
@@ -10988,7 +9854,7 @@ var CoopExitService = class extends BaseTransferService {
10988
9854
  };
10989
9855
 
10990
9856
  // src/services/lightning.ts
10991
- import { secp256k1 as secp256k113 } from "@noble/curves/secp256k1";
9857
+ import { secp256k1 as secp256k111 } from "@noble/curves/secp256k1";
10992
9858
  import {
10993
9859
  bytesToNumberBE as bytesToNumberBE7,
10994
9860
  hexToBytes as hexToBytes9,
@@ -11079,7 +9945,7 @@ var LightningService = class {
11079
9945
  const crypto = getCrypto();
11080
9946
  const randBytes = crypto.getRandomValues(new Uint8Array(32));
11081
9947
  const preimage = numberToBytesBE5(
11082
- bytesToNumberBE7(randBytes) % secp256k113.CURVE.n,
9948
+ bytesToNumberBE7(randBytes) % secp256k111.CURVE.n,
11083
9949
  32
11084
9950
  );
11085
9951
  return await this.createLightningInvoiceWithPreImage({
@@ -11116,7 +9982,7 @@ var LightningService = class {
11116
9982
  }
11117
9983
  const shares = await this.config.signer.splitSecretWithProofs({
11118
9984
  secret: preimage,
11119
- curveOrder: secp256k113.CURVE.n,
9985
+ curveOrder: secp256k111.CURVE.n,
11120
9986
  threshold: this.config.getThreshold(),
11121
9987
  numShares: Object.keys(this.config.getSigningOperators()).length
11122
9988
  });
@@ -12108,47 +10974,7 @@ var SparkWallet = class _SparkWallet extends EventEmitter {
12108
10974
  senderPublicKey,
12109
10975
  expiryTime
12110
10976
  }) {
12111
- const MAX_SATS_AMOUNT = 21e14;
12112
- if (amount && (amount < 0 || amount > MAX_SATS_AMOUNT)) {
12113
- throw new ValidationError(
12114
- `Amount must be between 0 and ${MAX_SATS_AMOUNT} sats`,
12115
- {
12116
- field: "amount",
12117
- value: amount,
12118
- expected: `less than or equal to ${MAX_SATS_AMOUNT}`
12119
- }
12120
- );
12121
- }
12122
- const protoPayment = {
12123
- $case: "satsPayment",
12124
- satsPayment: {
12125
- amount
12126
- }
12127
- };
12128
- const invoiceFields = {
12129
- version: 1,
12130
- id: uuidv7obj().bytes,
12131
- paymentType: protoPayment,
12132
- memo,
12133
- senderPublicKey: senderPublicKey ? hexToBytes11(senderPublicKey) : void 0,
12134
- expiryTime: expiryTime ?? void 0
12135
- };
12136
- validateSparkInvoiceFields(invoiceFields);
12137
- const identityPublicKey = await this.config.signer.getIdentityPublicKey();
12138
- const hash = HashSparkInvoice(
12139
- invoiceFields,
12140
- identityPublicKey,
12141
- this.config.getNetworkType()
12142
- );
12143
- const signature = await this.config.signer.signSchnorrWithIdentityKey(hash);
12144
- return encodeSparkAddressWithSignature(
12145
- {
12146
- identityPublicKey: bytesToHex10(identityPublicKey),
12147
- network: this.config.getNetworkType(),
12148
- sparkInvoiceFields: invoiceFields
12149
- },
12150
- signature
12151
- );
10977
+ throw new NotImplementedError("Invoice functionality is not enabled");
12152
10978
  }
12153
10979
  /**
12154
10980
  * Creates a Spark invoice for a tokens payment on Spark.
@@ -12168,52 +10994,7 @@ var SparkWallet = class _SparkWallet extends EventEmitter {
12168
10994
  senderPublicKey,
12169
10995
  expiryTime
12170
10996
  }) {
12171
- const MAX_UINT128 = BigInt(2 ** 128 - 1);
12172
- if (amount && (amount < 0 || amount > MAX_UINT128)) {
12173
- throw new ValidationError(`Amount must be between 0 and ${MAX_UINT128}`, {
12174
- field: "amount",
12175
- value: amount,
12176
- expected: `greater than or equal to 0 and less than or equal to ${MAX_UINT128}`
12177
- });
12178
- }
12179
- let decodedTokenIdentifier = void 0;
12180
- if (tokenIdentifier) {
12181
- decodedTokenIdentifier = decodeBech32mTokenIdentifier(
12182
- tokenIdentifier,
12183
- this.config.getNetworkType()
12184
- ).tokenIdentifier;
12185
- }
12186
- const protoPayment = {
12187
- $case: "tokensPayment",
12188
- tokensPayment: {
12189
- tokenIdentifier: decodedTokenIdentifier ?? void 0,
12190
- amount: amount ? numberToVarBytesBE(amount) : void 0
12191
- }
12192
- };
12193
- const invoiceFields = {
12194
- version: 1,
12195
- id: uuidv7obj().bytes,
12196
- paymentType: protoPayment,
12197
- memo: memo ?? void 0,
12198
- senderPublicKey: senderPublicKey ? hexToBytes11(senderPublicKey) : void 0,
12199
- expiryTime: expiryTime ?? void 0
12200
- };
12201
- validateSparkInvoiceFields(invoiceFields);
12202
- const identityPublicKey = await this.config.signer.getIdentityPublicKey();
12203
- const hash = HashSparkInvoice(
12204
- invoiceFields,
12205
- identityPublicKey,
12206
- this.config.getNetworkType()
12207
- );
12208
- const signature = await this.config.signer.signSchnorrWithIdentityKey(hash);
12209
- return encodeSparkAddressWithSignature(
12210
- {
12211
- identityPublicKey: bytesToHex10(identityPublicKey),
12212
- network: this.config.getNetworkType(),
12213
- sparkInvoiceFields: invoiceFields
12214
- },
12215
- signature
12216
- );
10997
+ throw new NotImplementedError("Invoice functionality is not enabled");
12217
10998
  }
12218
10999
  /**
12219
11000
  * Initializes the wallet using either a mnemonic phrase or a raw seed.
@@ -12538,7 +11319,7 @@ var SparkWallet = class _SparkWallet extends EventEmitter {
12538
11319
  }
12539
11320
  const sspClient = this.getSspClient();
12540
11321
  const cpfpAdaptorPubkey = bytesToHex10(
12541
- secp256k114.getPublicKey(cpfpAdaptorPrivateKey)
11322
+ secp256k112.getPublicKey(cpfpAdaptorPrivateKey)
12542
11323
  );
12543
11324
  if (!cpfpAdaptorPubkey) {
12544
11325
  throw new Error("Failed to generate CPFP adaptor pubkey");
@@ -12546,13 +11327,13 @@ var SparkWallet = class _SparkWallet extends EventEmitter {
12546
11327
  let directAdaptorPubkey;
12547
11328
  if (directAdaptorPrivateKey.length > 0) {
12548
11329
  directAdaptorPubkey = bytesToHex10(
12549
- secp256k114.getPublicKey(directAdaptorPrivateKey)
11330
+ secp256k112.getPublicKey(directAdaptorPrivateKey)
12550
11331
  );
12551
11332
  }
12552
11333
  let directFromCpfpAdaptorPubkey;
12553
11334
  if (directFromCpfpAdaptorPrivateKey.length > 0) {
12554
11335
  directFromCpfpAdaptorPubkey = bytesToHex10(
12555
- secp256k114.getPublicKey(directFromCpfpAdaptorPrivateKey)
11336
+ secp256k112.getPublicKey(directFromCpfpAdaptorPrivateKey)
12556
11337
  );
12557
11338
  }
12558
11339
  let request = null;
@@ -14167,10 +12948,30 @@ var SparkWallet = class _SparkWallet extends EventEmitter {
14167
12948
  if (!invoice2) {
14168
12949
  throw new Error("Failed to create lightning invoice");
14169
12950
  }
12951
+ const decodedInvoice = decodeInvoice(invoice2.invoice.encodedInvoice);
12952
+ if (invoice2.invoice.paymentHash !== bytesToHex10(paymentHash) || decodedInvoice.paymentHash !== bytesToHex10(paymentHash)) {
12953
+ throw new ValidationError("Payment hash mismatch", {
12954
+ field: "paymentHash",
12955
+ value: invoice2.invoice.paymentHash,
12956
+ expected: bytesToHex10(paymentHash)
12957
+ });
12958
+ }
12959
+ if (decodedInvoice.amountMSats === null && amountSats2 !== 0) {
12960
+ throw new ValidationError("Amount mismatch", {
12961
+ field: "amountMSats",
12962
+ value: "null",
12963
+ expected: amountSats2 * 1e3
12964
+ });
12965
+ }
12966
+ if (decodedInvoice.amountMSats !== null && decodedInvoice.amountMSats !== BigInt(amountSats2 * 1e3)) {
12967
+ throw new ValidationError("Amount mismatch", {
12968
+ field: "amountMSats",
12969
+ value: decodedInvoice.amountMSats,
12970
+ expected: amountSats2 * 1e3
12971
+ });
12972
+ }
14170
12973
  if (includeSparkAddress) {
14171
- const sparkFallbackAddress = decodeInvoice(
14172
- invoice2.invoice.encodedInvoice
14173
- ).fallbackAddress;
12974
+ const sparkFallbackAddress = decodedInvoice.fallbackAddress;
14174
12975
  if (!sparkFallbackAddress) {
14175
12976
  throw new ValidationError(
14176
12977
  "No spark fallback address found in lightning invoice",
@@ -14192,6 +12993,14 @@ var SparkWallet = class _SparkWallet extends EventEmitter {
14192
12993
  }
14193
12994
  );
14194
12995
  }
12996
+ } else if (decodedInvoice.fallbackAddress !== void 0) {
12997
+ throw new ValidationError(
12998
+ "Spark fallback address found in lightning invoice but includeSparkAddress is false",
12999
+ {
13000
+ field: "sparkFallbackAddress",
13001
+ value: decodedInvoice.fallbackAddress
13002
+ }
13003
+ );
14195
13004
  }
14196
13005
  return invoice2;
14197
13006
  };
@@ -14359,91 +13168,7 @@ var SparkWallet = class _SparkWallet extends EventEmitter {
14359
13168
  });
14360
13169
  }
14361
13170
  async fulfillSparkInvoice(sparkInvoices) {
14362
- if (!Array.isArray(sparkInvoices) || sparkInvoices.length === 0) {
14363
- throw new ValidationError("No Spark invoices provided", {
14364
- field: "sparkInvoices",
14365
- value: sparkInvoices,
14366
- expected: "Non-empty array"
14367
- });
14368
- }
14369
- const satsTransactionSuccess = [];
14370
- const satsTransactionErrors = [];
14371
- const tokenTransactionSuccess = [];
14372
- const tokenTransactionErrors = [];
14373
- const { satsInvoices, tokenInvoices, invalidInvoices } = await this.groupSparkInvoicesByPaymentType(sparkInvoices);
14374
- if (invalidInvoices.length > 0) {
14375
- return {
14376
- satsTransactionSuccess,
14377
- satsTransactionErrors,
14378
- tokenTransactionSuccess,
14379
- tokenTransactionErrors,
14380
- invalidInvoices
14381
- };
14382
- }
14383
- if (tokenInvoices.size > 0) {
14384
- await this.syncTokenOutputs();
14385
- const tokenTransferTasks = [];
14386
- for (const [identifierHex, decodedInvoices] of tokenInvoices.entries()) {
14387
- const tokenIdentifier = hexToBytes11(identifierHex);
14388
- const tokenIdB32 = encodeBech32mTokenIdentifier({
14389
- tokenIdentifier,
14390
- network: this.config.getNetworkType()
14391
- });
14392
- const receiverOutputs = decodedInvoices.map((d) => ({
14393
- tokenIdentifier: tokenIdB32,
14394
- tokenAmount: d.amount,
14395
- receiverSparkAddress: d.invoice
14396
- }));
14397
- tokenTransferTasks.push(
14398
- this.tokenTransactionService.tokenTransfer({ tokenOutputs: this.tokenOutputs, receiverOutputs }).then((txid) => ({
14399
- ok: true,
14400
- tokenIdentifier: tokenIdB32,
14401
- txid
14402
- })).catch((e) => ({
14403
- ok: false,
14404
- tokenIdentifier: tokenIdB32,
14405
- error: e instanceof Error ? e : new Error(String(e))
14406
- }))
14407
- );
14408
- }
14409
- const results = await Promise.all(tokenTransferTasks);
14410
- for (const r of results) {
14411
- if (r.ok) {
14412
- tokenTransactionSuccess.push({
14413
- tokenIdentifier: r.tokenIdentifier,
14414
- txid: r.txid
14415
- });
14416
- } else {
14417
- tokenTransactionErrors.push({
14418
- tokenIdentifier: r.tokenIdentifier,
14419
- error: r.error
14420
- });
14421
- }
14422
- }
14423
- }
14424
- if (satsInvoices.length > 0) {
14425
- const transfers = await this.transferWithInvoice(satsInvoices);
14426
- for (const transfer of transfers) {
14427
- if (transfer.ok) {
14428
- satsTransactionSuccess.push({
14429
- invoice: transfer.param.sparkInvoice ?? "",
14430
- transferResponse: transfer.transfer
14431
- });
14432
- } else {
14433
- satsTransactionErrors.push({
14434
- invoice: transfer.param.sparkInvoice ?? "",
14435
- error: transfer.error
14436
- });
14437
- }
14438
- }
14439
- }
14440
- return {
14441
- satsTransactionSuccess,
14442
- satsTransactionErrors,
14443
- tokenTransactionSuccess,
14444
- tokenTransactionErrors,
14445
- invalidInvoices
14446
- };
13171
+ throw new NotImplementedError("Invoice functionality is not enabled");
14447
13172
  }
14448
13173
  async groupSparkInvoicesByPaymentType(sparkInvoices) {
14449
13174
  const satsInvoices = [];
@@ -14580,6 +13305,9 @@ var SparkWallet = class _SparkWallet extends EventEmitter {
14580
13305
  });
14581
13306
  return { satsInvoices, tokenInvoices, invalidInvoices };
14582
13307
  }
13308
+ async querySparkInvoices(invoices) {
13309
+ throw new NotImplementedError("Invoice functionality is not enabled");
13310
+ }
14583
13311
  /**
14584
13312
  * Gets fee estimate for sending Lightning payments.
14585
13313
  *
@@ -15641,6 +14369,27 @@ async function isTxBroadcast(txid, baseUrl, network) {
15641
14369
  return true;
15642
14370
  }
15643
14371
 
14372
+ // src/utils/response-validation.ts
14373
+ function collectResponses(responses) {
14374
+ const successfulResponses = responses.filter(
14375
+ (result) => result.status === "fulfilled"
14376
+ ).map((result) => result.value);
14377
+ const failedResponses = responses.filter(
14378
+ (result) => result.status === "rejected"
14379
+ );
14380
+ if (failedResponses.length > 0) {
14381
+ const errors = failedResponses.map((result) => result.reason).join("\n");
14382
+ throw new NetworkError(
14383
+ `${failedResponses.length} out of ${responses.length} requests failed, please try again`,
14384
+ {
14385
+ errorCount: failedResponses.length,
14386
+ errors
14387
+ }
14388
+ );
14389
+ }
14390
+ return successfulResponses;
14391
+ }
14392
+
15644
14393
  // src/utils/unilateral-exit.ts
15645
14394
  import { bytesToHex as bytesToHex11, hexToBytes as hexToBytes12 } from "@noble/curves/utils";
15646
14395
  import { ripemd160 } from "@noble/hashes/legacy";
@@ -16157,6 +14906,7 @@ __export(utils_exports, {
16157
14906
  addPublicKeys: () => addPublicKeys,
16158
14907
  applyAdaptorToSignature: () => applyAdaptorToSignature,
16159
14908
  applyAdditiveTweakToPublicKey: () => applyAdditiveTweakToPublicKey,
14909
+ assertBech32: () => assertBech32,
16160
14910
  bech32mDecode: () => bech32mDecode,
16161
14911
  bigIntToPrivateKey: () => bigIntToPrivateKey,
16162
14912
  checkIfSelectedOutputsAreAvailable: () => checkIfSelectedOutputsAreAvailable,
@@ -16219,6 +14969,7 @@ __export(utils_exports, {
16219
14969
  getTxId: () => getTxId,
16220
14970
  getTxIdNoReverse: () => getTxIdNoReverse,
16221
14971
  isEphemeralAnchorOutput: () => isEphemeralAnchorOutput,
14972
+ isLegacySparkAddress: () => isLegacySparkAddress,
16222
14973
  isSafeForNumber: () => isSafeForNumber,
16223
14974
  isTxBroadcast: () => isTxBroadcast,
16224
14975
  isValidPublicKey: () => isValidPublicKey,
@@ -16331,15 +15082,16 @@ export {
16331
15082
  encodeSparkAddress,
16332
15083
  encodeSparkAddressWithSignature,
16333
15084
  decodeSparkAddress,
15085
+ getNetworkFromSparkAddress,
15086
+ isLegacySparkAddress,
16334
15087
  isValidSparkAddress,
16335
15088
  isValidPublicKey,
16336
15089
  validateSparkInvoiceFields,
16337
15090
  validateSparkInvoiceSignature,
16338
- getNetworkFromSparkAddress,
16339
15091
  toProtoTimestamp,
15092
+ assertBech32,
16340
15093
  bech32mDecode,
16341
15094
  isSafeForNumber,
16342
- collectResponses,
16343
15095
  encodeBech32mTokenIdentifier,
16344
15096
  decodeBech32mTokenIdentifier,
16345
15097
  getNetworkFromBech32mTokenIdentifier,
@@ -16356,6 +15108,7 @@ export {
16356
15108
  SparkWallet,
16357
15109
  getLatestDepositTxId,
16358
15110
  isTxBroadcast,
15111
+ collectResponses,
16359
15112
  isEphemeralAnchorOutput,
16360
15113
  constructUnilateralExitTxs,
16361
15114
  constructUnilateralExitFeeBumpPackages,