@rango-dev/widget-embedded 0.1.10-next.99 → 0.1.11-next.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 (105) hide show
  1. package/dist/App.d.ts.map +1 -1
  2. package/dist/QueueManager.d.ts.map +1 -1
  3. package/dist/components/AppRouter.d.ts +6 -1
  4. package/dist/components/AppRouter.d.ts.map +1 -1
  5. package/dist/components/AppRoutes.d.ts.map +1 -1
  6. package/dist/components/HeaderButtons.d.ts +4 -1
  7. package/dist/components/HeaderButtons.d.ts.map +1 -1
  8. package/dist/components/Layout.d.ts.map +1 -1
  9. package/dist/components/PercentageChange.d.ts +9 -0
  10. package/dist/components/PercentageChange.d.ts.map +1 -0
  11. package/dist/components/SwapDetailsPlaceholder.d.ts +9 -0
  12. package/dist/components/SwapDetailsPlaceholder.d.ts.map +1 -0
  13. package/dist/components/TokenInfo.d.ts.map +1 -1
  14. package/dist/components/TokenPreview.d.ts +3 -2
  15. package/dist/components/TokenPreview.d.ts.map +1 -1
  16. package/dist/components/UpdateUrl.d.ts.map +1 -1
  17. package/dist/components/warnings/BalanceWarnings.d.ts.map +1 -1
  18. package/dist/components/warnings/MinRequiredSlippage.d.ts +1 -1
  19. package/dist/components/warnings/MinRequiredSlippage.d.ts.map +1 -1
  20. package/dist/constants/navigationRoutes.d.ts +0 -1
  21. package/dist/constants/navigationRoutes.d.ts.map +1 -1
  22. package/dist/globalStyles.d.ts.map +1 -1
  23. package/dist/hooks/useConfirmSwap.d.ts.map +1 -1
  24. package/dist/lib.d.ts.map +1 -1
  25. package/dist/pages/ConfirmSwapPage.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/SelectTokenPage.d.ts.map +1 -1
  30. package/dist/pages/SettingsPage.d.ts.map +1 -1
  31. package/dist/pages/SwapDetailsPage.d.ts.map +1 -1
  32. package/dist/pages/WalletsPage.d.ts +1 -0
  33. package/dist/pages/WalletsPage.d.ts.map +1 -1
  34. package/dist/store/bestRoute.d.ts +3 -0
  35. package/dist/store/bestRoute.d.ts.map +1 -1
  36. package/dist/store/ui.d.ts.map +1 -1
  37. package/dist/store/wallets.d.ts +14 -0
  38. package/dist/store/wallets.d.ts.map +1 -1
  39. package/dist/types/routing.d.ts +15 -2
  40. package/dist/types/routing.d.ts.map +1 -1
  41. package/dist/types/swap.d.ts +6 -0
  42. package/dist/types/swap.d.ts.map +1 -1
  43. package/dist/utils/common.d.ts +1 -0
  44. package/dist/utils/common.d.ts.map +1 -1
  45. package/dist/utils/date.d.ts +3 -0
  46. package/dist/utils/date.d.ts.map +1 -0
  47. package/dist/utils/routing.d.ts +3 -2
  48. package/dist/utils/routing.d.ts.map +1 -1
  49. package/dist/utils/swap.d.ts +16 -5
  50. package/dist/utils/swap.d.ts.map +1 -1
  51. package/dist/utils/time.d.ts +4 -0
  52. package/dist/utils/time.d.ts.map +1 -0
  53. package/dist/utils/wallets.d.ts +1 -1
  54. package/dist/utils/wallets.d.ts.map +1 -1
  55. package/dist/widget-embedded.cjs.development.js +1122 -719
  56. package/dist/widget-embedded.cjs.development.js.map +1 -1
  57. package/dist/widget-embedded.cjs.production.min.js +1122 -719
  58. package/dist/widget-embedded.cjs.production.min.js.map +1 -1
  59. package/dist/widget-embedded.esm.js +1131 -728
  60. package/dist/widget-embedded.esm.js.map +1 -1
  61. package/package.json +12 -11
  62. package/readme.md +1 -2
  63. package/src/App.tsx +30 -5
  64. package/src/QueueManager.tsx +5 -2
  65. package/src/components/AppRouter.tsx +24 -13
  66. package/src/components/AppRoutes.tsx +15 -12
  67. package/src/components/HeaderButtons.tsx +9 -2
  68. package/src/components/Layout.tsx +37 -5
  69. package/src/components/PercentageChange.tsx +33 -0
  70. package/src/components/SwapDetailsPlaceholder.tsx +32 -0
  71. package/src/components/TokenInfo.tsx +20 -4
  72. package/src/components/TokenPreview.tsx +17 -6
  73. package/src/components/UpdateUrl.tsx +1 -3
  74. package/src/components/warnings/BalanceWarnings.tsx +1 -0
  75. package/src/components/warnings/MinRequiredSlippage.tsx +9 -4
  76. package/src/constants/navigationRoutes.ts +0 -1
  77. package/src/globalStyles.ts +2 -1
  78. package/src/hooks/useConfirmSwap.ts +2 -1
  79. package/src/hooks/useNavigateBack.ts +3 -3
  80. package/src/lib.tsx +25 -3
  81. package/src/pages/ConfirmSwapPage.tsx +133 -20
  82. package/src/pages/HistoryPage.tsx +4 -4
  83. package/src/pages/Home.tsx +27 -22
  84. package/src/pages/LiquiditySourcesPage.tsx +2 -0
  85. package/src/pages/SelectTokenPage.tsx +3 -1
  86. package/src/pages/SettingsPage.tsx +3 -0
  87. package/src/pages/SwapDetailsPage.tsx +142 -6
  88. package/src/pages/WalletsPage.tsx +47 -11
  89. package/src/store/bestRoute.ts +143 -16
  90. package/src/store/ui.ts +4 -0
  91. package/src/store/wallets.ts +4 -1
  92. package/src/types/routing.ts +18 -2
  93. package/src/types/swap.ts +7 -0
  94. package/src/utils/common.ts +14 -0
  95. package/src/utils/date.ts +62 -0
  96. package/src/utils/routing.ts +36 -20
  97. package/src/utils/swap.ts +103 -11
  98. package/src/utils/time.ts +52 -0
  99. package/src/utils/wallets.ts +13 -4
  100. package/dist/components/Header.d.ts +0 -10
  101. package/dist/components/Header.d.ts.map +0 -1
  102. package/dist/pages/ConfirmWalletsPage.d.ts +0 -3
  103. package/dist/pages/ConfirmWalletsPage.d.ts.map +0 -1
  104. package/src/components/Header.tsx +0 -37
  105. package/src/pages/ConfirmWalletsPage.tsx +0 -127
