@ledgerhq/live-common 21.5.1 → 21.7.1-patch.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (170) hide show
  1. package/lib/env.js +1 -1
  2. package/lib/env.js.map +1 -1
  3. package/lib/exchange/swap/getExchangeRates.d.ts.map +1 -1
  4. package/lib/exchange/swap/getExchangeRates.js +9 -8
  5. package/lib/exchange/swap/getExchangeRates.js.map +1 -1
  6. package/lib/exchange/swap/hooks/index.d.ts +11 -0
  7. package/lib/exchange/swap/hooks/index.d.ts.map +1 -0
  8. package/lib/exchange/swap/hooks/index.js +23 -0
  9. package/lib/exchange/swap/hooks/index.js.map +1 -0
  10. package/lib/exchange/swap/hooks/useFromState.d.ts +15 -0
  11. package/lib/exchange/swap/hooks/useFromState.d.ts.map +1 -0
  12. package/lib/exchange/swap/hooks/useFromState.js +67 -0
  13. package/lib/exchange/swap/hooks/useFromState.js.map +1 -0
  14. package/lib/exchange/swap/hooks/useFromState.test.d.ts +2 -0
  15. package/lib/exchange/swap/hooks/useFromState.test.d.ts.map +1 -0
  16. package/lib/exchange/swap/hooks/useFromState.test.js +141 -0
  17. package/lib/exchange/swap/hooks/useFromState.test.js.map +1 -0
  18. package/lib/exchange/swap/hooks/usePickDefaultAccount.d.ts +5 -0
  19. package/lib/exchange/swap/hooks/usePickDefaultAccount.d.ts.map +1 -0
  20. package/lib/exchange/swap/hooks/usePickDefaultAccount.js +37 -0
  21. package/lib/exchange/swap/hooks/usePickDefaultAccount.js.map +1 -0
  22. package/lib/exchange/swap/hooks/usePickDefaultAccount.test.d.ts +2 -0
  23. package/lib/exchange/swap/hooks/usePickDefaultAccount.test.d.ts.map +1 -0
  24. package/lib/exchange/swap/hooks/usePickDefaultAccount.test.js +185 -0
  25. package/lib/exchange/swap/hooks/usePickDefaultAccount.test.js.map +1 -0
  26. package/lib/exchange/swap/hooks/usePickDefaultCurrency.d.ts +3 -0
  27. package/lib/exchange/swap/hooks/usePickDefaultCurrency.d.ts.map +1 -0
  28. package/lib/exchange/swap/hooks/usePickDefaultCurrency.js +17 -0
  29. package/lib/exchange/swap/hooks/usePickDefaultCurrency.js.map +1 -0
  30. package/lib/exchange/swap/hooks/usePickDefaultCurrency.test.d.ts +2 -0
  31. package/lib/exchange/swap/hooks/usePickDefaultCurrency.test.d.ts.map +1 -0
  32. package/lib/exchange/swap/hooks/usePickDefaultCurrency.test.js +73 -0
  33. package/lib/exchange/swap/hooks/usePickDefaultCurrency.test.js.map +1 -0
  34. package/lib/exchange/swap/hooks/usePollKYCStatus.d.ts +12 -0
  35. package/lib/exchange/swap/hooks/usePollKYCStatus.d.ts.map +1 -0
  36. package/lib/exchange/swap/hooks/usePollKYCStatus.js +105 -0
  37. package/lib/exchange/swap/hooks/usePollKYCStatus.js.map +1 -0
  38. package/lib/exchange/swap/hooks/usePollKYCStatus.test.d.ts +2 -0
  39. package/lib/exchange/swap/hooks/usePollKYCStatus.test.d.ts.map +1 -0
  40. package/lib/exchange/swap/hooks/usePollKYCStatus.test.js +78 -0
  41. package/lib/exchange/swap/hooks/usePollKYCStatus.test.js.map +1 -0
  42. package/lib/exchange/swap/hooks/useProviderRates.d.ts +20 -0
  43. package/lib/exchange/swap/hooks/useProviderRates.d.ts.map +1 -0
  44. package/lib/exchange/swap/hooks/useProviderRates.js +174 -0
  45. package/lib/exchange/swap/hooks/useProviderRates.js.map +1 -0
  46. package/lib/exchange/swap/hooks/useProviderRates.test.d.ts +2 -0
  47. package/lib/exchange/swap/hooks/useProviderRates.test.d.ts.map +1 -0
  48. package/lib/exchange/swap/hooks/useProviderRates.test.js +261 -0
  49. package/lib/exchange/swap/hooks/useProviderRates.test.js.map +1 -0
  50. package/lib/exchange/swap/hooks/useReverseAccounts.d.ts +15 -0
  51. package/lib/exchange/swap/hooks/useReverseAccounts.d.ts.map +1 -0
  52. package/lib/exchange/swap/hooks/useReverseAccounts.js +35 -0
  53. package/lib/exchange/swap/hooks/useReverseAccounts.js.map +1 -0
  54. package/lib/exchange/swap/hooks/useReverseAccounts.test.d.ts +2 -0
  55. package/lib/exchange/swap/hooks/useReverseAccounts.test.d.ts.map +1 -0
  56. package/lib/exchange/swap/hooks/useReverseAccounts.test.js +79 -0
  57. package/lib/exchange/swap/hooks/useReverseAccounts.test.js.map +1 -0
  58. package/lib/exchange/swap/hooks/useSelectableCurrencies.d.ts +5 -0
  59. package/lib/exchange/swap/hooks/useSelectableCurrencies.d.ts.map +1 -0
  60. package/lib/exchange/swap/hooks/useSelectableCurrencies.js +43 -0
  61. package/lib/exchange/swap/hooks/useSelectableCurrencies.js.map +1 -0
  62. package/lib/exchange/swap/hooks/useSelectableCurrencies.test.d.ts +2 -0
  63. package/lib/exchange/swap/hooks/useSelectableCurrencies.test.d.ts.map +1 -0
  64. package/lib/exchange/swap/hooks/useSelectableCurrencies.test.js +32 -0
  65. package/lib/exchange/swap/hooks/useSelectableCurrencies.test.js.map +1 -0
  66. package/lib/exchange/swap/hooks/useSwapProviders.d.ts +14 -0
  67. package/lib/exchange/swap/hooks/useSwapProviders.d.ts.map +1 -0
  68. package/lib/exchange/swap/hooks/useSwapProviders.js +104 -0
  69. package/lib/exchange/swap/hooks/useSwapProviders.js.map +1 -0
  70. package/lib/exchange/swap/hooks/useSwapProviders.test.d.ts +2 -0
  71. package/lib/exchange/swap/hooks/useSwapProviders.test.d.ts.map +1 -0
  72. package/lib/exchange/swap/hooks/useSwapProviders.test.js +174 -0
  73. package/lib/exchange/swap/hooks/useSwapProviders.test.js.map +1 -0
  74. package/lib/exchange/swap/hooks/useSwapTransaction.d.ts +53 -0
  75. package/lib/exchange/swap/hooks/useSwapTransaction.d.ts.map +1 -0
  76. package/lib/exchange/swap/hooks/useSwapTransaction.js +109 -0
  77. package/lib/exchange/swap/hooks/useSwapTransaction.js.map +1 -0
  78. package/lib/exchange/swap/hooks/useSwapTransaction.test.d.ts +2 -0
  79. package/lib/exchange/swap/hooks/useSwapTransaction.test.d.ts.map +1 -0
  80. package/lib/exchange/swap/hooks/useSwapTransaction.test.js +50 -0
  81. package/lib/exchange/swap/hooks/useSwapTransaction.test.js.map +1 -0
  82. package/lib/exchange/swap/hooks/useToState.d.ts +12 -0
  83. package/lib/exchange/swap/hooks/useToState.d.ts.map +1 -0
  84. package/lib/exchange/swap/hooks/useToState.js +73 -0
  85. package/lib/exchange/swap/hooks/useToState.js.map +1 -0
  86. package/lib/exchange/swap/hooks/useToState.test.d.ts +2 -0
  87. package/lib/exchange/swap/hooks/useToState.test.d.ts.map +1 -0
  88. package/lib/exchange/swap/hooks/useToState.test.js +107 -0
  89. package/lib/exchange/swap/hooks/useToState.test.js.map +1 -0
  90. package/lib/exchange/swap/hooks/useUpdateMaxAmount.d.ts +15 -0
  91. package/lib/exchange/swap/hooks/useUpdateMaxAmount.d.ts.map +1 -0
  92. package/lib/exchange/swap/hooks/useUpdateMaxAmount.js +106 -0
  93. package/lib/exchange/swap/hooks/useUpdateMaxAmount.js.map +1 -0
  94. package/lib/exchange/swap/hooks/useUpdateMaxAmount.test.d.ts +2 -0
  95. package/lib/exchange/swap/hooks/useUpdateMaxAmount.test.d.ts.map +1 -0
  96. package/lib/exchange/swap/hooks/useUpdateMaxAmount.test.js +217 -0
  97. package/lib/exchange/swap/hooks/useUpdateMaxAmount.test.js.map +1 -0
  98. package/lib/exchange/swap/mock.d.ts +6 -2
  99. package/lib/exchange/swap/mock.d.ts.map +1 -1
  100. package/lib/exchange/swap/mock.js +21 -6
  101. package/lib/exchange/swap/mock.js.map +1 -1
  102. package/lib/exchange/swap/types.d.ts +1 -1
  103. package/lib/exchange/swap/types.d.ts.map +1 -1
  104. package/lib/exchange/swap/utils/index.d.ts +16 -0
  105. package/lib/exchange/swap/utils/index.d.ts.map +1 -0
  106. package/lib/exchange/swap/utils/index.js +49 -0
  107. package/lib/exchange/swap/utils/index.js.map +1 -0
  108. package/lib/exchange/swap/utils/index.test.d.ts +2 -0
  109. package/lib/exchange/swap/utils/index.test.d.ts.map +1 -0
  110. package/lib/exchange/swap/utils/index.test.js +238 -0
  111. package/lib/exchange/swap/utils/index.test.js.map +1 -0
  112. package/lib/families/crypto_org/datasets/croeseid.d.ts.map +1 -1
  113. package/lib/families/crypto_org/datasets/croeseid.js +2 -6
  114. package/lib/families/crypto_org/datasets/croeseid.js.map +1 -1
  115. package/lib/families/elrond/api/apiCalls.d.ts +0 -4
  116. package/lib/families/elrond/api/apiCalls.d.ts.map +1 -1
  117. package/lib/families/elrond/api/apiCalls.js +3 -37
  118. package/lib/families/elrond/api/apiCalls.js.map +1 -1
  119. package/lib/families/elrond/api/sdk.js +2 -2
  120. package/lib/families/elrond/api/sdk.js.map +1 -1
  121. package/lib/families/elrond/js-transaction.d.ts +2 -0
  122. package/lib/families/elrond/js-transaction.d.ts.map +1 -1
  123. package/lib/families/elrond/types.d.ts +2 -0
  124. package/lib/families/elrond/types.d.ts.map +1 -1
  125. package/lib/families/elrond/types.js.map +1 -1
  126. package/lib/families/tezos/bridge/js.d.ts.map +1 -1
  127. package/lib/families/tezos/bridge/js.js +11 -1
  128. package/lib/families/tezos/bridge/js.js.map +1 -1
  129. package/lib/mock/account.d.ts +2 -1
  130. package/lib/mock/account.d.ts.map +1 -1
  131. package/lib/mock/account.js +4 -2
  132. package/lib/mock/account.js.map +1 -1
  133. package/package.json +15 -15
  134. package/src/__tests__/__snapshots__/all.libcore.ts.snap +10 -10
  135. package/src/currencies/__snapshots__/sortByMarketcap.test.ts.snap +30 -15
  136. package/src/env.ts +1 -1
  137. package/src/exchange/swap/getExchangeRates.ts +8 -5
  138. package/src/exchange/swap/hooks/index.ts +10 -0
  139. package/src/exchange/swap/hooks/useFromState.test.ts +134 -0
  140. package/src/exchange/swap/hooks/useFromState.ts +84 -0
  141. package/src/exchange/swap/hooks/usePickDefaultAccount.test.ts +167 -0
  142. package/src/exchange/swap/hooks/usePickDefaultAccount.ts +47 -0
  143. package/src/exchange/swap/hooks/usePickDefaultCurrency.test.ts +107 -0
  144. package/src/exchange/swap/hooks/usePickDefaultCurrency.ts +20 -0
  145. package/src/exchange/swap/hooks/usePollKYCStatus.test.ts +89 -0
  146. package/src/exchange/swap/hooks/usePollKYCStatus.ts +43 -0
  147. package/src/exchange/swap/hooks/useProviderRates.test.ts +200 -0
  148. package/src/exchange/swap/hooks/useProviderRates.ts +130 -0
  149. package/src/exchange/swap/hooks/useReverseAccounts.test.ts +83 -0
  150. package/src/exchange/swap/hooks/useReverseAccounts.ts +56 -0
  151. package/src/exchange/swap/hooks/useSelectableCurrencies.test.ts +39 -0
  152. package/src/exchange/swap/hooks/useSelectableCurrencies.ts +26 -0
  153. package/src/exchange/swap/hooks/useSwapProviders.test.ts +113 -0
  154. package/src/exchange/swap/hooks/useSwapProviders.ts +57 -0
  155. package/src/exchange/swap/hooks/useSwapTransaction.test.ts +54 -0
  156. package/src/exchange/swap/hooks/useSwapTransaction.ts +170 -0
  157. package/src/exchange/swap/hooks/useToState.test.ts +53 -0
  158. package/src/exchange/swap/hooks/useToState.ts +86 -0
  159. package/src/exchange/swap/hooks/useUpdateMaxAmount.test.ts +132 -0
  160. package/src/exchange/swap/hooks/useUpdateMaxAmount.ts +67 -0
  161. package/src/exchange/swap/mock.ts +22 -3
  162. package/src/exchange/swap/types.ts +2 -1
  163. package/src/exchange/swap/utils/index.test.ts +224 -0
  164. package/src/exchange/swap/utils/index.ts +67 -0
  165. package/src/families/crypto_org/datasets/croeseid.ts +7 -9
  166. package/src/families/elrond/api/apiCalls.ts +3 -31
  167. package/src/families/elrond/api/sdk.ts +2 -2
  168. package/src/families/elrond/types.ts +2 -0
  169. package/src/families/tezos/bridge/js.ts +13 -0
  170. package/src/mock/account.ts +2 -2
