@rango-dev/widget-embedded 0.1.10-next.100

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 (204) hide show
  1. package/dist/App.d.ts +9 -0
  2. package/dist/App.d.ts.map +1 -0
  3. package/dist/QueueManager.d.ts +4 -0
  4. package/dist/QueueManager.d.ts.map +1 -0
  5. package/dist/components/AppRouter.d.ts +9 -0
  6. package/dist/components/AppRouter.d.ts.map +1 -0
  7. package/dist/components/AppRoutes.d.ts +8 -0
  8. package/dist/components/AppRoutes.d.ts.map +1 -0
  9. package/dist/components/BottomLogo.d.ts +3 -0
  10. package/dist/components/BottomLogo.d.ts.map +1 -0
  11. package/dist/components/ChangeSlippageButton.d.ts +3 -0
  12. package/dist/components/ChangeSlippageButton.d.ts.map +1 -0
  13. package/dist/components/ConfirmSwapErrors.d.ts +4 -0
  14. package/dist/components/ConfirmSwapErrors.d.ts.map +1 -0
  15. package/dist/components/ConfirmSwapWarnings.d.ts +4 -0
  16. package/dist/components/ConfirmSwapWarnings.d.ts.map +1 -0
  17. package/dist/components/Footer.d.ts +2 -0
  18. package/dist/components/Footer.d.ts.map +1 -0
  19. package/dist/components/Header.d.ts +10 -0
  20. package/dist/components/Header.d.ts.map +1 -0
  21. package/dist/components/HeaderButtons.d.ts +4 -0
  22. package/dist/components/HeaderButtons.d.ts.map +1 -0
  23. package/dist/components/Layout.d.ts +7 -0
  24. package/dist/components/Layout.d.ts.map +1 -0
  25. package/dist/components/RoutesOverview.d.ts +10 -0
  26. package/dist/components/RoutesOverview.d.ts.map +1 -0
  27. package/dist/components/SwitchFromAndTo.d.ts +4 -0
  28. package/dist/components/SwitchFromAndTo.d.ts.map +1 -0
  29. package/dist/components/TokenInfo.d.ts +18 -0
  30. package/dist/components/TokenInfo.d.ts.map +1 -0
  31. package/dist/components/TokenPreview.d.ts +20 -0
  32. package/dist/components/TokenPreview.d.ts.map +1 -0
  33. package/dist/components/UpdateUrl.d.ts +2 -0
  34. package/dist/components/UpdateUrl.d.ts.map +1 -0
  35. package/dist/components/warnings/BalanceWarnings.d.ts +7 -0
  36. package/dist/components/warnings/BalanceWarnings.d.ts.map +1 -0
  37. package/dist/components/warnings/ConfirmSwapExtraMessages.d.ts +7 -0
  38. package/dist/components/warnings/ConfirmSwapExtraMessages.d.ts.map +1 -0
  39. package/dist/components/warnings/HighSlippageWarning.d.ts +7 -0
  40. package/dist/components/warnings/HighSlippageWarning.d.ts.map +1 -0
  41. package/dist/components/warnings/MinRequiredSlippage.d.ts +7 -0
  42. package/dist/components/warnings/MinRequiredSlippage.d.ts.map +1 -0
  43. package/dist/constants/errors.d.ts +4 -0
  44. package/dist/constants/errors.d.ts.map +1 -0
  45. package/dist/constants/navigationRoutes.d.ts +15 -0
  46. package/dist/constants/navigationRoutes.d.ts.map +1 -0
  47. package/dist/constants/numbers.d.ts +3 -0
  48. package/dist/constants/numbers.d.ts.map +1 -0
  49. package/dist/constants/searchParams.d.ts +8 -0
  50. package/dist/constants/searchParams.d.ts.map +1 -0
  51. package/dist/constants/swapSettings.d.ts +6 -0
  52. package/dist/constants/swapSettings.d.ts.map +1 -0
  53. package/dist/globalStyles.d.ts +3 -0
  54. package/dist/globalStyles.d.ts.map +1 -0
  55. package/dist/hooks/useConfirmSwap.d.ts +11 -0
  56. package/dist/hooks/useConfirmSwap.d.ts.map +1 -0
  57. package/dist/hooks/useCopyToClipboard.d.ts +2 -0
  58. package/dist/hooks/useCopyToClipboard.d.ts.map +1 -0
  59. package/dist/hooks/useNavigateBack.d.ts +4 -0
  60. package/dist/hooks/useNavigateBack.d.ts.map +1 -0
  61. package/dist/hooks/usePrevious.d.ts +2 -0
  62. package/dist/hooks/usePrevious.d.ts.map +1 -0
  63. package/dist/hooks/useSelectLanguage.d.ts +5 -0
  64. package/dist/hooks/useSelectLanguage.d.ts.map +1 -0
  65. package/dist/hooks/useTheme.d.ts +8 -0
  66. package/dist/hooks/useTheme.d.ts.map +1 -0
  67. package/dist/i18n.d.ts +3 -0
  68. package/dist/i18n.d.ts.map +1 -0
  69. package/dist/index.d.ts +2 -0
  70. package/dist/index.d.ts.map +1 -0
  71. package/dist/index.js +8 -0
  72. package/dist/lib.d.ts +8 -0
  73. package/dist/lib.d.ts.map +1 -0
  74. package/dist/mockData/pendingSwap.d.ts +2 -0
  75. package/dist/mockData/pendingSwap.d.ts.map +1 -0
  76. package/dist/pages/ConfirmSwapPage.d.ts +3 -0
  77. package/dist/pages/ConfirmSwapPage.d.ts.map +1 -0
  78. package/dist/pages/ConfirmWalletsPage.d.ts +3 -0
  79. package/dist/pages/ConfirmWalletsPage.d.ts.map +1 -0
  80. package/dist/pages/HistoryPage.d.ts +3 -0
  81. package/dist/pages/HistoryPage.d.ts.map +1 -0
  82. package/dist/pages/Home.d.ts +9 -0
  83. package/dist/pages/Home.d.ts.map +1 -0
  84. package/dist/pages/LiquiditySourcesPage.d.ts +8 -0
  85. package/dist/pages/LiquiditySourcesPage.d.ts.map +1 -0
  86. package/dist/pages/SelectChainPage.d.ts +9 -0
  87. package/dist/pages/SelectChainPage.d.ts.map +1 -0
  88. package/dist/pages/SelectTokenPage.d.ts +15 -0
  89. package/dist/pages/SelectTokenPage.d.ts.map +1 -0
  90. package/dist/pages/SettingsPage.d.ts +8 -0
  91. package/dist/pages/SettingsPage.d.ts.map +1 -0
  92. package/dist/pages/SwapDetailsPage.d.ts +3 -0
  93. package/dist/pages/SwapDetailsPage.d.ts.map +1 -0
  94. package/dist/pages/WalletsPage.d.ts +9 -0
  95. package/dist/pages/WalletsPage.d.ts.map +1 -0
  96. package/dist/services/httpService.d.ts +3 -0
  97. package/dist/services/httpService.d.ts.map +1 -0
  98. package/dist/store/bestRoute.d.ts +28 -0
  99. package/dist/store/bestRoute.d.ts.map +1 -0
  100. package/dist/store/meta.d.ts +9 -0
  101. package/dist/store/meta.d.ts.map +1 -0
  102. package/dist/store/selectors.d.ts +11 -0
  103. package/dist/store/selectors.d.ts.map +1 -0
  104. package/dist/store/settings.d.ts +17 -0
  105. package/dist/store/settings.d.ts.map +1 -0
  106. package/dist/store/ui.d.ts +2 -0
  107. package/dist/store/ui.d.ts.map +1 -0
  108. package/dist/store/wallets.d.ts +28 -0
  109. package/dist/store/wallets.d.ts.map +1 -0
  110. package/dist/types/config.d.ts +40 -0
  111. package/dist/types/config.d.ts.map +1 -0
  112. package/dist/types/index.d.ts +4 -0
  113. package/dist/types/index.d.ts.map +1 -0
  114. package/dist/types/routing.d.ts +45 -0
  115. package/dist/types/routing.d.ts.map +1 -0
  116. package/dist/types/swap.d.ts +11 -0
  117. package/dist/types/swap.d.ts.map +1 -0
  118. package/dist/utils/common.d.ts +4 -0
  119. package/dist/utils/common.d.ts.map +1 -0
  120. package/dist/utils/numbers.d.ts +14 -0
  121. package/dist/utils/numbers.d.ts.map +1 -0
  122. package/dist/utils/queue.d.ts +4 -0
  123. package/dist/utils/queue.d.ts.map +1 -0
  124. package/dist/utils/routing.d.ts +18 -0
  125. package/dist/utils/routing.d.ts.map +1 -0
  126. package/dist/utils/swap.d.ts +45 -0
  127. package/dist/utils/swap.d.ts.map +1 -0
  128. package/dist/utils/wallets.d.ts +29 -0
  129. package/dist/utils/wallets.d.ts.map +1 -0
  130. package/dist/widget-embedded.cjs.development.js +3101 -0
  131. package/dist/widget-embedded.cjs.development.js.map +1 -0
  132. package/dist/widget-embedded.cjs.production.min.js +3101 -0
  133. package/dist/widget-embedded.cjs.production.min.js.map +1 -0
  134. package/dist/widget-embedded.esm.js +3092 -0
  135. package/dist/widget-embedded.esm.js.map +1 -0
  136. package/package.json +55 -0
  137. package/readme.md +2 -0
  138. package/src/App.tsx +91 -0
  139. package/src/QueueManager.tsx +94 -0
  140. package/src/app.css +27 -0
  141. package/src/components/AppRouter.tsx +60 -0
  142. package/src/components/AppRoutes.tsx +105 -0
  143. package/src/components/BottomLogo.tsx +47 -0
  144. package/src/components/ChangeSlippageButton.tsx +19 -0
  145. package/src/components/ConfirmSwapErrors.tsx +38 -0
  146. package/src/components/ConfirmSwapWarnings.tsx +35 -0
  147. package/src/components/Footer.tsx +8 -0
  148. package/src/components/Header.tsx +37 -0
  149. package/src/components/HeaderButtons.tsx +47 -0
  150. package/src/components/Layout.tsx +96 -0
  151. package/src/components/RoutesOverview.tsx +60 -0
  152. package/src/components/SwitchFromAndTo.tsx +30 -0
  153. package/src/components/TokenInfo.tsx +311 -0
  154. package/src/components/TokenPreview.tsx +175 -0
  155. package/src/components/UpdateUrl.tsx +162 -0
  156. package/src/components/warnings/BalanceWarnings.tsx +39 -0
  157. package/src/components/warnings/ConfirmSwapExtraMessages.tsx +20 -0
  158. package/src/components/warnings/HighSlippageWarning.tsx +18 -0
  159. package/src/components/warnings/MinRequiredSlippage.tsx +18 -0
  160. package/src/constants/errors.ts +3 -0
  161. package/src/constants/navigationRoutes.ts +14 -0
  162. package/src/constants/numbers.ts +3 -0
  163. package/src/constants/searchParams.ts +7 -0
  164. package/src/constants/swapSettings.ts +9 -0
  165. package/src/globalStyles.ts +26 -0
  166. package/src/hooks/useConfirmSwap.ts +260 -0
  167. package/src/hooks/useCopyToClipboard.ts +23 -0
  168. package/src/hooks/useNavigateBack.ts +40 -0
  169. package/src/hooks/usePrevious.ts +13 -0
  170. package/src/hooks/useSelectLanguage.ts +15 -0
  171. package/src/hooks/useTheme.ts +127 -0
  172. package/src/i18n.js +30 -0
  173. package/src/index.tsx +14 -0
  174. package/src/languages/en.json +14 -0
  175. package/src/languages/tr.json +11 -0
  176. package/src/lib.tsx +119 -0
  177. package/src/mockData/pendingSwap.ts +607 -0
  178. package/src/pages/ConfirmSwapPage.tsx +72 -0
  179. package/src/pages/ConfirmWalletsPage.tsx +127 -0
  180. package/src/pages/HistoryPage.tsx +29 -0
  181. package/src/pages/Home.tsx +228 -0
  182. package/src/pages/LiquiditySourcesPage.tsx +64 -0
  183. package/src/pages/SelectChainPage.tsx +42 -0
  184. package/src/pages/SelectTokenPage.tsx +64 -0
  185. package/src/pages/SettingsPage.tsx +98 -0
  186. package/src/pages/SwapDetailsPage.tsx +38 -0
  187. package/src/pages/WalletsPage.tsx +119 -0
  188. package/src/services/httpService.ts +5 -0
  189. package/src/store/bestRoute.ts +245 -0
  190. package/src/store/meta.ts +35 -0
  191. package/src/store/selectors.ts +19 -0
  192. package/src/store/settings.ts +84 -0
  193. package/src/store/ui.ts +21 -0
  194. package/src/store/wallets.ts +190 -0
  195. package/src/types/config.ts +44 -0
  196. package/src/types/index.ts +3 -0
  197. package/src/types/routing.ts +60 -0
  198. package/src/types/swap.ts +13 -0
  199. package/src/utils/common.ts +35 -0
  200. package/src/utils/numbers.ts +133 -0
  201. package/src/utils/queue.ts +24 -0
  202. package/src/utils/routing.ts +150 -0
  203. package/src/utils/swap.ts +552 -0
  204. package/src/utils/wallets.ts +481 -0
