@ledgerhq/live-common 25.0.0-next.3 → 25.0.0-next.6
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/lib/apps/support.d.ts.map +1 -1
- package/lib/apps/support.js +2 -1
- package/lib/apps/support.js.map +1 -1
- package/lib/families/cardano/bridge.integration.test.d.ts.map +1 -1
- package/lib/families/cardano/bridge.integration.test.js +36 -2
- package/lib/families/cardano/bridge.integration.test.js.map +1 -1
- package/lib/families/cardano/buildSubAccounts.d.ts.map +1 -1
- package/lib/families/cardano/buildSubAccounts.js +5 -3
- package/lib/families/cardano/buildSubAccounts.js.map +1 -1
- package/lib/families/cardano/deviceTransactionConfig.d.ts +11 -0
- package/lib/families/cardano/deviceTransactionConfig.d.ts.map +1 -0
- package/lib/families/cardano/deviceTransactionConfig.js +91 -0
- package/lib/families/cardano/deviceTransactionConfig.js.map +1 -0
- package/lib/families/cardano/errors.d.ts +4 -0
- package/lib/families/cardano/errors.d.ts.map +1 -1
- package/lib/families/cardano/errors.js +5 -1
- package/lib/families/cardano/errors.js.map +1 -1
- package/lib/families/cardano/js-estimateMaxSpendable.d.ts.map +1 -1
- package/lib/families/cardano/js-estimateMaxSpendable.js +3 -2
- package/lib/families/cardano/js-estimateMaxSpendable.js.map +1 -1
- package/lib/families/cardano/js-getTransactionStatus.d.ts.map +1 -1
- package/lib/families/cardano/js-getTransactionStatus.js +6 -5
- package/lib/families/cardano/js-getTransactionStatus.js.map +1 -1
- package/lib/families/cardano/js-signOperation.d.ts.map +1 -1
- package/lib/families/cardano/js-signOperation.js +10 -5
- package/lib/families/cardano/js-signOperation.js.map +1 -1
- package/lib/families/cardano/js-synchronisation.d.ts.map +1 -1
- package/lib/families/cardano/js-synchronisation.js +126 -98
- package/lib/families/cardano/js-synchronisation.js.map +1 -1
- package/lib/families/cardano/js-transaction.js +1 -1
- package/lib/families/cardano/js-transaction.js.map +1 -1
- package/lib/families/cardano/logic.d.ts +1 -0
- package/lib/families/cardano/logic.d.ts.map +1 -1
- package/lib/families/cardano/logic.js +11 -1
- package/lib/families/cardano/logic.js.map +1 -1
- package/lib/families/cardano/specs.d.ts.map +1 -1
- package/lib/families/cardano/specs.js +39 -1
- package/lib/families/cardano/specs.js.map +1 -1
- package/lib/families/cardano/speculos-deviceActions.d.ts.map +1 -1
- package/lib/families/cardano/speculos-deviceActions.js +15 -0
- package/lib/families/cardano/speculos-deviceActions.js.map +1 -1
- package/lib/families/cosmos/react.d.ts +1 -1
- package/lib/families/cosmos/react.d.ts.map +1 -1
- package/lib/families/cosmos/react.js +9 -4
- package/lib/families/cosmos/react.js.map +1 -1
- package/lib/families/hedera/api/mirror.js +1 -1
- package/lib/families/hedera/api/mirror.js.map +1 -1
- package/lib/families/hedera/api/network.d.ts.map +1 -1
- package/lib/families/hedera/api/network.js +3 -1
- package/lib/families/hedera/api/network.js.map +1 -1
- package/lib/families/hedera/deviceTransactionConfig.d.ts.map +1 -1
- package/lib/families/hedera/deviceTransactionConfig.js +7 -0
- package/lib/families/hedera/deviceTransactionConfig.js.map +1 -1
- package/lib/families/hedera/js-synchronisation.d.ts.map +1 -1
- package/lib/families/hedera/js-synchronisation.js +10 -7
- package/lib/families/hedera/js-synchronisation.js.map +1 -1
- package/lib/families/hedera/specs.d.ts.map +1 -1
- package/lib/families/hedera/specs.js +23 -0
- package/lib/families/hedera/specs.js.map +1 -1
- package/lib/families/hedera/speculos-deviceActions.d.ts.map +1 -1
- package/lib/families/hedera/speculos-deviceActions.js +5 -1
- package/lib/families/hedera/speculos-deviceActions.js.map +1 -1
- package/lib/families/hedera/transaction.d.ts.map +1 -1
- package/lib/families/hedera/transaction.js +2 -2
- package/lib/families/hedera/transaction.js.map +1 -1
- package/lib/families/hedera/types.d.ts +2 -5
- package/lib/families/hedera/types.d.ts.map +1 -1
- package/lib/families/hedera/types.js +0 -4
- package/lib/families/hedera/types.js.map +1 -1
- package/lib/families/hedera/utils.d.ts.map +1 -1
- package/lib/families/solana/react.d.ts +2 -1
- package/lib/families/solana/react.d.ts.map +1 -1
- package/lib/families/solana/react.integration.test.d.ts +2 -0
- package/lib/families/solana/react.integration.test.d.ts.map +1 -0
- package/lib/families/solana/react.integration.test.js +142 -0
- package/lib/families/solana/react.integration.test.js.map +1 -0
- package/lib/families/solana/react.js +21 -3
- package/lib/families/solana/react.js.map +1 -1
- package/lib/featureFlags/types.d.ts +1 -1
- package/lib/featureFlags/types.d.ts.map +1 -1
- package/lib/generated/deviceTransactionConfig.d.ts +2 -0
- package/lib/generated/deviceTransactionConfig.d.ts.map +1 -1
- package/lib/generated/deviceTransactionConfig.js +28 -26
- package/lib/generated/deviceTransactionConfig.js.map +1 -1
- package/package.json +3 -3
- package/src/apps/support.ts +1 -0
- package/src/currencies/__snapshots__/sortByMarketcap.test.ts.snap +101 -0
- package/src/families/cardano/__snapshots__/bridge.integration.test.ts.snap +41 -1
- package/src/families/cardano/bridge.integration.test.ts +38 -0
- package/src/families/cardano/buildSubAccounts.ts +5 -3
- package/src/families/cardano/deviceTransactionConfig.ts +109 -0
- package/src/families/cardano/errors.ts +7 -0
- package/src/families/cardano/js-estimateMaxSpendable.ts +4 -1
- package/src/families/cardano/js-getTransactionStatus.ts +7 -7
- package/src/families/cardano/js-signOperation.ts +10 -5
- package/src/families/cardano/js-synchronisation.ts +52 -21
- package/src/families/cardano/js-transaction.ts +1 -1
- package/src/families/cardano/logic.ts +10 -0
- package/src/families/cardano/specs.ts +53 -1
- package/src/families/cardano/speculos-deviceActions.ts +15 -0
- package/src/families/cosmos/react.ts +12 -4
- package/src/families/hedera/api/mirror.ts +1 -1
- package/src/families/hedera/api/network.ts +1 -0
- package/src/families/hedera/deviceTransactionConfig.ts +8 -0
- package/src/families/hedera/js-synchronisation.ts +5 -3
- package/src/families/hedera/specs.ts +56 -5
- package/src/families/hedera/speculos-deviceActions.ts +1 -0
- package/src/families/hedera/transaction.ts +2 -0
- package/src/families/hedera/types.ts +2 -8
- package/src/families/hedera/utils.ts +1 -1
- package/src/families/solana/react.integration.test.ts +76 -0
- package/src/families/solana/react.ts +28 -3
- package/src/featureFlags/types.ts +1 -0
- package/src/generated/deviceTransactionConfig.ts +3 -0
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
getMemoFromTx,
|
|
22
22
|
getOperationType,
|
|
23
23
|
isHexString,
|
|
24
|
+
mergeTokens,
|
|
24
25
|
} from "./logic";
|
|
25
26
|
import { encodeOperationId } from "../../operation";
|
|
26
27
|
import { getNetworkParameters } from "./networks";
|
|
@@ -28,6 +29,9 @@ import { getNetworkInfo } from "./api/getNetworkInfo";
|
|
|
28
29
|
import uniqBy from "lodash/uniqBy";
|
|
29
30
|
import postSyncPatch from "./postSyncPatch";
|
|
30
31
|
import { getTransactions } from "./api/getTransactions";
|
|
32
|
+
import { buildSubAccounts } from "./buildSubAccounts";
|
|
33
|
+
import { calculateMinUtxoAmount } from "@stricahq/typhonjs/dist/utils/utils";
|
|
34
|
+
import { listTokensForCryptoCurrency } from "../../currencies";
|
|
31
35
|
|
|
32
36
|
function mapTxToAccountOperation(
|
|
33
37
|
tx: APITransaction,
|
|
@@ -43,6 +47,10 @@ function mapTxToAccountOperation(
|
|
|
43
47
|
|
|
44
48
|
const subOperations = inferSubOperations(tx.hash, subAccounts);
|
|
45
49
|
const memo = getMemoFromTx(tx);
|
|
50
|
+
const extra = {};
|
|
51
|
+
if (memo) {
|
|
52
|
+
extra["memo"] = memo;
|
|
53
|
+
}
|
|
46
54
|
|
|
47
55
|
return {
|
|
48
56
|
accountId,
|
|
@@ -64,14 +72,12 @@ function mapTxToAccountOperation(
|
|
|
64
72
|
subOperations,
|
|
65
73
|
blockHeight: tx.blockHeight,
|
|
66
74
|
date: new Date(tx.timestamp),
|
|
67
|
-
extra:
|
|
68
|
-
memo,
|
|
69
|
-
},
|
|
75
|
+
extra: extra,
|
|
70
76
|
blockHash: undefined,
|
|
71
77
|
};
|
|
72
78
|
}
|
|
73
79
|
|
|
74
|
-
function
|
|
80
|
+
function prepareUtxos(
|
|
75
81
|
newTransactions: Array<APITransaction>,
|
|
76
82
|
stableUtxos: Array<CardanoOutput>,
|
|
77
83
|
accountCredentialsMap: Record<string, PaymentCredential>
|
|
@@ -116,7 +122,10 @@ function syncUtxos(
|
|
|
116
122
|
return utxos;
|
|
117
123
|
}
|
|
118
124
|
|
|
119
|
-
export const getAccountShape: GetAccountShape = async (
|
|
125
|
+
export const getAccountShape: GetAccountShape = async (
|
|
126
|
+
info,
|
|
127
|
+
{ blacklistedTokenIds }
|
|
128
|
+
) => {
|
|
120
129
|
const {
|
|
121
130
|
transport,
|
|
122
131
|
currency,
|
|
@@ -152,16 +161,27 @@ export const getAccountShape: GetAccountShape = async (info) => {
|
|
|
152
161
|
derivationMode,
|
|
153
162
|
});
|
|
154
163
|
|
|
164
|
+
// when new tokens are added / blacklist changes, we need to sync again because we need to go through all operations again
|
|
165
|
+
const syncHash =
|
|
166
|
+
JSON.stringify(blacklistedTokenIds || []) +
|
|
167
|
+
"_" +
|
|
168
|
+
listTokensForCryptoCurrency(currency, {
|
|
169
|
+
withDelisted: true,
|
|
170
|
+
}).length;
|
|
171
|
+
const outdatedSyncHash = initialAccount?.syncHash !== syncHash;
|
|
172
|
+
|
|
155
173
|
const requiredConfirmations = 90;
|
|
156
174
|
|
|
157
175
|
const oldOperations = initialAccount?.operations || [];
|
|
158
176
|
const lastBlockHeight = oldOperations.length
|
|
159
177
|
? (oldOperations[0].blockHeight || 0) + 1
|
|
160
178
|
: 0;
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
179
|
+
|
|
180
|
+
const syncFromBlockHeight = outdatedSyncHash
|
|
181
|
+
? 0
|
|
182
|
+
: lastBlockHeight > requiredConfirmations
|
|
183
|
+
? lastBlockHeight - requiredConfirmations
|
|
184
|
+
: 0;
|
|
165
185
|
|
|
166
186
|
const {
|
|
167
187
|
transactions: newTransactions,
|
|
@@ -195,21 +215,24 @@ export const getAccountShape: GetAccountShape = async (info) => {
|
|
|
195
215
|
(u) => stableOperationsByIds[u.hash]
|
|
196
216
|
);
|
|
197
217
|
|
|
198
|
-
const utxos =
|
|
218
|
+
const utxos = prepareUtxos(
|
|
219
|
+
newTransactions,
|
|
220
|
+
stableUtxos,
|
|
221
|
+
accountCredentialsMap
|
|
222
|
+
);
|
|
199
223
|
const accountBalance = utxos.reduce(
|
|
200
224
|
(total, u) => total.plus(u.amount),
|
|
201
225
|
new BigNumber(0)
|
|
202
226
|
);
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
const subAccounts = [];
|
|
227
|
+
const tokenBalance = mergeTokens(utxos.map((u) => u.tokens).flat());
|
|
228
|
+
const subAccounts = buildSubAccounts({
|
|
229
|
+
initialAccount,
|
|
230
|
+
parentAccountId: accountId,
|
|
231
|
+
parentCurrency: currency,
|
|
232
|
+
newTransactions,
|
|
233
|
+
tokens: tokenBalance,
|
|
234
|
+
accountCredentialsMap,
|
|
235
|
+
});
|
|
213
236
|
|
|
214
237
|
const newOperations = newTransactions.map((t) =>
|
|
215
238
|
mapTxToAccountOperation(t, accountId, accountCredentialsMap, subAccounts)
|
|
@@ -233,13 +256,21 @@ export const getAccountShape: GetAccountShape = async (info) => {
|
|
|
233
256
|
}).getBech32(),
|
|
234
257
|
}));
|
|
235
258
|
const cardanoNetworkInfo = await getNetworkInfo(initialAccount, currency);
|
|
259
|
+
const minAdaBalanceForTokens = tokenBalance.length
|
|
260
|
+
? calculateMinUtxoAmount(
|
|
261
|
+
tokenBalance,
|
|
262
|
+
new BigNumber(cardanoNetworkInfo.protocolParams.lovelacePerUtxoWord),
|
|
263
|
+
false
|
|
264
|
+
)
|
|
265
|
+
: new BigNumber(0);
|
|
236
266
|
|
|
237
267
|
return {
|
|
238
268
|
id: accountId,
|
|
239
269
|
xpub,
|
|
240
270
|
balance: accountBalance,
|
|
241
|
-
spendableBalance: accountBalance,
|
|
271
|
+
spendableBalance: accountBalance.minus(minAdaBalanceForTokens),
|
|
242
272
|
operations: operations,
|
|
273
|
+
syncHash,
|
|
243
274
|
subAccounts,
|
|
244
275
|
freshAddresses,
|
|
245
276
|
freshAddress: freshAddresses[0].address,
|
|
@@ -47,7 +47,7 @@ export const prepareTransaction = async (
|
|
|
47
47
|
try {
|
|
48
48
|
transaction = await buildTransaction(a, t);
|
|
49
49
|
} catch (error) {
|
|
50
|
-
return { ...t, fees: new BigNumber(0), amount:
|
|
50
|
+
return { ...t, fees: new BigNumber(0), amount: t.amount };
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
const transactionFees = transaction.getFee();
|
|
@@ -448,3 +448,13 @@ export function isHexString(value: string): boolean {
|
|
|
448
448
|
const regExp = /^[0-9a-fA-F]+$/;
|
|
449
449
|
return regExp.test(value);
|
|
450
450
|
}
|
|
451
|
+
|
|
452
|
+
export function decodeTokenName(assetName: string): string {
|
|
453
|
+
if (assetName.length > 0) {
|
|
454
|
+
const bytes = [...Buffer.from(assetName, "hex")];
|
|
455
|
+
if (bytes.filter((byte) => byte <= 32 || byte >= 127).length === 0) {
|
|
456
|
+
return String.fromCharCode(...bytes);
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
return assetName;
|
|
460
|
+
}
|
|
@@ -9,10 +9,15 @@ import invariant from "invariant";
|
|
|
9
9
|
import { utils as TyphonUtils } from "@stricahq/typhonjs";
|
|
10
10
|
import { mergeTokens } from "./logic";
|
|
11
11
|
import { parseCurrencyUnit } from "../../currencies";
|
|
12
|
+
import { SubAccount } from "../../types";
|
|
12
13
|
|
|
13
14
|
const currency = getCryptoCurrencyById("cardano");
|
|
14
15
|
const minBalanceRequired = parseCurrencyUnit(currency.units[0], "2.2");
|
|
15
16
|
const minBalanceRequiredForMaxSend = parseCurrencyUnit(currency.units[0], "1");
|
|
17
|
+
const minSpendableRequiredForTokenTx = parseCurrencyUnit(
|
|
18
|
+
currency.units[0],
|
|
19
|
+
"3"
|
|
20
|
+
);
|
|
16
21
|
|
|
17
22
|
const cardano: AppSpec<Transaction> = {
|
|
18
23
|
name: "cardano",
|
|
@@ -34,7 +39,12 @@ const cardano: AppSpec<Transaction> = {
|
|
|
34
39
|
|
|
35
40
|
const updates = [
|
|
36
41
|
{ recipient },
|
|
37
|
-
{
|
|
42
|
+
{
|
|
43
|
+
amount: new BigNumber(account.balance.dividedBy(2)).dp(
|
|
44
|
+
0,
|
|
45
|
+
BigNumber.ROUND_CEIL
|
|
46
|
+
),
|
|
47
|
+
},
|
|
38
48
|
{ memo: "LedgerLiveBot" },
|
|
39
49
|
];
|
|
40
50
|
|
|
@@ -90,6 +100,48 @@ const cardano: AppSpec<Transaction> = {
|
|
|
90
100
|
);
|
|
91
101
|
},
|
|
92
102
|
},
|
|
103
|
+
{
|
|
104
|
+
name: "move ~10% token",
|
|
105
|
+
maxRun: 1,
|
|
106
|
+
transaction: ({ account, siblings, bridge, maxSpendable }) => {
|
|
107
|
+
invariant(
|
|
108
|
+
maxSpendable.gte(minSpendableRequiredForTokenTx),
|
|
109
|
+
"balance is too low"
|
|
110
|
+
);
|
|
111
|
+
const sibling = pickSiblings(siblings, 3);
|
|
112
|
+
const recipient = sibling.freshAddress;
|
|
113
|
+
const transaction = bridge.createTransaction(account);
|
|
114
|
+
|
|
115
|
+
const subAccount = account.subAccounts?.find((subAccount) =>
|
|
116
|
+
subAccount.balance.gt(1)
|
|
117
|
+
) as SubAccount;
|
|
118
|
+
invariant(subAccount, "No token account with balance");
|
|
119
|
+
|
|
120
|
+
const updates = [
|
|
121
|
+
{ subAccountId: subAccount.id },
|
|
122
|
+
{ recipient },
|
|
123
|
+
{
|
|
124
|
+
amount: new BigNumber(subAccount.balance.dividedBy(10)).dp(
|
|
125
|
+
0,
|
|
126
|
+
BigNumber.ROUND_CEIL
|
|
127
|
+
),
|
|
128
|
+
},
|
|
129
|
+
];
|
|
130
|
+
|
|
131
|
+
return {
|
|
132
|
+
transaction,
|
|
133
|
+
updates,
|
|
134
|
+
};
|
|
135
|
+
},
|
|
136
|
+
test: ({ operation, transaction }): void => {
|
|
137
|
+
expect(operation.subOperations).toBeTruthy();
|
|
138
|
+
expect(operation.subOperations?.length).toEqual(1);
|
|
139
|
+
|
|
140
|
+
const subOperation =
|
|
141
|
+
operation.subOperations && operation.subOperations[0];
|
|
142
|
+
expect(subOperation?.value).toEqual(transaction.amount);
|
|
143
|
+
},
|
|
144
|
+
},
|
|
93
145
|
],
|
|
94
146
|
};
|
|
95
147
|
|
|
@@ -39,6 +39,21 @@ const acceptTransaction: DeviceAction<Transaction, any> = deviceActionFlow({
|
|
|
39
39
|
expectedValue: ({ account, status }) =>
|
|
40
40
|
expectedValue(account.unit, status.amount),
|
|
41
41
|
},
|
|
42
|
+
{
|
|
43
|
+
title: "Asset fingerprint",
|
|
44
|
+
button: "LRlr",
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
title: "Token amount",
|
|
48
|
+
button: "LRlr",
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
title: "Confirm",
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
title: "output?",
|
|
55
|
+
button: "Rr",
|
|
56
|
+
},
|
|
42
57
|
{
|
|
43
58
|
title: "Transaction fee",
|
|
44
59
|
button: "LRlr",
|
|
@@ -165,19 +165,27 @@ export function useMappedExtraOperationDetails({
|
|
|
165
165
|
};
|
|
166
166
|
}
|
|
167
167
|
|
|
168
|
-
export function useLedgerFirstShuffledValidatorsCosmos(
|
|
168
|
+
export function useLedgerFirstShuffledValidatorsCosmos(
|
|
169
|
+
searchInput?: string
|
|
170
|
+
): CosmosValidatorItem[] {
|
|
169
171
|
const data = useCosmosPreloadData();
|
|
170
172
|
|
|
171
173
|
return useMemo(() => {
|
|
172
|
-
return reorderValidators(data?.validators ?? []);
|
|
173
|
-
}, [data]);
|
|
174
|
+
return reorderValidators(data?.validators ?? [], searchInput);
|
|
175
|
+
}, [data, searchInput]);
|
|
174
176
|
}
|
|
175
177
|
|
|
176
178
|
function reorderValidators(
|
|
177
|
-
validators: CosmosValidatorItem[]
|
|
179
|
+
validators: CosmosValidatorItem[],
|
|
180
|
+
searchInput?: string
|
|
178
181
|
): CosmosValidatorItem[] {
|
|
179
182
|
const sortedValidators = validators
|
|
180
183
|
.filter((validator) => validator.commission !== 1.0)
|
|
184
|
+
.filter((validator) =>
|
|
185
|
+
searchInput
|
|
186
|
+
? validator.name.toLowerCase().includes(searchInput.toLowerCase())
|
|
187
|
+
: true
|
|
188
|
+
)
|
|
181
189
|
.sort((a, b) => b.votingPower - a.votingPower);
|
|
182
190
|
|
|
183
191
|
// move Ledger validator to the first position
|
|
@@ -136,7 +136,7 @@ export async function getOperationsForAccount(
|
|
|
136
136
|
// Set a value just so that it's considered confirmed according to isConfirmedOperation
|
|
137
137
|
blockHeight: 5,
|
|
138
138
|
blockHash: null,
|
|
139
|
-
extra: {
|
|
139
|
+
extra: {},
|
|
140
140
|
fee,
|
|
141
141
|
hash,
|
|
142
142
|
recipients,
|
|
@@ -23,6 +23,7 @@ export async function buildUnsignedTransaction({
|
|
|
23
23
|
return new hedera.TransferTransaction()
|
|
24
24
|
.setNodeAccountIds([new AccountId(3)])
|
|
25
25
|
.setTransactionId(hedera.TransactionId.generate(accountId))
|
|
26
|
+
.setTransactionMemo(transaction.memo ?? "")
|
|
26
27
|
.addHbarTransfer(accountId, hbarAmount.negated())
|
|
27
28
|
.addHbarTransfer(transaction.recipient, hbarAmount)
|
|
28
29
|
.freeze();
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import invariant from "invariant";
|
|
2
|
+
import { BigNumber } from "bignumber.js";
|
|
2
3
|
import { Account, getDerivationScheme, runDerivationScheme } from "../../types";
|
|
3
4
|
import type {
|
|
4
5
|
GetAccountShape,
|
|
@@ -31,14 +32,15 @@ const getAccountShape: GetAccountShape = async (
|
|
|
31
32
|
|
|
32
33
|
// grab latest operation's consensus timestamp for incremental sync
|
|
33
34
|
const oldOperations = initialAccount?.operations ?? [];
|
|
34
|
-
const latestOperationTimestamp =
|
|
35
|
-
oldOperations[0]
|
|
35
|
+
const latestOperationTimestamp = oldOperations[0]
|
|
36
|
+
? Math.floor(oldOperations[0].date.getTime() / 1000)
|
|
37
|
+
: 0;
|
|
36
38
|
|
|
37
39
|
// merge new operations w/ previously synced ones
|
|
38
40
|
const newOperations = await getOperationsForAccount(
|
|
39
41
|
liveAccountId,
|
|
40
42
|
address,
|
|
41
|
-
latestOperationTimestamp
|
|
43
|
+
new BigNumber(latestOperationTimestamp).toString()
|
|
42
44
|
);
|
|
43
45
|
const operations = mergeOps(oldOperations, newOperations);
|
|
44
46
|
|
|
@@ -2,12 +2,18 @@ import expect from "expect";
|
|
|
2
2
|
import invariant from "invariant";
|
|
3
3
|
import { getCryptoCurrencyById, parseCurrencyUnit } from "../../currencies";
|
|
4
4
|
import { DeviceModelId } from "@ledgerhq/devices";
|
|
5
|
-
import type {
|
|
5
|
+
import type {
|
|
6
|
+
AppSpec,
|
|
7
|
+
TransactionTestInput,
|
|
8
|
+
TransactionArg,
|
|
9
|
+
TransactionRes,
|
|
10
|
+
} from "../../bot/types";
|
|
6
11
|
import type { Transaction } from "./types";
|
|
7
12
|
import { pickSiblings } from "../../bot/specs";
|
|
8
13
|
import { isAccountEmpty } from "../../account";
|
|
9
14
|
|
|
10
15
|
const currency = getCryptoCurrencyById("hedera");
|
|
16
|
+
const memoTestMessage = "This is a test memo.";
|
|
11
17
|
|
|
12
18
|
// Ensure that, when the recipient corresponds to an empty account,
|
|
13
19
|
// the amount to send is greater or equal to the required minimum
|
|
@@ -41,7 +47,11 @@ const hedera: AppSpec<Transaction> = {
|
|
|
41
47
|
{
|
|
42
48
|
name: "Send ~50%",
|
|
43
49
|
maxRun: 2,
|
|
44
|
-
transaction: ({
|
|
50
|
+
transaction: ({
|
|
51
|
+
account,
|
|
52
|
+
siblings,
|
|
53
|
+
bridge,
|
|
54
|
+
}: TransactionArg<Transaction>): TransactionRes<Transaction> => {
|
|
45
55
|
const sibling = pickSiblings(siblings, 4);
|
|
46
56
|
const recipient = sibling.freshAddress;
|
|
47
57
|
|
|
@@ -58,7 +68,11 @@ const hedera: AppSpec<Transaction> = {
|
|
|
58
68
|
updates: [{ amount }, { recipient }],
|
|
59
69
|
};
|
|
60
70
|
},
|
|
61
|
-
test: ({
|
|
71
|
+
test: ({
|
|
72
|
+
account,
|
|
73
|
+
accountBeforeTransaction,
|
|
74
|
+
operation,
|
|
75
|
+
}: TransactionTestInput<Transaction>): void => {
|
|
62
76
|
expect(account.balance.toString()).toBe(
|
|
63
77
|
accountBeforeTransaction.balance.minus(operation.value).toString()
|
|
64
78
|
);
|
|
@@ -67,7 +81,11 @@ const hedera: AppSpec<Transaction> = {
|
|
|
67
81
|
{
|
|
68
82
|
name: "Send max",
|
|
69
83
|
maxRun: 2,
|
|
70
|
-
transaction: ({
|
|
84
|
+
transaction: ({
|
|
85
|
+
account,
|
|
86
|
+
siblings,
|
|
87
|
+
bridge,
|
|
88
|
+
}: TransactionArg<Transaction>): TransactionRes<Transaction> => {
|
|
71
89
|
const sibling = pickSiblings(siblings, 4);
|
|
72
90
|
const recipient = sibling.freshAddress;
|
|
73
91
|
|
|
@@ -78,7 +96,12 @@ const hedera: AppSpec<Transaction> = {
|
|
|
78
96
|
updates: [{ recipient }, { useAllAmount: true }],
|
|
79
97
|
};
|
|
80
98
|
},
|
|
81
|
-
test: ({
|
|
99
|
+
test: ({
|
|
100
|
+
accountBeforeTransaction,
|
|
101
|
+
account,
|
|
102
|
+
operation,
|
|
103
|
+
transaction,
|
|
104
|
+
}: TransactionTestInput<Transaction>): void => {
|
|
82
105
|
const accountBalanceAfterTx = account.balance.toNumber();
|
|
83
106
|
|
|
84
107
|
// NOTE: operation.fee is the ACTUAL (not estimated) fee cost of the transaction
|
|
@@ -89,6 +112,34 @@ const hedera: AppSpec<Transaction> = {
|
|
|
89
112
|
expect(accountBalanceAfterTx).toBe(amount);
|
|
90
113
|
},
|
|
91
114
|
},
|
|
115
|
+
{
|
|
116
|
+
name: "Memo",
|
|
117
|
+
maxRun: 2,
|
|
118
|
+
transaction: ({
|
|
119
|
+
account,
|
|
120
|
+
siblings,
|
|
121
|
+
bridge,
|
|
122
|
+
}: TransactionArg<Transaction>): TransactionRes<Transaction> => {
|
|
123
|
+
const sibling = pickSiblings(siblings, 4);
|
|
124
|
+
const recipient = sibling.freshAddress;
|
|
125
|
+
|
|
126
|
+
const transaction = bridge.createTransaction(account);
|
|
127
|
+
|
|
128
|
+
const amount = account.balance
|
|
129
|
+
.div(1.9 + 0.2 * Math.random())
|
|
130
|
+
.integerValue();
|
|
131
|
+
|
|
132
|
+
checkSendableToEmptyAccount(amount, sibling);
|
|
133
|
+
|
|
134
|
+
return {
|
|
135
|
+
transaction,
|
|
136
|
+
updates: [{ recipient }, { amount }, { memo: memoTestMessage }],
|
|
137
|
+
};
|
|
138
|
+
},
|
|
139
|
+
test: ({ transaction }: TransactionTestInput<Transaction>): void => {
|
|
140
|
+
expect(transaction.memo).toBe(memoTestMessage);
|
|
141
|
+
},
|
|
142
|
+
},
|
|
92
143
|
],
|
|
93
144
|
};
|
|
94
145
|
|
|
@@ -29,6 +29,7 @@ export function fromTransactionRaw(tr: TransactionRaw): Transaction {
|
|
|
29
29
|
return {
|
|
30
30
|
...common,
|
|
31
31
|
family: tr.family,
|
|
32
|
+
memo: tr.memo,
|
|
32
33
|
};
|
|
33
34
|
}
|
|
34
35
|
|
|
@@ -38,6 +39,7 @@ export function toTransactionRaw(t: Transaction): TransactionRaw {
|
|
|
38
39
|
return {
|
|
39
40
|
...common,
|
|
40
41
|
family: t.family,
|
|
42
|
+
memo: t.memo,
|
|
41
43
|
};
|
|
42
44
|
}
|
|
43
45
|
|
|
@@ -3,11 +3,6 @@ import type {
|
|
|
3
3
|
TransactionCommonRaw,
|
|
4
4
|
} from "../../types/transaction";
|
|
5
5
|
|
|
6
|
-
export type CoreStatics = Record<string, never>;
|
|
7
|
-
export type CoreAccountSpecifics = Record<string, never>;
|
|
8
|
-
export type CoreOperationSpecifics = Record<string, never>;
|
|
9
|
-
export type CoreCurrencySpecifics = Record<string, never>;
|
|
10
|
-
|
|
11
6
|
export type NetworkInfo = {
|
|
12
7
|
family: "hedera";
|
|
13
8
|
};
|
|
@@ -18,11 +13,10 @@ export type NetworkInfoRaw = {
|
|
|
18
13
|
|
|
19
14
|
export type Transaction = TransactionCommon & {
|
|
20
15
|
family: "hedera";
|
|
16
|
+
memo?: string;
|
|
21
17
|
};
|
|
22
18
|
|
|
23
19
|
export type TransactionRaw = TransactionCommonRaw & {
|
|
24
20
|
family: "hedera";
|
|
21
|
+
memo?: string;
|
|
25
22
|
};
|
|
26
|
-
|
|
27
|
-
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any
|
|
28
|
-
export const reflect = (_declare: any) => {};
|
|
@@ -31,7 +31,7 @@ export async function calculateAmount({
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
// NOTE: convert from the non-url-safe version of base64 to the url-safe version (that the explorer uses)
|
|
34
|
-
export function base64ToUrlSafeBase64(data: string) {
|
|
34
|
+
export function base64ToUrlSafeBase64(data: string): string {
|
|
35
35
|
// Might be nice to use this alternative if .nvmrc changes to >= Node v14.18.0
|
|
36
36
|
// base64url encoding option isn't supported until then
|
|
37
37
|
// Buffer.from(data, "base64").toString("base64url");
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { renderHook } from "@testing-library/react-hooks";
|
|
2
|
+
import { getAccountBridge, getCurrencyBridge } from "../../bridge";
|
|
3
|
+
import { getCryptoCurrencyById } from "../../currencies";
|
|
4
|
+
import { setEnv } from "../../env";
|
|
5
|
+
import { makeBridgeCacheSystem } from "../../bridge/cache";
|
|
6
|
+
import { genAccount, genAddingOperationsInAccount } from "../../mock/account";
|
|
7
|
+
import type { Account, CurrencyBridge } from "../../types";
|
|
8
|
+
import type { Transaction } from "./types";
|
|
9
|
+
import { getCurrentSolanaPreloadData } from "./js-preload-data";
|
|
10
|
+
import { LEDGER_VALIDATOR_ADDRESS } from "./utils";
|
|
11
|
+
import * as hooks from "./react";
|
|
12
|
+
|
|
13
|
+
const localCache = {};
|
|
14
|
+
const cache = makeBridgeCacheSystem({
|
|
15
|
+
saveData(c, d) {
|
|
16
|
+
localCache[c.id] = d;
|
|
17
|
+
return Promise.resolve();
|
|
18
|
+
},
|
|
19
|
+
|
|
20
|
+
getData(c) {
|
|
21
|
+
return Promise.resolve(localCache[c.id]);
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
describe("solana/react", () => {
|
|
25
|
+
describe("useValidators", () => {
|
|
26
|
+
it("should return validators", async () => {
|
|
27
|
+
const { prepare, account } = setup();
|
|
28
|
+
await prepare();
|
|
29
|
+
const { result } = renderHook(() =>
|
|
30
|
+
hooks.useValidators(account.currency)
|
|
31
|
+
);
|
|
32
|
+
const data = getCurrentSolanaPreloadData(account.currency);
|
|
33
|
+
|
|
34
|
+
expect(result.current).toStrictEqual(data.validators);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it("should return validators", async () => {
|
|
38
|
+
const { prepare, account } = setup();
|
|
39
|
+
await prepare();
|
|
40
|
+
const { result } = renderHook(() =>
|
|
41
|
+
hooks.useValidators(account.currency, "Ledger")
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
expect(
|
|
45
|
+
result.current.some(
|
|
46
|
+
(validator) => validator.voteAccount === LEDGER_VALIDATOR_ADDRESS
|
|
47
|
+
)
|
|
48
|
+
).toBe(true);
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
function setup(): {
|
|
54
|
+
account: Account;
|
|
55
|
+
currencyBridge: CurrencyBridge;
|
|
56
|
+
transaction: Transaction;
|
|
57
|
+
prepare: () => Promise<any>;
|
|
58
|
+
} {
|
|
59
|
+
setEnv("MOCK", 1);
|
|
60
|
+
setEnv("EXPERIMENTAL_CURRENCIES", "solana");
|
|
61
|
+
const seed = "solana-2";
|
|
62
|
+
const currency = getCryptoCurrencyById("solana");
|
|
63
|
+
const a = genAccount(seed, {
|
|
64
|
+
currency,
|
|
65
|
+
});
|
|
66
|
+
const account = genAddingOperationsInAccount(a, 3, seed);
|
|
67
|
+
const currencyBridge = getCurrencyBridge(currency);
|
|
68
|
+
const bridge = getAccountBridge(account);
|
|
69
|
+
const transaction = bridge.createTransaction(account);
|
|
70
|
+
return {
|
|
71
|
+
account,
|
|
72
|
+
currencyBridge,
|
|
73
|
+
transaction,
|
|
74
|
+
prepare: async () => cache.prepareCurrency(currency),
|
|
75
|
+
};
|
|
76
|
+
}
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
getSolanaPreloadData,
|
|
7
7
|
} from "./js-preload-data";
|
|
8
8
|
import { SolanaPreloadDataV1, SolanaStake, SolanaStakeWithMeta } from "./types";
|
|
9
|
+
import { ValidatorsAppValidator } from "./validator-app";
|
|
9
10
|
|
|
10
11
|
export function useSolanaPreloadData(
|
|
11
12
|
currency: CryptoCurrency
|
|
@@ -16,12 +17,36 @@ export function useSolanaPreloadData(
|
|
|
16
17
|
);
|
|
17
18
|
}
|
|
18
19
|
|
|
19
|
-
export function useValidators(
|
|
20
|
+
export function useValidators(
|
|
21
|
+
currency: CryptoCurrency,
|
|
22
|
+
search?: string
|
|
23
|
+
): ValidatorsAppValidator[] {
|
|
20
24
|
const data = useSolanaPreloadData(currency);
|
|
21
25
|
|
|
22
26
|
return useMemo(() => {
|
|
23
|
-
|
|
24
|
-
|
|
27
|
+
const validators = data?.validators ?? [];
|
|
28
|
+
|
|
29
|
+
if (validators.length === 0 || !search || search === "") {
|
|
30
|
+
return validators;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const lowercaseSearch = search.toLowerCase();
|
|
34
|
+
|
|
35
|
+
const filtered = validators.filter(
|
|
36
|
+
(validator) =>
|
|
37
|
+
validator.name?.toLowerCase().includes(lowercaseSearch) ||
|
|
38
|
+
validator.voteAccount.toLowerCase().includes(lowercaseSearch)
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
const flags = [];
|
|
42
|
+
const output: ValidatorsAppValidator[] = [];
|
|
43
|
+
for (let i = 0; i < filtered.length; i++) {
|
|
44
|
+
if (flags[filtered[i].voteAccount]) continue;
|
|
45
|
+
flags[filtered[i].voteAccount] = true;
|
|
46
|
+
output.push(filtered[i]);
|
|
47
|
+
}
|
|
48
|
+
return output;
|
|
49
|
+
}, [data, search]);
|
|
25
50
|
}
|
|
26
51
|
|
|
27
52
|
export function useSolanaStakesWithMeta(
|
|
@@ -2,6 +2,8 @@ import algorand from "../families/algorand/deviceTransactionConfig";
|
|
|
2
2
|
|
|
3
3
|
import bitcoin from "../families/bitcoin/deviceTransactionConfig";
|
|
4
4
|
|
|
5
|
+
import cardano from "../families/cardano/deviceTransactionConfig";
|
|
6
|
+
|
|
5
7
|
import celo from "../families/celo/deviceTransactionConfig";
|
|
6
8
|
|
|
7
9
|
import cosmos from "../families/cosmos/deviceTransactionConfig";
|
|
@@ -32,6 +34,7 @@ import tron from "../families/tron/deviceTransactionConfig";
|
|
|
32
34
|
export default {
|
|
33
35
|
algorand,
|
|
34
36
|
bitcoin,
|
|
37
|
+
cardano,
|
|
35
38
|
celo,
|
|
36
39
|
cosmos,
|
|
37
40
|
crypto_org,
|