@buildonspark/issuer-sdk 0.0.59 → 0.0.60

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.
@@ -1,6 +1,6 @@
1
1
  import { filterTokenBalanceForTokenPublicKey } from "@buildonspark/spark-sdk/utils";
2
2
  import { jest } from "@jest/globals";
3
- import { hexToBytes } from "@noble/curves/abstract/utils";
3
+ import { encodeSparkAddress } from "@buildonspark/spark-sdk/address";
4
4
  import {
5
5
  LOCAL_WALLET_CONFIG_ECDSA,
6
6
  LOCAL_WALLET_CONFIG_SCHNORR,
@@ -8,8 +8,23 @@ import {
8
8
  import { BitcoinFaucet } from "../../../../spark-sdk/src/tests/utils/test-faucet.js";
9
9
  import { IssuerSparkWalletTesting } from "../utils/issuer-test-wallet.js";
10
10
  import { SparkWalletTesting } from "../utils/spark-testing-wallet.js";
11
- import { SparkWallet } from "@buildonspark/spark-sdk";
12
11
  import { IssuerSparkWallet } from "../../index.js";
12
+ import { OperationType } from "@buildonspark/spark-sdk/proto/lrc20";
13
+
14
+ function hexStringToUint8Array(hexString) {
15
+ if (hexString.length % 2 !== 0) {
16
+ throw new Error("Hex string must have an even number of characters.");
17
+ }
18
+
19
+ const uint8Array = new Uint8Array(hexString.length / 2);
20
+
21
+ for (let i = 0; i < hexString.length; i += 2) {
22
+ const byte = parseInt(hexString.substring(i, i + 2), 16);
23
+ uint8Array[i / 2] = byte;
24
+ }
25
+
26
+ return uint8Array;
27
+ }
13
28
 
14
29
  const brokenTestFn = process.env.GITHUB_ACTIONS ? it.skip : it;
15
30
  describe("token integration tests", () => {
@@ -113,6 +128,138 @@ describe("token integration tests", () => {
113
128
  expect(destinationBalance.balance).toEqual(tokenAmount);
114
129
  });
115
130
 
131
+ it("should announce, mint, get list all transactions, and transfer tokens with ECDSA multiple times, get list all transactions again and check difference", async () => {
132
+ const tokenAmount: bigint = 100n;
133
+
134
+ const { wallet: issuerWallet } = await IssuerSparkWalletTesting.initialize({
135
+ options: LOCAL_WALLET_CONFIG_ECDSA,
136
+ });
137
+
138
+ const { wallet: destinationWallet } = await SparkWalletTesting.initialize({
139
+ options: LOCAL_WALLET_CONFIG_ECDSA,
140
+ });
141
+
142
+ await fundAndAnnounce(issuerWallet, 100000n, 0, "ECDSATransfer", "ETT");
143
+
144
+ {
145
+ const transactions = await issuerWallet.getIssuerTokenActivity();
146
+ const amount_of_transactions = transactions.transactions.length;
147
+ expect(amount_of_transactions).toEqual(0);
148
+ }
149
+
150
+ await issuerWallet.mintTokens(tokenAmount);
151
+
152
+ {
153
+ const transactions = await issuerWallet.getIssuerTokenActivity();
154
+ const amount_of_transactions = transactions.transactions.length;
155
+ expect(amount_of_transactions).toEqual(1);
156
+ }
157
+
158
+ await issuerWallet.transferTokens({
159
+ tokenAmount,
160
+ tokenPublicKey: await issuerWallet.getIdentityPublicKey(),
161
+ receiverSparkAddress: await destinationWallet.getSparkAddress(),
162
+ });
163
+
164
+ {
165
+ const transactions = await issuerWallet.getIssuerTokenActivity();
166
+ const amount_of_transactions = transactions.transactions.length;
167
+ expect(amount_of_transactions).toEqual(2);
168
+ }
169
+
170
+ for (let index = 0; index < 100; ++index) {
171
+ await issuerWallet.mintTokens(tokenAmount);
172
+ await issuerWallet.transferTokens({
173
+ tokenAmount,
174
+ tokenPublicKey: await issuerWallet.getIdentityPublicKey(),
175
+ receiverSparkAddress: await destinationWallet.getSparkAddress(),
176
+ });
177
+ } // 202 in total
178
+
179
+ let all_transactions = await issuerWallet.getIssuerTokenActivity(250);
180
+ const amount_of_transactions = all_transactions.transactions.length;
181
+ expect(amount_of_transactions).toEqual(202);
182
+
183
+ {
184
+ const transactions = await issuerWallet.getIssuerTokenActivity(10);
185
+ const amount_of_transactions = transactions.transactions.length;
186
+ expect(amount_of_transactions).toEqual(10);
187
+ }
188
+
189
+ {
190
+ let hashset_of_all_transactions: Set<String> = new Set();
191
+
192
+ let transactions = await issuerWallet.getIssuerTokenActivity(10);
193
+ let amount_of_transactions = transactions.transactions.length;
194
+ expect(amount_of_transactions).toEqual(10);
195
+ let page_num = 0;
196
+ for (let index = 0; index < transactions.transactions.length; ++index) {
197
+ const element = transactions.transactions[index];
198
+ if (!(element.transaction === undefined)) {
199
+ let hash: String = "";
200
+ if (element.transaction.$case === "spark") {
201
+ hash = element.transaction.spark.transactionHash;
202
+ } else if (element.transaction.$case === "onChain") {
203
+ hash = element.transaction.onChain.transactionHash;
204
+ }
205
+ if (hashset_of_all_transactions.has(hash)) {
206
+ expect(
207
+ `Dublicate found. Pagination is broken? Index of transaction: ${index} ; page №: ${page_num} ; page size: 10 ; hash_dublicate: ${hash}`,
208
+ ).toEqual("");
209
+ } else {
210
+ hashset_of_all_transactions.add(hash);
211
+ }
212
+ } else {
213
+ expect(
214
+ `Transaction is undefined. Something is really wrong. Index of transaction: ${index} ; page №: ${page_num} ; page size: 10`,
215
+ ).toEqual("");
216
+ }
217
+ }
218
+
219
+ while (!(undefined === transactions.nextCursor)) {
220
+ let transactions_2 = await issuerWallet.getIssuerTokenActivity(10, {
221
+ lastTransactionHash: hexStringToUint8Array(
222
+ transactions.nextCursor.lastTransactionHash,
223
+ ),
224
+ layer: transactions.nextCursor.layer,
225
+ });
226
+
227
+ ++page_num;
228
+
229
+ for (
230
+ let index = 0;
231
+ index < transactions_2.transactions.length;
232
+ ++index
233
+ ) {
234
+ const element = transactions_2.transactions[index];
235
+ if (!(element.transaction === undefined)) {
236
+ let hash: String = "";
237
+ if (element.transaction.$case === "spark") {
238
+ hash = element.transaction.spark.transactionHash;
239
+ } else if (element.transaction.$case === "onChain") {
240
+ hash = element.transaction.onChain.transactionHash;
241
+ }
242
+ if (hashset_of_all_transactions.has(hash)) {
243
+ expect(
244
+ `Dublicate found. Pagination is broken? Index of transaction: ${index} ; page №: ${page_num} ; page size: 10 ; hash_dublicate: ${hash}`,
245
+ ).toEqual("");
246
+ } else {
247
+ hashset_of_all_transactions.add(hash);
248
+ }
249
+ } else {
250
+ expect(
251
+ `Transaction is undefined. Something is really wrong. Index of transaction: ${index} ; page №: ${page_num} ; page size: 10`,
252
+ ).toEqual("");
253
+ }
254
+ }
255
+
256
+ transactions = transactions_2;
257
+ }
258
+
259
+ expect(hashset_of_all_transactions.size == 202);
260
+ }
261
+ });
262
+
116
263
  it("should announce, mint, and batchtransfer tokens with ECDSA", async () => {
117
264
  const tokenAmount: bigint = 999n;
118
265
 
@@ -270,8 +417,7 @@ describe("token integration tests", () => {
270
417
  expect(destinationBalance.balance).toEqual(tokenAmount);
271
418
  });
272
419
 
273
- // broken because LRC20 does not yet have ISSUER operation types.
274
- brokenTestFn("should track token operations in monitoring", async () => {
420
+ it("should track token operations in monitoring", async () => {
275
421
  const tokenAmount: bigint = 1000n;
276
422
 
277
423
  const { wallet: issuerWallet } = await IssuerSparkWalletTesting.initialize({
@@ -500,6 +646,26 @@ describe("token integration tests", () => {
500
646
  expect(issuerTokenBalanceAfterBurn).toEqual(0n);
501
647
  });
502
648
 
649
+ it("should announce, mint, and burn tokens with ECDSA and totalSupply has to be equal amount of token minted minus burned tokens", async () => {
650
+ const tokenAmount_init: bigint = 2000n;
651
+ const tokenAmount_burn: bigint = 1000n;
652
+
653
+ const { wallet: issuerWallet } = await IssuerSparkWalletTesting.initialize({
654
+ options: LOCAL_WALLET_CONFIG_ECDSA,
655
+ });
656
+
657
+ await fundAndAnnounce(issuerWallet, 100000n, 0, "ECDSATotalSupply", "ETS");
658
+ await issuerWallet.mintTokens(tokenAmount_init);
659
+
660
+ await issuerWallet.burnTokens(tokenAmount_burn);
661
+
662
+ const smth_with_total_supply = await issuerWallet.getIssuerTokenInfo();
663
+
664
+ expect(smth_with_total_supply?.totalSupply).toEqual(
665
+ tokenAmount_init - tokenAmount_burn,
666
+ );
667
+ });
668
+
503
669
  it("should announce, mint, and burn tokens with Schnorr", async () => {
504
670
  const tokenAmount: bigint = 200n;
505
671
  const { wallet: issuerWallet } = await IssuerSparkWalletTesting.initialize({
@@ -646,6 +812,87 @@ describe("token integration tests", () => {
646
812
  ).balance;
647
813
  expect(issuerTokenBalanceAfterBurn).toEqual(0n);
648
814
  });
815
+ it("should correctly assign operation types for complete token lifecycle operations", async () => {
816
+ const { wallet: issuerWallet } = await IssuerSparkWalletTesting.initialize({
817
+ options: LOCAL_WALLET_CONFIG_SCHNORR,
818
+ });
819
+
820
+ const { wallet: userWallet } = await SparkWalletTesting.initialize({
821
+ options: LOCAL_WALLET_CONFIG_SCHNORR,
822
+ });
823
+
824
+ const tokenAmount = 1000n;
825
+
826
+ await fundAndAnnounce(issuerWallet, 100000n, 0, "OperationTypeTest", "OTT");
827
+ await issuerWallet.mintTokens(tokenAmount);
828
+
829
+ await issuerWallet.transferTokens({
830
+ tokenAmount: 500n,
831
+ tokenPublicKey: await issuerWallet.getIdentityPublicKey(),
832
+ receiverSparkAddress: await userWallet.getSparkAddress(),
833
+ });
834
+
835
+ const tokenPublicKeyHex = await issuerWallet.getIdentityPublicKey();
836
+
837
+ await userWallet.transferTokens({
838
+ tokenPublicKey: tokenPublicKeyHex,
839
+ tokenAmount: 250n,
840
+ receiverSparkAddress: await issuerWallet.getSparkAddress(),
841
+ });
842
+
843
+ // as in userWallet we didn't have burnTokens method, we need to transfer tokens to burn address manually
844
+ const BURN_ADDRESS = "02".repeat(33);
845
+ const burnAddress = encodeSparkAddress({
846
+ identityPublicKey: BURN_ADDRESS,
847
+ network: "LOCAL",
848
+ });
849
+
850
+ await userWallet.transferTokens({
851
+ tokenPublicKey: tokenPublicKeyHex,
852
+ tokenAmount: 250n,
853
+ receiverSparkAddress: burnAddress,
854
+ });
855
+
856
+ await issuerWallet.burnTokens(250n);
857
+
858
+ const activity = await issuerWallet.getIssuerTokenActivity();
859
+
860
+ const mintTransaction = activity.transactions.find(
861
+ (tx) =>
862
+ tx.transaction?.$case === "spark" &&
863
+ tx.transaction.spark.operationType === "ISSUER_MINT",
864
+ );
865
+
866
+ const transferTransaction = activity.transactions.find(
867
+ (tx) =>
868
+ tx.transaction?.$case === "spark" &&
869
+ tx.transaction.spark.operationType === "ISSUER_TRANSFER",
870
+ );
871
+
872
+ const burnTransaction = activity.transactions.find(
873
+ (tx) =>
874
+ tx.transaction?.$case === "spark" &&
875
+ tx.transaction.spark.operationType === "ISSUER_BURN",
876
+ );
877
+
878
+ const transferBackTransaction = activity.transactions.find(
879
+ (tx) =>
880
+ tx.transaction?.$case === "spark" &&
881
+ tx.transaction.spark.operationType === "USER_TRANSFER",
882
+ );
883
+
884
+ const userBurnTransaction = activity.transactions.find(
885
+ (tx) =>
886
+ tx.transaction?.$case === "spark" &&
887
+ tx.transaction.spark.operationType === "USER_BURN",
888
+ );
889
+
890
+ expect(mintTransaction).toBeDefined();
891
+ expect(transferTransaction).toBeDefined();
892
+ expect(burnTransaction).toBeDefined();
893
+ expect(transferBackTransaction).toBeDefined();
894
+ expect(userBurnTransaction).toBeDefined();
895
+ });
649
896
  });
650
897
 
651
898
  async function fundAndAnnounce(
package/src/types.ts CHANGED
@@ -1,36 +1,4 @@
1
- // String enums to replace numeric enums
2
- export enum LayerType {
3
- L1 = "L1",
4
- SPARK = "SPARK",
5
- }
6
-
7
- export enum OperationType {
8
- USER_TRANSFER = "USER_TRANSFER",
9
- USER_BURN = "USER_BURN",
10
- ISSUER_ANNOUNCE = "ISSUER_ANNOUNCE",
11
- ISSUER_MINT = "ISSUER_MINT",
12
- ISSUER_TRANSFER = "ISSUER_TRANSFER",
13
- ISSUER_FREEZE = "ISSUER_FREEZE",
14
- ISSUER_UNFREEZE = "ISSUER_UNFREEZE",
15
- ISSUER_BURN = "ISSUER_BURN",
16
- }
17
-
18
- export enum OnChainTransactionStatus {
19
- PENDING = "PENDING",
20
- CONFIRMED = "CONFIRMED",
21
- WAITING_MINED = "WAITING_MINED",
22
- MINED = "MINED",
23
- ATTACHING = "ATTACHING",
24
- ATTACHED = "ATTACHED",
25
- }
26
-
27
- export enum SparkTransactionStatus {
28
- STARTED = "STARTED",
29
- SIGNED = "SIGNED",
30
- FINALIZED = "FINALIZED",
31
- }
32
-
33
- export type GetTokenActivityResponse = {
1
+ export type TokenActivityResponse = {
34
2
  transactions: Transaction[];
35
3
  nextCursor?: ListAllTokenTransactionsCursor | undefined;
36
4
  };
@@ -70,19 +38,19 @@ export interface OnChainTokenOutput {
70
38
  tokenAmount?: string | undefined;
71
39
  }
72
40
  export interface OnChainTransaction {
73
- operationType: OperationType;
41
+ operationType: string;
74
42
  transactionHash: string;
75
43
  rawtx: string;
76
- status: OnChainTransactionStatus;
44
+ status: string;
77
45
  inputs: OnChainTokenOutput[];
78
46
  outputs: OnChainTokenOutput[];
79
47
  broadcastedAt: Date | undefined;
80
48
  confirmedAt: Date | undefined;
81
49
  }
82
50
  export interface SparkTransaction {
83
- operationType: OperationType;
51
+ operationType: string;
84
52
  transactionHash: string;
85
- status: SparkTransactionStatus;
53
+ status: string;
86
54
  confirmedAt: Date | undefined;
87
55
  leavesToCreate: SparkLeaf[];
88
56
  leavesToSpend: SparkLeaf[];
@@ -105,7 +73,7 @@ export interface SparkLeaf {
105
73
 
106
74
  export interface ListAllTokenTransactionsCursor {
107
75
  lastTransactionHash: string;
108
- layer: LayerType;
76
+ layer: string;
109
77
  }
110
78
 
111
79
  export interface TokenDistribution {
@@ -1,15 +1,13 @@
1
- import {
2
- ListAllTokenTransactionsResponse,
3
- TokenPubkeyInfo,
4
- } from "@buildonspark/lrc20-sdk";
5
- import { GetTokenActivityResponse, TokenPubKeyInfoResponse } from "../types.js";
1
+ import { TokenPubkeyInfo } from "@buildonspark/lrc20-sdk";
2
+ import { TokenActivityResponse, TokenPubKeyInfoResponse } from "../types.js";
6
3
  import { bytesToHex, bytesToNumberBE } from "@noble/curves/abstract/utils";
7
4
  import {
8
- mapOperationType,
9
- mapOnChainTransactionStatus,
10
- mapSparkTransactionStatus,
11
- mapLayer,
12
- } from "./enum-mappers.js";
5
+ ListAllTokenTransactionsResponse,
6
+ OperationType,
7
+ OnChainTransactionStatus,
8
+ SparkTransactionStatus,
9
+ Layer,
10
+ } from "@buildonspark/spark-sdk/proto/lrc20";
13
11
 
14
12
  export function convertToTokenPubKeyInfoResponse(
15
13
  tokenPubkeyInfo: TokenPubkeyInfo,
@@ -31,10 +29,16 @@ export function convertToTokenPubKeyInfoResponse(
31
29
  };
32
30
  }
33
31
 
34
- export function convertTokenActivityToHexEncoded(
32
+ /**
33
+ * Converts a ListAllTokenTransactionsResponse to a TokenActivityResponse
34
+ * Main purpose is to convert Uint8Arrays to hex strings
35
+ * @param rawTransactions - The ListAllTokenTransactionsResponse to convert
36
+ * @returns The converted TokenActivityResponse
37
+ */
38
+ export function convertToTokenActivity(
35
39
  rawTransactions: ListAllTokenTransactionsResponse,
36
- ): GetTokenActivityResponse {
37
- const response: GetTokenActivityResponse = {
40
+ ): TokenActivityResponse {
41
+ const response: TokenActivityResponse = {
38
42
  transactions: rawTransactions.transactions.map((transaction) => {
39
43
  if (!transaction.transaction) {
40
44
  return { transaction: undefined };
@@ -46,10 +50,10 @@ export function convertTokenActivityToHexEncoded(
46
50
  transaction: {
47
51
  $case: "onChain",
48
52
  onChain: {
49
- operationType: mapOperationType(onChain.operationType),
53
+ operationType: getEnumName(OperationType, onChain.operationType),
50
54
  transactionHash: bytesToHex(onChain.transactionHash),
51
55
  rawtx: bytesToHex(onChain.rawtx),
52
- status: mapOnChainTransactionStatus(onChain.status),
56
+ status: getEnumName(OnChainTransactionStatus, onChain.status),
53
57
  inputs: onChain.inputs.map((input) => ({
54
58
  rawTx: bytesToHex(input.rawTx),
55
59
  vout: input.vout,
@@ -79,9 +83,9 @@ export function convertTokenActivityToHexEncoded(
79
83
  transaction: {
80
84
  $case: "spark",
81
85
  spark: {
82
- operationType: mapOperationType(spark.operationType),
86
+ operationType: getEnumName(OperationType, spark.operationType),
83
87
  transactionHash: bytesToHex(spark.transactionHash),
84
- status: mapSparkTransactionStatus(spark.status),
88
+ status: getEnumName(SparkTransactionStatus, spark.status),
85
89
  confirmedAt: spark.confirmedAt,
86
90
  leavesToCreate: spark.leavesToCreate.map((leaf) => ({
87
91
  tokenPublicKey: bytesToHex(leaf.tokenPublicKey),
@@ -131,10 +135,14 @@ export function convertTokenActivityToHexEncoded(
131
135
  lastTransactionHash: bytesToHex(
132
136
  rawTransactions.nextCursor.lastTransactionHash,
133
137
  ),
134
- layer: mapLayer(rawTransactions.nextCursor.layer),
138
+ layer: getEnumName(Layer, rawTransactions.nextCursor.layer),
135
139
  }
136
140
  : undefined,
137
141
  };
138
142
 
139
143
  return response;
140
144
  }
145
+
146
+ export function getEnumName(enumObj: any, value: number): string {
147
+ return enumObj[value];
148
+ }
@@ -1,48 +0,0 @@
1
- // buffer.js
2
- import { Buffer } from "buffer";
3
- if (typeof globalThis.Buffer === "undefined") {
4
- globalThis.Buffer = Buffer;
5
- }
6
- if (typeof global === "undefined") {
7
- window.global = window.globalThis;
8
- }
9
-
10
- // src/types.ts
11
- var LayerType = /* @__PURE__ */ ((LayerType2) => {
12
- LayerType2["L1"] = "L1";
13
- LayerType2["SPARK"] = "SPARK";
14
- return LayerType2;
15
- })(LayerType || {});
16
- var OperationType = /* @__PURE__ */ ((OperationType2) => {
17
- OperationType2["USER_TRANSFER"] = "USER_TRANSFER";
18
- OperationType2["USER_BURN"] = "USER_BURN";
19
- OperationType2["ISSUER_ANNOUNCE"] = "ISSUER_ANNOUNCE";
20
- OperationType2["ISSUER_MINT"] = "ISSUER_MINT";
21
- OperationType2["ISSUER_TRANSFER"] = "ISSUER_TRANSFER";
22
- OperationType2["ISSUER_FREEZE"] = "ISSUER_FREEZE";
23
- OperationType2["ISSUER_UNFREEZE"] = "ISSUER_UNFREEZE";
24
- OperationType2["ISSUER_BURN"] = "ISSUER_BURN";
25
- return OperationType2;
26
- })(OperationType || {});
27
- var OnChainTransactionStatus = /* @__PURE__ */ ((OnChainTransactionStatus2) => {
28
- OnChainTransactionStatus2["PENDING"] = "PENDING";
29
- OnChainTransactionStatus2["CONFIRMED"] = "CONFIRMED";
30
- OnChainTransactionStatus2["WAITING_MINED"] = "WAITING_MINED";
31
- OnChainTransactionStatus2["MINED"] = "MINED";
32
- OnChainTransactionStatus2["ATTACHING"] = "ATTACHING";
33
- OnChainTransactionStatus2["ATTACHED"] = "ATTACHED";
34
- return OnChainTransactionStatus2;
35
- })(OnChainTransactionStatus || {});
36
- var SparkTransactionStatus = /* @__PURE__ */ ((SparkTransactionStatus2) => {
37
- SparkTransactionStatus2["STARTED"] = "STARTED";
38
- SparkTransactionStatus2["SIGNED"] = "SIGNED";
39
- SparkTransactionStatus2["FINALIZED"] = "FINALIZED";
40
- return SparkTransactionStatus2;
41
- })(SparkTransactionStatus || {});
42
-
43
- export {
44
- LayerType,
45
- OperationType,
46
- OnChainTransactionStatus,
47
- SparkTransactionStatus
48
- };