@buildonspark/issuer-sdk 0.0.86 → 0.0.87

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 CHANGED
@@ -1,5 +1,18 @@
1
1
  # @buildonspark/issuer-sdk
2
2
 
3
+ ## 0.0.87
4
+
5
+ ### Patch Changes
6
+
7
+ - -- Added spark invoice support for token transfers
8
+ -- Added support for initialization SparkWallet with pre-existing keys
9
+ -- Return bare info in x-client-env
10
+ -- Improved test coverage for multiple coordinators
11
+ -- Improved retry mechanism for transfer claim
12
+ -- Improved error handling for alreaday exists
13
+ - Updated dependencies
14
+ - @buildonspark/spark-sdk@0.2.8
15
+
3
16
  ## 0.0.86
4
17
 
5
18
  ### Patch Changes
@@ -177,7 +177,7 @@ var IssuerTokenTransactionService = class extends TokenTransactionService {
177
177
  }
178
178
  async constructMintTokenTransaction(rawTokenIdentifierBytes, issuerTokenPublicKey, tokenAmount) {
179
179
  return {
180
- version: 1,
180
+ version: 2,
181
181
  network: this.config.getNetworkProto(),
182
182
  tokenInputs: {
183
183
  $case: "mintInput",
@@ -195,12 +195,13 @@ var IssuerTokenTransactionService = class extends TokenTransactionService {
195
195
  ],
196
196
  clientCreatedTimestamp: /* @__PURE__ */ new Date(),
197
197
  sparkOperatorIdentityPublicKeys: super.collectOperatorIdentityPublicKeys(),
198
- expiryTime: void 0
198
+ expiryTime: void 0,
199
+ invoiceAttachments: []
199
200
  };
200
201
  }
201
202
  async constructCreateTokenTransaction(tokenPublicKey, tokenName, tokenTicker, decimals, maxSupply, isFreezable) {
202
203
  return {
203
- version: 1,
204
+ version: 2,
204
205
  network: this.config.getNetworkProto(),
205
206
  tokenInputs: {
206
207
  $case: "createInput",
@@ -216,7 +217,8 @@ var IssuerTokenTransactionService = class extends TokenTransactionService {
216
217
  tokenOutputs: [],
217
218
  clientCreatedTimestamp: /* @__PURE__ */ new Date(),
218
219
  sparkOperatorIdentityPublicKeys: super.collectOperatorIdentityPublicKeys(),
219
- expiryTime: void 0
220
+ expiryTime: void 0,
221
+ invoiceAttachments: []
220
222
  };
221
223
  }
222
224
  };
@@ -315,6 +317,12 @@ var IssuerSparkWallet = class _IssuerSparkWallet extends SparkWallet {
315
317
  }) {
316
318
  const wallet = new _IssuerSparkWallet(options, signer);
317
319
  wallet.initializeTracer(wallet);
320
+ if (options && options.signerWithPreExistingKeys) {
321
+ await wallet.initWalletWithoutSeed();
322
+ return {
323
+ wallet
324
+ };
325
+ }
318
326
  const initResponse = await wallet.initWallet(mnemonicOrSeed, accountNumber);
319
327
  return {
320
328
  wallet,
package/dist/index.cjs CHANGED
@@ -199,7 +199,7 @@ var IssuerTokenTransactionService = class extends import_spark_sdk3.TokenTransac
199
199
  }
200
200
  async constructMintTokenTransaction(rawTokenIdentifierBytes, issuerTokenPublicKey, tokenAmount) {
201
201
  return {
202
- version: 1,
202
+ version: 2,
203
203
  network: this.config.getNetworkProto(),
204
204
  tokenInputs: {
205
205
  $case: "mintInput",
@@ -217,12 +217,13 @@ var IssuerTokenTransactionService = class extends import_spark_sdk3.TokenTransac
217
217
  ],
218
218
  clientCreatedTimestamp: /* @__PURE__ */ new Date(),
219
219
  sparkOperatorIdentityPublicKeys: super.collectOperatorIdentityPublicKeys(),
220
- expiryTime: void 0
220
+ expiryTime: void 0,
221
+ invoiceAttachments: []
221
222
  };
222
223
  }
223
224
  async constructCreateTokenTransaction(tokenPublicKey, tokenName, tokenTicker, decimals, maxSupply, isFreezable) {
224
225
  return {
225
- version: 1,
226
+ version: 2,
226
227
  network: this.config.getNetworkProto(),
227
228
  tokenInputs: {
228
229
  $case: "createInput",
@@ -238,7 +239,8 @@ var IssuerTokenTransactionService = class extends import_spark_sdk3.TokenTransac
238
239
  tokenOutputs: [],
239
240
  clientCreatedTimestamp: /* @__PURE__ */ new Date(),
240
241
  sparkOperatorIdentityPublicKeys: super.collectOperatorIdentityPublicKeys(),
241
- expiryTime: void 0
242
+ expiryTime: void 0,
243
+ invoiceAttachments: []
242
244
  };
243
245
  }
244
246
  };
@@ -335,6 +337,12 @@ var IssuerSparkWallet = class _IssuerSparkWallet extends import_spark_sdk5.Spark
335
337
  }) {
336
338
  const wallet = new _IssuerSparkWallet(options, signer);
337
339
  wallet.initializeTracer(wallet);
340
+ if (options && options.signerWithPreExistingKeys) {
341
+ await wallet.initWalletWithoutSeed();
342
+ return {
343
+ wallet
344
+ };
345
+ }
338
346
  const initResponse = await wallet.initWallet(mnemonicOrSeed, accountNumber);
339
347
  return {
340
348
  wallet,
@@ -636,6 +644,12 @@ var IssuerSparkWalletBrowser = class _IssuerSparkWalletBrowser extends IssuerSpa
636
644
  }) {
637
645
  const wallet = new _IssuerSparkWalletBrowser(options, signer);
638
646
  wallet.initializeTracer(wallet);
647
+ if (options && options.signerWithPreExistingKeys) {
648
+ await wallet.initWalletWithoutSeed();
649
+ return {
650
+ wallet
651
+ };
652
+ }
639
653
  const initResponse = await wallet.initWallet(mnemonicOrSeed, accountNumber);
640
654
  return {
641
655
  wallet,
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  IssuerSparkWallet
3
- } from "./chunk-NRKE2XKD.js";
3
+ } from "./chunk-ZMLVOUPB.js";
4
4
  import "./chunk-7B4B24XF.js";