@@ -0,0 +1,552 @@
1
+ import { PendingSwap } from '@rango-dev/ui/dist/containers/History/types';
2
+ import {
3
+ WalletTypeAndAddress,
4
+ SwapSavedSettings,
5
+ } from '@rango-dev/ui/dist/types/swaps';
6
+ import BigNumber from 'bignumber.js';
7
+ import {
8
+ BestRouteRequest,
9
+ BestRouteResponse,
10
+ RecommendedSlippage,
11
+ SwapResult,
12
+ MetaResponse,
13
+ Token,
14
+ } from 'rango-sdk';
15
+ import { Account } from '../store/wallets';
16
+ import { ZERO } from '../constants/numbers';
17
+ import { numberToString } from './numbers';
18
+ import { WalletType } from '@rango-dev/wallets-shared';
19
+ import { getRequiredBalanceOfWallet } from './routing';
20
+ import { getRequiredChains, SelectedWallet } from './wallets';
21
+ import { LoadingStatus } from '../store/meta';
22
+ import { SwapButtonState } from '../types';
23
+
24
+ export function getOutputRatio(
25
+ inputUsdValue: BigNumber,
26
+ outputUsdValue: BigNumber
27
+ ) {
28
+ if (inputUsdValue.lte(ZERO) || outputUsdValue.lte(ZERO)) return 0;
29
+ return outputUsdValue.div(inputUsdValue).minus(1).multipliedBy(100);
30
+ }
31
+
32
+ export function outputRatioHasWarning(
33
+ inputUsdValue: BigNumber,
34
+ outputRatio: BigNumber | 0
35
+ ) {
36
+ return (
37
+ (parseInt(outputRatio.toFixed(2) || '0') <= -10 &&
38
+ inputUsdValue.gte(new BigNumber(400))) ||
39
+ (parseInt(outputRatio.toFixed(2) || '0') <= -5 &&
40
+ inputUsdValue.gte(new BigNumber(1000)))
41
+ );
42
+ }
43
+
44
+ export function hasLimitError(bestRoute: BestRouteResponse | null): boolean {
45
+ return (
46
+ (bestRoute?.result?.swaps || []).filter((swap) => {
47
+ const minimum = !!swap.fromAmountMinValue
48
+ ? new BigNumber(swap.fromAmountMinValue)
49
+ : null;
50
+ const maximum = !!swap.fromAmountMaxValue
51
+ ? new BigNumber(swap.fromAmountMaxValue)
52
+ : null;
53
+ const isExclusive = swap.fromAmountRestrictionType === 'EXCLUSIVE';
54
+ if (isExclusive) {
55
+ return minimum?.gte(swap.fromAmount) || maximum?.lte(swap.fromAmount);
56
+ } else {
57
+ return minimum?.gt(swap.fromAmount) || maximum?.lt(swap.fromAmount);
58
+ }
59
+ }).length > 0
60
+ );
61
+ }
62
+
63
+ export function LimitErrorMessage(bestRoute: BestRouteResponse | null): {
64
+ swap: SwapResult | null;
65
+ fromAmountRangeError: string;
66
+ recommendation: string;
67
+ } {
68
+ if (!bestRoute)
69
+ return { swap: null, fromAmountRangeError: '', recommendation: '' };
70
+ const swap = (bestRoute?.result?.swaps || []).filter((swap) => {
71
+ const minimum = !!swap.fromAmountMinValue
72
+ ? new BigNumber(swap.fromAmountMinValue)
73
+ : null;
74
+ const maximum = !!swap.fromAmountMaxValue
75
+ ? new BigNumber(swap.fromAmountMaxValue)
76
+ : null;
77
+ const isExclusive = swap.fromAmountRestrictionType === 'EXCLUSIVE';
78
+ if (isExclusive) {
79
+ return minimum?.gte(swap.fromAmount) || maximum?.lte(swap.fromAmount);
80
+ } else {
81
+ return minimum?.gt(swap.fromAmount) || maximum?.lt(swap.fromAmount);
82
+ }
83
+ })[0];
84
+ if (!swap)
85
+ return { swap: null, fromAmountRangeError: '', recommendation: '' };
86
+ const minimum = !!swap.fromAmountMinValue
87
+ ? new BigNumber(swap.fromAmountMinValue)
88
+ : null;
89
+ const maximum = !!swap.fromAmountMaxValue
90
+ ? new BigNumber(swap.fromAmountMaxValue)
91
+ : null;
92
+ const isExclusive = swap.fromAmountRestrictionType === 'EXCLUSIVE';
93
+
94
+ let fromAmountRangeError = '';
95
+ let recommendation = '';
96
+ if (!isExclusive && !!minimum && minimum.gt(swap.fromAmount)) {
97
+ fromAmountRangeError = `Required: >= ${numberToString(minimum)} ${
98
+ swap.from.symbol
99
+ }`;
100
+ recommendation = 'Increase your swap amount';
101
+ } else if (isExclusive && !!minimum && minimum.gte(swap.fromAmount)) {
102
+ fromAmountRangeError = `Required: > ${numberToString(minimum)} ${
103
+ swap.from.symbol
104
+ }`;
105
+ recommendation = 'Increase your swap amount';
106
+ }
107
+
108
+ if (!isExclusive && !!maximum && maximum.lt(swap.fromAmount)) {
109
+ fromAmountRangeError = `Required: <= ${numberToString(maximum)} ${
110
+ swap.from.symbol
111
+ }`;
112
+ recommendation = 'Decrease your swap amount';
113
+ } else if (isExclusive && !!maximum && maximum.lte(swap.fromAmount)) {
114
+ fromAmountRangeError = `Required: < ${numberToString(maximum)} ${
115
+ swap.from.symbol
116
+ }`;
117
+ recommendation = 'Decrease your swap amount';
118
+ }
119
+
120
+ return { swap, fromAmountRangeError, recommendation };
121
+ }
122
+
123
+ export function getSwapButtonState(
124
+ loadingMetaStatus: LoadingStatus,
125
+ accounts: Account[],
126
+ loading: boolean,
127
+ bestRoute: BestRouteResponse | null,
128
+ hasLimitError: boolean,
129
+ highValueLoss: boolean,
130
+ priceImpactCanNotBeComputed: boolean,
131
+ needsToWarnEthOnPath: boolean,
132
+ inputIsZero: boolean
133
+ ): SwapButtonState {
134
+ if (loadingMetaStatus !== 'success')
135
+ return { title: 'Connect Wallet', disabled: true };
136
+ if (accounts.length == 0) return { title: 'Connect Wallet', disabled: false };
137
+ if (loading) return { title: 'Finding Best Route...', disabled: true };
138
+ else if (inputIsZero) return { title: 'Enter an amount', disabled: true };
139
+ else if (!bestRoute) return { title: 'Swap', disabled: true };
140
+ else if (hasLimitError) return { title: 'Limit Error', disabled: true };
141
+ else if (highValueLoss)
142
+ return { title: 'Price impact is too high!', disabled: true };
143
+ else if (priceImpactCanNotBeComputed)
144
+ return {
145
+ title: 'USD price is unknown, price impact might be high!',
146
+ disabled: false,
147
+ hasWarning: true,
148
+ };
149
+ else if (needsToWarnEthOnPath)
150
+ return {
151
+ title: 'The route goes through Ethereum. Continue?',
152
+ disabled: false,
153
+ hasWarning: true,
154
+ };
155
+ else return { title: 'Swap', disabled: false };
156
+ }
157
+
158
+ export function canComputePriceImpact(
159
+ bestRoute: BestRouteResponse | null,
160
+ inputAmount: string,
161
+ inputUsdValue: BigNumber,
162
+ outputUsdValue: BigNumber
163
+ ) {
164
+ return !(
165
+ (inputUsdValue.lte(ZERO) || outputUsdValue.lte(ZERO)) &&
166
+ !!bestRoute?.result &&
167
+ !!inputAmount &&
168
+ inputAmount !== '0' &&
169
+ parseFloat(inputAmount || '0') !== 0 &&
170
+ !!bestRoute.result
171
+ );
172
+ }
173
+
174
+ export function calculatePendingSwap(
175
+ inputAmount: string,
176
+ bestRoute: BestRouteResponse,
177
+ wallets: { [p: string]: WalletTypeAndAddress },
178
+ settings: Omit<SwapSavedSettings, 'disabledSwappersIds'>,
179
+ validateBalanceOrFee: boolean,
180
+ meta: MetaResponse
181
+ ): PendingSwap {
182
+ const simulationResult = bestRoute.result;
183
+ if (!simulationResult) throw Error('Simulation result should not be null');
184
+
185
+ return {
186
+ creationTime: new Date().getTime().toString(),
187
+ finishTime: null,
188
+ requestId: bestRoute.requestId || '',
189
+ inputAmount: inputAmount,
190
+ wallets,
191
+ status: 'running',
192
+ isPaused: false,
193
+ extraMessage: null,
194
+ extraMessageSeverity: null,
195
+ extraMessageDetail: null,
196
+ extraMessageErrorCode: null,
197
+ networkStatusExtraMessage: null,
198
+ networkStatusExtraMessageDetail: null,
199
+ lastNotificationTime: null,
200
+ //@ts-ignore
201
+ settings: settings,
202
+ simulationResult: simulationResult,
203
+ validateBalanceOrFee,
204
+ steps:
205
+ bestRoute.result?.swaps?.map((swap, index) => {
206
+ const swapper = meta.swappers.find(
207
+ (swapper) => swapper.id === swap.swapperId
208
+ );
209
+ const swapperType = swapper?.types[0];
210
+ const fromBlockchain = meta.blockchains.find(
211
+ (blockchain) => blockchain.name === swap.from.blockchain
212
+ );
213
+ const toBlockchain = meta.blockchains.find(
214
+ (blockchain) => blockchain.name === swap.to.blockchain
215
+ );
216
+ return {
217
+ id: index + 1,
218
+ fromBlockchain: swap.from.blockchain,
219
+ fromSymbol: swap.from.symbol,
220
+ fromSymbolAddress: swap.from.address,
221
+ fromDecimals: swap.from.decimals,
222
+ fromAmountPrecision: swap.fromAmountPrecision,
223
+ fromAmountMinValue: swap.fromAmountMinValue,
224
+ fromAmountMaxValue: swap.fromAmountMaxValue,
225
+ toBlockchain: swap.to.blockchain,
226
+ fromLogo: swap.from.logo,
227
+ toSymbol: swap.to.symbol,
228
+ toSymbolAddress: swap.to.address,
229
+ toDecimals: swap.to.decimals,
230
+ toLogo: swap.to.logo,
231
+ startTransactionTime: new Date().getTime(),
232
+ swapperId: swap.swapperId,
233
+ feeInUsd: numberToString(getUsdFeeOfStep(swap, meta.tokens), null, 2),
234
+ expectedOutputAmountHumanReadable: swap.toAmount,
235
+ outputAmount: '',
236
+ status: 'created',
237
+ networkStatus: null,
238
+ executedTransactionId: null,
239
+ externalTransactionId: null,
240
+ explorerUrl: null,
241
+ trackingCode: null,
242
+ cosmosTransaction: null,
243
+ solanaTransaction: null,
244
+ starknetTransaction: null,
245
+ starknetApprovalTransaction: null,
246
+ tronTransaction: null,
247
+ tronApprovalTransaction: null,
248
+ evmTransaction: null,
249
+ evmApprovalTransaction: null,
250
+ transferTransaction: null,
251
+ diagnosisUrl: null,
252
+ internalSteps: null,
253
+ fromBlockchainLogo: fromBlockchain?.logo || '',
254
+ toBlockchainLogo: toBlockchain?.logo || '',
255
+ swapperLogo: swapper?.logo || '',
256
+ swapperType: swapperType || '',
257
+ };
258
+ }) || [],
259
+ };
260
+ }
261
+
262
+ export function requiredWallets(route: BestRouteResponse | null) {
263
+ const wallets: string[] = [];
264
+
265
+ route?.result?.swaps.forEach((swap) => {
266
+ const currentStepFromBlockchain = swap.from.blockchain;
267
+ const currentStepToBlockchain = swap.to.blockchain;
268
+ let lastAddedWallet = wallets[wallets.length - 1];
269
+ if (currentStepFromBlockchain != lastAddedWallet)
270
+ wallets.push(currentStepFromBlockchain);
271
+ lastAddedWallet = wallets[wallets.length - 1];
272
+ if (currentStepToBlockchain != lastAddedWallet)
273
+ wallets.push(currentStepToBlockchain);
274
+ });
275
+ return wallets;
276
+ }
277
+
278
+ export const getUsdPrice = (
279
+ blockchain: string,
280
+ symbol: string,
281
+ address: string | null,
282
+ allTokens: Token[]
283
+ ): number | null => {
284
+ const token = allTokens?.find(
285
+ (t) =>
286
+ t.blockchain === blockchain &&
287
+ t.symbol?.toUpperCase() === symbol?.toUpperCase() &&
288
+ t.address === address
289
+ );
290
+ return token?.usdPrice || null;
291
+ };
292
+
293
+ export function getUsdFeeOfStep(
294
+ step: SwapResult,
295
+ allTokens: Token[]
296
+ ): BigNumber {
297
+ let totalFeeInUsd = ZERO;
298
+ for (let i = 0; i < step.fee.length; i++) {
299
+ const fee = step.fee[i];
300
+ if (fee.expenseType === 'DECREASE_FROM_OUTPUT') continue;
301
+
302
+ const unitPrice = getUsdPrice(
303
+ fee.asset.blockchain,
304
+ fee.asset.symbol,
305
+ fee.asset.address,
306
+ allTokens
307
+ );
308
+ totalFeeInUsd = totalFeeInUsd.plus(
309
+ new BigNumber(fee.amount).multipliedBy(unitPrice || 0)
310
+ );
311
+ }
312
+
313
+ return totalFeeInUsd;
314
+ }
315
+
316
+ export function getTotalFeeInUsd(
317
+ bestRoute: BestRouteResponse | null,
318
+ allTokens: Token[]
319
+ ): BigNumber | null {
320
+ return (
321
+ bestRoute?.result?.swaps.reduce(
322
+ (totalFee: BigNumber, step) =>
323
+ totalFee.plus(getUsdFeeOfStep(step, allTokens)),
324
+ ZERO
325
+ ) || null
326
+ );
327
+ }
328
+
329
+ export function hasHighFee(totalFeeInUsd: BigNumber | null) {
330
+ if (!totalFeeInUsd) return false;
331
+ return !totalFeeInUsd.lt(new BigNumber(30));
332
+ }
333
+
334
+ export function hasSlippageError(
335
+ slippages: (RecommendedSlippage | null)[] | undefined
336
+ ) {
337
+ return (slippages?.filter((s) => !!s?.error)?.length || 0) > 0;
338
+ }
339
+
340
+ export function getMinRequiredSlippage(
341
+ route: BestRouteResponse
342
+ ): number | null {
343
+ const slippages = route.result?.swaps.map(
344
+ (slippage) => slippage.recommendedSlippage
345
+ );
346
+ return (
347
+ slippages
348
+ ?.map((s) => parseFloat(s?.slippage || '0'))
349
+ ?.filter((s) => s > 0)
350
+ ?.sort((a, b) => b - a)
351
+ ?.find(() => true) || null
352
+ );
353
+ }
354
+
355
+ export function hasProperSlippage(
356
+ userSlippage: string,
357
+ minRequiredSlippage: number | null
358
+ ) {
359
+ if (!minRequiredSlippage) return true;
360
+ //@ts-ignore
361
+ return parseFloat(userSlippage) >= parseFloat(minRequiredSlippage);
362
+ }
363
+
364
+ export function hasEnoughBalance(
365
+ route: BestRouteResponse,
366
+ selectedWallets: SelectedWallet[]
367
+ ) {
368
+ const fee = route.validationStatus;
369
+
370
+ if (fee === null || fee.length === 0) return true;
371
+
372
+ for (const wallet of selectedWallets) {
373
+ const requiredAssets = getRequiredBalanceOfWallet(wallet, fee);
374
+ if (!requiredAssets) continue;
375
+
376
+ const enoughBalanceInWallet = requiredAssets
377
+ .map((asset) => asset.ok)
378
+ .reduce((previous, current) => previous && current);
379
+ if (!enoughBalanceInWallet) return false;
380
+ }
381
+
382
+ return true;
383
+ }
384
+
385
+ export function hasEnoughBalanceAndProperSlippage(
386
+ route: BestRouteResponse,
387
+ selectedWallets: SelectedWallet[],
388
+ userSlippage: string,
389
+ minRequiredSlippage: number | null
390
+ ): boolean {
391
+ return (
392
+ hasEnoughBalance(route, selectedWallets) &&
393
+ hasProperSlippage(userSlippage, minRequiredSlippage)
394
+ );
395
+ }
396
+
397
+ export function createBestRouteRequestBody(
398
+ fromToken: Token,
399
+ toToken: Token,
400
+ inputAmount: string,
401
+ wallets: Account[],
402
+ selectedWallets: SelectedWallet[],
403
+ disabledLiquiditySources: string[],
404
+ slippage: number,
405
+ checkPrerequisites: boolean
406
+ ): BestRouteRequest {
407
+ const selectedWalletsMap = selectedWallets.reduce(
408
+ (
409
+ selectedWalletsMap: BestRouteRequest['selectedWallets'],
410
+ selectedWallet
411
+ ) => (
412
+ (selectedWalletsMap[selectedWallet.chain] = selectedWallet.address),
413
+ selectedWalletsMap
414
+ ),
415
+ {}
416
+ );
417
+
418
+ const connectedWallets: BestRouteRequest['connectedWallets'] = [];
419
+
420
+ wallets.forEach((wallet) => {
421
+ const chainAndAccounts = connectedWallets.find(
422
+ (connectedWallet) => connectedWallet.blockchain === wallet.chain
423
+ );
424
+ if (!!chainAndAccounts) chainAndAccounts.addresses.push(wallet.address);
425
+ else
426
+ connectedWallets.push({
427
+ blockchain: wallet.chain,
428
+ addresses: [wallet.address],
429
+ });
430
+ });
431
+
432
+ const requestBody: BestRouteRequest = {
433
+ amount: inputAmount.toString(),
434
+ checkPrerequisites,
435
+ from: {
436
+ address: fromToken.address,
437
+ blockchain: fromToken.blockchain,
438
+ symbol: fromToken.symbol,
439
+ },
440
+ to: {
441
+ address: toToken.address,
442
+ blockchain: toToken.blockchain,
443
+ symbol: toToken.symbol,
444
+ },
445
+ connectedWallets,
446
+ selectedWallets: selectedWalletsMap,
447
+ swapperGroups: disabledLiquiditySources,
448
+ swappersGroupsExclude: true,
449
+ //@ts-ignore
450
+ slippage: slippage.toString(),
451
+ };
452
+
453
+ return requestBody;
454
+ }
455
+
456
+ export function getWalletsForNewSwap(selectedWallets: SelectedWallet[]) {
457
+ const wallets = selectedWallets.reduce(
458
+ (
459
+ selectedWalletsMap: {
460
+ [p: string]: { address: string; walletType: WalletType };
461
+ },
462
+ selectedWallet
463
+ ) => (
464
+ (selectedWalletsMap[selectedWallet.chain] = {
465
+ address: selectedWallet.address,
466
+ walletType: selectedWallet.walletType,
467
+ }),
468
+ selectedWalletsMap
469
+ ),
470
+ {}
471
+ );
472
+
473
+ return wallets;
474
+ }
475
+
476
+ export function getRouteOutputAmount(route: BestRouteResponse | null) {
477
+ return route?.result?.outputAmount || null;
478
+ }
479
+
480
+ export function getPercentageChange(
481
+ oldValue: string | number | null,
482
+ newValue: string | number | null
483
+ ) {
484
+ if (!oldValue || !newValue) return null;
485
+ return new BigNumber(newValue)
486
+ .div(new BigNumber(oldValue))
487
+ .minus(1)
488
+ .multipliedBy(100);
489
+ }
490
+
491
+ export function isOutputAmountChangedALot(
492
+ oldRoute: BestRouteResponse,
493
+ newRoute: BestRouteResponse
494
+ ) {
495
+ const oldOutputAmount = getRouteOutputAmount(oldRoute);
496
+ const newOutputAmount = getRouteOutputAmount(newRoute);
497
+ if (!oldOutputAmount || !newOutputAmount) return false;
498
+ const percentageChange = getPercentageChange(
499
+ oldOutputAmount,
500
+ newOutputAmount
501
+ );
502
+ if (!percentageChange) return true;
503
+
504
+ return percentageChange.toNumber() <= -1;
505
+ }
506
+
507
+ export function getBalanceWarnings(
508
+ route: BestRouteResponse,
509
+ selectedWallets: SelectedWallet[]
510
+ ) {
511
+ const fee = route.validationStatus;
512
+ const requiredWallets = getRequiredChains(route);
513
+ const walletsSortedByRequiredWallets = selectedWallets.sort(
514
+ (selectedWallet1, selectedWallet2) =>
515
+ requiredWallets.indexOf(selectedWallet1.chain) -
516
+ requiredWallets.indexOf(selectedWallet2.chain)
517
+ );
518
+ return walletsSortedByRequiredWallets
519
+ .flatMap((wallet) => getRequiredBalanceOfWallet(wallet, fee) || [])
520
+ .filter((asset) => !asset.ok)
521
+ .map((asset) => {
522
+ const symbol = asset.asset.symbol;
523
+ const currentAmount = numberToString(
524
+ new BigNumber(asset.currentAmount.amount).shiftedBy(
525
+ -asset.currentAmount.decimals
526
+ ),
527
+ 8
528
+ );
529
+ const requiredAmount = numberToString(
530
+ new BigNumber(asset.requiredAmount.amount).shiftedBy(
531
+ -asset.requiredAmount.decimals
532
+ ),
533
+ 8
534
+ );
535
+ let reason = '';
536
+ if (asset.reason === 'FEE') reason = ' for network fee';
537
+ if (asset.reason === 'INPUT_ASSET') reason = ' for swap';
538
+ if (asset.reason === 'FEE_AND_INPUT_ASSET')
539
+ reason = ' for input and network fee';
540
+ const warningMessage = `Needs ≈ ${requiredAmount} ${symbol}${reason}, but you have ${currentAmount} ${symbol} in your ${asset.asset.blockchain} wallet.`;
541
+ return warningMessage;
542
+ });
543
+ }
544
+
545
+ export function calcOutputUsdValue(
546
+ outputAmount?: string,
547
+ tokenPrice?: number | null
548
+ ) {
549
+ const amount = !!outputAmount ? new BigNumber(outputAmount) : ZERO;
550
+
551
+ return amount.multipliedBy(tokenPrice || 0);
552
+ }