@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.
@@ -2,6 +2,7 @@ import * as sdk from "./sdk";
2
2
  import coinConfig from "../config";
3
3
  import { BigNumber } from "bignumber.js";
4
4
  import { SuiClient } from "@mysten/sui/client";
5
+ import assert from "assert";
5
6
  // Mock SUI client for tests
6
7
  jest.mock("@mysten/sui/client", () => {
7
8
  return {
@@ -180,6 +181,87 @@ const mockTransaction = {
180
181
  timestampMs: "1742294454878",
181
182
  checkpoint: "313024",
182
183
  };
184
+ // Create a mock staking transaction
185
+ // amount must be a negative number
186
+ function mockStakingTx(address, amount) {
187
+ assert(new BigNumber(amount).lte(0), "amount must be a negative number");
188
+ return {
189
+ digest: "delegate_tx_digest_123",
190
+ transaction: {
191
+ data: {
192
+ sender: address,
193
+ transaction: {
194
+ kind: "ProgrammableTransaction",
195
+ inputs: [],
196
+ transactions: [
197
+ {
198
+ MoveCall: {
199
+ function: "request_add_stake",
200
+ },
201
+ },
202
+ ],
203
+ },
204
+ },
205
+ },
206
+ effects: {
207
+ status: { status: "success" },
208
+ gasUsed: {
209
+ computationCost: "1000000",
210
+ storageCost: "500000",
211
+ storageRebate: "450000",
212
+ },
213
+ },
214
+ balanceChanges: [
215
+ {
216
+ owner: { AddressOwner: address },
217
+ coinType: "0x2::sui::SUI",
218
+ amount: amount.startsWith("-") ? amount : `-${amount}`,
219
+ },
220
+ ],
221
+ timestampMs: "1742294454878",
222
+ checkpoint: "313024",
223
+ };
224
+ }
225
+ // amount must be a positive number
226
+ function mockUnstakingTx(address, amount) {
227
+ assert(new BigNumber(amount).gte(0), "amount must be a positive number");
228
+ return {
229
+ digest: "undelegate_tx_digest_456",
230
+ transaction: {
231
+ data: {
232
+ sender: address,
233
+ transaction: {
234
+ kind: "ProgrammableTransaction",
235
+ inputs: [],
236
+ transactions: [
237
+ {
238
+ MoveCall: {
239
+ function: "request_withdraw_stake",
240
+ },
241
+ },
242
+ ],
243
+ },
244
+ },
245
+ },
246
+ effects: {
247
+ status: { status: "success" },
248
+ gasUsed: {
249
+ computationCost: "1000000",
250
+ storageCost: "500000",
251
+ storageRebate: "450000",
252
+ },
253
+ },
254
+ balanceChanges: [
255
+ {
256
+ owner: { AddressOwner: address },
257
+ coinType: "0x2::sui::SUI",
258
+ amount: amount,
259
+ },
260
+ ],
261
+ timestampMs: "1742294454878",
262
+ checkpoint: "313024",
263
+ };
264
+ }
183
265
  const mockApi = new SuiClient({ url: "mock" });
184
266
  // Add getTransactionBlock method to mockApi
185
267
  mockApi.getTransactionBlock = jest.fn();
@@ -465,195 +547,39 @@ describe("Staking Operations", () => {
465
547
  describe("Operation Type Detection", () => {
466
548
  test("getOperationType should return DELEGATE for staking transaction", () => {
467
549
  const address = "0x65449f57946938c84c512732f1d69405d1fce417d9c9894696ddf4522f479e24";
468
- // Create a mock staking transaction
469
- const mockStakingTx = {
470
- digest: "delegate_tx_digest_123",
471
- transaction: {
472
- data: {
473
- sender: address,
474
- transaction: {
475
- kind: "ProgrammableTransaction",
476
- inputs: [],
477
- transactions: [
478
- {
479
- MoveCall: {
480
- function: "request_add_stake",
481
- },
482
- },
483
- ],
484
- },
485
- },
486
- },
487
- effects: {
488
- status: { status: "success" },
489
- gasUsed: {
490
- computationCost: "1000000",
491
- storageCost: "500000",
492
- storageRebate: "450000",
493
- },
494
- },
495
- balanceChanges: [
496
- {
497
- owner: { AddressOwner: address },
498
- coinType: "0x2::sui::SUI",
499
- amount: "-1000000000",
500
- },
501
- ],
502
- timestampMs: "1742294454878",
503
- checkpoint: "313024",
504
- };
505
- expect(sdk.getOperationType(address, mockStakingTx)).toBe("DELEGATE");
550
+ expect(sdk.getOperationType(address, mockStakingTx(address, "-1000000000"))).toBe("DELEGATE");
506
551
  });
507
552
  test("getOperationType should return UNDELEGATE for unstaking transaction", () => {
508
553
  const address = "0x65449f57946938c84c512732f1d69405d1fce417d9c9894696ddf4522f479e24";
509
- // Create a mock unstaking transaction
510
- const mockUnstakingTx = {
511
- digest: "undelegate_tx_digest_456",
512
- transaction: {
513
- data: {
514
- sender: address,
515
- transaction: {
516
- kind: "ProgrammableTransaction",
517
- inputs: [],
518
- transactions: [
519
- {
520
- MoveCall: {
521
- function: "request_withdraw_stake",
522
- },
523
- },
524
- ],
525
- },
526
- },
527
- },
528
- effects: {
529
- status: { status: "success" },
530
- gasUsed: {
531
- computationCost: "1000000",
532
- storageCost: "500000",
533
- storageRebate: "450000",
534
- },
535
- },
536
- balanceChanges: [
537
- {
538
- owner: { AddressOwner: address },
539
- coinType: "0x2::sui::SUI",
540
- amount: "0",
541
- },
542
- ],
543
- timestampMs: "1742294454878",
544
- checkpoint: "313024",
545
- };
546
- expect(sdk.getOperationType(address, mockUnstakingTx)).toBe("UNDELEGATE");
554
+ expect(sdk.getOperationType(address, mockUnstakingTx(address, "1000000000"))).toBe("UNDELEGATE");
547
555
  });
548
556
  });
549
557
  describe("Operation Amount Calculation", () => {
550
558
  const address = "0x6e143fe0a8ca010a86580dafac44298e5b1b7d73efc345356a59a15f0d7824f0";
551
- const mockStakingTx = {
552
- transaction: {
553
- data: {
554
- transaction: {
555
- kind: "ProgrammableTransaction",
556
- transactions: [
557
- {
558
- MoveCall: {
559
- function: "request_add_stake",
560
- },
561
- },
562
- ],
563
- },
564
- },
565
- },
566
- balanceChanges: [
567
- {
568
- owner: { AddressOwner: address },
569
- coinType: "0x2::sui::SUI",
570
- amount: "-1000000000",
571
- },
572
- ],
573
- };
574
- function mockUnstakingTx(amount) {
575
- return {
576
- transaction: {
577
- data: {
578
- transaction: {
579
- kind: "ProgrammableTransaction",
580
- transactions: [
581
- {
582
- MoveCall: {
583
- function: "request_withdraw_stake",
584
- },
585
- },
586
- ],
587
- },
588
- },
589
- },
590
- balanceChanges: [
591
- {
592
- owner: { AddressOwner: address },
593
- coinType: "0x2::sui::SUI",
594
- amount: amount,
595
- },
596
- ],
597
- };
598
- }
599
559
  function bridgeOperationAmount(mock, coinType = sdk.DEFAULT_COIN_TYPE) {
600
560
  return sdk.getOperationAmount(address, mock, coinType);
601
561
  }
602
- test("getOperationAmount should calculate staking amount", () => expect(bridgeOperationAmount(mockStakingTx)).toEqual(new BigNumber("1000000000")));
603
- test("getOperationAmount should calculate unstaking amount of 1000", () => expect(bridgeOperationAmount(mockUnstakingTx("1000"))).toEqual(new BigNumber("-1000")));
604
- test("getOperationAmount should calculate unstaking amount of 0", () => expect(bridgeOperationAmount(mockUnstakingTx("0"))).toEqual(new BigNumber("0")));
562
+ test("getOperationAmount should calculate staking amount", () => expect(bridgeOperationAmount(mockStakingTx(address, "-1000000000"))).toEqual(new BigNumber("1000000000")));
563
+ test("getOperationAmount should calculate unstaking amount of 1000", () => expect(bridgeOperationAmount(mockUnstakingTx(address, "1000"))).toEqual(new BigNumber("-1000")));
564
+ test("getOperationAmount should calculate unstaking amount of 0", () => expect(bridgeOperationAmount(mockUnstakingTx(address, "0"))).toEqual(new BigNumber("0")));
605
565
  test("getOperationAmount should calculate amount correctly for SUI", () => expect(bridgeOperationAmount(mockTransaction)).toEqual(new BigNumber("9998990120")));
606
566
  test("getOperationAmount should calculate amount correctly for tokens", () => expect(bridgeOperationAmount(mockTransaction, "0x123::test::TOKEN")).toEqual(new BigNumber("500000")));
607
567
  function alpacaOperationAmount(mock, coinType = sdk.DEFAULT_COIN_TYPE) {
608
568
  return sdk.alpacaGetOperationAmount(address, mock, coinType);
609
569
  }
610
- test("alpaca getOperationAmount should calculate staking amount", () => expect(alpacaOperationAmount(mockStakingTx)).toEqual(new BigNumber("1000000000")));
611
- test("alpaca getOperationAmount should calculate unstaking amount of 1000", () => expect(alpacaOperationAmount(mockUnstakingTx("1000"))).toEqual(new BigNumber("1000")));
612
- test("alpaca getOperationAmount should calculate unstaking amount of 0", () => expect(alpacaOperationAmount(mockUnstakingTx("0"))).toEqual(new BigNumber("0")));
570
+ test("alpaca getOperationAmount should calculate staking amount", () => expect(alpacaOperationAmount(mockStakingTx(address, "-1000000000"))).toEqual(new BigNumber("1000000000")));
571
+ test("alpaca getOperationAmount should calculate unstaking amount of 1000", () => expect(alpacaOperationAmount(mockUnstakingTx(address, "1000"))).toEqual(new BigNumber("1000")));
572
+ test("alpaca getOperationAmount should calculate unstaking amount of 0", () => expect(alpacaOperationAmount(mockUnstakingTx(address, "0"))).toEqual(new BigNumber("0")));
613
573
  test("alpaca getOperationAmount should calculate amount correctly for SUI", () => expect(alpacaOperationAmount(mockTransaction)).toEqual(new BigNumber("9998990120")));
614
574
  test("alpaca getOperationAmount should calculate amount correctly for tokens", () => expect(alpacaOperationAmount(mockTransaction, "0x123::test::TOKEN")).toEqual(new BigNumber("500000")));
615
575
  });
616
576
  describe("Operation Recipients", () => {
617
577
  test("getOperationRecipients should return empty array for staking transaction", () => {
618
- const mockStakingTx = {
619
- transaction: {
620
- data: {
621
- transaction: {
622
- kind: "ProgrammableTransaction",
623
- inputs: [],
624
- transactions: [
625
- {
626
- MoveCall: {
627
- function: "request_add_stake",
628
- },
629
- },
630
- ],
631
- },
632
- },
633
- },
634
- };
635
- const recipients = sdk.getOperationRecipients(mockStakingTx.transaction?.data);
578
+ const recipients = sdk.getOperationRecipients(mockStakingTx("0xdeadbeef", "-1000000000").transaction?.data);
636
579
  expect(recipients).toEqual([]);
637
580
  });
638
581
  test("getOperationRecipients should return empty array for unstaking transaction", () => {
639
- const mockUnstakingTx = {
640
- transaction: {
641
- data: {
642
- transaction: {
643
- kind: "ProgrammableTransaction",
644
- inputs: [],
645
- transactions: [
646
- {
647
- MoveCall: {
648
- function: "request_withdraw_stake",
649
- },
650
- },
651
- ],
652
- },
653
- },
654
- },
655
- };
656
- const recipients = sdk.getOperationRecipients(mockUnstakingTx.transaction?.data);
582
+ const recipients = sdk.getOperationRecipients(mockUnstakingTx("0xdeadbeef", "1000000000").transaction?.data);
657
583
  expect(recipients).toEqual([]);
658
584
  });
659
585
  });
@@ -734,43 +660,7 @@ describe("Staking Operations", () => {
734
660
  test("transactionToOperation should map staking transaction correctly", () => {
735
661
  const accountId = "mockAccountId";
736
662
  const address = "0x65449f57946938c84c512732f1d69405d1fce417d9c9894696ddf4522f479e24";
737
- const mockStakingTx = {
738
- digest: "delegate_tx_digest_123",
739
- transaction: {
740
- data: {
741
- sender: address,
742
- transaction: {
743
- kind: "ProgrammableTransaction",
744
- inputs: [],
745
- transactions: [
746
- {
747
- MoveCall: {
748
- function: "request_add_stake",
749
- },
750
- },
751
- ],
752
- },
753
- },
754
- },
755
- effects: {
756
- status: { status: "success" },
757
- gasUsed: {
758
- computationCost: "1000000",
759
- storageCost: "500000",
760
- storageRebate: "450000",
761
- },
762
- },
763
- balanceChanges: [
764
- {
765
- owner: { AddressOwner: address },
766
- coinType: "0x2::sui::SUI",
767
- amount: "-1000000000",
768
- },
769
- ],
770
- timestampMs: "1742294454878",
771
- checkpoint: "313024",
772
- };
773
- const operation = sdk.transactionToOperation(accountId, address, mockStakingTx);
663
+ const operation = sdk.transactionToOperation(accountId, address, mockStakingTx(address, "-1000000000"));
774
664
  expect(operation).toHaveProperty("id");
775
665
  expect(operation).toHaveProperty("accountId", accountId);
776
666
  expect(operation).toHaveProperty("type", "DELEGATE");
@@ -784,92 +674,20 @@ describe("Staking Operations", () => {
784
674
  test("transactionToOperation should map unstaking transaction correctly", () => {
785
675
  const accountId = "mockAccountId";
786
676
  const address = "0x65449f57946938c84c512732f1d69405d1fce417d9c9894696ddf4522f479e24";
787
- const mockUnstakingTx = {
788
- digest: "undelegate_tx_digest_456",
789
- transaction: {
790
- data: {
791
- sender: address,
792
- transaction: {
793
- kind: "ProgrammableTransaction",
794
- inputs: [],
795
- transactions: [
796
- {
797
- MoveCall: {
798
- function: "request_withdraw_stake",
799
- },
800
- },
801
- ],
802
- },
803
- },
804
- },
805
- effects: {
806
- status: { status: "success" },
807
- gasUsed: {
808
- computationCost: "1000000",
809
- storageCost: "500000",
810
- storageRebate: "450000",
811
- },
812
- },
813
- balanceChanges: [
814
- {
815
- owner: { AddressOwner: address },
816
- coinType: "0x2::sui::SUI",
817
- amount: "0",
818
- },
819
- ],
820
- timestampMs: "1742294454878",
821
- checkpoint: "313024",
822
- };
823
- const operation = sdk.transactionToOperation(accountId, address, mockUnstakingTx);
677
+ const operation = sdk.transactionToOperation(accountId, address, mockUnstakingTx(address, "1000000000"));
824
678
  expect(operation).toHaveProperty("id");
825
679
  expect(operation).toHaveProperty("accountId", accountId);
826
680
  expect(operation).toHaveProperty("type", "UNDELEGATE");
827
681
  expect(operation).toHaveProperty("hash", "undelegate_tx_digest_456");
828
682
  expect(operation).toHaveProperty("extra");
829
683
  expect(operation.extra.coinType).toBe(sdk.DEFAULT_COIN_TYPE);
830
- expect(operation.value).toEqual(new BigNumber("0"));
684
+ expect(operation.value).toEqual(new BigNumber("-1000000000"));
831
685
  expect(operation.recipients).toEqual([]);
832
686
  expect(operation.senders).toEqual([address]);
833
687
  });
834
688
  test("transactionToOp should map staking transaction correctly", () => {
835
689
  const address = "0x65449f57946938c84c512732f1d69405d1fce417d9c9894696ddf4522f479e24";
836
- const mockStakingTx = {
837
- digest: "delegate_tx_digest_123",
838
- transaction: {
839
- data: {
840
- sender: address,
841
- transaction: {
842
- kind: "ProgrammableTransaction",
843
- inputs: [],
844
- transactions: [
845
- {
846
- MoveCall: {
847
- function: "request_add_stake",
848
- },
849
- },
850
- ],
851
- },
852
- },
853
- },
854
- effects: {
855
- status: { status: "success" },
856
- gasUsed: {
857
- computationCost: "1000000",
858
- storageCost: "500000",
859
- storageRebate: "450000",
860
- },
861
- },
862
- balanceChanges: [
863
- {
864
- owner: { AddressOwner: address },
865
- coinType: "0x2::sui::SUI",
866
- amount: "-1000000000",
867
- },
868
- ],
869
- timestampMs: "1742294454878",
870
- checkpoint: "313024",
871
- };
872
- const operation = sdk.alpacaTransactionToOp(address, mockStakingTx);
690
+ const operation = sdk.alpacaTransactionToOp(address, mockStakingTx(address, "-1000000000"));
873
691
  expect(operation.id).toEqual("delegate_tx_digest_123");
874
692
  expect(operation.type).toEqual("DELEGATE");
875
693
  expect(operation.senders).toEqual([address]);
@@ -880,48 +698,12 @@ describe("Staking Operations", () => {
880
698
  });
881
699
  test("transactionToOp should map unstaking transaction correctly", () => {
882
700
  const address = "0x65449f57946938c84c512732f1d69405d1fce417d9c9894696ddf4522f479e24";
883
- const mockUnstakingTx = {
884
- digest: "undelegate_tx_digest_456",
885
- transaction: {
886
- data: {
887
- sender: address,
888
- transaction: {
889
- kind: "ProgrammableTransaction",
890
- inputs: [],
891
- transactions: [
892
- {
893
- MoveCall: {
894
- function: "request_withdraw_stake",
895
- },
896
- },
897
- ],
898
- },
899
- },
900
- },
901
- effects: {
902
- status: { status: "success" },
903
- gasUsed: {
904
- computationCost: "1000000",
905
- storageCost: "500000",
906
- storageRebate: "450000",
907
- },
908
- },
909
- balanceChanges: [
910
- {
911
- owner: { AddressOwner: address },
912
- coinType: "0x2::sui::SUI",
913
- amount: "0",
914
- },
915
- ],
916
- timestampMs: "1742294454878",
917
- checkpoint: "313024",
918
- };
919
- const operation = sdk.alpacaTransactionToOp(address, mockUnstakingTx);
701
+ const operation = sdk.alpacaTransactionToOp(address, mockUnstakingTx(address, "1000000000"));
920
702
  expect(operation.id).toEqual("undelegate_tx_digest_456");
921
703
  expect(operation.type).toEqual("UNDELEGATE");
922
704
  expect(operation.senders).toEqual([address]);
923
705
  expect(operation.recipients).toEqual([]);
924
- expect(operation.value).toEqual(0n);
706
+ expect(operation.value).toEqual(1000000000n);
925
707
  expect(operation.asset).toEqual({ type: "native" });
926
708
  expect(operation.tx.block.hash).toBeUndefined();
927
709
  });
@@ -1662,7 +1444,7 @@ describe("filterOperations", () => {
1662
1444
  });
1663
1445
  describe("conversion methods", () => {
1664
1446
  test("toBlockOperation should map native transfers correctly", () => {
1665
- expect(sdk.toBlockOperation({
1447
+ expect(sdk.toBlockOperation(mockTransaction, {
1666
1448
  owner: {
1667
1449
  AddressOwner: "0x65449f57946938c84c5127",
1668
1450
  },
@@ -1678,7 +1460,7 @@ describe("filterOperations", () => {
1678
1460
  ]);
1679
1461
  });
1680
1462
  test("toBlockOperation should ignore transfers from shared owner", () => {
1681
- expect(sdk.toBlockOperation({
1463
+ expect(sdk.toBlockOperation(mockTransaction, {
1682
1464
  owner: {
1683
1465
  Shared: {
1684
1466
  initial_shared_version: "0",
@@ -1689,7 +1471,7 @@ describe("filterOperations", () => {
1689
1471
  })).toEqual([]);
1690
1472
  });
1691
1473
  test("toBlockOperation should ignore transfers from object owner", () => {
1692
- expect(sdk.toBlockOperation({
1474
+ expect(sdk.toBlockOperation(mockTransaction, {
1693
1475
  owner: {
1694
1476
  ObjectOwner: "test",
1695
1477
  },
@@ -1698,14 +1480,14 @@ describe("filterOperations", () => {
1698
1480
  })).toEqual([]);
1699
1481
  });
1700
1482
  test("toBlockOperation should ignore transfers from immutable owner", () => {
1701
- expect(sdk.toBlockOperation({
1483
+ expect(sdk.toBlockOperation(mockTransaction, {
1702
1484
  owner: "Immutable",
1703
1485
  coinType: sdk.DEFAULT_COIN_TYPE,
1704
1486
  amount: "-10000000000",
1705
1487
  })).toEqual([]);
1706
1488
  });
1707
1489
  test("toBlockOperation should ignore transfers from consensus owner", () => {
1708
- expect(sdk.toBlockOperation({
1490
+ expect(sdk.toBlockOperation(mockTransaction, {
1709
1491
  owner: {
1710
1492
  ConsensusAddressOwner: {
1711
1493
  owner: "test",
@@ -1717,7 +1499,7 @@ describe("filterOperations", () => {
1717
1499
  })).toEqual([]);
1718
1500
  });
1719
1501
  test("toBlockOperation should map token transfers correctly", () => {
1720
- expect(sdk.toBlockOperation({
1502
+ expect(sdk.toBlockOperation(mockTransaction, {
1721
1503
  owner: {
1722
1504
  AddressOwner: "0x65449f57946938c84c5127",
1723
1505
  },
@@ -1735,6 +1517,38 @@ describe("filterOperations", () => {
1735
1517
  },
1736
1518
  ]);
1737
1519
  });
1520
+ test("toBlockOperation should map staking operations correctly", () => {
1521
+ const address = "0x65449f57946938c84c512732f1d69405d1fce417d9c9894696ddf4522f479e24";
1522
+ expect(sdk.toBlockOperation(mockStakingTx(address, "-1000000000"), {
1523
+ owner: { AddressOwner: address },
1524
+ coinType: sdk.DEFAULT_COIN_TYPE,
1525
+ amount: "-10000000000",
1526
+ })).toEqual([
1527
+ {
1528
+ type: "other",
1529
+ operationType: "DELEGATE",
1530
+ address: address,
1531
+ asset: { type: "native" },
1532
+ amount: 10000000000n,
1533
+ },
1534
+ ]);
1535
+ });
1536
+ test("toBlockOperation should map unstaking operations correctly", () => {
1537
+ const address = "0x65449f57946938c84c512732f1d69405d1fce417d9c9894696ddf4522f479e24";
1538
+ expect(sdk.toBlockOperation(mockUnstakingTx(address, "1000000000"), {
1539
+ owner: { AddressOwner: address },
1540
+ coinType: sdk.DEFAULT_COIN_TYPE,
1541
+ amount: "10000000000",
1542
+ })).toEqual([
1543
+ {
1544
+ type: "other",
1545
+ operationType: "UNDELEGATE",
1546
+ address: address,
1547
+ asset: { type: "native" },
1548
+ amount: 10000000000n,
1549
+ },
1550
+ ]);
1551
+ });
1738
1552
  test("toBlockInfo should map checkpoints correctly", () => {
1739
1553
  expect(sdk.toBlockInfo({
1740
1554
  checkpointCommitments: [],