@@ -0,0 +1,170 @@
1
+ import { useMemo } from "react";
2
+ import { BigNumber } from "bignumber.js";
3
+ import useBridgeTransaction, {
4
+ Result as UseBridgeTransactionReturnType,
5
+ } from "../../../bridge/useBridgeTransaction";
6
+ import type {
7
+ Account,
8
+ TokenAccount,
9
+ TokenCurrency,
10
+ CryptoCurrency,
11
+ } from "../../../types";
12
+ import { ExchangeRate } from "../types";
13
+ import { AmountRequired } from "@ledgerhq/errors";
14
+ import { useUpdateMaxAmount } from "./useUpdateMaxAmount";
15
+ import {
16
+ RatesReducerState,
17
+ useFromState,
18
+ useProviderRates,
19
+ useToState,
20
+ } from ".";
21
+ import { useReverseAccounts } from "./useReverseAccounts";
22
+
23
+ export type SwapSelectorStateType = {
24
+ currency: null | undefined | TokenCurrency | CryptoCurrency;
25
+ account: null | undefined | Account | TokenAccount;
26
+ parentAccount: null | undefined | Account;
27
+ amount: null | undefined | BigNumber;
28
+ };
29
+ export type SwapDataType = {
30
+ from: SwapSelectorStateType;
31
+ to: SwapSelectorStateType;
32
+ isMaxEnabled: boolean;
33
+ isSwapReversable: boolean;
34
+ rates: RatesReducerState;
35
+ refetchRates: () => void;
36
+ targetAccounts?: Account[];
37
+ };
38
+ export const selectorStateDefaultValues = {
39
+ currency: null,
40
+ account: null,
41
+ parentAccount: null,
42
+ amount: null,
43
+ };
44
+
45
+ export type SwapTransactionType = UseBridgeTransactionReturnType & {
46
+ swap: SwapDataType;
47
+ setFromAccount: (account: SwapSelectorStateType["account"]) => void;
48
+ setToAccount: (
49
+ currency: SwapSelectorStateType["currency"],
50
+ account: SwapSelectorStateType["account"],
51
+ parentAccount: SwapSelectorStateType["parentAccount"]
52
+ ) => void;
53
+ setFromAmount: (amount: BigNumber) => void;
54
+ setToAmount: (amount: BigNumber) => void;
55
+ setToCurrency: (currency: SwapSelectorStateType["currency"]) => void;
56
+ toggleMax: () => void;
57
+ reverseSwap: () => void;
58
+ fromAmountError?: Error;
59
+ };
60
+
61
+ export type OnNoRatesCallback = (arg: {
62
+ fromState: SwapSelectorStateType;
63
+ toState: SwapSelectorStateType;
64
+ }) => void;
65
+ export type SetExchangeRateCallback = (
66
+ exchangeRate?: ExchangeRate | null
67
+ ) => void;
68
+
69
+ export const useFromAmountError = (
70
+ errors: Record<string, Error | undefined>
71
+ ): Error | undefined => {
72
+ const fromAmountError = useMemo(() => {
73
+ const [error] = [errors?.gasPrice, errors?.amount]
74
+ .filter(Boolean)
75
+ .filter((error) => !(error instanceof AmountRequired));
76
+
77
+ return error;
78
+ }, [errors?.gasPrice, errors?.amount]);
79
+
80
+ return fromAmountError;
81
+ };
82
+
83
+ export const useSwapTransaction = ({
84
+ accounts,
85
+ exchangeRate,
86
+ setExchangeRate,
87
+ defaultCurrency = selectorStateDefaultValues.currency,
88
+ defaultAccount = selectorStateDefaultValues.account,
89
+ defaultParentAccount = selectorStateDefaultValues.parentAccount,
90
+ onNoRates,
91
+ }: {
92
+ accounts?: Account[];
93
+ exchangeRate?: ExchangeRate;
94
+ setExchangeRate?: SetExchangeRateCallback;
95
+ defaultCurrency?: SwapSelectorStateType["currency"];
96
+ defaultAccount?: SwapSelectorStateType["account"];
97
+ defaultParentAccount?: SwapSelectorStateType["parentAccount"];
98
+ onNoRates?: OnNoRatesCallback;
99
+ } = {}): SwapTransactionType => {
100
+ const bridgeTransaction = useBridgeTransaction(() => ({
101
+ account: defaultAccount,
102
+ parentAccount: defaultParentAccount,
103
+ }));
104
+ const { fromState, setFromAccount, setFromAmount } = useFromState({
105
+ accounts,
106
+ defaultCurrency,
107
+ defaultAccount,
108
+ defaultParentAccount,
109
+ bridgeTransaction,
110
+ });
111
+ const { toState, setToAccount, setToAmount, setToCurrency, targetAccounts } =
112
+ useToState({ accounts });
113
+ const {
114
+ account: fromAccount,
115
+ parentAccount: fromParentAccount,
116
+ currency: fromCurrency,
117
+ } = fromState;
118
+ const { account: toAccount } = toState;
119
+ const transaction = bridgeTransaction?.transaction;
120
+
121
+ const fromAmountError = useFromAmountError(bridgeTransaction.status.errors);
122
+
123
+ const { isSwapReversable, reverseSwap } = useReverseAccounts({
124
+ accounts,
125
+ fromAccount,
126
+ toAccount,
127
+ fromParentAccount,
128
+ fromCurrency,
129
+ setFromAccount,
130
+ setToAccount,
131
+ });
132
+
133
+ const { isMaxEnabled, toggleMax } = useUpdateMaxAmount({
134
+ setFromAmount,
135
+ account: fromAccount,
136
+ parentAccount: fromParentAccount,
137
+ transaction,
138
+ feesStrategy: transaction?.feesStrategy,
139
+ });
140
+
141
+ const { rates, refetchRates } = useProviderRates({
142
+ fromState,
143
+ toState,
144
+ exchangeRate,
145
+ transaction,
146
+ onNoRates,
147
+ setExchangeRate,
148
+ });
149
+
150
+ return {
151
+ ...bridgeTransaction,
152
+ swap: {
153
+ to: toState,
154
+ from: fromState,
155
+ isMaxEnabled,
156
+ isSwapReversable,
157
+ rates,
158
+ refetchRates,
159
+ targetAccounts,
160
+ },
161
+ setFromAmount,
162
+ toggleMax,
163
+ fromAmountError,
164
+ setToAccount,
165
+ setToCurrency,
166
+ setFromAccount,
167
+ setToAmount,
168
+ reverseSwap,
169
+ };
170
+ };
@@ -0,0 +1,53 @@
1
+ import { renderHook, act } from "@testing-library/react-hooks";
2
+ import { getCryptoCurrencyById, getTokenById } from "@ledgerhq/cryptoassets";
3
+ import { selectorStateDefaultValues, useToState } from ".";
4
+ import { genAccount, genTokenAccount } from "../../../mock/account";
5
+ import { Account } from "../../../types";
6
+ import BigNumber from "bignumber.js";
7
+
8
+ const BTC = getCryptoCurrencyById("bitcoin");
9
+ const ETH = getCryptoCurrencyById("ethereum");
10
+ const USDT = getTokenById("ethereum/erc20/usd_tether__erc20_");
11
+
12
+ const accounts: Account[] = [
13
+ genAccount("mocked-account-1", { currency: BTC }),
14
+ genAccount("mocked-account-2", { currency: ETH }),
15
+ ];
16
+ const subAccount = genTokenAccount(1, accounts[1], USDT);
17
+
18
+ describe("useToState", () => {
19
+ const defaultProps = { accounts };
20
+
21
+ it("should initialize a blank state", () => {
22
+ const { result } = renderHook(useToState, { initialProps: defaultProps });
23
+ expect(result.current.toState).toMatchObject(selectorStateDefaultValues);
24
+ });
25
+
26
+ it("should set the account", async () => {
27
+ const [currency, account, parentAccount] = [USDT, subAccount, accounts[1]];
28
+ const { result } = renderHook(useToState, { initialProps: defaultProps });
29
+ act(() => result.current.setToAccount(currency, account, parentAccount));
30
+ expect(result.current.toState).toMatchObject({
31
+ account,
32
+ parentAccount,
33
+ currency,
34
+ });
35
+ });
36
+
37
+ it("should set the amount", () => {
38
+ const amount = new BigNumber(10);
39
+ const { result } = renderHook(useToState, { initialProps: defaultProps });
40
+ act(() => result.current.setToAmount(amount));
41
+ expect(result.current.toState.amount).toBe(amount);
42
+ });
43
+
44
+ it("should set the currency", () => {
45
+ const { result } = renderHook(useToState, { initialProps: defaultProps });
46
+ act(() => result.current.setToCurrency(BTC));
47
+ expect(result.current.toState).toMatchObject({
48
+ account: accounts[0],
49
+ parentAccount: null,
50
+ currency: BTC,
51
+ });
52
+ });
53
+ });
@@ -0,0 +1,86 @@
1
+ import { useCallback, useMemo, useState } from "react";
2
+ import {
3
+ selectorStateDefaultValues,
4
+ SwapDataType,
5
+ SwapSelectorStateType,
6
+ SwapTransactionType,
7
+ } from ".";
8
+ import { Account } from "../../../types";
9
+ import { getAccountTuplesForCurrency } from "../utils";
10
+
11
+ export const useToState = ({
12
+ accounts,
13
+ }: {
14
+ accounts: Account[] | undefined;
15
+ }): {
16
+ toState: SwapSelectorStateType;
17
+ setToAccount: SwapTransactionType["setToAccount"];
18
+ setToAmount: SwapTransactionType["setToAmount"];
19
+ setToCurrency: SwapTransactionType["setToCurrency"];
20
+ targetAccounts: SwapDataType["targetAccounts"];
21
+ } => {
22
+ const [toState, setToState] = useState<SwapSelectorStateType>(
23
+ selectorStateDefaultValues
24
+ );
25
+
26
+ /* UPDATE to accounts */
27
+ const setToAccount: SwapTransactionType["setToAccount"] = useCallback(
28
+ (currency, account, parentAccount) =>
29
+ setToState({
30
+ ...selectorStateDefaultValues,
31
+ currency,
32
+ account,
33
+ parentAccount,
34
+ }),
35
+ []
36
+ );
37
+
38
+ /* Get the list of possible target accounts given the target currency. */
39
+ const getTargetAccountsPairs = useCallback(
40
+ (currency) =>
41
+ currency &&
42
+ accounts &&
43
+ getAccountTuplesForCurrency(currency, accounts, false),
44
+ [accounts]
45
+ );
46
+ const targetAccounts = useMemo(
47
+ () =>
48
+ getTargetAccountsPairs(toState.currency)?.map(
49
+ ({ account, subAccount }) => subAccount || account
50
+ ),
51
+ [toState.currency, getTargetAccountsPairs]
52
+ );
53
+
54
+ const setToCurrency: SwapTransactionType["setToCurrency"] = useCallback(
55
+ (currency) => {
56
+ const targetAccountsPairs = getTargetAccountsPairs(currency);
57
+ const accountPair = targetAccountsPairs && targetAccountsPairs[0];
58
+ const account =
59
+ accountPair && (accountPair.subAccount || accountPair.account);
60
+ const parentAccount =
61
+ accountPair && accountPair.subAccount && accountPair.account;
62
+
63
+ setToState({
64
+ ...selectorStateDefaultValues,
65
+ currency,
66
+ account,
67
+ parentAccount,
68
+ });
69
+ },
70
+ [getTargetAccountsPairs]
71
+ );
72
+
73
+ const setToAmount: SwapTransactionType["setToAmount"] = useCallback(
74
+ (amount) =>
75
+ setToState((previousState) => ({ ...previousState, amount: amount })),
76
+ []
77
+ );
78
+
79
+ return {
80
+ toState,
81
+ setToAccount,
82
+ setToAmount,
83
+ setToCurrency,
84
+ targetAccounts,
85
+ };
86
+ };
@@ -0,0 +1,132 @@
1
+ import { renderHook, act } from "@testing-library/react-hooks";
2
+ import { getCryptoCurrencyById, getTokenById } from "@ledgerhq/cryptoassets";
3
+ import { mocked } from "ts-jest/utils";
4
+ import { useUpdateMaxAmount, ZERO } from "./useUpdateMaxAmount";
5
+ import { genAccount, genTokenAccount } from "../../../mock/account";
6
+ import BigNumber from "bignumber.js";
7
+ import ethBridge from "../../../families/ethereum/bridge/mock";
8
+ import { checkAccountSupported } from "../../../account/support";
9
+
10
+ // Needs to be mocked since userSupportedCurrencies is initially empty.
11
+ jest.mock("../../../account/support");
12
+ const mockedCheckAccount = mocked(checkAccountSupported);
13
+ // Mock to use a custom estimate value and test the result.
14
+ jest.mock("../../../families/ethereum/bridge/mock");
15
+ const mockedEstimateMaxSpendable = mocked(
16
+ ethBridge.accountBridge.estimateMaxSpendable,
17
+ true
18
+ );
19
+
20
+ const ETH = getCryptoCurrencyById("ethereum");
21
+ const USDT = getTokenById("ethereum/erc20/usd_tether__erc20_");
22
+
23
+ const parentAccount = genAccount("parent-account", {
24
+ currency: ETH,
25
+ });
26
+ const account = genTokenAccount(1, parentAccount, USDT);
27
+
28
+ describe("updateAmountUsingMax", () => {
29
+ const setFromAmount = jest.fn();
30
+
31
+ const defaultProps = {
32
+ setFromAmount,
33
+ account,
34
+ parentAccount,
35
+ transaction: { amount: new BigNumber(1) } as any,
36
+ feesStrategy: "slow" as any,
37
+ };
38
+
39
+ beforeAll(() => {
40
+ mockedCheckAccount.mockImplementation(() => null);
41
+ });
42
+
43
+ afterAll(() => {
44
+ mockedCheckAccount.mockReset();
45
+ });
46
+
47
+ beforeEach(() => {
48
+ setFromAmount.mockClear();
49
+ });
50
+
51
+ const wait = () => new Promise((resolve) => setTimeout(resolve, 500));
52
+
53
+ it("should toggle the amount", async () => {
54
+ const amount = new BigNumber(0.5);
55
+ mockedEstimateMaxSpendable.mockResolvedValue(amount);
56
+ const { result } = renderHook(useUpdateMaxAmount, {
57
+ initialProps: defaultProps,
58
+ });
59
+
60
+ expect(result.current.isMaxEnabled).toBe(false);
61
+ expect(setFromAmount).toBeCalledTimes(0);
62
+ act(() => result.current.toggleMax());
63
+ expect(result.current.isMaxEnabled).toBe(true);
64
+
65
+ // Lest resort solution, since waitFor and other helpers will not work here.
66
+ await wait();
67
+
68
+ expect(setFromAmount).toBeCalledTimes(1);
69
+ expect(setFromAmount.mock.calls[0][0]).toBe(amount);
70
+ setFromAmount.mockClear();
71
+
72
+ act(() => result.current.toggleMax());
73
+ expect(result.current.isMaxEnabled).toBe(false);
74
+
75
+ await wait();
76
+
77
+ expect(setFromAmount).toBeCalledTimes(1);
78
+ expect(setFromAmount.mock.calls[0][0]).toBe(ZERO);
79
+ });
80
+
81
+ it("should update the max amount whenever the dependencies change", async () => {
82
+ const { result, rerender } = renderHook(useUpdateMaxAmount, {
83
+ initialProps: defaultProps,
84
+ });
85
+
86
+ const feesGenerator = (function* feesGenerator() {
87
+ const feesArray = ["medium", "fast", "custom", "slow"];
88
+ let index = 0;
89
+ while (true) {
90
+ yield feesArray[index];
91
+ index = (index + 1) % feesArray.length;
92
+ }
93
+ })();
94
+
95
+ // setFromAmount, account, parentAccount, feesStrategy
96
+ const propsVariants = [
97
+ {
98
+ ...defaultProps,
99
+ account: { ...account },
100
+ },
101
+ {
102
+ ...defaultProps,
103
+ parentAccount: { ...parentAccount },
104
+ },
105
+ {
106
+ ...defaultProps,
107
+ feesStrategy: feesGenerator.next().value,
108
+ },
109
+ ];
110
+
111
+ // Updating dependencies when the toggle is off should not do anything.
112
+ propsVariants.forEach(rerender);
113
+ expect(setFromAmount).toBeCalledTimes(0);
114
+
115
+ mockedEstimateMaxSpendable.mockResolvedValue(new BigNumber(0));
116
+ act(() => result.current.toggleMax());
117
+ await wait();
118
+
119
+ // Checking that updating dependencies update the max amount when the toggle is on.
120
+ let idx = 1;
121
+ for await (const props of propsVariants) {
122
+ const amount = new BigNumber(idx);
123
+ setFromAmount.mockReset();
124
+ mockedEstimateMaxSpendable.mockResolvedValue(amount);
125
+ rerender(props);
126
+ await wait();
127
+ expect(setFromAmount).toBeCalledTimes(1);
128
+ expect(setFromAmount.mock.calls[0][0]).toBe(amount);
129
+ idx += 1;
130
+ }
131
+ });
132
+ });
@@ -0,0 +1,67 @@
1
+ import { useCallback, useEffect, useState } from "react";
2
+ import { getAccountBridge } from "../../../bridge";
3
+
4
+ import {
5
+ SwapTransactionType,
6
+ SwapDataType,
7
+ SwapSelectorStateType,
8
+ } from "./useSwapTransaction";
9
+ import { Transaction } from "../../../generated/types";
10
+ import BigNumber from "bignumber.js";
11
+
12
+ export const ZERO = new BigNumber(0);
13
+
14
+ export const useUpdateMaxAmount = ({
15
+ setFromAmount,
16
+ account,
17
+ parentAccount,
18
+ transaction,
19
+ feesStrategy,
20
+ }: {
21
+ setFromAmount: SwapTransactionType["setFromAmount"];
22
+ account: SwapSelectorStateType["account"];
23
+ parentAccount: SwapSelectorStateType["parentAccount"];
24
+ transaction: SwapTransactionType["transaction"];
25
+ feesStrategy: Transaction["feesStrategy"];
26
+ }): {
27
+ isMaxEnabled: SwapDataType["isMaxEnabled"];
28
+ toggleMax: SwapTransactionType["toggleMax"];
29
+ } => {
30
+ const [isMaxEnabled, setMax] = useState<SwapDataType["isMaxEnabled"]>(false);
31
+
32
+ const toggleMax: SwapTransactionType["toggleMax"] = useCallback(
33
+ () =>
34
+ setMax((previous) => {
35
+ if (previous) {
36
+ setFromAmount(ZERO);
37
+ }
38
+ return !previous;
39
+ }),
40
+ [setFromAmount]
41
+ );
42
+
43
+ /* UPDATE from amount to the estimate max spendable on account
44
+ change when the amount feature is enabled */
45
+ useEffect(
46
+ () => {
47
+ const updateAmountUsingMax = async () => {
48
+ if (!account) return;
49
+ const bridge = getAccountBridge(account, parentAccount);
50
+ const amount = await bridge.estimateMaxSpendable({
51
+ account,
52
+ parentAccount,
53
+ transaction,
54
+ });
55
+ setFromAmount(amount);
56
+ };
57
+
58
+ if (isMaxEnabled) {
59
+ updateAmountUsingMax();
60
+ }
61
+ },
62
+ // eslint-disable-next-line react-hooks/exhaustive-deps
63
+ [setFromAmount, isMaxEnabled, account, parentAccount, feesStrategy]
64
+ );
65
+
66
+ return { isMaxEnabled, toggleMax };
67
+ };
@@ -7,7 +7,7 @@ import type {
7
7
  SwapRequestEvent,
8
8
  } from "./types";
