@rango-dev/widget-embedded 0.1.10-next.80 → 0.1.10-next.81

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