@ledgerhq/coin-sui 0.11.0 → 0.12.0-nightly.1
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/.eslintrc.js +1 -0
- package/.turbo/turbo-build.log +1 -1
- package/.unimportedrc.json +1 -0
- package/CHANGELOG.md +21 -0
- package/index.d.ts +0 -1
- package/jest.config.js +1 -1
- package/lib/bridge/broadcast.d.ts.map +1 -1
- package/lib/bridge/broadcast.js +3 -0
- package/lib/bridge/broadcast.js.map +1 -1
- package/lib/bridge/buildOptimisticOperation.js +31 -0
- package/lib/bridge/buildOptimisticOperation.js.map +1 -1
- package/lib/bridge/buildTransaction.d.ts +1 -1
- package/lib/bridge/buildTransaction.d.ts.map +1 -1
- package/lib/bridge/buildTransaction.js +3 -1
- package/lib/bridge/buildTransaction.js.map +1 -1
- package/lib/bridge/buildTransaction.test.js +4 -0
- package/lib/bridge/buildTransaction.test.js.map +1 -1
- package/lib/bridge/estimateMaxSpendable.d.ts.map +1 -1
- package/lib/bridge/estimateMaxSpendable.js +15 -3
- package/lib/bridge/estimateMaxSpendable.js.map +1 -1
- package/lib/bridge/estimateMaxSpendable.test.js +27 -0
- package/lib/bridge/estimateMaxSpendable.test.js.map +1 -1
- package/lib/bridge/getFeesForTransaction.d.ts.map +1 -1
- package/lib/bridge/getFeesForTransaction.js +13 -1
- package/lib/bridge/getFeesForTransaction.js.map +1 -1
- package/lib/bridge/getOperationExtra.d.ts +2 -0
- package/lib/bridge/getOperationExtra.d.ts.map +1 -0
- package/lib/bridge/getOperationExtra.js +6 -0
- package/lib/bridge/getOperationExtra.js.map +1 -0
- package/lib/bridge/getTransactionStatus.d.ts.map +1 -1
- package/lib/bridge/getTransactionStatus.js +45 -20
- package/lib/bridge/getTransactionStatus.js.map +1 -1
- package/lib/bridge/preload.d.ts.map +1 -1
- package/lib/bridge/preload.js +5 -3
- package/lib/bridge/preload.js.map +1 -1
- package/lib/bridge/preload.test.js +13 -217
- package/lib/bridge/preload.test.js.map +1 -1
- package/lib/bridge/prepareTransaction.js +1 -1
- package/lib/bridge/prepareTransaction.js.map +1 -1
- package/lib/bridge/synchronisation.d.ts.map +1 -1
- package/lib/bridge/synchronisation.js +5 -2
- package/lib/bridge/synchronisation.js.map +1 -1
- package/lib/bridge/synchronisation.test.js +355 -7
- package/lib/bridge/synchronisation.test.js.map +1 -1
- package/lib/bridge/utils.d.ts +1 -1
- package/lib/bridge/utils.d.ts.map +1 -1
- package/lib/bridge/utils.js +22 -0
- package/lib/bridge/utils.js.map +1 -1
- package/lib/constants.d.ts +4 -0
- package/lib/constants.d.ts.map +1 -0
- package/lib/constants.js +7 -0
- package/lib/constants.js.map +1 -0
- package/lib/errors.d.ts +13 -0
- package/lib/errors.d.ts.map +1 -0
- package/lib/errors.js +21 -0
- package/lib/errors.js.map +1 -0
- package/lib/logic/craftTransaction.d.ts +5 -10
- package/lib/logic/craftTransaction.d.ts.map +1 -1
- package/lib/logic/craftTransaction.js +2 -1
- package/lib/logic/craftTransaction.js.map +1 -1
- package/lib/logic/estimateFees.d.ts +1 -1
- package/lib/logic/estimateFees.d.ts.map +1 -1
- package/lib/logic/estimateFees.js +14 -2
- package/lib/logic/estimateFees.js.map +1 -1
- package/lib/logic/index.d.ts +2 -1
- package/lib/logic/index.d.ts.map +1 -1
- package/lib/logic/index.js +3 -1
- package/lib/logic/index.js.map +1 -1
- package/lib/logic/stake.d.ts +3 -0
- package/lib/logic/stake.d.ts.map +1 -0
- package/lib/logic/stake.js +12 -0
- package/lib/logic/stake.js.map +1 -0
- package/lib/network/index.d.ts +5 -4
- package/lib/network/index.d.ts.map +1 -1
- package/lib/network/index.js +5 -3
- package/lib/network/index.js.map +1 -1
- package/lib/network/sdk.d.ts +5 -3
- package/lib/network/sdk.d.ts.map +1 -1
- package/lib/network/sdk.js +148 -26
- package/lib/network/sdk.js.map +1 -1
- package/lib/network/sdk.test.js +491 -6
- package/lib/network/sdk.test.js.map +1 -1
- package/lib/types/bridge.d.ts +33 -6
- package/lib/types/bridge.d.ts.map +1 -1
- package/lib-es/bridge/broadcast.d.ts.map +1 -1
- package/lib-es/bridge/broadcast.js +3 -0
- package/lib-es/bridge/broadcast.js.map +1 -1
- package/lib-es/bridge/buildOptimisticOperation.js +31 -0
- package/lib-es/bridge/buildOptimisticOperation.js.map +1 -1
- package/lib-es/bridge/buildTransaction.d.ts +1 -1
- package/lib-es/bridge/buildTransaction.d.ts.map +1 -1
- package/lib-es/bridge/buildTransaction.js +3 -1
- package/lib-es/bridge/buildTransaction.js.map +1 -1
- package/lib-es/bridge/buildTransaction.test.js +4 -0
- package/lib-es/bridge/buildTransaction.test.js.map +1 -1
- package/lib-es/bridge/estimateMaxSpendable.d.ts.map +1 -1
- package/lib-es/bridge/estimateMaxSpendable.js +15 -3
- package/lib-es/bridge/estimateMaxSpendable.js.map +1 -1
- package/lib-es/bridge/estimateMaxSpendable.test.js +27 -0
- package/lib-es/bridge/estimateMaxSpendable.test.js.map +1 -1
- package/lib-es/bridge/getFeesForTransaction.d.ts.map +1 -1
- package/lib-es/bridge/getFeesForTransaction.js +13 -1
- package/lib-es/bridge/getFeesForTransaction.js.map +1 -1
- package/lib-es/bridge/getOperationExtra.d.ts +2 -0
- package/lib-es/bridge/getOperationExtra.d.ts.map +1 -0
- package/lib-es/bridge/getOperationExtra.js +2 -0
- package/lib-es/bridge/getOperationExtra.js.map +1 -0
- package/lib-es/bridge/getTransactionStatus.d.ts.map +1 -1
- package/lib-es/bridge/getTransactionStatus.js +46 -21
- package/lib-es/bridge/getTransactionStatus.js.map +1 -1
- package/lib-es/bridge/preload.d.ts.map +1 -1
- package/lib-es/bridge/preload.js +5 -3
- package/lib-es/bridge/preload.js.map +1 -1
- package/lib-es/bridge/preload.test.js +14 -218
- package/lib-es/bridge/preload.test.js.map +1 -1
- package/lib-es/bridge/prepareTransaction.js +1 -1
- package/lib-es/bridge/prepareTransaction.js.map +1 -1
- package/lib-es/bridge/synchronisation.d.ts.map +1 -1
- package/lib-es/bridge/synchronisation.js +6 -3
- package/lib-es/bridge/synchronisation.js.map +1 -1
- package/lib-es/bridge/synchronisation.test.js +332 -7
- package/lib-es/bridge/synchronisation.test.js.map +1 -1
- package/lib-es/bridge/utils.d.ts +1 -1
- package/lib-es/bridge/utils.d.ts.map +1 -1
- package/lib-es/bridge/utils.js +22 -0
- package/lib-es/bridge/utils.js.map +1 -1
- package/lib-es/constants.d.ts +4 -0
- package/lib-es/constants.d.ts.map +1 -0
- package/lib-es/constants.js +4 -0
- package/lib-es/constants.js.map +1 -0
- package/lib-es/errors.d.ts +13 -0
- package/lib-es/errors.d.ts.map +1 -0
- package/lib-es/errors.js +18 -0
- package/lib-es/errors.js.map +1 -0
- package/lib-es/logic/craftTransaction.d.ts +5 -10
- package/lib-es/logic/craftTransaction.d.ts.map +1 -1
- package/lib-es/logic/craftTransaction.js +2 -1
- package/lib-es/logic/craftTransaction.js.map +1 -1
- package/lib-es/logic/estimateFees.d.ts +1 -1
- package/lib-es/logic/estimateFees.d.ts.map +1 -1
- package/lib-es/logic/estimateFees.js +14 -2
- package/lib-es/logic/estimateFees.js.map +1 -1
- package/lib-es/logic/index.d.ts +2 -1
- package/lib-es/logic/index.d.ts.map +1 -1
- package/lib-es/logic/index.js +1 -0
- package/lib-es/logic/index.js.map +1 -1
- package/lib-es/logic/stake.d.ts +3 -0
- package/lib-es/logic/stake.d.ts.map +1 -0
- package/lib-es/logic/stake.js +8 -0
- package/lib-es/logic/stake.js.map +1 -0
- package/lib-es/network/index.d.ts +5 -4
- package/lib-es/network/index.d.ts.map +1 -1
- package/lib-es/network/index.js +4 -3
- package/lib-es/network/index.js.map +1 -1
- package/lib-es/network/sdk.d.ts +5 -3
- package/lib-es/network/sdk.d.ts.map +1 -1
- package/lib-es/network/sdk.js +144 -25
- package/lib-es/network/sdk.js.map +1 -1
- package/lib-es/network/sdk.test.js +491 -6
- package/lib-es/network/sdk.test.js.map +1 -1
- package/lib-es/types/bridge.d.ts +33 -6
- package/lib-es/types/bridge.d.ts.map +1 -1
- package/package.json +20 -12
- package/src/bridge/broadcast.ts +3 -0
- package/src/bridge/buildOptimisticOperation.ts +47 -4
- package/src/bridge/buildTransaction.test.ts +4 -0
- package/src/bridge/buildTransaction.ts +3 -1
- package/src/bridge/estimateMaxSpendable.test.ts +33 -0
- package/src/bridge/estimateMaxSpendable.ts +17 -3
- package/src/bridge/getFeesForTransaction.ts +14 -1
- package/src/bridge/getOperationExtra.ts +1 -0
- package/src/bridge/getTransactionStatus.ts +53 -21
- package/src/bridge/preload.test.ts +13 -279
- package/src/bridge/preload.ts +5 -3
- package/src/bridge/prepareTransaction.ts +1 -1
- package/src/bridge/synchronisation.test.ts +389 -7
- package/src/bridge/synchronisation.ts +6 -3
- package/src/bridge/utils.ts +25 -1
- package/src/constants.ts +4 -0
- package/src/errors.ts +21 -0
- package/src/logic/craftTransaction.ts +6 -9
- package/src/logic/estimateFees.ts +16 -1
- package/src/logic/index.ts +2 -1
- package/src/logic/stake.ts +9 -0
- package/src/network/index.ts +6 -3
- package/src/network/sdk.test.ts +538 -10
- package/src/network/sdk.ts +179 -31
- package/src/types/bridge.ts +32 -6
|
@@ -4,6 +4,7 @@ import { getMainAccount } from "@ledgerhq/coin-framework/account/index";
|
|
|
4
4
|
import type { SuiAccount, Transaction } from "../types";
|
|
5
5
|
import getFeesForTransaction from "./getFeesForTransaction";
|
|
6
6
|
import createTransaction from "./createTransaction";
|
|
7
|
+
import { ONE_SUI } from "../constants";
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* Returns the maximum possible amount for transaction
|
|
@@ -30,17 +31,30 @@ export const estimateMaxSpendable: AccountBridge<Transaction>["estimateMaxSpenda
|
|
|
30
31
|
|
|
31
32
|
let spendableBalance = account.spendableBalance;
|
|
32
33
|
|
|
33
|
-
if (account.type
|
|
34
|
+
if (account.type === "Account") {
|
|
34
35
|
const fees = await getFeesForTransaction({
|
|
35
36
|
account: mainAccount,
|
|
36
37
|
transaction: estimatedTransaction,
|
|
37
38
|
});
|
|
38
39
|
if (fees) {
|
|
39
|
-
spendableBalance =
|
|
40
|
+
spendableBalance = spendableBalance.minus(fees);
|
|
40
41
|
}
|
|
41
42
|
}
|
|
42
43
|
|
|
43
|
-
|
|
44
|
+
// Apply delegation-specific constraints
|
|
45
|
+
if (transaction?.mode === "delegate") {
|
|
46
|
+
// Reserve 0.1 SUI for future gas fees as recommended
|
|
47
|
+
const gasReserve = new BigNumber(ONE_SUI).div(10);
|
|
48
|
+
spendableBalance = spendableBalance.minus(gasReserve);
|
|
49
|
+
|
|
50
|
+
// Ensure we don't go below 1 SUI minimum for delegation
|
|
51
|
+
const oneSui = new BigNumber(ONE_SUI);
|
|
52
|
+
if (spendableBalance.lt(oneSui)) {
|
|
53
|
+
return new BigNumber(0);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return BigNumber.max(spendableBalance, 0);
|
|
44
58
|
} catch (e) {
|
|
45
59
|
return new BigNumber(0);
|
|
46
60
|
}
|
|
@@ -37,11 +37,24 @@ export default async function getEstimatedFees({
|
|
|
37
37
|
const subAccount = findSubAccountById(account, transaction.subAccountId ?? "");
|
|
38
38
|
const asset = toSuiAsset(subAccount?.token.contractAddress ?? DEFAULT_COIN_TYPE);
|
|
39
39
|
|
|
40
|
+
let transactionType: "send" | "delegate" | "undelegate";
|
|
41
|
+
switch (transaction.mode) {
|
|
42
|
+
case "delegate":
|
|
43
|
+
transactionType = "delegate";
|
|
44
|
+
break;
|
|
45
|
+
case "undelegate":
|
|
46
|
+
transactionType = "undelegate";
|
|
47
|
+
break;
|
|
48
|
+
default:
|
|
49
|
+
transactionType = "send";
|
|
50
|
+
break;
|
|
51
|
+
}
|
|
52
|
+
|
|
40
53
|
const fees = await estimateFees({
|
|
41
54
|
recipient: getAbandonSeedAddress(account.currency.id),
|
|
42
55
|
sender: account.freshAddress,
|
|
43
56
|
amount: BigInt(t.amount.toString()),
|
|
44
|
-
type:
|
|
57
|
+
type: transactionType,
|
|
45
58
|
asset,
|
|
46
59
|
});
|
|
47
60
|
return new BigNumber(fees.toString());
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { getOperationExtra } from "../network/sdk";
|
|
@@ -3,17 +3,24 @@ import {
|
|
|
3
3
|
NotEnoughBalance,
|
|
4
4
|
NotEnoughBalanceInParentAccount,
|
|
5
5
|
RecipientRequired,
|
|
6
|
-
InvalidAddress,
|
|
7
6
|
InvalidAddressBecauseDestinationIsAlsoSource,
|
|
8
7
|
AmountRequired,
|
|
9
8
|
FeeNotLoaded,
|
|
10
9
|
FeeTooHigh,
|
|
10
|
+
InvalidAddress,
|
|
11
11
|
} from "@ledgerhq/errors";
|
|
12
12
|
import { AccountBridge } from "@ledgerhq/types-live";
|
|
13
13
|
import { findSubAccountById } from "@ledgerhq/coin-framework/account/index";
|
|
14
14
|
import { isValidSuiAddress } from "@mysten/sui/utils";
|
|
15
15
|
import type { SuiAccount, Transaction, TransactionStatus } from "../types";
|
|
16
16
|
import { ensureAddressFormat } from "../utils";
|
|
17
|
+
import {
|
|
18
|
+
OneSuiMinForStake,
|
|
19
|
+
OneSuiMinForUnstake,
|
|
20
|
+
OneSuiMinForUnstakeToBeLeft,
|
|
21
|
+
SomeSuiForUnstake,
|
|
22
|
+
} from "../errors";
|
|
23
|
+
import { ONE_SUI } from "../constants";
|
|
17
24
|
|
|
18
25
|
/**
|
|
19
26
|
* Get the status of a transaction.
|
|
@@ -39,36 +46,61 @@ export const getTransactionStatus: AccountBridge<
|
|
|
39
46
|
accountBalance = subAccount?.balance ?? new BigNumber(0);
|
|
40
47
|
}
|
|
41
48
|
|
|
42
|
-
if (amount.lte(0)) {
|
|
49
|
+
if (amount.lte(0) && !transaction.useAllAmount) {
|
|
43
50
|
errors.amount = new AmountRequired();
|
|
44
51
|
} else if (estimatedFees.times(10).gt(amount) && !transaction.subAccountId) {
|
|
45
52
|
warnings.feeTooHigh = new FeeTooHigh();
|
|
46
53
|
}
|
|
47
54
|
|
|
48
|
-
if (!transaction.
|
|
49
|
-
errors.
|
|
50
|
-
} else if (!isValidSuiAddress(transaction.recipient)) {
|
|
51
|
-
errors.recipient = new InvalidAddress(undefined, {
|
|
52
|
-
currencyName: account.currency.name,
|
|
53
|
-
});
|
|
55
|
+
if (!transaction.fees) {
|
|
56
|
+
errors.fees = new FeeNotLoaded();
|
|
54
57
|
}
|
|
55
58
|
|
|
56
|
-
if (
|
|
57
|
-
|
|
58
|
-
|
|
59
|
+
if (transaction.mode === "undelegate") {
|
|
60
|
+
const stakes = account.suiResources?.stakes?.flatMap(({ stakes }) => stakes) ?? [];
|
|
61
|
+
const stake = stakes.find(s => s.stakedSuiId === transaction.stakedSuiId);
|
|
62
|
+
if (stake) {
|
|
63
|
+
if (!transaction.useAllAmount && amount.lt(ONE_SUI)) {
|
|
64
|
+
errors.amount = new OneSuiMinForUnstake();
|
|
65
|
+
}
|
|
66
|
+
const stakeLeft = BigNumber(stake?.principal).minus(amount);
|
|
67
|
+
if (!transaction.useAllAmount && stakeLeft.lt(ONE_SUI) && stakeLeft.gt(0)) {
|
|
68
|
+
errors.amount = new OneSuiMinForUnstakeToBeLeft();
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
} else {
|
|
72
|
+
if (!transaction.recipient) {
|
|
73
|
+
errors.recipient = new RecipientRequired();
|
|
74
|
+
} else if (!isValidSuiAddress(transaction.recipient)) {
|
|
75
|
+
errors.recipient = new InvalidAddress(undefined, {
|
|
76
|
+
currencyName: account.currency.name,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
59
79
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
80
|
+
if (ensureAddressFormat(account.freshAddress) === ensureAddressFormat(transaction.recipient)) {
|
|
81
|
+
errors.recipient = new InvalidAddressBecauseDestinationIsAlsoSource();
|
|
82
|
+
}
|
|
63
83
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
84
|
+
if (totalSpent.eq(0) && transaction.useAllAmount) {
|
|
85
|
+
errors.amount = new NotEnoughBalance();
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (transaction.subAccountId && estimatedFees.gt(account.balance)) {
|
|
89
|
+
errors.amount = new NotEnoughBalanceInParentAccount();
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (totalSpent.gt(accountBalance)) {
|
|
93
|
+
errors.amount = new NotEnoughBalance();
|
|
94
|
+
}
|
|
69
95
|
}
|
|
70
|
-
if (
|
|
71
|
-
|
|
96
|
+
if (transaction.mode === "delegate") {
|
|
97
|
+
if (amount.lt(new BigNumber(ONE_SUI))) {
|
|
98
|
+
errors.amount = new OneSuiMinForStake();
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// 0.1 SUI
|
|
102
|
+
if (account.balance.minus(transaction.amount).lt(ONE_SUI / 10))
|
|
103
|
+
warnings.amount = new SomeSuiForUnstake();
|
|
72
104
|
}
|
|
73
105
|
|
|
74
106
|
return {
|
|
@@ -5,8 +5,6 @@ import {
|
|
|
5
5
|
setSuiPreloadData,
|
|
6
6
|
getSuiPreloadDataUpdates,
|
|
7
7
|
getPreloadStrategy,
|
|
8
|
-
preload,
|
|
9
|
-
hydrate,
|
|
10
8
|
} from "./preload";
|
|
11
9
|
import type { SuiPreloadData } from "../types";
|
|
12
10
|
|
|
@@ -18,17 +16,12 @@ jest.mock("@ledgerhq/logs", () => ({
|
|
|
18
16
|
describe("Sui Preload Functions", () => {
|
|
19
17
|
beforeEach(() => {
|
|
20
18
|
// Reset the preload data before each test
|
|
21
|
-
setSuiPreloadData({});
|
|
19
|
+
setSuiPreloadData({ validators: [] });
|
|
22
20
|
});
|
|
23
21
|
|
|
24
22
|
describe("getCurrentSuiPreloadData", () => {
|
|
25
|
-
it("should return empty object by default", () => {
|
|
26
|
-
const data = getCurrentSuiPreloadData();
|
|
27
|
-
expect(data).toEqual({});
|
|
28
|
-
});
|
|
29
|
-
|
|
30
23
|
it("should return the current preloaded data", () => {
|
|
31
|
-
const testData: SuiPreloadData = {
|
|
24
|
+
const testData: SuiPreloadData = { validators: [] };
|
|
32
25
|
setSuiPreloadData(testData);
|
|
33
26
|
|
|
34
27
|
const data = getCurrentSuiPreloadData();
|
|
@@ -36,46 +29,6 @@ describe("Sui Preload Functions", () => {
|
|
|
36
29
|
});
|
|
37
30
|
});
|
|
38
31
|
|
|
39
|
-
describe("setSuiPreloadData", () => {
|
|
40
|
-
it("should set the preload data", () => {
|
|
41
|
-
const testData: SuiPreloadData = { key1: "value1", key2: "value2" };
|
|
42
|
-
|
|
43
|
-
setSuiPreloadData(testData);
|
|
44
|
-
|
|
45
|
-
const currentData = getCurrentSuiPreloadData();
|
|
46
|
-
expect(currentData).toEqual(testData);
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
it("should not update if data is the same reference", () => {
|
|
50
|
-
const testData: SuiPreloadData = { test: "data" };
|
|
51
|
-
|
|
52
|
-
// Set data first time
|
|
53
|
-
setSuiPreloadData(testData);
|
|
54
|
-
const firstCall = getCurrentSuiPreloadData();
|
|
55
|
-
|
|
56
|
-
// Set the same data reference
|
|
57
|
-
setSuiPreloadData(testData);
|
|
58
|
-
const secondCall = getCurrentSuiPreloadData();
|
|
59
|
-
|
|
60
|
-
expect(firstCall).toBe(secondCall);
|
|
61
|
-
expect(firstCall).toEqual(testData);
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
it("should update if data has different content", () => {
|
|
65
|
-
const firstData: SuiPreloadData = { test: "first" };
|
|
66
|
-
const secondData: SuiPreloadData = { test: "second" };
|
|
67
|
-
|
|
68
|
-
setSuiPreloadData(firstData);
|
|
69
|
-
const firstCall = getCurrentSuiPreloadData();
|
|
70
|
-
|
|
71
|
-
setSuiPreloadData(secondData);
|
|
72
|
-
const secondCall = getCurrentSuiPreloadData();
|
|
73
|
-
|
|
74
|
-
expect(firstCall).not.toBe(secondCall);
|
|
75
|
-
expect(secondCall).toEqual(secondData);
|
|
76
|
-
});
|
|
77
|
-
});
|
|
78
|
-
|
|
79
32
|
describe("getSuiPreloadDataUpdates", () => {
|
|
80
33
|
it("should return an Observable", () => {
|
|
81
34
|
const updates = getSuiPreloadDataUpdates();
|
|
@@ -83,7 +36,7 @@ describe("Sui Preload Functions", () => {
|
|
|
83
36
|
});
|
|
84
37
|
|
|
85
38
|
it("should emit updates when data is set", done => {
|
|
86
|
-
const testData: SuiPreloadData = {
|
|
39
|
+
const testData: SuiPreloadData = { validators: [] };
|
|
87
40
|
const updates = getSuiPreloadDataUpdates();
|
|
88
41
|
|
|
89
42
|
updates.pipe(take(1)).subscribe(data => {
|
|
@@ -94,240 +47,21 @@ describe("Sui Preload Functions", () => {
|
|
|
94
47
|
setSuiPreloadData(testData);
|
|
95
48
|
});
|
|
96
49
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
const updates = getSuiPreloadDataUpdates();
|
|
101
|
-
|
|
102
|
-
let callCount = 0;
|
|
103
|
-
updates.pipe(take(2)).subscribe(data => {
|
|
104
|
-
callCount++;
|
|
105
|
-
if (callCount === 1) {
|
|
106
|
-
expect(data).toEqual(firstData);
|
|
107
|
-
} else if (callCount === 2) {
|
|
108
|
-
expect(data).toEqual(secondData);
|
|
109
|
-
done();
|
|
110
|
-
}
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
setSuiPreloadData(firstData);
|
|
114
|
-
setSuiPreloadData(secondData);
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
it("should not emit when same data reference is set", done => {
|
|
118
|
-
const testData: SuiPreloadData = { test: "data" };
|
|
119
|
-
const updates = getSuiPreloadDataUpdates();
|
|
120
|
-
|
|
121
|
-
let callCount = 0;
|
|
122
|
-
updates.pipe(take(1)).subscribe(data => {
|
|
123
|
-
callCount++;
|
|
124
|
-
expect(data).toEqual(testData);
|
|
125
|
-
// Wait a bit to ensure no additional emissions
|
|
126
|
-
setTimeout(() => {
|
|
127
|
-
expect(callCount).toBe(1);
|
|
128
|
-
done();
|
|
129
|
-
}, 10);
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
setSuiPreloadData(testData);
|
|
133
|
-
setSuiPreloadData(testData); // Same reference, should not emit
|
|
134
|
-
});
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
describe("getPreloadStrategy", () => {
|
|
138
|
-
it("should return preload strategy with correct max age", () => {
|
|
139
|
-
const strategy = getPreloadStrategy();
|
|
140
|
-
|
|
141
|
-
expect(strategy).toHaveProperty("preloadMaxAge");
|
|
142
|
-
expect(strategy.preloadMaxAge).toBe(30 * 60 * 1000); // 30 minutes in milliseconds
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
it("should return consistent strategy object", () => {
|
|
146
|
-
const strategy1 = getPreloadStrategy();
|
|
147
|
-
const strategy2 = getPreloadStrategy();
|
|
148
|
-
|
|
149
|
-
expect(strategy1).toEqual(strategy2);
|
|
150
|
-
expect(strategy1.preloadMaxAge).toBe(30 * 60 * 1000);
|
|
151
|
-
});
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
describe("preload", () => {
|
|
155
|
-
it("should return empty object", async () => {
|
|
156
|
-
const result = await preload();
|
|
157
|
-
expect(result).toEqual({});
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
it("should log preload message", async () => {
|
|
161
|
-
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
162
|
-
const { log } = require("@ledgerhq/logs");
|
|
163
|
-
|
|
164
|
-
await preload();
|
|
165
|
-
|
|
166
|
-
expect(log).toHaveBeenCalledWith("sui/preload", "preloading sui data...");
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
it("should always return the same result", async () => {
|
|
170
|
-
const result1 = await preload();
|
|
171
|
-
const result2 = await preload();
|
|
172
|
-
|
|
173
|
-
expect(result1).toEqual(result2);
|
|
174
|
-
expect(result1).toEqual({});
|
|
175
|
-
});
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
describe("hydrate", () => {
|
|
179
|
-
it("should set preload data with hydrated data", () => {
|
|
180
|
-
const testData: SuiPreloadData = { hydrate: "test" };
|
|
181
|
-
|
|
182
|
-
hydrate(testData);
|
|
183
|
-
|
|
184
|
-
const currentData = getCurrentSuiPreloadData();
|
|
185
|
-
expect(currentData).toEqual({}); // fromHydratePreloadData returns empty object
|
|
186
|
-
});
|
|
187
|
-
|
|
188
|
-
it("should emit update when hydrated", done => {
|
|
189
|
-
const testData: SuiPreloadData = { hydrate: "test" };
|
|
190
|
-
const updates = getSuiPreloadDataUpdates();
|
|
191
|
-
|
|
192
|
-
updates.pipe(take(1)).subscribe(data => {
|
|
193
|
-
expect(data).toEqual({}); // fromHydratePreloadData returns empty object
|
|
194
|
-
done();
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
hydrate(testData);
|
|
198
|
-
});
|
|
199
|
-
|
|
200
|
-
it("should handle empty data", () => {
|
|
201
|
-
const emptyData: SuiPreloadData = {};
|
|
202
|
-
|
|
203
|
-
hydrate(emptyData);
|
|
204
|
-
|
|
205
|
-
const currentData = getCurrentSuiPreloadData();
|
|
206
|
-
expect(currentData).toEqual({});
|
|
207
|
-
});
|
|
208
|
-
|
|
209
|
-
it("should handle complex data structures", () => {
|
|
210
|
-
const complexData: SuiPreloadData = {
|
|
211
|
-
nested: { key: "value" },
|
|
212
|
-
array: [1, 2, 3],
|
|
213
|
-
boolean: true,
|
|
214
|
-
number: 42,
|
|
215
|
-
};
|
|
216
|
-
|
|
217
|
-
hydrate(complexData);
|
|
218
|
-
|
|
219
|
-
const currentData = getCurrentSuiPreloadData();
|
|
220
|
-
expect(currentData).toEqual({}); // fromHydratePreloadData returns empty object
|
|
221
|
-
});
|
|
222
|
-
});
|
|
223
|
-
|
|
224
|
-
describe("Integration Tests", () => {
|
|
225
|
-
it("should maintain data consistency across multiple operations", () => {
|
|
226
|
-
const testData: SuiPreloadData = { integration: "test" };
|
|
227
|
-
|
|
228
|
-
// Set data
|
|
229
|
-
setSuiPreloadData(testData);
|
|
230
|
-
expect(getCurrentSuiPreloadData()).toEqual(testData);
|
|
231
|
-
|
|
232
|
-
// Hydrate should override
|
|
233
|
-
hydrate({ different: "data" });
|
|
234
|
-
expect(getCurrentSuiPreloadData()).toEqual({});
|
|
235
|
-
|
|
236
|
-
// Set again
|
|
237
|
-
setSuiPreloadData(testData);
|
|
238
|
-
expect(getCurrentSuiPreloadData()).toEqual(testData);
|
|
239
|
-
});
|
|
240
|
-
|
|
241
|
-
it("should handle rapid successive updates", done => {
|
|
242
|
-
const updates = getSuiPreloadDataUpdates();
|
|
243
|
-
const results: SuiPreloadData[] = [];
|
|
50
|
+
describe("getPreloadStrategy", () => {
|
|
51
|
+
it("should return preload strategy with correct max age", () => {
|
|
52
|
+
const strategy = getPreloadStrategy();
|
|
244
53
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
if (results.length === 3) {
|
|
248
|
-
expect(results).toEqual([{ first: "update" }, { second: "update" }, { third: "update" }]);
|
|
249
|
-
done();
|
|
250
|
-
}
|
|
54
|
+
expect(strategy).toHaveProperty("preloadMaxAge");
|
|
55
|
+
expect(strategy.preloadMaxAge).toBe(30 * 60 * 1000); // 30 minutes in milliseconds
|
|
251
56
|
});
|
|
252
57
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
});
|
|
257
|
-
|
|
258
|
-
it("should work with preload strategy", async () => {
|
|
259
|
-
const strategy = getPreloadStrategy();
|
|
260
|
-
const preloadResult = await preload();
|
|
261
|
-
|
|
262
|
-
expect(strategy.preloadMaxAge).toBe(30 * 60 * 1000);
|
|
263
|
-
expect(preloadResult).toEqual({});
|
|
264
|
-
|
|
265
|
-
// Preload should not affect current data
|
|
266
|
-
expect(getCurrentSuiPreloadData()).toEqual({});
|
|
267
|
-
});
|
|
268
|
-
});
|
|
269
|
-
|
|
270
|
-
describe("Edge Cases", () => {
|
|
271
|
-
it("should handle null data gracefully", () => {
|
|
272
|
-
// TypeScript would prevent this, but testing runtime behavior
|
|
273
|
-
const nullData = null as any;
|
|
274
|
-
|
|
275
|
-
expect(() => {
|
|
276
|
-
setSuiPreloadData(nullData);
|
|
277
|
-
}).not.toThrow();
|
|
278
|
-
});
|
|
279
|
-
|
|
280
|
-
it("should handle undefined data gracefully", () => {
|
|
281
|
-
// TypeScript would prevent this, but testing runtime behavior
|
|
282
|
-
const undefinedData = undefined as any;
|
|
283
|
-
|
|
284
|
-
expect(() => {
|
|
285
|
-
setSuiPreloadData(undefinedData);
|
|
286
|
-
}).not.toThrow();
|
|
287
|
-
});
|
|
288
|
-
|
|
289
|
-
it("should handle multiple subscribers", done => {
|
|
290
|
-
const updates1 = getSuiPreloadDataUpdates();
|
|
291
|
-
const updates2 = getSuiPreloadDataUpdates();
|
|
292
|
-
|
|
293
|
-
let subscriber1Called = false;
|
|
294
|
-
let subscriber2Called = false;
|
|
58
|
+
it("should return consistent strategy object", () => {
|
|
59
|
+
const strategy1 = getPreloadStrategy();
|
|
60
|
+
const strategy2 = getPreloadStrategy();
|
|
295
61
|
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
if (subscriber1Called && subscriber2Called) {
|
|
299
|
-
done();
|
|
300
|
-
}
|
|
62
|
+
expect(strategy1).toEqual(strategy2);
|
|
63
|
+
expect(strategy1.preloadMaxAge).toBe(30 * 60 * 1000);
|
|
301
64
|
});
|
|
302
|
-
|
|
303
|
-
updates2.pipe(take(1)).subscribe(() => {
|
|
304
|
-
subscriber2Called = true;
|
|
305
|
-
if (subscriber1Called && subscriber2Called) {
|
|
306
|
-
done();
|
|
307
|
-
}
|
|
308
|
-
});
|
|
309
|
-
|
|
310
|
-
setSuiPreloadData({ multi: "subscriber" });
|
|
311
|
-
});
|
|
312
|
-
|
|
313
|
-
it("should handle unsubscribe scenarios", done => {
|
|
314
|
-
const updates = getSuiPreloadDataUpdates();
|
|
315
|
-
let callCount = 0;
|
|
316
|
-
|
|
317
|
-
const subscription = updates.subscribe(() => {
|
|
318
|
-
callCount++;
|
|
319
|
-
});
|
|
320
|
-
|
|
321
|
-
setSuiPreloadData({ first: "update" });
|
|
322
|
-
|
|
323
|
-
subscription.unsubscribe();
|
|
324
|
-
|
|
325
|
-
setSuiPreloadData({ second: "update" });
|
|
326
|
-
|
|
327
|
-
setTimeout(() => {
|
|
328
|
-
expect(callCount).toBe(1); // Should only receive first update
|
|
329
|
-
done();
|
|
330
|
-
}, 10);
|
|
331
65
|
});
|
|
332
66
|
});
|
|
333
67
|
});
|
package/src/bridge/preload.ts
CHANGED
|
@@ -2,13 +2,14 @@ import { Observable, Subject } from "rxjs";
|
|
|
2
2
|
import { log } from "@ledgerhq/logs";
|
|
3
3
|
|
|
4
4
|
import type { SuiPreloadData } from "../types";
|
|
5
|
+
import { getValidators } from "../network/sdk";
|
|
5
6
|
|
|
6
7
|
const PRELOAD_MAX_AGE = 30 * 60 * 1000; // 30 minutes
|
|
7
8
|
|
|
8
|
-
let currentPreloadedData: SuiPreloadData = {};
|
|
9
|
+
let currentPreloadedData: SuiPreloadData = { validators: [] };
|
|
9
10
|
|
|
10
11
|
function fromHydratePreloadData(_data: SuiPreloadData): SuiPreloadData {
|
|
11
|
-
return {};
|
|
12
|
+
return { validators: _data.validators };
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
const updates = new Subject<SuiPreloadData>();
|
|
@@ -34,9 +35,10 @@ export const getPreloadStrategy = () => ({
|
|
|
34
35
|
});
|
|
35
36
|
|
|
36
37
|
export const preload = async (): Promise<SuiPreloadData> => {
|
|
38
|
+
const validators = await getValidators();
|
|
37
39
|
log("sui/preload", "preloading sui data...");
|
|
38
40
|
|
|
39
|
-
return {};
|
|
41
|
+
return { validators };
|
|
40
42
|
};
|
|
41
43
|
|
|
42
44
|
export const hydrate = (data: SuiPreloadData) => {
|
|
@@ -35,7 +35,7 @@ export const prepareTransaction: AccountBridge<
|
|
|
35
35
|
fees = BigNumber(0);
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
let mode: SuiTransactionMode = "send";
|
|
38
|
+
let mode: SuiTransactionMode = transaction.mode ?? "send";
|
|
39
39
|
let coinType = DEFAULT_COIN_TYPE;
|
|
40
40
|
if (transaction?.subAccountId) {
|
|
41
41
|
mode = "token.send";
|