@@ -1,4 +1,4 @@
1
- import React from 'react';
1
+ import React, { useEffect, useState } from 'react';
2
2
  import { navigationRoutes } from '../constants/navigationRoutes';
3
3
  import useCopyToClipboard from '../hooks/useCopyToClipboard';
4
4
  import { useManager } from '@rango-dev/queue-manager-react';
@@ -6,33 +6,169 @@ import { useNavigateBack } from '../hooks/useNavigateBack';
6
6
  import { getPendingSwaps } from '../utils/queue';
7
7
  import { SwapHistory } from '@rango-dev/ui';
8
8
  import { useUiStore } from '../store/ui';
9
- import { cancelSwap } from '@rango-dev/queue-manager-rango-preset';
9
+ import {
10
+ cancelSwap,
11
+ PendingSwapNetworkStatus,
12
+ } from '@rango-dev/queue-manager-rango-preset';
13
+ import { useWallets } from '@rango-dev/wallets-core';
14
+ import {
15
+ getCurrentBlockchainOfOrNull,
16
+ getCurrentStep,
17
+ getRelatedWalletOrNull,
18
+ } from '@rango-dev/queue-manager-rango-preset';
19
+ import { getSwapDate } from '../utils/time';
20
+ import { useNavigate } from 'react-router-dom';
21
+ import { useBestRouteStore } from '../store/bestRoute';
22
+ import {
23
+ getLastConvertedTokenInFailedSwap,
24
+ getSwapMessages,
25
+ isNetworkStatusInWarningState,
26
+ shouldRetrySwap,
27
+ } from '../utils/swap';
28
+ import { TokenPreview } from '../components/TokenPreview';
29
+ import { Spacer } from '@rango-dev/ui';
30
+ import { numberToString } from '../utils/numbers';
31
+ //@ts-ignore
32
+ import { t } from 'i18next';
33
+ import { SwapDetailsPlaceholder } from '../components/SwapDetailsPlaceholder';
10
34
 