5
5
 
6
6
  // src/issuer-wallet/issuer-spark-wallet.browser.ts
@@ -16,6 +16,12 @@ var IssuerSparkWalletBrowser = class _IssuerSparkWalletBrowser extends IssuerSpa
16
16
  }) {
17
17
  const wallet = new _IssuerSparkWalletBrowser(options, signer);
18
18
  wallet.initializeTracer(wallet);
19
+ if (options && options.signerWithPreExistingKeys) {
20
+ await wallet.initWalletWithoutSeed();
21
+ return {
22
+ wallet
23
+ };
24
+ }
19
25
  const initResponse = await wallet.initWallet(mnemonicOrSeed, accountNumber);
20
26
  return {
21
27
  wallet,
@@ -199,7 +199,7 @@ var IssuerTokenTransactionService = class extends import_spark_sdk3.TokenTransac
199
199
  }
200
200
  async constructMintTokenTransaction(rawTokenIdentifierBytes, issuerTokenPublicKey, tokenAmount) {
201
201
  return {
202
- version: 1,
202
+ version: 2,
203
203
  network: this.config.getNetworkProto(),
204
204
  tokenInputs: {
205
205
  $case: "mintInput",
@@ -217,12 +217,13 @@ var IssuerTokenTransactionService = class extends import_spark_sdk3.TokenTransac
217
217
  ],
218
218
  clientCreatedTimestamp: /* @__PURE__ */ new Date(),
219
219
  sparkOperatorIdentityPublicKeys: super.collectOperatorIdentityPublicKeys(),
220
- expiryTime: void 0
220
+ expiryTime: void 0,
221
+ invoiceAttachments: []
221
222
  };
222
223
  }
223
224
  async constructCreateTokenTransaction(tokenPublicKey, tokenName, tokenTicker, decimals, maxSupply, isFreezable) {
224
225
  return {
225
- version: 1,
226
+ version: 2,
226
227
  network: this.config.getNetworkProto(),
227
228
  tokenInputs: {
228
229
  $case: "createInput",
@@ -238,7 +239,8 @@ var IssuerTokenTransactionService = class extends import_spark_sdk3.TokenTransac
238
239
  tokenOutputs: [],
239
240
  clientCreatedTimestamp: /* @__PURE__ */ new Date(),
240
241
  sparkOperatorIdentityPublicKeys: super.collectOperatorIdentityPublicKeys(),
241
- expiryTime: void 0
242
+ expiryTime: void 0,
243
+ invoiceAttachments: []
242
244
  };
243
245
  }
244
246
  };
@@ -335,6 +337,12 @@ var IssuerSparkWallet = class _IssuerSparkWallet extends import_spark_sdk5.Spark
335
337
  }) {
336
338
  const wallet = new _IssuerSparkWallet(options, signer);
337
339
  wallet.initializeTracer(wallet);
340
+ if (options && options.signerWithPreExistingKeys) {
341
+ await wallet.initWalletWithoutSeed();
342
+ return {
343
+ wallet
344
+ };
345
+ }
338
346
  const initResponse = await wallet.initWallet(mnemonicOrSeed, accountNumber);
339
347
  return {
340
348
  wallet,
@@ -636,6 +644,12 @@ var IssuerSparkWalletNodeJS = class _IssuerSparkWalletNodeJS extends IssuerSpark
636
644
  }) {
637
645
  const wallet = new _IssuerSparkWalletNodeJS(options, signer);
638
646
  wallet.initializeTracer(wallet);
647
+ if (options && options.signerWithPreExistingKeys) {
648
+ await wallet.initWalletWithoutSeed();
649
+ return {
650
+ wallet
651
+ };
652
+ }
639
653
  const initResponse = await wallet.initWallet(mnemonicOrSeed, accountNumber);
640
654
  return {
641
655
  wallet,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  IssuerSparkWallet
3
- } from "./chunk-NRKE2XKD.js";
3
+ } from "./chunk-ZMLVOUPB.js";
4
4
  import "./chunk-7B4B24XF.js";
