@buildonspark/issuer-sdk 0.1.2 → 0.1.4
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/CHANGELOG.md +109 -0
- package/dist/index.browser.d.ts +133 -9
- package/dist/index.browser.js +341 -83
- package/dist/index.node.cjs +348 -90
- package/dist/index.node.d.cts +133 -9
- package/dist/index.node.d.ts +133 -9
- package/dist/index.node.js +341 -83
- package/dist/native/index.react-native.cjs +345 -87
- package/dist/native/index.react-native.d.cts +133 -9
- package/dist/native/index.react-native.d.ts +133 -9
- package/dist/native/index.react-native.js +341 -83
- package/dist/proto/spark.d.cts +1 -1
- package/dist/proto/spark.d.ts +1 -1
- package/package.json +2 -2
- package/src/issuer-wallet/issuer-spark-wallet.ts +528 -58
- package/src/issuer-wallet/types.ts +25 -0
- package/src/tests/integration/multi-token-issuer.test.ts +437 -0
- package/src/tests/integration/nft-creation.test.ts +32 -17
|
@@ -15,8 +15,13 @@ import { OutputWithPreviousTransactionData } from "@buildonspark/spark-sdk/proto
|
|
|
15
15
|
import { bytesToHex, bytesToNumberBE, hexToBytes } from "@noble/curves/utils";
|
|
16
16
|
import { TokenFreezeService } from "../services/freeze.js";
|
|
17
17
|
import { IssuerTokenTransactionService } from "../services/token-transactions.js";
|
|
18
|
+
import { hashFinalTokenTransaction } from "@buildonspark/spark-sdk";
|
|
18
19
|
import { validateTokenParameters } from "../utils/create-validation.js";
|
|
19
|
-
import {
|
|
20
|
+
import {
|
|
21
|
+
IssuerTokenMetadata,
|
|
22
|
+
TokenCreationDetails,
|
|
23
|
+
TokenDistribution,
|
|
24
|
+
} from "./types.js";
|
|
20
25
|
|
|
21
26
|
const BURN_ADDRESS = "02".repeat(33);
|
|
22
27
|
|
|
@@ -50,7 +55,10 @@ export abstract class IssuerSparkWallet extends SparkWallet {
|
|
|
50
55
|
|
|
51
56
|
/**
|
|
52
57
|
* Gets the token balance for the issuer's token.
|
|
58
|
+
* @deprecated Use getIssuerTokenBalances() instead. This method will be removed in a future version.
|
|
53
59
|
* @returns An object containing the token balance as a bigint
|
|
60
|
+
*
|
|
61
|
+
* @throws {SparkValidationError} If multiple tokens are found for this issuer
|
|
54
62
|
*/
|
|
55
63
|
public async getIssuerTokenBalance(): Promise<{
|
|
56
64
|
tokenIdentifier: Bech32mTokenIdentifier | undefined;
|
|
@@ -58,37 +66,112 @@ export abstract class IssuerSparkWallet extends SparkWallet {
|
|
|
58
66
|
}> {
|
|
59
67
|
const publicKey = await super.getIdentityPublicKey();
|
|
60
68
|
const balanceObj = await this.getBalance();
|
|
61
|
-
const issuerBalance = [...balanceObj.tokenBalances.entries()].
|
|
69
|
+
const issuerBalance = [...balanceObj.tokenBalances.entries()].filter(
|
|
62
70
|
([, info]) => info.tokenMetadata.tokenPublicKey === publicKey,
|
|
63
71
|
); // [tokenIdentifier, { balance, tokenMetadata }]
|
|
64
72
|
|
|
65
|
-
if (
|
|
73
|
+
if (issuerBalance.length > 1) {
|
|
74
|
+
throw new SparkValidationError(
|
|
75
|
+
"Multiple tokens found for this issuer. Use getIssuerTokenBalances() instead.",
|
|
76
|
+
{
|
|
77
|
+
field: "issuerTokenBalance",
|
|
78
|
+
expected: "single token",
|
|
79
|
+
actual: `${issuerBalance.length} tokens`,
|
|
80
|
+
},
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (issuerBalance.length === 0) {
|
|
66
85
|
return {
|
|
67
86
|
tokenIdentifier: undefined,
|
|
68
87
|
balance: 0n,
|
|
69
88
|
};
|
|
70
89
|
}
|
|
90
|
+
|
|
71
91
|
return {
|
|
72
|
-
tokenIdentifier: issuerBalance[0]
|
|
73
|
-
balance: issuerBalance[1].balance,
|
|
92
|
+
tokenIdentifier: issuerBalance[0][0],
|
|
93
|
+
balance: issuerBalance[0][1].balance,
|
|
74
94
|
};
|
|
75
95
|
}
|
|
76
96
|
|
|
97
|
+
/**
|
|
98
|
+
* Gets the token balances for the tokens that were issued by this user.
|
|
99
|
+
* @returns An array of objects containing the token identifier and balance
|
|
100
|
+
*/
|
|
101
|
+
public async getIssuerTokenBalances(): Promise<
|
|
102
|
+
{
|
|
103
|
+
tokenIdentifier: Bech32mTokenIdentifier | undefined;
|
|
104
|
+
balance: bigint;
|
|
105
|
+
}[]
|
|
106
|
+
> {
|
|
107
|
+
const publicKey = await super.getIdentityPublicKey();
|
|
108
|
+
const balanceObj = await this.getBalance();
|
|
109
|
+
const issuerBalance = [...balanceObj.tokenBalances.entries()].filter(
|
|
110
|
+
([, info]) => info.tokenMetadata.tokenPublicKey === publicKey,
|
|
111
|
+
); // [tokenIdentifier, { balance, tokenMetadata }]
|
|
112
|
+
|
|
113
|
+
if (issuerBalance.length === 0) {
|
|
114
|
+
return [
|
|
115
|
+
{
|
|
116
|
+
tokenIdentifier: undefined,
|
|
117
|
+
balance: 0n,
|
|
118
|
+
},
|
|
119
|
+
];
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return issuerBalance.map(([tokenIdentifier, { balance }]) => ({
|
|
123
|
+
tokenIdentifier,
|
|
124
|
+
balance,
|
|
125
|
+
}));
|
|
126
|
+
}
|
|
127
|
+
|
|
77
128
|
/**
|
|
78
129
|
* Retrieves information about the issuer's token.
|
|
79
|
-
* @
|
|
130
|
+
* @deprecated Use getIssuerTokensMetadata() instead. This method will be removed in a future version.
|
|
131
|
+
* @returns An object containing token information including public key, name, symbol, decimals, max supply, freeze status, and extra metadata
|
|
80
132
|
* @throws {SparkRequestError} If the token metadata cannot be retrieved
|
|
133
|
+
* @throws {SparkValidationError} If multiple tokens are found for this issuer
|
|
81
134
|
*/
|
|
82
135
|
public async getIssuerTokenMetadata(): Promise<IssuerTokenMetadata> {
|
|
83
136
|
const issuerPublicKey = await super.getIdentityPublicKey();
|
|
84
|
-
const tokenMetadata = this.tokenMetadata;
|
|
85
137
|
|
|
86
|
-
const
|
|
87
|
-
(
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
const
|
|
138
|
+
const sparkTokenClient =
|
|
139
|
+
await this.connectionManager.createSparkTokenClient(
|
|
140
|
+
this.config.getCoordinatorAddress(),
|
|
141
|
+
);
|
|
142
|
+
try {
|
|
143
|
+
const response = await sparkTokenClient.query_token_metadata({
|
|
144
|
+
issuerPublicKeys: Array.of(hexToBytes(issuerPublicKey)),
|
|
145
|
+
});
|
|
146
|
+
if (response.tokenMetadata.length === 0) {
|
|
147
|
+
throw new SparkValidationError(
|
|
148
|
+
"Token metadata not found - If a token has not yet been created, please create it first. Try again in a few seconds.",
|
|
149
|
+
{
|
|
150
|
+
field: "tokenMetadata",
|
|
151
|
+
value: response.tokenMetadata,
|
|
152
|
+
expected: "non-empty array",
|
|
153
|
+
actualLength: response.tokenMetadata.length,
|
|
154
|
+
expectedLength: 1,
|
|
155
|
+
},
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
if (response.tokenMetadata.length > 1) {
|
|
159
|
+
throw new SparkValidationError(
|
|
160
|
+
"Multiple tokens found for this issuer. Please migrate to getIssuerTokensMetadata() instead.",
|
|
161
|
+
{
|
|
162
|
+
field: "tokenMetadata",
|
|
163
|
+
value: response.tokenMetadata,
|
|
164
|
+
},
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const metadata = response.tokenMetadata[0];
|
|
169
|
+
const bech32mTokenIdentifier = encodeBech32mTokenIdentifier({
|
|
170
|
+
tokenIdentifier: metadata.tokenIdentifier,
|
|
171
|
+
network: this.config.getNetworkType(),
|
|
172
|
+
});
|
|
173
|
+
this.tokenMetadata.set(bech32mTokenIdentifier, metadata);
|
|
174
|
+
|
|
92
175
|
return {
|
|
93
176
|
tokenPublicKey: bytesToHex(metadata.issuerPublicKey),
|
|
94
177
|
rawTokenIdentifier: metadata.tokenIdentifier,
|
|
@@ -100,8 +183,20 @@ export abstract class IssuerSparkWallet extends SparkWallet {
|
|
|
100
183
|
extraMetadata: metadata.extraMetadata
|
|
101
184
|
? new Uint8Array(metadata.extraMetadata)
|
|
102
185
|
: undefined,
|
|
186
|
+
bech32mTokenIdentifier,
|
|
103
187
|
};
|
|
188
|
+
} catch (error) {
|
|
189
|
+
throw new SparkRequestError("Failed to fetch token metadata", { error });
|
|
104
190
|
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Retrieves information about the tokens that were issued by this user.
|
|
195
|
+
* @returns An array of objects containing token information including public key, name, symbol, decimals, max supply, freeze status, and extra metadata
|
|
196
|
+
* @throws {SparkRequestError} If the token metadata cannot be retrieved
|
|
197
|
+
*/
|
|
198
|
+
public async getIssuerTokensMetadata(): Promise<IssuerTokenMetadata[]> {
|
|
199
|
+
const issuerPublicKey = await super.getIdentityPublicKey();
|
|
105
200
|
|
|
106
201
|
const sparkTokenClient =
|
|
107
202
|
await this.connectionManager.createSparkTokenClient(
|
|
@@ -123,23 +218,32 @@ export abstract class IssuerSparkWallet extends SparkWallet {
|
|
|
123
218
|
},
|
|
124
219
|
);
|
|
125
220
|
}
|
|
126
|
-
const metadata = response.tokenMetadata[0];
|
|
127
|
-
const tokenIdentifier = encodeBech32mTokenIdentifier({
|
|
128
|
-
tokenIdentifier: metadata.tokenIdentifier,
|
|
129
|
-
network: this.config.getNetworkType(),
|
|
130
|
-
});
|
|
131
|
-
this.tokenMetadata.set(tokenIdentifier, metadata);
|
|
132
221
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
222
|
+
const tokenMetadata: IssuerTokenMetadata[] = [];
|
|
223
|
+
|
|
224
|
+
for (const metadata of response.tokenMetadata) {
|
|
225
|
+
const bech32mTokenIdentifier = encodeBech32mTokenIdentifier({
|
|
226
|
+
tokenIdentifier: metadata.tokenIdentifier,
|
|
227
|
+
network: this.config.getNetworkType(),
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
this.tokenMetadata.set(bech32mTokenIdentifier, metadata);
|
|
231
|
+
|
|
232
|
+
tokenMetadata.push({
|
|
233
|
+
tokenPublicKey: bytesToHex(metadata.issuerPublicKey),
|
|
234
|
+
rawTokenIdentifier: metadata.tokenIdentifier,
|
|
235
|
+
tokenName: metadata.tokenName,
|
|
236
|
+
tokenTicker: metadata.tokenTicker,
|
|
237
|
+
decimals: metadata.decimals,
|
|
238
|
+
maxSupply: bytesToNumberBE(metadata.maxSupply),
|
|
239
|
+
isFreezable: metadata.isFreezable,
|
|
240
|
+
extraMetadata: metadata.extraMetadata
|
|
241
|
+
? new Uint8Array(metadata.extraMetadata)
|
|
242
|
+
: undefined,
|
|
243
|
+
bech32mTokenIdentifier,
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
return tokenMetadata;
|
|
143
247
|
} catch (error) {
|
|
144
248
|
throw new SparkRequestError("Failed to fetch token metadata", { error });
|
|
145
249
|
}
|
|
@@ -147,16 +251,47 @@ export abstract class IssuerSparkWallet extends SparkWallet {
|
|
|
147
251
|
|
|
148
252
|
/**
|
|
149
253
|
* Retrieves the bech32m encoded token identifier for the issuer's token.
|
|
254
|
+
* @deprecated Use getIssuerTokenIdentifiers() instead. This method will be removed in a future version.
|
|
150
255
|
* @returns The bech32m encoded token identifier for the issuer's token
|
|
151
256
|
* @throws {SparkRequestError} If the token identifier cannot be retrieved
|
|
257
|
+
* @throws {SparkValidationError} If multiple tokens are found for this issuer
|
|
152
258
|
*/
|
|
153
259
|
public async getIssuerTokenIdentifier(): Promise<Bech32mTokenIdentifier> {
|
|
154
|
-
const
|
|
260
|
+
const tokensMetadata = await this.getIssuerTokensMetadata();
|
|
261
|
+
|
|
262
|
+
if (tokensMetadata.length > 1) {
|
|
263
|
+
throw new SparkValidationError(
|
|
264
|
+
"Multiple tokens found. Use getIssuerTokenIdentifiers() instead.",
|
|
265
|
+
{
|
|
266
|
+
method: "getIssuerTokenIdentifier",
|
|
267
|
+
availableTokens: tokensMetadata.map((t) => ({
|
|
268
|
+
tokenName: t.tokenName,
|
|
269
|
+
tokenTicker: t.tokenTicker,
|
|
270
|
+
bech32mTokenIdentifier: encodeBech32mTokenIdentifier({
|
|
271
|
+
tokenIdentifier: t.rawTokenIdentifier,
|
|
272
|
+
network: this.config.getNetworkType(),
|
|
273
|
+
}),
|
|
274
|
+
})),
|
|
275
|
+
},
|
|
276
|
+
);
|
|
277
|
+
}
|
|
155
278
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
279
|
+
if (tokensMetadata.length === 0) {
|
|
280
|
+
throw new SparkValidationError("No tokens found. Create a token first.");
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
return tokensMetadata[0].bech32mTokenIdentifier;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Retrieves the bech32m encoded token identifier for the issuer's token.
|
|
288
|
+
* @returns The bech32m encoded token identifier for the issuer's token
|
|
289
|
+
* @throws {SparkRequestError} If the token identifier cannot be retrieved
|
|
290
|
+
*/
|
|
291
|
+
public async getIssuerTokenIdentifiers(): Promise<Bech32mTokenIdentifier[]> {
|
|
292
|
+
const tokensMetadata = await this.getIssuerTokensMetadata();
|
|
293
|
+
|
|
294
|
+
return tokensMetadata.map((metadata) => metadata.bech32mTokenIdentifier);
|
|
160
295
|
}
|
|
161
296
|
|
|
162
297
|
/**
|
|
@@ -169,12 +304,31 @@ export abstract class IssuerSparkWallet extends SparkWallet {
|
|
|
169
304
|
* @param params.isFreezable - Whether the token can be frozen.
|
|
170
305
|
* @param [params.maxSupply=0n] - (Optional) The maximum supply of the token. Defaults to <code>0n</code>.
|
|
171
306
|
* @param params.extraMetadata - (Optional) This can be used to store additional bytes data to be associated with a token, like image data.
|
|
172
|
-
*
|
|
173
|
-
* @returns The transaction
|
|
174
|
-
*
|
|
307
|
+
* @param params.returnIdentifierForCreate - (Optional) Whether to return the token identifier in addition to the transaction hash. Defaults to <code>false</code>.
|
|
308
|
+
* @returns The transaction hash of the announcement or TokenCreationDetails if `returnIdentifierForCreate` is true.
|
|
175
309
|
* @throws {SparkValidationError} If `decimals` is not a safe integer or other validation fails.
|
|
176
310
|
* @throws {SparkRequestError} If the announcement transaction cannot be broadcast.
|
|
177
311
|
*/
|
|
312
|
+
public async createToken(params: {
|
|
313
|
+
tokenName: string;
|
|
314
|
+
tokenTicker: string;
|
|
315
|
+
decimals: number;
|
|
316
|
+
isFreezable: boolean;
|
|
317
|
+
maxSupply?: bigint;
|
|
318
|
+
extraMetadata?: Uint8Array;
|
|
319
|
+
returnIdentifierForCreate?: false;
|
|
320
|
+
}): Promise<string>;
|
|
321
|
+
|
|
322
|
+
public async createToken(params: {
|
|
323
|
+
tokenName: string;
|
|
324
|
+
tokenTicker: string;
|
|
325
|
+
decimals: number;
|
|
326
|
+
isFreezable: boolean;
|
|
327
|
+
maxSupply?: bigint;
|
|
328
|
+
extraMetadata?: Uint8Array;
|
|
329
|
+
returnIdentifierForCreate: true;
|
|
330
|
+
}): Promise<TokenCreationDetails>;
|
|
331
|
+
|
|
178
332
|
public async createToken({
|
|
179
333
|
tokenName,
|
|
180
334
|
tokenTicker,
|
|
@@ -182,6 +336,7 @@ export abstract class IssuerSparkWallet extends SparkWallet {
|
|
|
182
336
|
isFreezable,
|
|
183
337
|
maxSupply = 0n,
|
|
184
338
|
extraMetadata,
|
|
339
|
+
returnIdentifierForCreate = false,
|
|
185
340
|
}: {
|
|
186
341
|
tokenName: string;
|
|
187
342
|
tokenTicker: string;
|
|
@@ -189,7 +344,8 @@ export abstract class IssuerSparkWallet extends SparkWallet {
|
|
|
189
344
|
isFreezable: boolean;
|
|
190
345
|
maxSupply?: bigint;
|
|
191
346
|
extraMetadata?: Uint8Array;
|
|
192
|
-
|
|
347
|
+
returnIdentifierForCreate?: boolean;
|
|
348
|
+
}): Promise<string | TokenCreationDetails> {
|
|
193
349
|
validateTokenParameters(
|
|
194
350
|
tokenName,
|
|
195
351
|
tokenTicker,
|
|
@@ -212,9 +368,32 @@ export abstract class IssuerSparkWallet extends SparkWallet {
|
|
|
212
368
|
extraMetadata,
|
|
213
369
|
);
|
|
214
370
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
371
|
+
const { finalTokenTransactionHash, tokenIdentifier } =
|
|
372
|
+
await this.issuerTokenTransactionService.broadcastTokenTransactionDetailed(
|
|
373
|
+
tokenTransaction,
|
|
374
|
+
);
|
|
375
|
+
const txHash = bytesToHex(finalTokenTransactionHash);
|
|
376
|
+
|
|
377
|
+
if (returnIdentifierForCreate) {
|
|
378
|
+
if (!tokenIdentifier) {
|
|
379
|
+
throw new SparkRequestError(
|
|
380
|
+
"Server response missing expected field: tokenIdentifier",
|
|
381
|
+
{
|
|
382
|
+
operation: "broadcast_transaction",
|
|
383
|
+
field: "tokenIdentifier",
|
|
384
|
+
},
|
|
385
|
+
);
|
|
386
|
+
}
|
|
387
|
+
const bech32mTokenIdentifier = encodeBech32mTokenIdentifier({
|
|
388
|
+
tokenIdentifier: tokenIdentifier,
|
|
389
|
+
network: this.config.getNetworkType(),
|
|
390
|
+
});
|
|
391
|
+
return {
|
|
392
|
+
tokenIdentifier: bech32mTokenIdentifier,
|
|
393
|
+
transactionHash: txHash,
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
return txHash;
|
|
218
397
|
} else {
|
|
219
398
|
const partialTokenTransaction =
|
|
220
399
|
await this.issuerTokenTransactionService.constructPartialCreateTokenTransaction(
|
|
@@ -227,23 +406,116 @@ export abstract class IssuerSparkWallet extends SparkWallet {
|
|
|
227
406
|
extraMetadata,
|
|
228
407
|
);
|
|
229
408
|
|
|
230
|
-
|
|
231
|
-
|
|
409
|
+
const broadcastResponse =
|
|
410
|
+
await this.issuerTokenTransactionService.broadcastTokenTransactionV3Detailed(
|
|
411
|
+
partialTokenTransaction,
|
|
412
|
+
);
|
|
413
|
+
const finalHash = await hashFinalTokenTransaction(
|
|
414
|
+
broadcastResponse.finalTokenTransaction!,
|
|
232
415
|
);
|
|
416
|
+
const finalTransactionHash = bytesToHex(finalHash);
|
|
417
|
+
|
|
418
|
+
if (returnIdentifierForCreate) {
|
|
419
|
+
if (!broadcastResponse.tokenIdentifier) {
|
|
420
|
+
throw new SparkRequestError(
|
|
421
|
+
"Server response missing expected field: tokenIdentifier",
|
|
422
|
+
{
|
|
423
|
+
operation: "broadcast_transaction",
|
|
424
|
+
field: "tokenIdentifier",
|
|
425
|
+
},
|
|
426
|
+
);
|
|
427
|
+
}
|
|
428
|
+
const tokenIdentifier = encodeBech32mTokenIdentifier({
|
|
429
|
+
tokenIdentifier: broadcastResponse.tokenIdentifier!,
|
|
430
|
+
network: this.config.getNetworkType(),
|
|
431
|
+
});
|
|
432
|
+
return {
|
|
433
|
+
tokenIdentifier,
|
|
434
|
+
transactionHash: finalTransactionHash,
|
|
435
|
+
};
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
return finalTransactionHash;
|
|
233
439
|
}
|
|
234
440
|
}
|
|
235
441
|
|
|
442
|
+
/**
|
|
443
|
+
* @deprecated Use mintTokens({ tokenAmount, tokenIdentifier }) instead. This method will be removed in a future version.
|
|
444
|
+
* @param amount - The amount of tokens to mint
|
|
445
|
+
* @returns The transaction ID of the mint operation
|
|
446
|
+
* @throws {SparkValidationError} If multiple tokens are found for this issuer
|
|
447
|
+
* @throws {SparkValidationError} If no tokens are found for this issuer
|
|
448
|
+
*/
|
|
449
|
+
public async mintTokens(amount: bigint): Promise<string>;
|
|
450
|
+
|
|
236
451
|
/**
|
|
237
452
|
* Mints new tokens
|
|
238
|
-
* @param
|
|
453
|
+
* @param params - Object containing token minting parameters.
|
|
454
|
+
* @param params.tokenAmount - The amount of tokens to mint
|
|
455
|
+
* @param params.tokenIdentifier - The bech32m encoded token identifier
|
|
239
456
|
* @returns The transaction ID of the mint operation
|
|
457
|
+
* @throws {SparkValidationError} If no tokens are found for this issuer
|
|
240
458
|
*/
|
|
241
|
-
public async mintTokens(
|
|
459
|
+
public async mintTokens({
|
|
460
|
+
tokenAmount,
|
|
461
|
+
tokenIdentifier,
|
|
462
|
+
}: {
|
|
463
|
+
tokenAmount: bigint;
|
|
464
|
+
tokenIdentifier?: Bech32mTokenIdentifier;
|
|
465
|
+
}): Promise<string>;
|
|
466
|
+
|
|
467
|
+
public async mintTokens(
|
|
468
|
+
tokenAmountOrParams:
|
|
469
|
+
| bigint
|
|
470
|
+
| {
|
|
471
|
+
tokenAmount: bigint;
|
|
472
|
+
tokenIdentifier?: Bech32mTokenIdentifier;
|
|
473
|
+
},
|
|
474
|
+
): Promise<string> {
|
|
475
|
+
let tokenAmount: bigint;
|
|
476
|
+
let bech32mTokenIdentifier: Bech32mTokenIdentifier | undefined;
|
|
477
|
+
|
|
478
|
+
if (typeof tokenAmountOrParams === "bigint") {
|
|
479
|
+
tokenAmount = tokenAmountOrParams;
|
|
480
|
+
bech32mTokenIdentifier = undefined;
|
|
481
|
+
} else {
|
|
482
|
+
tokenAmount = tokenAmountOrParams.tokenAmount;
|
|
483
|
+
bech32mTokenIdentifier = tokenAmountOrParams.tokenIdentifier;
|
|
484
|
+
}
|
|
485
|
+
|
|
242
486
|
const issuerTokenPublicKey = await super.getIdentityPublicKey();
|
|
243
487
|
const issuerTokenPublicKeyBytes = hexToBytes(issuerTokenPublicKey);
|
|
244
488
|
|
|
245
|
-
const
|
|
246
|
-
|
|
489
|
+
const tokensMetadata = await this.getIssuerTokensMetadata();
|
|
490
|
+
if (bech32mTokenIdentifier === undefined) {
|
|
491
|
+
if (tokensMetadata.length > 1) {
|
|
492
|
+
throw new SparkValidationError(
|
|
493
|
+
"Multiple tokens found. Please use mintTokens({ tokenAmount, tokenIdentifier }) instead.",
|
|
494
|
+
{
|
|
495
|
+
field: "tokenIdentifier",
|
|
496
|
+
availableTokens: tokensMetadata.map((t) => ({
|
|
497
|
+
tokenName: t.tokenName,
|
|
498
|
+
tokenTicker: t.tokenTicker,
|
|
499
|
+
bech32mTokenIdentifier: encodeBech32mTokenIdentifier({
|
|
500
|
+
tokenIdentifier: t.rawTokenIdentifier,
|
|
501
|
+
network: this.config.getNetworkType(),
|
|
502
|
+
}),
|
|
503
|
+
})),
|
|
504
|
+
},
|
|
505
|
+
);
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
const encodedTokenIdentifier = encodeBech32mTokenIdentifier({
|
|
509
|
+
tokenIdentifier: tokensMetadata[0].rawTokenIdentifier,
|
|
510
|
+
network: this.config.getNetworkType(),
|
|
511
|
+
});
|
|
512
|
+
bech32mTokenIdentifier = encodedTokenIdentifier;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
const rawTokenIdentifier = decodeBech32mTokenIdentifier(
|
|
516
|
+
bech32mTokenIdentifier,
|
|
517
|
+
this.config.getNetworkType(),
|
|
518
|
+
).tokenIdentifier;
|
|
247
519
|
|
|
248
520
|
if (this.config.getTokenTransactionVersion() === "V2") {
|
|
249
521
|
const tokenTransaction =
|
|
@@ -272,47 +544,191 @@ export abstract class IssuerSparkWallet extends SparkWallet {
|
|
|
272
544
|
|
|
273
545
|
/**
|
|
274
546
|
* Burns issuer's tokens
|
|
547
|
+
* @deprecated Use burnTokens({ tokenAmount, tokenIdentifier, selectedOutputs }) instead. This method will be removed in a future version.
|
|
275
548
|
* @param tokenAmount - The amount of tokens to burn
|
|
276
549
|
* @param selectedOutputs - Optional array of outputs to use for the burn operation
|
|
277
550
|
* @returns The transaction ID of the burn operation
|
|
551
|
+
* @throws {SparkValidationError} If multiple tokens are found for this issuer
|
|
552
|
+
* @throws {SparkValidationError} If no tokens are found for this issuer
|
|
278
553
|
*/
|
|
279
554
|
public async burnTokens(
|
|
280
555
|
tokenAmount: bigint,
|
|
281
556
|
selectedOutputs?: OutputWithPreviousTransactionData[],
|
|
557
|
+
): Promise<string>;
|
|
558
|
+
|
|
559
|
+
/**
|
|
560
|
+
* Burns issuer's tokens
|
|
561
|
+
* @param params - Object containing token burning parameters.
|
|
562
|
+
* @param params.tokenAmount - The amount of tokens to burn
|
|
563
|
+
* @param params.tokenIdentifier - The bech32m encoded token identifier
|
|
564
|
+
* @param params.selectedOutputs - Optional array of outputs to use for the burn operation
|
|
565
|
+
* @returns The transaction ID of the burn operation
|
|
566
|
+
*/
|
|
567
|
+
public async burnTokens({
|
|
568
|
+
tokenAmount,
|
|
569
|
+
tokenIdentifier,
|
|
570
|
+
selectedOutputs,
|
|
571
|
+
}: {
|
|
572
|
+
tokenAmount: bigint;
|
|
573
|
+
tokenIdentifier?: Bech32mTokenIdentifier;
|
|
574
|
+
selectedOutputs?: OutputWithPreviousTransactionData[];
|
|
575
|
+
}): Promise<string>;
|
|
576
|
+
|
|
577
|
+
public async burnTokens(
|
|
578
|
+
tokenAmountOrParams:
|
|
579
|
+
| bigint
|
|
580
|
+
| {
|
|
581
|
+
tokenAmount: bigint;
|
|
582
|
+
tokenIdentifier?: Bech32mTokenIdentifier;
|
|
583
|
+
selectedOutputs?: OutputWithPreviousTransactionData[];
|
|
584
|
+
},
|
|
585
|
+
selectedOutputs?: OutputWithPreviousTransactionData[],
|
|
282
586
|
): Promise<string> {
|
|
587
|
+
let bech32mTokenIdentifier: Bech32mTokenIdentifier;
|
|
588
|
+
let tokenAmount: bigint;
|
|
589
|
+
let outputs: OutputWithPreviousTransactionData[] | undefined;
|
|
590
|
+
|
|
591
|
+
if (typeof tokenAmountOrParams === "bigint") {
|
|
592
|
+
tokenAmount = tokenAmountOrParams;
|
|
593
|
+
outputs = selectedOutputs;
|
|
594
|
+
|
|
595
|
+
const tokenIdentifiers = await this.getIssuerTokenIdentifiers();
|
|
596
|
+
if (tokenIdentifiers.length > 1) {
|
|
597
|
+
throw new SparkValidationError(
|
|
598
|
+
"Multiple tokens found. Use burnTokens({ tokenIdentifier, tokenAmount, selectedOutputs }) to specify which token to burn.",
|
|
599
|
+
{
|
|
600
|
+
field: "tokenIdentifier",
|
|
601
|
+
availableTokens: tokenIdentifiers,
|
|
602
|
+
},
|
|
603
|
+
);
|
|
604
|
+
}
|
|
605
|
+
if (tokenIdentifiers.length === 0) {
|
|
606
|
+
throw new SparkValidationError(
|
|
607
|
+
"No tokens found. Create a token first.",
|
|
608
|
+
);
|
|
609
|
+
}
|
|
610
|
+
bech32mTokenIdentifier = tokenIdentifiers[0];
|
|
611
|
+
} else {
|
|
612
|
+
tokenAmount = tokenAmountOrParams.tokenAmount;
|
|
613
|
+
outputs = tokenAmountOrParams.selectedOutputs;
|
|
614
|
+
|
|
615
|
+
if (tokenAmountOrParams.tokenIdentifier) {
|
|
616
|
+
const tokenIdentifiers = await this.getIssuerTokenIdentifiers();
|
|
617
|
+
const tokenIdentifier = tokenIdentifiers.find(
|
|
618
|
+
(identifier) => identifier === tokenAmountOrParams.tokenIdentifier,
|
|
619
|
+
);
|
|
620
|
+
if (!tokenIdentifier) {
|
|
621
|
+
throw new SparkValidationError("Token not found for this issuer", {
|
|
622
|
+
field: "tokenIdentifier",
|
|
623
|
+
value: tokenAmountOrParams.tokenIdentifier,
|
|
624
|
+
});
|
|
625
|
+
}
|
|
626
|
+
bech32mTokenIdentifier = tokenAmountOrParams.tokenIdentifier;
|
|
627
|
+
} else {
|
|
628
|
+
const tokenIdentifiers = await this.getIssuerTokenIdentifiers();
|
|
629
|
+
if (tokenIdentifiers.length === 0) {
|
|
630
|
+
throw new SparkValidationError(
|
|
631
|
+
"No tokens found. Create a token first.",
|
|
632
|
+
);
|
|
633
|
+
}
|
|
634
|
+
if (tokenIdentifiers.length > 1) {
|
|
635
|
+
throw new SparkValidationError(
|
|
636
|
+
"Multiple tokens found. Please specify tokenIdentifier in parameters.",
|
|
637
|
+
{
|
|
638
|
+
field: "tokenIdentifier",
|
|
639
|
+
availableTokens: tokenIdentifiers,
|
|
640
|
+
},
|
|
641
|
+
);
|
|
642
|
+
}
|
|
643
|
+
bech32mTokenIdentifier = tokenIdentifiers[0];
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
|
|
283
647
|
const burnAddress = encodeSparkAddress({
|
|
284
648
|
identityPublicKey: BURN_ADDRESS,
|
|
285
649
|
network: this.config.getNetworkType(),
|
|
286
650
|
});
|
|
287
|
-
const issuerTokenIdentifier: Bech32mTokenIdentifier =
|
|
288
|
-
await this.getIssuerTokenIdentifier();
|
|
289
651
|
|
|
290
652
|
return await this.transferTokens({
|
|
291
|
-
tokenIdentifier:
|
|
653
|
+
tokenIdentifier: bech32mTokenIdentifier,
|
|
292
654
|
tokenAmount,
|
|
293
655
|
receiverSparkAddress: burnAddress,
|
|
294
|
-
selectedOutputs,
|
|
656
|
+
selectedOutputs: outputs,
|
|
295
657
|
});
|
|
296
658
|
}
|
|
297
659
|
|
|
298
660
|
/**
|
|
299
661
|
* Freezes tokens associated with a specific Spark address.
|
|
662
|
+
* @deprecated Use freezeToken({ tokenIdentifier, sparkAddress }) instead. This method will be removed in a future version.
|
|
300
663
|
* @param sparkAddress - The Spark address whose tokens should be frozen
|
|
301
664
|
* @returns An object containing the IDs of impacted outputs and the total amount of frozen tokens
|
|
665
|
+
* @throws {SparkValidationError} If multiple tokens are found for this issuer
|
|
666
|
+
* @throws {SparkValidationError} If no tokens are found for this issuer
|
|
302
667
|
*/
|
|
303
668
|
public async freezeTokens(
|
|
304
669
|
sparkAddress: string,
|
|
670
|
+
): Promise<{ impactedOutputIds: string[]; impactedTokenAmount: bigint }>;
|
|
671
|
+
|
|
672
|
+
/**
|
|
673
|
+
* Freezes tokens associated with a specific Spark address.
|
|
674
|
+
* @param params - Object containing token freezing parameters.
|
|
675
|
+
* @param params.tokenIdentifier - The bech32m encoded token identifier
|
|
676
|
+
* @param params.sparkAddress - The Spark address whose tokens should be frozen
|
|
677
|
+
* @returns An object containing the IDs of impacted outputs and the total amount of frozen tokens
|
|
678
|
+
*/
|
|
679
|
+
public async freezeTokens({
|
|
680
|
+
tokenIdentifier,
|
|
681
|
+
sparkAddress,
|
|
682
|
+
}: {
|
|
683
|
+
tokenIdentifier: Bech32mTokenIdentifier;
|
|
684
|
+
sparkAddress: string;
|
|
685
|
+
}): Promise<{ impactedOutputIds: string[]; impactedTokenAmount: bigint }>;
|
|
686
|
+
|
|
687
|
+
public async freezeTokens(
|
|
688
|
+
sparkAddressOrParams:
|
|
689
|
+
| string
|
|
690
|
+
| {
|
|
691
|
+
tokenIdentifier: Bech32mTokenIdentifier;
|
|
692
|
+
sparkAddress: string;
|
|
693
|
+
},
|
|
305
694
|
): Promise<{ impactedOutputIds: string[]; impactedTokenAmount: bigint }> {
|
|
306
|
-
|
|
695
|
+
let bech32mTokenIdentifier: Bech32mTokenIdentifier | undefined;
|
|
696
|
+
let sparkAddress: string;
|
|
697
|
+
|
|
698
|
+
if (typeof sparkAddressOrParams === "string") {
|
|
699
|
+
sparkAddress = sparkAddressOrParams;
|
|
700
|
+
bech32mTokenIdentifier = undefined;
|
|
701
|
+
} else {
|
|
702
|
+
sparkAddress = sparkAddressOrParams.sparkAddress;
|
|
703
|
+
bech32mTokenIdentifier = sparkAddressOrParams.tokenIdentifier;
|
|
704
|
+
}
|
|
705
|
+
|
|
307
706
|
const decodedOwnerPubkey = decodeSparkAddress(
|
|
308
707
|
sparkAddress,
|
|
309
708
|
this.config.getNetworkType(),
|
|
310
709
|
);
|
|
311
710
|
|
|
312
|
-
|
|
711
|
+
if (bech32mTokenIdentifier === undefined) {
|
|
712
|
+
const tokenIdentifiers = await this.getIssuerTokenIdentifiers();
|
|
713
|
+
if (tokenIdentifiers.length === 0) {
|
|
714
|
+
throw new SparkValidationError(
|
|
715
|
+
"No tokens found. Create a token first.",
|
|
716
|
+
);
|
|
717
|
+
}
|
|
718
|
+
if (tokenIdentifiers.length > 1) {
|
|
719
|
+
throw new SparkValidationError(
|
|
720
|
+
"Multiple tokens found. Use freezeTokens({ tokenIdentifier, sparkAddress }) instead.",
|
|
721
|
+
{
|
|
722
|
+
field: "tokenIdentifier",
|
|
723
|
+
availableTokens: tokenIdentifiers,
|
|
724
|
+
},
|
|
725
|
+
);
|
|
726
|
+
}
|
|
727
|
+
bech32mTokenIdentifier = tokenIdentifiers[0];
|
|
728
|
+
}
|
|
313
729
|
|
|
314
730
|
const rawTokenIdentifier = decodeBech32mTokenIdentifier(
|
|
315
|
-
|
|
731
|
+
bech32mTokenIdentifier,
|
|
316
732
|
this.config.getNetworkType(),
|
|
317
733
|
).tokenIdentifier;
|
|
318
734
|
|
|
@@ -332,22 +748,73 @@ export abstract class IssuerSparkWallet extends SparkWallet {
|
|
|
332
748
|
|
|
333
749
|
/**
|
|
334
750
|
* Unfreezes previously frozen tokens associated with a specific Spark address.
|
|
751
|
+
* @deprecated Use unfreezeToken({ tokenIdentifier, sparkAddress }) instead. This method will be removed in a future version.
|
|
335
752
|
* @param sparkAddress - The Spark address whose tokens should be unfrozen
|
|
336
753
|
* @returns An object containing the IDs of impacted outputs and the total amount of unfrozen tokens
|
|
754
|
+
* @throws {SparkValidationError} If multiple tokens are found for this issuer
|
|
755
|
+
* @throws {SparkValidationError} If no tokens are found for this issuer
|
|
337
756
|
*/
|
|
338
757
|
public async unfreezeTokens(
|
|
339
758
|
sparkAddress: string,
|
|
759
|
+
): Promise<{ impactedOutputIds: string[]; impactedTokenAmount: bigint }>;
|
|
760
|
+
|
|
761
|
+
/**
|
|
762
|
+
* Unfreezes previously frozen tokens associated with a specific Spark address.
|
|
763
|
+
* @param params - Object containing token unfreezing parameters.
|
|
764
|
+
* @param params.tokenIdentifier - The bech32m encoded token identifier
|
|
765
|
+
* @param params.sparkAddress - The Spark address whose tokens should be unfrozen
|
|
766
|
+
* @returns An object containing the IDs of impacted outputs and the total amount of unfrozen tokens
|
|
767
|
+
* @throws {SparkValidationError} If multiple tokens are found for this issuer
|
|
768
|
+
* @throws {SparkValidationError} If no tokens are found for this issuer
|
|
769
|
+
*/
|
|
770
|
+
public async unfreezeTokens({
|
|
771
|
+
tokenIdentifier,
|
|
772
|
+
sparkAddress,
|
|
773
|
+
}: {
|
|
774
|
+
tokenIdentifier: Bech32mTokenIdentifier;
|
|
775
|
+
sparkAddress: string;
|
|
776
|
+
}): Promise<{ impactedOutputIds: string[]; impactedTokenAmount: bigint }>;
|
|
777
|
+
|
|
778
|
+
public async unfreezeTokens(
|
|
779
|
+
sparkAddressOrParams:
|
|
780
|
+
| string
|
|
781
|
+
| {
|
|
782
|
+
tokenIdentifier: Bech32mTokenIdentifier;
|
|
783
|
+
sparkAddress: string;
|
|
784
|
+
},
|
|
340
785
|
): Promise<{ impactedOutputIds: string[]; impactedTokenAmount: bigint }> {
|
|
341
|
-
|
|
786
|
+
let bech32mTokenIdentifier: Bech32mTokenIdentifier | undefined;
|
|
787
|
+
let sparkAddress: string;
|
|
788
|
+
|
|
789
|
+
if (typeof sparkAddressOrParams === "string") {
|
|
790
|
+
sparkAddress = sparkAddressOrParams;
|
|
791
|
+
bech32mTokenIdentifier = undefined;
|
|
792
|
+
} else {
|
|
793
|
+
sparkAddress = sparkAddressOrParams.sparkAddress;
|
|
794
|
+
bech32mTokenIdentifier = sparkAddressOrParams.tokenIdentifier;
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
if (bech32mTokenIdentifier === undefined) {
|
|
798
|
+
const tokenIdentifiers = await this.getIssuerTokenIdentifiers();
|
|
799
|
+
if (tokenIdentifiers.length > 1) {
|
|
800
|
+
throw new SparkValidationError(
|
|
801
|
+
"Multiple tokens found. Use unfreezeTokens({ tokenIdentifier, sparkAddress }) instead.",
|
|
802
|
+
{
|
|
803
|
+
field: "tokenIdentifier",
|
|
804
|
+
availableTokens: tokenIdentifiers,
|
|
805
|
+
},
|
|
806
|
+
);
|
|
807
|
+
}
|
|
808
|
+
bech32mTokenIdentifier = tokenIdentifiers[0];
|
|
809
|
+
}
|
|
810
|
+
|
|
342
811
|
const decodedOwnerPubkey = decodeSparkAddress(
|
|
343
812
|
sparkAddress,
|
|
344
813
|
this.config.getNetworkType(),
|
|
345
814
|
);
|
|
346
815
|
|
|
347
|
-
const issuerTokenIdentifier = await this.getIssuerTokenIdentifier();
|
|
348
|
-
|
|
349
816
|
const rawTokenIdentifier = decodeBech32mTokenIdentifier(
|
|
350
|
-
|
|
817
|
+
bech32mTokenIdentifier,
|
|
351
818
|
this.config.getNetworkType(),
|
|
352
819
|
).tokenIdentifier;
|
|
353
820
|
|
|
@@ -421,8 +888,11 @@ type IssuerSparkWalletFunctionKeys = Extract<
|
|
|
421
888
|
|
|
422
889
|
const PUBLIC_ISSUER_SPARK_WALLET_METHODS = [
|
|
423
890
|
"getIssuerTokenBalance",
|
|
891
|
+
"getIssuerTokenBalances",
|
|
424
892
|
"getIssuerTokenMetadata",
|
|
893
|
+
"getIssuerTokensMetadata",
|
|
425
894
|
"getIssuerTokenIdentifier",
|
|
895
|
+
"getIssuerTokenIdentifiers",
|
|
426
896
|
"createToken",
|
|
427
897
|
"mintTokens",
|
|
428
898
|
"burnTokens",
|