11
35
  export function SwapDetailsPage() {
12
36
  const selectedSwapRequestId = useUiStore.use.selectedSwapRequestId();
37
+ const { canSwitchNetworkTo, connect } = useWallets();
38
+ const retry = useBestRouteStore.use.retry();
39
+ const navigate = useNavigate();
13
40
  const { navigateBackFrom } = useNavigateBack();
14
- const { manager } = useManager();
15
41
  const [isCopied, handleCopy] = useCopyToClipboard(2000);
42
+ const { manager } = useManager();
43
+
44
+ const [loading, setLoading] = useState(true);
45
+
46
+ useEffect(() => {
47
+ setTimeout(() => {
48
+ setLoading(false);
49
+ }, 5000);
50
+ }, []);
16
51
 
17
52
  const pendingSwaps = getPendingSwaps(manager);
18
53
  const selectedSwap = pendingSwaps.find(
19
54
  ({ swap }) => swap.requestId === selectedSwapRequestId
20
55
  );
21
56
 
22
- //TODO: implement swap cancellation (move queueManager logic to queueManager/rango-preset)
23
57
  const onCancel = () => {
24
- const swap = selectedSwap ? manager?.get(selectedSwap.id) : undefined;
58
+ const swap = manager?.get(selectedSwap?.id!);
25
59
  if (swap) cancelSwap(swap);
26
60
  };
61
+ const swap = selectedSwap?.swap;
62
+
63
+ if (!swap)
64
+ return (
65
+ <SwapDetailsPlaceholder
66
+ requestId={selectedSwapRequestId || ''}
67
+ loading={loading}
68
+ onBack={navigateBackFrom.bind(null, navigationRoutes.swapDetails)}
69
+ />
70
+ );
71
+
72
+ const firstStep = swap.steps[0];
73
+ const lastStep = swap.steps[swap.steps.length - 1];
74
+ const fromAmount = numberToString(swap.inputAmount);
75
+ const toAmount = numberToString(swap.simulationResult.outputAmount);
76
+
77
+ const currentStep = getCurrentStep(swap);
78
+
79
+ const currentStepBlockchain = currentStep
80
+ ? getCurrentBlockchainOfOrNull(swap, currentStep)
81
+ : null;
82
+ const currentStepWallet = currentStep
83
+ ? getRelatedWalletOrNull(swap, currentStep)
84
+ : null;
85
+ const currentStepNetworkStatus = currentStep?.networkStatus;
86
+
87
+ const swapMessages = getSwapMessages(swap, currentStep);
88
+
89
+ const networkWarningState = isNetworkStatusInWarningState(currentStep);
90
+
91
+ const swapDate = getSwapDate(swap);
92
+
93
+ const shouldRetry = shouldRetrySwap(swap);
94
+
95
+ const switchNetwork =
96
+ !!currentStepBlockchain &&
97
+ !!currentStepWallet?.walletType &&
98
+ currentStepNetworkStatus ===
99
+ PendingSwapNetworkStatus.WaitingForNetworkChange &&
100
+ canSwitchNetworkTo(currentStepWallet?.walletType, currentStepBlockchain)
101
+ ? connect.bind(null, currentStepWallet.walletType, currentStepBlockchain)
102
+ : undefined;
103
+
104
+ const lastConvertedTokenInFailedSwap =
105
+ getLastConvertedTokenInFailedSwap(swap);
106
+
27
107
  return (
28
108
  <SwapHistory
29
109
  onBack={navigateBackFrom.bind(null, navigationRoutes.swapDetails)}
110
+ previewInputs={
111
+ <>
112
+ <TokenPreview
113
+ chain={{
114
+ displayName: firstStep?.fromBlockchain || '',
115
+ // @ts-ignore
116
+ logo: firstStep?.fromBlockchainLogo || '',
117
+ }}
118
+ token={{
119
+ symbol: firstStep?.fromSymbol || '',
120
+ image: firstStep?.fromLogo || '',
121
+ }}
122
+ amount={fromAmount}
123
+ label={t('From')}
124
+ loadingStatus={'success'}
125
+ />
126
+ <Spacer size={12} direction="vertical" />
127
+ <TokenPreview
128
+ chain={{
129
+ displayName: lastStep?.toBlockchain || '',
130
+ // @ts-ignore
131
+ logo: lastStep?.toBlockchainLogo || '',
132
+ }}
133
+ token={{
134
+ symbol: lastStep?.toSymbol || '',
135
+ image: lastStep?.toLogo || '',
136
+ }}
137
+ amount={toAmount}
138
+ label={t('To')}
139
+ loadingStatus={'success'}
140
+ />
141
+ </>
142
+ }
30
143
  //todo: move PendingSwap type to rango-types
31
144
  //@ts-ignore
32
- pendingSwap={selectedSwap?.swap}
145
+ pendingSwap={swap}
33
146
  onCopy={handleCopy}
34
147
  isCopied={isCopied}
35
148
  onCancel={onCancel}
149
+ shortMessage={swapMessages.shortMessage}
150
+ detailedMessage={swapMessages.detailedMessage}
151
+ currentStepBlockchain={currentStepBlockchain || ''}
152
+ switchNetwork={switchNetwork}
153
+ type={
154
+ networkWarningState ? 'warning' : swap.extraMessageSeverity || undefined
155
+ }
156
+ date={swapDate}
157
+ {...(shouldRetry && {
158
+ onRetry: () => {
159
+ retry(swap);
160
+ setTimeout(() => {
161
+ navigate(navigationRoutes.home);
162
+ }, 0);
163
+ },
164
+ })}
165
+ {...(lastConvertedTokenInFailedSwap && {
166
+ lastConvertedTokenInFailedSwap: {
167
+ blockchain: lastConvertedTokenInFailedSwap.blockchain,
168
+ outputAmount: lastConvertedTokenInFailedSwap.outputAmount || '',
169
+ symbol: lastConvertedTokenInFailedSwap.symbol,
170
+ },
171
+ })}
36
172
  />
37
173
  );
38
174
  }
