@rango-dev/widget-embedded 0.1.10-next.98 → 0.1.10

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 (110) 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/ChangeSlippageButton.d.ts.map +1 -1
  7. package/dist/components/HeaderButtons.d.ts +4 -1
  8. package/dist/components/HeaderButtons.d.ts.map +1 -1
  9. package/dist/components/Layout.d.ts.map +1 -1
  10. package/dist/components/RoutesOverview.d.ts +10 -0
  11. package/dist/components/RoutesOverview.d.ts.map +1 -0
  12. package/dist/components/SwapDetailsPlaceholder.d.ts +9 -0
  13. package/dist/components/SwapDetailsPlaceholder.d.ts.map +1 -0
  14. package/dist/components/TokenInfo.d.ts.map +1 -1
  15. package/dist/components/TokenPreview.d.ts +20 -0
  16. package/dist/components/TokenPreview.d.ts.map +1 -0
  17. package/dist/components/UpdateUrl.d.ts.map +1 -1
  18. package/dist/components/warnings/BalanceWarnings.d.ts.map +1 -1
  19. package/dist/components/warnings/HighSlippageWarning.d.ts.map +1 -1
  20. package/dist/components/warnings/MinRequiredSlippage.d.ts +1 -1
  21. package/dist/components/warnings/MinRequiredSlippage.d.ts.map +1 -1
  22. package/dist/constants/navigationRoutes.d.ts +0 -1
  23. package/dist/constants/navigationRoutes.d.ts.map +1 -1
  24. package/dist/globalStyles.d.ts.map +1 -1
  25. package/dist/hooks/useConfirmSwap.d.ts.map +1 -1
  26. package/dist/lib.d.ts.map +1 -1
  27. package/dist/pages/ConfirmSwapPage.d.ts.map +1 -1
  28. package/dist/pages/HistoryPage.d.ts.map +1 -1
  29. package/dist/pages/Home.d.ts.map +1 -1
  30. package/dist/pages/LiquiditySourcesPage.d.ts.map +1 -1
  31. package/dist/pages/SelectTokenPage.d.ts.map +1 -1
  32. package/dist/pages/SettingsPage.d.ts.map +1 -1
  33. package/dist/pages/SwapDetailsPage.d.ts.map +1 -1
  34. package/dist/pages/WalletsPage.d.ts +1 -0
  35. package/dist/pages/WalletsPage.d.ts.map +1 -1
  36. package/dist/store/bestRoute.d.ts +2 -0
  37. package/dist/store/bestRoute.d.ts.map +1 -1
  38. package/dist/store/ui.d.ts.map +1 -1
  39. package/dist/store/wallets.d.ts +14 -0
  40. package/dist/store/wallets.d.ts.map +1 -1
  41. package/dist/types/routing.d.ts +1 -1
  42. package/dist/types/swap.d.ts +6 -0
  43. package/dist/types/swap.d.ts.map +1 -1
  44. package/dist/utils/common.d.ts +1 -0
  45. package/dist/utils/common.d.ts.map +1 -1
  46. package/dist/utils/date.d.ts +3 -0
  47. package/dist/utils/date.d.ts.map +1 -0
  48. package/dist/utils/routing.d.ts +1 -0
  49. package/dist/utils/routing.d.ts.map +1 -1
  50. package/dist/utils/swap.d.ts +18 -6
  51. package/dist/utils/swap.d.ts.map +1 -1
  52. package/dist/utils/time.d.ts +4 -0
  53. package/dist/utils/time.d.ts.map +1 -0
  54. package/dist/utils/wallets.d.ts +1 -1
  55. package/dist/utils/wallets.d.ts.map +1 -1
  56. package/dist/widget-embedded.cjs.development.js +1004 -418
  57. package/dist/widget-embedded.cjs.development.js.map +1 -1
  58. package/dist/widget-embedded.cjs.production.min.js +1004 -418
  59. package/dist/widget-embedded.cjs.production.min.js.map +1 -1
  60. package/dist/widget-embedded.esm.js +1008 -423
  61. package/dist/widget-embedded.esm.js.map +1 -1
  62. package/package.json +12 -11
  63. package/readme.md +1 -2
  64. package/src/App.tsx +30 -5
  65. package/src/QueueManager.tsx +5 -2
  66. package/src/components/AppRouter.tsx +24 -13
  67. package/src/components/AppRoutes.tsx +15 -12
  68. package/src/components/ChangeSlippageButton.tsx +4 -8
  69. package/src/components/HeaderButtons.tsx +11 -4
  70. package/src/components/Layout.tsx +37 -5
  71. package/src/components/RoutesOverview.tsx +60 -0
  72. package/src/components/SwapDetailsPlaceholder.tsx +32 -0
  73. package/src/components/TokenInfo.tsx +125 -77
  74. package/src/components/TokenPreview.tsx +178 -0
  75. package/src/components/UpdateUrl.tsx +1 -3
  76. package/src/components/warnings/BalanceWarnings.tsx +1 -0
  77. package/src/components/warnings/HighSlippageWarning.tsx +4 -7
  78. package/src/components/warnings/MinRequiredSlippage.tsx +9 -4
  79. package/src/constants/navigationRoutes.ts +0 -1
  80. package/src/globalStyles.ts +3 -2
  81. package/src/hooks/useConfirmSwap.ts +2 -1
  82. package/src/hooks/useNavigateBack.ts +3 -3
  83. package/src/hooks/useTheme.ts +9 -9
  84. package/src/languages/en.json +9 -8
  85. package/src/lib.tsx +25 -3
  86. package/src/pages/ConfirmSwapPage.tsx +128 -20
  87. package/src/pages/HistoryPage.tsx +4 -4
  88. package/src/pages/Home.tsx +51 -42
  89. package/src/pages/LiquiditySourcesPage.tsx +2 -0
  90. package/src/pages/SelectTokenPage.tsx +3 -1
  91. package/src/pages/SettingsPage.tsx +3 -0
  92. package/src/pages/SwapDetailsPage.tsx +142 -6
  93. package/src/pages/WalletsPage.tsx +49 -16
  94. package/src/store/bestRoute.ts +114 -17
  95. package/src/store/ui.ts +4 -0
  96. package/src/store/wallets.ts +4 -1
  97. package/src/types/routing.ts +1 -1
  98. package/src/types/swap.ts +7 -0
  99. package/src/utils/common.ts +14 -0
  100. package/src/utils/date.ts +62 -0
  101. package/src/utils/routing.ts +23 -13
  102. package/src/utils/swap.ts +113 -11
  103. package/src/utils/time.ts +52 -0
  104. package/src/utils/wallets.ts +13 -4
  105. package/dist/components/Header.d.ts +0 -10
  106. package/dist/components/Header.d.ts.map +0 -1
  107. package/dist/pages/ConfirmWalletsPage.d.ts +0 -3
  108. package/dist/pages/ConfirmWalletsPage.d.ts.map +0 -1
  109. package/src/components/Header.tsx +0 -37
  110. package/src/pages/ConfirmWalletsPage.tsx +0 -80
