@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
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { Bech32mTokenIdentifier } from "@buildonspark/spark-sdk";
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Token metadata containing essential information about issuer's token.
|
|
3
5
|
* This is the wallet's internal representation with JavaScript-friendly types.
|
|
@@ -36,6 +38,8 @@ export type IssuerTokenMetadata = {
|
|
|
36
38
|
isFreezable: boolean;
|
|
37
39
|
/** Extra metadata of the token */
|
|
38
40
|
extraMetadata?: Uint8Array;
|
|
41
|
+
/** Bech32m encoded token identifier */
|
|
42
|
+
bech32mTokenIdentifier: Bech32mTokenIdentifier;
|
|
39
43
|
};
|
|
40
44
|
|
|
41
45
|
export interface TokenDistribution {
|
|
@@ -45,3 +49,24 @@ export interface TokenDistribution {
|
|
|
45
49
|
numHoldingAddress: number;
|
|
46
50
|
numConfirmedTransactions: bigint;
|
|
47
51
|
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Details of a token creation.
|
|
55
|
+
*
|
|
56
|
+
* tokenIdentifier: The Bech32m encoded token identifier.
|
|
57
|
+
* transactionHash: The hash of the transaction that created the token.
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```typescript
|
|
61
|
+
* const tokenCreationDetails: TokenCreationDetails = {
|
|
62
|
+
* tokenIdentifier: "btkn1...",
|
|
63
|
+
* transactionHash: "1234567890abcdef...",
|
|
64
|
+
* };
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
export interface TokenCreationDetails {
|
|
68
|
+
/** Bech32m encoded token identifier */
|
|
69
|
+
tokenIdentifier: Bech32mTokenIdentifier;
|
|
70
|
+
/** Transaction hash of the announcement */
|
|
71
|
+
transactionHash: string;
|
|
72
|
+
}
|
|
@@ -0,0 +1,437 @@
|
|
|
1
|
+
import { jest } from "@jest/globals";
|
|
2
|
+
import { IssuerSparkWalletTesting } from "../utils/issuer-test-wallet.js";
|
|
3
|
+
import { TEST_CONFIGS } from "./test-configs.js";
|
|
4
|
+
import { IssuerSparkWallet } from "../../issuer-wallet/issuer-spark-wallet.js";
|
|
5
|
+
|
|
6
|
+
const TX_HASH_REGEX = /^[a-f0-9]{64}$/i; // valid tx hash: hex string of 64 characters
|
|
7
|
+
|
|
8
|
+
const TOKEN_AMOUNT = 100n;
|
|
9
|
+
const TOKEN_ONE_NAME = "Token1";
|
|
10
|
+
const TOKEN_ONE_TICKER = "TK1";
|
|
11
|
+
const TOKEN_ONE_METADATA = new Uint8Array([1, 2, 3]);
|
|
12
|
+
const TOKEN_TWO_NAME = "Token2";
|
|
13
|
+
const TOKEN_TWO_TICKER = "TK2";
|
|
14
|
+
const TOKEN_TWO_METADATA = new Uint8Array([4, 5, 6]);
|
|
15
|
+
|
|
16
|
+
const TOKEN_ONE_CREATE_TRANSACTION_PARAMS = {
|
|
17
|
+
tokenName: TOKEN_ONE_NAME,
|
|
18
|
+
tokenTicker: TOKEN_ONE_TICKER,
|
|
19
|
+
decimals: 0,
|
|
20
|
+
isFreezable: true,
|
|
21
|
+
maxSupply: 1000n,
|
|
22
|
+
extraMetadata: TOKEN_ONE_METADATA,
|
|
23
|
+
returnIdentifierForCreate: true,
|
|
24
|
+
} as const;
|
|
25
|
+
|
|
26
|
+
const TOKEN_TWO_CREATE_TRANSACTION_PARAMS = {
|
|
27
|
+
tokenName: TOKEN_TWO_NAME,
|
|
28
|
+
tokenTicker: TOKEN_TWO_TICKER,
|
|
29
|
+
decimals: 0,
|
|
30
|
+
isFreezable: true,
|
|
31
|
+
maxSupply: 1000n,
|
|
32
|
+
extraMetadata: TOKEN_TWO_METADATA,
|
|
33
|
+
returnIdentifierForCreate: true,
|
|
34
|
+
} as const;
|
|
35
|
+
|
|
36
|
+
const setupMultipleTokens = async (issuerWallet: IssuerSparkWallet) => {
|
|
37
|
+
const firstCreateTransactionDetails = await issuerWallet.createToken(
|
|
38
|
+
TOKEN_ONE_CREATE_TRANSACTION_PARAMS,
|
|
39
|
+
);
|
|
40
|
+
const secondCreateTransactionDetails = await issuerWallet.createToken(
|
|
41
|
+
TOKEN_TWO_CREATE_TRANSACTION_PARAMS,
|
|
42
|
+
);
|
|
43
|
+
return {
|
|
44
|
+
firstTokenIdentifier: firstCreateTransactionDetails.tokenIdentifier,
|
|
45
|
+
secondTokenIdentifier: secondCreateTransactionDetails.tokenIdentifier,
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
describe.each(TEST_CONFIGS)(
|
|
50
|
+
"multi token issuer tests - $name",
|
|
51
|
+
({ name, config }) => {
|
|
52
|
+
jest.setTimeout(80000);
|
|
53
|
+
|
|
54
|
+
it("should successfully create multiple tokens with different parameters", async () => {
|
|
55
|
+
const { wallet: issuerWallet } =
|
|
56
|
+
await IssuerSparkWalletTesting.initialize({
|
|
57
|
+
options: config,
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
const { firstTokenIdentifier, secondTokenIdentifier } =
|
|
61
|
+
await setupMultipleTokens(issuerWallet);
|
|
62
|
+
|
|
63
|
+
expect(firstTokenIdentifier).toBeDefined();
|
|
64
|
+
expect(firstTokenIdentifier.length).toBeGreaterThan(0);
|
|
65
|
+
expect(secondTokenIdentifier).toBeDefined();
|
|
66
|
+
expect(secondTokenIdentifier.length).toBeGreaterThan(0);
|
|
67
|
+
|
|
68
|
+
const metadata = await issuerWallet.getIssuerTokensMetadata();
|
|
69
|
+
expect(metadata.length).toEqual(2);
|
|
70
|
+
expect(metadata[0].tokenName).toEqual("Token1");
|
|
71
|
+
expect(metadata[0].tokenTicker).toEqual("TK1");
|
|
72
|
+
expect(metadata[1].tokenName).toEqual("Token2");
|
|
73
|
+
expect(metadata[1].tokenTicker).toEqual("TK2");
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it("should fail to create multiple tokens with the same parameters", async () => {
|
|
77
|
+
const { wallet: issuerWallet } =
|
|
78
|
+
await IssuerSparkWalletTesting.initialize({
|
|
79
|
+
options: config,
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
const firstCreateTransactionDetails = await issuerWallet.createToken(
|
|
83
|
+
TOKEN_ONE_CREATE_TRANSACTION_PARAMS,
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
expect(firstCreateTransactionDetails).toBeDefined();
|
|
87
|
+
expect(firstCreateTransactionDetails.tokenIdentifier).toBeDefined();
|
|
88
|
+
expect(
|
|
89
|
+
firstCreateTransactionDetails.tokenIdentifier.length,
|
|
90
|
+
).toBeGreaterThan(0);
|
|
91
|
+
expect(firstCreateTransactionDetails.transactionHash).toBeDefined();
|
|
92
|
+
expect(
|
|
93
|
+
firstCreateTransactionDetails.transactionHash.length,
|
|
94
|
+
).toBeGreaterThan(0);
|
|
95
|
+
|
|
96
|
+
await expect(
|
|
97
|
+
issuerWallet.createToken(TOKEN_ONE_CREATE_TRANSACTION_PARAMS),
|
|
98
|
+
).rejects.toThrow();
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it("should fail to execute legacy methods that do not support multiple tokens and succeed with new methods that accept token identifiers", async () => {
|
|
102
|
+
const { wallet: issuerWallet } =
|
|
103
|
+
await IssuerSparkWalletTesting.initialize({
|
|
104
|
+
options: config,
|
|
105
|
+
});
|
|
106
|
+
const issuerSparkAddress = await issuerWallet.getSparkAddress();
|
|
107
|
+
const { wallet: receiverWallet } =
|
|
108
|
+
await IssuerSparkWalletTesting.initialize({
|
|
109
|
+
options: config,
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
const receiverAddress = await receiverWallet.getSparkAddress();
|
|
113
|
+
|
|
114
|
+
const { firstTokenIdentifier, secondTokenIdentifier } =
|
|
115
|
+
await setupMultipleTokens(issuerWallet);
|
|
116
|
+
|
|
117
|
+
// Legacy single token issuer method - should fail when multiple tokens are created
|
|
118
|
+
await expect(issuerWallet.getIssuerTokenIdentifier()).rejects.toThrow();
|
|
119
|
+
|
|
120
|
+
// Multi token issuer method - should succeed to get token identifiers
|
|
121
|
+
const tokenIdentifiers = await issuerWallet.getIssuerTokenIdentifiers();
|
|
122
|
+
expect(tokenIdentifiers.length).toEqual(2);
|
|
123
|
+
expect(tokenIdentifiers[0]).toEqual(firstTokenIdentifier);
|
|
124
|
+
expect(tokenIdentifiers[1]).toEqual(secondTokenIdentifier);
|
|
125
|
+
|
|
126
|
+
// Legacy single token issuer method - should fail when multiple tokens are created
|
|
127
|
+
await expect(issuerWallet.getIssuerTokenMetadata()).rejects.toThrow();
|
|
128
|
+
|
|
129
|
+
// Multi token issuer method - should succeed to get token metadata
|
|
130
|
+
const metadataArr = await issuerWallet.getIssuerTokensMetadata();
|
|
131
|
+
expect(metadataArr.length).toEqual(2);
|
|
132
|
+
expect(metadataArr[0].tokenName).toEqual(TOKEN_ONE_NAME);
|
|
133
|
+
expect(metadataArr[0].tokenTicker).toEqual(TOKEN_ONE_TICKER);
|
|
134
|
+
expect(metadataArr[1].tokenName).toEqual(TOKEN_TWO_NAME);
|
|
135
|
+
expect(metadataArr[1].tokenTicker).toEqual(TOKEN_TWO_TICKER);
|
|
136
|
+
|
|
137
|
+
// === Minting tokens ===
|
|
138
|
+
// Legacy single token issuer method - should fail when multiple tokens are created
|
|
139
|
+
await expect(issuerWallet.mintTokens(1n)).rejects.toThrow();
|
|
140
|
+
|
|
141
|
+
// Multi token issuer method - should succeed to mint tokens with a token identifier
|
|
142
|
+
const firstMintHash = await issuerWallet.mintTokens({
|
|
143
|
+
tokenAmount: 100n,
|
|
144
|
+
tokenIdentifier: firstTokenIdentifier,
|
|
145
|
+
});
|
|
146
|
+
expect(firstMintHash).toBeDefined();
|
|
147
|
+
expect(firstMintHash).toMatch(TX_HASH_REGEX);
|
|
148
|
+
|
|
149
|
+
// Multi token issuer method - should succeed to mint tokens with a token identifier
|
|
150
|
+
const secondMintHash = await issuerWallet.mintTokens({
|
|
151
|
+
tokenAmount: 100n,
|
|
152
|
+
tokenIdentifier: secondTokenIdentifier,
|
|
153
|
+
});
|
|
154
|
+
expect(secondMintHash).toBeDefined();
|
|
155
|
+
expect(secondMintHash).toMatch(TX_HASH_REGEX);
|
|
156
|
+
|
|
157
|
+
// Legacy single token issuer method - should fail when multiple tokens are created
|
|
158
|
+
await expect(issuerWallet.getIssuerTokenBalance()).rejects.toThrow();
|
|
159
|
+
|
|
160
|
+
// Multi token issuer method - should succeed to get token balances
|
|
161
|
+
const balances = await issuerWallet.getIssuerTokenBalances();
|
|
162
|
+
const firstBalance = balances.find(
|
|
163
|
+
(b) => b.tokenIdentifier === firstTokenIdentifier,
|
|
164
|
+
);
|
|
165
|
+
const secondBalance = balances.find(
|
|
166
|
+
(b) => b.tokenIdentifier === secondTokenIdentifier,
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
expect(firstBalance?.balance).toEqual(100n);
|
|
170
|
+
expect(secondBalance?.balance).toEqual(100n);
|
|
171
|
+
|
|
172
|
+
// Multi token issuer method - should succeed to transfer tokens with a token identifier
|
|
173
|
+
const firstTransferResponse = await issuerWallet.transferTokens({
|
|
174
|
+
tokenAmount: TOKEN_AMOUNT,
|
|
175
|
+
tokenIdentifier: firstTokenIdentifier,
|
|
176
|
+
receiverSparkAddress: receiverAddress,
|
|
177
|
+
});
|
|
178
|
+
expect(firstTransferResponse).toBeDefined();
|
|
179
|
+
expect(firstTransferResponse).toMatch(TX_HASH_REGEX);
|
|
180
|
+
|
|
181
|
+
const secondTransferResponse = await issuerWallet.transferTokens({
|
|
182
|
+
tokenAmount: TOKEN_AMOUNT,
|
|
183
|
+
tokenIdentifier: secondTokenIdentifier,
|
|
184
|
+
receiverSparkAddress: receiverAddress,
|
|
185
|
+
});
|
|
186
|
+
expect(secondTransferResponse).toBeDefined();
|
|
187
|
+
expect(secondTransferResponse).toMatch(TX_HASH_REGEX);
|
|
188
|
+
|
|
189
|
+
const receiverBalances = await receiverWallet.getBalance();
|
|
190
|
+
const receiverFirstBalance =
|
|
191
|
+
receiverBalances.tokenBalances.get(firstTokenIdentifier);
|
|
192
|
+
const receiverSecondBalance = receiverBalances.tokenBalances.get(
|
|
193
|
+
secondTokenIdentifier,
|
|
194
|
+
);
|
|
195
|
+
expect(receiverFirstBalance?.balance).toEqual(TOKEN_AMOUNT);
|
|
196
|
+
expect(receiverSecondBalance?.balance).toEqual(TOKEN_AMOUNT);
|
|
197
|
+
|
|
198
|
+
// === Freezing tokens ===
|
|
199
|
+
// Legacy single token issuer method - should fail when multiple tokens are created
|
|
200
|
+
await expect(
|
|
201
|
+
issuerWallet.freezeTokens(receiverAddress),
|
|
202
|
+
).rejects.toThrow();
|
|
203
|
+
|
|
204
|
+
// Multi token issuer method - should succeed when using freezeTokens with a token identifier
|
|
205
|
+
const freezeResponse = await issuerWallet.freezeTokens({
|
|
206
|
+
tokenIdentifier: firstTokenIdentifier,
|
|
207
|
+
sparkAddress: receiverAddress,
|
|
208
|
+
});
|
|
209
|
+
expect(freezeResponse.impactedOutputIds.length).toBeGreaterThan(0);
|
|
210
|
+
expect(freezeResponse.impactedTokenAmount).toEqual(TOKEN_AMOUNT);
|
|
211
|
+
|
|
212
|
+
// Should fail to transfer tokens because the outputs are frozen
|
|
213
|
+
await expect(
|
|
214
|
+
receiverWallet.transferTokens({
|
|
215
|
+
tokenAmount: TOKEN_AMOUNT,
|
|
216
|
+
tokenIdentifier: firstTokenIdentifier,
|
|
217
|
+
receiverSparkAddress: issuerSparkAddress,
|
|
218
|
+
}),
|
|
219
|
+
).rejects.toThrow();
|
|
220
|
+
|
|
221
|
+
// Multi token issuer method - should succeed to transfer tokens with a token identifier
|
|
222
|
+
const transferBackToIssuerOfNeverfrozenToken =
|
|
223
|
+
await receiverWallet.transferTokens({
|
|
224
|
+
tokenAmount: TOKEN_AMOUNT,
|
|
225
|
+
tokenIdentifier: secondTokenIdentifier,
|
|
226
|
+
receiverSparkAddress: issuerSparkAddress,
|
|
227
|
+
});
|
|
228
|
+
expect(transferBackToIssuerOfNeverfrozenToken).toBeDefined();
|
|
229
|
+
expect(transferBackToIssuerOfNeverfrozenToken).toMatch(TX_HASH_REGEX);
|
|
230
|
+
|
|
231
|
+
// === Unfreezing tokens ===
|
|
232
|
+
// Legacy single token issuer method - should fail when multiple tokens are created
|
|
233
|
+
await expect(
|
|
234
|
+
issuerWallet.unfreezeTokens(receiverAddress),
|
|
235
|
+
).rejects.toThrow();
|
|
236
|
+
|
|
237
|
+
// Multi token issuer method - should succeed when using unfreezeTokens with a token identifier
|
|
238
|
+
const unfreezeResponse = await issuerWallet.unfreezeTokens({
|
|
239
|
+
tokenIdentifier: firstTokenIdentifier,
|
|
240
|
+
sparkAddress: receiverAddress,
|
|
241
|
+
});
|
|
242
|
+
expect(unfreezeResponse.impactedOutputIds.length).toBeGreaterThan(0);
|
|
243
|
+
expect(unfreezeResponse.impactedTokenAmount).toEqual(TOKEN_AMOUNT);
|
|
244
|
+
|
|
245
|
+
// Outputs unfrozen, transfer should succeed
|
|
246
|
+
const transferBackToIssuerOfOnceFrozenToken =
|
|
247
|
+
await receiverWallet.transferTokens({
|
|
248
|
+
tokenAmount: TOKEN_AMOUNT,
|
|
249
|
+
tokenIdentifier: firstTokenIdentifier,
|
|
250
|
+
receiverSparkAddress: issuerSparkAddress,
|
|
251
|
+
});
|
|
252
|
+
expect(transferBackToIssuerOfOnceFrozenToken).toBeDefined();
|
|
253
|
+
expect(transferBackToIssuerOfOnceFrozenToken).toMatch(TX_HASH_REGEX);
|
|
254
|
+
|
|
255
|
+
const receiverBalancesAfterTransferBack =
|
|
256
|
+
await receiverWallet.getBalance();
|
|
257
|
+
const receiverFirstBalanceAfterTransferBack =
|
|
258
|
+
receiverBalancesAfterTransferBack.tokenBalances.get(
|
|
259
|
+
firstTokenIdentifier,
|
|
260
|
+
);
|
|
261
|
+
const receiverSecondBalanceAfterTransferBack =
|
|
262
|
+
receiverBalancesAfterTransferBack.tokenBalances.get(
|
|
263
|
+
secondTokenIdentifier,
|
|
264
|
+
);
|
|
265
|
+
expect(receiverFirstBalanceAfterTransferBack?.balance).toBeUndefined();
|
|
266
|
+
expect(receiverSecondBalanceAfterTransferBack?.balance).toBeUndefined();
|
|
267
|
+
|
|
268
|
+
// Verify that the issuer has the correct balances
|
|
269
|
+
const issuerBalances = await issuerWallet.getIssuerTokenBalances();
|
|
270
|
+
const issuerFirstBalance = issuerBalances.find(
|
|
271
|
+
(b) => b.tokenIdentifier === firstTokenIdentifier,
|
|
272
|
+
);
|
|
273
|
+
const issuerSecondBalance = issuerBalances.find(
|
|
274
|
+
(b) => b.tokenIdentifier === secondTokenIdentifier,
|
|
275
|
+
);
|
|
276
|
+
expect(issuerFirstBalance?.balance).toEqual(TOKEN_AMOUNT);
|
|
277
|
+
expect(issuerSecondBalance?.balance).toEqual(TOKEN_AMOUNT);
|
|
278
|
+
|
|
279
|
+
// === Burning tokens ===
|
|
280
|
+
// Legacy single token issuer method - should fail when multiple tokens are created
|
|
281
|
+
await expect(issuerWallet.burnTokens(100n)).rejects.toThrow();
|
|
282
|
+
|
|
283
|
+
// Multi token issuer method - should succeed to burn tokens with a token identifier
|
|
284
|
+
const burnResponse = await issuerWallet.burnTokens({
|
|
285
|
+
tokenAmount: TOKEN_AMOUNT,
|
|
286
|
+
tokenIdentifier: firstTokenIdentifier,
|
|
287
|
+
});
|
|
288
|
+
expect(burnResponse).toBeDefined();
|
|
289
|
+
expect(burnResponse).toMatch(TX_HASH_REGEX);
|
|
290
|
+
|
|
291
|
+
// Verify that the issuer has the correct balances
|
|
292
|
+
const issuerBalancesAfterBurn =
|
|
293
|
+
await issuerWallet.getIssuerTokenBalances();
|
|
294
|
+
const issuerFirstBalanceAfterBurn = issuerBalancesAfterBurn.find(
|
|
295
|
+
(b) => b.tokenIdentifier === firstTokenIdentifier,
|
|
296
|
+
);
|
|
297
|
+
const issuerSecondBalanceAfterBurn = issuerBalancesAfterBurn.find(
|
|
298
|
+
(b) => b.tokenIdentifier === secondTokenIdentifier,
|
|
299
|
+
);
|
|
300
|
+
expect(issuerFirstBalanceAfterBurn?.balance).toBe(0n);
|
|
301
|
+
expect(issuerSecondBalanceAfterBurn?.balance).toEqual(TOKEN_AMOUNT);
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
// CNT-608: skip until we migrate existing tests to use multi token methods
|
|
305
|
+
it.skip("should allow legacy methods to be used with a single token", async () => {
|
|
306
|
+
const { wallet: issuerWallet } =
|
|
307
|
+
await IssuerSparkWalletTesting.initialize({
|
|
308
|
+
options: config,
|
|
309
|
+
});
|
|
310
|
+
const issuerSparkAddress = await issuerWallet.getSparkAddress();
|
|
311
|
+
|
|
312
|
+
const { wallet: receiverWallet } =
|
|
313
|
+
await IssuerSparkWalletTesting.initialize({
|
|
314
|
+
options: config,
|
|
315
|
+
});
|
|
316
|
+
const receiverSparkAddress = await receiverWallet.getSparkAddress();
|
|
317
|
+
|
|
318
|
+
const createTransactionDetails = await issuerWallet.createToken(
|
|
319
|
+
TOKEN_ONE_CREATE_TRANSACTION_PARAMS,
|
|
320
|
+
);
|
|
321
|
+
expect(createTransactionDetails).toBeDefined();
|
|
322
|
+
expect(createTransactionDetails.tokenIdentifier).toBeDefined();
|
|
323
|
+
expect(createTransactionDetails.tokenIdentifier.length).toBeGreaterThan(
|
|
324
|
+
0,
|
|
325
|
+
);
|
|
326
|
+
expect(createTransactionDetails.transactionHash).toBeDefined();
|
|
327
|
+
expect(createTransactionDetails.transactionHash.length).toBeGreaterThan(
|
|
328
|
+
0,
|
|
329
|
+
);
|
|
330
|
+
|
|
331
|
+
// Legacy single token issuer method should succeed when only one token is created
|
|
332
|
+
const tokenIdentifier = await issuerWallet.getIssuerTokenIdentifier();
|
|
333
|
+
expect(tokenIdentifier).toBeDefined();
|
|
334
|
+
expect(tokenIdentifier).toEqual(createTransactionDetails.tokenIdentifier);
|
|
335
|
+
|
|
336
|
+
// === Minting tokens ===
|
|
337
|
+
const mintHash = await issuerWallet.mintTokens(TOKEN_AMOUNT);
|
|
338
|
+
expect(mintHash).toBeDefined();
|
|
339
|
+
expect(mintHash).toMatch(TX_HASH_REGEX);
|
|
340
|
+
|
|
341
|
+
// Legacy single token issuer method should succeed when only one token is created
|
|
342
|
+
const tokenBalance = await issuerWallet.getIssuerTokenBalance();
|
|
343
|
+
expect(tokenBalance).toBeDefined();
|
|
344
|
+
expect(tokenBalance.balance).toEqual(TOKEN_AMOUNT);
|
|
345
|
+
|
|
346
|
+
const issuerBalanceAfterMint = await issuerWallet.getBalance();
|
|
347
|
+
expect(
|
|
348
|
+
issuerBalanceAfterMint.tokenBalances.get(
|
|
349
|
+
createTransactionDetails.tokenIdentifier,
|
|
350
|
+
)?.balance,
|
|
351
|
+
).toEqual(TOKEN_AMOUNT);
|
|
352
|
+
|
|
353
|
+
const transferHash = await issuerWallet.transferTokens({
|
|
354
|
+
tokenAmount: TOKEN_AMOUNT,
|
|
355
|
+
tokenIdentifier: createTransactionDetails.tokenIdentifier,
|
|
356
|
+
receiverSparkAddress: receiverSparkAddress,
|
|
357
|
+
});
|
|
358
|
+
expect(transferHash).toBeDefined();
|
|
359
|
+
expect(transferHash).toMatch(TX_HASH_REGEX);
|
|
360
|
+
|
|
361
|
+
const receiverBalance = await receiverWallet.getBalance();
|
|
362
|
+
expect(
|
|
363
|
+
receiverBalance.tokenBalances.get(
|
|
364
|
+
createTransactionDetails.tokenIdentifier,
|
|
365
|
+
)?.balance,
|
|
366
|
+
).toEqual(TOKEN_AMOUNT);
|
|
367
|
+
|
|
368
|
+
const issuerBalanceAfterTransfer = await issuerWallet.getBalance();
|
|
369
|
+
expect(
|
|
370
|
+
issuerBalanceAfterTransfer.tokenBalances.get(
|
|
371
|
+
createTransactionDetails.tokenIdentifier,
|
|
372
|
+
)?.balance,
|
|
373
|
+
).toBeUndefined();
|
|
374
|
+
|
|
375
|
+
// === Freezing tokens ===
|
|
376
|
+
// Legacy single token issuer method should succeed when only one token is created
|
|
377
|
+
const freezeResponse =
|
|
378
|
+
await issuerWallet.freezeTokens(receiverSparkAddress);
|
|
379
|
+
expect(freezeResponse.impactedOutputIds.length).toBeGreaterThan(0);
|
|
380
|
+
expect(freezeResponse.impactedTokenAmount).toEqual(TOKEN_AMOUNT);
|
|
381
|
+
|
|
382
|
+
// Should fail to transfer tokens because the outputs are frozen
|
|
383
|
+
await expect(
|
|
384
|
+
receiverWallet.transferTokens({
|
|
385
|
+
tokenAmount: TOKEN_AMOUNT,
|
|
386
|
+
tokenIdentifier: createTransactionDetails.tokenIdentifier,
|
|
387
|
+
receiverSparkAddress: issuerSparkAddress,
|
|
388
|
+
}),
|
|
389
|
+
).rejects.toThrow();
|
|
390
|
+
|
|
391
|
+
// === Unfreezing tokens ===
|
|
392
|
+
// Legacy single token issuer method should succeed when only one token is created
|
|
393
|
+
const unfreezeResponse =
|
|
394
|
+
await issuerWallet.unfreezeTokens(receiverSparkAddress);
|
|
395
|
+
expect(unfreezeResponse.impactedOutputIds.length).toBeGreaterThan(0);
|
|
396
|
+
expect(unfreezeResponse.impactedTokenAmount).toEqual(TOKEN_AMOUNT);
|
|
397
|
+
|
|
398
|
+
const transferBackToIssuerOfUnfrozenToken =
|
|
399
|
+
await receiverWallet.transferTokens({
|
|
400
|
+
tokenAmount: TOKEN_AMOUNT,
|
|
401
|
+
tokenIdentifier: createTransactionDetails.tokenIdentifier,
|
|
402
|
+
receiverSparkAddress: issuerSparkAddress,
|
|
403
|
+
});
|
|
404
|
+
expect(transferBackToIssuerOfUnfrozenToken).toBeDefined();
|
|
405
|
+
expect(transferBackToIssuerOfUnfrozenToken).toMatch(TX_HASH_REGEX);
|
|
406
|
+
|
|
407
|
+
const receiverBalanceAfterTransferOfUnfrozenToken =
|
|
408
|
+
await receiverWallet.getBalance();
|
|
409
|
+
expect(
|
|
410
|
+
receiverBalanceAfterTransferOfUnfrozenToken.tokenBalances.get(
|
|
411
|
+
createTransactionDetails.tokenIdentifier,
|
|
412
|
+
)?.balance,
|
|
413
|
+
).toBeUndefined();
|
|
414
|
+
|
|
415
|
+
const issuerBalanceAfterTransferOfUnfrozenToken =
|
|
416
|
+
await issuerWallet.getBalance();
|
|
417
|
+
expect(
|
|
418
|
+
issuerBalanceAfterTransferOfUnfrozenToken.tokenBalances.get(
|
|
419
|
+
createTransactionDetails.tokenIdentifier,
|
|
420
|
+
)?.balance,
|
|
421
|
+
).toEqual(TOKEN_AMOUNT);
|
|
422
|
+
|
|
423
|
+
// === Burning tokens ===
|
|
424
|
+
// Legacy single token issuer method should succeed when only one token is created
|
|
425
|
+
const burnHash = await issuerWallet.burnTokens(TOKEN_AMOUNT);
|
|
426
|
+
expect(burnHash).toBeDefined();
|
|
427
|
+
expect(burnHash).toMatch(TX_HASH_REGEX);
|
|
428
|
+
|
|
429
|
+
const issuerBalanceAfterBurn = await issuerWallet.getBalance();
|
|
430
|
+
expect(
|
|
431
|
+
issuerBalanceAfterBurn.tokenBalances.get(
|
|
432
|
+
createTransactionDetails.tokenIdentifier,
|
|
433
|
+
)?.balance,
|
|
434
|
+
).toBeUndefined();
|
|
435
|
+
});
|
|
436
|
+
},
|
|
437
|
+
);
|
|
@@ -17,44 +17,59 @@ describe.each(TEST_CONFIGS)(
|
|
|
17
17
|
const tokenName = `${name}NFT`;
|
|
18
18
|
const tokenTicker = "NFT";
|
|
19
19
|
const extraMetadata = new Uint8Array([1, 2, 3]);
|
|
20
|
-
const
|
|
20
|
+
const createTransactionDetails = await issuerWallet.createToken({
|
|
21
21
|
tokenName,
|
|
22
22
|
tokenTicker,
|
|
23
23
|
decimals: 0,
|
|
24
24
|
isFreezable: false,
|
|
25
25
|
maxSupply: 1n,
|
|
26
26
|
extraMetadata,
|
|
27
|
+
returnIdentifierForCreate: true,
|
|
27
28
|
});
|
|
28
29
|
|
|
29
|
-
expect(typeof
|
|
30
|
-
expect(
|
|
30
|
+
expect(typeof createTransactionDetails).toBe("object");
|
|
31
|
+
expect(createTransactionDetails.tokenIdentifier).toBeDefined();
|
|
32
|
+
expect(createTransactionDetails.tokenIdentifier.length).toBeGreaterThan(
|
|
33
|
+
0,
|
|
34
|
+
);
|
|
35
|
+
expect(createTransactionDetails.transactionHash).toBeDefined();
|
|
36
|
+
expect(createTransactionDetails.transactionHash.length).toBeGreaterThan(
|
|
37
|
+
0,
|
|
38
|
+
);
|
|
39
|
+
const bech32mTokenIdentifier = createTransactionDetails.tokenIdentifier;
|
|
31
40
|
|
|
32
|
-
const metadata = await issuerWallet.
|
|
33
|
-
expect(metadata.
|
|
34
|
-
|
|
35
|
-
expect(
|
|
36
|
-
expect(
|
|
37
|
-
expect(
|
|
41
|
+
const metadata = await issuerWallet.getIssuerTokensMetadata();
|
|
42
|
+
expect(metadata.length).toEqual(1);
|
|
43
|
+
const tokensMetadata = metadata[0];
|
|
44
|
+
expect(tokensMetadata.tokenName).toEqual(tokenName);
|
|
45
|
+
expect(tokensMetadata.tokenTicker).toEqual(tokenTicker);
|
|
46
|
+
expect(tokensMetadata.maxSupply).toEqual(1n);
|
|
47
|
+
expect(tokensMetadata.decimals).toEqual(0);
|
|
48
|
+
expect(Array.from(tokensMetadata.extraMetadata!)).toEqual(
|
|
38
49
|
Array.from(extraMetadata),
|
|
39
50
|
);
|
|
40
51
|
|
|
41
|
-
const txId = await issuerWallet.mintTokens(
|
|
52
|
+
const txId = await issuerWallet.mintTokens({
|
|
53
|
+
tokenAmount: 1n,
|
|
54
|
+
tokenIdentifier: bech32mTokenIdentifier,
|
|
55
|
+
});
|
|
42
56
|
expect(typeof txId).toBe("string");
|
|
43
57
|
expect(txId.length).toBeGreaterThan(0);
|
|
44
58
|
|
|
45
|
-
const
|
|
46
|
-
expect(
|
|
47
|
-
expect(
|
|
59
|
+
const tokenIdentifiers = await issuerWallet.getIssuerTokenIdentifiers();
|
|
60
|
+
expect(tokenIdentifiers.length).toEqual(1);
|
|
61
|
+
expect(tokenIdentifiers[0]).toEqual(bech32mTokenIdentifier);
|
|
48
62
|
|
|
49
63
|
const { balance: satsBalance, tokenBalances: tokenBalancesMap } =
|
|
50
64
|
await issuerWallet.getBalance();
|
|
51
65
|
expect(satsBalance).toEqual(0n);
|
|
52
66
|
expect(tokenBalancesMap.size).toEqual(1);
|
|
53
|
-
expect(tokenBalancesMap.get(
|
|
54
|
-
expect(tokenBalancesMap.get(
|
|
67
|
+
expect(tokenBalancesMap.get(bech32mTokenIdentifier)).toBeDefined();
|
|
68
|
+
expect(tokenBalancesMap.get(bech32mTokenIdentifier)?.balance).toEqual(1n);
|
|
55
69
|
|
|
56
|
-
const tokenMetadata =
|
|
57
|
-
|
|
70
|
+
const tokenMetadata = tokenBalancesMap.get(
|
|
71
|
+
bech32mTokenIdentifier,
|
|
72
|
+
)?.tokenMetadata;
|
|
58
73
|
expect(tokenMetadata).toBeDefined();
|
|
59
74
|
expect(tokenMetadata?.tokenName).toEqual(tokenName);
|
|
60
75
|
expect(tokenMetadata?.tokenTicker).toEqual(tokenTicker);
|