@@ -4,8 +4,9 @@ import {
4
4
  styled,
5
5
  Wallet,
6
6
  WalletState,
7
+ WalletInfo,
7
8
  } from '@rango-dev/ui';
8
- import React, { useEffect, useState } from 'react';
9
+ import React, { useEffect, useRef, useState } from 'react';
9
10
  import { getlistWallet, sortWalletsBasedOnState } from '../utils/wallets';
10
11
  import { WalletType, detectMobileScreens } from '@rango-dev/wallets-shared';
11
12
  import { useWallets } from '@rango-dev/wallets-core';
@@ -14,6 +15,9 @@ import { useUiStore } from '../store/ui';
14
15
  import { useNavigateBack } from '../hooks/useNavigateBack';
15
16
  import { navigationRoutes } from '../constants/navigationRoutes';
16
17
  import { useTranslation } from 'react-i18next';
18
+ import { useMetaStore } from '../store/meta';
19
+ import { Spinner } from '@rango-dev/ui';
20
+ import { LoadingFailedAlert } from '@rango-dev/ui';
17
21
 
18
22
  interface PropTypes {
19
23
  supportedWallets: 'all' | WalletType[];
@@ -24,9 +28,17 @@ const ListContainer = styled('div', {
24
28
  display: 'grid',
25
29
  gap: '.5rem',
26
30
  gridTemplateColumns: ' repeat(2, minmax(0, 1fr))',
27
- height: '450px',
28
31
  alignContent: 'baseline',
29
32
  padding: '0.5rem',
33
+ overflowY: 'auto',
34
+ });
35
+
36
+ export const LoaderContainer = styled('div', {
37
+ display: 'flex',
38
+ justifyContent: 'center',
39
+ width: '100%',
40
+ position: 'absolute',
41
+ top: '50%',
30
42
  });
31
43
 
32
44
  const AlertContainer = styled('div', {
@@ -40,6 +52,7 @@ export function WalletsPage({ supportedWallets, multiWallets }: PropTypes) {
40
52
  getWalletInfo,
41
53
  supportedWallets === 'all' ? Object.values(WalletType) : supportedWallets
42
54
  );
55
+ const walletsRef = useRef<WalletInfo[]>();
43
56
 
44
57
  let sortedWallets = detectMobileScreens()
45
58
  ? wallets.filter((wallet) => wallet.showOnMobile)
@@ -48,6 +61,7 @@ export function WalletsPage({ supportedWallets, multiWallets }: PropTypes) {
48
61
  const [walletErrorMessage, setWalletErrorMessage] = useState('');
49
62
  const toggleConnectWalletsButton =
50
63
  useUiStore.use.toggleConnectWalletsButton();
64
+ const loadingMetaStatus = useMetaStore.use.loadingStatus();
51
65
  const { t } = useTranslation();
52
66
 
53
67
  const onSelectWallet = async (type: WalletType) => {
@@ -69,12 +83,27 @@ export function WalletsPage({ supportedWallets, multiWallets }: PropTypes) {
69
83
  setWalletErrorMessage('Error: ' + (e as any)?.message);
70
84
  }
71
85
  };
72
-
86
+ const disconnectConnectingWallets = () => {
87
+ const connectingWallets =
88
+ walletsRef.current?.filter(
89
+ (wallet) => wallet.state === WalletState.CONNECTING
90
+ ) || [];
91
+ for (const wallet of connectingWallets) {
92
+ disconnect(wallet.type);
93
+ }
94
+ };
73
95
  useEffect(() => {
74
96
  toggleConnectWalletsButton();
75
- return () => toggleConnectWalletsButton();
97
+ return () => {
98
+ disconnectConnectingWallets();
99
+ toggleConnectWalletsButton();
100
+ };
76
101
  }, []);
77
102
 
103
+ useEffect(() => {
104
+ walletsRef.current = wallets;
105
+ }, [wallets]);
106
+
78
107
  return (
79
108
  <SecondaryPage
80
109
  title={t('Select Wallet') || ''}
@@ -87,14 +116,21 @@ export function WalletsPage({ supportedWallets, multiWallets }: PropTypes) {
87
116
  <Alert type="error">{walletErrorMessage}</Alert>
88
117
  </AlertContainer>
89
118
  )}
119
+ {loadingMetaStatus === 'loading' && (
120
+ <LoaderContainer className="loader">
121
+ <Spinner size={24} />
122
+ </LoaderContainer>
123
+ )}
124
+ {loadingMetaStatus === 'failed' && <LoadingFailedAlert />}
90
125
  <ListContainer>
91
- {sortedWallets.map((wallet, index) => (
92
- <Wallet
93
- {...wallet}
94
- key={`${index}-${wallet.type}`}
95
- onClick={onSelectWallet}
96
- />
97
- ))}
126
+ {loadingMetaStatus === 'success' &&
127
+ sortedWallets.map((wallet, index) => (
128
+ <Wallet
129
+ {...wallet}
130
+ key={`${index}-${wallet.type}`}
131
+ onClick={onSelectWallet}
132
+ />
133
+ ))}
98
134
  </ListContainer>
99
135
  </>
100
136
  </SecondaryPage>
@@ -13,10 +13,15 @@ import { httpService } from '../services/httpService';
13
13
  import { useSettingsStore } from './settings';
14
14
  import { calcOutputUsdValue, createBestRouteRequestBody } from '../utils/swap';
15
15
  import { useMetaStore } from './meta';
16
- import { getDefaultToken, getSortedTokens } from '../utils/wallets';
16
+ import {
17
+ getDefaultToken,
18
+ getSortedTokens,
19
+ tokensAreEqual,
20
+ } from '../utils/wallets';
17
21
  import { useWalletsStore } from './wallets';
18
22
  import { TokenWithBalance } from '../pages/SelectTokenPage';
19
-
23
+ import { PendingSwap } from '@rango-dev/queue-manager-rango-preset/dist/shared';
24
+ import { debounce } from '../utils/common';
20
25
  const getUsdValue = (token: Token | null, amount: string) =>
21
26
  new BigNumber(amount || ZERO).multipliedBy(token?.usdPrice || 0);
22
27
 
@@ -43,6 +48,8 @@ export interface RouteState {
43
48
  setInputAmount: (amount: string) => void;
44
49
  bestRoute: BestRouteResponse | null;
45
50
  setBestRoute: (bestRoute: BestRouteResponse | null) => void;
51
+ retry: (pendingSwap: PendingSwap) => void;
52
+ switchFromAndTo: () => void;
46
53
  }
47
54
 
48
55
  export const useBestRouteStore = createSelectors(
@@ -65,6 +72,7 @@ export const useBestRouteStore = createSelectors(
65
72
  set((state) => {
66
73
  let outputAmount: BigNumber | null = null;
67
74
  let outputUsdValue: BigNumber = ZERO;
75
+ if (!state.inputAmount || state.inputAmount === '0') return {};
68
76
  if (!!bestRoute) {
69
77
  outputAmount = !!bestRoute.result?.outputAmount
70
78
  ? new BigNumber(bestRoute.result?.outputAmount)
@@ -151,6 +159,85 @@ export const useBestRouteStore = createSelectors(
151
159
  }),
152
160
  }));
153
161
  },
162
+ retry: (pendingSwap) => {
163
+ const { tokens, blockchains } = useMetaStore.getState().meta;
164
+ const balances = useWalletsStore.getState().balances;
165
+ const failedIndex =
166
+ pendingSwap.status === 'failed'
167
+ ? pendingSwap.steps.findIndex((s) => s.status === 'failed')
168
+ : null;
169
+
170
+ if (failedIndex === null || failedIndex < 0) return;
171
+
172
+ const firstStep = pendingSwap.steps[0];
173
+ const lastStep = pendingSwap.steps[pendingSwap.steps.length - 1];
174
+ const fromChain =
175
+ blockchains.find(
176
+ (blockchain) => blockchain.name === firstStep.fromBlockchain
177
+ ) || null;
178
+ const toChain =
179
+ blockchains.find(
180
+ (blockchain) => blockchain.name === lastStep.toBlockchain
181
+ ) || null;
182
+
183
+ const fromToken = tokens.find((token) =>
184
+ tokensAreEqual(token, {
185
+ blockchain: firstStep.fromBlockchain,
186
+ symbol: firstStep.fromSymbol,
187
+ address: firstStep.fromSymbolAddress,
188
+ })
189
+ );
190
+
191
+ const toToken = tokens.find((token) =>
192
+ tokensAreEqual(token, {
193
+ blockchain: lastStep.toBlockchain,
194
+ symbol: lastStep.toSymbol,
195
+ address: lastStep.toSymbolAddress,
196
+ })
197
+ );
198
+ const sortedSourceTokens = getSortedTokens(
199
+ fromChain,
200
+ tokens,
201
+ balances,
202
+ []
203
+ );
204
+ const sortedDestinationTokens = getSortedTokens(
205
+ toChain,
206
+ tokens,
207
+ balances,
208
+ []
209
+ );
210
+ const inputAmount = pendingSwap.inputAmount;
211
+ set({
212
+ fromChain,
213
+ fromToken,
214
+ inputAmount,
215
+ outputAmount: null,
216
+ inputUsdValue: getUsdValue(fromToken || null, inputAmount),
217
+ outputUsdValue: new BigNumber(0),
218
+ toChain,
219
+ toToken,
220
+ bestRoute: null,
221
+ loading: false,
222
+ error: '',
223
+ sourceTokens: sortedSourceTokens,
224
+ destinationTokens: sortedDestinationTokens,
225
+ });
226
+ },
227
+ switchFromAndTo: () =>
228
+ set((state) => ({
229
+ fromChain: state.toChain,
230
+ fromToken: state.toToken,
231
+ toChain: state.fromChain,
232
+ toToken: state.fromToken,
233
+ sourceTokens: state.destinationTokens,
234
+ destinationTokens: state.sourceTokens,
235
+ inputAmount: state.outputAmount?.toString() || '',
236
+ inputUsdValue: getUsdValue(
237
+ state.toToken,
238
+ state.outputAmount?.toString() || ''
239
+ ),
240
+ })),
154
241
  }))
155
242
  )
