@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.
Files changed (236) hide show
  1. package/lib/__tests__/currencies.js +1 -1
  2. package/lib/__tests__/families/bitcoin/wallet-btc/xpub.synced.unit.test.js +27 -26
  3. package/lib/__tests__/families/bitcoin/wallet-btc/xpub.synced.unit.test.js.map +1 -1
  4. package/lib/__tests__/families/bitcoin/wallet-btc/xpub.syncing.integration.test.js +9 -7
  5. package/lib/__tests__/families/bitcoin/wallet-btc/xpub.syncing.integration.test.js.map +1 -1
  6. package/lib/apps/support.d.ts.map +1 -1
  7. package/lib/apps/support.js +2 -1
  8. package/lib/apps/support.js.map +1 -1
  9. package/lib/bridge/jsHelpers.js +1 -1
  10. package/lib/bridge/jsHelpers.js.map +1 -1
  11. package/lib/data/icons/react/index.d.ts +1 -0
  12. package/lib/data/icons/react/index.d.ts.map +1 -1
  13. package/lib/data/icons/react/index.js +4 -2
  14. package/lib/data/icons/react/index.js.map +1 -1
  15. package/lib/data/icons/react/sol.js +3 -3
  16. package/lib/data/icons/react/sol.js.map +1 -1
  17. package/lib/data/icons/react/tyc.d.ts +8 -0
  18. package/lib/data/icons/react/tyc.d.ts.map +1 -0
  19. package/lib/data/icons/react/tyc.js +33 -0
  20. package/lib/data/icons/react/tyc.js.map +1 -0
  21. package/lib/data/icons/reactNative/index.d.ts +1 -0
  22. package/lib/data/icons/reactNative/index.d.ts.map +1 -1
  23. package/lib/data/icons/reactNative/index.js +4 -2
  24. package/lib/data/icons/reactNative/index.js.map +1 -1
  25. package/lib/data/icons/reactNative/sol.js +3 -3
  26. package/lib/data/icons/reactNative/sol.js.map +1 -1
  27. package/lib/data/icons/reactNative/tyc.d.ts +8 -0
  28. package/lib/data/icons/reactNative/tyc.d.ts.map +1 -0
  29. package/lib/data/icons/reactNative/tyc.js +34 -0
  30. package/lib/data/icons/reactNative/tyc.js.map +1 -0
  31. package/lib/env.d.ts +15 -6
  32. package/lib/env.d.ts.map +1 -1
  33. package/lib/env.js +11 -2
  34. package/lib/env.js.map +1 -1
  35. package/lib/env.react.d.ts +1 -1
  36. package/lib/env.react.d.ts.map +1 -1
  37. package/lib/exchange/hw-app-exchange/Exchange.d.ts +12 -15
  38. package/lib/exchange/hw-app-exchange/Exchange.d.ts.map +1 -1
  39. package/lib/exchange/hw-app-exchange/Exchange.js +4 -13
  40. package/lib/exchange/hw-app-exchange/Exchange.js.map +1 -1
  41. package/lib/exchange/index.d.ts.map +1 -1
  42. package/lib/exchange/index.js +9 -2
  43. package/lib/exchange/index.js.map +1 -1
  44. package/lib/exchange/platform/completeExchange.d.ts +6 -0
  45. package/lib/exchange/platform/completeExchange.d.ts.map +1 -0
  46. package/lib/exchange/platform/completeExchange.js +24 -0
  47. package/lib/exchange/platform/completeExchange.js.map +1 -0
  48. package/lib/exchange/platform/serialization.d.ts +4 -0
  49. package/lib/exchange/platform/serialization.d.ts.map +1 -0
  50. package/lib/exchange/platform/serialization.js +57 -0
  51. package/lib/exchange/platform/serialization.js.map +1 -0
  52. package/lib/exchange/{swap → platform}/startExchange.d.ts +0 -0
  53. package/lib/exchange/platform/startExchange.d.ts.map +1 -0
  54. package/lib/exchange/{swap → platform}/startExchange.js +3 -3
  55. package/lib/exchange/platform/startExchange.js.map +1 -0
  56. package/lib/exchange/platform/transfer/completeExchange.d.ts +5 -0
  57. package/lib/exchange/platform/transfer/completeExchange.d.ts.map +1 -0
  58. package/lib/exchange/platform/transfer/completeExchange.js +198 -0
  59. package/lib/exchange/platform/transfer/completeExchange.js.map +1 -0
  60. package/lib/exchange/platform/transfer/index.d.ts +5 -0
  61. package/lib/exchange/platform/transfer/index.d.ts.map +1 -0
  62. package/lib/exchange/platform/transfer/index.js +49 -0
  63. package/lib/exchange/platform/transfer/index.js.map +1 -0
  64. package/lib/exchange/platform/types.d.ts +59 -0
  65. package/lib/exchange/platform/types.d.ts.map +1 -0
  66. package/lib/exchange/platform/types.js +3 -0
  67. package/lib/exchange/platform/types.js.map +1 -0
  68. package/lib/exchange/sell/checkSignatureAndPrepare.js +1 -2
  69. package/lib/exchange/sell/checkSignatureAndPrepare.js.map +1 -1
  70. package/lib/exchange/sell/getTransactionId.js +1 -2
  71. package/lib/exchange/sell/getTransactionId.js.map +1 -1
  72. package/lib/exchange/sell/index.d.ts +6 -0
  73. package/lib/exchange/sell/index.d.ts.map +1 -1
  74. package/lib/exchange/sell/index.js +3 -3
  75. package/lib/exchange/sell/index.js.map +1 -1
  76. package/lib/exchange/swap/completeExchange.d.ts +2 -13
  77. package/lib/exchange/swap/completeExchange.d.ts.map +1 -1
  78. package/lib/exchange/swap/completeExchange.js +2 -4
  79. package/lib/exchange/swap/completeExchange.js.map +1 -1
  80. package/lib/exchange/swap/hooks/usePickDefaultAccount.d.ts.map +1 -1
  81. package/lib/exchange/swap/hooks/usePickDefaultAccount.js +4 -9
  82. package/lib/exchange/swap/hooks/usePickDefaultAccount.js.map +1 -1
  83. package/lib/exchange/swap/initSwap.d.ts.map +1 -1
  84. package/lib/exchange/swap/initSwap.js +3 -4
  85. package/lib/exchange/swap/initSwap.js.map +1 -1
  86. package/lib/exchange/swap/types.d.ts +0 -12
  87. package/lib/exchange/swap/types.d.ts.map +1 -1
  88. package/lib/exchange/swap/utils/index.d.ts +6 -1
  89. package/lib/exchange/swap/utils/index.d.ts.map +1 -1
  90. package/lib/exchange/swap/utils/index.js +8 -1
  91. package/lib/exchange/swap/utils/index.js.map +1 -1
  92. package/lib/exchange/swap/utils/index.test.js +27 -0
  93. package/lib/exchange/swap/utils/index.test.js.map +1 -1
  94. package/lib/exchange/testCurrencyConfig/data/coins.d.ts +8 -0
  95. package/lib/exchange/testCurrencyConfig/data/coins.d.ts.map +1 -0
  96. package/lib/exchange/testCurrencyConfig/data/coins.js +21 -0
  97. package/lib/exchange/testCurrencyConfig/data/coins.js.map +1 -0
  98. package/lib/exchange/testCurrencyConfig/index.d.ts +8 -0
  99. package/lib/exchange/testCurrencyConfig/index.d.ts.map +1 -0
  100. package/lib/exchange/testCurrencyConfig/index.js +68 -0
  101. package/lib/exchange/testCurrencyConfig/index.js.map +1 -0
  102. package/lib/families/algorand/api/algodv2.d.ts +2 -1
  103. package/lib/families/algorand/api/algodv2.d.ts.map +1 -1
  104. package/lib/families/algorand/api/algodv2.js +2 -2
  105. package/lib/families/algorand/api/algodv2.js.map +1 -1
  106. package/lib/families/algorand/js-broadcast.js +1 -1
  107. package/lib/families/algorand/js-broadcast.js.map +1 -1
  108. package/lib/families/algorand/js-signOperation.d.ts.map +1 -1
  109. package/lib/families/algorand/js-signOperation.js +1 -1
  110. package/lib/families/algorand/js-signOperation.js.map +1 -1
  111. package/lib/families/bitcoin/wallet-btc/wallet.d.ts.map +1 -1
  112. package/lib/families/bitcoin/wallet-btc/wallet.js +8 -2
  113. package/lib/families/bitcoin/wallet-btc/wallet.js.map +1 -1
  114. package/lib/families/bitcoin/wallet-btc/xpub.js +1 -1
  115. package/lib/families/bitcoin/wallet-btc/xpub.js.map +1 -1
  116. package/lib/families/ethereum/datasets/ethereum.scanAccounts.1.js +1 -1
  117. package/lib/families/ethereum/datasets/ethereum.scanAccounts.1.js.map +1 -1
  118. package/lib/families/ethereum/nft.integration.test.js +1 -36
  119. package/lib/families/ethereum/nft.integration.test.js.map +1 -1
  120. package/lib/families/ethereum/specs.d.ts.map +1 -1
  121. package/lib/families/ethereum/specs.js +2 -0
  122. package/lib/families/ethereum/specs.js.map +1 -1
  123. package/lib/families/ethereum/synchronisation.d.ts.map +1 -1
  124. package/lib/families/ethereum/synchronisation.js +2 -7
  125. package/lib/families/ethereum/synchronisation.js.map +1 -1
  126. package/lib/families/solana/api/chain/index.d.ts.map +1 -1
  127. package/lib/families/solana/api/chain/index.js +3 -1
  128. package/lib/families/solana/api/chain/index.js.map +1 -1
  129. package/lib/families/tezos/datasets/tezos.scanAccounts.1.js +1 -1
  130. package/lib/families/tezos/datasets/tezos.scanAccounts.1.js.map +1 -1
  131. package/lib/hw/actions/app.d.ts +3 -0
  132. package/lib/hw/actions/app.d.ts.map +1 -1
  133. package/lib/hw/actions/app.js +7 -1
  134. package/lib/hw/actions/app.js.map +1 -1
  135. package/lib/hw/actions/completeExchange.d.ts +1 -0
  136. package/lib/hw/actions/completeExchange.d.ts.map +1 -1
  137. package/lib/hw/actions/completeExchange.js +4 -3
  138. package/lib/hw/actions/completeExchange.js.map +1 -1
  139. package/lib/hw/connectApp.d.ts +5 -0
  140. package/lib/hw/connectApp.d.ts.map +1 -1
  141. package/lib/hw/connectApp.js +37 -26
  142. package/lib/hw/connectApp.js.map +1 -1
  143. package/lib/market/MarketDataProvider.d.ts +26 -0
  144. package/lib/market/MarketDataProvider.d.ts.map +1 -0
  145. package/lib/market/MarketDataProvider.js +339 -0
  146. package/lib/market/MarketDataProvider.js.map +1 -0
  147. package/lib/market/api/api.d.ts +15 -0
  148. package/lib/market/api/api.d.ts.map +1 -0
  149. package/lib/market/api/api.js +261 -0
  150. package/lib/market/api/api.js.map +1 -0
  151. package/lib/market/api/api.mock.d.ts +15 -0
  152. package/lib/market/api/api.mock.d.ts.map +1 -0
  153. package/lib/market/api/api.mock.js +454 -0
  154. package/lib/market/api/api.mock.js.map +1 -0
  155. package/lib/market/types.d.ts +83 -0
  156. package/lib/market/types.d.ts.map +1 -0
  157. package/lib/market/types.js +3 -0
  158. package/lib/market/types.js.map +1 -0
  159. package/lib/market/utils/countervalueFormatter.d.ts +8 -0
  160. package/lib/market/utils/countervalueFormatter.d.ts.map +1 -0
  161. package/lib/market/utils/countervalueFormatter.js +18 -0
  162. package/lib/market/utils/countervalueFormatter.js.map +1 -0
  163. package/lib/market/utils/rangeDataTable.d.ts +10 -0
  164. package/lib/market/utils/rangeDataTable.d.ts.map +1 -0
  165. package/lib/market/utils/rangeDataTable.js +36 -0
  166. package/lib/market/utils/rangeDataTable.js.map +1 -0
  167. package/lib/nft/support.d.ts.map +1 -1
  168. package/lib/nft/support.js +1 -1
  169. package/lib/nft/support.js.map +1 -1
  170. package/lib/platform/PlatformAppProvider/api/api.mock.d.ts.map +1 -1
  171. package/lib/platform/PlatformAppProvider/api/api.mock.js +27 -0
  172. package/lib/platform/PlatformAppProvider/api/api.mock.js.map +1 -1
  173. package/package.json +17 -17
  174. package/src/__tests__/__snapshots__/all.libcore.ts.snap +221 -212
  175. package/src/__tests__/currencies.ts +1 -1
  176. package/src/__tests__/families/bitcoin/wallet-btc/xpub.synced.unit.test.ts +26 -25
  177. package/src/__tests__/families/bitcoin/wallet-btc/xpub.syncing.integration.test.ts +2 -0
  178. package/src/apps/support.ts +1 -0
  179. package/src/bridge/jsHelpers.ts +1 -1
  180. package/src/data/icons/react/index.tsx +1 -0
  181. package/src/data/icons/react/sol.tsx +1 -1
  182. package/src/data/icons/react/tyc.tsx +12 -0
  183. package/src/data/icons/reactNative/index.tsx +1 -0
  184. package/src/data/icons/reactNative/sol.tsx +1 -1
  185. package/src/data/icons/reactNative/tyc.tsx +13 -0
  186. package/src/data/icons/svg/SOL.svg +8 -1
  187. package/src/data/icons/svg/TYC.svg +6 -0
  188. package/src/env.ts +11 -2
  189. package/src/exchange/hw-app-exchange/Exchange.ts +22 -18
  190. package/src/exchange/index.ts +19 -1
  191. package/src/exchange/platform/completeExchange.ts +42 -0
  192. package/src/exchange/platform/serialization.ts +78 -0
  193. package/src/exchange/{swap → platform}/startExchange.ts +6 -2
  194. package/src/exchange/platform/transfer/completeExchange.ts +187 -0
  195. package/src/exchange/platform/transfer/index.ts +66 -0
  196. package/src/exchange/platform/types.ts +76 -0
  197. package/src/exchange/sell/checkSignatureAndPrepare.ts +2 -2
  198. package/src/exchange/sell/getTransactionId.ts +2 -2
  199. package/src/exchange/sell/index.ts +1 -1
  200. package/src/exchange/swap/completeExchange.ts +41 -50
  201. package/src/exchange/swap/hooks/usePickDefaultAccount.ts +4 -9
  202. package/src/exchange/swap/initSwap.ts +4 -7
  203. package/src/exchange/swap/types.ts +1 -14
  204. package/src/exchange/swap/utils/index.test.ts +44 -1
  205. package/src/exchange/swap/utils/index.ts +12 -1
  206. package/src/exchange/testCurrencyConfig/data/coins.ts +20 -0
  207. package/src/exchange/testCurrencyConfig/index.ts +24 -0
  208. package/src/families/algorand/api/algodv2.ts +2 -2
  209. package/src/families/algorand/js-broadcast.ts +1 -1
  210. package/src/families/algorand/js-signOperation.ts +8 -3
  211. package/src/families/bitcoin/wallet-btc/wallet.ts +6 -2
  212. package/src/families/bitcoin/wallet-btc/xpub.ts +1 -1
  213. package/src/families/ethereum/datasets/ethereum.scanAccounts.1.ts +43 -43
  214. package/src/families/ethereum/nft.integration.test.ts +1 -18
  215. package/src/families/ethereum/specs.ts +2 -0
  216. package/src/families/ethereum/synchronisation.ts +1 -6
  217. package/src/families/solana/api/chain/index.ts +6 -2
  218. package/src/families/tezos/datasets/tezos.scanAccounts.1.ts +39 -39
  219. package/src/hw/actions/app.ts +17 -1
  220. package/src/hw/actions/completeExchange.ts +9 -3
  221. package/src/hw/connectApp.ts +53 -31
  222. package/src/market/MarketDataProvider.tsx +440 -0
  223. package/src/market/api/api.mock.ts +374 -0
  224. package/src/market/api/api.ts +227 -0
  225. package/src/market/types.ts +92 -0
  226. package/src/market/utils/countervalueFormatter.ts +24 -0
  227. package/src/market/utils/rangeDataTable.ts +40 -0
  228. package/src/nft/support.ts +1 -3
  229. package/src/platform/PlatformAppProvider/api/api.mock.ts +27 -0
  230. package/lib/exchange/swap/startExchange.d.ts.map +0 -1
  231. package/lib/exchange/swap/startExchange.js.map +0 -1
  232. package/lib/families/ethereum/versions.d.ts +0 -2
  233. package/lib/families/ethereum/versions.d.ts.map +0 -1
  234. package/lib/families/ethereum/versions.js +0 -5
  235. package/lib/families/ethereum/versions.js.map +0 -1
  236. 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 { TRANSACTION_TYPES } from "../hw-app-exchange/Exchange";
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, TRANSACTION_TYPES.SELL);
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 { TRANSACTION_TYPES } from "../hw-app-exchange/Exchange";
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, TRANSACTION_TYPES.SELL);
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,6 +1,6 @@
1
1
  import type { ExchangeProviderNameAndSignature } from "../";
