@buildonspark/issuer-sdk 0.1.4 → 0.1.6

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.
@@ -114,10 +114,12 @@ declare abstract class IssuerSparkWallet extends SparkWallet {
114
114
  getIssuerTokenMetadata(): Promise<IssuerTokenMetadata>;
115
115
  /**
116
116
  * Retrieves information about the tokens that were issued by this user.
117
+ * @param tokenIdentifiers - Optional array of specific token identifiers to fetch.
118
+ * If omitted, all tokens for this issuer are fetched.
117
119
  * @returns An array of objects containing token information including public key, name, symbol, decimals, max supply, freeze status, and extra metadata
118
120
  * @throws {SparkRequestError} If the token metadata cannot be retrieved
119
121
  */
120
- getIssuerTokensMetadata(): Promise<IssuerTokenMetadata[]>;
122
+ getIssuerTokensMetadata(tokenIdentifiers?: Bech32mTokenIdentifier[]): Promise<IssuerTokenMetadata[]>;
121
123
  /**
122
124
  * Retrieves the bech32m encoded token identifier for the issuer's token.
123
125
  * @deprecated Use getIssuerTokenIdentifiers() instead. This method will be removed in a future version.
@@ -183,7 +185,7 @@ declare abstract class IssuerSparkWallet extends SparkWallet {
183
185
  */
184
186
  mintTokens({ tokenAmount, tokenIdentifier, }: {
185
187
  tokenAmount: bigint;
186
- tokenIdentifier?: Bech32mTokenIdentifier;
188
+ tokenIdentifier: Bech32mTokenIdentifier;
187
189
  }): Promise<string>;
188
190
  /**
189
191
  * Burns issuer's tokens
@@ -205,7 +207,7 @@ declare abstract class IssuerSparkWallet extends SparkWallet {
205
207
  */
206
208
  burnTokens({ tokenAmount, tokenIdentifier, selectedOutputs, }: {
207
209
  tokenAmount: bigint;
208
- tokenIdentifier?: Bech32mTokenIdentifier;
210
+ tokenIdentifier: Bech32mTokenIdentifier;
209
211
  selectedOutputs?: OutputWithPreviousTransactionData[];
210
212
  }): Promise<string>;
211
213
  /**
@@ -267,6 +269,14 @@ declare abstract class IssuerSparkWallet extends SparkWallet {
267
269
  * @throws {SparkError} This feature is not yet supported
268
270
  */
269
271
  getIssuerTokenDistribution(): Promise<TokenDistribution>;
272
+ /**
273
+ * This validates that the token belongs to this issuer.
274
+ * If a token is in the cache, it must belong to this issuer.
275
+ * @param tokenIdentifier - The bech32m encoded token identifier
276
+ * @throws {SparkValidationError} If the token is not found for this issuer
277
+ * @private
278
+ */
279
+ private validateTokenIssuer;
270
280
  protected getTraceName(methodName: string): string;
271
281
  private wrapIssuerPublicMethod;
272
282
  private wrapIssuerSparkWalletMethods;
@@ -114,10 +114,12 @@ declare abstract class IssuerSparkWallet extends SparkWallet {
114
114
  getIssuerTokenMetadata(): Promise<IssuerTokenMetadata>;
115
115
  /**
116
116
  * Retrieves information about the tokens that were issued by this user.
117
+ * @param tokenIdentifiers - Optional array of specific token identifiers to fetch.
118
+ * If omitted, all tokens for this issuer are fetched.
117
119
  * @returns An array of objects containing token information including public key, name, symbol, decimals, max supply, freeze status, and extra metadata
118
120
  * @throws {SparkRequestError} If the token metadata cannot be retrieved
119
121
  */
120
- getIssuerTokensMetadata(): Promise<IssuerTokenMetadata[]>;
122
+ getIssuerTokensMetadata(tokenIdentifiers?: Bech32mTokenIdentifier[]): Promise<IssuerTokenMetadata[]>;
121
123
  /**
122
124
  * Retrieves the bech32m encoded token identifier for the issuer's token.
123
125
  * @deprecated Use getIssuerTokenIdentifiers() instead. This method will be removed in a future version.
@@ -183,7 +185,7 @@ declare abstract class IssuerSparkWallet extends SparkWallet {
183
185
  */
184
186
  mintTokens({ tokenAmount, tokenIdentifier, }: {
185
187
  tokenAmount: bigint;
186
- tokenIdentifier?: Bech32mTokenIdentifier;
188
+ tokenIdentifier: Bech32mTokenIdentifier;
187
189
  }): Promise<string>;
188
190
  /**
189
191
  * Burns issuer's tokens
@@ -205,7 +207,7 @@ declare abstract class IssuerSparkWallet extends SparkWallet {
205
207
  */
206
208
  burnTokens({ tokenAmount, tokenIdentifier, selectedOutputs, }: {
207
209
  tokenAmount: bigint;
208
- tokenIdentifier?: Bech32mTokenIdentifier;
210
+ tokenIdentifier: Bech32mTokenIdentifier;
209
211
  selectedOutputs?: OutputWithPreviousTransactionData[];
210
212
  }): Promise<string>;
211
213
  /**
@@ -267,6 +269,14 @@ declare abstract class IssuerSparkWallet extends SparkWallet {
267
269
  * @throws {SparkError} This feature is not yet supported
268
270
  */
269
271
  getIssuerTokenDistribution(): Promise<TokenDistribution>;
272
+ /**
273
+ * This validates that the token belongs to this issuer.
274
+ * If a token is in the cache, it must belong to this issuer.
275
+ * @param tokenIdentifier - The bech32m encoded token identifier
276
+ * @throws {SparkValidationError} If the token is not found for this issuer
277
+ * @private
278
+ */
279
+ private validateTokenIssuer;
270
280
  protected getTraceName(methodName: string): string;
271
281
  private wrapIssuerPublicMethod;
272
282
  private wrapIssuerSparkWalletMethods;
@@ -438,88 +438,57 @@ var IssuerSparkWallet = class extends SparkWallet {
438
438
  * @throws {SparkValidationError} If multiple tokens are found for this issuer
439
439
  */
440
440
  async getIssuerTokenMetadata() {
441
- const issuerPublicKey = await super.getIdentityPublicKey();
442
- const sparkTokenClient = await this.connectionManager.createSparkTokenClient(
443
- this.config.getCoordinatorAddress()
444
- );
445
- try {
446
- const response = await sparkTokenClient.query_token_metadata({
447
- issuerPublicKeys: Array.of(hexToBytes2(issuerPublicKey))
448
- });
449
- if (response.tokenMetadata.length === 0) {
450
- throw new SparkValidationError3(
451
- "Token metadata not found - If a token has not yet been created, please create it first. Try again in a few seconds.",
452
- {
453
- field: "tokenMetadata",
454
- value: response.tokenMetadata,
455
- expected: "non-empty array",
456
- actualLength: response.tokenMetadata.length,
457
- expectedLength: 1
458
- }
459
- );
460
- }
461
- if (response.tokenMetadata.length > 1) {
462
- throw new SparkValidationError3(
463
- "Multiple tokens found for this issuer. Please migrate to getIssuerTokensMetadata() instead.",
464
- {
465
- field: "tokenMetadata",
466
- value: response.tokenMetadata
467
- }
468
- );
469
- }
470
- const metadata = response.tokenMetadata[0];
471
- const bech32mTokenIdentifier = encodeBech32mTokenIdentifier({
472
- tokenIdentifier: metadata.tokenIdentifier,
473
- network: this.config.getNetworkType()
474
- });
475
- this.tokenMetadata.set(bech32mTokenIdentifier, metadata);
476
- return {
477
- tokenPublicKey: bytesToHex(metadata.issuerPublicKey),
478
- rawTokenIdentifier: metadata.tokenIdentifier,
479
- tokenName: metadata.tokenName,
480
- tokenTicker: metadata.tokenTicker,
481
- decimals: metadata.decimals,
482
- maxSupply: bytesToNumberBE(metadata.maxSupply),
483
- isFreezable: metadata.isFreezable,
484
- extraMetadata: metadata.extraMetadata ? new Uint8Array(metadata.extraMetadata) : void 0,
485
- bech32mTokenIdentifier
486
- };
487
- } catch (error) {
488
- throw new SparkRequestError2("Failed to fetch token metadata", { error });
441
+ const tokensMetadata = await this.getIssuerTokensMetadata();
442
+ if (tokensMetadata.length === 0) {
443
+ throw new SparkValidationError3("No tokens found. Create a token first.");
444
+ }
445
+ if (tokensMetadata.length > 1) {
446
+ throw new SparkValidationError3(
447
+ "Multiple tokens found for this issuer. Please migrate to getIssuerTokensMetadata() instead.",
448
+ {
449
+ field: "tokenMetadata",
450
+ value: tokensMetadata
451
+ }
452
+ );
489
453
  }
454
+ return tokensMetadata[0];
490
455
  }
491
456
  /**
492
457
  * Retrieves information about the tokens that were issued by this user.
458
+ * @param tokenIdentifiers - Optional array of specific token identifiers to fetch.
459
+ * If omitted, all tokens for this issuer are fetched.
493
460
  * @returns An array of objects containing token information including public key, name, symbol, decimals, max supply, freeze status, and extra metadata
494
461
  * @throws {SparkRequestError} If the token metadata cannot be retrieved
495
462
  */
496
- async getIssuerTokensMetadata() {
463
+ async getIssuerTokensMetadata(tokenIdentifiers) {
497
464
  const issuerPublicKey = await super.getIdentityPublicKey();
498
465
  const sparkTokenClient = await this.connectionManager.createSparkTokenClient(
499
466
  this.config.getCoordinatorAddress()
500
467
  );
468
+ const filterByIdentifiers = Array.isArray(tokenIdentifiers) && tokenIdentifiers.length > 0;
469
+ const tokenIdentifierSet = filterByIdentifiers ? new Set(tokenIdentifiers) : void 0;
470
+ const request = {};
471
+ if (filterByIdentifiers) {
472
+ request.tokenIdentifiers = tokenIdentifiers.map(
473
+ (id) => decodeBech32mTokenIdentifier(id, this.config.getNetworkType()).tokenIdentifier
474
+ );
475
+ } else {
476
+ request.issuerPublicKeys = Array.of(hexToBytes2(issuerPublicKey));
477
+ }
501
478
  try {
502
- const response = await sparkTokenClient.query_token_metadata({
503
- issuerPublicKeys: Array.of(hexToBytes2(issuerPublicKey))
504
- });
505
- if (response.tokenMetadata.length === 0) {
506
- throw new SparkValidationError3(
507
- "Token metadata not found - If a token has not yet been created, please create it first. Try again in a few seconds.",
508
- {
509
- field: "tokenMetadata",
510
- value: response.tokenMetadata,
511
- expected: "non-empty array",
512
- actualLength: response.tokenMetadata.length,
513
- expectedLength: 1
514
- }
515
- );
516
- }
479
+ const response = await sparkTokenClient.query_token_metadata(request);
517
480
  const tokenMetadata = [];
518
481
  for (const metadata of response.tokenMetadata) {
519
482
  const bech32mTokenIdentifier = encodeBech32mTokenIdentifier({
520
483
  tokenIdentifier: metadata.tokenIdentifier,
521
484
  network: this.config.getNetworkType()
522
485
  });
486
+ if (bytesToHex(metadata.issuerPublicKey) !== issuerPublicKey) {
487
+ continue;
488
+ }
489
+ if (filterByIdentifiers && !tokenIdentifierSet.has(bech32mTokenIdentifier)) {
490
+ continue;
491
+ }
523
492
  this.tokenMetadata.set(bech32mTokenIdentifier, metadata);
524
493
  tokenMetadata.push({
525
494
  tokenPublicKey: bytesToHex(metadata.issuerPublicKey),
@@ -535,6 +504,9 @@ var IssuerSparkWallet = class extends SparkWallet {
535
504
  }
536
505
  return tokenMetadata;
537
506
  } catch (error) {
507
+ if (error instanceof SparkError) {
508
+ throw error;
509
+ }
538
510
  throw new SparkRequestError2("Failed to fetch token metadata", { error });
539
511
  }
540
512
  }
@@ -547,6 +519,9 @@ var IssuerSparkWallet = class extends SparkWallet {
547
519
  */
548
520
  async getIssuerTokenIdentifier() {
549
521
  const tokensMetadata = await this.getIssuerTokensMetadata();
522
+ if (tokensMetadata.length === 0) {
523
+ throw new SparkValidationError3("No tokens found. Create a token first.");
524
+ }
550
525
  if (tokensMetadata.length > 1) {
551
526
  throw new SparkValidationError3(
552
527
  "Multiple tokens found. Use getIssuerTokenIdentifiers() instead.",
@@ -563,9 +538,6 @@ var IssuerSparkWallet = class extends SparkWallet {
563
538
  }
564
539
  );
565
540
  }
566
- if (tokensMetadata.length === 0) {
567
- throw new SparkValidationError3("No tokens found. Create a token first.");
568
- }
569
541
  return tokensMetadata[0].bech32mTokenIdentifier;
570
542
  }
571
543
  /**
@@ -679,8 +651,13 @@ var IssuerSparkWallet = class extends SparkWallet {
679
651
  }
680
652
  const issuerTokenPublicKey = await super.getIdentityPublicKey();
681
653
  const issuerTokenPublicKeyBytes = hexToBytes2(issuerTokenPublicKey);
682
- const tokensMetadata = await this.getIssuerTokensMetadata();
683
654
  if (bech32mTokenIdentifier === void 0) {
655
+ const tokensMetadata = await this.getIssuerTokensMetadata();
656
+ if (tokensMetadata.length === 0) {
657
+ throw new SparkValidationError3(
658
+ "No tokens found. Create a token first."
659
+ );
660
+ }
684
661
  if (tokensMetadata.length > 1) {
685
662
  throw new SparkValidationError3(
686
663
  "Multiple tokens found. Please use mintTokens({ tokenAmount, tokenIdentifier }) instead.",
@@ -689,19 +666,14 @@ var IssuerSparkWallet = class extends SparkWallet {
689
666
  availableTokens: tokensMetadata.map((t) => ({
690
667
  tokenName: t.tokenName,
691
668
  tokenTicker: t.tokenTicker,
692
- bech32mTokenIdentifier: encodeBech32mTokenIdentifier({
693
- tokenIdentifier: t.rawTokenIdentifier,
694
- network: this.config.getNetworkType()
695
- })
669
+ bech32mTokenIdentifier: t.bech32mTokenIdentifier
696
670
  }))
697
671
  }
698
672
  );
699
673
  }
700
- const encodedTokenIdentifier = encodeBech32mTokenIdentifier({
701
- tokenIdentifier: tokensMetadata[0].rawTokenIdentifier,
702
- network: this.config.getNetworkType()
703
- });
704
- bech32mTokenIdentifier = encodedTokenIdentifier;
674
+ bech32mTokenIdentifier = tokensMetadata[0].bech32mTokenIdentifier;
675
+ } else {
676
+ await this.validateTokenIssuer(bech32mTokenIdentifier);
705
677
  }
706
678
  const rawTokenIdentifier = decodeBech32mTokenIdentifier(
707
679
  bech32mTokenIdentifier,
@@ -728,13 +700,18 @@ var IssuerSparkWallet = class extends SparkWallet {
728
700
  }
729
701
  }
730
702
  async burnTokens(tokenAmountOrParams, selectedOutputs) {
731
- let bech32mTokenIdentifier;
703
+ let burnTokenIdentifier;
732
704
  let tokenAmount;
733
705
  let outputs;
734
706
  if (typeof tokenAmountOrParams === "bigint") {
735
707
  tokenAmount = tokenAmountOrParams;
736
708
  outputs = selectedOutputs;
737
709
  const tokenIdentifiers = await this.getIssuerTokenIdentifiers();
710
+ if (tokenIdentifiers.length === 0) {
711
+ throw new SparkValidationError3(
712
+ "No tokens found. Create a token first."
713
+ );
714
+ }
738
715
  if (tokenIdentifiers.length > 1) {
739
716
  throw new SparkValidationError3(
740
717
  "Multiple tokens found. Use burnTokens({ tokenIdentifier, tokenAmount, selectedOutputs }) to specify which token to burn.",
@@ -744,52 +721,19 @@ var IssuerSparkWallet = class extends SparkWallet {
744
721
  }
745
722
  );
746
723
  }
747
- if (tokenIdentifiers.length === 0) {
748
- throw new SparkValidationError3(
749
- "No tokens found. Create a token first."
750
- );
751
- }
752
- bech32mTokenIdentifier = tokenIdentifiers[0];
724
+ burnTokenIdentifier = tokenIdentifiers[0];
753
725
  } else {
754
726
  tokenAmount = tokenAmountOrParams.tokenAmount;
755
727
  outputs = tokenAmountOrParams.selectedOutputs;
756
- if (tokenAmountOrParams.tokenIdentifier) {
757
- const tokenIdentifiers = await this.getIssuerTokenIdentifiers();
758
- const tokenIdentifier = tokenIdentifiers.find(
759
- (identifier) => identifier === tokenAmountOrParams.tokenIdentifier
760
- );
761
- if (!tokenIdentifier) {
762
- throw new SparkValidationError3("Token not found for this issuer", {
763
- field: "tokenIdentifier",
764
- value: tokenAmountOrParams.tokenIdentifier
765
- });
766
- }
767
- bech32mTokenIdentifier = tokenAmountOrParams.tokenIdentifier;
768
- } else {
769
- const tokenIdentifiers = await this.getIssuerTokenIdentifiers();
770
- if (tokenIdentifiers.length === 0) {
771
- throw new SparkValidationError3(
772
- "No tokens found. Create a token first."
773
- );
774
- }
775
- if (tokenIdentifiers.length > 1) {
776
- throw new SparkValidationError3(
777
- "Multiple tokens found. Please specify tokenIdentifier in parameters.",
778
- {
779
- field: "tokenIdentifier",
780
- availableTokens: tokenIdentifiers
781
- }
782
- );
783
- }
784
- bech32mTokenIdentifier = tokenIdentifiers[0];
785
- }
728
+ await this.validateTokenIssuer(tokenAmountOrParams.tokenIdentifier);
729
+ burnTokenIdentifier = tokenAmountOrParams.tokenIdentifier;
786
730
  }
787
731
  const burnAddress = encodeSparkAddress({
788
732
  identityPublicKey: BURN_ADDRESS,
789
733
  network: this.config.getNetworkType()
790
734
  });
791
735
  return await this.transferTokens({
792
- tokenIdentifier: bech32mTokenIdentifier,
736
+ tokenIdentifier: burnTokenIdentifier,
793
737
  tokenAmount,
794
738
  receiverSparkAddress: burnAddress,
795
739
  selectedOutputs: outputs
@@ -826,6 +770,8 @@ var IssuerSparkWallet = class extends SparkWallet {
826
770
  );
827
771
  }
828
772
  bech32mTokenIdentifier = tokenIdentifiers[0];
773
+ } else {
774
+ await this.validateTokenIssuer(bech32mTokenIdentifier);
829
775
  }
830
776
  const rawTokenIdentifier = decodeBech32mTokenIdentifier(
831
777
  bech32mTokenIdentifier,
@@ -853,6 +799,11 @@ var IssuerSparkWallet = class extends SparkWallet {
853
799
  }
854
800
  if (bech32mTokenIdentifier === void 0) {
855
801
  const tokenIdentifiers = await this.getIssuerTokenIdentifiers();
802
+ if (tokenIdentifiers.length === 0) {
803
+ throw new SparkValidationError3(
804
+ "No tokens found. Create a token first."
805
+ );
806
+ }
856
807
  if (tokenIdentifiers.length > 1) {
857
808
  throw new SparkValidationError3(
858
809
  "Multiple tokens found. Use unfreezeTokens({ tokenIdentifier, sparkAddress }) instead.",
@@ -863,6 +814,8 @@ var IssuerSparkWallet = class extends SparkWallet {
863
814
  );
864
815
  }
865
816
  bech32mTokenIdentifier = tokenIdentifiers[0];
817
+ } else {
818
+ await this.validateTokenIssuer(bech32mTokenIdentifier);
866
819
  }
867
820
  const decodedOwnerPubkey = decodeSparkAddress(
868
821
  sparkAddress,
@@ -889,6 +842,45 @@ var IssuerSparkWallet = class extends SparkWallet {
889
842
  async getIssuerTokenDistribution() {
890
843
  throw new SparkError("Token distribution is not yet supported");
891
844
  }
845
+ /**
846
+ * This validates that the token belongs to this issuer.
847
+ * If a token is in the cache, it must belong to this issuer.
848
+ * @param tokenIdentifier - The bech32m encoded token identifier
849
+ * @throws {SparkValidationError} If the token is not found for this issuer
850
+ * @private
851
+ */
852
+ async validateTokenIssuer(tokenIdentifier) {
853
+ const issuerPublicKey = await super.getIdentityPublicKey();
854
+ const cachedMetadata = this.tokenMetadata.get(tokenIdentifier);
855
+ if (cachedMetadata) {
856
+ if (bytesToHex(cachedMetadata.issuerPublicKey) !== issuerPublicKey) {
857
+ throw new SparkValidationError3("Token was not issued by this issuer", {
858
+ field: "issuerPublicKey",
859
+ tokenIdentifier,
860
+ expected: issuerPublicKey,
861
+ actual: bytesToHex(cachedMetadata.issuerPublicKey)
862
+ });
863
+ }
864
+ } else {
865
+ const tokensMetadata = await this.getIssuerTokensMetadata([
866
+ tokenIdentifier
867
+ ]);
868
+ if (tokensMetadata.length === 0) {
869
+ throw new SparkValidationError3("Token not found for this issuer", {
870
+ field: "tokenIdentifier",
871
+ value: tokenIdentifier
872
+ });
873
+ }
874
+ if (tokensMetadata[0].tokenPublicKey !== issuerPublicKey) {
875
+ throw new SparkValidationError3("Token was not issued by this issuer", {
876
+ field: "issuerPublicKey",
877
+ tokenIdentifier,
878
+ expected: issuerPublicKey,
879
+ actual: tokensMetadata[0].tokenPublicKey
880
+ });
881
+ }
882
+ }
883
+ }
892
884
  getTraceName(methodName) {
893
885
  return `IssuerSparkWallet.${methodName}`;
894
886
  }
@@ -1,4 +1,4 @@
1
1
  export * from '@buildonspark/spark-sdk/proto/spark';
2
2
  import '@buildonspark/spark-sdk/proto/spark_token';
3
- import '@buildonspark/spark-sdk/types';
4
3
  import '@buildonspark/spark-sdk/test-utils';
4
+ import '@buildonspark/spark-sdk/types';
@@ -1,4 +1,4 @@
1
1
  export * from '@buildonspark/spark-sdk/proto/spark';
2
2
  import '@buildonspark/spark-sdk/proto/spark_token';
3
- import '@buildonspark/spark-sdk/types';
4
3
  import '@buildonspark/spark-sdk/test-utils';
4
+ import '@buildonspark/spark-sdk/types';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@buildonspark/issuer-sdk",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "description": "Spark Issuer SDK for token issuance",
5
5
  "license": "Apache-2.0",
6
6
  "main": "./dist/index.browser.js",
@@ -76,7 +76,7 @@
76
76
  "types": "tsc"
77
77
  },
78
78
  "dependencies": {
79
- "@buildonspark/spark-sdk": "0.5.4",
79
+ "@buildonspark/spark-sdk": "0.5.6",
80
80
  "@noble/curves": "^1.8.0",
81
81
  "@scure/btc-signer": "^1.5.0",
82
82
  "buffer": "^6.0.3"