156
243
  );
@@ -164,7 +251,7 @@ const bestRoute = (
164
251
  const { fromToken, toToken, inputAmount } = bestRouteStore.getState();
165
252
  const { slippage, customSlippage, disabledLiquiditySources } =
166
253
  settingsStore.getState();
167
- if (!fromToken || !toToken || !inputAmount) return;
254
+ if (!fromToken || !toToken || !inputAmount || inputAmount === '0') return;
168
255
  abortController?.abort();
169
256
  abortController = new AbortController();
170
257
  const userSlippage = !!customSlippage ? customSlippage : slippage;
@@ -178,12 +265,13 @@ const bestRoute = (
178
265
  userSlippage,
179
266
  false
180
267
  );
181
- bestRouteStore.setState({
182
- loading: true,
183
- bestRoute: null,
184
- outputAmount: null,
185
- outputUsdValue: new BigNumber(0),
186
- });
268
+ if (!bestRouteStore.getState().loading)
269
+ bestRouteStore.setState({
270
+ loading: true,
271
+ bestRoute: null,
272
+ outputAmount: null,
273
+ outputUsdValue: new BigNumber(0),
274
+ });
187
275
  httpService
188
276
  .getBestRoute(requestBody, {
189
277
  signal: abortController.signal,
@@ -203,6 +291,31 @@ const bestRoute = (
203
291
  });
204
292
  };
205
293
 
294
+ const debouncedFetchBestRoute = debounce(fetchBestRoute, 600);
295
+
296
+ const bestRouteParamsListener = () => {
297
+ const { fromToken, toToken, inputAmount, inputUsdValue } =
298
+ useBestRouteStore.getState();
299
+ if (!inputAmount || inputAmount === '0' || inputUsdValue.eq(0)) return;
300
+
301
+ if (tokensAreEqual(fromToken, toToken))
302
+ return bestRouteStore.setState({
303
+ loading: false,
304
+ bestRoute: null,
305
+ outputAmount: new BigNumber(inputAmount),
306
+ outputUsdValue: inputUsdValue,
307
+ });
308
+
309
+ if (!bestRouteStore.getState().loading)
310
+ bestRouteStore.setState({
311
+ loading: true,
312
+ bestRoute: null,
313
+ outputAmount: null,
314
+ outputUsdValue: new BigNumber(0),
315
+ });
316
+ debouncedFetchBestRoute();
317
+ };
318
+
206
319
  useBestRouteStore.subscribe(
207
320
  (state) => ({
208
321
  fromChain: state.fromChain,
@@ -211,11 +324,17 @@ const bestRoute = (
211
324
  toToken: state.toToken,
212
325
  inputAmount: state.inputAmount,
213
326
  }),
214
-
215
- fetchBestRoute.bind(null),
327
+ bestRouteParamsListener,
216
328
  {
217
- equalityFn: (prevState, state) => {
218
- if (isRouteParametersChanged(prevState, state)) return false;
329
+ equalityFn: (prevState, currentState) => {
330
+ if (
331
+ isRouteParametersChanged({
332
+ store: 'bestRoute',
333
+ prevState,
334
+ currentState,
335
+ })
336
+ )
337
+ return false;
219
338
  else return true;
220
339
  },
221
340
  }
@@ -226,11 +345,19 @@ const bestRoute = (
226
345
  slippage: state.slippage,
227
346
  customSlippage: state.customSlippage,
228
347
  disabledLiquiditySources: state.disabledLiquiditySources,
348
+ infiniteApprove: state.infiniteApprove,
229
349
  }),
230
- fetchBestRoute.bind(null),
350
+ bestRouteParamsListener,
231
351
  {
232
- equalityFn: (prevState, state) => {
233
- if (isRouteParametersChanged(prevState, state)) return false;
352
+ equalityFn: (prevState, currentState) => {
353
+ if (
354
+ isRouteParametersChanged({
355
+ store: 'settings',
356
+ prevState,
357
+ currentState,
358
+ })
359
+ )
360
+ return false;
234
361
  else return true;
235
362
  },
236
363
  }
package/src/store/ui.ts CHANGED
@@ -4,18 +4,22 @@ import createSelectors from './selectors';
4
4
  interface UiState {
5
5
  connectWalletsButtonDisabled: boolean;
6
6
  selectedSwapRequestId: string | null;
7
+ currentPage: string;
7
8
  toggleConnectWalletsButton: () => void;
8
9
  setSelectedSwap: (requestId: string | null) => void;
10
+ setCurrentPage: (path: string) => void;
9
11
  }
10
12
 
11
13
  export const useUiStore = createSelectors(
12
14
  create<UiState>()((set) => ({
13
15
  connectWalletsButtonDisabled: false,
14
16
  selectedSwapRequestId: null,
17
+ currentPage: '',
15
18
  toggleConnectWalletsButton: () =>
16
19
  set((state) => ({
17
20
  connectWalletsButtonDisabled: !state.connectWalletsButtonDisabled,
18
21
  })),
19
22
  setSelectedSwap: (requestId) => set({ selectedSwapRequestId: requestId }),
23
+ setCurrentPage: (path) => set({ currentPage: path }),
20
24
  }))
21
25
  );
@@ -142,7 +142,7 @@ export const useWalletsStore = createSelectors(
142
142
  }
143
143
  });
144
144
  return {
145
- selectedWallets: state.selectedWallets.concat(selectedWallets),
145
+ selectedWallets: selectedWallets,
146
146
  };
147
147
  }),
