@ledgerhq/live-common 21.26.2 → 21.29.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/__tests__/currencies.js +1 -1
- package/lib/__tests__/families/bitcoin/wallet-btc/xpub.synced.unit.test.js +27 -26
- package/lib/__tests__/families/bitcoin/wallet-btc/xpub.synced.unit.test.js.map +1 -1
- package/lib/__tests__/families/bitcoin/wallet-btc/xpub.syncing.integration.test.js +9 -7
- package/lib/__tests__/families/bitcoin/wallet-btc/xpub.syncing.integration.test.js.map +1 -1
- 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/bridge/jsHelpers.js +1 -1
- package/lib/bridge/jsHelpers.js.map +1 -1
- package/lib/data/icons/react/index.d.ts +1 -0
- package/lib/data/icons/react/index.d.ts.map +1 -1
- package/lib/data/icons/react/index.js +4 -2
- package/lib/data/icons/react/index.js.map +1 -1
- package/lib/data/icons/react/sol.js +3 -3
- package/lib/data/icons/react/sol.js.map +1 -1
- package/lib/data/icons/react/tyc.d.ts +8 -0
- package/lib/data/icons/react/tyc.d.ts.map +1 -0
- package/lib/data/icons/react/tyc.js +33 -0
- package/lib/data/icons/react/tyc.js.map +1 -0
- package/lib/data/icons/reactNative/index.d.ts +1 -0
- package/lib/data/icons/reactNative/index.d.ts.map +1 -1
- package/lib/data/icons/reactNative/index.js +4 -2
- package/lib/data/icons/reactNative/index.js.map +1 -1
- package/lib/data/icons/reactNative/sol.js +3 -3
- package/lib/data/icons/reactNative/sol.js.map +1 -1
- package/lib/data/icons/reactNative/tyc.d.ts +8 -0
- package/lib/data/icons/reactNative/tyc.d.ts.map +1 -0
- package/lib/data/icons/reactNative/tyc.js +34 -0
- package/lib/data/icons/reactNative/tyc.js.map +1 -0
- package/lib/env.d.ts +15 -6
- package/lib/env.d.ts.map +1 -1
- package/lib/env.js +11 -2
- 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/exchange/hw-app-exchange/Exchange.d.ts +12 -15
- package/lib/exchange/hw-app-exchange/Exchange.d.ts.map +1 -1
- package/lib/exchange/hw-app-exchange/Exchange.js +4 -13
- package/lib/exchange/hw-app-exchange/Exchange.js.map +1 -1
- package/lib/exchange/index.d.ts.map +1 -1
- package/lib/exchange/index.js +9 -2
- package/lib/exchange/index.js.map +1 -1
- package/lib/exchange/platform/completeExchange.d.ts +6 -0
- package/lib/exchange/platform/completeExchange.d.ts.map +1 -0
- package/lib/exchange/platform/completeExchange.js +24 -0
- package/lib/exchange/platform/completeExchange.js.map +1 -0
- package/lib/exchange/platform/serialization.d.ts +4 -0
- package/lib/exchange/platform/serialization.d.ts.map +1 -0
- package/lib/exchange/platform/serialization.js +57 -0
- package/lib/exchange/platform/serialization.js.map +1 -0
- package/lib/exchange/{swap → platform}/startExchange.d.ts +0 -0
- package/lib/exchange/platform/startExchange.d.ts.map +1 -0
- package/lib/exchange/{swap → platform}/startExchange.js +3 -3
- package/lib/exchange/platform/startExchange.js.map +1 -0
- package/lib/exchange/platform/transfer/completeExchange.d.ts +5 -0
- package/lib/exchange/platform/transfer/completeExchange.d.ts.map +1 -0
- package/lib/exchange/platform/transfer/completeExchange.js +198 -0
- package/lib/exchange/platform/transfer/completeExchange.js.map +1 -0
- package/lib/exchange/platform/transfer/index.d.ts +5 -0
- package/lib/exchange/platform/transfer/index.d.ts.map +1 -0
- package/lib/exchange/platform/transfer/index.js +49 -0
- package/lib/exchange/platform/transfer/index.js.map +1 -0
- package/lib/exchange/platform/types.d.ts +59 -0
- package/lib/exchange/platform/types.d.ts.map +1 -0
- package/lib/exchange/platform/types.js +3 -0
- package/lib/exchange/platform/types.js.map +1 -0
- package/lib/exchange/sell/checkSignatureAndPrepare.js +1 -2
- package/lib/exchange/sell/checkSignatureAndPrepare.js.map +1 -1
- package/lib/exchange/sell/getTransactionId.js +1 -2
- package/lib/exchange/sell/getTransactionId.js.map +1 -1
- package/lib/exchange/sell/index.d.ts +6 -0
- package/lib/exchange/sell/index.d.ts.map +1 -1
- package/lib/exchange/sell/index.js +3 -3
- package/lib/exchange/sell/index.js.map +1 -1
- package/lib/exchange/swap/completeExchange.d.ts +2 -13
- package/lib/exchange/swap/completeExchange.d.ts.map +1 -1
- package/lib/exchange/swap/completeExchange.js +2 -4
- package/lib/exchange/swap/completeExchange.js.map +1 -1
- package/lib/exchange/swap/hooks/usePickDefaultAccount.d.ts.map +1 -1
- package/lib/exchange/swap/hooks/usePickDefaultAccount.js +4 -9
- package/lib/exchange/swap/hooks/usePickDefaultAccount.js.map +1 -1
- package/lib/exchange/swap/initSwap.d.ts.map +1 -1
- package/lib/exchange/swap/initSwap.js +3 -4
- package/lib/exchange/swap/initSwap.js.map +1 -1
- package/lib/exchange/swap/types.d.ts +0 -12
- package/lib/exchange/swap/types.d.ts.map +1 -1
- package/lib/exchange/swap/utils/index.d.ts +6 -1
- package/lib/exchange/swap/utils/index.d.ts.map +1 -1
- package/lib/exchange/swap/utils/index.js +8 -1
- package/lib/exchange/swap/utils/index.js.map +1 -1
- package/lib/exchange/swap/utils/index.test.js +27 -0
- package/lib/exchange/swap/utils/index.test.js.map +1 -1
- package/lib/exchange/testCurrencyConfig/data/coins.d.ts +8 -0
- package/lib/exchange/testCurrencyConfig/data/coins.d.ts.map +1 -0
- package/lib/exchange/testCurrencyConfig/data/coins.js +21 -0
- package/lib/exchange/testCurrencyConfig/data/coins.js.map +1 -0
- package/lib/exchange/testCurrencyConfig/index.d.ts +8 -0
- package/lib/exchange/testCurrencyConfig/index.d.ts.map +1 -0
- package/lib/exchange/testCurrencyConfig/index.js +68 -0
- package/lib/exchange/testCurrencyConfig/index.js.map +1 -0
- package/lib/families/algorand/api/algodv2.d.ts +2 -1
- package/lib/families/algorand/api/algodv2.d.ts.map +1 -1
- package/lib/families/algorand/api/algodv2.js +2 -2
- package/lib/families/algorand/api/algodv2.js.map +1 -1
- package/lib/families/algorand/js-broadcast.js +1 -1
- package/lib/families/algorand/js-broadcast.js.map +1 -1
- package/lib/families/algorand/js-signOperation.d.ts.map +1 -1
- package/lib/families/algorand/js-signOperation.js +1 -1
- package/lib/families/algorand/js-signOperation.js.map +1 -1
- package/lib/families/bitcoin/wallet-btc/wallet.d.ts.map +1 -1
- package/lib/families/bitcoin/wallet-btc/wallet.js +8 -2
- package/lib/families/bitcoin/wallet-btc/wallet.js.map +1 -1
- package/lib/families/bitcoin/wallet-btc/xpub.js +1 -1
- package/lib/families/bitcoin/wallet-btc/xpub.js.map +1 -1
- package/lib/families/ethereum/datasets/ethereum.scanAccounts.1.js +1 -1
- package/lib/families/ethereum/datasets/ethereum.scanAccounts.1.js.map +1 -1
- package/lib/families/ethereum/nft.integration.test.js +1 -36
- package/lib/families/ethereum/nft.integration.test.js.map +1 -1
- package/lib/families/ethereum/specs.d.ts.map +1 -1
- package/lib/families/ethereum/specs.js +2 -0
- package/lib/families/ethereum/specs.js.map +1 -1
- package/lib/families/ethereum/synchronisation.d.ts.map +1 -1
- package/lib/families/ethereum/synchronisation.js +2 -7
- package/lib/families/ethereum/synchronisation.js.map +1 -1
- package/lib/families/solana/api/chain/index.d.ts.map +1 -1
- package/lib/families/solana/api/chain/index.js +3 -1
- package/lib/families/solana/api/chain/index.js.map +1 -1
- package/lib/families/tezos/datasets/tezos.scanAccounts.1.js +1 -1
- package/lib/families/tezos/datasets/tezos.scanAccounts.1.js.map +1 -1
- package/lib/hw/actions/app.d.ts +3 -0
- package/lib/hw/actions/app.d.ts.map +1 -1
- package/lib/hw/actions/app.js +7 -1
- package/lib/hw/actions/app.js.map +1 -1
- package/lib/hw/actions/completeExchange.d.ts +1 -0
- package/lib/hw/actions/completeExchange.d.ts.map +1 -1
- package/lib/hw/actions/completeExchange.js +4 -3
- package/lib/hw/actions/completeExchange.js.map +1 -1
- package/lib/hw/connectApp.d.ts +5 -0
- package/lib/hw/connectApp.d.ts.map +1 -1
- package/lib/hw/connectApp.js +37 -26
- package/lib/hw/connectApp.js.map +1 -1
- package/lib/market/MarketDataProvider.d.ts +26 -0
- package/lib/market/MarketDataProvider.d.ts.map +1 -0
- package/lib/market/MarketDataProvider.js +339 -0
- package/lib/market/MarketDataProvider.js.map +1 -0
- package/lib/market/api/api.d.ts +15 -0
- package/lib/market/api/api.d.ts.map +1 -0
- package/lib/market/api/api.js +261 -0
- package/lib/market/api/api.js.map +1 -0
- package/lib/market/api/api.mock.d.ts +15 -0
- package/lib/market/api/api.mock.d.ts.map +1 -0
- package/lib/market/api/api.mock.js +454 -0
- package/lib/market/api/api.mock.js.map +1 -0
- package/lib/market/types.d.ts +83 -0
- package/lib/market/types.d.ts.map +1 -0
- package/lib/market/types.js +3 -0
- package/lib/market/types.js.map +1 -0
- package/lib/market/utils/countervalueFormatter.d.ts +8 -0
- package/lib/market/utils/countervalueFormatter.d.ts.map +1 -0
- package/lib/market/utils/countervalueFormatter.js +18 -0
- package/lib/market/utils/countervalueFormatter.js.map +1 -0
- package/lib/market/utils/rangeDataTable.d.ts +10 -0
- package/lib/market/utils/rangeDataTable.d.ts.map +1 -0
- package/lib/market/utils/rangeDataTable.js +36 -0
- package/lib/market/utils/rangeDataTable.js.map +1 -0
- package/lib/nft/support.d.ts.map +1 -1
- package/lib/nft/support.js +1 -1
- package/lib/nft/support.js.map +1 -1
- package/lib/platform/PlatformAppProvider/api/api.mock.d.ts.map +1 -1
- package/lib/platform/PlatformAppProvider/api/api.mock.js +27 -0
- package/lib/platform/PlatformAppProvider/api/api.mock.js.map +1 -1
- package/package.json +17 -17
- package/src/__tests__/__snapshots__/all.libcore.ts.snap +221 -212
- package/src/__tests__/currencies.ts +1 -1
- package/src/__tests__/families/bitcoin/wallet-btc/xpub.synced.unit.test.ts +26 -25
- package/src/__tests__/families/bitcoin/wallet-btc/xpub.syncing.integration.test.ts +2 -0
- package/src/apps/support.ts +1 -0
- package/src/bridge/jsHelpers.ts +1 -1
- package/src/data/icons/react/index.tsx +1 -0
- package/src/data/icons/react/sol.tsx +1 -1
- package/src/data/icons/react/tyc.tsx +12 -0
- package/src/data/icons/reactNative/index.tsx +1 -0
- package/src/data/icons/reactNative/sol.tsx +1 -1
- package/src/data/icons/reactNative/tyc.tsx +13 -0
- package/src/data/icons/svg/SOL.svg +8 -1
- package/src/data/icons/svg/TYC.svg +6 -0
- package/src/env.ts +11 -2
- package/src/exchange/hw-app-exchange/Exchange.ts +22 -18
- package/src/exchange/index.ts +19 -1
- package/src/exchange/platform/completeExchange.ts +42 -0
- package/src/exchange/platform/serialization.ts +78 -0
- package/src/exchange/{swap → platform}/startExchange.ts +6 -2
- package/src/exchange/platform/transfer/completeExchange.ts +187 -0
- package/src/exchange/platform/transfer/index.ts +66 -0
- package/src/exchange/platform/types.ts +76 -0
- package/src/exchange/sell/checkSignatureAndPrepare.ts +2 -2
- package/src/exchange/sell/getTransactionId.ts +2 -2
- package/src/exchange/sell/index.ts +1 -1
- package/src/exchange/swap/completeExchange.ts +41 -50
- package/src/exchange/swap/hooks/usePickDefaultAccount.ts +4 -9
- package/src/exchange/swap/initSwap.ts +4 -7
- package/src/exchange/swap/types.ts +1 -14
- package/src/exchange/swap/utils/index.test.ts +44 -1
- package/src/exchange/swap/utils/index.ts +12 -1
- package/src/exchange/testCurrencyConfig/data/coins.ts +20 -0
- package/src/exchange/testCurrencyConfig/index.ts +24 -0
- package/src/families/algorand/api/algodv2.ts +2 -2
- package/src/families/algorand/js-broadcast.ts +1 -1
- package/src/families/algorand/js-signOperation.ts +8 -3
- package/src/families/bitcoin/wallet-btc/wallet.ts +6 -2
- package/src/families/bitcoin/wallet-btc/xpub.ts +1 -1
- package/src/families/ethereum/datasets/ethereum.scanAccounts.1.ts +43 -43
- package/src/families/ethereum/nft.integration.test.ts +1 -18
- package/src/families/ethereum/specs.ts +2 -0
- package/src/families/ethereum/synchronisation.ts +1 -6
- package/src/families/solana/api/chain/index.ts +6 -2
- package/src/families/tezos/datasets/tezos.scanAccounts.1.ts +39 -39
- package/src/hw/actions/app.ts +17 -1
- package/src/hw/actions/completeExchange.ts +9 -3
- package/src/hw/connectApp.ts +53 -31
- package/src/market/MarketDataProvider.tsx +440 -0
- package/src/market/api/api.mock.ts +374 -0
- package/src/market/api/api.ts +227 -0
- package/src/market/types.ts +92 -0
- package/src/market/utils/countervalueFormatter.ts +24 -0
- package/src/market/utils/rangeDataTable.ts +40 -0
- package/src/nft/support.ts +1 -3
- package/src/platform/PlatformAppProvider/api/api.mock.ts +27 -0
- package/lib/exchange/swap/startExchange.d.ts.map +0 -1
- package/lib/exchange/swap/startExchange.js.map +0 -1
- package/lib/families/ethereum/versions.d.ts +0 -2
- package/lib/families/ethereum/versions.d.ts.map +0 -1
- package/lib/families/ethereum/versions.js +0 -5
- package/lib/families/ethereum/versions.js.map +0 -1
- package/src/families/ethereum/versions.ts +0 -1
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import secp256k1 from "secp256k1";
|
|
2
|
+
import { from, Observable } from "rxjs";
|
|
3
|
+
import { TransportStatusError, WrongDeviceForAccount } from "@ledgerhq/errors";
|
|
4
|
+
|
|
5
|
+
import { delay } from "../../../promise";
|
|
6
|
+
import ExchangeTransport, {
|
|
7
|
+
ExchangeTypes,
|
|
8
|
+
} from "../../hw-app-exchange/Exchange";
|
|
9
|
+
import perFamily from "../../../generated/exchange";
|
|
10
|
+
import { getAccountCurrency, getMainAccount } from "../../../account";
|
|
11
|
+
import { getAccountBridge } from "../../../bridge";
|
|
12
|
+
import { TransactionRefusedOnDevice } from "../../../errors";
|
|
13
|
+
import { withDevice } from "../../../hw/deviceAccess";
|
|
14
|
+
import { getCurrencyExchangeConfig } from "../..";
|
|
15
|
+
import { getProvider } from ".";
|
|
16
|
+
|
|
17
|
+
import type {
|
|
18
|
+
CompleteExchangeInputFund,
|
|
19
|
+
CompleteExchangeInputSell,
|
|
20
|
+
CompleteExchangeRequestEvent,
|
|
21
|
+
} from "../types";
|
|
22
|
+
|
|
23
|
+
const withDevicePromise = (deviceId, fn) =>
|
|
24
|
+
withDevice(deviceId)((transport) => from(fn(transport))).toPromise();
|
|
25
|
+
|
|
26
|
+
const completeExchange = (
|
|
27
|
+
input: CompleteExchangeInputFund | CompleteExchangeInputSell
|
|
28
|
+
): Observable<CompleteExchangeRequestEvent> => {
|
|
29
|
+
let { transaction } = input; // TODO build a tx from the data
|
|
30
|
+
|
|
31
|
+
const {
|
|
32
|
+
deviceId,
|
|
33
|
+
exchange,
|
|
34
|
+
provider,
|
|
35
|
+
binaryPayload,
|
|
36
|
+
signature,
|
|
37
|
+
exchangeType,
|
|
38
|
+
rateType, // TODO Pass fixed/float for UI switch ?
|
|
39
|
+
} = input;
|
|
40
|
+
|
|
41
|
+
const { fromAccount, fromParentAccount } = exchange;
|
|
42
|
+
|
|
43
|
+
return new Observable((o) => {
|
|
44
|
+
let unsubscribed = false;
|
|
45
|
+
let ignoreTransportError = false;
|
|
46
|
+
|
|
47
|
+
const confirmExchange = async () => {
|
|
48
|
+
await withDevicePromise(deviceId, async (transport) => {
|
|
49
|
+
const providerNameAndSignature = getProvider(exchangeType, provider);
|
|
50
|
+
|
|
51
|
+
if (!providerNameAndSignature)
|
|
52
|
+
throw new Error("Could not get provider infos");
|
|
53
|
+
|
|
54
|
+
const exchange = new ExchangeTransport(
|
|
55
|
+
transport,
|
|
56
|
+
exchangeType,
|
|
57
|
+
rateType
|
|
58
|
+
);
|
|
59
|
+
const refundAccount = getMainAccount(fromAccount, fromParentAccount);
|
|
60
|
+
const accountBridge = getAccountBridge(refundAccount);
|
|
61
|
+
const refundCurrency = getAccountCurrency(refundAccount);
|
|
62
|
+
|
|
63
|
+
if (refundCurrency.type !== "CryptoCurrency")
|
|
64
|
+
throw new Error("This should be a cryptocurrency");
|
|
65
|
+
|
|
66
|
+
transaction = await accountBridge.prepareTransaction(
|
|
67
|
+
refundAccount,
|
|
68
|
+
transaction
|
|
69
|
+
);
|
|
70
|
+
if (unsubscribed) return;
|
|
71
|
+
|
|
72
|
+
const { errors, estimatedFees } =
|
|
73
|
+
await accountBridge.getTransactionStatus(refundAccount, transaction);
|
|
74
|
+
if (unsubscribed) return;
|
|
75
|
+
|
|
76
|
+
const errorsKeys = Object.keys(errors);
|
|
77
|
+
if (errorsKeys.length > 0) throw errors[errorsKeys[0]]; // throw the first error
|
|
78
|
+
|
|
79
|
+
await exchange.setPartnerKey(providerNameAndSignature.nameAndPubkey);
|
|
80
|
+
if (unsubscribed) return;
|
|
81
|
+
|
|
82
|
+
await exchange.checkPartner(providerNameAndSignature.signature);
|
|
83
|
+
if (unsubscribed) return;
|
|
84
|
+
|
|
85
|
+
await exchange.processTransaction(
|
|
86
|
+
Buffer.from(binaryPayload, "hex"),
|
|
87
|
+
estimatedFees
|
|
88
|
+
);
|
|
89
|
+
if (unsubscribed) return;
|
|
90
|
+
|
|
91
|
+
const bufferSignature = Buffer.from(signature, "hex");
|
|
92
|
+
/**
|
|
93
|
+
* For the Fund and Swap flow, the signature sent to the nano needs to
|
|
94
|
+
* be in DER format, which is not the case for Sell flow. Hence the
|
|
95
|
+
* ternary.
|
|
96
|
+
* cf. https://github.com/LedgerHQ/app-exchange/blob/e67848f136dc7227521791b91f608f7cd32e7da7/src/check_tx_signature.c#L14-L32
|
|
97
|
+
*/
|
|
98
|
+
const goodSign =
|
|
99
|
+
exchangeType === ExchangeTypes.Sell
|
|
100
|
+
? bufferSignature
|
|
101
|
+
: Buffer.from(secp256k1.signatureExport(bufferSignature));
|
|
102
|
+
|
|
103
|
+
if (!goodSign) {
|
|
104
|
+
throw new Error("Could not check provider signature");
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
await exchange.checkTransactionSignature(goodSign);
|
|
108
|
+
if (unsubscribed) return;
|
|
109
|
+
|
|
110
|
+
const payoutAddressParameters = await perFamily[
|
|
111
|
+
refundCurrency.family
|
|
112
|
+
].getSerializedAddressParameters(
|
|
113
|
+
refundAccount.freshAddressPath,
|
|
114
|
+
refundAccount.derivationMode,
|
|
115
|
+
refundCurrency.id
|
|
116
|
+
);
|
|
117
|
+
if (unsubscribed) return;
|
|
118
|
+
|
|
119
|
+
const {
|
|
120
|
+
config: payoutAddressConfig,
|
|
121
|
+
signature: payoutAddressConfigSignature,
|
|
122
|
+
} = getCurrencyExchangeConfig(refundCurrency);
|
|
123
|
+
|
|
124
|
+
try {
|
|
125
|
+
await exchange.checkPayoutAddress(
|
|
126
|
+
payoutAddressConfig,
|
|
127
|
+
payoutAddressConfigSignature,
|
|
128
|
+
payoutAddressParameters.addressParameters
|
|
129
|
+
);
|
|
130
|
+
} catch (e) {
|
|
131
|
+
// @ts-expect-error TransportStatusError to be typed on ledgerjs
|
|
132
|
+
if (e instanceof TransportStatusError && e.statusCode === 0x6a83) {
|
|
133
|
+
throw new WrongDeviceForAccount(undefined, {
|
|
134
|
+
accountName: refundAccount.name,
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
throw e;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
o.next({
|
|
142
|
+
type: "complete-exchange-requested",
|
|
143
|
+
estimatedFees,
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
if (unsubscribed) return;
|
|
147
|
+
ignoreTransportError = true;
|
|
148
|
+
await exchange.signCoinTransaction();
|
|
149
|
+
}).catch((e) => {
|
|
150
|
+
if (ignoreTransportError) return;
|
|
151
|
+
|
|
152
|
+
// @ts-expect-error TransportStatusError to be typed on ledgerjs
|
|
153
|
+
if (e instanceof TransportStatusError && e.statusCode === 0x6a84) {
|
|
154
|
+
throw new TransactionRefusedOnDevice();
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
throw e;
|
|
158
|
+
});
|
|
159
|
+
await delay(3000);
|
|
160
|
+
if (unsubscribed) return;
|
|
161
|
+
o.next({
|
|
162
|
+
type: "complete-exchange-result",
|
|
163
|
+
completeExchangeResult: transaction,
|
|
164
|
+
});
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
confirmExchange().then(
|
|
168
|
+
() => {
|
|
169
|
+
o.complete();
|
|
170
|
+
unsubscribed = true;
|
|
171
|
+
},
|
|
172
|
+
(e) => {
|
|
173
|
+
o.next({
|
|
174
|
+
type: "complete-exchange-error",
|
|
175
|
+
error: e,
|
|
176
|
+
});
|
|
177
|
+
o.complete();
|
|
178
|
+
unsubscribed = true;
|
|
179
|
+
}
|
|
180
|
+
);
|
|
181
|
+
return () => {
|
|
182
|
+
unsubscribed = true;
|
|
183
|
+
};
|
|
184
|
+
});
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
export default completeExchange;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { ExchangeProviderNameAndSignature } from "../..";
|
|
2
|
+
import { getEnv } from "../../../env";
|
|
3
|
+
import { ExchangeTypes } from "../../hw-app-exchange/Exchange";
|
|
4
|
+
// FIXME: to be move in this file alongide 'fundProviders' once 'src/exchange/sell/' is deprecated
|
|
5
|
+
import { sellProviders } from "../../sell";
|
|
6
|
+
|
|
7
|
+
const testFundProvider = {
|
|
8
|
+
nameAndPubkey: Buffer.from([
|
|
9
|
+
0x9, 0x46, 0x55, 0x4e, 0x44, 0x5f, 0x54, 0x45, 0x53, 0x54, 0x4, 0x0, 0xbe,
|
|
10
|
+
0xef, 0x98, 0xb4, 0xb2, 0x99, 0x4f, 0x68, 0x8f, 0xd9, 0x8b, 0x56, 0x5e,
|
|
11
|
+
0x17, 0x1e, 0xc9, 0x25, 0x9c, 0x89, 0x6, 0x14, 0xd2, 0xdb, 0xa6, 0x10, 0x52,
|
|
12
|
+
0x2, 0x1, 0x8e, 0x3a, 0x76, 0x4a, 0xa6, 0x68, 0x3e, 0xa1, 0x16, 0xc9, 0xe0,
|
|
13
|
+
0xe3, 0xc8, 0x1, 0xca, 0x5a, 0xb9, 0x72, 0xa2, 0xf8, 0xf7, 0x9f, 0x90, 0x6e,
|
|
14
|
+
0x19, 0xf7, 0x3e, 0xdb, 0x91, 0x45, 0x0, 0xea, 0xd0, 0x2d, 0x70,
|
|
15
|
+
]),
|
|
16
|
+
signature: Buffer.from([
|
|
17
|
+
0x30, 0x44, 0x2, 0x20, 0x3c, 0x1c, 0xe9, 0xea, 0xf2, 0x1a, 0x18, 0x80, 0x3e,
|
|
18
|
+
0xa9, 0x87, 0x6f, 0xab, 0x8f, 0x8a, 0x24, 0xb0, 0xd6, 0xe5, 0xf2, 0x6e,
|
|
19
|
+
0xf7, 0x54, 0xf2, 0xd1, 0xa0, 0xac, 0x34, 0x24, 0xfc, 0xb8, 0xe1, 0x2, 0x20,
|
|
20
|
+
0x4f, 0x6c, 0x92, 0xcf, 0xec, 0x8f, 0x23, 0x2c, 0x1b, 0x14, 0x89, 0x88,
|
|
21
|
+
0x2f, 0x98, 0x7, 0xf, 0xe3, 0xe2, 0x0, 0x84, 0xd0, 0x23, 0xd6, 0x53, 0xe3,
|
|
22
|
+
0xee, 0xf6, 0x96, 0xbc, 0xa0, 0x27, 0x78,
|
|
23
|
+
]),
|
|
24
|
+
curve: "secpk256k1",
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const fundProviders: Record<
|
|
28
|
+
string,
|
|
29
|
+
{
|
|
30
|
+
nameAndPubkey: Buffer;
|
|
31
|
+
signature: Buffer;
|
|
32
|
+
curve: string;
|
|
33
|
+
}
|
|
34
|
+
> = {
|
|
35
|
+
// FIXME: no prod provider for now
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const getProvider = (
|
|
39
|
+
exchangeType: ExchangeTypes,
|
|
40
|
+
providerName: string
|
|
41
|
+
): ExchangeProviderNameAndSignature => {
|
|
42
|
+
if (getEnv("MOCK_EXCHANGE_TEST_CONFIG")) {
|
|
43
|
+
return testFundProvider;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const res = (() => {
|
|
47
|
+
switch (exchangeType) {
|
|
48
|
+
case ExchangeTypes.Fund:
|
|
49
|
+
return fundProviders[providerName.toLowerCase()];
|
|
50
|
+
|
|
51
|
+
case ExchangeTypes.Sell:
|
|
52
|
+
return sellProviders[providerName.toLowerCase()];
|
|
53
|
+
|
|
54
|
+
default:
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
})();
|
|
58
|
+
|
|
59
|
+
if (!res) {
|
|
60
|
+
throw new Error(`Unknown partner ${providerName}`);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return res;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export { getProvider };
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { BigNumber } from "bignumber.js";
|
|
2
|
+
|
|
3
|
+
import type {
|
|
4
|
+
Transaction,
|
|
5
|
+
Account,
|
|
6
|
+
AccountLike,
|
|
7
|
+
AccountRaw,
|
|
8
|
+
AccountRawLike,
|
|
9
|
+
} from "../../types";
|
|
10
|
+
import { ExchangeTypes, RateTypes } from "../hw-app-exchange/Exchange";
|
|
11
|
+
|
|
12
|
+
export type CompleteExchangeRequestEvent =
|
|
13
|
+
| { type: "complete-exchange" }
|
|
14
|
+
| {
|
|
15
|
+
type: "complete-exchange-requested";
|
|
16
|
+
estimatedFees: BigNumber;
|
|
17
|
+
}
|
|
18
|
+
| {
|
|
19
|
+
type: "complete-exchange-error";
|
|
20
|
+
error: Error;
|
|
21
|
+
}
|
|
22
|
+
| {
|
|
23
|
+
type: "complete-exchange-result";
|
|
24
|
+
completeExchangeResult: Transaction;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export type ExchangeSwap = {
|
|
28
|
+
fromParentAccount: Account | null | undefined;
|
|
29
|
+
fromAccount: AccountLike;
|
|
30
|
+
toParentAccount: Account | null | undefined;
|
|
31
|
+
toAccount: AccountLike;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export type ExchangeSwapRaw = {
|
|
35
|
+
fromParentAccount: AccountRaw | null | undefined;
|
|
36
|
+
fromAccount: AccountRawLike;
|
|
37
|
+
toParentAccount: AccountRaw | null | undefined;
|
|
38
|
+
toAccount: AccountRawLike;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export type ExchangeSell = {
|
|
42
|
+
fromParentAccount: Account | null | undefined;
|
|
43
|
+
fromAccount: AccountLike;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export type ExchangeSellRaw = {
|
|
47
|
+
fromParentAccount: AccountRaw | null | undefined;
|
|
48
|
+
fromAccount: AccountRawLike;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
interface CompleteExchangeInputCommon {
|
|
52
|
+
rateType: RateTypes;
|
|
53
|
+
deviceId: string;
|
|
54
|
+
provider: string;
|
|
55
|
+
binaryPayload: string;
|
|
56
|
+
signature: string;
|
|
57
|
+
transaction: Transaction;
|
|
58
|
+
}
|
|
59
|
+
export interface CompleteExchangeInputSell extends CompleteExchangeInputCommon {
|
|
60
|
+
readonly exchangeType: ExchangeTypes.Sell;
|
|
61
|
+
exchange: ExchangeSell;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export interface CompleteExchangeInputFund extends CompleteExchangeInputCommon {
|
|
65
|
+
readonly exchangeType: ExchangeTypes.Fund;
|
|
66
|
+
exchange: ExchangeSell;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export interface CompleteExchangeInputSwap extends CompleteExchangeInputCommon {
|
|
70
|
+
readonly exchangeType: ExchangeTypes.Swap;
|
|
71
|
+
exchange: ExchangeSwap;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export type Exchange = ExchangeSwap | ExchangeSell;
|
|
75
|
+
|
|
76
|
+
export type ExchangeRaw = ExchangeSwapRaw | ExchangeSellRaw;
|
|
@@ -7,7 +7,7 @@ import { getAccountCurrency, getMainAccount } from "../../account";
|
|
|
7
7
|
import { getCurrencyExchangeConfig } from "../";
|
|
8
8
|
import perFamily from "../../generated/exchange";
|
|
9
9
|
import type { SellRequestEvent } from "./types";
|
|
10
|
-
import {
|
|
10
|
+
import { ExchangeTypes } from "../hw-app-exchange/Exchange";
|
|
11
11
|
import type {
|
|
12
12
|
Account,
|
|
13
13
|
AccountLike,
|
|
@@ -38,7 +38,7 @@ export default async (
|
|
|
38
38
|
payloadSignature,
|
|
39
39
|
transaction,
|
|
40
40
|
} = input;
|
|
41
|
-
const exchange = new Exchange(transport,
|
|
41
|
+
const exchange = new Exchange(transport, ExchangeTypes.Sell);
|
|
42
42
|
const mainAccount = getMainAccount(account, parentAccount);
|
|
43
43
|
const { estimatedFees } = status;
|
|
44
44
|
const provider = getProvider("coinify"); // FIXME Don't forget to switch to prod
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import Transport from "@ledgerhq/hw-transport";
|
|
2
2
|
import Exchange from "../hw-app-exchange/Exchange";
|
|
3
3
|
import type { SellRequestEvent } from "./types";
|
|
4
|
-
import {
|
|
4
|
+
import { ExchangeTypes } from "../hw-app-exchange/Exchange";
|
|
5
5
|
|
|
6
6
|
function base64EncodeUrl(str) {
|
|
7
7
|
return str.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
export default async (transport: Transport): Promise<SellRequestEvent> => {
|
|
11
|
-
const sell = new Exchange(transport,
|
|
11
|
+
const sell = new Exchange(transport, ExchangeTypes.Sell);
|
|
12
12
|
const txId = await sell.startNewTransaction();
|
|
13
13
|
return {
|
|
14
14
|
type: "init-sell-get-transaction-id",
|
|
@@ -1,36 +1,28 @@
|
|
|
1
1
|
import { log } from "@ledgerhq/logs";
|
|
2
|
-
import { from } from "rxjs";
|
|
2
|
+
import { from, Observable } from "rxjs";
|
|
3
3
|
import secp256k1 from "secp256k1";
|
|
4
4
|
import { TransportStatusError, WrongDeviceForAccount } from "@ledgerhq/errors";
|
|
5
|
+
|
|
5
6
|
import { delay } from "../../promise";
|
|
6
7
|
import ExchangeTransport from "../hw-app-exchange/Exchange";
|
|
7
8
|
import perFamily from "../../generated/exchange";
|
|
8
9
|
import { getAccountCurrency, getMainAccount } from "../../account";
|
|
9
10
|
import { getAccountBridge } from "../../bridge";
|
|
10
11
|
import { TransactionRefusedOnDevice } from "../../errors";
|
|
11
|
-
import type { CompleteExchangeRequestEvent, Exchange } from "./types";
|
|
12
|
-
import { Observable } from "rxjs";
|
|
13
12
|
import { withDevice } from "../../hw/deviceAccess";
|
|
14
13
|
import { getProviderNameAndSignature } from "./";
|
|
15
14
|
import { getCurrencyExchangeConfig } from "../";
|
|
16
|
-
|
|
15
|
+
|
|
16
|
+
import type {
|
|
17
|
+
CompleteExchangeInputSwap,
|
|
18
|
+
CompleteExchangeRequestEvent,
|
|
19
|
+
} from "../platform/types";
|
|
17
20
|
|
|
18
21
|
const withDevicePromise = (deviceId, fn) =>
|
|
19
22
|
withDevice(deviceId)((transport) => from(fn(transport))).toPromise();
|
|
20
23
|
|
|
21
|
-
type CompleteExchangeInput = {
|
|
22
|
-
exchange: Exchange;
|
|
23
|
-
deviceId: string;
|
|
24
|
-
provider: string;
|
|
25
|
-
binaryPayload: string;
|
|
26
|
-
signature: string;
|
|
27
|
-
transaction: Transaction;
|
|
28
|
-
exchangeType: number;
|
|
29
|
-
rateType: number;
|
|
30
|
-
};
|
|
31
|
-
|
|
32
24
|
const completeExchange = (
|
|
33
|
-
input:
|
|
25
|
+
input: CompleteExchangeInputSwap
|
|
34
26
|
): Observable<CompleteExchangeRequestEvent> => {
|
|
35
27
|
let { transaction } = input; // TODO build a tx from the data
|
|
36
28
|
|
|
@@ -41,7 +33,7 @@ const completeExchange = (
|
|
|
41
33
|
binaryPayload,
|
|
42
34
|
signature,
|
|
43
35
|
exchangeType,
|
|
44
|
-
rateType
|
|
36
|
+
rateType,
|
|
45
37
|
} = input;
|
|
46
38
|
|
|
47
39
|
const { fromAccount, fromParentAccount } = exchange;
|
|
@@ -131,41 +123,40 @@ const completeExchange = (
|
|
|
131
123
|
|
|
132
124
|
throw e;
|
|
133
125
|
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
126
|
+
|
|
127
|
+
// Swap specific checks to confirm the refund address is correct.
|
|
128
|
+
if (unsubscribed) return;
|
|
129
|
+
const refundAddressParameters = await perFamily[
|
|
130
|
+
refundCurrency.family
|
|
131
|
+
].getSerializedAddressParameters(
|
|
132
|
+
refundAccount.freshAddressPath,
|
|
133
|
+
refundAccount.derivationMode,
|
|
134
|
+
refundCurrency.id
|
|
135
|
+
);
|
|
136
|
+
if (unsubscribed) return;
|
|
137
|
+
|
|
138
|
+
const {
|
|
139
|
+
config: refundAddressConfig,
|
|
140
|
+
signature: refundAddressConfigSignature,
|
|
141
|
+
} = getCurrencyExchangeConfig(refundCurrency);
|
|
142
|
+
if (unsubscribed) return;
|
|
143
|
+
|
|
144
|
+
try {
|
|
145
|
+
await exchange.checkRefundAddress(
|
|
146
|
+
refundAddressConfig,
|
|
147
|
+
refundAddressConfigSignature,
|
|
148
|
+
refundAddressParameters.addressParameters
|
|
143
149
|
);
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
try {
|
|
153
|
-
await exchange.checkRefundAddress(
|
|
154
|
-
refundAddressConfig,
|
|
155
|
-
refundAddressConfigSignature,
|
|
156
|
-
refundAddressParameters.addressParameters
|
|
157
|
-
);
|
|
158
|
-
log("exchange", "checkrefund address");
|
|
159
|
-
} catch (e) {
|
|
160
|
-
// @ts-expect-error TransportStatusError to be typed on ledgerjs
|
|
161
|
-
if (e instanceof TransportStatusError && e.statusCode === 0x6a83) {
|
|
162
|
-
log("exchange", "transport error");
|
|
163
|
-
throw new WrongDeviceForAccount(undefined, {
|
|
164
|
-
accountName: refundAccount.name,
|
|
165
|
-
});
|
|
166
|
-
}
|
|
167
|
-
throw e;
|
|
150
|
+
log("exchange", "checkrefund address");
|
|
151
|
+
} catch (e) {
|
|
152
|
+
// @ts-expect-error TransportStatusError to be typed on ledgerjs
|
|
153
|
+
if (e instanceof TransportStatusError && e.statusCode === 0x6a83) {
|
|
154
|
+
log("exchange", "transport error");
|
|
155
|
+
throw new WrongDeviceForAccount(undefined, {
|
|
156
|
+
accountName: refundAccount.name,
|
|
157
|
+
});
|
|
168
158
|
}
|
|
159
|
+
throw e;
|
|
169
160
|
}
|
|
170
161
|
|
|
171
162
|
o.next({
|
|
@@ -2,7 +2,7 @@ import { useEffect } from "react";
|
|
|
2
2
|
import { Account, TokenAccount } from "../../../types";
|
|
3
3
|
import { useCurrenciesByMarketcap } from "../../../currencies/sortByMarketcap";
|
|
4
4
|
import { listCryptoCurrencies, listTokens } from "../../../currencies";
|
|
5
|
-
import {
|
|
5
|
+
import { getAvailableAccountsById } from "../utils";
|
|
6
6
|
|
|
7
7
|
// Pick a default source account if none are selected.
|
|
8
8
|
export const usePickDefaultAccount = (
|
|
@@ -17,14 +17,9 @@ export const usePickDefaultAccount = (
|
|
|
17
17
|
if (!fromAccount && allCurrencies.length > 0) {
|
|
18
18
|
const defaultAccount: Account | TokenAccount | undefined = allCurrencies
|
|
19
19
|
.map(({ id }) =>
|
|
20
|
-
accounts
|
|
21
|
-
.
|
|
22
|
-
|
|
23
|
-
getAccountCurrency(acc)?.id === id &&
|
|
24
|
-
acc.balance.gt(0) &&
|
|
25
|
-
!acc.disabled
|
|
26
|
-
)
|
|
27
|
-
.sort((a, b) => b.balance.minus(a.balance).toNumber())
|
|
20
|
+
getAvailableAccountsById(id, accounts).filter((account) =>
|
|
21
|
+
account.balance.gt(0)
|
|
22
|
+
)
|
|
28
23
|
)
|
|
29
24
|
.flat(1)
|
|
30
25
|
.find(Boolean);
|
|
@@ -23,10 +23,7 @@ import { withDevice } from "../../hw/deviceAccess";
|
|
|
23
23
|
import { getProviderNameAndSignature, getSwapAPIBaseURL } from "./";
|
|
24
24
|
import { getCurrencyExchangeConfig } from "../";
|
|
25
25
|
import { getEnv } from "../../env";
|
|
26
|
-
import {
|
|
27
|
-
TRANSACTION_RATES,
|
|
28
|
-
TRANSACTION_TYPES,
|
|
29
|
-
} from "../hw-app-exchange/Exchange";
|
|
26
|
+
import { RateTypes, ExchangeTypes } from "../hw-app-exchange/Exchange";
|
|
30
27
|
|
|
31
28
|
const withDevicePromise = (deviceId, fn) =>
|
|
32
29
|
withDevice(deviceId)((transport) => from(fn(transport))).toPromise();
|
|
@@ -48,9 +45,9 @@ const initSwap = (input: InitSwapInput): Observable<SwapRequestEvent> => {
|
|
|
48
45
|
await withDevicePromise(deviceId, async (transport) => {
|
|
49
46
|
const ratesFlag =
|
|
50
47
|
exchangeRate.tradeMethod === "fixed"
|
|
51
|
-
?
|
|
52
|
-
:
|
|
53
|
-
const swap = new Exchange(transport,
|
|
48
|
+
? RateTypes.Fixed
|
|
49
|
+
: RateTypes.Floating;
|
|
50
|
+
const swap = new Exchange(transport, ExchangeTypes.Swap, ratesFlag);
|
|
54
51
|
// NB this id is crucial to prevent replay attacks, if it changes
|
|
55
52
|
// we need to start the flow again.
|
|
56
53
|
const deviceTransactionId = await swap.startNewTransaction();
|
|
@@ -130,20 +130,7 @@ export type SwapRequestEvent =
|
|
|
130
130
|
type: "init-swap-result";
|
|
131
131
|
initSwapResult: InitSwapResult;
|
|
132
132
|
};
|
|
133
|
-
|
|
134
|
-
| { type: "complete-exchange" }
|
|
135
|
-
| {
|
|
136
|
-
type: "complete-exchange-requested";
|
|
137
|
-
estimatedFees: BigNumber;
|
|
138
|
-
}
|
|
139
|
-
| {
|
|
140
|
-
type: "complete-exchange-error";
|
|
141
|
-
error: Error;
|
|
142
|
-
}
|
|
143
|
-
| {
|
|
144
|
-
type: "complete-exchange-result";
|
|
145
|
-
completeExchangeResult: Transaction;
|
|
146
|
-
};
|
|
133
|
+
|
|
147
134
|
export type SwapHistorySection = {
|
|
148
135
|
day: Date;
|
|
149
136
|
data: MappedSwapOperation[];
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import BigNumber from "bignumber.js";
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
pickExchangeRate,
|
|
5
|
+
getAccountTuplesForCurrency,
|
|
6
|
+
getAvailableAccountsById,
|
|
7
|
+
} from "./index";
|
|
4
8
|
import { getMockExchangeRate } from "../mock";
|
|
5
9
|
import { genAccount } from "../../../mock/account";
|
|
6
10
|
import type {
|
|
@@ -222,3 +226,42 @@ describe("swap/utils/getAccountTuplesForCurrency", () => {
|
|
|
222
226
|
});
|
|
223
227
|
});
|
|
224
228
|
});
|
|
229
|
+
|
|
230
|
+
describe("swap/utils/getAvailableAccountsById", () => {
|
|
231
|
+
const getEthAccount = getAccountCreator("ethereum");
|
|
232
|
+
const getBtcAccount = getAccountCreator("bitcoin");
|
|
233
|
+
const getPolkadotAccount = getAccountCreator("polkadot");
|
|
234
|
+
const getCosmosAccount = getAccountCreator("cosmos");
|
|
235
|
+
|
|
236
|
+
test("return the correct accounts after sorting/filtering them", () => {
|
|
237
|
+
const [
|
|
238
|
+
disabledAccount,
|
|
239
|
+
higherBalanceAccount,
|
|
240
|
+
lowerBalanceAccount,
|
|
241
|
+
...accounts
|
|
242
|
+
] = new Array(6).fill(null).map(getEthAccount);
|
|
243
|
+
|
|
244
|
+
// mutate some accounts to test sorting/filtering
|
|
245
|
+
disabledAccount.disabled = true;
|
|
246
|
+
higherBalanceAccount.balance = new BigNumber(10);
|
|
247
|
+
lowerBalanceAccount.balance = new BigNumber(2);
|
|
248
|
+
|
|
249
|
+
const allAccounts: Account[] = [
|
|
250
|
+
getCosmosAccount(),
|
|
251
|
+
disabledAccount,
|
|
252
|
+
higherBalanceAccount,
|
|
253
|
+
lowerBalanceAccount,
|
|
254
|
+
...accounts,
|
|
255
|
+
getBtcAccount(),
|
|
256
|
+
getPolkadotAccount(),
|
|
257
|
+
];
|
|
258
|
+
|
|
259
|
+
const results = getAvailableAccountsById("ethereum", allAccounts);
|
|
260
|
+
expect(results).toHaveLength(5);
|
|
261
|
+
expect(results[0].balance.toNumber()).toBeGreaterThan(0);
|
|
262
|
+
expect(results[1].balance.toNumber()).toBeGreaterThan(0);
|
|
263
|
+
expect(results[0].balance.toNumber()).toBeGreaterThan(
|
|
264
|
+
results[1].balance.toNumber()
|
|
265
|
+
);
|
|
266
|
+
});
|
|
267
|
+
});
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { CryptoCurrency, TokenCurrency } from "@ledgerhq/cryptoassets";
|
|
2
2
|
import { makeEmptyTokenAccount } from "../../../account";
|
|
3
|
-
import { Account, SubAccount } from "../../../types";
|
|
3
|
+
import { Account, SubAccount, TokenAccount } from "../../../types";
|
|
4
4
|
import type { ExchangeRate } from "../types";
|
|
5
|
+
import { getAccountCurrency } from "../../../account";
|
|
5
6
|
|
|
6
7
|
export const KYC_STATUS = {
|
|
7
8
|
pending: "pending",
|
|
@@ -65,3 +66,13 @@ export function getAccountTuplesForCurrency(
|
|
|
65
66
|
}))
|
|
66
67
|
.filter((a) => (hideEmpty ? a.account?.balance.gt(0) : true));
|
|
67
68
|
}
|
|
69
|
+
|
|
70
|
+
export const getAvailableAccountsById = (
|
|
71
|
+
id: string,
|
|
72
|
+
accounts: ((Account | TokenAccount) & { disabled?: boolean })[]
|
|
73
|
+
): ((Account | TokenAccount) & {
|
|
74
|
+
disabled?: boolean | undefined;
|
|
75
|
+
})[] =>
|
|
76
|
+
accounts
|
|
77
|
+
.filter((acc) => getAccountCurrency(acc)?.id === id && !acc.disabled)
|
|
78
|
+
.sort((a, b) => b.balance.minus(a.balance).toNumber());
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FIXME:
|
|
3
|
+
* Minimal config for now, need to extend it to match prod config
|
|
4
|
+
* cf. https://github.com/LedgerHQ/ledgerjs/tree/master/packages/cryptoassets/data/exchange
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const coins = [
|
|
8
|
+
[
|
|
9
|
+
"bitcoin",
|
|
10
|
+
"0342544307426974636f696e00",
|
|
11
|
+
"3045022100cb174382302219dca359c0a4d457b2569e31a06b2c25c0088a2bd3fd6c04386a02202c6d0a5b924a414621067e316f021aa13aa5b2eee2bf36ea3cfddebc053b201b",
|
|
12
|
+
],
|
|
13
|
+
[
|
|
14
|
+
"ethereum",
|
|
15
|
+
"0345544808457468657265756d050345544812",
|
|
16
|
+
"3044022065d7931ab3144362d57e3fdcc5de921fb65024737d917f0ab1f8b173d1ed3c2e022027493568d112dc53c7177f8e5fc915d91a903780a067badf109085a73d360323",
|
|
17
|
+
],
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
export default coins;
|