@buildonspark/issuer-sdk 0.0.78 → 0.0.79
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 +7 -0
- package/dist/index.cjs +48 -12
- package/dist/index.d.cts +9 -2
- package/dist/index.d.ts +9 -2
- package/dist/index.js +50 -12
- package/package.json +2 -2
- package/src/issuer-wallet/issuer-spark-wallet.ts +54 -10
- package/src/services/token-transactions.ts +6 -4
- package/src/tests/integration/spark.test.ts +33 -18
- package/src/tests/stress/transfers.test.ts +13 -6
package/CHANGELOG.md
CHANGED
package/dist/index.cjs
CHANGED
|
@@ -181,20 +181,21 @@ var IssuerTokenTransactionService = class extends import_spark_sdk3.TokenTransac
|
|
|
181
181
|
sparkOperatorIdentityPublicKeys: super.collectOperatorIdentityPublicKeys()
|
|
182
182
|
};
|
|
183
183
|
}
|
|
184
|
-
async constructMintTokenTransaction(
|
|
184
|
+
async constructMintTokenTransaction(rawTokenIdentifierBytes, issuerTokenPublicKey, tokenAmount) {
|
|
185
185
|
return {
|
|
186
186
|
version: 1,
|
|
187
187
|
network: this.config.getNetworkProto(),
|
|
188
188
|
tokenInputs: {
|
|
189
189
|
$case: "mintInput",
|
|
190
190
|
mintInput: {
|
|
191
|
-
issuerPublicKey:
|
|
191
|
+
issuerPublicKey: issuerTokenPublicKey,
|
|
192
|
+
tokenIdentifier: rawTokenIdentifierBytes
|
|
192
193
|
}
|
|
193
194
|
},
|
|
194
195
|
tokenOutputs: [
|
|
195
196
|
{
|
|
196
|
-
ownerPublicKey:
|
|
197
|
-
|
|
197
|
+
ownerPublicKey: issuerTokenPublicKey,
|
|
198
|
+
tokenIdentifier: rawTokenIdentifierBytes,
|
|
198
199
|
tokenAmount: (0, import_utils3.numberToBytesBE)(tokenAmount, 16)
|
|
199
200
|
}
|
|
200
201
|
],
|
|
@@ -207,6 +208,7 @@ var IssuerTokenTransactionService = class extends import_spark_sdk3.TokenTransac
|
|
|
207
208
|
|
|
208
209
|
// src/issuer-wallet/issuer-spark-wallet.ts
|
|
209
210
|
var import_spark_sdk6 = require("@buildonspark/spark-sdk");
|
|
211
|
+
var import_spark_sdk7 = require("@buildonspark/spark-sdk");
|
|
210
212
|
var BURN_ADDRESS = "02".repeat(33);
|
|
211
213
|
var IssuerSparkWallet = class _IssuerSparkWallet extends import_spark_sdk4.SparkWallet {
|
|
212
214
|
issuerTokenTransactionService;
|
|
@@ -242,6 +244,10 @@ var IssuerSparkWallet = class _IssuerSparkWallet extends import_spark_sdk4.Spark
|
|
|
242
244
|
"SparkIssuerWallet.getIssuerTokenMetadata",
|
|
243
245
|
this.getIssuerTokenMetadata.bind(this)
|
|
244
246
|
);
|
|
247
|
+
this.getIssuerTokenIdentifier = this.wrapWithOtelSpan(
|
|
248
|
+
"SparkIssuerWallet.getIssuerTokenIdentifier",
|
|
249
|
+
this.getIssuerTokenIdentifier.bind(this)
|
|
250
|
+
);
|
|
245
251
|
this.mintTokens = this.wrapWithOtelSpan(
|
|
246
252
|
"SparkIssuerWallet.mintTokens",
|
|
247
253
|
this.mintTokens.bind(this)
|
|
@@ -290,22 +296,28 @@ var IssuerSparkWallet = class _IssuerSparkWallet extends import_spark_sdk4.Spark
|
|
|
290
296
|
);
|
|
291
297
|
if (!balanceObj.tokenBalances || issuerBalance === void 0) {
|
|
292
298
|
return {
|
|
299
|
+
tokenIdentifier: void 0,
|
|
293
300
|
balance: 0n
|
|
294
301
|
};
|
|
295
302
|
}
|
|
296
303
|
return {
|
|
304
|
+
tokenIdentifier: issuerBalance[0] ?? void 0,
|
|
297
305
|
balance: issuerBalance[1].balance
|
|
298
306
|
};
|
|
299
307
|
}
|
|
300
308
|
/**
|
|
301
|
-
* Retrieves
|
|
309
|
+
* Retrieves information about the issuer's token.
|
|
302
310
|
* @returns An object containing token information including public key, name, symbol, decimals, max supply, and freeze status
|
|
303
311
|
* @throws {NetworkError} If the token metadata cannot be retrieved
|
|
304
312
|
*/
|
|
305
313
|
async getIssuerTokenMetadata() {
|
|
306
314
|
const issuerPublicKey = await super.getIdentityPublicKey();
|
|
307
|
-
|
|
308
|
-
|
|
315
|
+
const tokenMetadata = this.tokenMetadata;
|
|
316
|
+
const cachedIssuerTokenMetadata = [...tokenMetadata.entries()].find(
|
|
317
|
+
([, metadata]) => (0, import_utils4.bytesToHex)(metadata.issuerPublicKey) === issuerPublicKey
|
|
318
|
+
);
|
|
319
|
+
if (cachedIssuerTokenMetadata !== void 0) {
|
|
320
|
+
const metadata = cachedIssuerTokenMetadata[1];
|
|
309
321
|
return {
|
|
310
322
|
tokenPublicKey: (0, import_utils4.bytesToHex)(metadata.issuerPublicKey),
|
|
311
323
|
rawTokenIdentifier: metadata.tokenIdentifier,
|
|
@@ -336,7 +348,11 @@ var IssuerSparkWallet = class _IssuerSparkWallet extends import_spark_sdk4.Spark
|
|
|
336
348
|
);
|
|
337
349
|
}
|
|
338
350
|
const metadata = response.tokenMetadata[0];
|
|
339
|
-
|
|
351
|
+
const tokenIdentifier = (0, import_spark_sdk7.encodeBech32mTokenIdentifier)({
|
|
352
|
+
tokenIdentifier: metadata.tokenIdentifier,
|
|
353
|
+
network: this.config.getNetworkType()
|
|
354
|
+
});
|
|
355
|
+
this.tokenMetadata.set(tokenIdentifier, metadata);
|
|
340
356
|
return {
|
|
341
357
|
tokenPublicKey: (0, import_utils4.bytesToHex)(metadata.issuerPublicKey),
|
|
342
358
|
rawTokenIdentifier: metadata.tokenIdentifier,
|
|
@@ -353,22 +369,38 @@ var IssuerSparkWallet = class _IssuerSparkWallet extends import_spark_sdk4.Spark
|
|
|
353
369
|
});
|
|
354
370
|
}
|
|
355
371
|
}
|
|
372
|
+
/**
|
|
373
|
+
* Retrieves the bech32m encoded token identifier for the issuer's token.
|
|
374
|
+
* @returns The bech32m encoded token identifier for the issuer's token
|
|
375
|
+
* @throws {NetworkError} If the token identifier cannot be retrieved
|
|
376
|
+
*/
|
|
377
|
+
async getIssuerTokenIdentifier() {
|
|
378
|
+
const tokenMetadata = await this.getIssuerTokenMetadata();
|
|
379
|
+
return (0, import_spark_sdk7.encodeBech32mTokenIdentifier)({
|
|
380
|
+
tokenIdentifier: tokenMetadata.rawTokenIdentifier,
|
|
381
|
+
network: this.config.getNetworkType()
|
|
382
|
+
});
|
|
383
|
+
}
|
|
356
384
|
/**
|
|
357
385
|
* Mints new tokens
|
|
358
386
|
* @param tokenAmount - The amount of tokens to mint
|
|
359
387
|
* @returns The transaction ID of the mint operation
|
|
360
388
|
*/
|
|
361
389
|
async mintTokens(tokenAmount) {
|
|
362
|
-
const tokenPublicKey = await super.getIdentityPublicKey();
|
|
363
390
|
let tokenTransaction;
|
|
391
|
+
const issuerTokenPublicKey = await super.getIdentityPublicKey();
|
|
392
|
+
const issuerTokenPublicKeyBytes = (0, import_utils4.hexToBytes)(issuerTokenPublicKey);
|
|
393
|
+
const tokenMetadata = await this.getIssuerTokenMetadata();
|
|
394
|
+
const rawTokenIdentifier = tokenMetadata.rawTokenIdentifier;
|
|
364
395
|
if (this.config.getTokenTransactionVersion() === "V0") {
|
|
365
396
|
tokenTransaction = await this.issuerTokenTransactionService.constructMintTokenTransactionV0(
|
|
366
|
-
|
|
397
|
+
issuerTokenPublicKeyBytes,
|
|
367
398
|
tokenAmount
|
|
368
399
|
);
|
|
369
400
|
} else {
|
|
370
401
|
tokenTransaction = await this.issuerTokenTransactionService.constructMintTokenTransaction(
|
|
371
|
-
|
|
402
|
+
rawTokenIdentifier,
|
|
403
|
+
issuerTokenPublicKeyBytes,
|
|
372
404
|
tokenAmount
|
|
373
405
|
);
|
|
374
406
|
}
|
|
@@ -387,8 +419,12 @@ var IssuerSparkWallet = class _IssuerSparkWallet extends import_spark_sdk4.Spark
|
|
|
387
419
|
identityPublicKey: BURN_ADDRESS,
|
|
388
420
|
network: this.config.getNetworkType()
|
|
389
421
|
});
|
|
422
|
+
const issuerTokenIdentifier = await this.getIssuerTokenIdentifier();
|
|
423
|
+
if (issuerTokenIdentifier === null) {
|
|
424
|
+
throw new import_spark_sdk4.ValidationError("Issuer token identifier not found");
|
|
425
|
+
}
|
|
390
426
|
return await this.transferTokens({
|
|
391
|
-
|
|
427
|
+
tokenIdentifier: issuerTokenIdentifier,
|
|
392
428
|
tokenAmount,
|
|
393
429
|
receiverSparkAddress: burnAddress,
|
|
394
430
|
selectedOutputs
|
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { SparkWallet, SparkWalletProps, ConfigOptions, SparkSigner } from '@buildonspark/spark-sdk';
|
|
1
|
+
import { SparkWallet, SparkWalletProps, ConfigOptions, SparkSigner, Bech32mTokenIdentifier } from '@buildonspark/spark-sdk';
|
|
2
2
|
import { OutputWithPreviousTransactionData } from '@buildonspark/spark-sdk/proto/spark';
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -71,14 +71,21 @@ declare class IssuerSparkWallet extends SparkWallet {
|
|
|
71
71
|
* @returns An object containing the token balance as a bigint
|
|
72
72
|
*/
|
|
73
73
|
getIssuerTokenBalance(): Promise<{
|
|
74
|
+
tokenIdentifier: Bech32mTokenIdentifier | undefined;
|
|
74
75
|
balance: bigint;
|
|
75
76
|
}>;
|
|
76
77
|
/**
|
|
77
|
-
* Retrieves
|
|
78
|
+
* Retrieves information about the issuer's token.
|
|
78
79
|
* @returns An object containing token information including public key, name, symbol, decimals, max supply, and freeze status
|
|
79
80
|
* @throws {NetworkError} If the token metadata cannot be retrieved
|
|
80
81
|
*/
|
|
81
82
|
getIssuerTokenMetadata(): Promise<IssuerTokenMetadata>;
|
|
83
|
+
/**
|
|
84
|
+
* Retrieves the bech32m encoded token identifier for the issuer's token.
|
|
85
|
+
* @returns The bech32m encoded token identifier for the issuer's token
|
|
86
|
+
* @throws {NetworkError} If the token identifier cannot be retrieved
|
|
87
|
+
*/
|
|
88
|
+
getIssuerTokenIdentifier(): Promise<Bech32mTokenIdentifier | null>;
|
|
82
89
|
/**
|
|
83
90
|
* Mints new tokens
|
|
84
91
|
* @param tokenAmount - The amount of tokens to mint
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { SparkWallet, SparkWalletProps, ConfigOptions, SparkSigner } from '@buildonspark/spark-sdk';
|
|
1
|
+
import { SparkWallet, SparkWalletProps, ConfigOptions, SparkSigner, Bech32mTokenIdentifier } from '@buildonspark/spark-sdk';
|
|
2
2
|
import { OutputWithPreviousTransactionData } from '@buildonspark/spark-sdk/proto/spark';
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -71,14 +71,21 @@ declare class IssuerSparkWallet extends SparkWallet {
|
|
|
71
71
|
* @returns An object containing the token balance as a bigint
|
|
72
72
|
*/
|
|
73
73
|
getIssuerTokenBalance(): Promise<{
|
|
74
|
+
tokenIdentifier: Bech32mTokenIdentifier | undefined;
|
|
74
75
|
balance: bigint;
|
|
75
76
|
}>;
|
|
76
77
|
/**
|
|
77
|
-
* Retrieves
|
|
78
|
+
* Retrieves information about the issuer's token.
|
|
78
79
|
* @returns An object containing token information including public key, name, symbol, decimals, max supply, and freeze status
|
|
79
80
|
* @throws {NetworkError} If the token metadata cannot be retrieved
|
|
80
81
|
*/
|
|
81
82
|
getIssuerTokenMetadata(): Promise<IssuerTokenMetadata>;
|
|
83
|
+
/**
|
|
84
|
+
* Retrieves the bech32m encoded token identifier for the issuer's token.
|
|
85
|
+
* @returns The bech32m encoded token identifier for the issuer's token
|
|
86
|
+
* @throws {NetworkError} If the token identifier cannot be retrieved
|
|
87
|
+
*/
|
|
88
|
+
getIssuerTokenIdentifier(): Promise<Bech32mTokenIdentifier | null>;
|
|
82
89
|
/**
|
|
83
90
|
* Mints new tokens
|
|
84
91
|
* @param tokenAmount - The amount of tokens to mint
|
package/dist/index.js
CHANGED
|
@@ -157,20 +157,21 @@ var IssuerTokenTransactionService = class extends TokenTransactionService {
|
|
|
157
157
|
sparkOperatorIdentityPublicKeys: super.collectOperatorIdentityPublicKeys()
|
|
158
158
|
};
|
|
159
159
|
}
|
|
160
|
-
async constructMintTokenTransaction(
|
|
160
|
+
async constructMintTokenTransaction(rawTokenIdentifierBytes, issuerTokenPublicKey, tokenAmount) {
|
|
161
161
|
return {
|
|
162
162
|
version: 1,
|
|
163
163
|
network: this.config.getNetworkProto(),
|
|
164
164
|
tokenInputs: {
|
|
165
165
|
$case: "mintInput",
|
|
166
166
|
mintInput: {
|
|
167
|
-
issuerPublicKey:
|
|
167
|
+
issuerPublicKey: issuerTokenPublicKey,
|
|
168
|
+
tokenIdentifier: rawTokenIdentifierBytes
|
|
168
169
|
}
|
|
169
170
|
},
|
|
170
171
|
tokenOutputs: [
|
|
171
172
|
{
|
|
172
|
-
ownerPublicKey:
|
|
173
|
-
|
|
173
|
+
ownerPublicKey: issuerTokenPublicKey,
|
|
174
|
+
tokenIdentifier: rawTokenIdentifierBytes,
|
|
174
175
|
tokenAmount: numberToBytesBE(tokenAmount, 16)
|
|
175
176
|
}
|
|
176
177
|
],
|
|
@@ -183,6 +184,9 @@ var IssuerTokenTransactionService = class extends TokenTransactionService {
|
|
|
183
184
|
|
|
184
185
|
// src/issuer-wallet/issuer-spark-wallet.ts
|
|
185
186
|
import { NotImplementedError } from "@buildonspark/spark-sdk";
|
|
187
|
+
import {
|
|
188
|
+
encodeBech32mTokenIdentifier
|
|
189
|
+
} from "@buildonspark/spark-sdk";
|
|
186
190
|
var BURN_ADDRESS = "02".repeat(33);
|
|
187
191
|
var IssuerSparkWallet = class _IssuerSparkWallet extends SparkWallet {
|
|
188
192
|
issuerTokenTransactionService;
|
|
@@ -218,6 +222,10 @@ var IssuerSparkWallet = class _IssuerSparkWallet extends SparkWallet {
|
|
|
218
222
|
"SparkIssuerWallet.getIssuerTokenMetadata",
|
|
219
223
|
this.getIssuerTokenMetadata.bind(this)
|
|
220
224
|
);
|
|
225
|
+
this.getIssuerTokenIdentifier = this.wrapWithOtelSpan(
|
|
226
|
+
"SparkIssuerWallet.getIssuerTokenIdentifier",
|
|
227
|
+
this.getIssuerTokenIdentifier.bind(this)
|
|
228
|
+
);
|
|
221
229
|
this.mintTokens = this.wrapWithOtelSpan(
|
|
222
230
|
"SparkIssuerWallet.mintTokens",
|
|
223
231
|
this.mintTokens.bind(this)
|
|
@@ -266,22 +274,28 @@ var IssuerSparkWallet = class _IssuerSparkWallet extends SparkWallet {
|
|
|
266
274
|
);
|
|
267
275
|
if (!balanceObj.tokenBalances || issuerBalance === void 0) {
|
|
268
276
|
return {
|
|
277
|
+
tokenIdentifier: void 0,
|
|
269
278
|
balance: 0n
|
|
270
279
|
};
|
|
271
280
|
}
|
|
272
281
|
return {
|
|
282
|
+
tokenIdentifier: issuerBalance[0] ?? void 0,
|
|
273
283
|
balance: issuerBalance[1].balance
|
|
274
284
|
};
|
|
275
285
|
}
|
|
276
286
|
/**
|
|
277
|
-
* Retrieves
|
|
287
|
+
* Retrieves information about the issuer's token.
|
|
278
288
|
* @returns An object containing token information including public key, name, symbol, decimals, max supply, and freeze status
|
|
279
289
|
* @throws {NetworkError} If the token metadata cannot be retrieved
|
|
280
290
|
*/
|
|
281
291
|
async getIssuerTokenMetadata() {
|
|
282
292
|
const issuerPublicKey = await super.getIdentityPublicKey();
|
|
283
|
-
|
|
284
|
-
|
|
293
|
+
const tokenMetadata = this.tokenMetadata;
|
|
294
|
+
const cachedIssuerTokenMetadata = [...tokenMetadata.entries()].find(
|
|
295
|
+
([, metadata]) => bytesToHex(metadata.issuerPublicKey) === issuerPublicKey
|
|
296
|
+
);
|
|
297
|
+
if (cachedIssuerTokenMetadata !== void 0) {
|
|
298
|
+
const metadata = cachedIssuerTokenMetadata[1];
|
|
285
299
|
return {
|
|
286
300
|
tokenPublicKey: bytesToHex(metadata.issuerPublicKey),
|
|
287
301
|
rawTokenIdentifier: metadata.tokenIdentifier,
|
|
@@ -312,7 +326,11 @@ var IssuerSparkWallet = class _IssuerSparkWallet extends SparkWallet {
|
|
|
312
326
|
);
|
|
313
327
|
}
|
|
314
328
|
const metadata = response.tokenMetadata[0];
|
|
315
|
-
|
|
329
|
+
const tokenIdentifier = encodeBech32mTokenIdentifier({
|
|
330
|
+
tokenIdentifier: metadata.tokenIdentifier,
|
|
331
|
+
network: this.config.getNetworkType()
|
|
332
|
+
});
|
|
333
|
+
this.tokenMetadata.set(tokenIdentifier, metadata);
|
|
316
334
|
return {
|
|
317
335
|
tokenPublicKey: bytesToHex(metadata.issuerPublicKey),
|
|
318
336
|
rawTokenIdentifier: metadata.tokenIdentifier,
|
|
@@ -329,22 +347,38 @@ var IssuerSparkWallet = class _IssuerSparkWallet extends SparkWallet {
|
|
|
329
347
|
});
|
|
330
348
|
}
|
|
331
349
|
}
|
|
350
|
+
/**
|
|
351
|
+
* Retrieves the bech32m encoded token identifier for the issuer's token.
|
|
352
|
+
* @returns The bech32m encoded token identifier for the issuer's token
|
|
353
|
+
* @throws {NetworkError} If the token identifier cannot be retrieved
|
|
354
|
+
*/
|
|
355
|
+
async getIssuerTokenIdentifier() {
|
|
356
|
+
const tokenMetadata = await this.getIssuerTokenMetadata();
|
|
357
|
+
return encodeBech32mTokenIdentifier({
|
|
358
|
+
tokenIdentifier: tokenMetadata.rawTokenIdentifier,
|
|
359
|
+
network: this.config.getNetworkType()
|
|
360
|
+
});
|
|
361
|
+
}
|
|
332
362
|
/**
|
|
333
363
|
* Mints new tokens
|
|
334
364
|
* @param tokenAmount - The amount of tokens to mint
|
|
335
365
|
* @returns The transaction ID of the mint operation
|
|
336
366
|
*/
|
|
337
367
|
async mintTokens(tokenAmount) {
|
|
338
|
-
const tokenPublicKey = await super.getIdentityPublicKey();
|
|
339
368
|
let tokenTransaction;
|
|
369
|
+
const issuerTokenPublicKey = await super.getIdentityPublicKey();
|
|
370
|
+
const issuerTokenPublicKeyBytes = hexToBytes2(issuerTokenPublicKey);
|
|
371
|
+
const tokenMetadata = await this.getIssuerTokenMetadata();
|
|
372
|
+
const rawTokenIdentifier = tokenMetadata.rawTokenIdentifier;
|
|
340
373
|
if (this.config.getTokenTransactionVersion() === "V0") {
|
|
341
374
|
tokenTransaction = await this.issuerTokenTransactionService.constructMintTokenTransactionV0(
|
|
342
|
-
|
|
375
|
+
issuerTokenPublicKeyBytes,
|
|
343
376
|
tokenAmount
|
|
344
377
|
);
|
|
345
378
|
} else {
|
|
346
379
|
tokenTransaction = await this.issuerTokenTransactionService.constructMintTokenTransaction(
|
|
347
|
-
|
|
380
|
+
rawTokenIdentifier,
|
|
381
|
+
issuerTokenPublicKeyBytes,
|
|
348
382
|
tokenAmount
|
|
349
383
|
);
|
|
350
384
|
}
|
|
@@ -363,8 +397,12 @@ var IssuerSparkWallet = class _IssuerSparkWallet extends SparkWallet {
|
|
|
363
397
|
identityPublicKey: BURN_ADDRESS,
|
|
364
398
|
network: this.config.getNetworkType()
|
|
365
399
|
});
|
|
400
|
+
const issuerTokenIdentifier = await this.getIssuerTokenIdentifier();
|
|
401
|
+
if (issuerTokenIdentifier === null) {
|
|
402
|
+
throw new ValidationError2("Issuer token identifier not found");
|
|
403
|
+
}
|
|
366
404
|
return await this.transferTokens({
|
|
367
|
-
|
|
405
|
+
tokenIdentifier: issuerTokenIdentifier,
|
|
368
406
|
tokenAmount,
|
|
369
407
|
receiverSparkAddress: burnAddress,
|
|
370
408
|
selectedOutputs
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@buildonspark/issuer-sdk",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.79",
|
|
4
4
|
"description": "Spark Issuer SDK for token issuance",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
},
|
|
56
56
|
"dependencies": {
|
|
57
57
|
"@buildonspark/lrc20-sdk": "0.0.59",
|
|
58
|
-
"@buildonspark/spark-sdk": "0.
|
|
58
|
+
"@buildonspark/spark-sdk": "0.2.0",
|
|
59
59
|
"@lightsparkdev/core": "^1.4.2",
|
|
60
60
|
"@noble/curves": "^1.8.0",
|
|
61
61
|
"@scure/btc-signer": "^1.5.0",
|
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
NetworkError,
|
|
4
4
|
SparkWallet,
|
|
5
5
|
SparkWalletProps,
|
|
6
|
+
UserTokenMetadata,
|
|
6
7
|
ValidationError,
|
|
7
8
|
} from "@buildonspark/spark-sdk";
|
|
8
9
|
import { isNode } from "@lightsparkdev/core";
|
|
@@ -26,6 +27,10 @@ import { IssuerTokenTransactionService } from "../services/token-transactions.js
|
|
|
26
27
|
import { TokenDistribution, IssuerTokenMetadata } from "./types.js";
|
|
27
28
|
import { NotImplementedError } from "@buildonspark/spark-sdk";
|
|
28
29
|
import { SparkSigner } from "@buildonspark/spark-sdk";
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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,44 @@ 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
|
+
|
|
200
233
|
/**
|
|
201
234
|
* Mints new tokens
|
|
202
235
|
* @param tokenAmount - The amount of tokens to mint
|
|
203
236
|
* @returns The transaction ID of the mint operation
|
|
204
237
|
*/
|
|
205
238
|
public async mintTokens(tokenAmount: bigint): Promise<string> {
|
|
206
|
-
const tokenPublicKey = await super.getIdentityPublicKey();
|
|
207
239
|
let tokenTransaction: TokenTransactionV0 | TokenTransaction;
|
|
240
|
+
const issuerTokenPublicKey = await super.getIdentityPublicKey();
|
|
241
|
+
const issuerTokenPublicKeyBytes = hexToBytes(issuerTokenPublicKey);
|
|
242
|
+
|
|
243
|
+
const tokenMetadata = await this.getIssuerTokenMetadata();
|
|
244
|
+
const rawTokenIdentifier: Uint8Array = tokenMetadata.rawTokenIdentifier;
|
|
208
245
|
|
|
209
246
|
if (this.config.getTokenTransactionVersion() === "V0") {
|
|
210
247
|
tokenTransaction =
|
|
211
248
|
await this.issuerTokenTransactionService.constructMintTokenTransactionV0(
|
|
212
|
-
|
|
249
|
+
issuerTokenPublicKeyBytes,
|
|
213
250
|
tokenAmount,
|
|
214
251
|
);
|
|
215
252
|
} else {
|
|
216
253
|
tokenTransaction =
|
|
217
254
|
await this.issuerTokenTransactionService.constructMintTokenTransaction(
|
|
218
|
-
|
|
255
|
+
rawTokenIdentifier,
|
|
256
|
+
issuerTokenPublicKeyBytes,
|
|
219
257
|
tokenAmount,
|
|
220
258
|
);
|
|
221
259
|
}
|
|
@@ -239,8 +277,14 @@ export class IssuerSparkWallet extends SparkWallet {
|
|
|
239
277
|
identityPublicKey: BURN_ADDRESS,
|
|
240
278
|
network: this.config.getNetworkType(),
|
|
241
279
|
});
|
|
280
|
+
const issuerTokenIdentifier: Bech32mTokenIdentifier | null =
|
|
281
|
+
await this.getIssuerTokenIdentifier();
|
|
282
|
+
if (issuerTokenIdentifier === null) {
|
|
283
|
+
throw new ValidationError("Issuer token identifier not found");
|
|
284
|
+
}
|
|
285
|
+
|
|
242
286
|
return await this.transferTokens({
|
|
243
|
-
|
|
287
|
+
tokenIdentifier: issuerTokenIdentifier,
|
|
244
288
|
tokenAmount,
|
|
245
289
|
receiverSparkAddress: burnAddress,
|
|
246
290
|
selectedOutputs,
|
|
@@ -39,7 +39,8 @@ export class IssuerTokenTransactionService extends TokenTransactionService {
|
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
async constructMintTokenTransaction(
|
|
42
|
-
|
|
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:
|
|
52
|
+
issuerPublicKey: issuerTokenPublicKey,
|
|
53
|
+
tokenIdentifier: rawTokenIdentifierBytes,
|
|
52
54
|
},
|
|
53
55
|
},
|
|
54
56
|
tokenOutputs: [
|
|
55
57
|
{
|
|
56
|
-
ownerPublicKey:
|
|
57
|
-
|
|
58
|
+
ownerPublicKey: issuerTokenPublicKey,
|
|
59
|
+
tokenIdentifier: rawTokenIdentifierBytes,
|
|
58
60
|
tokenAmount: numberToBytesBE(tokenAmount, 16),
|
|
59
61
|
},
|
|
60
62
|
],
|
|
@@ -139,9 +139,14 @@ describe.each(TEST_CONFIGS)(
|
|
|
139
139
|
const tokenAmount: bigint = 1000n;
|
|
140
140
|
|
|
141
141
|
await sharedIssuerWallet.mintTokens(tokenAmount);
|
|
142
|
+
|
|
143
|
+
const sharedIssuerBalance =
|
|
144
|
+
await sharedIssuerWallet.getIssuerTokenBalance();
|
|
145
|
+
expect(sharedIssuerBalance).toBeDefined();
|
|
146
|
+
expect(sharedIssuerBalance.tokenIdentifier).toBeDefined();
|
|
142
147
|
await sharedIssuerWallet.transferTokens({
|
|
143
148
|
tokenAmount,
|
|
144
|
-
|
|
149
|
+
tokenIdentifier: sharedIssuerBalance.tokenIdentifier!,
|
|
145
150
|
receiverSparkAddress: await sharedUserWallet.getSparkAddress(),
|
|
146
151
|
});
|
|
147
152
|
|
|
@@ -308,24 +313,28 @@ describe.each(TEST_CONFIGS)(
|
|
|
308
313
|
});
|
|
309
314
|
|
|
310
315
|
await sharedIssuerWallet.mintTokens(tokenAmount);
|
|
311
|
-
const
|
|
312
|
-
await sharedIssuerWallet.getIssuerTokenBalance()
|
|
313
|
-
).
|
|
316
|
+
const sharedIssuerBalance =
|
|
317
|
+
await sharedIssuerWallet.getIssuerTokenBalance();
|
|
318
|
+
expect(sharedIssuerBalance).toBeDefined();
|
|
319
|
+
expect(sharedIssuerBalance.tokenIdentifier).toBeDefined();
|
|
320
|
+
|
|
321
|
+
const tokenIdentifier = sharedIssuerBalance.tokenIdentifier!;
|
|
322
|
+
const sourceBalanceBefore = sharedIssuerBalance.balance;
|
|
314
323
|
|
|
315
324
|
await sharedIssuerWallet.batchTransferTokens([
|
|
316
325
|
{
|
|
317
326
|
tokenAmount: tokenAmount / 3n,
|
|
318
|
-
|
|
327
|
+
tokenIdentifier,
|
|
319
328
|
receiverSparkAddress: await destinationWallet.getSparkAddress(),
|
|
320
329
|
},
|
|
321
330
|
{
|
|
322
331
|
tokenAmount: tokenAmount / 3n,
|
|
323
|
-
|
|
332
|
+
tokenIdentifier,
|
|
324
333
|
receiverSparkAddress: await destinationWallet2.getSparkAddress(),
|
|
325
334
|
},
|
|
326
335
|
{
|
|
327
336
|
tokenAmount: tokenAmount / 3n,
|
|
328
|
-
|
|
337
|
+
tokenIdentifier,
|
|
329
338
|
receiverSparkAddress: await destinationWallet3.getSparkAddress(),
|
|
330
339
|
},
|
|
331
340
|
]);
|
|
@@ -461,9 +470,14 @@ describe.each(TEST_CONFIGS)(
|
|
|
461
470
|
await issuerWallet.mintTokens(tokenAmount);
|
|
462
471
|
|
|
463
472
|
// Check issuer balance after minting
|
|
464
|
-
const
|
|
465
|
-
await issuerWallet.getIssuerTokenBalance()
|
|
466
|
-
).
|
|
473
|
+
const issuerBalanceObjAfterMint =
|
|
474
|
+
await issuerWallet.getIssuerTokenBalance();
|
|
475
|
+
expect(issuerBalanceObjAfterMint).toBeDefined();
|
|
476
|
+
expect(issuerBalanceObjAfterMint.tokenIdentifier).toBeDefined();
|
|
477
|
+
|
|
478
|
+
const issuerBalanceAfterMint = issuerBalanceObjAfterMint.balance;
|
|
479
|
+
const tokenIdentifier = issuerBalanceObjAfterMint.tokenIdentifier!;
|
|
480
|
+
|
|
467
481
|
expect(issuerBalanceAfterMint).toEqual(tokenAmount);
|
|
468
482
|
|
|
469
483
|
const { wallet: userWallet } = await SparkWalletTesting.initialize({
|
|
@@ -473,7 +487,7 @@ describe.each(TEST_CONFIGS)(
|
|
|
473
487
|
|
|
474
488
|
await issuerWallet.transferTokens({
|
|
475
489
|
tokenAmount,
|
|
476
|
-
|
|
490
|
+
tokenIdentifier,
|
|
477
491
|
receiverSparkAddress: userWalletPublicKey,
|
|
478
492
|
});
|
|
479
493
|
const issuerBalanceAfterTransfer = (
|
|
@@ -533,17 +547,18 @@ describe.each(TEST_CONFIGS)(
|
|
|
533
547
|
.balance;
|
|
534
548
|
|
|
535
549
|
await sharedIssuerWallet.mintTokens(tokenAmount);
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
550
|
+
const issuerBalanceObjAfterMint =
|
|
551
|
+
await sharedIssuerWallet.getIssuerTokenBalance();
|
|
552
|
+
expect(issuerBalanceObjAfterMint).toBeDefined();
|
|
553
|
+
const issuerBalanceAfterMint = issuerBalanceObjAfterMint.balance;
|
|
540
554
|
expect(issuerBalanceAfterMint).toEqual(initialBalance + tokenAmount);
|
|
541
|
-
|
|
555
|
+
expect(issuerBalanceObjAfterMint.tokenIdentifier).toBeDefined();
|
|
556
|
+
const tokenIdentifier = issuerBalanceObjAfterMint.tokenIdentifier!;
|
|
542
557
|
const userWalletPublicKey = await userWallet.getSparkAddress();
|
|
543
558
|
|
|
544
559
|
await sharedIssuerWallet.transferTokens({
|
|
545
560
|
tokenAmount,
|
|
546
|
-
|
|
561
|
+
tokenIdentifier,
|
|
547
562
|
receiverSparkAddress: userWalletPublicKey,
|
|
548
563
|
});
|
|
549
564
|
|
|
@@ -560,7 +575,7 @@ describe.each(TEST_CONFIGS)(
|
|
|
560
575
|
expect(userBalanceAfterTransfer.balance).toEqual(tokenAmount);
|
|
561
576
|
|
|
562
577
|
await userWallet.transferTokens({
|
|
563
|
-
|
|
578
|
+
tokenIdentifier,
|
|
564
579
|
tokenAmount,
|
|
565
580
|
receiverSparkAddress: await sharedIssuerWallet.getSparkAddress(),
|
|
566
581
|
});
|
|
@@ -45,6 +45,10 @@ describe("Stress test for token transfers", () => {
|
|
|
45
45
|
const tokenPublicKey = await issuerWallet.getIdentityPublicKey();
|
|
46
46
|
const userWalletSparkAddress = await userWallet.getSparkAddress();
|
|
47
47
|
const issuerWalletSparkAddress = await issuerWallet.getSparkAddress();
|
|
48
|
+
const issuerBalanceObj = await issuerWallet.getIssuerTokenBalance();
|
|
49
|
+
expect(issuerBalanceObj).toBeDefined();
|
|
50
|
+
expect(issuerBalanceObj.tokenIdentifier).toBeDefined();
|
|
51
|
+
const tokenIdentifier = issuerBalanceObj.tokenIdentifier!;
|
|
48
52
|
|
|
49
53
|
for (let i = 0; i < maxTransactionCycles; i++) {
|
|
50
54
|
if (timeoutReached) {
|
|
@@ -59,7 +63,7 @@ describe("Stress test for token transfers", () => {
|
|
|
59
63
|
try {
|
|
60
64
|
// Transfer tokens from issuer to user
|
|
61
65
|
await issuerWallet.transferTokens({
|
|
62
|
-
|
|
66
|
+
tokenIdentifier,
|
|
63
67
|
tokenAmount: TOKEN_AMOUNT,
|
|
64
68
|
receiverSparkAddress: userWalletSparkAddress,
|
|
65
69
|
});
|
|
@@ -75,7 +79,7 @@ describe("Stress test for token transfers", () => {
|
|
|
75
79
|
|
|
76
80
|
// Transfer tokens from user to issuer
|
|
77
81
|
await userWallet.transferTokens({
|
|
78
|
-
|
|
82
|
+
tokenIdentifier,
|
|
79
83
|
tokenAmount: TOKEN_AMOUNT,
|
|
80
84
|
receiverSparkAddress: issuerWalletSparkAddress,
|
|
81
85
|
});
|
|
@@ -126,20 +130,23 @@ describe("Stress test for token transfers", () => {
|
|
|
126
130
|
});
|
|
127
131
|
|
|
128
132
|
await issuer.wallet.mintTokens(TOKEN_AMOUNT);
|
|
129
|
-
const tokenPublicKey = await issuer.wallet.getIdentityPublicKey();
|
|
130
133
|
const userAddress = await user.wallet.getSparkAddress();
|
|
134
|
+
const issuerBalanceObj = await issuer.wallet.getIssuerTokenBalance();
|
|
135
|
+
expect(issuerBalanceObj).toBeDefined();
|
|
136
|
+
expect(issuerBalanceObj.tokenIdentifier).toBeDefined();
|
|
137
|
+
const tokenIdentifier = issuerBalanceObj.tokenIdentifier!;
|
|
131
138
|
|
|
132
|
-
return { issuer,
|
|
139
|
+
return { issuer, tokenIdentifier, userAddress };
|
|
133
140
|
}),
|
|
134
141
|
);
|
|
135
142
|
|
|
136
143
|
const transactions = walletPairs.map(
|
|
137
|
-
({ issuer,
|
|
144
|
+
({ issuer, tokenIdentifier, userAddress }) =>
|
|
138
145
|
async () => {
|
|
139
146
|
const start_time = Date.now();
|
|
140
147
|
try {
|
|
141
148
|
await issuer.wallet.transferTokens({
|
|
142
|
-
|
|
149
|
+
tokenIdentifier,
|
|
143
150
|
tokenAmount: TOKEN_AMOUNT,
|
|
144
151
|
receiverSparkAddress: userAddress,
|
|
145
152
|
});
|