148
148
  setSelectedWallet: (wallet) =>
@@ -188,3 +188,6 @@ useWalletsStore.subscribe(
188
188
  equalityFn: shallow,
189
189
  }
190
190
  );
191
+
192
+ export const fetchingBalanceSelector = (state: WalletsStore) =>
193
+ !!state.balances.find((wallet) => wallet.loading);
@@ -1,17 +1,33 @@
1
1
  import { RouteState } from '../store/bestRoute';
2
2
  import { SettingsState } from '../store/settings';
3
3
 
4
- export interface BestRouteParams {
4
+ interface BestRouteStoreParams {
5
5
  fromChain?: RouteState['fromChain'];
6
6
  toChain?: RouteState['toChain'];
7
7
  fromToken?: RouteState['fromToken'];
8
8
  toToken?: RouteState['toToken'];
9
9
  inputAmount?: RouteState['inputAmount'];
10
+ }
11
+
12
+ interface SettingsStoreParams {
10
13
  slippage?: SettingsState['slippage'];
11
14
  customSlippage?: SettingsState['customSlippage'];
12
15
  disabledLiquiditySources?: SettingsState['disabledLiquiditySources'];
16
+ infiniteApprove?: SettingsState['infiniteApprove'];
13
17
  }
14
18
 
19
+ export type BestRouteEqualityParams =
20
+ | {
21
+ store: 'bestRoute';
22
+ prevState: BestRouteStoreParams;
23
+ currentState: BestRouteStoreParams;
24
+ }
25
+ | {
26
+ store: 'settings';
27
+ prevState: SettingsStoreParams;
28
+ currentState: SettingsStoreParams;
29
+ };
30
+
15
31
  export enum ConfirmSwapErrorTypes {
16
32
  NO_ROUTE,
17
33
  ROUTE_UPDATED_WITH_HIGH_VALUE_LOSS,
@@ -26,7 +42,7 @@ export type ConfirmSwapError =
26
42
  }
27
43
  | {
28
44
  type: ConfirmSwapErrorTypes.INSUFFICIENT_SLIPPAGE;
29
- minRequiredSlippage: number | null;
45
+ minRequiredSlippage: string | null;
30
46
  }
31
47
  | {
32
48
  type: Exclude<
package/src/types/swap.ts CHANGED
@@ -11,3 +11,10 @@ export type SwapButtonState = (
11
11
  ) & {
12
12
  title: string;
13
13
  };
14
+
15
+ export type ConvertedToken = {
16
+ symbol: string;
17
+ address: string | null;
18
+ blockchain: string;
19
+ outputAmount: string | null;
20
+ } | null;
@@ -33,3 +33,17 @@ export function shadeColor(color: string, percent: number) {
33
33
 
34
34
  return '#' + RR + GG + BB;
35
35
  }
36
+
37
+ export function debounce(fn: Function, time: number) {
38
+ let timeoutId: ReturnType<typeof setTimeout> | null;
39
+ return wrapper;
40
+ function wrapper(...args: any) {
41
+ if (timeoutId) {
42
+ clearTimeout(timeoutId);
43
+ }
44
+ timeoutId = setTimeout(() => {
45
+ timeoutId = null;
46
+ fn(...args);
47
+ }, time);
48
+ }
49
+ }
@@ -0,0 +1,62 @@
1
+ import { PendingSwap } from '@rango-dev/queue-manager-rango-preset';
2
+ import dayjs from 'dayjs';
3
+ import { GroupBy } from '@rango-dev/ui';
4
+
5
+ export const groupSwapsByDate: GroupBy = swaps => {
6
+ const output: Map<
7
+ string,
8
+ {
9
+ title: string;
10
+ swaps: PendingSwap[];
11
+ }
12
+ > = new Map([
13
+ [
14
+ 'today',
15
+ {
16
+ title: 'Today',
17
+ swaps: [],
18
+ },
19
+ ],
20
+ [
21
+ 'week',
22
+ {
23
+ title: 'This week',
24
+ swaps: [],
25
+ },
26
+ ],
27
+ [
28
+ 'month',
29
+ {
30
+ title: 'This month',
31
+ swaps: [],
32
+ },
33
+ ],
34
+ [
35
+ 'year',
36
+ {
37
+ title: 'This year',
38
+ swaps: [],
39
+ },
40
+ ],
41
+ [
42
+ 'history',
43
+ {
44
+ title: 'History',
45
+ swaps: [],
46
+ },
47
+ ],
48
+ ]);
49
+
50
+ const now = dayjs();
51
+ swaps.forEach(swap => {
52
+ const swapDate = dayjs(Number(swap.creationTime));
53
+ if (now.isSame(swapDate, 'day')) output.get('today')?.swaps.push(swap);
54
+ else if (now.isSame(swapDate, 'week')) output.get('week')?.swaps.push(swap);
55
+ else if (now.isSame(swapDate, 'month'))
56
+ output.get('month')?.swaps.push(swap);
57
+ else if (now.isSame(swapDate, 'year')) output.get('year')?.swaps.push(swap);
58
+ else output.get('history')?.swaps.push(swap);
59
+ });
60
+
61
+ return Array.from(output.values());
62
+ };