@ledgerhq/live-common 21.26.1 → 21.27.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/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 +19 -5
- package/lib/env.d.ts.map +1 -1
- package/lib/env.js +14 -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/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/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/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/bitcoin/wallet-btc/wallet.d.ts.map +1 -1
- package/lib/families/bitcoin/wallet-btc/wallet.js +10 -2
- package/lib/families/bitcoin/wallet-btc/wallet.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/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 +11 -1
- 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/package.json +7 -7
- package/src/.DS_Store +0 -0
- package/src/__tests__/.DS_Store +0 -0
- package/src/__tests__/__snapshots__/all.libcore.ts.snap +144 -193
- 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/bridge/jsHelpers.ts +1 -1
- package/src/currencies/__snapshots__/.DS_Store +0 -0
- 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 +14 -0
- 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/initSwap.ts +4 -7
- package/src/exchange/swap/types.ts +1 -14
- package/src/exchange/testCurrencyConfig/data/coins.ts +20 -0
- package/src/exchange/testCurrencyConfig/index.ts +24 -0
- package/src/families/bitcoin/wallet-btc/wallet.ts +8 -2
- package/src/families/ethereum/specs.ts +2 -0
- package/src/hw/actions/app.ts +17 -1
- package/src/hw/actions/completeExchange.ts +9 -3
- package/src/hw/connectApp.ts +19 -0
- 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/lib/exchange/swap/startExchange.d.ts.map +0 -1
- package/lib/exchange/swap/startExchange.js.map +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({
|
|
@@ -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[];
|
|
@@ -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;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import coins from "./data/coins";
|
|
2
|
+
const all = [...coins];
|
|
3
|
+
const configs = {};
|
|
4
|
+
|
|
5
|
+
for (const [id, config, signature] of all) {
|
|
6
|
+
configs[id] = {
|
|
7
|
+
config,
|
|
8
|
+
signature,
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
*
|
|
14
|
+
*/
|
|
15
|
+
export const findTestExchangeCurrencyConfig = (
|
|
16
|
+
id: string
|
|
17
|
+
):
|
|
18
|
+
| {
|
|
19
|
+
config: string;
|
|
20
|
+
|
|
21
|
+
signature: string;
|
|
22
|
+
}
|
|
23
|
+
| null
|
|
24
|
+
| undefined => configs[id];
|
|
@@ -229,7 +229,6 @@ class BitcoinLikeWallet {
|
|
|
229
229
|
btc,
|
|
230
230
|
fromAccount,
|
|
231
231
|
txInfo,
|
|
232
|
-
hasTimestamp,
|
|
233
232
|
initialTimestamp,
|
|
234
233
|
additionals,
|
|
235
234
|
hasExtraData,
|
|
@@ -237,7 +236,7 @@ class BitcoinLikeWallet {
|
|
|
237
236
|
onDeviceSignatureGranted,
|
|
238
237
|
onDeviceStreaming,
|
|
239
238
|
} = params;
|
|
240
|
-
|
|
239
|
+
let hasTimestamp = params.hasTimestamp;
|
|
241
240
|
let length = txInfo.outputs.reduce((sum, output) => {
|
|
242
241
|
return sum + 8 + output.script.length + 1;
|
|
243
242
|
}, 1);
|
|
@@ -270,6 +269,13 @@ class BitcoinLikeWallet {
|
|
|
270
269
|
number | null | undefined
|
|
271
270
|
][];
|
|
272
271
|
const inputs: Inputs = txInfo.inputs.map((i) => {
|
|
272
|
+
if (additionals && additionals.includes("peercoin")) {
|
|
273
|
+
// remove timestamp for new version of peercoin input, refer to https://github.com/peercoin/rfcs/issues/5 and https://github.com/LedgerHQ/ledgerjs/issues/701
|
|
274
|
+
const version = i.txHex.substring(0, 8);
|
|
275
|
+
if (version !== "01000000" && version !== "02000000") {
|
|
276
|
+
hasTimestamp = false;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
273
279
|
log("hw", `splitTransaction`, {
|
|
274
280
|
transactionHex: i.txHex,
|
|
275
281
|
isSegwitSupported: true,
|
|
@@ -406,6 +406,7 @@ const bsc: AppSpec<Transaction> = {
|
|
|
406
406
|
model: DeviceModelId.nanoS,
|
|
407
407
|
appName: "Binance Smart Chain",
|
|
408
408
|
},
|
|
409
|
+
dependency: "Ethereum",
|
|
409
410
|
testTimeout: 2 * 60 * 1000,
|
|
410
411
|
transactionCheck: ({ maxSpendable }) => {
|
|
411
412
|
invariant(
|
|
@@ -452,6 +453,7 @@ const polygon: AppSpec<Transaction> = {
|
|
|
452
453
|
model: DeviceModelId.nanoS,
|
|
453
454
|
appName: "Polygon",
|
|
454
455
|
},
|
|
456
|
+
dependency: "Ethereum",
|
|
455
457
|
testTimeout: 2 * 60 * 1000,
|
|
456
458
|
transactionCheck: ({ maxSpendable }) => {
|
|
457
459
|
invariant(
|