@ledgerhq/live-common 24.1.0 → 25.0.0-next.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/lib/apps/support.js +1 -1
- package/lib/apps/support.js.map +1 -1
- package/lib/bot/index.d.ts.map +1 -1
- package/lib/bot/index.js +4 -2
- package/lib/bot/index.js.map +1 -1
- package/lib/bot/specs.d.ts +1 -0
- package/lib/bot/specs.d.ts.map +1 -1
- package/lib/bot/specs.js +6 -1
- package/lib/bot/specs.js.map +1 -1
- package/lib/currencies/support.d.ts +1 -1
- package/lib/currencies/support.d.ts.map +1 -1
- package/lib/env.d.ts +15 -5
- package/lib/env.d.ts.map +1 -1
- package/lib/env.js +10 -0
- package/lib/env.js.map +1 -1
- package/lib/env.react.d.ts +1 -1
- package/lib/env.react.d.ts.map +1 -1
- package/lib/errors.d.ts +101 -306
- package/lib/errors.d.ts.map +1 -1
- package/lib/errors.js +3 -4
- package/lib/errors.js.map +1 -1
- package/lib/errors.test.d.ts +2 -0
- package/lib/errors.test.d.ts.map +1 -0
- package/lib/errors.test.js +20 -0
- package/lib/errors.test.js.map +1 -0
- package/lib/exchange/swap/utils/index.test.js +2 -2
- package/lib/exchange/swap/utils/index.test.js.map +1 -1
- package/lib/families/bitcoin/datasets/bitcoin.d.ts.map +1 -1
- package/lib/families/bitcoin/datasets/bitcoin.js +2 -4
- package/lib/families/bitcoin/datasets/bitcoin.js.map +1 -1
- package/lib/families/bitcoin/descriptor.d.ts.map +1 -1
- package/lib/families/bitcoin/descriptor.js +3 -1
- package/lib/families/bitcoin/descriptor.js.map +1 -1
- package/lib/families/bitcoin/errors.d.ts +1 -3
- package/lib/families/bitcoin/errors.d.ts.map +1 -1
- package/lib/families/bitcoin/exchange.js +1 -1
- package/lib/families/bitcoin/exchange.js.map +1 -1
- package/lib/families/bitcoin/hw-getAddress.d.ts +1 -1
- package/lib/families/bitcoin/hw-getAddress.d.ts.map +1 -1
- package/lib/families/bitcoin/js-synchronisation.d.ts.map +1 -1
- package/lib/families/bitcoin/js-synchronisation.js +20 -2
- package/lib/families/bitcoin/js-synchronisation.js.map +1 -1
- package/lib/families/bitcoin/wallet-btc/storage/index.d.ts +0 -36
- package/lib/families/bitcoin/wallet-btc/storage/index.d.ts.map +1 -1
- package/lib/families/bitcoin/wallet-btc/storage/index.js +14 -14
- package/lib/families/bitcoin/wallet-btc/storage/index.js.map +1 -1
- package/lib/families/bitcoin/wallet-btc/storage/types.d.ts +1 -0
- package/lib/families/bitcoin/wallet-btc/storage/types.d.ts.map +1 -1
- package/lib/families/bitcoin/xpub.txs.loadExport.unit.test.d.ts +2 -0
- package/lib/families/bitcoin/xpub.txs.loadExport.unit.test.d.ts.map +1 -0
- package/lib/families/bitcoin/xpub.txs.loadExport.unit.test.js +146 -0
- package/lib/families/bitcoin/xpub.txs.loadExport.unit.test.js.map +1 -0
- package/lib/families/cardano/errors.d.ts +1 -3
- package/lib/families/cardano/errors.d.ts.map +1 -1
- package/lib/families/crypto_org/errors.d.ts +3 -9
- package/lib/families/crypto_org/errors.d.ts.map +1 -1
- package/lib/families/ethereum/exchange.js +1 -1
- package/lib/families/ethereum/exchange.js.map +1 -1
- package/lib/families/ethereum/modules/index.d.ts +1 -1
- package/lib/families/ethereum/modules/index.d.ts.map +1 -1
- package/lib/families/ethereum/signOperation.js +2 -2
- package/lib/families/ethereum/signOperation.js.map +1 -1
- package/lib/families/ethereum/specs.d.ts +1 -1
- package/lib/families/ethereum/specs.js +5 -5
- package/lib/families/ethereum/specs.js.map +1 -1
- package/lib/families/polkadot/errors.d.ts +12 -36
- package/lib/families/polkadot/errors.d.ts.map +1 -1
- package/lib/families/ripple/exchange.js +1 -1
- package/lib/families/ripple/exchange.js.map +1 -1
- package/lib/families/solana/api/chain/instruction/token/types.d.ts +3 -3
- package/lib/families/solana/errors.d.ts +20 -60
- package/lib/families/solana/errors.d.ts.map +1 -1
- package/lib/families/stellar/api/horizon.d.ts +29 -7
- package/lib/families/stellar/api/horizon.d.ts.map +1 -1
- package/lib/families/stellar/api/horizon.js +114 -58
- package/lib/families/stellar/api/horizon.js.map +1 -1
- package/lib/families/stellar/api/index.d.ts +1 -1
- package/lib/families/stellar/api/index.d.ts.map +1 -1
- package/lib/families/stellar/api/index.js +5 -1
- package/lib/families/stellar/api/index.js.map +1 -1
- package/lib/families/stellar/bridge/mock.d.ts.map +1 -1
- package/lib/families/stellar/bridge/mock.js +4 -1
- package/lib/families/stellar/bridge/mock.js.map +1 -1
- package/lib/families/stellar/bridge.integration.test.js +12 -4
- package/lib/families/stellar/bridge.integration.test.js.map +1 -1
- package/lib/families/stellar/cli-transaction.d.ts +3 -1
- package/lib/families/stellar/cli-transaction.d.ts.map +1 -1
- package/lib/families/stellar/cli-transaction.js +48 -2
- package/lib/families/stellar/cli-transaction.js.map +1 -1
- package/lib/families/stellar/deviceTransactionConfig.d.ts +7 -1
- package/lib/families/stellar/deviceTransactionConfig.d.ts.map +1 -1
- package/lib/families/stellar/deviceTransactionConfig.js +12 -1
- package/lib/families/stellar/deviceTransactionConfig.js.map +1 -1
- package/lib/families/stellar/errors.d.ts +12 -0
- package/lib/families/stellar/errors.d.ts.map +1 -0
- package/lib/families/stellar/errors.js +16 -0
- package/lib/families/stellar/errors.js.map +1 -0
- package/lib/families/stellar/exchange.js +1 -1
- package/lib/families/stellar/exchange.js.map +1 -1
- package/lib/families/stellar/js-buildTransaction.d.ts.map +1 -1
- package/lib/families/stellar/js-buildTransaction.js +34 -16
- package/lib/families/stellar/js-buildTransaction.js.map +1 -1
- package/lib/families/stellar/js-createTransaction.d.ts.map +1 -1
- package/lib/families/stellar/js-createTransaction.js +4 -1
- package/lib/families/stellar/js-createTransaction.js.map +1 -1
- package/lib/families/stellar/js-estimateMaxSpendable.js +2 -1
- package/lib/families/stellar/js-estimateMaxSpendable.js.map +1 -1
- package/lib/families/stellar/js-getTransactionStatus.d.ts.map +1 -1
- package/lib/families/stellar/js-getTransactionStatus.js +127 -57
- package/lib/families/stellar/js-getTransactionStatus.js.map +1 -1
- package/lib/families/stellar/js-prepareTransaction.d.ts.map +1 -1
- package/lib/families/stellar/js-prepareTransaction.js +25 -7
- package/lib/families/stellar/js-prepareTransaction.js.map +1 -1
- package/lib/families/stellar/js-signOperation.d.ts.map +1 -1
- package/lib/families/stellar/js-signOperation.js +33 -6
- package/lib/families/stellar/js-signOperation.js.map +1 -1
- package/lib/families/stellar/js-synchronization.d.ts +1 -1
- package/lib/families/stellar/js-synchronization.d.ts.map +1 -1
- package/lib/families/stellar/js-synchronization.js +42 -16
- package/lib/families/stellar/js-synchronization.js.map +1 -1
- package/lib/families/stellar/logic.d.ts +21 -14
- package/lib/families/stellar/logic.d.ts.map +1 -1
- package/lib/families/stellar/logic.js +158 -57
- package/lib/families/stellar/logic.js.map +1 -1
- package/lib/families/stellar/specs.d.ts.map +1 -1
- package/lib/families/stellar/specs.js +182 -7
- package/lib/families/stellar/specs.js.map +1 -1
- package/lib/families/stellar/speculos-deviceActions.d.ts.map +1 -1
- package/lib/families/stellar/speculos-deviceActions.js +60 -28
- package/lib/families/stellar/speculos-deviceActions.js.map +1 -1
- package/lib/families/stellar/tokens.d.ts +11 -0
- package/lib/families/stellar/tokens.d.ts.map +1 -0
- package/lib/families/stellar/tokens.js +82 -0
- package/lib/families/stellar/tokens.js.map +1 -0
- package/lib/families/stellar/transaction.d.ts +2 -2
- package/lib/families/stellar/transaction.d.ts.map +1 -1
- package/lib/families/stellar/transaction.js +32 -6
- package/lib/families/stellar/transaction.js.map +1 -1
- package/lib/families/stellar/types.d.ts +45 -0
- package/lib/families/stellar/types.d.ts.map +1 -1
- package/lib/families/stellar/types.js +7 -1
- package/lib/families/stellar/types.js.map +1 -1
- package/lib/families/tezos/exchange.js +1 -1
- package/lib/families/tezos/exchange.js.map +1 -1
- package/lib/generated/cli-transaction.d.ts +1 -0
- package/lib/generated/cli-transaction.d.ts.map +1 -1
- package/lib/generated/specs.d.ts +1 -1
- package/lib/generated/transaction.d.ts +1 -1
- package/lib/hw/signMessage/index.d.ts +4 -3
- package/lib/hw/signMessage/index.d.ts.map +1 -1
- package/lib/hw/signMessage/index.js +25 -11
- package/lib/hw/signMessage/index.js.map +1 -1
- package/lib/hw/signMessage/index.test.d.ts +2 -0
- package/lib/hw/signMessage/index.test.d.ts.map +1 -0
- package/lib/hw/signMessage/index.test.js +126 -0
- package/lib/hw/signMessage/index.test.js.map +1 -0
- package/lib/load/speculos.d.ts.map +1 -1
- package/lib/load/speculos.js +1 -3
- package/lib/load/speculos.js.map +1 -1
- package/lib/mock/Btc.d.ts +1 -1
- package/lib/mock/Btc.d.ts.map +1 -1
- package/lib/performance.d.ts +10 -0
- package/lib/performance.d.ts.map +1 -0
- package/lib/performance.js +72 -0
- package/lib/performance.js.map +1 -0
- package/lib/performance.test.d.ts +2 -0
- package/lib/performance.test.d.ts.map +1 -0
- package/lib/performance.test.js +28 -0
- package/lib/performance.test.js.map +1 -0
- package/lib/platform/providers/RemoteLiveAppProvider/api/index.d.ts.map +1 -1
- package/lib/platform/providers/RemoteLiveAppProvider/api/index.js +28 -0
- package/lib/platform/providers/RemoteLiveAppProvider/api/index.js.map +1 -1
- package/lib/platform/providers/RemoteLiveAppProvider/api/mock.json +0 -31
- package/lib/types/currencies.d.ts +1 -1
- package/lib/types/currencies.d.ts.map +1 -1
- package/lib/walletconnect/Provider.d.ts.map +1 -1
- package/lib/walletconnect/Provider.js +1 -3
- package/lib/walletconnect/Provider.js.map +1 -1
- package/package.json +71 -19
- package/src/apps/support.ts +1 -1
- package/src/bot/index.ts +3 -1
- package/src/bot/specs.ts +7 -1
- package/src/currencies/__snapshots__/sortByMarketcap.test.ts.snap +34 -6
- package/src/currencies/support.ts +1 -1
- package/src/env.ts +10 -0
- package/src/errors.test.ts +21 -0
- package/src/errors.ts +1 -6
- package/src/exchange/swap/utils/index.test.ts +1 -1
- package/src/families/bitcoin/datasets/bitcoin.ts +0 -2
- package/src/families/bitcoin/descriptor.ts +4 -1
- package/src/families/bitcoin/exchange.ts +1 -1
- package/src/families/bitcoin/hw-getAddress.ts +1 -1
- package/src/families/bitcoin/js-synchronisation.ts +23 -1
- package/src/families/bitcoin/wallet-btc/storage/index.ts +17 -31
- package/src/families/bitcoin/wallet-btc/storage/types.ts +1 -0
- package/src/families/bitcoin/wallet-btc/wallet.ts +1 -1
- package/src/families/bitcoin/xpub.txs.loadExport.unit.test.ts +101 -0
- package/src/families/ethereum/exchange.ts +1 -1
- package/src/families/ethereum/modules/index.ts +1 -1
- package/src/families/ethereum/signOperation.ts +2 -2
- package/src/families/ethereum/specs.ts +5 -5
- package/src/families/ripple/exchange.ts +1 -1
- package/src/families/stellar/__snapshots__/bridge.integration.test.ts.snap +765 -339
- package/src/families/stellar/api/horizon.ts +115 -33
- package/src/families/stellar/api/index.ts +4 -0
- package/src/families/stellar/bridge/mock.ts +3 -0
- package/src/families/stellar/bridge.integration.test.ts +10 -2
- package/src/families/stellar/cli-transaction.ts +75 -2
- package/src/families/stellar/deviceTransactionConfig.ts +22 -0
- package/src/families/stellar/errors.ts +34 -0
- package/src/families/stellar/exchange.ts +1 -1
- package/src/families/stellar/js-buildTransaction.ts +56 -16
- package/src/families/stellar/js-createTransaction.ts +3 -0
- package/src/families/stellar/js-estimateMaxSpendable.ts +1 -1
- package/src/families/stellar/js-getTransactionStatus.ts +152 -60
- package/src/families/stellar/js-prepareTransaction.ts +4 -3
- package/src/families/stellar/js-signOperation.ts +37 -6
- package/src/families/stellar/js-synchronization.ts +53 -11
- package/src/families/stellar/logic.ts +198 -62
- package/src/families/stellar/specs.ts +227 -8
- package/src/families/stellar/speculos-deviceActions.ts +66 -22
- package/src/families/stellar/tokens.ts +118 -0
- package/src/families/stellar/transaction.ts +31 -3
- package/src/families/stellar/types.ts +52 -0
- package/src/families/tezos/exchange.ts +1 -1
- package/src/hw/signMessage/index.test.ts +128 -0
- package/src/hw/signMessage/index.ts +37 -15
- package/src/load/speculos.ts +1 -3
- package/src/mock/Btc.ts +1 -1
- package/src/performance.test.ts +26 -0
- package/src/performance.ts +61 -0
- package/src/platform/providers/RemoteLiveAppProvider/api/index.ts +6 -0
- package/src/platform/providers/RemoteLiveAppProvider/api/mock.json +1 -32
- package/src/types/currencies.ts +1 -1
- package/src/walletconnect/Provider.tsx +4 -5
|
@@ -1,19 +1,37 @@
|
|
|
1
1
|
import { BigNumber } from "bignumber.js";
|
|
2
2
|
import StellarSdk, { ServerApi } from "stellar-sdk";
|
|
3
|
+
import { findSubAccountById } from "../../account";
|
|
3
4
|
import type { CacheRes } from "../../cache";
|
|
4
5
|
import { makeLRUCache } from "../../cache";
|
|
5
|
-
import type {
|
|
6
|
-
|
|
6
|
+
import type {
|
|
7
|
+
Account,
|
|
8
|
+
Operation,
|
|
9
|
+
OperationType,
|
|
10
|
+
TokenAccount,
|
|
11
|
+
} from "../../types";
|
|
12
|
+
import {
|
|
13
|
+
fetchSigners,
|
|
14
|
+
fetchBaseFee,
|
|
15
|
+
loadAccount,
|
|
16
|
+
BASE_RESERVE,
|
|
17
|
+
BASE_RESERVE_MIN_COUNT,
|
|
18
|
+
} from "./api";
|
|
7
19
|
import { getCryptoCurrencyById, parseCurrencyUnit } from "../../currencies";
|
|
8
20
|
import { encodeOperationId } from "../../operation";
|
|
21
|
+
import type {
|
|
22
|
+
Transaction,
|
|
23
|
+
TransactionRaw,
|
|
24
|
+
BalanceAsset,
|
|
25
|
+
RawOperation,
|
|
26
|
+
} from "./types";
|
|
9
27
|
|
|
10
28
|
const currency = getCryptoCurrencyById("stellar");
|
|
11
29
|
|
|
12
30
|
const getMinimumBalance = (account: ServerApi.AccountRecord): BigNumber => {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
31
|
+
return parseCurrencyUnit(
|
|
32
|
+
currency.units[0],
|
|
33
|
+
getReservedBalance(account).toString()
|
|
34
|
+
);
|
|
17
35
|
};
|
|
18
36
|
|
|
19
37
|
export const getAccountSpendableBalance = async (
|
|
@@ -21,12 +39,69 @@ export const getAccountSpendableBalance = async (
|
|
|
21
39
|
account: ServerApi.AccountRecord
|
|
22
40
|
): Promise<BigNumber> => {
|
|
23
41
|
const minimumBalance = getMinimumBalance(account);
|
|
24
|
-
const
|
|
25
|
-
return BigNumber.max(balance.minus(minimumBalance).minus(
|
|
42
|
+
const { recommendedFee } = await fetchBaseFee();
|
|
43
|
+
return BigNumber.max(balance.minus(minimumBalance).minus(recommendedFee), 0);
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export const getAmountValue = (
|
|
47
|
+
account: Account,
|
|
48
|
+
transaction: Transaction,
|
|
49
|
+
fees: BigNumber
|
|
50
|
+
): BigNumber => {
|
|
51
|
+
// Asset
|
|
52
|
+
if (transaction.subAccountId) {
|
|
53
|
+
const asset = findSubAccountById(
|
|
54
|
+
account,
|
|
55
|
+
transaction.subAccountId
|
|
56
|
+
) as TokenAccount;
|
|
57
|
+
return transaction.useAllAmount
|
|
58
|
+
? new BigNumber(asset.spendableBalance)
|
|
59
|
+
: transaction.amount;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Native
|
|
63
|
+
return transaction.useAllAmount && transaction.networkInfo
|
|
64
|
+
? BigNumber.max(account.spendableBalance.minus(fees), 0)
|
|
65
|
+
: transaction.amount;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export const getBalanceId = (balance: BalanceAsset): string | null => {
|
|
69
|
+
switch (balance.asset_type) {
|
|
70
|
+
case "native":
|
|
71
|
+
return "native";
|
|
72
|
+
case "liquidity_pool_shares":
|
|
73
|
+
return balance.liquidity_pool_id || null;
|
|
74
|
+
case "credit_alphanum4":
|
|
75
|
+
case "credit_alphanum12":
|
|
76
|
+
return `${balance.asset_code}:${balance.asset_issuer}`;
|
|
77
|
+
default:
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
export const getReservedBalance = (
|
|
83
|
+
account: ServerApi.AccountRecord
|
|
84
|
+
): BigNumber => {
|
|
85
|
+
const numOfSponsoringEntries = Number(account.num_sponsoring);
|
|
86
|
+
const numOfSponsoredEntries = Number(account.num_sponsored);
|
|
87
|
+
|
|
88
|
+
const nativeAsset = account.balances?.find(
|
|
89
|
+
(b) => b.asset_type === "native"
|
|
90
|
+
) as BalanceAsset;
|
|
91
|
+
|
|
92
|
+
const amountInOffers = new BigNumber(nativeAsset?.buying_liabilities || 0);
|
|
93
|
+
const numOfEntries = new BigNumber(account.subentry_count);
|
|
94
|
+
|
|
95
|
+
return new BigNumber(BASE_RESERVE_MIN_COUNT)
|
|
96
|
+
.plus(numOfEntries)
|
|
97
|
+
.plus(numOfSponsoringEntries)
|
|
98
|
+
.minus(numOfSponsoredEntries)
|
|
99
|
+
.times(BASE_RESERVE)
|
|
100
|
+
.plus(amountInOffers);
|
|
26
101
|
};
|
|
27
102
|
|
|
28
103
|
export const getOperationType = (
|
|
29
|
-
operation:
|
|
104
|
+
operation: RawOperation,
|
|
30
105
|
addr: string
|
|
31
106
|
): OperationType => {
|
|
32
107
|
switch (operation.type) {
|
|
@@ -41,11 +116,19 @@ export const getOperationType = (
|
|
|
41
116
|
return "IN";
|
|
42
117
|
|
|
43
118
|
case "path_payment_strict_send":
|
|
119
|
+
if (operation.to === addr) return "IN";
|
|
44
120
|
return "OUT";
|
|
45
121
|
|
|
46
122
|
case "path_payment_strict_receive":
|
|
47
123
|
return "IN";
|
|
48
124
|
|
|
125
|
+
case "change_trust":
|
|
126
|
+
if (new BigNumber(operation.limit).eq(0)) {
|
|
127
|
+
return "OPT_OUT";
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return "OPT_IN";
|
|
131
|
+
|
|
49
132
|
default:
|
|
50
133
|
if (operation.source_account === addr) {
|
|
51
134
|
return "OUT";
|
|
@@ -55,12 +138,26 @@ export const getOperationType = (
|
|
|
55
138
|
}
|
|
56
139
|
};
|
|
57
140
|
|
|
141
|
+
export const getAssetCodeIssuer = (
|
|
142
|
+
tr: Transaction | TransactionRaw
|
|
143
|
+
): string[] => {
|
|
144
|
+
if (tr.subAccountId) {
|
|
145
|
+
const assetString = tr.subAccountId.split("+")[1];
|
|
146
|
+
return assetString.split(":");
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return [tr.assetCode || "", tr.assetIssuer || ""];
|
|
150
|
+
};
|
|
151
|
+
|
|
58
152
|
const getRecipients = (operation): string[] => {
|
|
59
153
|
switch (operation.type) {
|
|
60
154
|
case "create_account":
|
|
61
155
|
return [operation.account];
|
|
62
156
|
|
|
63
157
|
case "payment":
|
|
158
|
+
return [operation.to_muxed || operation.to];
|
|
159
|
+
|
|
160
|
+
case "path_payment_strict_send":
|
|
64
161
|
return [operation.to];
|
|
65
162
|
|
|
66
163
|
default:
|
|
@@ -69,7 +166,7 @@ const getRecipients = (operation): string[] => {
|
|
|
69
166
|
};
|
|
70
167
|
|
|
71
168
|
export const formatOperation = async (
|
|
72
|
-
rawOperation:
|
|
169
|
+
rawOperation: RawOperation,
|
|
73
170
|
accountId: string,
|
|
74
171
|
addr: string
|
|
75
172
|
): Promise<Operation> => {
|
|
@@ -86,34 +183,42 @@ export const formatOperation = async (
|
|
|
86
183
|
id: encodeOperationId(accountId, rawOperation.transaction_hash, type),
|
|
87
184
|
accountId,
|
|
88
185
|
fee: new BigNumber(transaction.fee_charged),
|
|
89
|
-
value
|
|
90
|
-
|
|
186
|
+
value: rawOperation?.asset_code
|
|
187
|
+
? new BigNumber(transaction.fee_charged)
|
|
188
|
+
: value,
|
|
189
|
+
// Using type NONE to hide asset operations from the main account (show them
|
|
190
|
+
// only on sub-account)
|
|
191
|
+
type:
|
|
192
|
+
rawOperation?.asset_code && !["OPT_IN", "OPT_OUT"].includes(type)
|
|
193
|
+
? "NONE"
|
|
194
|
+
: type,
|
|
91
195
|
hash: rawOperation.transaction_hash,
|
|
92
196
|
blockHeight: transaction.ledger_attr,
|
|
93
197
|
date: new Date(rawOperation.created_at),
|
|
94
198
|
senders: [rawOperation.source_account],
|
|
95
199
|
recipients,
|
|
96
200
|
transactionSequenceNumber: Number(transaction.source_account_sequence),
|
|
97
|
-
// @ts-expect-error check transaction_successful property
|
|
98
201
|
hasFailed: !rawOperation.transaction_successful,
|
|
99
202
|
blockHash: null,
|
|
100
|
-
extra:
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
:
|
|
203
|
+
extra: {
|
|
204
|
+
pagingToken: rawOperation.paging_token,
|
|
205
|
+
assetCode: rawOperation?.asset_code,
|
|
206
|
+
assetIssuer: rawOperation?.asset_issuer,
|
|
207
|
+
assetAmount: rawOperation?.asset_code ? value.toString() : undefined,
|
|
208
|
+
ledgerOpType: type,
|
|
209
|
+
memo,
|
|
210
|
+
},
|
|
105
211
|
};
|
|
106
212
|
return operation;
|
|
107
213
|
};
|
|
108
214
|
|
|
109
215
|
const getValue = (
|
|
110
|
-
operation:
|
|
216
|
+
operation: RawOperation,
|
|
111
217
|
transaction: ServerApi.TransactionRecord,
|
|
112
218
|
type: OperationType
|
|
113
219
|
): BigNumber => {
|
|
114
220
|
let value = new BigNumber(0);
|
|
115
221
|
|
|
116
|
-
// @ts-expect-error check transaction_successful property
|
|
117
222
|
if (!operation.transaction_successful) {
|
|
118
223
|
return type === "IN" ? value : new BigNumber(transaction.fee_charged || 0);
|
|
119
224
|
}
|
|
@@ -131,38 +236,13 @@ const getValue = (
|
|
|
131
236
|
case "payment":
|
|
132
237
|
case "path_payment_strict_send":
|
|
133
238
|
case "path_payment_strict_receive":
|
|
134
|
-
|
|
135
|
-
operation.asset_type === "native"
|
|
136
|
-
? parseCurrencyUnit(currency.units[0], operation.amount)
|
|
137
|
-
: new BigNumber(0);
|
|
138
|
-
|
|
139
|
-
if (type === "OUT") {
|
|
140
|
-
value = value.plus(transaction.fee_charged);
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
return value;
|
|
239
|
+
return parseCurrencyUnit(currency.units[0], operation.amount);
|
|
144
240
|
|
|
145
241
|
default:
|
|
146
242
|
return type !== "IN" ? new BigNumber(transaction.fee_charged) : value;
|
|
147
243
|
}
|
|
148
244
|
};
|
|
149
245
|
|
|
150
|
-
// TODO: Move to cache.js
|
|
151
|
-
export const checkRecipientExist: CacheRes<
|
|
152
|
-
Array<{
|
|
153
|
-
account: Account;
|
|
154
|
-
recipient: string;
|
|
155
|
-
}>,
|
|
156
|
-
boolean
|
|
157
|
-
> = makeLRUCache(
|
|
158
|
-
async ({ recipient }) => await addressExists(recipient),
|
|
159
|
-
(extract) => extract.recipient,
|
|
160
|
-
{
|
|
161
|
-
max: 300,
|
|
162
|
-
maxAge: 5 * 60,
|
|
163
|
-
} // 5 minutes
|
|
164
|
-
);
|
|
165
|
-
|
|
166
246
|
export const isMemoValid = (memoType: string, memoValue: string): boolean => {
|
|
167
247
|
switch (memoType) {
|
|
168
248
|
case "MEMO_TEXT":
|
|
@@ -191,7 +271,9 @@ export const isMemoValid = (memoType: string, memoValue: string): boolean => {
|
|
|
191
271
|
return true;
|
|
192
272
|
};
|
|
193
273
|
|
|
194
|
-
export const isAccountMultiSign = async (
|
|
274
|
+
export const isAccountMultiSign = async (
|
|
275
|
+
account: Account
|
|
276
|
+
): Promise<boolean> => {
|
|
195
277
|
const signers = await fetchSigners(account);
|
|
196
278
|
return signers.length > 1;
|
|
197
279
|
};
|
|
@@ -205,43 +287,97 @@ export const isAddressValid = (address: string): boolean => {
|
|
|
205
287
|
if (!address) return false;
|
|
206
288
|
|
|
207
289
|
try {
|
|
208
|
-
return
|
|
290
|
+
return (
|
|
291
|
+
StellarSdk.StrKey.isValidEd25519PublicKey(address) ||
|
|
292
|
+
StellarSdk.StrKey.isValidMed25519PublicKey(address)
|
|
293
|
+
);
|
|
209
294
|
} catch (err) {
|
|
210
295
|
return false;
|
|
211
296
|
}
|
|
212
297
|
};
|
|
213
298
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
299
|
+
export const getRecipientAccount: CacheRes<
|
|
300
|
+
Array<{
|
|
301
|
+
account: Account;
|
|
302
|
+
recipient: string;
|
|
303
|
+
}>,
|
|
304
|
+
{
|
|
305
|
+
id: string | null;
|
|
306
|
+
isMuxedAccount: boolean;
|
|
307
|
+
assetIds: string[];
|
|
308
|
+
} | null
|
|
309
|
+
> = makeLRUCache(
|
|
310
|
+
async ({ recipient }) => await recipientAccount(recipient),
|
|
311
|
+
(extract) => extract.recipient,
|
|
312
|
+
{
|
|
313
|
+
max: 300,
|
|
314
|
+
maxAge: 5 * 60,
|
|
315
|
+
} // 5 minutes
|
|
316
|
+
);
|
|
317
|
+
|
|
318
|
+
export const recipientAccount = async (
|
|
319
|
+
address?: string
|
|
320
|
+
): Promise<{
|
|
321
|
+
id: string | null;
|
|
322
|
+
isMuxedAccount: boolean;
|
|
323
|
+
assetIds: string[];
|
|
324
|
+
} | null> => {
|
|
325
|
+
if (!address) {
|
|
326
|
+
return null;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
let accountAddress = address;
|
|
330
|
+
|
|
331
|
+
const isMuxedAccount = Boolean(
|
|
332
|
+
StellarSdk.StrKey.isValidMed25519PublicKey(address)
|
|
333
|
+
);
|
|
334
|
+
|
|
335
|
+
if (isMuxedAccount) {
|
|
336
|
+
const muxedAccount = new StellarSdk.MuxedAccount.fromAddress(address, "0");
|
|
337
|
+
accountAddress = muxedAccount.baseAccount().accountId();
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
const account = await loadAccount(accountAddress);
|
|
341
|
+
|
|
342
|
+
if (!account) {
|
|
343
|
+
return null;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
return {
|
|
347
|
+
id: account.id,
|
|
348
|
+
isMuxedAccount,
|
|
349
|
+
assetIds: account.balances.reduce((allAssets, balance) => {
|
|
350
|
+
return [...allAssets, getBalanceId(balance)];
|
|
351
|
+
}, []),
|
|
352
|
+
};
|
|
223
353
|
};
|
|
224
354
|
|
|
225
355
|
export const rawOperationsToOperations = async (
|
|
226
|
-
operations:
|
|
356
|
+
operations: RawOperation[],
|
|
227
357
|
addr: string,
|
|
228
358
|
accountId: string
|
|
229
359
|
): Promise<Operation[]> => {
|
|
360
|
+
const supportedOperationTypes = [
|
|
361
|
+
"create_account",
|
|
362
|
+
"payment",
|
|
363
|
+
"path_payment_strict_send",
|
|
364
|
+
"path_payment_strict_receive",
|
|
365
|
+
"change_trust",
|
|
366
|
+
];
|
|
367
|
+
|
|
230
368
|
return Promise.all(
|
|
231
369
|
operations
|
|
232
370
|
.filter((operation) => {
|
|
233
371
|
return (
|
|
234
|
-
// @ts-expect-error check from property
|
|
235
372
|
operation.from === addr ||
|
|
236
|
-
// @ts-expect-error check to property
|
|
237
373
|
operation.to === addr ||
|
|
238
|
-
// @ts-expect-error check funder property
|
|
239
374
|
operation.funder === addr ||
|
|
240
|
-
// @ts-expect-error check account property
|
|
241
375
|
operation.account === addr ||
|
|
376
|
+
operation.trustor === addr ||
|
|
242
377
|
operation.source_account === addr
|
|
243
378
|
);
|
|
244
379
|
})
|
|
380
|
+
.filter((operation) => supportedOperationTypes.includes(operation.type))
|
|
245
381
|
.map((operation) => formatOperation(operation, accountId, addr))
|
|
246
382
|
);
|
|
247
383
|
};
|
|
@@ -1,13 +1,30 @@
|
|
|
1
1
|
import expect from "expect";
|
|
2
2
|
import invariant from "invariant";
|
|
3
|
+
import BigNumber from "bignumber.js";
|
|
3
4
|
import type { Transaction } from "./types";
|
|
4
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
getCryptoCurrencyById,
|
|
7
|
+
parseCurrencyUnit,
|
|
8
|
+
listTokensForCryptoCurrency,
|
|
9
|
+
} from "../../currencies";
|
|
5
10
|
import { pickSiblings } from "../../bot/specs";
|
|
6
11
|
import type { AppSpec } from "../../bot/types";
|
|
7
12
|
import { DeviceModelId } from "@ledgerhq/devices";
|
|
13
|
+
import { TokenCurrency, SubAccount } from "../../types";
|
|
14
|
+
|
|
8
15
|
const currency = getCryptoCurrencyById("stellar");
|
|
9
16
|
const minAmountCutoff = parseCurrencyUnit(currency.units[0], "0.1");
|
|
10
|
-
const reserve = parseCurrencyUnit(currency.units[0], "1");
|
|
17
|
+
const reserve = parseCurrencyUnit(currency.units[0], "1.5");
|
|
18
|
+
|
|
19
|
+
const MAX_FEE = 5000;
|
|
20
|
+
const USDC_CODE = "USDC";
|
|
21
|
+
const USDC_ISSUER = "GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN";
|
|
22
|
+
const USDC_ASSET_ID = `${USDC_CODE}:${USDC_ISSUER}`;
|
|
23
|
+
const MIN_ASSET_BALANCE = parseCurrencyUnit(currency.units[0], "0.01");
|
|
24
|
+
|
|
25
|
+
const findAssetUSDC = <T extends { id: string }>(subAccounts?: T[]) =>
|
|
26
|
+
(subAccounts || []).find((s) => s.id.endsWith(USDC_ASSET_ID));
|
|
27
|
+
|
|
11
28
|
const stellar: AppSpec<Transaction> = {
|
|
12
29
|
name: "Stellar",
|
|
13
30
|
currency,
|
|
@@ -15,12 +32,14 @@ const stellar: AppSpec<Transaction> = {
|
|
|
15
32
|
model: DeviceModelId.nanoS,
|
|
16
33
|
appName: "Stellar",
|
|
17
34
|
},
|
|
35
|
+
testTimeout: 2 * 60 * 1000,
|
|
18
36
|
mutations: [
|
|
19
37
|
{
|
|
20
|
-
name: "move ~50%",
|
|
38
|
+
name: "move ~50% XLM",
|
|
21
39
|
maxRun: 2,
|
|
22
40
|
transaction: ({ account, siblings, bridge, maxSpendable }) => {
|
|
23
|
-
invariant(maxSpendable.gt(minAmountCutoff), "balance is too low");
|
|
41
|
+
invariant(maxSpendable.gt(minAmountCutoff), "XLM balance is too low");
|
|
42
|
+
|
|
24
43
|
const transaction = bridge.createTransaction(account);
|
|
25
44
|
const sibling = pickSiblings(siblings, 4);
|
|
26
45
|
const recipient = sibling.freshAddress;
|
|
@@ -29,17 +48,81 @@ const stellar: AppSpec<Transaction> = {
|
|
|
29
48
|
if (!sibling.used && amount.lt(reserve)) {
|
|
30
49
|
invariant(
|
|
31
50
|
maxSpendable.gt(reserve.plus(minAmountCutoff)),
|
|
32
|
-
"not enough funds to send to new account"
|
|
51
|
+
"not enough XLM funds to send to new account"
|
|
33
52
|
);
|
|
34
53
|
amount = reserve;
|
|
35
54
|
}
|
|
36
55
|
|
|
37
56
|
const updates: Array<Partial<Transaction>> = [
|
|
57
|
+
{
|
|
58
|
+
recipient,
|
|
59
|
+
// Setting higher max fee here to make sure transaction doesn't
|
|
60
|
+
// time out.
|
|
61
|
+
fees: new BigNumber(MAX_FEE),
|
|
62
|
+
},
|
|
38
63
|
{
|
|
39
64
|
amount,
|
|
40
65
|
},
|
|
66
|
+
];
|
|
67
|
+
|
|
68
|
+
if (Math.random() < 0.5) {
|
|
69
|
+
updates.push({
|
|
70
|
+
memoType: "MEMO_TEXT",
|
|
71
|
+
memoValue: "Ledger Live",
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return {
|
|
76
|
+
transaction,
|
|
77
|
+
updates,
|
|
78
|
+
};
|
|
79
|
+
},
|
|
80
|
+
test: ({ account, accountBeforeTransaction, operation, transaction }) => {
|
|
81
|
+
// We don't know what the final fee will be until after the tx is
|
|
82
|
+
// submitted. Using higher max fee to make sure tx doesn't time out.
|
|
83
|
+
expect(account.balance.toNumber()).toBeLessThanOrEqual(
|
|
84
|
+
accountBeforeTransaction.balance.minus(operation.value).toNumber()
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
if (transaction.memoValue) {
|
|
88
|
+
expect(operation.extra).toMatchObject({
|
|
89
|
+
memo: transaction.memoValue,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const getType = () => {
|
|
94
|
+
switch (transaction.mode) {
|
|
95
|
+
case "send":
|
|
96
|
+
return "send";
|
|
97
|
+
case "changeTrust":
|
|
98
|
+
return /change_trust/;
|
|
99
|
+
default:
|
|
100
|
+
return "";
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
expect(transaction.mode).toMatch(getType());
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
name: "Send max XLM",
|
|
109
|
+
maxRun: 2,
|
|
110
|
+
transaction: ({ account, siblings, bridge, maxSpendable }) => {
|
|
111
|
+
invariant(maxSpendable.gt(minAmountCutoff), "XLM balance is too low");
|
|
112
|
+
|
|
113
|
+
const transaction = bridge.createTransaction(account);
|
|
114
|
+
const sibling = pickSiblings(siblings, 4);
|
|
115
|
+
const recipient = sibling.freshAddress;
|
|
116
|
+
|
|
117
|
+
const updates: Array<Partial<Transaction>> = [
|
|
41
118
|
{
|
|
42
119
|
recipient,
|
|
120
|
+
// Setting higher max fee here to make sure transaction doesn't
|
|
121
|
+
// time out.
|
|
122
|
+
fees: new BigNumber(MAX_FEE),
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
useAllAmount: true,
|
|
43
126
|
},
|
|
44
127
|
];
|
|
45
128
|
|
|
@@ -56,12 +139,148 @@ const stellar: AppSpec<Transaction> = {
|
|
|
56
139
|
};
|
|
57
140
|
},
|
|
58
141
|
test: ({ account, accountBeforeTransaction, operation, transaction }) => {
|
|
59
|
-
|
|
60
|
-
|
|
142
|
+
// We don't know what the final fee will be until after the tx is
|
|
143
|
+
// submitted. Using higher max fee to make sure tx doesn't time out.
|
|
144
|
+
expect(account.balance.toNumber()).toBeLessThanOrEqual(
|
|
145
|
+
accountBeforeTransaction.balance.minus(operation.value).toNumber()
|
|
146
|
+
);
|
|
147
|
+
|
|
148
|
+
if (transaction.memoValue) {
|
|
149
|
+
expect(operation.extra).toMatchObject({
|
|
150
|
+
memo: transaction.memoValue,
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const getType = () => {
|
|
155
|
+
switch (transaction.mode) {
|
|
156
|
+
case "send":
|
|
157
|
+
return "send";
|
|
158
|
+
case "changeTrust":
|
|
159
|
+
return /change_trust/;
|
|
160
|
+
default:
|
|
161
|
+
return "";
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
expect(transaction.mode).toMatch(getType());
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
name: "add USDC asset",
|
|
170
|
+
maxRun: 1,
|
|
171
|
+
transaction: ({ account, bridge, maxSpendable }) => {
|
|
172
|
+
invariant(maxSpendable.gt(reserve), "XLM balance is too low 1");
|
|
173
|
+
invariant(
|
|
174
|
+
account.subAccounts && !findAssetUSDC(account.subAccounts),
|
|
175
|
+
"already have subaccounts"
|
|
176
|
+
);
|
|
177
|
+
const assetUSDC = findAssetUSDC<TokenCurrency>(
|
|
178
|
+
listTokensForCryptoCurrency(account.currency)
|
|
179
|
+
);
|
|
180
|
+
invariant(assetUSDC, "USDC asset not found");
|
|
181
|
+
|
|
182
|
+
const transaction = bridge.createTransaction(account);
|
|
183
|
+
|
|
184
|
+
const updates: Array<Partial<Transaction>> = [
|
|
185
|
+
{
|
|
186
|
+
mode: "changeTrust",
|
|
187
|
+
// Setting higher max fee here to make sure transaction doesn't
|
|
188
|
+
// time out.
|
|
189
|
+
fees: new BigNumber(MAX_FEE),
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
assetCode: USDC_CODE,
|
|
193
|
+
assetIssuer: USDC_ISSUER,
|
|
194
|
+
},
|
|
195
|
+
];
|
|
196
|
+
|
|
197
|
+
return {
|
|
198
|
+
transaction,
|
|
199
|
+
updates,
|
|
200
|
+
};
|
|
201
|
+
},
|
|
202
|
+
test: ({ account }) => {
|
|
203
|
+
const assetId = `${USDC_CODE}:${USDC_ISSUER}`;
|
|
204
|
+
const hasAsset = account.subAccounts?.find((a) =>
|
|
205
|
+
a.id.endsWith(assetId)
|
|
206
|
+
);
|
|
207
|
+
expect(hasAsset).toBeTruthy();
|
|
208
|
+
},
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
name: "move ~50% USDC asset",
|
|
212
|
+
maxRun: 1,
|
|
213
|
+
transaction: ({ account, siblings, bridge, maxSpendable }) => {
|
|
214
|
+
invariant(maxSpendable.gt(minAmountCutoff), "XLM balance is too low");
|
|
215
|
+
|
|
216
|
+
const usdcSubAccount = findAssetUSDC<SubAccount>(account?.subAccounts);
|
|
217
|
+
|
|
218
|
+
invariant(usdcSubAccount, "USDC asset not found");
|
|
219
|
+
invariant(
|
|
220
|
+
usdcSubAccount?.balance.gt(MIN_ASSET_BALANCE),
|
|
221
|
+
"USDC balance is too low"
|
|
222
|
+
);
|
|
223
|
+
|
|
224
|
+
const siblingWithAssetUSDC = siblings.find((s) =>
|
|
225
|
+
findAssetUSDC(s.subAccounts)
|
|
226
|
+
);
|
|
227
|
+
invariant(siblingWithAssetUSDC, "No siblings with USDC asset");
|
|
228
|
+
|
|
229
|
+
if (!usdcSubAccount || !siblingWithAssetUSDC) {
|
|
230
|
+
throw new Error("No USDC asset or sibling with USDC asset");
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const transaction = bridge.createTransaction(account);
|
|
234
|
+
const recipient = siblingWithAssetUSDC.freshAddress;
|
|
235
|
+
const amount = usdcSubAccount.balance
|
|
236
|
+
.div(1.9 + 0.2 * Math.random())
|
|
237
|
+
.integerValue();
|
|
238
|
+
|
|
239
|
+
const updates: Array<Partial<Transaction>> = [
|
|
240
|
+
{
|
|
241
|
+
recipient,
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
subAccountId: usdcSubAccount.id,
|
|
245
|
+
},
|
|
246
|
+
{
|
|
247
|
+
amount,
|
|
248
|
+
// Setting higher max fee here to make sure transaction doesn't
|
|
249
|
+
// time out.
|
|
250
|
+
fees: new BigNumber(MAX_FEE),
|
|
251
|
+
},
|
|
252
|
+
];
|
|
253
|
+
|
|
254
|
+
if (Math.random() < 0.5) {
|
|
255
|
+
updates.push({
|
|
256
|
+
memoType: "MEMO_TEXT",
|
|
257
|
+
memoValue: "Ledger Live",
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
return {
|
|
262
|
+
transaction,
|
|
263
|
+
updates,
|
|
264
|
+
};
|
|
265
|
+
},
|
|
266
|
+
test: ({
|
|
267
|
+
account,
|
|
268
|
+
accountBeforeTransaction,
|
|
269
|
+
operation,
|
|
270
|
+
transaction,
|
|
271
|
+
status,
|
|
272
|
+
}) => {
|
|
273
|
+
const asset = findAssetUSDC<SubAccount>(account?.subAccounts);
|
|
274
|
+
const assetBeforeTx = findAssetUSDC<SubAccount>(
|
|
275
|
+
accountBeforeTransaction?.subAccounts
|
|
276
|
+
);
|
|
277
|
+
|
|
278
|
+
expect(asset?.balance.toString()).toBe(
|
|
279
|
+
assetBeforeTx?.balance.minus(status.amount).toString()
|
|
61
280
|
);
|
|
62
281
|
|
|
63
282
|
if (transaction.memoValue) {
|
|
64
|
-
expect(operation.extra).
|
|
283
|
+
expect(operation.extra).toMatchObject({
|
|
65
284
|
memo: transaction.memoValue,
|
|
66
285
|
});
|
|
67
286
|
}
|