9
9
  import { getAccountUnit } from "../../account";
10
- import type { Transaction } from "../../types";
10
+ import type { Transaction, TokenCurrency, CryptoCurrency } from "../../types";
11
11
  import { formatCurrencyUnit } from "../../currencies";
12
12
  import {
13
13
  SwapExchangeRateAmountTooLow,
@@ -16,14 +16,33 @@ import {
16
16
  import { Observable, of } from "rxjs";
17
17
  import { getSwapAPIBaseURL } from "./";
18
18
 
19
+ export const getMockExchangeRate = ({
20
+ provider = "changelly",
21
+ tradeMethod = "fixed",
22
+ }: {
23
+ provider?: string;
24
+ tradeMethod?: "fixed" | "float";
25
+ } = {}): ExchangeRate => ({
26
+ rate: new BigNumber("1"),
27
+ toAmount: new BigNumber("12"),
28
+ magnitudeAwareRate: new BigNumber(1)
29
+ .div(new BigNumber(10).pow(18))
30
+ .times(new BigNumber(10).pow(8)),
31
+ rateId: "mockedRateId",
32
+ provider,
33
+ tradeMethod,
34
+ });
35
+
19
36
  export const mockGetExchangeRates = async (
20
37
  exchange: Exchange,
21
- transaction: Transaction
38
+ transaction: Transaction,
39
+ currencyTo?: TokenCurrency | CryptoCurrency | undefined | null
22
40
  ): Promise<(ExchangeRate & { expirationDate?: Date })[]> => {
23
41
  const { fromAccount, toAccount } = exchange;
24
42
  const amount = transaction.amount;
25
43
  const unitFrom = getAccountUnit(fromAccount);
26
- const unitTo = getAccountUnit(toAccount);
44
+ const unitTo =
45
+ (currencyTo && currencyTo.units[0]) ?? getAccountUnit(toAccount);
27
46
  const tenPowMagnitude = new BigNumber(10).pow(unitFrom.magnitude);
28
47
  const amountFrom = amount.div(tenPowMagnitude);
29
48
  const minAmountFrom = new BigNumber(0.0001);
@@ -85,7 +85,8 @@ export type AvailableProvider = AvailableProviderV2 | AvailableProviderV3;
85
85
  export type GetExchangeRates = (
86
86
  arg0: Exchange,
87
87
  arg1: Transaction,
88
- wyreUserId?: string
88
+ wyreUserId?: string,
89
+ currencyTo?: TokenCurrency | CryptoCurrency | undefined | null
89
90
  ) => Promise<ExchangeRate[]>;
90
91
  export type GetProviders = () => Promise<AvailableProvider[]>;
91
92
  export type InitSwapResult = {