5
5
 
6
6
  // src/issuer-wallet/issuer-spark-wallet.node.ts
@@ -16,6 +16,12 @@ var IssuerSparkWalletNodeJS = class _IssuerSparkWalletNodeJS extends IssuerSpark
16
16
  }) {
17
17
  const wallet = new _IssuerSparkWalletNodeJS(options, signer);
18
18
  wallet.initializeTracer(wallet);
19
+ if (options && options.signerWithPreExistingKeys) {
20
+ await wallet.initWalletWithoutSeed();
21
+ return {
22
+ wallet
23
+ };
24
+ }
19
25
  const initResponse = await wallet.initWallet(mnemonicOrSeed, accountNumber);
20
26
  return {
21
27
  wallet,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@buildonspark/issuer-sdk",
3
- "version": "0.0.86",
3
+ "version": "0.0.87",
4
4
  "description": "Spark Issuer SDK for token issuance",
5
5
  "license": "Apache-2.0",
6
6
  "module": "./dist/index.js",
@@ -72,12 +72,10 @@
72
72
  "types": "tsc"
73
73
  },
74
74
  "dependencies": {
75
- "@buildonspark/spark-sdk": "0.2.7",
76
- "@lightsparkdev/core": "^1.4.3",
75
+ "@buildonspark/spark-sdk": "0.2.8",
77
76
  "@noble/curves": "^1.8.0",
78
77
  "@scure/btc-signer": "^1.5.0",
79
- "buffer": "^6.0.3",
80
- "ts-proto": "^2.6.1"
78
+ "buffer": "^6.0.3"
81
79
  },
82
80
  "devDependencies": {
83
81
  "@arethetypeswrong/cli": "^0.17.4",
@@ -14,6 +14,14 @@ export class IssuerSparkWalletBrowser extends BaseIssuerSparkWallet {
14
14
  const wallet = new IssuerSparkWalletBrowser(options, signer);
15
15
  wallet.initializeTracer(wallet);
16
16
 
17
+ if (options && options.signerWithPreExistingKeys) {
18
+ await wallet.initWalletWithoutSeed();
19
+
20
+ return {
21
+ wallet,
22
+ };
23
+ }
24
+
17
25
  const initResponse = await wallet.initWallet(mnemonicOrSeed, accountNumber);
18
26
 
19
27
  return {
@@ -14,6 +14,14 @@ export class IssuerSparkWalletNodeJS extends BaseIssuerSparkWallet {
14
14
  const wallet = new IssuerSparkWalletNodeJS(options, signer);
15
15
  wallet.initializeTracer(wallet);
16
16
 
17
+ if (options && options.signerWithPreExistingKeys) {
18
+ await wallet.initWalletWithoutSeed();
19
+
20
+ return {
21
+ wallet,
22
+ };
23
+ }
24
+
17
25
  const initResponse = await wallet.initWallet(mnemonicOrSeed, accountNumber);
18
26
 
19
27
  return {
@@ -4,7 +4,6 @@ import {
4
4
  SparkWalletProps,
5
5
  ValidationError,
6
6
  } from "@buildonspark/spark-sdk";
7
- import { isNode } from "@lightsparkdev/core";
8
7
  import {
9
8
  decodeSparkAddress,
10
9
  encodeSparkAddress,
@@ -58,6 +57,14 @@ export class IssuerSparkWallet extends SparkWallet {
58
57
  const wallet = new IssuerSparkWallet(options, signer);
59
58
  wallet.initializeTracer(wallet);
60
59
 
60
+ if (options && options.signerWithPreExistingKeys) {
61
+ await wallet.initWalletWithoutSeed();
62
+
63
+ return {
64
+ wallet,
65
+ };
66
+ }
67
+
61
68
  const initResponse = await wallet.initWallet(mnemonicOrSeed, accountNumber);
62
69
 
63
70
  return {
@@ -44,7 +44,7 @@ export class IssuerTokenTransactionService extends TokenTransactionService {
44
44
  tokenAmount: bigint,
45
45
  ): Promise<TokenTransaction> {
46
46
  return {
47
- version: 1,
47
+ version: 2,
48
48
  network: this.config.getNetworkProto(),
49
49
  tokenInputs: {
50
50
  $case: "mintInput",
@@ -64,6 +64,7 @@ export class IssuerTokenTransactionService extends TokenTransactionService {
64
64
  sparkOperatorIdentityPublicKeys:
65
65
  super.collectOperatorIdentityPublicKeys(),
66
66
  expiryTime: undefined,
67
+ invoiceAttachments: [],
67
68
  };
68
69
  }
69
70
 
@@ -76,7 +77,7 @@ export class IssuerTokenTransactionService extends TokenTransactionService {
76
77
  isFreezable: boolean,
77
78
  ): Promise<TokenTransaction> {
78
79
  return {
79
- version: 1,
80
+ version: 2,
80
81
  network: this.config.getNetworkProto(),
81
82
  tokenInputs: {
82
83
  $case: "createInput",
@@ -94,6 +95,7 @@ export class IssuerTokenTransactionService extends TokenTransactionService {
94
95
  sparkOperatorIdentityPublicKeys:
95
96
  super.collectOperatorIdentityPublicKeys(),
96
97
  expiryTime: undefined,
98
+ invoiceAttachments: [],
97
99
  };
98
100
  }
99
101
  }
@@ -113,7 +113,7 @@ describe.each(TEST_CONFIGS)(
113
113
  await expect(wallet.mintTokens(tokenAmount)).rejects.toThrow();
114
114
  });
115
115
 
116
- it("should create, andfail when minting more than max supply", async () => {
116
+ it("should create, and fail when minting more than max supply", async () => {
117
117
  const tokenAmount: bigint = 1000n;
118
118
  const { wallet } = await IssuerSparkWalletTesting.initialize({
119
119
  options: config,
@@ -198,6 +198,306 @@ describe.each(TEST_CONFIGS)(
198
198
  expect(userBalance.balance).toBeGreaterThanOrEqual(tokenAmount);
199
199
  });
200
200
 
201
+ const tv1It = name.startsWith("TV1") ? it : it.skip;
202
+ tv1It("should transfer tokens using spark invoices", async () => {
203
+ const tokenAmount: bigint = 777n;
204
+ const initialIssuerBalance = 100000n;
205
+
206
+ const { wallet: issuerWallet } =
207
+ await IssuerSparkWalletTesting.initialize({
208
+ options: config,
209
+ });
210
+ const { wallet: receiverWallet } = await SparkWalletTesting.initialize({
211
+ options: config,
212
+ });
213
+
214
+ await issuerWallet.createToken({
215
+ tokenName: `${name}INV`,
216
+ tokenTicker: "INV",
217
+ decimals: 0,
218
+ isFreezable: false,
219
+ maxSupply: 1_000_000n,
220
+ });
221
+
222
+ await issuerWallet.mintTokens(initialIssuerBalance);
223
+
224
+ const issuerBalanceAfterMint = await issuerWallet.getIssuerTokenBalance();
225
+ expect(issuerBalanceAfterMint).toBeDefined();
226
+ expect(issuerBalanceAfterMint.balance).toBe(initialIssuerBalance);
227
+ const tokenIdentifier = issuerBalanceAfterMint.tokenIdentifier!;
228
+ const issuerBalanceBeforeTransfer = issuerBalanceAfterMint.balance;
229
+
230
+ const invoice = await receiverWallet.createTokensInvoice({
231
+ amount: tokenAmount,
232
+ tokenIdentifier,
233
+ memo: "Invoice test",
234
+ expiryTime: new Date(Date.now() + 1000 * 60 * 60 * 24),
235
+ });
236
+
237
+ const txId = await issuerWallet.fulfillSparkInvoice([{ invoice }]);
238
+ expect(typeof txId).toBe("string");
239
+ expect(txId.length).toBeGreaterThan(0);
240
+
241
+ const issuerBalanceAfter = (await issuerWallet.getIssuerTokenBalance())
242
+ .balance;
243
+ expect(issuerBalanceAfter).toEqual(
244
+ issuerBalanceBeforeTransfer - tokenAmount,
245
+ );
246
+
247
+ const receiverBalanceObj = await receiverWallet.getBalance();
248
+ const receiverBalance = filterTokenBalanceForTokenIdentifier(
249
+ receiverBalanceObj?.tokenBalances,
250
+ tokenIdentifier!,
251
+ );
252
+ expect(receiverBalance.balance).toEqual(tokenAmount);
253
+ });
254
+
255
+ tv1It("should transfer tokens using multiple spark invoices", async () => {
256
+ const amount1: bigint = 111n;
257
+ const amount2: bigint = 222n;
258
+ const amount3: bigint = 333n;
259
+ const totalAmount: bigint = amount1 + amount2 + amount3;
260
+ const initialIssuerBalance = 100000n;
261
+
262
+ const { wallet: issuerWallet } =
263
+ await IssuerSparkWalletTesting.initialize({
264
+ options: config,
265
+ });
266
+ const { wallet: receiverWallet1 } = await SparkWalletTesting.initialize({
267
+ options: config,
268
+ });
269
+ const { wallet: receiverWallet2 } = await SparkWalletTesting.initialize({
270
+ options: config,
271
+ });
272
+
273
+ await issuerWallet.createToken({
274
+ tokenName: `${name}INVM`,
275
+ tokenTicker: "INM",
276
+ decimals: 0,
277
+ isFreezable: false,
278
+ maxSupply: 1_000_000n,
279
+ });
280
+
281
+ await issuerWallet.mintTokens(initialIssuerBalance);
282
+
283
+ const issuerBalanceAfterMint = await issuerWallet.getIssuerTokenBalance();
284
+ expect(issuerBalanceAfterMint).toBeDefined();
285
+ expect(issuerBalanceAfterMint.balance).toBe(initialIssuerBalance);
286
+ const tokenIdentifier = issuerBalanceAfterMint.tokenIdentifier!;
287
+ const issuerBalanceBeforeTransfer = issuerBalanceAfterMint.balance;
288
+
289
+ const invoice1 = await receiverWallet1.createTokensInvoice({
290
+ amount: amount1,
291
+ tokenIdentifier,
292
+ memo: "Invoice #1",
293
+ expiryTime: new Date(Date.now() + 1000 * 60 * 60 * 24),
294
+ });
295
+
296
+ const invoice2 = await receiverWallet1.createTokensInvoice({
297
+ amount: amount2,
298
+ tokenIdentifier,
299
+ memo: "Invoice #2",
300
+ expiryTime: new Date(Date.now() + 1000 * 60 * 60 * 24),
301
+ });
302
+
303
+ const invoice3 = await receiverWallet2.createTokensInvoice({
304
+ amount: amount3,
305
+ tokenIdentifier,
306
+ memo: "Invoice #3",
307
+ expiryTime: new Date(Date.now() + 1000 * 60 * 60 * 24),
308
+ });
309
+
310
+ const txId = await issuerWallet.fulfillSparkInvoice([
311
+ { invoice: invoice1 },
312
+ { invoice: invoice2 },
313
+ { invoice: invoice3 },
314
+ ]);
315
+ expect(typeof txId).toBe("string");
316
+ expect(txId.length).toBeGreaterThan(0);
317
+
318
+ const issuerBalanceAfter = (await issuerWallet.getIssuerTokenBalance())
319
+ .balance;
320
+ expect(issuerBalanceAfter).toEqual(
321
+ issuerBalanceBeforeTransfer - totalAmount,
322
+ );
323
+
324
+ const receiver1BalanceObj = await receiverWallet1.getBalance();
325
+ const receiver1Balance = filterTokenBalanceForTokenIdentifier(
326
+ receiver1BalanceObj?.tokenBalances,
327
+ tokenIdentifier!,
328
+ );
329
+ expect(receiver1Balance.balance).toEqual(amount1 + amount2);
330
+
331
+ const receiver2BalanceObj = await receiverWallet2.getBalance();
332
+ const receiver2Balance = filterTokenBalanceForTokenIdentifier(
333
+ receiver2BalanceObj?.tokenBalances,
334
+ tokenIdentifier!,
335
+ );
336
+ expect(receiver2Balance.balance).toEqual(amount3);
337
+ });
338
+
339
+ tv1It("should fail to fulfill an expired spark invoice", async () => {
340
+ const tokenAmount: bigint = 123n;
341
+ const initialIssuerBalance = 100000n;
342
+
343
+ const { wallet: issuerWallet } =
344
+ await IssuerSparkWalletTesting.initialize({
345
+ options: config,
346
+ });
347
+ const { wallet: receiverWallet } = await SparkWalletTesting.initialize({
348
+ options: config,
349
+ });
350
+
351
+ await issuerWallet.createToken({
352
+ tokenName: `${name}INVEXP`,
353
+ tokenTicker: "INVX",
354
+ decimals: 0,
355
+ isFreezable: false,
356
+ maxSupply: 1_000_000n,
357
+ });
358
+
359
+ await issuerWallet.mintTokens(initialIssuerBalance);
360
+
361
+ const issuerBalanceAfterMint = await issuerWallet.getIssuerTokenBalance();
362
+ expect(issuerBalanceAfterMint).toBeDefined();
363
+ expect(issuerBalanceAfterMint.balance).toBe(initialIssuerBalance);
364
+ const tokenIdentifier = issuerBalanceAfterMint.tokenIdentifier!;
365
+ const issuerBalanceBefore = issuerBalanceAfterMint.balance;
366
+
367
+ const expiredInvoice = await receiverWallet.createTokensInvoice({
368
+ amount: tokenAmount,
369
+ tokenIdentifier,
370
+ memo: "Expired invoice",
371
+ expiryTime: new Date(Date.now() - 60_000),
372
+ });
373
+
374
+ await expect(
375
+ issuerWallet.fulfillSparkInvoice([{ invoice: expiredInvoice }]),
376
+ ).rejects.toThrow("expired");
377
+
378
+ const issuerBalanceAfter = (await issuerWallet.getIssuerTokenBalance())
379
+ .balance;
380
+ expect(issuerBalanceAfter).toEqual(issuerBalanceBefore);
381
+
382
+ const receiverBalanceObj = await receiverWallet.getBalance();
383
+ const receiverBalance = filterTokenBalanceForTokenIdentifier(
384
+ receiverBalanceObj?.tokenBalances,
385
+ tokenIdentifier!,
386
+ );
387
+ expect(receiverBalance.balance).toEqual(0n);
388
+ });
389
+
390
+ tv1It("should fulfill a spark invoice with null expiry", async () => {
391
+ const tokenAmount: bigint = 321n;
392
+ const initialIssuerBalance = 100000n;
393
+
394
+ const { wallet: issuerWallet } =
395
+ await IssuerSparkWalletTesting.initialize({
396
+ options: config,
397
+ });
398
+ const { wallet: receiverWallet } = await SparkWalletTesting.initialize({
399
+ options: config,
400
+ });
401
+
402
+ await issuerWallet.createToken({
403
+ tokenName: `${name}INVNULL`,
404
+ tokenTicker: "INVN",
405
+ decimals: 0,
406
+ isFreezable: false,
407
+ maxSupply: 1_000_000n,
408
+ });
409
+
410
+ await issuerWallet.mintTokens(initialIssuerBalance);
411
+
412
+ const issuerBalanceAfterMint = await issuerWallet.getIssuerTokenBalance();
413
+ expect(issuerBalanceAfterMint).toBeDefined();
414
+ expect(issuerBalanceAfterMint.balance).toBe(initialIssuerBalance);
415
+ const tokenIdentifier = issuerBalanceAfterMint.tokenIdentifier!;
416
+ const issuerBalanceBefore = issuerBalanceAfterMint.balance;
417
+
418
+ const nullExpiryInvoice = await receiverWallet.createTokensInvoice({
419
+ amount: tokenAmount,
420
+ tokenIdentifier,
421
+ memo: "Null expiry invoice",
422
+ expiryTime: null as unknown as Date,
423
+ });
424
+
425
+ const txId = await issuerWallet.fulfillSparkInvoice([
426
+ { invoice: nullExpiryInvoice },
427
+ ]);
428
+ expect(typeof txId).toBe("string");
429
+ expect(txId.length).toBeGreaterThan(0);
430
+
431
+ const issuerBalanceAfter = (await issuerWallet.getIssuerTokenBalance())
432
+ .balance;
433
+ expect(issuerBalanceAfter).toEqual(issuerBalanceBefore - tokenAmount);
434
+
435
+ const receiverBalanceObj = await receiverWallet.getBalance();
436
+ const receiverBalance = filterTokenBalanceForTokenIdentifier(
437
+ receiverBalanceObj?.tokenBalances,
438
+ tokenIdentifier!,
439
+ );
440
+ expect(receiverBalance.balance).toEqual(tokenAmount);
441
+ });
442
+
443
+ tv1It(
444
+ "should fulfill a tokens invoice without amount by passing amount parameter",
445
+ async () => {
446
+ const tokenAmount: bigint = 555n;
447
+ const initialIssuerBalance = 100000n;
448
+
449
+ const { wallet: issuerWallet } =
450
+ await IssuerSparkWalletTesting.initialize({
451
+ options: config,
452
+ });
453
+ const { wallet: receiverWallet } = await SparkWalletTesting.initialize({
454
+ options: config,
455
+ });
456
+
457
+ await issuerWallet.createToken({
458
+ tokenName: `${name}INVAOPT`,
459
+ tokenTicker: "INO",
460
+ decimals: 0,
461
+ isFreezable: false,
462
+ maxSupply: 1_000_000n,
463
+ });
464
+
465
+ await issuerWallet.mintTokens(initialIssuerBalance);
466
+
467
+ const issuerBalanceAfterMint =
468
+ await issuerWallet.getIssuerTokenBalance();
469
+ expect(issuerBalanceAfterMint).toBeDefined();
470
+ expect(issuerBalanceAfterMint.balance).toBe(initialIssuerBalance);
471
+ const tokenIdentifier = issuerBalanceAfterMint.tokenIdentifier!;
472
+ const issuerBalanceBeforeTransfer = issuerBalanceAfterMint.balance;
473
+
474
+ const invoiceWithoutAmount = await receiverWallet.createTokensInvoice({
475
+ tokenIdentifier,
476
+ memo: "Invoice without preset amount",
477
+ expiryTime: new Date(Date.now() + 1000 * 60 * 60 * 24),
478
+ });
479
+
480
+ const txId = await (issuerWallet as any).fulfillSparkInvoice([
481
+ { invoice: invoiceWithoutAmount, amount: tokenAmount },
482
+ ]);
483
+ expect(typeof txId).toBe("string");
484
+ expect(txId.length).toBeGreaterThan(0);
485
+
486
+ const issuerBalanceAfter = (await issuerWallet.getIssuerTokenBalance())
487
+ .balance;
488
+ expect(issuerBalanceAfter).toEqual(
489
+ issuerBalanceBeforeTransfer - tokenAmount,
490
+ );
491
+
492
+ const receiverBalanceObj = await receiverWallet.getBalance();
493
+ const receiverBalance = filterTokenBalanceForTokenIdentifier(
494
+ receiverBalanceObj?.tokenBalances,
495
+ tokenIdentifier!,
496
+ );
497
+ expect(receiverBalance.balance).toEqual(tokenAmount);
498
+ },
499
+ );
500
+
201
501
  it("should create, mint, and batchtransfer tokens", async () => {
202
502
  const tokenAmount: bigint = 999n;
203
503