@buildonspark/issuer-sdk 0.0.78 → 0.0.80

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.
package/dist/index.js CHANGED
@@ -1,11 +1,13 @@
1
- import "./chunk-5MYKP7NN.js";
1
+ import {
2
+ Buffer
3
+ } from "./chunk-7B4B24XF.js";
2
4
 
3
5
  // src/issuer-wallet/issuer-spark-wallet.ts
4
6
  import { TokenPubkey, TokenPubkeyAnnouncement } from "@buildonspark/lrc20-sdk";
5
7
  import {
6
8
  NetworkError as NetworkError2,
7
9
  SparkWallet,
8
- ValidationError as ValidationError2
10
+ ValidationError as ValidationError3
9
11
  } from "@buildonspark/spark-sdk";
10
12
  import { isNode } from "@lightsparkdev/core";
11
13
  import {
@@ -157,20 +159,21 @@ var IssuerTokenTransactionService = class extends TokenTransactionService {
157
159
  sparkOperatorIdentityPublicKeys: super.collectOperatorIdentityPublicKeys()
158
160
  };
159
161
  }
160
- async constructMintTokenTransaction(tokenPublicKey, tokenAmount) {
162
+ async constructMintTokenTransaction(rawTokenIdentifierBytes, issuerTokenPublicKey, tokenAmount) {
161
163
  return {
162
164
  version: 1,
163
165
  network: this.config.getNetworkProto(),
164
166
  tokenInputs: {
165
167
  $case: "mintInput",
166
168
  mintInput: {
167
- issuerPublicKey: tokenPublicKey
169
+ issuerPublicKey: issuerTokenPublicKey,
170
+ tokenIdentifier: rawTokenIdentifierBytes
168
171
  }
169
172
  },
170
173
  tokenOutputs: [
171
174
  {
172
- ownerPublicKey: tokenPublicKey,
173
- tokenPublicKey,
175
+ ownerPublicKey: issuerTokenPublicKey,
176
+ tokenIdentifier: rawTokenIdentifierBytes,
174
177
  tokenAmount: numberToBytesBE(tokenAmount, 16)
175
178
  }
176
179
  ],
@@ -179,10 +182,105 @@ var IssuerTokenTransactionService = class extends TokenTransactionService {
179
182
  expiryTime: void 0
180
183
  };
181
184
  }
185
+ async constructCreateTokenTransaction(tokenPublicKey, tokenName, tokenTicker, decimals, maxSupply, isFreezable) {
186
+ return {
187
+ version: 1,
188
+ network: this.config.getNetworkProto(),
189
+ tokenInputs: {
190
+ $case: "createInput",
191
+ createInput: {
192
+ issuerPublicKey: tokenPublicKey,
193
+ tokenName,
194
+ tokenTicker,
195
+ decimals,
196
+ maxSupply: numberToBytesBE(maxSupply, 16),
197
+ isFreezable
198
+ }
199
+ },
200
+ tokenOutputs: [],
201
+ clientCreatedTimestamp: /* @__PURE__ */ new Date(),
202
+ sparkOperatorIdentityPublicKeys: super.collectOperatorIdentityPublicKeys(),
203
+ expiryTime: void 0
204
+ };
205
+ }
182
206
  };
183
207
 
184
208
  // src/issuer-wallet/issuer-spark-wallet.ts
185
209
  import { NotImplementedError } from "@buildonspark/spark-sdk";
210
+
211
+ // src/utils/create-validation.ts
212
+ import { ValidationError as ValidationError2 } from "@buildonspark/spark-sdk";
213
+ function isNfcNormalized(value) {
214
+ return value.normalize("NFC") === value;
215
+ }
216
+ var MIN_NAME_SIZE = 3;
217
+ var MAX_NAME_SIZE = 20;
218
+ var MIN_SYMBOL_SIZE = 3;
219
+ var MAX_SYMBOL_SIZE = 6;
220
+ var MAX_DECIMALS = 255;
221
+ var MAXIMUM_MAX_SUPPLY = (1n << 128n) - 1n;
222
+ function validateTokenParameters(tokenName, tokenTicker, decimals, maxSupply) {
223
+ if (!isNfcNormalized(tokenName)) {
224
+ throw new ValidationError2("Token name must be NFC-normalised UTF-8", {
225
+ field: "tokenName",
226
+ value: tokenName,
227
+ expected: "NFC normalised string"
228
+ });
229
+ }
230
+ if (!isNfcNormalized(tokenTicker)) {
231
+ throw new ValidationError2("Token ticker must be NFC-normalised UTF-8", {
232
+ field: "tokenTicker",
233
+ value: tokenTicker,
234
+ expected: "NFC normalised string"
235
+ });
236
+ }
237
+ const nameBytes = Buffer.from(tokenName, "utf-8").length;
238
+ if (nameBytes < MIN_NAME_SIZE || nameBytes > MAX_NAME_SIZE) {
239
+ throw new ValidationError2(
240
+ `Token name must be between ${MIN_NAME_SIZE} and ${MAX_NAME_SIZE} bytes`,
241
+ {
242
+ field: "tokenName",
243
+ value: tokenName,
244
+ actualLength: nameBytes,
245
+ expected: `>=${MIN_NAME_SIZE} and <=${MAX_NAME_SIZE}`
246
+ }
247
+ );
248
+ }
249
+ const tickerBytes = Buffer.from(tokenTicker, "utf-8").length;
250
+ if (tickerBytes < MIN_SYMBOL_SIZE || tickerBytes > MAX_SYMBOL_SIZE) {
251
+ throw new ValidationError2(
252
+ `Token ticker must be between ${MIN_SYMBOL_SIZE} and ${MAX_SYMBOL_SIZE} bytes`,
253
+ {
254
+ field: "tokenTicker",
255
+ value: tokenTicker,
256
+ actualLength: tickerBytes,
257
+ expected: `>=${MIN_SYMBOL_SIZE} and <=${MAX_SYMBOL_SIZE}`
258
+ }
259
+ );
260
+ }
261
+ if (!Number.isSafeInteger(decimals) || decimals < 0 || decimals > MAX_DECIMALS) {
262
+ throw new ValidationError2(
263
+ `Decimals must be an integer between 0 and ${MAX_DECIMALS}`,
264
+ {
265
+ field: "decimals",
266
+ value: decimals,
267
+ expected: `>=0 and <=${MAX_DECIMALS}`
268
+ }
269
+ );
270
+ }
271
+ if (maxSupply < 0n || maxSupply > MAXIMUM_MAX_SUPPLY) {
272
+ throw new ValidationError2(`maxSupply must be between 0 and 2^128-1`, {
273
+ field: "maxSupply",
274
+ value: maxSupply.toString(),
275
+ expected: `>=0 and <=${MAXIMUM_MAX_SUPPLY.toString()}`
276
+ });
277
+ }
278
+ }
279
+
280
+ // src/issuer-wallet/issuer-spark-wallet.ts
281
+ import {
282
+ encodeBech32mTokenIdentifier
283
+ } from "@buildonspark/spark-sdk";
186
284
  var BURN_ADDRESS = "02".repeat(33);
187
285
  var IssuerSparkWallet = class _IssuerSparkWallet extends SparkWallet {
188
286
  issuerTokenTransactionService;
@@ -218,6 +316,10 @@ var IssuerSparkWallet = class _IssuerSparkWallet extends SparkWallet {
218
316
  "SparkIssuerWallet.getIssuerTokenMetadata",
219
317
  this.getIssuerTokenMetadata.bind(this)
220
318
  );
319
+ this.getIssuerTokenIdentifier = this.wrapWithOtelSpan(
320
+ "SparkIssuerWallet.getIssuerTokenIdentifier",
321
+ this.getIssuerTokenIdentifier.bind(this)
322
+ );
221
323
  this.mintTokens = this.wrapWithOtelSpan(
222
324
  "SparkIssuerWallet.mintTokens",
223
325
  this.mintTokens.bind(this)
@@ -266,22 +368,28 @@ var IssuerSparkWallet = class _IssuerSparkWallet extends SparkWallet {
266
368
  );
267
369
  if (!balanceObj.tokenBalances || issuerBalance === void 0) {
268
370
  return {
371
+ tokenIdentifier: void 0,
269
372
  balance: 0n
270
373
  };
271
374
  }
272
375
  return {
376
+ tokenIdentifier: issuerBalance[0] ?? void 0,
273
377
  balance: issuerBalance[1].balance
274
378
  };
275
379
  }
276
380
  /**
277
- * Retrieves metadata about the issuer's token.
381
+ * Retrieves information about the issuer's token.
278
382
  * @returns An object containing token information including public key, name, symbol, decimals, max supply, and freeze status
279
383
  * @throws {NetworkError} If the token metadata cannot be retrieved
280
384
  */
281
385
  async getIssuerTokenMetadata() {
282
386
  const issuerPublicKey = await super.getIdentityPublicKey();
283
- if (this.tokenMetadata.has(issuerPublicKey)) {
284
- const metadata = this.tokenMetadata.get(issuerPublicKey);
387
+ const tokenMetadata = this.tokenMetadata;
388
+ const cachedIssuerTokenMetadata = [...tokenMetadata.entries()].find(
389
+ ([, metadata]) => bytesToHex(metadata.issuerPublicKey) === issuerPublicKey
390
+ );
391
+ if (cachedIssuerTokenMetadata !== void 0) {
392
+ const metadata = cachedIssuerTokenMetadata[1];
285
393
  return {
286
394
  tokenPublicKey: bytesToHex(metadata.issuerPublicKey),
287
395
  rawTokenIdentifier: metadata.tokenIdentifier,
@@ -300,7 +408,7 @@ var IssuerSparkWallet = class _IssuerSparkWallet extends SparkWallet {
300
408
  issuerPublicKeys: Array.of(hexToBytes2(issuerPublicKey))
301
409
  });
302
410
  if (response.tokenMetadata.length === 0) {
303
- throw new ValidationError2(
411
+ throw new ValidationError3(
304
412
  "Token metadata not found - If a token has not yet been announced, please announce. If a token was recently announced, it is being confirmed. Try again in a few seconds.",
305
413
  {
306
414
  field: "tokenMetadata",
@@ -312,7 +420,11 @@ var IssuerSparkWallet = class _IssuerSparkWallet extends SparkWallet {
312
420
  );
313
421
  }
314
422
  const metadata = response.tokenMetadata[0];
315
- this.tokenMetadata.set(issuerPublicKey, metadata);
423
+ const tokenIdentifier = encodeBech32mTokenIdentifier({
424
+ tokenIdentifier: metadata.tokenIdentifier,
425
+ network: this.config.getNetworkType()
426
+ });
427
+ this.tokenMetadata.set(tokenIdentifier, metadata);
316
428
  return {
317
429
  tokenPublicKey: bytesToHex(metadata.issuerPublicKey),
318
430
  rawTokenIdentifier: metadata.tokenIdentifier,
@@ -329,22 +441,74 @@ var IssuerSparkWallet = class _IssuerSparkWallet extends SparkWallet {
329
441
  });
330
442
  }
331
443
  }
444
+ /**
445
+ * Retrieves the bech32m encoded token identifier for the issuer's token.
446
+ * @returns The bech32m encoded token identifier for the issuer's token
447
+ * @throws {NetworkError} If the token identifier cannot be retrieved
448
+ */
449
+ async getIssuerTokenIdentifier() {
450
+ const tokenMetadata = await this.getIssuerTokenMetadata();
451
+ return encodeBech32mTokenIdentifier({
452
+ tokenIdentifier: tokenMetadata.rawTokenIdentifier,
453
+ network: this.config.getNetworkType()
454
+ });
455
+ }
456
+ /**
457
+ * Create a new token on Spark.
458
+ *
459
+ * @param params - Object containing token creation parameters.
460
+ * @param params.tokenName - The name of the token.
461
+ * @param params.tokenTicker - The ticker symbol for the token.
462
+ * @param params.decimals - The number of decimal places for the token.
463
+ * @param params.isFreezable - Whether the token can be frozen.
464
+ * @param [params.maxSupply=0n] - (Optional) The maximum supply of the token. Defaults to <code>0n</code>.
465
+ *
466
+ * @returns The transaction ID of the announcement.
467
+ *
468
+ * @throws {ValidationError} If `decimals` is not a safe integer or other validation fails.
469
+ * @throws {NetworkError} If the announcement transaction cannot be broadcast.
470
+ */
471
+ async createToken({
472
+ tokenName,
473
+ tokenTicker,
474
+ decimals,
475
+ isFreezable,
476
+ maxSupply = 0n
477
+ }) {
478
+ validateTokenParameters(tokenName, tokenTicker, decimals, maxSupply);
479
+ const issuerPublicKey = await super.getIdentityPublicKey();
480
+ const tokenTransaction = await this.issuerTokenTransactionService.constructCreateTokenTransaction(
481
+ hexToBytes2(issuerPublicKey),
482
+ tokenName,
483
+ tokenTicker,
484
+ decimals,
485
+ maxSupply,
486
+ isFreezable
487
+ );
488
+ return await this.issuerTokenTransactionService.broadcastTokenTransaction(
489
+ tokenTransaction
490
+ );
491
+ }
332
492
  /**
333
493
  * Mints new tokens
334
494
  * @param tokenAmount - The amount of tokens to mint
335
495
  * @returns The transaction ID of the mint operation
336
496
  */
337
497
  async mintTokens(tokenAmount) {
338
- const tokenPublicKey = await super.getIdentityPublicKey();
339
498
  let tokenTransaction;
499
+ const issuerTokenPublicKey = await super.getIdentityPublicKey();
500
+ const issuerTokenPublicKeyBytes = hexToBytes2(issuerTokenPublicKey);
501
+ const tokenMetadata = await this.getIssuerTokenMetadata();
502
+ const rawTokenIdentifier = tokenMetadata.rawTokenIdentifier;
340
503
  if (this.config.getTokenTransactionVersion() === "V0") {
341
504
  tokenTransaction = await this.issuerTokenTransactionService.constructMintTokenTransactionV0(
342
- hexToBytes2(tokenPublicKey),
505
+ issuerTokenPublicKeyBytes,
343
506
  tokenAmount
344
507
  );
345
508
  } else {
346
509
  tokenTransaction = await this.issuerTokenTransactionService.constructMintTokenTransaction(
347
- hexToBytes2(tokenPublicKey),
510
+ rawTokenIdentifier,
511
+ issuerTokenPublicKeyBytes,
348
512
  tokenAmount
349
513
  );
350
514
  }
@@ -363,8 +527,12 @@ var IssuerSparkWallet = class _IssuerSparkWallet extends SparkWallet {
363
527
  identityPublicKey: BURN_ADDRESS,
364
528
  network: this.config.getNetworkType()
365
529
  });
530
+ const issuerTokenIdentifier = await this.getIssuerTokenIdentifier();
531
+ if (issuerTokenIdentifier === null) {
532
+ throw new ValidationError3("Issuer token identifier not found");
533
+ }
366
534
  return await this.transferTokens({
367
- tokenPublicKey: await super.getIdentityPublicKey(),
535
+ tokenIdentifier: issuerTokenIdentifier,
368
536
  tokenAmount,
369
537
  receiverSparkAddress: burnAddress,
370
538
  selectedOutputs
@@ -434,8 +602,9 @@ var IssuerSparkWallet = class _IssuerSparkWallet extends SparkWallet {
434
602
  * @throws {NetworkError} If the announcement transaction cannot be broadcast
435
603
  */
436
604
  async announceTokenL1(tokenName, tokenTicker, decimals, maxSupply, isFreezable, feeRateSatsPerVb = 4) {
605
+ validateTokenParameters(tokenName, tokenTicker, decimals, maxSupply);
437
606
  if (!Number.isSafeInteger(decimals)) {
438
- throw new ValidationError2("Decimals must be less than 2^53", {
607
+ throw new ValidationError3("Decimals must be less than 2^53", {
439
608
  field: "decimals",
440
609
  value: decimals,
441
610
  expected: "smaller or equal to " + Number.MAX_SAFE_INTEGER
@@ -1,4 +1,4 @@
1
- import "../chunk-5MYKP7NN.js";
1
+ import "../chunk-7B4B24XF.js";
2
2
 
3
3
  // src/proto/spark.ts
4
4
  export * from "@buildonspark/spark-sdk/proto/spark";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@buildonspark/issuer-sdk",
3
- "version": "0.0.78",
3
+ "version": "0.0.80",
4
4
  "description": "Spark Issuer SDK for token issuance",
5
5
  "license": "Apache-2.0",
6
6
  "module": "./dist/index.js",
@@ -47,15 +47,15 @@
47
47
  "package:checks": "yarn depcheck && yarn attw --pack . && echo \"\nPackage checks passed successfully!\"",
48
48
  "postversion": "yarn build",
49
49
  "test-cmd": "node --experimental-vm-modules $(yarn bin jest) --no-cache --runInBand --detectOpenHandles --forceExit",
50
- "test": "echo \"Error: no tests yet\"",
50
+ "test": "yarn test-cmd src/tests/*.test.ts",
51
51
  "test:integration": "HERMETIC_TEST=true yarn test-cmd src/tests/integration/*.test.ts",
52
52
  "test:stress": "yarn test-cmd src/tests/stress/*.test.ts",
53
53
  "types:watch": "tsc-absolute --watch",
54
54
  "types": "tsc"
55
55
  },
56
56
  "dependencies": {
57
- "@buildonspark/lrc20-sdk": "0.0.59",
58
- "@buildonspark/spark-sdk": "0.1.47",
57
+ "@buildonspark/lrc20-sdk": "0.0.60",
58
+ "@buildonspark/spark-sdk": "0.2.1",
59
59
  "@lightsparkdev/core": "^1.4.2",
60
60
  "@noble/curves": "^1.8.0",
61
61
  "@scure/btc-signer": "^1.5.0",
@@ -26,6 +26,11 @@ import { IssuerTokenTransactionService } from "../services/token-transactions.js
26
26
  import { TokenDistribution, IssuerTokenMetadata } from "./types.js";
27
27
  import { NotImplementedError } from "@buildonspark/spark-sdk";
28
28
  import { SparkSigner } from "@buildonspark/spark-sdk";
29
+ import { validateTokenParameters } from "../utils/create-validation.js";
30
+ import {
31
+ encodeBech32mTokenIdentifier,
32
+ Bech32mTokenIdentifier,
33
+ } from "@buildonspark/spark-sdk";
29
34
 
30
35
  const BURN_ADDRESS = "02".repeat(33);
31
36
 
@@ -73,6 +78,10 @@ export class IssuerSparkWallet extends SparkWallet {
73
78
  "SparkIssuerWallet.getIssuerTokenMetadata",
74
79
  this.getIssuerTokenMetadata.bind(this),
75
80
  );
81
+ this.getIssuerTokenIdentifier = this.wrapWithOtelSpan(
82
+ "SparkIssuerWallet.getIssuerTokenIdentifier",
83
+ this.getIssuerTokenIdentifier.bind(this),
84
+ );
76
85
  this.mintTokens = this.wrapWithOtelSpan(
77
86
  "SparkIssuerWallet.mintTokens",
78
87
  this.mintTokens.bind(this),
@@ -116,6 +125,7 @@ export class IssuerSparkWallet extends SparkWallet {
116
125
  * @returns An object containing the token balance as a bigint
117
126
  */
118
127
  public async getIssuerTokenBalance(): Promise<{
128
+ tokenIdentifier: Bech32mTokenIdentifier | undefined;
119
129
  balance: bigint;
120
130
  }> {
121
131
  const publicKey = await super.getIdentityPublicKey();
@@ -126,24 +136,31 @@ export class IssuerSparkWallet extends SparkWallet {
126
136
 
127
137
  if (!balanceObj.tokenBalances || issuerBalance === undefined) {
128
138
  return {
139
+ tokenIdentifier: undefined,
129
140
  balance: 0n,
130
141
  };
131
142
  }
132
143
  return {
144
+ tokenIdentifier: issuerBalance[0] ?? undefined,
133
145
  balance: issuerBalance[1].balance,
134
146
  };
135
147
  }
136
148
 
137
149
  /**
138
- * Retrieves metadata about the issuer's token.
150
+ * Retrieves information about the issuer's token.
139
151
  * @returns An object containing token information including public key, name, symbol, decimals, max supply, and freeze status
140
152
  * @throws {NetworkError} If the token metadata cannot be retrieved
141
153
  */
142
154
  public async getIssuerTokenMetadata(): Promise<IssuerTokenMetadata> {
143
155
  const issuerPublicKey = await super.getIdentityPublicKey();
144
- if (this.tokenMetadata.has(issuerPublicKey)) {
145
- const metadata = this.tokenMetadata.get(issuerPublicKey)!;
156
+ const tokenMetadata = this.tokenMetadata;
146
157
 
158
+ const cachedIssuerTokenMetadata = [...tokenMetadata.entries()].find(
159
+ ([, metadata]) =>
160
+ bytesToHex(metadata.issuerPublicKey) === issuerPublicKey,
161
+ );
162
+ if (cachedIssuerTokenMetadata !== undefined) {
163
+ const metadata = cachedIssuerTokenMetadata[1];
147
164
  return {
148
165
  tokenPublicKey: bytesToHex(metadata.issuerPublicKey),
149
166
  rawTokenIdentifier: metadata.tokenIdentifier,
@@ -163,7 +180,6 @@ export class IssuerSparkWallet extends SparkWallet {
163
180
  const response = await sparkTokenClient.query_token_metadata({
164
181
  issuerPublicKeys: Array.of(hexToBytes(issuerPublicKey)),
165
182
  });
166
-
167
183
  if (response.tokenMetadata.length === 0) {
168
184
  throw new ValidationError(
169
185
  "Token metadata not found - If a token has not yet been announced, please announce. If a token was recently announced, it is being confirmed. Try again in a few seconds.",
@@ -176,9 +192,12 @@ export class IssuerSparkWallet extends SparkWallet {
176
192
  },
177
193
  );
178
194
  }
179
-
180
195
  const metadata = response.tokenMetadata[0];
181
- this.tokenMetadata.set(issuerPublicKey, metadata);
196
+ const tokenIdentifier = encodeBech32mTokenIdentifier({
197
+ tokenIdentifier: metadata.tokenIdentifier,
198
+ network: this.config.getNetworkType(),
199
+ });
200
+ this.tokenMetadata.set(tokenIdentifier, metadata);
182
201
 
183
202
  return {
184
203
  tokenPublicKey: bytesToHex(metadata.issuerPublicKey),
@@ -197,25 +216,91 @@ export class IssuerSparkWallet extends SparkWallet {
197
216
  }
198
217
  }
199
218
 
219
+ /**
220
+ * Retrieves the bech32m encoded token identifier for the issuer's token.
221
+ * @returns The bech32m encoded token identifier for the issuer's token
222
+ * @throws {NetworkError} If the token identifier cannot be retrieved
223
+ */
224
+ public async getIssuerTokenIdentifier(): Promise<Bech32mTokenIdentifier | null> {
225
+ const tokenMetadata = await this.getIssuerTokenMetadata();
226
+
227
+ return encodeBech32mTokenIdentifier({
228
+ tokenIdentifier: tokenMetadata.rawTokenIdentifier,
229
+ network: this.config.getNetworkType(),
230
+ });
231
+ }
232
+
233
+ /**
234
+ * Create a new token on Spark.
235
+ *
236
+ * @param params - Object containing token creation parameters.
237
+ * @param params.tokenName - The name of the token.
238
+ * @param params.tokenTicker - The ticker symbol for the token.
239
+ * @param params.decimals - The number of decimal places for the token.
240
+ * @param params.isFreezable - Whether the token can be frozen.
241
+ * @param [params.maxSupply=0n] - (Optional) The maximum supply of the token. Defaults to <code>0n</code>.
242
+ *
243
+ * @returns The transaction ID of the announcement.
244
+ *
245
+ * @throws {ValidationError} If `decimals` is not a safe integer or other validation fails.
246
+ * @throws {NetworkError} If the announcement transaction cannot be broadcast.
247
+ */
248
+ public async createToken({
249
+ tokenName,
250
+ tokenTicker,
251
+ decimals,
252
+ isFreezable,
253
+ maxSupply = 0n,
254
+ }: {
255
+ tokenName: string;
256
+ tokenTicker: string;
257
+ decimals: number;
258
+ isFreezable: boolean;
259
+ maxSupply?: bigint;
260
+ }): Promise<string> {
261
+ validateTokenParameters(tokenName, tokenTicker, decimals, maxSupply);
262
+
263
+ const issuerPublicKey = await super.getIdentityPublicKey();
264
+
265
+ const tokenTransaction =
266
+ await this.issuerTokenTransactionService.constructCreateTokenTransaction(
267
+ hexToBytes(issuerPublicKey),
268
+ tokenName,
269
+ tokenTicker,
270
+ decimals,
271
+ maxSupply,
272
+ isFreezable,
273
+ );
274
+
275
+ return await this.issuerTokenTransactionService.broadcastTokenTransaction(
276
+ tokenTransaction,
277
+ );
278
+ }
279
+
200
280
  /**
201
281
  * Mints new tokens
202
282
  * @param tokenAmount - The amount of tokens to mint
203
283
  * @returns The transaction ID of the mint operation
204
284
  */
205
285
  public async mintTokens(tokenAmount: bigint): Promise<string> {
206
- const tokenPublicKey = await super.getIdentityPublicKey();
207
286
  let tokenTransaction: TokenTransactionV0 | TokenTransaction;
287
+ const issuerTokenPublicKey = await super.getIdentityPublicKey();
288
+ const issuerTokenPublicKeyBytes = hexToBytes(issuerTokenPublicKey);
289
+
290
+ const tokenMetadata = await this.getIssuerTokenMetadata();
291
+ const rawTokenIdentifier: Uint8Array = tokenMetadata.rawTokenIdentifier;
208
292
 
209
293
  if (this.config.getTokenTransactionVersion() === "V0") {
210
294
  tokenTransaction =
211
295
  await this.issuerTokenTransactionService.constructMintTokenTransactionV0(
212
- hexToBytes(tokenPublicKey),
296
+ issuerTokenPublicKeyBytes,
213
297
  tokenAmount,
214
298
  );
215
299
  } else {
216
300
  tokenTransaction =
217
301
  await this.issuerTokenTransactionService.constructMintTokenTransaction(
218
- hexToBytes(tokenPublicKey),
302
+ rawTokenIdentifier,
303
+ issuerTokenPublicKeyBytes,
219
304
  tokenAmount,
220
305
  );
221
306
  }
@@ -239,8 +324,14 @@ export class IssuerSparkWallet extends SparkWallet {
239
324
  identityPublicKey: BURN_ADDRESS,
240
325
  network: this.config.getNetworkType(),
241
326
  });
327
+ const issuerTokenIdentifier: Bech32mTokenIdentifier | null =
328
+ await this.getIssuerTokenIdentifier();
329
+ if (issuerTokenIdentifier === null) {
330
+ throw new ValidationError("Issuer token identifier not found");
331
+ }
332
+
242
333
  return await this.transferTokens({
243
- tokenPublicKey: await super.getIdentityPublicKey(),
334
+ tokenIdentifier: issuerTokenIdentifier,
244
335
  tokenAmount,
245
336
  receiverSparkAddress: burnAddress,
246
337
  selectedOutputs,
@@ -329,6 +420,8 @@ export class IssuerSparkWallet extends SparkWallet {
329
420
  isFreezable: boolean,
330
421
  feeRateSatsPerVb: number = 4.0,
331
422
  ): Promise<string> {
423
+ validateTokenParameters(tokenName, tokenTicker, decimals, maxSupply);
424
+
332
425
  if (!Number.isSafeInteger(decimals)) {
333
426
  throw new ValidationError("Decimals must be less than 2^53", {
334
427
  field: "decimals",
@@ -39,7 +39,8 @@ export class IssuerTokenTransactionService extends TokenTransactionService {
39
39
  }
40
40
 
41
41
  async constructMintTokenTransaction(
42
- tokenPublicKey: Uint8Array,
42
+ rawTokenIdentifierBytes: Uint8Array,
43
+ issuerTokenPublicKey: Uint8Array,
43
44
  tokenAmount: bigint,
44
45
  ): Promise<TokenTransaction> {
45
46
  return {
@@ -48,13 +49,14 @@ export class IssuerTokenTransactionService extends TokenTransactionService {
48
49
  tokenInputs: {
49
50
  $case: "mintInput",
50
51
  mintInput: {
51
- issuerPublicKey: tokenPublicKey,
52
+ issuerPublicKey: issuerTokenPublicKey,
53
+ tokenIdentifier: rawTokenIdentifierBytes,
52
54
  },
53
55
  },
54
56
  tokenOutputs: [
55
57
  {
56
- ownerPublicKey: tokenPublicKey,
57
- tokenPublicKey: tokenPublicKey,
58
+ ownerPublicKey: issuerTokenPublicKey,
59
+ tokenIdentifier: rawTokenIdentifierBytes,
58
60
  tokenAmount: numberToBytesBE(tokenAmount, 16),
59
61
  },
60
62
  ],
@@ -64,4 +66,34 @@ export class IssuerTokenTransactionService extends TokenTransactionService {
64
66
  expiryTime: undefined,
65
67
  };
66
68
  }
69
+
70
+ async constructCreateTokenTransaction(
71
+ tokenPublicKey: Uint8Array,
72
+ tokenName: string,
73
+ tokenTicker: string,
74
+ decimals: number,
75
+ maxSupply: bigint,
76
+ isFreezable: boolean,
77
+ ): Promise<TokenTransaction> {
78
+ return {
79
+ version: 1,
80
+ network: this.config.getNetworkProto(),
81
+ tokenInputs: {
82
+ $case: "createInput",
83
+ createInput: {
84
+ issuerPublicKey: tokenPublicKey,
85
+ tokenName: tokenName,
86
+ tokenTicker: tokenTicker,
87
+ decimals: decimals,
88
+ maxSupply: numberToBytesBE(maxSupply, 16),
89
+ isFreezable: isFreezable,
90
+ },
91
+ },
92
+ tokenOutputs: [],
93
+ clientCreatedTimestamp: new Date(),
94
+ sparkOperatorIdentityPublicKeys:
95
+ super.collectOperatorIdentityPublicKeys(),
96
+ expiryTime: undefined,
97
+ };
98
+ }
67
99
  }