@@ -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
  }
@@ -3,10 +3,10 @@ import {
3
3
  SecondaryPage,
4
4
  styled,
5
5
  Wallet,
6
- Typography,
7
6
  WalletState,
7
+ WalletInfo,
8
8
  } from '@rango-dev/ui';
9
- import React, { useEffect, useState } from 'react';
9
+ import React, { useEffect, useRef, useState } from 'react';
10
10
  import { getlistWallet, sortWalletsBasedOnState } from '../utils/wallets';
11
11
  import { WalletType, detectMobileScreens } from '@rango-dev/wallets-shared';
12
12
  import { useWallets } from '@rango-dev/wallets-core';
@@ -15,6 +15,9 @@ import { useUiStore } from '../store/ui';
15
15
  import { useNavigateBack } from '../hooks/useNavigateBack';
16
16
  import { navigationRoutes } from '../constants/navigationRoutes';
17
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';
18
21
 
19
22
  interface PropTypes {
20
23
  supportedWallets: 'all' | WalletType[];
@@ -25,9 +28,17 @@ const ListContainer = styled('div', {
25
28
  display: 'grid',
26
29
  gap: '.5rem',
27
30
  gridTemplateColumns: ' repeat(2, minmax(0, 1fr))',
28
- height: '450px',
29
31
  alignContent: 'baseline',
30
- padding: '0 0.5rem',
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%',
31
42
  });
32
43
 
33
44
  const AlertContainer = styled('div', {
@@ -41,6 +52,7 @@ export function WalletsPage({ supportedWallets, multiWallets }: PropTypes) {
41
52
  getWalletInfo,
42
53
  supportedWallets === 'all' ? Object.values(WalletType) : supportedWallets
43
54
  );
55
+ const walletsRef = useRef<WalletInfo[]>();
44
56
 
45
57
  let sortedWallets = detectMobileScreens()
46
58
  ? wallets.filter((wallet) => wallet.showOnMobile)
@@ -49,6 +61,7 @@ export function WalletsPage({ supportedWallets, multiWallets }: PropTypes) {
49
61
  const [walletErrorMessage, setWalletErrorMessage] = useState('');
50
62
  const toggleConnectWalletsButton =
51
63
  useUiStore.use.toggleConnectWalletsButton();
64
+ const loadingMetaStatus = useMetaStore.use.loadingStatus();
52
65
  const { t } = useTranslation();
53
66
 
54
67
  const onSelectWallet = async (type: WalletType) => {
@@ -70,12 +83,27 @@ export function WalletsPage({ supportedWallets, multiWallets }: PropTypes) {
70
83
  setWalletErrorMessage('Error: ' + (e as any)?.message);
71
84
  }
72
85
  };
73
-
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
+ };
74
95
  useEffect(() => {
75
96
  toggleConnectWalletsButton();
76
- return () => toggleConnectWalletsButton();
97
+ return () => {
98
+ disconnectConnectingWallets();
99
+ toggleConnectWalletsButton();
100
+ };
77
101
  }, []);
78
102
 
103
+ useEffect(() => {
104
+ walletsRef.current = wallets;
105
+ }, [wallets]);
106
+
79
107
  return (
80
108
  <SecondaryPage
81
109
  title={t('Select Wallet') || ''}
@@ -85,19 +113,24 @@ export function WalletsPage({ supportedWallets, multiWallets }: PropTypes) {
85
113
  <>
86
114
  {walletErrorMessage && (
87
115
  <AlertContainer>
88
- <Alert type="error">
89
- <Typography variant="body2">{walletErrorMessage}</Typography>
90
- </Alert>
116
+ <Alert type="error">{walletErrorMessage}</Alert>
91
117
  </AlertContainer>
92
118
  )}
119
+ {loadingMetaStatus === 'loading' && (
120
+ <LoaderContainer className="loader">
121
+ <Spinner size={24} />
122
+ </LoaderContainer>
123
+ )}
124
+ {loadingMetaStatus === 'failed' && <LoadingFailedAlert />}
93
125
  <ListContainer>
94
- {sortedWallets.map((wallet, index) => (
95
- <Wallet
96
- {...wallet}
97
- key={`${index}-${wallet.type}`}
98
- onClick={onSelectWallet}
99
- />
100
- ))}
126
+ {loadingMetaStatus === 'success' &&
127
+ sortedWallets.map((wallet, index) => (
128
+ <Wallet
129
+ {...wallet}
130
+ key={`${index}-${wallet.type}`}
131
+ onClick={onSelectWallet}
132
+ />
133
+ ))}
101
134
  </ListContainer>
102
135
  </>
103
136
  </SecondaryPage>
@@ -11,12 +11,17 @@ import createSelectors from './selectors';
11
11
  import { subscribeWithSelector } from 'zustand/middleware';
12
12
  import { httpService } from '../services/httpService';
13
13
  import { useSettingsStore } from './settings';
14
- import { createBestRouteRequestBody } from '../utils/swap';
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,7 @@ 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;
46
52
  }
47
53
 
48
54
  export const useBestRouteStore = createSelectors(
@@ -65,14 +71,14 @@ export const useBestRouteStore = createSelectors(
65
71
  set((state) => {
66
72
  let outputAmount: BigNumber | null = null;
67
73
  let outputUsdValue: BigNumber = ZERO;
74
+ if (!state.inputAmount || state.inputAmount === '0') return {};
68
75
  if (!!bestRoute) {
69
76
  outputAmount = !!bestRoute.result?.outputAmount
70
77
  ? new BigNumber(bestRoute.result?.outputAmount)
71
78
  : null;
72
- outputUsdValue = new BigNumber(outputAmount || ZERO).multipliedBy(
73
- getBestRouteToTokenUsdPrice(bestRoute) ||
74
- state.toToken?.usdPrice ||
75
- 0
79
+ outputUsdValue = calcOutputUsdValue(
80
+ bestRoute.result?.outputAmount,
81
+ getBestRouteToTokenUsdPrice(bestRoute) || state.toToken?.usdPrice
76
82
  );
77
83
  }
78
84
  return {
@@ -140,6 +146,7 @@ export const useBestRouteStore = createSelectors(
140
146
  toToken: token,
141
147
  })),
142
148
  setInputAmount: (amount) => {
149
+ console.log(amount, typeof amount);
143
150
  set((state) => ({
144
151
  inputAmount: amount,
145
152
  ...(!amount && {
@@ -152,6 +159,71 @@ export const useBestRouteStore = createSelectors(
152
159
  }),
153
160
  }));
154
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
+ },
155
227
  }))
156
228
  )
157
229
  );
@@ -165,7 +237,7 @@ const bestRoute = (
165
237
  const { fromToken, toToken, inputAmount } = bestRouteStore.getState();
166
238
  const { slippage, customSlippage, disabledLiquiditySources } =
167
239
  settingsStore.getState();
168
- if (!fromToken || !toToken || !inputAmount) return;
240
+ if (!fromToken || !toToken || !inputAmount || inputAmount === '0') return;
169
241
  abortController?.abort();
170
242
  abortController = new AbortController();
171
243
  const userSlippage = !!customSlippage ? customSlippage : slippage;
@@ -179,12 +251,13 @@ const bestRoute = (
179
251
  userSlippage,
180
252
  false
181
253
  );
182
- bestRouteStore.setState({
183
- loading: true,
184
- bestRoute: null,
185
- outputAmount: null,
186
- outputUsdValue: new BigNumber(0),
187
- });
254
+ if (!bestRouteStore.getState().loading)
255
+ bestRouteStore.setState({
256
+ loading: true,
257
+ bestRoute: null,
258
+ outputAmount: null,
259
+ outputUsdValue: new BigNumber(0),
260
+ });
188
261
  httpService
189
262
  .getBestRoute(requestBody, {
190
263
  signal: abortController.signal,
@@ -204,6 +277,31 @@ const bestRoute = (
204
277
  });
205
278
  };
206
279
 
280
+ const debouncedFetchBestRoute = debounce(fetchBestRoute, 600);
281
+
282
+ const bestRouteParamsListener = () => {
283
+ const { fromToken, toToken, inputAmount, inputUsdValue } =
284
+ useBestRouteStore.getState();
285
+ if (!inputAmount || inputAmount === '0') return;
286
+
287
+ if (tokensAreEqual(fromToken, toToken))
288
+ return bestRouteStore.setState({
289
+ loading: false,
290
+ bestRoute: null,
291
+ outputAmount: new BigNumber(inputAmount),
292
+ outputUsdValue: inputUsdValue,
293
+ });
294
+
295
+ if (!bestRouteStore.getState().loading)
296
+ bestRouteStore.setState({
297
+ loading: true,
298
+ bestRoute: null,
299
+ outputAmount: null,
300
+ outputUsdValue: new BigNumber(0),
301
+ });
302
+ debouncedFetchBestRoute();
303
+ };
304
+
207
305
  useBestRouteStore.subscribe(
208
306
  (state) => ({
209
307
  fromChain: state.fromChain,
@@ -212,8 +310,7 @@ const bestRoute = (
212
310
  toToken: state.toToken,
213
311
  inputAmount: state.inputAmount,
214
312
  }),
215
-
216
- fetchBestRoute.bind(null),
313
+ bestRouteParamsListener,
217
314
  {
218
315
  equalityFn: (prevState, state) => {
219
316
  if (isRouteParametersChanged(prevState, state)) return false;
@@ -228,7 +325,7 @@ const bestRoute = (
228
325
  customSlippage: state.customSlippage,
229
326
  disabledLiquiditySources: state.disabledLiquiditySources,
230
327
  }),
231
- fetchBestRoute.bind(null),
328
+ bestRouteParamsListener,
232
329
  {
233
330
  equalityFn: (prevState, state) => {
234
331
  if (isRouteParametersChanged(prevState, state)) return false;
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);
@@ -26,7 +26,7 @@ export type ConfirmSwapError =
26
26
  }
27
27
  | {
28
28
  type: ConfirmSwapErrorTypes.INSUFFICIENT_SLIPPAGE;
29
- minRequiredSlippage: number | null;
29
+ minRequiredSlippage: string | null;
30
30
  }
31
31
  | {
32
32
  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
+ };