@buildonspark/issuer-sdk 0.0.84 → 0.0.85
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 +14 -0
- package/dist/chunk-HOLMXKFE.js +663 -0
- package/dist/index.cjs +61 -64
- package/dist/index.d.cts +8 -156
- package/dist/index.d.ts +8 -156
- package/dist/index.js +13 -669
- package/dist/index.node.cjs +708 -0
- package/dist/index.node.d.cts +14 -0
- package/dist/index.node.d.ts +14 -0
- package/dist/index.node.js +34 -0
- package/dist/issuer-spark-wallet-BFzkv4X5.d.cts +164 -0
- package/dist/issuer-spark-wallet-BFzkv4X5.d.ts +164 -0
- package/package.json +23 -5
- package/src/index.node.ts +2 -0
- package/src/index.ts +1 -1
- package/src/issuer-wallet/issuer-spark-wallet.browser.ts +33 -0
- package/src/issuer-wallet/issuer-spark-wallet.node.ts +33 -0
- package/src/issuer-wallet/issuer-spark-wallet.ts +46 -66
- package/src/tests/integration/spark.test.ts +405 -323
- package/src/tests/stress/transfers.test.ts +12 -19
- package/src/tests/utils/issuer-test-wallet.ts +1 -1
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
2
|
WalletConfig,
|
|
3
3
|
ConfigOptions,
|
|
4
|
-
|
|
4
|
+
filterTokenBalanceForTokenIdentifier,
|
|
5
5
|
} from "@buildonspark/spark-sdk";
|
|
6
6
|
import { jest } from "@jest/globals";
|
|
7
7
|
import { IssuerSparkWalletTesting } from "../utils/issuer-test-wallet.js";
|
|
8
8
|
import { SparkWalletTesting } from "../utils/spark-testing-wallet.js";
|
|
9
|
+
import { BitcoinFaucet } from "@buildonspark/spark-sdk/test-utils";
|
|
10
|
+
import { bytesToHex } from "@noble/curves/abstract/utils";
|
|
11
|
+
import { IssuerSparkWallet } from "../../issuer-wallet/issuer-spark-wallet.node.js";
|
|
9
12
|
|
|
10
13
|
export const TOKENS_V0_SCHNORR_CONFIG: Required<ConfigOptions> = {
|
|
11
14
|
...WalletConfig.LOCAL,
|
|
@@ -45,33 +48,99 @@ describe.each(TEST_CONFIGS)(
|
|
|
45
48
|
({ name, config }) => {
|
|
46
49
|
jest.setTimeout(80000);
|
|
47
50
|
|
|
48
|
-
it("should
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
51
|
+
it("should create a token", async () => {
|
|
52
|
+
const { wallet: issuerWallet } =
|
|
53
|
+
await IssuerSparkWalletTesting.initialize({
|
|
54
|
+
options: config,
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
const tokenName = `${name}Creatable`;
|
|
58
|
+
const tokenTicker = "CRT";
|
|
59
|
+
const maxSupply = 5000n;
|
|
60
|
+
const decimals = 0;
|
|
61
|
+
const txId = await issuerWallet.createToken({
|
|
62
|
+
tokenName,
|
|
63
|
+
tokenTicker,
|
|
64
|
+
decimals,
|
|
65
|
+
isFreezable: false,
|
|
66
|
+
maxSupply,
|
|
52
67
|
});
|
|
53
68
|
|
|
54
|
-
|
|
69
|
+
expect(typeof txId).toBe("string");
|
|
70
|
+
expect(txId.length).toBeGreaterThan(0);
|
|
71
|
+
|
|
72
|
+
const metadata = await issuerWallet.getIssuerTokenMetadata();
|
|
73
|
+
expect(metadata.tokenName).toEqual(tokenName);
|
|
74
|
+
expect(metadata.tokenTicker).toEqual(tokenTicker);
|
|
75
|
+
expect(metadata.maxSupply).toEqual(maxSupply);
|
|
76
|
+
expect(metadata.decimals).toEqual(decimals);
|
|
55
77
|
});
|
|
56
78
|
|
|
57
|
-
it("should
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
79
|
+
it("should announce a token", async () => {
|
|
80
|
+
const { wallet: issuerWallet } =
|
|
81
|
+
await IssuerSparkWalletTesting.initialize({
|
|
82
|
+
options: config,
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
const tokenName = `${name}Announcable`;
|
|
86
|
+
const tokenTicker = "ANN";
|
|
87
|
+
const maxSupply = 5000n;
|
|
88
|
+
const decimals = 0;
|
|
89
|
+
|
|
90
|
+
await fundAndAnnounce(
|
|
91
|
+
issuerWallet,
|
|
92
|
+
5000n,
|
|
93
|
+
0,
|
|
94
|
+
tokenName,
|
|
95
|
+
tokenTicker,
|
|
96
|
+
false,
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
const metadata = await issuerWallet.getIssuerTokenMetadata();
|
|
100
|
+
expect(metadata.tokenName).toEqual(tokenName);
|
|
101
|
+
expect(metadata.tokenTicker).toEqual(tokenTicker);
|
|
102
|
+
expect(metadata.maxSupply).toEqual(maxSupply);
|
|
103
|
+
expect(metadata.decimals).toEqual(decimals);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it("should fail on duplicate token creation", async () => {
|
|
107
|
+
const { wallet: issuerWallet } =
|
|
108
|
+
await IssuerSparkWalletTesting.initialize({
|
|
109
|
+
options: config,
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
const tokenName = `${name}Dup`;
|
|
113
|
+
const tokenTicker = `DP${name}`;
|
|
114
|
+
|
|
115
|
+
await issuerWallet.createToken({
|
|
116
|
+
tokenName,
|
|
117
|
+
tokenTicker,
|
|
118
|
+
decimals: 0,
|
|
119
|
+
isFreezable: false,
|
|
120
|
+
maxSupply: 100n,
|
|
61
121
|
});
|
|
62
122
|
|
|
63
123
|
await expect(
|
|
64
|
-
|
|
65
|
-
tokenName
|
|
66
|
-
tokenTicker
|
|
67
|
-
decimals:
|
|
124
|
+
issuerWallet.createToken({
|
|
125
|
+
tokenName,
|
|
126
|
+
tokenTicker,
|
|
127
|
+
decimals: 0,
|
|
68
128
|
isFreezable: false,
|
|
69
|
-
maxSupply:
|
|
129
|
+
maxSupply: 100n,
|
|
70
130
|
}),
|
|
71
131
|
).rejects.toThrow();
|
|
72
132
|
});
|
|
73
133
|
|
|
74
|
-
it("should fail when minting
|
|
134
|
+
it("should fail when minting tokens without creation", async () => {
|
|
135
|
+
const tokenAmount: bigint = 1000n;
|
|
136
|
+
const { wallet } = await IssuerSparkWalletTesting.initialize({
|
|
137
|
+
options: config,
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
await expect(wallet.mintTokens(tokenAmount)).rejects.toThrow();
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it("should create, andfail when minting more than max supply", async () => {
|
|
75
144
|
const tokenAmount: bigint = 1000n;
|
|
76
145
|
const { wallet } = await IssuerSparkWalletTesting.initialize({
|
|
77
146
|
options: config,
|
|
@@ -87,7 +156,7 @@ describe.each(TEST_CONFIGS)(
|
|
|
87
156
|
await expect(wallet.mintTokens(tokenAmount)).rejects.toThrow();
|
|
88
157
|
});
|
|
89
158
|
|
|
90
|
-
it("should mint tokens successfully", async () => {
|
|
159
|
+
it("should create, and mint tokens successfully", async () => {
|
|
91
160
|
const tokenAmount: bigint = 1000n;
|
|
92
161
|
|
|
93
162
|
const { wallet: issuerWallet } =
|
|
@@ -121,7 +190,7 @@ describe.each(TEST_CONFIGS)(
|
|
|
121
190
|
expect(tokenBalance.balance).toBeGreaterThanOrEqual(tokenAmount);
|
|
122
191
|
});
|
|
123
192
|
|
|
124
|
-
it("should mint and transfer tokens", async () => {
|
|
193
|
+
it("should create, mint, and transfer tokens", async () => {
|
|
125
194
|
const tokenAmount: bigint = 1000n;
|
|
126
195
|
|
|
127
196
|
const { wallet: issuerWallet } =
|
|
@@ -138,7 +207,6 @@ describe.each(TEST_CONFIGS)(
|
|
|
138
207
|
isFreezable: false,
|
|
139
208
|
maxSupply: 1_000_000n,
|
|
140
209
|
});
|
|
141
|
-
const issuerPublicKey = await issuerWallet.getIdentityPublicKey();
|
|
142
210
|
|
|
143
211
|
await issuerWallet.mintTokens(tokenAmount);
|
|
144
212
|
|
|
@@ -150,149 +218,14 @@ describe.each(TEST_CONFIGS)(
|
|
|
150
218
|
});
|
|
151
219
|
|
|
152
220
|
const balanceObj = await userWallet.getBalance();
|
|
153
|
-
const userBalance =
|
|
221
|
+
const userBalance = filterTokenBalanceForTokenIdentifier(
|
|
154
222
|
balanceObj?.tokenBalances,
|
|
155
|
-
|
|
223
|
+
tokenIdentifier!,
|
|
156
224
|
);
|
|
157
225
|
expect(userBalance.balance).toBeGreaterThanOrEqual(tokenAmount);
|
|
158
226
|
});
|
|
159
227
|
|
|
160
|
-
|
|
161
|
-
// const tokenAmount: bigint = 100n;
|
|
162
|
-
|
|
163
|
-
// const { wallet: issuerWallet } =
|
|
164
|
-
// await IssuerSparkWalletTesting.initialize({
|
|
165
|
-
// options: config,
|
|
166
|
-
// });
|
|
167
|
-
|
|
168
|
-
// const { wallet: destinationWallet } = await SparkWalletTesting.initialize(
|
|
169
|
-
// {
|
|
170
|
-
// options: config,
|
|
171
|
-
// },
|
|
172
|
-
// );
|
|
173
|
-
|
|
174
|
-
// await fundAndAnnounce(issuerWallet, 100000n, 0, `${name}Transfer`, "TTO");
|
|
175
|
-
|
|
176
|
-
// {
|
|
177
|
-
// const transactions = await issuerWallet.getIssuerTokenActivity();
|
|
178
|
-
// const amount_of_transactions = transactions.transactions.length;
|
|
179
|
-
// expect(amount_of_transactions).toEqual(0);
|
|
180
|
-
// }
|
|
181
|
-
|
|
182
|
-
// await issuerWallet.mintTokens(tokenAmount);
|
|
183
|
-
|
|
184
|
-
// {
|
|
185
|
-
// const transactions = await issuerWallet.getIssuerTokenActivity();
|
|
186
|
-
// const amount_of_transactions = transactions.transactions.length;
|
|
187
|
-
// expect(amount_of_transactions).toEqual(1);
|
|
188
|
-
// }
|
|
189
|
-
|
|
190
|
-
// await issuerWallet.transferTokens({
|
|
191
|
-
// tokenAmount,
|
|
192
|
-
// tokenPublicKey: await issuerWallet.getIdentityPublicKey(),
|
|
193
|
-
// receiverSparkAddress: await destinationWallet.getSparkAddress(),
|
|
194
|
-
// });
|
|
195
|
-
|
|
196
|
-
// {
|
|
197
|
-
// const transactions = await issuerWallet.getIssuerTokenActivity();
|
|
198
|
-
// const amount_of_transactions = transactions.transactions.length;
|
|
199
|
-
// expect(amount_of_transactions).toEqual(2);
|
|
200
|
-
// }
|
|
201
|
-
|
|
202
|
-
// for (let index = 0; index < 100; ++index) {
|
|
203
|
-
// await issuerWallet.mintTokens(tokenAmount);
|
|
204
|
-
// await issuerWallet.transferTokens({
|
|
205
|
-
// tokenAmount,
|
|
206
|
-
// tokenPublicKey: await issuerWallet.getIdentityPublicKey(),
|
|
207
|
-
// receiverSparkAddress: await destinationWallet.getSparkAddress(),
|
|
208
|
-
// });
|
|
209
|
-
// } // 202 in total
|
|
210
|
-
|
|
211
|
-
// let all_transactions = await issuerWallet.getIssuerTokenActivity(250);
|
|
212
|
-
// const amount_of_transactions = all_transactions.transactions.length;
|
|
213
|
-
// expect(amount_of_transactions).toEqual(202);
|
|
214
|
-
|
|
215
|
-
// {
|
|
216
|
-
// const transactions = await issuerWallet.getIssuerTokenActivity(10);
|
|
217
|
-
// const amount_of_transactions = transactions.transactions.length;
|
|
218
|
-
// expect(amount_of_transactions).toEqual(10);
|
|
219
|
-
// }
|
|
220
|
-
|
|
221
|
-
// {
|
|
222
|
-
// let hashset_of_all_transactions: Set<String> = new Set();
|
|
223
|
-
|
|
224
|
-
// let transactions = await issuerWallet.getIssuerTokenActivity(10);
|
|
225
|
-
// let amount_of_transactions = transactions.transactions.length;
|
|
226
|
-
// expect(amount_of_transactions).toEqual(10);
|
|
227
|
-
// let page_num = 0;
|
|
228
|
-
// for (let index = 0; index < transactions.transactions.length; ++index) {
|
|
229
|
-
// const element = transactions.transactions[index];
|
|
230
|
-
// if (!(element.transaction === undefined)) {
|
|
231
|
-
// let hash: String = "";
|
|
232
|
-
// if (element.transaction.$case === "spark") {
|
|
233
|
-
// hash = element.transaction.spark.transactionHash;
|
|
234
|
-
// } else if (element.transaction.$case === "onChain") {
|
|
235
|
-
// hash = element.transaction.onChain.transactionHash;
|
|
236
|
-
// }
|
|
237
|
-
// if (hashset_of_all_transactions.has(hash)) {
|
|
238
|
-
// expect(
|
|
239
|
-
// `Dublicate found. Pagination is broken? Index of transaction: ${index} ; page №: ${page_num} ; page size: 10 ; hash_dublicate: ${hash}`,
|
|
240
|
-
// ).toEqual("");
|
|
241
|
-
// } else {
|
|
242
|
-
// hashset_of_all_transactions.add(hash);
|
|
243
|
-
// }
|
|
244
|
-
// } else {
|
|
245
|
-
// expect(
|
|
246
|
-
// `Transaction is undefined. Something is really wrong. Index of transaction: ${index} ; page №: ${page_num} ; page size: 10`,
|
|
247
|
-
// ).toEqual("");
|
|
248
|
-
// }
|
|
249
|
-
// }
|
|
250
|
-
|
|
251
|
-
// while (!(undefined === transactions.nextCursor)) {
|
|
252
|
-
// let transactions_2 = await issuerWallet.getIssuerTokenActivity(10, {
|
|
253
|
-
// lastTransactionHash: hexToBytes(
|
|
254
|
-
// transactions.nextCursor.lastTransactionHash,
|
|
255
|
-
// ),
|
|
256
|
-
// layer: transactions.nextCursor.layer,
|
|
257
|
-
// });
|
|
258
|
-
|
|
259
|
-
// ++page_num;
|
|
260
|
-
|
|
261
|
-
// for (
|
|
262
|
-
// let index = 0;
|
|
263
|
-
// index < transactions_2.transactions.length;
|
|
264
|
-
// ++index
|
|
265
|
-
// ) {
|
|
266
|
-
// const element = transactions_2.transactions[index];
|
|
267
|
-
// if (!(element.transaction === undefined)) {
|
|
268
|
-
// let hash: String = "";
|
|
269
|
-
// if (element.transaction.$case === "spark") {
|
|
270
|
-
// hash = element.transaction.spark.transactionHash;
|
|
271
|
-
// } else if (element.transaction.$case === "onChain") {
|
|
272
|
-
// hash = element.transaction.onChain.transactionHash;
|
|
273
|
-
// }
|
|
274
|
-
// if (hashset_of_all_transactions.has(hash)) {
|
|
275
|
-
// expect(
|
|
276
|
-
// `Dublicate found. Pagination is broken? Index of transaction: ${index} ; page №: ${page_num} ; page size: 10 ; hash_dublicate: ${hash}`,
|
|
277
|
-
// ).toEqual("");
|
|
278
|
-
// } else {
|
|
279
|
-
// hashset_of_all_transactions.add(hash);
|
|
280
|
-
// }
|
|
281
|
-
// } else {
|
|
282
|
-
// expect(
|
|
283
|
-
// `Transaction is undefined. Something is really wrong. Index of transaction: ${index} ; page №: ${page_num} ; page size: 10`,
|
|
284
|
-
// ).toEqual("");
|
|
285
|
-
// }
|
|
286
|
-
// }
|
|
287
|
-
|
|
288
|
-
// transactions = transactions_2;
|
|
289
|
-
// }
|
|
290
|
-
|
|
291
|
-
// expect(hashset_of_all_transactions.size == 202);
|
|
292
|
-
// }
|
|
293
|
-
// });
|
|
294
|
-
|
|
295
|
-
it("should mint and batchtransfer tokens", async () => {
|
|
228
|
+
it("should create, mint, and batchtransfer tokens", async () => {
|
|
296
229
|
const tokenAmount: bigint = 999n;
|
|
297
230
|
|
|
298
231
|
const { wallet: issuerWallet } =
|
|
@@ -307,8 +240,6 @@ describe.each(TEST_CONFIGS)(
|
|
|
307
240
|
maxSupply: 1_000_000n,
|
|
308
241
|
});
|
|
309
242
|
|
|
310
|
-
const issuerPublicKey = await issuerWallet.getIdentityPublicKey();
|
|
311
|
-
|
|
312
243
|
const { wallet: destinationWallet } = await SparkWalletTesting.initialize(
|
|
313
244
|
{
|
|
314
245
|
options: config,
|
|
@@ -356,64 +287,262 @@ describe.each(TEST_CONFIGS)(
|
|
|
356
287
|
expect(sourceBalanceAfter).toEqual(sourceBalanceBefore - tokenAmount);
|
|
357
288
|
|
|
358
289
|
const balanceObj = await destinationWallet.getBalance();
|
|
359
|
-
const destinationBalance =
|
|
290
|
+
const destinationBalance = filterTokenBalanceForTokenIdentifier(
|
|
360
291
|
balanceObj?.tokenBalances,
|
|
361
|
-
|
|
292
|
+
tokenIdentifier!,
|
|
362
293
|
);
|
|
363
294
|
expect(destinationBalance.balance).toEqual(tokenAmount / 3n);
|
|
364
295
|
const balanceObj2 = await destinationWallet2.getBalance();
|
|
365
|
-
const destinationBalance2 =
|
|
296
|
+
const destinationBalance2 = filterTokenBalanceForTokenIdentifier(
|
|
366
297
|
balanceObj2?.tokenBalances,
|
|
367
|
-
|
|
298
|
+
tokenIdentifier!,
|
|
368
299
|
);
|
|
369
300
|
expect(destinationBalance2.balance).toEqual(tokenAmount / 3n);
|
|
370
301
|
const balanceObj3 = await destinationWallet3.getBalance();
|
|
371
|
-
const destinationBalance3 =
|
|
302
|
+
const destinationBalance3 = filterTokenBalanceForTokenIdentifier(
|
|
372
303
|
balanceObj3?.tokenBalances,
|
|
373
|
-
|
|
304
|
+
tokenIdentifier!,
|
|
374
305
|
);
|
|
375
306
|
expect(destinationBalance3.balance).toEqual(tokenAmount / 3n);
|
|
376
307
|
});
|
|
377
308
|
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
309
|
+
it("should track token operations in monitoring", async () => {
|
|
310
|
+
const tokenAmount: bigint = 1000n;
|
|
311
|
+
|
|
312
|
+
const { wallet: issuerWallet } =
|
|
313
|
+
await IssuerSparkWalletTesting.initialize({
|
|
314
|
+
options: config,
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
const { wallet: userWallet } = await SparkWalletTesting.initialize({
|
|
318
|
+
options: config,
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
await issuerWallet.createToken({
|
|
322
|
+
tokenName: `${name}FRZ`,
|
|
323
|
+
tokenTicker: "FRZ",
|
|
324
|
+
decimals: 0,
|
|
325
|
+
isFreezable: true,
|
|
326
|
+
maxSupply: 100000n,
|
|
327
|
+
});
|
|
328
|
+
await issuerWallet.mintTokens(tokenAmount);
|
|
329
|
+
const tokenIdentifier = await issuerWallet.getIssuerTokenIdentifier();
|
|
330
|
+
const issuerPublicKey = await issuerWallet.getIdentityPublicKey();
|
|
331
|
+
|
|
332
|
+
await issuerWallet.transferTokens({
|
|
333
|
+
tokenAmount,
|
|
334
|
+
tokenIdentifier: tokenIdentifier!,
|
|
335
|
+
receiverSparkAddress: await userWallet.getSparkAddress(),
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
const userBalanceObj = await userWallet.getBalance();
|
|
339
|
+
const userBalance = filterTokenBalanceForTokenIdentifier(
|
|
340
|
+
userBalanceObj?.tokenBalances,
|
|
341
|
+
tokenIdentifier!,
|
|
342
|
+
);
|
|
343
|
+
expect(userBalance.balance).toBeGreaterThanOrEqual(tokenAmount);
|
|
344
|
+
|
|
345
|
+
const transactions = await issuerWallet.queryTokenTransactions({
|
|
346
|
+
tokenIdentifiers: [tokenIdentifier!],
|
|
347
|
+
ownerPublicKeys: [issuerPublicKey],
|
|
348
|
+
});
|
|
349
|
+
expect(transactions.length).toBeGreaterThanOrEqual(2);
|
|
350
|
+
|
|
351
|
+
let mint_operation = 0;
|
|
352
|
+
let transfer_operation = 0;
|
|
353
|
+
transactions.forEach((transaction) => {
|
|
354
|
+
if (transaction.tokenTransaction?.tokenInputs?.$case === "mintInput") {
|
|
355
|
+
mint_operation++;
|
|
356
|
+
} else if (
|
|
357
|
+
transaction.tokenTransaction?.tokenInputs?.$case === "transferInput"
|
|
358
|
+
) {
|
|
359
|
+
transfer_operation++;
|
|
360
|
+
}
|
|
361
|
+
});
|
|
362
|
+
expect(mint_operation).toBeGreaterThanOrEqual(1);
|
|
363
|
+
expect(transfer_operation).toBeGreaterThanOrEqual(1);
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
it("should correctly assign operation types for complete token lifecycle operations", async () => {
|
|
367
|
+
const tokenAmount = 1000n;
|
|
368
|
+
|
|
369
|
+
const { wallet: issuerWallet } =
|
|
370
|
+
await IssuerSparkWalletTesting.initialize({
|
|
371
|
+
options: config,
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
const { wallet: userWallet } = await SparkWalletTesting.initialize({
|
|
375
|
+
options: config,
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
await issuerWallet.createToken({
|
|
379
|
+
tokenName: `${name}LFC`,
|
|
380
|
+
tokenTicker: "LFC",
|
|
381
|
+
decimals: 0,
|
|
382
|
+
isFreezable: false,
|
|
383
|
+
maxSupply: 1_000_000n,
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
await issuerWallet.mintTokens(tokenAmount);
|
|
387
|
+
|
|
388
|
+
const tokenIdentifier = await issuerWallet.getIssuerTokenIdentifier();
|
|
389
|
+
const issuerPublicKey = await issuerWallet.getIdentityPublicKey();
|
|
390
|
+
|
|
391
|
+
await issuerWallet.transferTokens({
|
|
392
|
+
tokenAmount: 500n,
|
|
393
|
+
tokenIdentifier: tokenIdentifier!,
|
|
394
|
+
receiverSparkAddress: await userWallet.getSparkAddress(),
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
await userWallet.transferTokens({
|
|
398
|
+
tokenAmount: 250n,
|
|
399
|
+
tokenIdentifier: tokenIdentifier!,
|
|
400
|
+
receiverSparkAddress: await issuerWallet.getSparkAddress(),
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
const BURN_ADDRESS = "02".repeat(33);
|
|
404
|
+
|
|
405
|
+
await issuerWallet.burnTokens(250n);
|
|
406
|
+
|
|
407
|
+
const transactions = await issuerWallet.queryTokenTransactions({
|
|
408
|
+
tokenIdentifiers: [tokenIdentifier!],
|
|
409
|
+
ownerPublicKeys: [issuerPublicKey],
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
const mintTransaction = transactions.find(
|
|
413
|
+
(tx) => tx.tokenTransaction?.tokenInputs?.$case === "mintInput",
|
|
414
|
+
);
|
|
415
|
+
|
|
416
|
+
const transferTransaction = transactions.find(
|
|
417
|
+
(tx) => tx.tokenTransaction?.tokenInputs?.$case === "transferInput",
|
|
418
|
+
);
|
|
419
|
+
|
|
420
|
+
const burnTransaction = transactions.find(
|
|
421
|
+
(tx) =>
|
|
422
|
+
tx.tokenTransaction?.tokenInputs?.$case === "transferInput" &&
|
|
423
|
+
bytesToHex(tx.tokenTransaction?.tokenOutputs?.[0]?.ownerPublicKey) ===
|
|
424
|
+
BURN_ADDRESS,
|
|
425
|
+
);
|
|
426
|
+
|
|
427
|
+
expect(mintTransaction).toBeDefined();
|
|
428
|
+
expect(transferTransaction).toBeDefined();
|
|
429
|
+
expect(burnTransaction).toBeDefined();
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
it("should create, mint, get all transactions, transfer tokens multiple times, get all transactions again, and check difference", async () => {
|
|
433
|
+
const tokenAmount: bigint = 100n;
|
|
434
|
+
|
|
435
|
+
const { wallet: issuerWallet } =
|
|
436
|
+
await IssuerSparkWalletTesting.initialize({
|
|
437
|
+
options: config,
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
const { wallet: userWallet } = await SparkWalletTesting.initialize({
|
|
441
|
+
options: config,
|
|
442
|
+
});
|
|
443
|
+
|
|
444
|
+
await issuerWallet.createToken({
|
|
445
|
+
tokenName: `${name}Transfer`,
|
|
446
|
+
tokenTicker: "TTO",
|
|
447
|
+
decimals: 0,
|
|
448
|
+
isFreezable: false,
|
|
449
|
+
maxSupply: 100000n,
|
|
450
|
+
});
|
|
451
|
+
|
|
452
|
+
const tokenIdentifier = await issuerWallet.getIssuerTokenIdentifier();
|
|
453
|
+
|
|
454
|
+
await issuerWallet.mintTokens(tokenAmount);
|
|
455
|
+
|
|
456
|
+
{
|
|
457
|
+
const transactions = await issuerWallet.queryTokenTransactions({
|
|
458
|
+
tokenIdentifiers: [tokenIdentifier!],
|
|
459
|
+
});
|
|
460
|
+
const amount_of_transactions = transactions.length;
|
|
461
|
+
expect(amount_of_transactions).toEqual(1);
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
await issuerWallet.transferTokens({
|
|
465
|
+
tokenAmount,
|
|
466
|
+
tokenIdentifier: tokenIdentifier!,
|
|
467
|
+
receiverSparkAddress: await userWallet.getSparkAddress(),
|
|
468
|
+
});
|
|
469
|
+
|
|
470
|
+
{
|
|
471
|
+
const transactions = await issuerWallet.queryTokenTransactions({
|
|
472
|
+
tokenIdentifiers: [tokenIdentifier!],
|
|
473
|
+
});
|
|
474
|
+
const amount_of_transactions = transactions.length;
|
|
475
|
+
expect(amount_of_transactions).toEqual(2);
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
for (let index = 0; index < 100; ++index) {
|
|
479
|
+
await issuerWallet.mintTokens(tokenAmount);
|
|
480
|
+
await issuerWallet.transferTokens({
|
|
481
|
+
tokenAmount,
|
|
482
|
+
tokenIdentifier: tokenIdentifier!,
|
|
483
|
+
receiverSparkAddress: await userWallet.getSparkAddress(),
|
|
484
|
+
});
|
|
485
|
+
} // 202 in total
|
|
486
|
+
|
|
487
|
+
{
|
|
488
|
+
const transactions = await issuerWallet.queryTokenTransactions({
|
|
489
|
+
tokenIdentifiers: [tokenIdentifier!],
|
|
490
|
+
pageSize: 10,
|
|
491
|
+
});
|
|
492
|
+
const amount_of_transactions = transactions.length;
|
|
493
|
+
expect(amount_of_transactions).toEqual(10);
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
{
|
|
497
|
+
let hashset_of_all_transactions: Set<String> = new Set();
|
|
498
|
+
|
|
499
|
+
let pageSize = 10;
|
|
500
|
+
let offset = 0;
|
|
501
|
+
let page_num = 0;
|
|
502
|
+
|
|
503
|
+
while (true) {
|
|
504
|
+
const transactionsPage = await issuerWallet.queryTokenTransactions({
|
|
505
|
+
tokenIdentifiers: [tokenIdentifier!],
|
|
506
|
+
pageSize,
|
|
507
|
+
offset,
|
|
508
|
+
});
|
|
509
|
+
|
|
510
|
+
if (transactionsPage.length === 0) {
|
|
511
|
+
break;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
if (offset === 0) {
|
|
515
|
+
expect(transactionsPage.length).toEqual(pageSize);
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
for (let index = 0; index < transactionsPage.length; ++index) {
|
|
519
|
+
const element = transactionsPage[index];
|
|
520
|
+
if (element.tokenTransaction !== undefined) {
|
|
521
|
+
const hash: String = bytesToHex(element.tokenTransactionHash);
|
|
522
|
+
if (hashset_of_all_transactions.has(hash)) {
|
|
523
|
+
expect(
|
|
524
|
+
`Duplicate found. Pagination is broken? Index of transaction: ${index} ; page №: ${page_num} ; page size: ${pageSize} ; hash_duplicate: ${hash}`,
|
|
525
|
+
).toEqual("");
|
|
526
|
+
} else {
|
|
527
|
+
hashset_of_all_transactions.add(hash);
|
|
528
|
+
}
|
|
529
|
+
} else {
|
|
530
|
+
expect(
|
|
531
|
+
`Transaction is undefined. Something is really wrong. Index of transaction: ${index} ; page №: ${page_num} ; page size: ${pageSize}`,
|
|
532
|
+
).toEqual("");
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
// Prepare for next iteration.
|
|
537
|
+
offset += transactionsPage.length;
|
|
538
|
+
page_num += 1;
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
expect(hashset_of_all_transactions.size).toEqual(202);
|
|
542
|
+
}
|
|
543
|
+
});
|
|
544
|
+
|
|
545
|
+
it("should mint token with 1 max supply without issue", async () => {
|
|
417
546
|
const tokenAmount: bigint = 1n;
|
|
418
547
|
const { wallet: issuerWallet } =
|
|
419
548
|
await IssuerSparkWalletTesting.initialize({
|
|
@@ -433,7 +562,7 @@ describe.each(TEST_CONFIGS)(
|
|
|
433
562
|
expect(tokenBalance.balance).toEqual(tokenAmount);
|
|
434
563
|
});
|
|
435
564
|
|
|
436
|
-
it("
|
|
565
|
+
it("should be able to create a token with name of size equal to MAX_SYMBOL_SIZE", async () => {
|
|
437
566
|
const { wallet: issuerWallet } =
|
|
438
567
|
await IssuerSparkWalletTesting.initialize({
|
|
439
568
|
options: config,
|
|
@@ -448,7 +577,16 @@ describe.each(TEST_CONFIGS)(
|
|
|
448
577
|
});
|
|
449
578
|
});
|
|
450
579
|
|
|
451
|
-
it("
|
|
580
|
+
it("should be able to anounce a token with name of size equal to MAX_SYMBOL_SIZE", async () => {
|
|
581
|
+
const { wallet: issuerWallet } =
|
|
582
|
+
await IssuerSparkWalletTesting.initialize({
|
|
583
|
+
options: config,
|
|
584
|
+
});
|
|
585
|
+
|
|
586
|
+
await fundAndAnnounce(issuerWallet, 100000n, 0, "MST", "TESTAA", false);
|
|
587
|
+
});
|
|
588
|
+
|
|
589
|
+
it("should be able to create a token with symbol of size equal to MAX_NAME_SIZE", async () => {
|
|
452
590
|
const { wallet: issuerWallet } =
|
|
453
591
|
await IssuerSparkWalletTesting.initialize({
|
|
454
592
|
options: config,
|
|
@@ -463,7 +601,23 @@ describe.each(TEST_CONFIGS)(
|
|
|
463
601
|
});
|
|
464
602
|
});
|
|
465
603
|
|
|
466
|
-
it("should
|
|
604
|
+
it("should be able to announce a token with symbol of size equal to MAX_NAME_SIZE", async () => {
|
|
605
|
+
const { wallet: issuerWallet } =
|
|
606
|
+
await IssuerSparkWalletTesting.initialize({
|
|
607
|
+
options: config,
|
|
608
|
+
});
|
|
609
|
+
|
|
610
|
+
await fundAndAnnounce(
|
|
611
|
+
issuerWallet,
|
|
612
|
+
100000n,
|
|
613
|
+
0,
|
|
614
|
+
"ABCDEFGHIJKLMNOPQ",
|
|
615
|
+
"MQS",
|
|
616
|
+
false,
|
|
617
|
+
);
|
|
618
|
+
});
|
|
619
|
+
|
|
620
|
+
it("should create, mint, freeze, and unfreeze tokens", async () => {
|
|
467
621
|
const tokenAmount: bigint = 1000n;
|
|
468
622
|
const { wallet: issuerWallet } =
|
|
469
623
|
await IssuerSparkWalletTesting.initialize({
|
|
@@ -505,11 +659,10 @@ describe.each(TEST_CONFIGS)(
|
|
|
505
659
|
).balance;
|
|
506
660
|
expect(issuerBalanceAfterTransfer).toEqual(0n);
|
|
507
661
|
|
|
508
|
-
const tokenPublicKey = await issuerWallet.getIdentityPublicKey();
|
|
509
662
|
const userBalanceObj = await userWallet.getBalance();
|
|
510
|
-
const userBalanceAfterTransfer =
|
|
663
|
+
const userBalanceAfterTransfer = filterTokenBalanceForTokenIdentifier(
|
|
511
664
|
userBalanceObj?.tokenBalances,
|
|
512
|
-
|
|
665
|
+
tokenIdentifier!,
|
|
513
666
|
);
|
|
514
667
|
expect(userBalanceAfterTransfer.balance).toEqual(tokenAmount);
|
|
515
668
|
|
|
@@ -525,7 +678,7 @@ describe.each(TEST_CONFIGS)(
|
|
|
525
678
|
expect(unfreezeResponse.impactedTokenAmount).toEqual(tokenAmount);
|
|
526
679
|
});
|
|
527
680
|
|
|
528
|
-
it("should mint and burn tokens", async () => {
|
|
681
|
+
it("should create, mint and burn tokens", async () => {
|
|
529
682
|
const tokenAmount: bigint = 200n;
|
|
530
683
|
|
|
531
684
|
const { wallet: issuerWallet } =
|
|
@@ -555,7 +708,7 @@ describe.each(TEST_CONFIGS)(
|
|
|
555
708
|
);
|
|
556
709
|
});
|
|
557
710
|
|
|
558
|
-
it("should complete full token lifecycle
|
|
711
|
+
it("should complete a full token lifecycle - create, mint, transfer, return, burn", async () => {
|
|
559
712
|
const tokenAmount: bigint = 1000n;
|
|
560
713
|
|
|
561
714
|
const { wallet: issuerWallet } =
|
|
@@ -569,7 +722,6 @@ describe.each(TEST_CONFIGS)(
|
|
|
569
722
|
isFreezable: false,
|
|
570
723
|
maxSupply: 1_000_000n,
|
|
571
724
|
});
|
|
572
|
-
const issuerPublicKey = await issuerWallet.getIdentityPublicKey();
|
|
573
725
|
|
|
574
726
|
const { wallet: userWallet } = await SparkWalletTesting.initialize({
|
|
575
727
|
options: config,
|
|
@@ -600,9 +752,9 @@ describe.each(TEST_CONFIGS)(
|
|
|
600
752
|
expect(issuerBalanceAfterTransfer).toEqual(initialBalance);
|
|
601
753
|
|
|
602
754
|
const userBalanceObj = await userWallet.getBalance();
|
|
603
|
-
const userBalanceAfterTransfer =
|
|
755
|
+
const userBalanceAfterTransfer = filterTokenBalanceForTokenIdentifier(
|
|
604
756
|
userBalanceObj?.tokenBalances,
|
|
605
|
-
|
|
757
|
+
tokenIdentifier!,
|
|
606
758
|
);
|
|
607
759
|
expect(userBalanceAfterTransfer.balance).toEqual(tokenAmount);
|
|
608
760
|
|
|
@@ -613,9 +765,9 @@ describe.each(TEST_CONFIGS)(
|
|
|
613
765
|
});
|
|
614
766
|
|
|
615
767
|
const userBalanceObjAfterTransferBack = await userWallet.getBalance();
|
|
616
|
-
const userBalanceAfterTransferBack =
|
|
768
|
+
const userBalanceAfterTransferBack = filterTokenBalanceForTokenIdentifier(
|
|
617
769
|
userBalanceObjAfterTransferBack?.tokenBalances,
|
|
618
|
-
|
|
770
|
+
tokenIdentifier!,
|
|
619
771
|
);
|
|
620
772
|
|
|
621
773
|
expect(userBalanceAfterTransferBack.balance).toEqual(0n);
|
|
@@ -631,111 +783,41 @@ describe.each(TEST_CONFIGS)(
|
|
|
631
783
|
).balance;
|
|
632
784
|
expect(issuerTokenBalanceAfterBurn).toEqual(initialBalance);
|
|
633
785
|
});
|
|
634
|
-
|
|
635
|
-
// it("should correctly assign operation types for complete token lifecycle operations", async () => {
|
|
636
|
-
// const { wallet: userWallet } = await SparkWalletTesting.initialize({
|
|
637
|
-
// options: config,
|
|
638
|
-
// });
|
|
639
|
-
|
|
640
|
-
// const tokenAmount = 1000n;
|
|
641
|
-
|
|
642
|
-
// await sharedIssuerWallet.mintTokens(tokenAmount);
|
|
643
|
-
|
|
644
|
-
// await sharedIssuerWallet.transferTokens({
|
|
645
|
-
// tokenAmount: 500n,
|
|
646
|
-
// tokenPublicKey: sharedTokenPublicKey,
|
|
647
|
-
// receiverSparkAddress: await userWallet.getSparkAddress(),
|
|
648
|
-
// });
|
|
649
|
-
|
|
650
|
-
// await userWallet.transferTokens({
|
|
651
|
-
// tokenPublicKey: sharedTokenPublicKey,
|
|
652
|
-
// tokenAmount: 250n,
|
|
653
|
-
// receiverSparkAddress: await sharedIssuerWallet.getSparkAddress(),
|
|
654
|
-
// });
|
|
655
|
-
|
|
656
|
-
// // as in userWallet we didn't have burnTokens method, we need to transfer tokens to burn address manually
|
|
657
|
-
// const BURN_ADDRESS = "02".repeat(33);
|
|
658
|
-
// const burnAddress = encodeSparkAddress({
|
|
659
|
-
// identityPublicKey: BURN_ADDRESS,
|
|
660
|
-
// network: "LOCAL",
|
|
661
|
-
// });
|
|
662
|
-
|
|
663
|
-
// await userWallet.transferTokens({
|
|
664
|
-
// tokenPublicKey: sharedTokenPublicKey,
|
|
665
|
-
// tokenAmount: 250n,
|
|
666
|
-
// receiverSparkAddress: burnAddress,
|
|
667
|
-
// });
|
|
668
|
-
|
|
669
|
-
// await sharedIssuerWallet.burnTokens(250n);
|
|
670
|
-
|
|
671
|
-
// const activity = await sharedIssuerWallet.getIssuerTokenActivity();
|
|
672
|
-
|
|
673
|
-
// const mintTransaction = activity.transactions.find(
|
|
674
|
-
// (tx) =>
|
|
675
|
-
// tx.transaction?.$case === "spark" &&
|
|
676
|
-
// tx.transaction.spark.operationType === "ISSUER_MINT",
|
|
677
|
-
// );
|
|
678
|
-
|
|
679
|
-
// const transferTransaction = activity.transactions.find(
|
|
680
|
-
// (tx) =>
|
|
681
|
-
// tx.transaction?.$case === "spark" &&
|
|
682
|
-
// tx.transaction.spark.operationType === "ISSUER_TRANSFER",
|
|
683
|
-
// );
|
|
684
|
-
|
|
685
|
-
// const burnTransaction = activity.transactions.find(
|
|
686
|
-
// (tx) =>
|
|
687
|
-
// tx.transaction?.$case === "spark" &&
|
|
688
|
-
// tx.transaction.spark.operationType === "ISSUER_BURN",
|
|
689
|
-
// );
|
|
690
|
-
|
|
691
|
-
// const transferBackTransaction = activity.transactions.find(
|
|
692
|
-
// (tx) =>
|
|
693
|
-
// tx.transaction?.$case === "spark" &&
|
|
694
|
-
// tx.transaction.spark.operationType === "USER_TRANSFER",
|
|
695
|
-
// );
|
|
696
|
-
|
|
697
|
-
// const userBurnTransaction = activity.transactions.find(
|
|
698
|
-
// (tx) =>
|
|
699
|
-
// tx.transaction?.$case === "spark" &&
|
|
700
|
-
// tx.transaction.spark.operationType === "USER_BURN",
|
|
701
|
-
// );
|
|
702
|
-
|
|
703
|
-
// expect(mintTransaction).toBeDefined();
|
|
704
|
-
// expect(transferTransaction).toBeDefined();
|
|
705
|
-
// expect(burnTransaction).toBeDefined();
|
|
706
|
-
// expect(transferBackTransaction).toBeDefined();
|
|
707
|
-
// expect(userBurnTransaction).toBeDefined();
|
|
708
|
-
// });
|
|
709
|
-
|
|
710
|
-
(config.tokenTransactionVersion === "V0" ? it.skip : it)(
|
|
711
|
-
"should create a token using createToken API",
|
|
712
|
-
async () => {
|
|
713
|
-
const { wallet: issuerWallet } =
|
|
714
|
-
await IssuerSparkWalletTesting.initialize({
|
|
715
|
-
options: config,
|
|
716
|
-
});
|
|
717
|
-
|
|
718
|
-
const tokenName = `${name}Creatable`;
|
|
719
|
-
const tokenTicker = "CRT";
|
|
720
|
-
const maxSupply = 5000n;
|
|
721
|
-
const decimals = 0;
|
|
722
|
-
const txId = await issuerWallet.createToken({
|
|
723
|
-
tokenName,
|
|
724
|
-
tokenTicker,
|
|
725
|
-
decimals,
|
|
726
|
-
isFreezable: false,
|
|
727
|
-
maxSupply,
|
|
728
|
-
});
|
|
729
|
-
|
|
730
|
-
expect(typeof txId).toBe("string");
|
|
731
|
-
expect(txId.length).toBeGreaterThan(0);
|
|
732
|
-
|
|
733
|
-
const metadata = await issuerWallet.getIssuerTokenMetadata();
|
|
734
|
-
expect(metadata.tokenName).toEqual(tokenName);
|
|
735
|
-
expect(metadata.tokenTicker).toEqual(tokenTicker);
|
|
736
|
-
expect(metadata.maxSupply).toEqual(maxSupply);
|
|
737
|
-
expect(metadata.decimals).toEqual(decimals);
|
|
738
|
-
},
|
|
739
|
-
);
|
|
740
786
|
},
|
|
741
787
|
);
|
|
788
|
+
|
|
789
|
+
async function fundAndAnnounce(
|
|
790
|
+
wallet: IssuerSparkWallet,
|
|
791
|
+
maxSupply: bigint = 100000n,
|
|
792
|
+
decimals: number = 0,
|
|
793
|
+
tokenName: string = "TestToken1",
|
|
794
|
+
tokenSymbol: string = "TT1",
|
|
795
|
+
isFreezable: boolean = false,
|
|
796
|
+
) {
|
|
797
|
+
// Faucet funds to the Issuer wallet because announcing a token
|
|
798
|
+
// requires ownership of an L1 UTXO.
|
|
799
|
+
const faucet = BitcoinFaucet.getInstance();
|
|
800
|
+
const l1WalletPubKey = await wallet.getTokenL1Address();
|
|
801
|
+
await faucet.sendToAddress(l1WalletPubKey, 100_000n);
|
|
802
|
+
await faucet.mineBlocks(6);
|
|
803
|
+
|
|
804
|
+
await new Promise((resolve) => setTimeout(resolve, 3000));
|
|
805
|
+
|
|
806
|
+
try {
|
|
807
|
+
const response = await wallet.announceTokenL1(
|
|
808
|
+
tokenName,
|
|
809
|
+
tokenSymbol,
|
|
810
|
+
decimals,
|
|
811
|
+
maxSupply,
|
|
812
|
+
isFreezable,
|
|
813
|
+
);
|
|
814
|
+
console.log("Announce token response:", response);
|
|
815
|
+
} catch (error: any) {
|
|
816
|
+
console.error("Error when announcing token on L1:", error);
|
|
817
|
+
throw error;
|
|
818
|
+
}
|
|
819
|
+
await faucet.mineBlocks(2);
|
|
820
|
+
|
|
821
|
+
const SECONDS = 1000;
|
|
822
|
+
await new Promise((resolve) => setTimeout(resolve, 3 * SECONDS));
|
|
823
|
+
}
|