@ledgerhq/coin-sui 0.15.0-nightly.4 → 0.15.1-nightly.0

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.
@@ -4,6 +4,7 @@ import coinConfig from "../config";
4
4
  import { BigNumber } from "bignumber.js";
5
5
  import { SuiClient } from "@mysten/sui/client";
6
6
  import type { TransactionBlockData, SuiTransactionBlockResponse } from "@mysten/sui/client";
7
+ import assert from "assert";
7
8
 
8
9
  // Mock SUI client for tests
9
10
  jest.mock("@mysten/sui/client", () => {
@@ -187,6 +188,89 @@ const mockTransaction = {
187
188
  checkpoint: "313024",
188
189
  } as SuiTransactionBlockResponse;
189
190
 
191
+ // Create a mock staking transaction
192
+ // amount must be a negative number
193
+ function mockStakingTx(address: string, amount: string) {
194
+ assert(new BigNumber(amount).lte(0), "amount must be a negative number");
195
+ return {
196
+ digest: "delegate_tx_digest_123",
197
+ transaction: {
198
+ data: {
199
+ sender: address,
200
+ transaction: {
201
+ kind: "ProgrammableTransaction",
202
+ inputs: [],
203
+ transactions: [
204
+ {
205
+ MoveCall: {
206
+ function: "request_add_stake",
207
+ },
208
+ },
209
+ ],
210
+ },
211
+ },
212
+ },
213
+ effects: {
214
+ status: { status: "success" },
215
+ gasUsed: {
216
+ computationCost: "1000000",
217
+ storageCost: "500000",
218
+ storageRebate: "450000",
219
+ },
220
+ },
221
+ balanceChanges: [
222
+ {
223
+ owner: { AddressOwner: address },
224
+ coinType: "0x2::sui::SUI",
225
+ amount: amount.startsWith("-") ? amount : `-${amount}`,
226
+ },
227
+ ],
228
+ timestampMs: "1742294454878",
229
+ checkpoint: "313024",
230
+ } as unknown as SuiTransactionBlockResponse;
231
+ }
232
+
233
+ // amount must be a positive number
234
+ function mockUnstakingTx(address: string, amount: string) {
235
+ assert(new BigNumber(amount).gte(0), "amount must be a positive number");
236
+ return {
237
+ digest: "undelegate_tx_digest_456",
238
+ transaction: {
239
+ data: {
240
+ sender: address,
241
+ transaction: {
242
+ kind: "ProgrammableTransaction",
243
+ inputs: [],
244
+ transactions: [
245
+ {
246
+ MoveCall: {
247
+ function: "request_withdraw_stake",
248
+ },
249
+ },
250
+ ],
251
+ },
252
+ },
253
+ },
254
+ effects: {
255
+ status: { status: "success" },
256
+ gasUsed: {
257
+ computationCost: "1000000",
258
+ storageCost: "500000",
259
+ storageRebate: "450000",
260
+ },
261
+ },
262
+ balanceChanges: [
263
+ {
264
+ owner: { AddressOwner: address },
265
+ coinType: "0x2::sui::SUI",
266
+ amount: amount,
267
+ },
268
+ ],
269
+ timestampMs: "1742294454878",
270
+ checkpoint: "313024",
271
+ } as unknown as SuiTransactionBlockResponse;
272
+ }
273
+
190
274
  const mockApi = new SuiClient({ url: "mock" }) as jest.Mocked<SuiClient>;
191
275
 
192
276
  // Add getTransactionBlock method to mockApi
@@ -527,146 +611,20 @@ describe("Staking Operations", () => {
527
611
  describe("Operation Type Detection", () => {
528
612
  test("getOperationType should return DELEGATE for staking transaction", () => {
529
613
  const address = "0x65449f57946938c84c512732f1d69405d1fce417d9c9894696ddf4522f479e24";
530
-
531
- // Create a mock staking transaction
532
- const mockStakingTx = {
533
- digest: "delegate_tx_digest_123",
534
- transaction: {
535
- data: {
536
- sender: address,
537
- transaction: {
538
- kind: "ProgrammableTransaction",
539
- inputs: [],
540
- transactions: [
541
- {
542
- MoveCall: {
543
- function: "request_add_stake",
544
- },
545
- },
546
- ],
547
- },
548
- },
549
- },
550
- effects: {
551
- status: { status: "success" },
552
- gasUsed: {
553
- computationCost: "1000000",
554
- storageCost: "500000",
555
- storageRebate: "450000",
556
- },
557
- },
558
- balanceChanges: [
559
- {
560
- owner: { AddressOwner: address },
561
- coinType: "0x2::sui::SUI",
562
- amount: "-1000000000",
563
- },
564
- ],
565
- timestampMs: "1742294454878",
566
- checkpoint: "313024",
567
- } as unknown as SuiTransactionBlockResponse;
568
-
569
- expect(sdk.getOperationType(address, mockStakingTx)).toBe("DELEGATE");
614
+ expect(sdk.getOperationType(address, mockStakingTx(address, "-1000000000"))).toBe("DELEGATE");
570
615
  });
571
616
 
572
617
  test("getOperationType should return UNDELEGATE for unstaking transaction", () => {
573
618
  const address = "0x65449f57946938c84c512732f1d69405d1fce417d9c9894696ddf4522f479e24";
574
-
575
- // Create a mock unstaking transaction
576
- const mockUnstakingTx = {
577
- digest: "undelegate_tx_digest_456",
578
- transaction: {
579
- data: {
580
- sender: address,
581
- transaction: {
582
- kind: "ProgrammableTransaction",
583
- inputs: [],
584
- transactions: [
585
- {
586
- MoveCall: {
587
- function: "request_withdraw_stake",
588
- },
589
- },
590
- ],
591
- },
592
- },
593
- },
594
- effects: {
595
- status: { status: "success" },
596
- gasUsed: {
597
- computationCost: "1000000",
598
- storageCost: "500000",
599
- storageRebate: "450000",
600
- },
601
- },
602
- balanceChanges: [
603
- {
604
- owner: { AddressOwner: address },
605
- coinType: "0x2::sui::SUI",
606
- amount: "0",
607
- },
608
- ],
609
- timestampMs: "1742294454878",
610
- checkpoint: "313024",
611
- } as unknown as SuiTransactionBlockResponse;
612
-
613
- expect(sdk.getOperationType(address, mockUnstakingTx)).toBe("UNDELEGATE");
619
+ expect(sdk.getOperationType(address, mockUnstakingTx(address, "1000000000"))).toBe(
620
+ "UNDELEGATE",
621
+ );
614
622
  });
615
623
  });
616
624
 
617
625
  describe("Operation Amount Calculation", () => {
618
626
  const address = "0x6e143fe0a8ca010a86580dafac44298e5b1b7d73efc345356a59a15f0d7824f0";
619
627
 
620
- const mockStakingTx = {
621
- transaction: {
622
- data: {
623
- transaction: {
624
- kind: "ProgrammableTransaction",
625
- transactions: [
626
- {
627
- MoveCall: {
628
- function: "request_add_stake",
629
- },
630
- },
631
- ],
632
- },
633
- },
634
- },
635
- balanceChanges: [
636
- {
637
- owner: { AddressOwner: address },
638
- coinType: "0x2::sui::SUI",
639
- amount: "-1000000000",
640
- },
641
- ],
642
- } as SuiTransactionBlockResponse;
643
-
644
- function mockUnstakingTx(amount: string) {
645
- return {
646
- transaction: {
647
- data: {
648
- transaction: {
649
- kind: "ProgrammableTransaction",
650
- transactions: [
651
- {
652
- MoveCall: {
653
- function: "request_withdraw_stake",
654
- },
655
- },
656
- ],
657
- },
658
- },
659
- },
660
- balanceChanges: [
661
- {
662
- owner: { AddressOwner: address },
663
- coinType: "0x2::sui::SUI",
664
- amount: amount,
665
- },
666
- ],
667
- } as SuiTransactionBlockResponse;
668
- }
669
-
670
628
  function bridgeOperationAmount(
671
629
  mock: SuiTransactionBlockResponse,
672
630
  coinType: string = sdk.DEFAULT_COIN_TYPE,
@@ -675,13 +633,17 @@ describe("Staking Operations", () => {
675
633
  }
676
634
 
677
635
  test("getOperationAmount should calculate staking amount", () =>
678
- expect(bridgeOperationAmount(mockStakingTx)).toEqual(new BigNumber("1000000000")));
636
+ expect(bridgeOperationAmount(mockStakingTx(address, "-1000000000"))).toEqual(
637
+ new BigNumber("1000000000"),
638
+ ));
679
639
 
680
640
  test("getOperationAmount should calculate unstaking amount of 1000", () =>
681
- expect(bridgeOperationAmount(mockUnstakingTx("1000"))).toEqual(new BigNumber("-1000")));
641
+ expect(bridgeOperationAmount(mockUnstakingTx(address, "1000"))).toEqual(
642
+ new BigNumber("-1000"),
643
+ ));
682
644
 
683
645
  test("getOperationAmount should calculate unstaking amount of 0", () =>
684
- expect(bridgeOperationAmount(mockUnstakingTx("0"))).toEqual(new BigNumber("0")));
646
+ expect(bridgeOperationAmount(mockUnstakingTx(address, "0"))).toEqual(new BigNumber("0")));
685
647
 
686
648
  test("getOperationAmount should calculate amount correctly for SUI", () =>
687
649
  expect(bridgeOperationAmount(mockTransaction)).toEqual(new BigNumber("9998990120")));
@@ -699,13 +661,17 @@ describe("Staking Operations", () => {
699
661
  }
700
662
 
701
663
  test("alpaca getOperationAmount should calculate staking amount", () =>
702
- expect(alpacaOperationAmount(mockStakingTx)).toEqual(new BigNumber("1000000000")));
664
+ expect(alpacaOperationAmount(mockStakingTx(address, "-1000000000"))).toEqual(
665
+ new BigNumber("1000000000"),
666
+ ));
703
667
 
704
668
  test("alpaca getOperationAmount should calculate unstaking amount of 1000", () =>
705
- expect(alpacaOperationAmount(mockUnstakingTx("1000"))).toEqual(new BigNumber("1000")));
669
+ expect(alpacaOperationAmount(mockUnstakingTx(address, "1000"))).toEqual(
670
+ new BigNumber("1000"),
671
+ ));
706
672
 
707
673
  test("alpaca getOperationAmount should calculate unstaking amount of 0", () =>
708
- expect(alpacaOperationAmount(mockUnstakingTx("0"))).toEqual(new BigNumber("0")));
674
+ expect(alpacaOperationAmount(mockUnstakingTx(address, "0"))).toEqual(new BigNumber("0")));
709
675
 
710
676
  test("alpaca getOperationAmount should calculate amount correctly for SUI", () =>
711
677
  expect(alpacaOperationAmount(mockTransaction)).toEqual(new BigNumber("9998990120")));
@@ -718,48 +684,16 @@ describe("Staking Operations", () => {
718
684
 
719
685
  describe("Operation Recipients", () => {
720
686
  test("getOperationRecipients should return empty array for staking transaction", () => {
721
- const mockStakingTx = {
722
- transaction: {
723
- data: {
724
- transaction: {
725
- kind: "ProgrammableTransaction",
726
- inputs: [],
727
- transactions: [
728
- {
729
- MoveCall: {
730
- function: "request_add_stake",
731
- },
732
- },
733
- ],
734
- },
735
- },
736
- },
737
- } as unknown as SuiTransactionBlockResponse;
738
-
739
- const recipients = sdk.getOperationRecipients(mockStakingTx.transaction?.data);
687
+ const recipients = sdk.getOperationRecipients(
688
+ mockStakingTx("0xdeadbeef", "-1000000000").transaction?.data,
689
+ );
740
690
  expect(recipients).toEqual([]);
741
691
  });
742
692
 
743
693
  test("getOperationRecipients should return empty array for unstaking transaction", () => {
744
- const mockUnstakingTx = {
745
- transaction: {
746
- data: {
747
- transaction: {
748
- kind: "ProgrammableTransaction",
749
- inputs: [],
750
- transactions: [
751
- {
752
- MoveCall: {
753
- function: "request_withdraw_stake",
754
- },
755
- },
756
- ],
757
- },
758
- },
759
- },
760
- } as unknown as SuiTransactionBlockResponse;
761
-
762
- const recipients = sdk.getOperationRecipients(mockUnstakingTx.transaction?.data);
694
+ const recipients = sdk.getOperationRecipients(
695
+ mockUnstakingTx("0xdeadbeef", "1000000000").transaction?.data,
696
+ );
763
697
  expect(recipients).toEqual([]);
764
698
  });
765
699
  });
@@ -850,44 +784,11 @@ describe("Staking Operations", () => {
850
784
  const accountId = "mockAccountId";
851
785
  const address = "0x65449f57946938c84c512732f1d69405d1fce417d9c9894696ddf4522f479e24";
852
786
 
853
- const mockStakingTx = {
854
- digest: "delegate_tx_digest_123",
855
- transaction: {
856
- data: {
857
- sender: address,
858
- transaction: {
859
- kind: "ProgrammableTransaction",
860
- inputs: [],
861
- transactions: [
862
- {
863
- MoveCall: {
864
- function: "request_add_stake",
865
- },
866
- },
867
- ],
868
- },
869
- },
870
- },
871
- effects: {
872
- status: { status: "success" },
873
- gasUsed: {
874
- computationCost: "1000000",
875
- storageCost: "500000",
876
- storageRebate: "450000",
877
- },
878
- },
879
- balanceChanges: [
880
- {
881
- owner: { AddressOwner: address },
882
- coinType: "0x2::sui::SUI",
883
- amount: "-1000000000",
884
- },
885
- ],
886
- timestampMs: "1742294454878",
887
- checkpoint: "313024",
888
- } as unknown as SuiTransactionBlockResponse;
889
-
890
- const operation = sdk.transactionToOperation(accountId, address, mockStakingTx);
787
+ const operation = sdk.transactionToOperation(
788
+ accountId,
789
+ address,
790
+ mockStakingTx(address, "-1000000000"),
791
+ );
891
792
 
892
793
  expect(operation).toHaveProperty("id");
893
794
  expect(operation).toHaveProperty("accountId", accountId);
@@ -903,45 +804,11 @@ describe("Staking Operations", () => {
903
804
  test("transactionToOperation should map unstaking transaction correctly", () => {
904
805
  const accountId = "mockAccountId";
905
806
  const address = "0x65449f57946938c84c512732f1d69405d1fce417d9c9894696ddf4522f479e24";
906
-
907
- const mockUnstakingTx = {
908
- digest: "undelegate_tx_digest_456",
909
- transaction: {
910
- data: {
911
- sender: address,
912
- transaction: {
913
- kind: "ProgrammableTransaction",
914
- inputs: [],
915
- transactions: [
916
- {
917
- MoveCall: {
918
- function: "request_withdraw_stake",
919
- },
920
- },
921
- ],
922
- },
923
- },
924
- },
925
- effects: {
926
- status: { status: "success" },
927
- gasUsed: {
928
- computationCost: "1000000",
929
- storageCost: "500000",
930
- storageRebate: "450000",
931
- },
932
- },
933
- balanceChanges: [
934
- {
935
- owner: { AddressOwner: address },
936
- coinType: "0x2::sui::SUI",
937
- amount: "0",
938
- },
939
- ],
940
- timestampMs: "1742294454878",
941
- checkpoint: "313024",
942
- } as unknown as SuiTransactionBlockResponse;
943
-
944
- const operation = sdk.transactionToOperation(accountId, address, mockUnstakingTx);
807
+ const operation = sdk.transactionToOperation(
808
+ accountId,
809
+ address,
810
+ mockUnstakingTx(address, "1000000000"),
811
+ );
945
812
 
946
813
  expect(operation).toHaveProperty("id");
947
814
  expect(operation).toHaveProperty("accountId", accountId);
@@ -949,7 +816,7 @@ describe("Staking Operations", () => {
949
816
  expect(operation).toHaveProperty("hash", "undelegate_tx_digest_456");
950
817
  expect(operation).toHaveProperty("extra");
951
818
  expect((operation.extra as { coinType: string }).coinType).toBe(sdk.DEFAULT_COIN_TYPE);
952
- expect(operation.value).toEqual(new BigNumber("0"));
819
+ expect(operation.value).toEqual(new BigNumber("-1000000000"));
953
820
  expect(operation.recipients).toEqual([]);
954
821
  expect(operation.senders).toEqual([address]);
955
822
  });
@@ -957,44 +824,7 @@ describe("Staking Operations", () => {
957
824
  test("transactionToOp should map staking transaction correctly", () => {
958
825
  const address = "0x65449f57946938c84c512732f1d69405d1fce417d9c9894696ddf4522f479e24";
959
826
 
960
- const mockStakingTx = {
961
- digest: "delegate_tx_digest_123",
962
- transaction: {
963
- data: {
964
- sender: address,
965
- transaction: {
966
- kind: "ProgrammableTransaction",
967
- inputs: [],
968
- transactions: [
969
- {
970
- MoveCall: {
971
- function: "request_add_stake",
972
- },
973
- },
974
- ],
975
- },
976
- },
977
- },
978
- effects: {
979
- status: { status: "success" },
980
- gasUsed: {
981
- computationCost: "1000000",
982
- storageCost: "500000",
983
- storageRebate: "450000",
984
- },
985
- },
986
- balanceChanges: [
987
- {
988
- owner: { AddressOwner: address },
989
- coinType: "0x2::sui::SUI",
990
- amount: "-1000000000",
991
- },
992
- ],
993
- timestampMs: "1742294454878",
994
- checkpoint: "313024",
995
- } as unknown as SuiTransactionBlockResponse;
996
-
997
- const operation = sdk.alpacaTransactionToOp(address, mockStakingTx);
827
+ const operation = sdk.alpacaTransactionToOp(address, mockStakingTx(address, "-1000000000"));
998
828
 
999
829
  expect(operation.id).toEqual("delegate_tx_digest_123");
1000
830
  expect(operation.type).toEqual("DELEGATE");
@@ -1008,50 +838,13 @@ describe("Staking Operations", () => {
1008
838
  test("transactionToOp should map unstaking transaction correctly", () => {
1009
839
  const address = "0x65449f57946938c84c512732f1d69405d1fce417d9c9894696ddf4522f479e24";
1010
840
 
1011
- const mockUnstakingTx = {
1012
- digest: "undelegate_tx_digest_456",
1013
- transaction: {
1014
- data: {
1015
- sender: address,
1016
- transaction: {
1017
- kind: "ProgrammableTransaction",
1018
- inputs: [],
1019
- transactions: [
1020
- {
1021
- MoveCall: {
1022
- function: "request_withdraw_stake",
1023
- },
1024
- },
1025
- ],
1026
- },
1027
- },
1028
- },
1029
- effects: {
1030
- status: { status: "success" },
1031
- gasUsed: {
1032
- computationCost: "1000000",
1033
- storageCost: "500000",
1034
- storageRebate: "450000",
1035
- },
1036
- },
1037
- balanceChanges: [
1038
- {
1039
- owner: { AddressOwner: address },
1040
- coinType: "0x2::sui::SUI",
1041
- amount: "0",
1042
- },
1043
- ],
1044
- timestampMs: "1742294454878",
1045
- checkpoint: "313024",
1046
- } as unknown as SuiTransactionBlockResponse;
1047
-
1048
- const operation = sdk.alpacaTransactionToOp(address, mockUnstakingTx);
841
+ const operation = sdk.alpacaTransactionToOp(address, mockUnstakingTx(address, "1000000000"));
1049
842
 
1050
843
  expect(operation.id).toEqual("undelegate_tx_digest_456");
1051
844
  expect(operation.type).toEqual("UNDELEGATE");
1052
845
  expect(operation.senders).toEqual([address]);
1053
846
  expect(operation.recipients).toEqual([]);
1054
- expect(operation.value).toEqual(0n);
847
+ expect(operation.value).toEqual(1000000000n);
1055
848
  expect(operation.asset).toEqual({ type: "native" });
1056
849
  expect(operation.tx.block.hash).toBeUndefined();
1057
850
  });
@@ -1944,7 +1737,7 @@ describe("filterOperations", () => {
1944
1737
  describe("conversion methods", () => {
1945
1738
  test("toBlockOperation should map native transfers correctly", () => {
1946
1739
  expect(
1947
- sdk.toBlockOperation({
1740
+ sdk.toBlockOperation(mockTransaction, {
1948
1741
  owner: {
1949
1742
  AddressOwner: "0x65449f57946938c84c5127",
1950
1743
  },
@@ -1963,7 +1756,7 @@ describe("filterOperations", () => {
1963
1756
 
1964
1757
  test("toBlockOperation should ignore transfers from shared owner", () => {
1965
1758
  expect(
1966
- sdk.toBlockOperation({
1759
+ sdk.toBlockOperation(mockTransaction, {
1967
1760
  owner: {
1968
1761
  Shared: {
1969
1762
  initial_shared_version: "0",
@@ -1977,7 +1770,7 @@ describe("filterOperations", () => {
1977
1770
 
1978
1771
  test("toBlockOperation should ignore transfers from object owner", () => {
1979
1772
  expect(
1980
- sdk.toBlockOperation({
1773
+ sdk.toBlockOperation(mockTransaction, {
1981
1774
  owner: {
1982
1775
  ObjectOwner: "test",
1983
1776
  },
@@ -1989,7 +1782,7 @@ describe("filterOperations", () => {
1989
1782
 
1990
1783
  test("toBlockOperation should ignore transfers from immutable owner", () => {
1991
1784
  expect(
1992
- sdk.toBlockOperation({
1785
+ sdk.toBlockOperation(mockTransaction, {
1993
1786
  owner: "Immutable",
1994
1787
  coinType: sdk.DEFAULT_COIN_TYPE,
1995
1788
  amount: "-10000000000",
@@ -1999,7 +1792,7 @@ describe("filterOperations", () => {
1999
1792
 
2000
1793
  test("toBlockOperation should ignore transfers from consensus owner", () => {
2001
1794
  expect(
2002
- sdk.toBlockOperation({
1795
+ sdk.toBlockOperation(mockTransaction, {
2003
1796
  owner: {
2004
1797
  ConsensusAddressOwner: {
2005
1798
  owner: "test",
@@ -2014,7 +1807,7 @@ describe("filterOperations", () => {
2014
1807
 
2015
1808
  test("toBlockOperation should map token transfers correctly", () => {
2016
1809
  expect(
2017
- sdk.toBlockOperation({
1810
+ sdk.toBlockOperation(mockTransaction, {
2018
1811
  owner: {
2019
1812
  AddressOwner: "0x65449f57946938c84c5127",
2020
1813
  },
@@ -2034,6 +1827,44 @@ describe("filterOperations", () => {
2034
1827
  ]);
2035
1828
  });
2036
1829
 
1830
+ test("toBlockOperation should map staking operations correctly", () => {
1831
+ const address = "0x65449f57946938c84c512732f1d69405d1fce417d9c9894696ddf4522f479e24";
1832
+ expect(
1833
+ sdk.toBlockOperation(mockStakingTx(address, "-1000000000"), {
1834
+ owner: { AddressOwner: address },
1835
+ coinType: sdk.DEFAULT_COIN_TYPE,
1836
+ amount: "-10000000000",
1837
+ }),
1838
+ ).toEqual([
1839
+ {
1840
+ type: "other",
1841
+ operationType: "DELEGATE",
1842
+ address: address,
1843
+ asset: { type: "native" },
1844
+ amount: 10000000000n,
1845
+ },
1846
+ ]);
1847
+ });
1848
+
1849
+ test("toBlockOperation should map unstaking operations correctly", () => {
1850
+ const address = "0x65449f57946938c84c512732f1d69405d1fce417d9c9894696ddf4522f479e24";
1851
+ expect(
1852
+ sdk.toBlockOperation(mockUnstakingTx(address, "1000000000"), {
1853
+ owner: { AddressOwner: address },
1854
+ coinType: sdk.DEFAULT_COIN_TYPE,
1855
+ amount: "10000000000",
1856
+ }),
1857
+ ).toEqual([
1858
+ {
1859
+ type: "other",
1860
+ operationType: "UNDELEGATE",
1861
+ address: address,
1862
+ asset: { type: "native" },
1863
+ amount: 10000000000n,
1864
+ },
1865
+ ]);
1866
+ });
1867
+
2037
1868
  test("toBlockInfo should map checkpoints correctly", () => {
2038
1869
  expect(
2039
1870
  sdk.toBlockInfo({