2
2
 
3
- const sellProviders: Record<
3
+ export const sellProviders: Record<
4
4
  string,
5
5
  {
6
6
  nameAndPubkey: Buffer;
@@ -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
- import { Transaction } from "../../types";
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: CompleteExchangeInput
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 = 0x00, // TODO Pass fixed/float for UI switch ?
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
- if (exchangeType === 0x00) {
135
- // Swap specific checks to confirm the refund address is correct.
136
- if (unsubscribed) return;
137
- const refundAddressParameters = await perFamily[
138
- refundCurrency.family
139
- ].getSerializedAddressParameters(
140
- refundAccount.freshAddressPath,
141
- refundAccount.derivationMode,
142
- refundCurrency.id
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
- if (unsubscribed) return;
145
-
146
- const {
147
- config: refundAddressConfig,
148
- signature: refundAddressConfigSignature,
149
- } = getCurrencyExchangeConfig(refundCurrency);
150
- if (unsubscribed) return;
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 { getAccountCurrency } from "../../../account";
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
- .filter(
22
- (acc) =>
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
- ? TRANSACTION_RATES.FIXED
52
- : TRANSACTION_RATES.FLOATING;
53
- const swap = new Exchange(transport, TRANSACTION_TYPES.SWAP, ratesFlag);
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
- export type CompleteExchangeRequestEvent =
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 { pickExchangeRate, getAccountTuplesForCurrency } from "./index";
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;