@rango-dev/widget-embedded 0.1.13-next.0 → 0.1.13-next.5

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 (55) 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.map +1 -1
  4. package/dist/components/Layout.d.ts.map +1 -1
  5. package/dist/components/TokenInfo.d.ts.map +1 -1
  6. package/dist/components/TokenPreview.d.ts.map +1 -1
  7. package/dist/components/UpdateUrl.d.ts.map +1 -1
  8. package/dist/components/warnings/BalanceErrors.d.ts.map +1 -1
  9. package/dist/globalStyles.d.ts +0 -1
  10. package/dist/globalStyles.d.ts.map +1 -1
  11. package/dist/hooks/useNavigateBack.d.ts.map +1 -1
  12. package/dist/lib.d.ts +1 -1
  13. package/dist/lib.d.ts.map +1 -1
  14. package/dist/pages/ConfirmSwapPage.d.ts.map +1 -1
  15. package/dist/pages/SwapDetailsPage.d.ts.map +1 -1
  16. package/dist/store/bestRoute.d.ts +1 -0
  17. package/dist/store/bestRoute.d.ts.map +1 -1
  18. package/dist/store/wallets.d.ts +1 -0
  19. package/dist/store/wallets.d.ts.map +1 -1
  20. package/dist/utils/numbers.d.ts +1 -2
  21. package/dist/utils/numbers.d.ts.map +1 -1
  22. package/dist/widget-embedded.cjs.development.js +1087 -1149
  23. package/dist/widget-embedded.cjs.development.js.map +1 -1
  24. package/dist/widget-embedded.cjs.production.min.js +1087 -1149
  25. package/dist/widget-embedded.cjs.production.min.js.map +1 -1
  26. package/dist/widget-embedded.esm.js +1090 -1152
  27. package/dist/widget-embedded.esm.js.map +1 -1
  28. package/package.json +3 -3
  29. package/src/App.tsx +1 -2
  30. package/src/QueueManager.tsx +28 -3
  31. package/src/components/AppRouter.tsx +4 -29
  32. package/src/components/AppRoutes.tsx +9 -9
  33. package/src/components/BottomLogo.tsx +1 -1
  34. package/src/components/ChangeSlippageButton.tsx +1 -1
  35. package/src/components/Layout.tsx +3 -1
  36. package/src/components/RoutesOverview.tsx +2 -2
  37. package/src/components/TokenInfo.tsx +3 -2
  38. package/src/components/TokenPreview.tsx +1 -0
  39. package/src/components/UpdateUrl.tsx +19 -50
  40. package/src/components/warnings/BalanceErrors.tsx +4 -2
  41. package/src/constants/navigationRoutes.ts +9 -9
  42. package/src/globalStyles.ts +0 -19
  43. package/src/hooks/useNavigateBack.ts +3 -4
  44. package/src/index.tsx +1 -1
  45. package/src/lib.tsx +16 -8
  46. package/src/pages/ConfirmSwapPage.tsx +33 -13
  47. package/src/pages/HistoryPage.tsx +1 -1
  48. package/src/pages/Home.tsx +1 -1
  49. package/src/pages/SwapDetailsPage.tsx +1 -2
  50. package/src/store/bestRoute.ts +18 -16
  51. package/src/store/wallets.ts +38 -28
  52. package/src/utils/numbers.ts +2 -5
  53. package/dist/hooks/useCopyToClipboard.d.ts +0 -2
  54. package/dist/hooks/useCopyToClipboard.d.ts.map +0 -1
  55. package/src/hooks/useCopyToClipboard.ts +0 -23
@@ -1,9 +1,9 @@
1
- import { WalletState, Typography, InfoCircleIcon, AngleDownIcon, Spacer, Button, Image, TextField, styled, Tooltip, RetryIcon, HistoryIcon, SettingsIcon, Header as Header$1, VerticalSwapIcon, BestRoute, Alert, ChevronRightIcon, GasIcon, ConfirmSwap, History, LiquiditySourcesSelector, BlockchainSelector, TokenSelector, Settings, SecondaryPage, Spinner, LoadingFailedAlert, Wallet, SwapHistory, AddWalletIcon, globalCss, createTheme, SwapContainer } from '@rango-dev/ui';
2
- import React, { useRef, useEffect, useState, useLayoutEffect, useMemo } from 'react';
3
- import { useInRouterContext as useInRouterContext$1, MemoryRouter, useLocation as useLocation$1, useNavigate as useNavigate$1 } from 'react-router';
1
+ import { WalletState, InfoCircleIcon, Typography, Button, Image, Spacer, styled, ChevronRightIcon, GasIcon, Alert, ConfirmSwap, LoadingFailedAlert, History, AngleDownIcon, TextField, Tooltip, RetryIcon, HistoryIcon, SettingsIcon, Header as Header$1, VerticalSwapIcon, BestRoute, LiquiditySourcesSelector, BlockchainSelector, TokenSelector, Settings, SecondaryPage, Spinner, Wallet, useCopyToClipboard, SwapHistory, AddWalletIcon, globalCss, createTheme, SwapContainer } from '@rango-dev/ui';
2
+ import React, { useRef, useEffect, Fragment, useState, useLayoutEffect, useMemo } from 'react';
3
+ import { useInRouterContext, MemoryRouter } from 'react-router';
4
4
  import { PendingSwapNetworkStatus, useQueueManager, calculatePendingSwap, getCurrentStep, getCurrentBlockchainOfOrNull, getRelatedWalletOrNull, cancelSwap, makeQueueDefinition, checkWaitingForNetworkChange } from '@rango-dev/queue-manager-rango-preset';
5
5
  import { isCosmosBlockchain, isEvmBlockchain } from 'rango-types';
6
- import { useSearchParams, useLocation, createSearchParams, useNavigate, useInRouterContext, useRoutes } from 'react-router-dom';
6
+ import { useSearchParams, useLocation, createSearchParams, useInRouterContext as useInRouterContext$1, useNavigate, useRoutes } from 'react-router-dom';
7
7
  import { create } from 'zustand';
8
8
  import BigNumber, { BigNumber as BigNumber$1 } from 'bignumber.js';
9
9
  import { persist, subscribeWithSelector } from 'zustand/middleware';
@@ -12,30 +12,15 @@ import { Network, isEvmAddress, KEPLR_COMPATIBLE_WALLETS, detectInstallLink, Wal
12
12
  export { WalletType } from '@rango-dev/wallets-shared';
13
13
  import { readAccountAddress, useWallets, Provider as Provider$1, Events } from '@rango-dev/wallets-core';
14
14
  import { shallow } from 'zustand/shallow';
15
- import { useTranslation, initReactI18next } from 'react-i18next';
16
- import { styled as styled$1 } from '@rango-dev/ui/src/theme';
17
15
  import { allProviders } from '@rango-dev/provider-all';
16
+ import { useTranslation, initReactI18next } from 'react-i18next';
18
17
  import i18n, { t } from 'i18next';
19
18
  import { useManager, Provider } from '@rango-dev/queue-manager-react';
20
19
  import dayjs from 'dayjs';
21
- import copy from 'copy-to-clipboard';
20
+ import { styled as styled$1 } from '@rango-dev/ui/src/theme';
22
21
  import Backend from 'i18next-http-backend';
23
22
  import LanguageDetector from 'i18next-browser-languagedetector';
24
23
 
25
- const navigationRoutes = {
26
- home: '/',
27
- fromChain: '/from-chain',
28
- fromToken: '/from-token',
29
- toChain: '/to-chain',
30
- toToken: '/to-token',
31
- settings: '/settings',
32
- liquiditySources: '/settings/liquidity-sources',
33
- swaps: '/swaps',
34
- wallets: '/wallets',
35
- confirmSwap: '/confirm-swap',
36
- swapDetails: '/swaps/:requestId'
37
- };
38
-
39
24
  const ZERO = /*#__PURE__*/new BigNumber(0);
40
25
 
41
26
  function removeDuplicateFrom(array) {
@@ -91,7 +76,7 @@ const numberToString = function (number, minDecimals, maxDecimals) {
91
76
  if (maxDecimals === void 0) {
92
77
  maxDecimals = null;
93
78
  }
94
- if (number === null) return '';
79
+ if (number === null || number === undefined) return '';
95
80
  if (number === '') return '';
96
81
  const n = new BigNumber$1(number);
97
82
  const roundingMode = 1;
@@ -112,12 +97,6 @@ const numberToString = function (number, minDecimals, maxDecimals) {
112
97
  return n.toFormat(Math.min(maxI, Math.min(maxDecimals || 100, Math.max(minDecimals || 0, 8))), roundingMode);
113
98
  };
114
99
  const totalArrivalTime = data => data?.result?.swaps?.reduce((a, b) => a + b.estimatedTimeInSeconds, 0) || 0;
115
- const decimalNumber = function (number, toFixed) {
116
- if (number === void 0) {
117
- number = '0';
118
- }
119
- return parseFloat(number).toFixed(toFixed);
120
- };
121
100
  const isPositiveNumber = text => !!text && parseFloat(text) > 0;
122
101
 
123
102
  function searchParamsToToken(tokens, searchParams, chain) {
@@ -838,12 +817,12 @@ function shouldRetrySwap(pendingSwap) {
838
817
  return pendingSwap.status === 'failed' && !!pendingSwap.finishTime && new Date().getTime() - parseInt(pendingSwap.finishTime) < 4 * 3600 * 1000;
839
818
  }
840
819
 
841
- const useWalletsStore = /*#__PURE__*/createSelectors( /*#__PURE__*/create()( /*#__PURE__*/subscribeWithSelector(set => ({
820
+ const useWalletsStore = /*#__PURE__*/createSelectors( /*#__PURE__*/create()( /*#__PURE__*/subscribeWithSelector((set, get) => ({
842
821
  accounts: [],
843
822
  balances: [],
844
823
  selectedWallets: [],
845
824
  connectWallet: accounts => {
846
- const tokens = useMetaStore.getState().meta.tokens;
825
+ const getOneOfWalletsDetails = get().getOneOfWalletsDetails;
847
826
  set(state => ({
848
827
  accounts: state.accounts.concat(accounts),
849
828
  balances: state.balances.concat(accounts.map(account => ({
@@ -856,28 +835,7 @@ const useWalletsStore = /*#__PURE__*/createSelectors( /*#__PURE__*/create()( /*#
856
835
  explorerUrl: null
857
836
  })))
858
837
  }));
859
- accounts.forEach(async account => {
860
- try {
861
- const response = await httpService().getWalletsDetails([{
862
- address: account.address,
863
- blockchain: account.chain
864
- }]);
865
- const retrivedBalance = response.wallets[0];
866
- if (retrivedBalance) {
867
- set(state => ({
868
- balances: state.balances.map(balance => {
869
- return isAccountAndBalanceMatched(account, balance) ? makeBalanceFor(account, retrivedBalance, tokens) : balance;
870
- })
871
- }));
872
- } else throw new Error('Wallet not found');
873
- } catch (error) {
874
- set(state => ({
875
- balances: state.balances.map(balance => {
876
- return isAccountAndBalanceMatched(account, balance) ? resetBalanceState(balance) : balance;
877
- })
878
- }));
879
- }
880
- });
838
+ accounts.forEach(async account => getOneOfWalletsDetails(account));
881
839
  },
882
840
  disconnectWallet: walletType => {
883
841
  set(state => ({
@@ -916,7 +874,38 @@ const useWalletsStore = /*#__PURE__*/createSelectors( /*#__PURE__*/create()( /*#
916
874
  accounts: [],
917
875
  balances: [],
918
876
  selectedWallets: []
919
- }))
877
+ })),
878
+ getOneOfWalletsDetails: async account => {
879
+ const tokens = useMetaStore.getState().meta.tokens;
880
+ set(state => ({
881
+ balances: state.balances.map(balance => {
882
+ return balance.address === account.address && balance.chain === account.chain ? {
883
+ ...balance,
884
+ loading: true
885
+ } : balance;
886
+ })
887
+ }));
888
+ try {
889
+ const response = await httpService().getWalletsDetails([{
890
+ address: account.address,
891
+ blockchain: account.chain
892
+ }]);
893
+ const retrivedBalance = response.wallets[0];
894
+ if (retrivedBalance) {
895
+ set(state => ({
896
+ balances: state.balances.map(balance => {
897
+ return isAccountAndBalanceMatched(account, balance) ? makeBalanceFor(account, retrivedBalance, tokens) : balance;
898
+ })
899
+ }));
900
+ } else throw new Error('Wallet not found');
901
+ } catch (error) {
902
+ set(state => ({
903
+ balances: state.balances.map(balance => {
904
+ return isAccountAndBalanceMatched(account, balance) ? resetBalanceState(balance) : balance;
905
+ })
906
+ }));
907
+ }
908
+ }
920
909
  }))));
921
910
  useWalletsStore.subscribe(state => state.balances, balances => {
922
911
  useBestRouteStore.setState(_ref => {
@@ -967,6 +956,13 @@ const useBestRouteStore = /*#__PURE__*/createSelectors( /*#__PURE__*/create()( /
967
956
  })
968
957
  };
969
958
  }),
959
+ resetRoute: () => set(() => ({
960
+ loading: true,
961
+ error: '',
962
+ bestRoute: null,
963
+ outputAmount: null,
964
+ outputUsdValue: new BigNumber(0)
965
+ })),
970
966
  setFromChain: (chain, setDefaultToken) => {
971
967
  set(state => {
972
968
  if (state.fromChain?.name === chain?.name) return {};
@@ -1016,7 +1012,8 @@ const useBestRouteStore = /*#__PURE__*/createSelectors( /*#__PURE__*/create()( /
1016
1012
  ...(!amount && {
1017
1013
  outputAmount: new BigNumber(0),
1018
1014
  outputUsdValue: new BigNumber(0),
1019
- bestRoute: null
1015
+ bestRoute: null,
1016
+ error: ''
1020
1017
  }),
1021
1018
  ...(!!state.fromToken && {
1022
1019
  inputUsdValue: getUsdValue(state.fromToken, amount)
@@ -1081,7 +1078,8 @@ const bestRoute = (bestRouteStore, settingsStore) => {
1081
1078
  const {
1082
1079
  fromToken,
1083
1080
  toToken,
1084
- inputAmount
1081
+ inputAmount,
1082
+ resetRoute
1085
1083
  } = bestRouteStore.getState();
1086
1084
  const {
1087
1085
  slippage,
@@ -1094,12 +1092,9 @@ const bestRoute = (bestRouteStore, settingsStore) => {
1094
1092
  abortController = new AbortController();
1095
1093
  const userSlippage = !!customSlippage ? customSlippage : slippage;
1096
1094
  const requestBody = createBestRouteRequestBody(fromToken, toToken, inputAmount, [], [], disabledLiquiditySources, userSlippage, affiliateRef);
1097
- if (!bestRouteStore.getState().loading) bestRouteStore.setState({
1098
- loading: true,
1099
- bestRoute: null,
1100
- outputAmount: null,
1101
- outputUsdValue: new BigNumber(0)
1102
- });
1095
+ if (!bestRouteStore.getState().loading) {
1096
+ resetRoute();
1097
+ }
1103
1098
  httpService().getBestRoute(requestBody, {
1104
1099
  signal: abortController.signal
1105
1100
  }).then(res => {
@@ -1125,7 +1120,8 @@ const bestRoute = (bestRouteStore, settingsStore) => {
1125
1120
  fromToken,
1126
1121
  toToken,
1127
1122
  inputAmount,
1128
- inputUsdValue
1123
+ inputUsdValue,
1124
+ resetRoute
1129
1125
  } = useBestRouteStore.getState();
1130
1126
  if (!isPositiveNumber(inputAmount) || inputUsdValue.eq(0)) return bestRouteStore.setState({
1131
1127
  loading: false
@@ -1136,12 +1132,7 @@ const bestRoute = (bestRouteStore, settingsStore) => {
1136
1132
  outputAmount: new BigNumber(inputAmount),
1137
1133
  outputUsdValue: inputUsdValue
1138
1134
  });
1139
- if (!bestRouteStore.getState().loading) bestRouteStore.setState({
1140
- loading: true,
1141
- bestRoute: null,
1142
- outputAmount: null,
1143
- outputUsdValue: new BigNumber(0)
1144
- });
1135
+ if (!bestRouteStore.getState().loading) resetRoute();
1145
1136
  debouncedFetchBestRoute();
1146
1137
  };
1147
1138
  useBestRouteStore.subscribe(state => ({
@@ -1190,6 +1181,20 @@ var SearchParams;
1190
1181
  SearchParams["FROM_AMOUNT"] = "fromAmount";
1191
1182
  })(SearchParams || (SearchParams = {}));
1192
1183
 
1184
+ const navigationRoutes = {
1185
+ home: '/',
1186
+ fromChain: 'from-chain',
1187
+ fromToken: 'from-token',
1188
+ toChain: 'to-chain',
1189
+ toToken: 'to-token',
1190
+ settings: 'settings',
1191
+ liquiditySources: '/settings/liquidity-sources',
1192
+ swaps: 'swaps',
1193
+ wallets: 'wallets',
1194
+ confirmSwap: 'confirm-swap',
1195
+ swapDetails: 'swaps/:requestId'
1196
+ };
1197
+
1193
1198
  const useUiStore = /*#__PURE__*/createSelectors( /*#__PURE__*/create()(set => ({
1194
1199
  connectWalletsButtonDisabled: false,
1195
1200
  selectedSwapRequestId: null,
@@ -1237,37 +1242,6 @@ function UpdateUrl() {
1237
1242
  if (requestId) setSelectedSwap(requestId);
1238
1243
  }, []);
1239
1244
  useEffect(() => {
1240
- let fromChainString = '',
1241
- fromTokenString = '',
1242
- toChainString = '',
1243
- toTokenString = '',
1244
- fromAmount = '';
1245
- if (loadingStatus !== 'success' && location.pathname != navigationRoutes.confirmSwap) {
1246
- fromChainString = searchParamsRef.current[SearchParams.FROM_CHAIN];
1247
- fromTokenString = searchParamsRef.current[SearchParams.FROM_TOKEN];
1248
- toChainString = searchParamsRef.current[SearchParams.TO_CHAIN];
1249
- toTokenString = searchParamsRef.current[SearchParams.TO_TOKEN];
1250
- fromAmount = searchParamsRef.current[SearchParams.FROM_AMOUNT];
1251
- setSearchParams({
1252
- ...(fromChainString && {
1253
- [SearchParams.FROM_CHAIN]: fromChainString
1254
- }),
1255
- ...(fromTokenString && {
1256
- [SearchParams.FROM_TOKEN]: fromTokenString
1257
- }),
1258
- ...(toChainString && {
1259
- [SearchParams.TO_CHAIN]: toChainString
1260
- }),
1261
- ...(toTokenString && {
1262
- [SearchParams.TO_TOKEN]: toTokenString
1263
- }),
1264
- ...(fromAmount && {
1265
- [SearchParams.FROM_AMOUNT]: fromAmount.toString()
1266
- })
1267
- }, {
1268
- replace: true
1269
- });
1270
- }
1271
1245
  if (!firstRender.current) {
1272
1246
  let fromChainString = '',
1273
1247
  fromTokenString = '',
@@ -1279,7 +1253,7 @@ function UpdateUrl() {
1279
1253
  fromTokenString = searchParamsRef.current[SearchParams.FROM_TOKEN];
1280
1254
  toChainString = searchParamsRef.current[SearchParams.TO_CHAIN];
1281
1255
  toTokenString = searchParamsRef.current[SearchParams.TO_TOKEN];
1282
- fromAmount = searchParamsRef.current[SearchParams.FROM_AMOUNT];
1256
+ fromAmount = searchParamsRef.current[SearchParams.FROM_AMOUNT] || inputAmount;
1283
1257
  } else {
1284
1258
  if (location.state === 'redirect') return;
1285
1259
  fromChainString = fromChain?.name || '';
@@ -1287,29 +1261,29 @@ function UpdateUrl() {
1287
1261
  toChainString = toChain?.name || '';
1288
1262
  toTokenString = (toToken?.symbol || '') + (toToken?.address ? `--${toToken?.address}` : '');
1289
1263
  fromAmount = inputAmount;
1290
- setSearchParams({
1291
- ...(fromChainString && {
1292
- [SearchParams.FROM_CHAIN]: fromChainString
1293
- }),
1294
- ...(fromTokenString && {
1295
- [SearchParams.FROM_TOKEN]: fromTokenString
1296
- }),
1297
- ...(toChainString && {
1298
- [SearchParams.TO_CHAIN]: toChainString
1299
- }),
1300
- ...(toTokenString && {
1301
- [SearchParams.TO_TOKEN]: toTokenString
1302
- }),
1303
- ...(fromAmount && {
1304
- [SearchParams.FROM_AMOUNT]: fromAmount.toString()
1305
- })
1306
- }, {
1307
- replace: true
1308
- });
1309
1264
  }
1265
+ setSearchParams({
1266
+ ...(fromChainString && {
1267
+ [SearchParams.FROM_CHAIN]: fromChainString
1268
+ }),
1269
+ ...(fromTokenString && {
1270
+ [SearchParams.FROM_TOKEN]: fromTokenString
1271
+ }),
1272
+ ...(toChainString && {
1273
+ [SearchParams.TO_CHAIN]: toChainString
1274
+ }),
1275
+ ...(toTokenString && {
1276
+ [SearchParams.TO_TOKEN]: toTokenString
1277
+ }),
1278
+ ...(fromAmount && {
1279
+ [SearchParams.FROM_AMOUNT]: fromAmount.toString()
1280
+ })
1281
+ }, {
1282
+ replace: true
1283
+ });
1310
1284
  }
1311
1285
  firstRender.current = false;
1312
- }, [location.pathname, inputAmount]);
1286
+ }, [location.pathname, inputAmount, fromChain, fromToken, toChain, toToken]);
1313
1287
  useEffect(() => {
1314
1288
  if (loadingStatus === 'success') {
1315
1289
  const fromChainString = searchParams.get(SearchParams.FROM_CHAIN);
@@ -1335,24 +1309,52 @@ function UpdateUrl() {
1335
1309
  return null;
1336
1310
  }
1337
1311
 
1338
- function PercentageChange(props) {
1312
+ function AppRouter(_ref) {
1313
+ let {
1314
+ children,
1315
+ ...props
1316
+ } = _ref;
1317
+ const isRouterInContext = useInRouterContext();
1318
+ const Router = isRouterInContext ? Fragment : MemoryRouter;
1339
1319
  const {
1340
- inputUsdValue,
1341
- outputUsdValue
1342
- } = props;
1343
- if (!inputUsdValue || !outputUsdValue || !outputUsdValue.gt(0)) return null;
1344
- const percentageChange = getPercentageChange(inputUsdValue.toNumber(), outputUsdValue.toNumber());
1345
- const showPercentageChange = percentageChange?.lt(0);
1346
- return React.createElement(React.Fragment, null, showPercentageChange && React.createElement(Typography, {
1347
- variant: "caption",
1348
- color: "$error500"
1349
- }, `(${numberToString(percentageChange, 0, 2)}%)`));
1320
+ blockchains
1321
+ } = useMetaStore.use.meta();
1322
+ const evmChains = blockchains.filter(isEvmBlockchain);
1323
+ useQueueManager({
1324
+ lastConnectedWallet: props.lastConnectedWallet,
1325
+ clearDisconnectedWallet: props.clearDisconnectedWallet,
1326
+ disconnectedWallet: props.disconnectedWallet,
1327
+ evmChains,
1328
+ notifier: () => {}
1329
+ });
1330
+ return React.createElement(React.Fragment, null, React.createElement(Router, null, children), isRouterInContext && React.createElement(UpdateUrl, null));
1331
+ }
1332
+
1333
+ function useNavigateBack() {
1334
+ const isRouterInContext = useInRouterContext$1();
1335
+ const navigate = useNavigate();
1336
+ const navigateBackFrom = currentRoute => {
1337
+ if (currentRoute === navigationRoutes.swapDetails) return navigate('/' + navigationRoutes.swaps, {
1338
+ replace: true
1339
+ });
1340
+ if (!isRouterInContext || window.history.state && window.history.state.idx > 0) navigate(-1);else {
1341
+ if ([navigationRoutes.fromChain, navigationRoutes.fromToken, navigationRoutes.toChain, navigationRoutes.toToken, navigationRoutes.settings, navigationRoutes.wallets, navigationRoutes.swaps, navigationRoutes.confirmSwap].includes(currentRoute)) navigate(navigationRoutes.home, {
1342
+ replace: true
1343
+ });else if (currentRoute === navigationRoutes.liquiditySources) navigate('/' + navigationRoutes.settings, {
1344
+ replace: true
1345
+ });
1346
+ }
1347
+ };
1348
+ return {
1349
+ navigateBackFrom
1350
+ };
1350
1351
  }
1351
1352
 
1352
1353
  const Box = /*#__PURE__*/styled('div', {
1353
1354
  display: 'flex',
1354
1355
  flexDirection: 'column',
1355
- width: '100%'
1356
+ width: '100%',
1357
+ overflow: 'hidden'
1356
1358
  });
1357
1359
  const Container = /*#__PURE__*/styled('div', {
1358
1360
  boxSizing: 'border-box',
@@ -1375,7 +1377,10 @@ const Container = /*#__PURE__*/styled('div', {
1375
1377
  display: 'flex',
1376
1378
  justifyContent: 'space-between',
1377
1379
  alignItems: 'center',
1378
- minHeight: '32px'
1380
+ minHeight: '32px',
1381
+ '.usd-value': {
1382
+ paddingLeft: '$8'
1383
+ }
1379
1384
  },
1380
1385
  '.form': {
1381
1386
  display: 'flex',
@@ -1392,21 +1397,6 @@ const Container = /*#__PURE__*/styled('div', {
1392
1397
  '.amount': {
1393
1398
  width: '30%'
1394
1399
  }
1395
- },
1396
- '.output-usd': {
1397
- display: 'flex',
1398
- div: {
1399
- display: 'flex',
1400
- paddingLeft: '$8'
1401
- }
1402
- }
1403
- });
1404
- const Options = /*#__PURE__*/styled('div', {
1405
- display: 'flex',
1406
- justifyContent: 'flex-end',
1407
- '.balance': {
1408
- display: 'flex',
1409
- alignItems: 'center'
1410
1400
  }
1411
1401
  });
1412
1402
  const ImagePlaceholder = /*#__PURE__*/styled('span', {
@@ -1427,28 +1417,16 @@ const OutputContainer = /*#__PURE__*/styled('div', {
1427
1417
  paddingLeft: '$8',
1428
1418
  paddingRight: '$8'
1429
1419
  });
1430
- function TokenInfo(props) {
1420
+ function TokenPreview(props) {
1431
1421
  const {
1432
- type,
1433
1422
  chain,
1434
- token
1423
+ token,
1424
+ loadingStatus,
1425
+ percentageChange
1435
1426
  } = props;
1436
- const loadingStatus = useMetaStore.use.loadingStatus();
1437
- const fromChain = useBestRouteStore.use.fromChain();
1438
- const toChain = useBestRouteStore.use.toChain();
1439
- const inputUsdValue = useBestRouteStore.use.inputUsdValue();
1440
- const fromToken = useBestRouteStore.use.fromToken();
1441
- const setInputAmount = useBestRouteStore.use.setInputAmount();
1442
- const bestRoute = useBestRouteStore.use.bestRoute();
1443
- const inputAmount = useBestRouteStore.use.inputAmount();
1444
- const balances = useWalletsStore.use.balances();
1445
- const fetchingBestRoute = useBestRouteStore.use.loading();
1446
- const navigate = useNavigate();
1447
1427
  const {
1448
1428
  t
1449
1429
  } = useTranslation();
1450
- const tokenBalance = !!fromChain && !!fromToken ? numberToString(getBalanceFromWallet(balances, fromChain?.name, fromToken?.symbol, fromToken?.address)?.amount || '0', 8) : '0';
1451
- const tokenBalanceReal = !!fromChain && !!fromToken ? numberToString(getBalanceFromWallet(balances, fromChain?.name, fromToken?.symbol, fromToken?.address)?.amount || '0', getBalanceFromWallet(balances, fromChain?.name, fromToken?.symbol, fromToken?.address)?.decimal) : '0';
1452
1430
  const ItemSuffix = React.createElement("div", {
1453
1431
  style: {
1454
1432
  display: 'flex',
@@ -1458,45 +1436,23 @@ function TokenInfo(props) {
1458
1436
  }, loadingStatus === 'failed' && React.createElement(InfoCircleIcon, {
1459
1437
  color: "error",
1460
1438
  size: 24
1461
- }), React.createElement(AngleDownIcon, null));
1439
+ }));
1462
1440
  return React.createElement(Box, null, React.createElement(Container, {
1463
- type: props.type === 'From' ? 'filled' : 'outlined'
1441
+ type: 'outlined'
1464
1442
  }, React.createElement("div", {
1465
1443
  className: "head"
1466
1444
  }, React.createElement(Typography, {
1467
1445
  variant: "body2",
1468
1446
  color: "neutrals800"
1469
- }, t(type)), props.type === 'From' ? React.createElement(Options, null, React.createElement("div", {
1470
- className: "balance",
1471
- onClick: () => {
1472
- if (tokenBalance !== '0') setInputAmount(tokenBalanceReal.split(',').join(''));
1473
- }
1474
- }, React.createElement(Typography, {
1475
- variant: "body3",
1476
- color: "neutrals600"
1477
- }, `${t('Balance')}: ${tokenBalance} ${fromToken?.symbol || ''}`), React.createElement(Spacer, {
1478
- size: 4
1479
- }), React.createElement(Button, {
1480
- type: "primary",
1481
- variant: "ghost",
1482
- size: "compact"
1483
- }, t('Max')))) : React.createElement("div", {
1484
- className: "output-usd"
1485
- }, React.createElement(PercentageChange, {
1486
- inputUsdValue: inputUsdValue,
1487
- outputUsdValue: props.outputUsdValue
1488
- }), React.createElement("div", null, React.createElement(Typography, {
1447
+ }, props.label), React.createElement("div", null, percentageChange, props.usdValue && React.createElement(Typography, {
1489
1448
  variant: "caption",
1490
- color: "neutrals600"
1491
- }, `$${numberToString(props.outputUsdValue)}`)))), React.createElement("div", {
1449
+ color: "neutrals600",
1450
+ className: "usd-value"
1451
+ }, `$${numberToString(props.usdValue)}`))), React.createElement("div", {
1492
1452
  className: "form"
1493
1453
  }, React.createElement(Button, {
1494
1454
  className: "selectors",
1495
- onClick: () => {
1496
- navigate(`/${props.type.toLowerCase()}-chain`);
1497
- },
1498
1455
  variant: "outlined",
1499
- disabled: loadingStatus === 'failed',
1500
1456
  loading: loadingStatus === 'loading',
1501
1457
  prefix: loadingStatus === 'success' && chain ? React.createElement(Image, {
1502
1458
  src: chain.logo,
@@ -1509,11 +1465,7 @@ function TokenInfo(props) {
1509
1465
  size: 12
1510
1466
  }), React.createElement(Button, {
1511
1467
  className: "selectors",
1512
- onClick: () => {
1513
- navigate(`/${props.type.toLowerCase()}-token`);
1514
- },
1515
1468
  variant: "outlined",
1516
- disabled: loadingStatus === 'failed' || type === 'From' && !fromChain || type === 'To' && !toChain,
1517
1469
  loading: loadingStatus === 'loading',
1518
1470
  prefix: loadingStatus === 'success' && token ? React.createElement(Image, {
1519
1471
  src: token.image,
@@ -1526,983 +1478,998 @@ function TokenInfo(props) {
1526
1478
  size: 12
1527
1479
  }), React.createElement("div", {
1528
1480
  className: "amount"
1529
- }, props.type === 'From' ? React.createElement(TextField, {
1530
- type: "number",
1531
- size: "large",
1532
- autoFocus: true,
1533
- placeholder: "0",
1534
- style: {
1535
- position: 'relative',
1536
- backgroundColor: '$background !important'
1537
- },
1538
- suffix: React.createElement("span", {
1539
- style: {
1540
- position: 'absolute',
1541
- right: '4px',
1542
- bottom: '2px'
1543
- }
1544
- }, React.createElement(Typography, {
1545
- variant: "caption",
1546
- color: "neutrals800"
1547
- }, `$${numberToString(inputUsdValue)}`)),
1548
- value: props.inputAmount || '',
1549
- min: 0,
1550
- onChange: props.type === 'From' ? event => {
1551
- props.onAmountChange(event.target.value);
1552
- } : undefined
1553
- }) : React.createElement(OutputContainer, null, React.createElement(Typography, {
1481
+ }, React.createElement(OutputContainer, null, React.createElement(Typography, {
1554
1482
  variant: "h4"
1555
- }, fetchingBestRoute && '?', !!bestRoute?.result && `≈ ${numberToString(props.outputAmount)}`, (!inputAmount || inputAmount === '0') && '0'))))));
1483
+ }, props.amount))))));
1556
1484
  }
1557
1485
 
1558
- const Container$1 = /*#__PURE__*/styled$1('div', {
1486
+ const Container$1 = /*#__PURE__*/styled('div', {
1559
1487
  display: 'flex',
1560
- width: '100%',
1561
- justifyContent: 'end',
1562
1488
  alignItems: 'center',
1563
- paddingTop: '$16'
1489
+ justifyContent: 'space-between',
1490
+ padding: '$8',
1491
+ borderRadius: '$5',
1492
+ backgroundColor: '$neutrals300',
1493
+ color: '$neutrals800',
1494
+ fontSize: '$12',
1495
+ '.routes': {
1496
+ display: 'flex',
1497
+ alignItems: 'center'
1498
+ },
1499
+ '.fee': {
1500
+ display: 'flex',
1501
+ alignItems: 'center'
1502
+ }
1564
1503
  });
1565
- const Logo = /*#__PURE__*/styled$1('svg', {
1566
- fill: '$foreground',
1567
- width: '$24',
1568
- margin: '0 $8 0 $16'
1569
- });
1570
- const StyledAnchor = /*#__PURE__*/styled$1('a', {
1571
- display: 'flex',
1572
- justifyContent: 'center',
1573
- alignItems: 'center',
1574
- textDecoration: 'none'
1575
- });
1576
- function BottomLogo() {
1577
- const {
1578
- t
1579
- } = useTranslation();
1580
- return React.createElement(Container$1, null, React.createElement(Typography, {
1581
- variant: "caption"
1582
- }, t('Powered By')), React.createElement(StyledAnchor, {
1583
- href: "https://rango.exchange",
1584
- target: "_blank"
1585
- }, React.createElement(Logo, {
1586
- xmlns: "http://www.w3.org/2000/svg",
1587
- viewBox: "0 0 33.68 29"
1588
- }, React.createElement("defs", null), React.createElement("g", {
1589
- id: "Layer_2",
1590
- "data-name": "Layer 2"
1591
- }, React.createElement("g", {
1592
- id: "Layer_1-2",
1593
- "data-name": "Layer 1"
1594
- }, React.createElement("path", {
1595
- d: "M33.68,18.05A17.93,17.93,0,0,0,28.34,5.29,18.31,18.31,0,0,0,15.45,0H13.54V7.41L6.07,0H.69L9.83,9.07H0V11A17.93,17.93,0,0,0,5.34,23.71,18.32,18.32,0,0,0,18.24,29h1.9V21.59l7.38,7.31h5.39l-9-9h9.82ZM17.37,16.16H12.49a1.93,1.93,0,0,0-1.35.55,1.89,1.89,0,0,0-.56,1.34,1.85,1.85,0,0,0,.56,1.33,1.93,1.93,0,0,0,1.35.55h3.84V25.1A14.43,14.43,0,0,1,8,21a14.21,14.21,0,0,1-4.1-8.2H21.2a1.86,1.86,0,0,0,.74-.13,1.92,1.92,0,0,0,.64-.4,2,2,0,0,0,.43-.62,1.88,1.88,0,0,0,0-1.47,2,2,0,0,0-.43-.62,1.92,1.92,0,0,0-.64-.4,1.86,1.86,0,0,0-.74-.13H17.35V3.9A14.43,14.43,0,0,1,25.64,8a14.19,14.19,0,0,1,4.11,8.2Zm2.12-5.27a1.43,1.43,0,0,1,.26-.83,1.52,1.52,0,0,1,.67-.56,1.55,1.55,0,0,1,.88-.08,1.51,1.51,0,0,1,.77.4,1.54,1.54,0,0,1,.42.77,1.41,1.41,0,0,1-.09.86,1.47,1.47,0,0,1-.55.68,1.56,1.56,0,0,1-.84.25,1.52,1.52,0,0,1-1.52-1.49Z"
1596
- }), React.createElement("path", {
1597
- d: "M21.7,11.57a.68.68,0,0,0-.12-.38.64.64,0,0,0-.31-.25.68.68,0,0,0-.75.15.61.61,0,0,0-.19.35.62.62,0,0,0,0,.4.67.67,0,0,0,.25.3.69.69,0,0,0,.39.12.7.7,0,0,0,.49-.2A.68.68,0,0,0,21.7,11.57Z"
1598
- })))), React.createElement(Typography, {
1599
- variant: "body2"
1600
- }, "RANGO")));
1601
- }
1602
-
1603
- function SwithFromAndTo(_ref) {
1604
- let {
1605
- count
1606
- } = _ref;
1607
- const firstRender = useRef(true);
1608
- const [searchParams, setSearchParams] = useSearchParams();
1609
- const outputAmount = useBestRouteStore.use.outputAmount();
1610
- useEffect(() => {
1611
- if (!firstRender.current) {
1612
- const fromChainString = searchParams.get(SearchParams.FROM_CHAIN);
1613
- const fromTokenString = searchParams.get(SearchParams.FROM_TOKEN);
1614
- const toChainString = searchParams.get(SearchParams.TO_CHAIN);
1615
- const toTokenString = searchParams.get(SearchParams.TO_TOKEN);
1616
- setSearchParams({
1617
- ...(toChainString && {
1618
- [SearchParams.FROM_CHAIN]: toChainString
1619
- }),
1620
- ...(toTokenString && {
1621
- [SearchParams.FROM_TOKEN]: toTokenString
1622
- }),
1623
- ...(fromChainString && {
1624
- [SearchParams.TO_CHAIN]: fromChainString
1625
- }),
1626
- ...(fromTokenString && {
1627
- [SearchParams.TO_TOKEN]: fromTokenString
1628
- }),
1629
- ...(outputAmount && {
1630
- [SearchParams.FROM_AMOUNT]: outputAmount.toString()
1631
- })
1632
- });
1633
- } else {
1634
- firstRender.current = false;
1635
- }
1636
- }, [count]);
1637
- return null;
1504
+ function RoutesOverview(props) {
1505
+ if (!props.routes) return null;
1506
+ const swaps = props.routes.result?.swaps;
1507
+ return React.createElement(Container$1, null, React.createElement("div", {
1508
+ className: "routes"
1509
+ }, swaps?.map((swap, idx) => {
1510
+ const isLast = idx + 1 == swaps.length;
1511
+ return React.createElement(React.Fragment, {
1512
+ key: idx
1513
+ }, React.createElement("div", {
1514
+ className: "route"
1515
+ }, swap.from.symbol), React.createElement(ChevronRightIcon, {
1516
+ size: 12
1517
+ }), isLast ? React.createElement("div", {
1518
+ className: "route"
1519
+ }, swap.to.symbol) : null);
1520
+ })), props.totalFee ? React.createElement("div", {
1521
+ className: "fee"
1522
+ }, React.createElement(GasIcon, {
1523
+ size: 12
1524
+ }), React.createElement(Spacer, {
1525
+ size: 4
1526
+ }), "$", props.totalFee) : null);
1638
1527
  }
1639
1528
 
1640
- const Footer = /*#__PURE__*/styled('div', {
1641
- display: 'flex',
1642
- flexDirection: 'column',
1643
- width: '100%',
1644
- paddingTop: '$16'
1645
- });
1646
-
1647
- const errorMessages = {
1648
- genericServerError: 'Error connecting server, please reload the app and try again'
1649
- };
1650
-
1651
- const ButtonsContainer = /*#__PURE__*/styled('div', {
1652
- display: 'flex'
1653
- });
1654
- function HeaderButtons(props) {
1655
- const {
1656
- onClickRefresh
1657
- } = props;
1658
- const navigate = useNavigate();
1659
- return React.createElement(ButtonsContainer, null, React.createElement(Tooltip, {
1660
- content: "Refresh"
1661
- }, React.createElement(Button, {
1662
- variant: "ghost",
1663
- onClick: onClickRefresh,
1664
- disabled: !onClickRefresh
1665
- }, React.createElement(RetryIcon, {
1666
- size: 24,
1667
- disabled: !onClickRefresh
1668
- }))), React.createElement(Tooltip, {
1669
- content: "Transactions History"
1670
- }, React.createElement(Button, {
1671
- variant: "ghost",
1672
- onClick: () => navigate(navigationRoutes.swaps)
1673
- }, React.createElement(HistoryIcon, {
1674
- size: 24
1675
- }))), React.createElement(Tooltip, {
1676
- content: "Settings"
1677
- }, React.createElement(Button, {
1678
- variant: "ghost",
1679
- onClick: () => navigate(navigationRoutes.settings)
1680
- }, React.createElement(SettingsIcon, {
1681
- size: 24
1682
- }))));
1683
- }
1529
+ var ConfirmSwapErrorTypes;
1530
+ (function (ConfirmSwapErrorTypes) {
1531
+ ConfirmSwapErrorTypes[ConfirmSwapErrorTypes["NO_ROUTE"] = 0] = "NO_ROUTE";
1532
+ ConfirmSwapErrorTypes[ConfirmSwapErrorTypes["ROUTE_UPDATED_WITH_HIGH_VALUE_LOSS"] = 1] = "ROUTE_UPDATED_WITH_HIGH_VALUE_LOSS";
1533
+ ConfirmSwapErrorTypes[ConfirmSwapErrorTypes["REQUEST_FAILED"] = 2] = "REQUEST_FAILED";
1534
+ ConfirmSwapErrorTypes[ConfirmSwapErrorTypes["INSUFFICIENT_SLIPPAGE"] = 3] = "INSUFFICIENT_SLIPPAGE";
1535
+ ConfirmSwapErrorTypes[ConfirmSwapErrorTypes["INSUFFICIENT_BALANCE"] = 4] = "INSUFFICIENT_BALANCE";
1536
+ })(ConfirmSwapErrorTypes || (ConfirmSwapErrorTypes = {}));
1537
+ var ConfirmSwapWarningTypes;
1538
+ (function (ConfirmSwapWarningTypes) {
1539
+ ConfirmSwapWarningTypes[ConfirmSwapWarningTypes["ROUTE_UPDATED"] = 0] = "ROUTE_UPDATED";
1540
+ ConfirmSwapWarningTypes[ConfirmSwapWarningTypes["ROUTE_SWAPPERS_UPDATED"] = 1] = "ROUTE_SWAPPERS_UPDATED";
1541
+ ConfirmSwapWarningTypes[ConfirmSwapWarningTypes["ROUTE_COINS_UPDATED"] = 2] = "ROUTE_COINS_UPDATED";
1542
+ ConfirmSwapWarningTypes[ConfirmSwapWarningTypes["ROUTE_AND_OUTPUT_AMOUNT_UPDATED"] = 3] = "ROUTE_AND_OUTPUT_AMOUNT_UPDATED";
1543
+ })(ConfirmSwapWarningTypes || (ConfirmSwapWarningTypes = {}));
1684
1544
 
1685
- const Container$2 = /*#__PURE__*/styled('div', {
1686
- display: 'flex',
1687
- flexDirection: 'column'
1688
- });
1689
- const FromContainer = /*#__PURE__*/styled('div', {
1690
- position: 'relative',
1691
- paddingBottom: '$12'
1692
- });
1693
- const SwitchButtonContainer = /*#__PURE__*/styled('div', {
1694
- position: 'absolute',
1695
- bottom: '-12px',
1696
- left: '50%',
1697
- transform: 'translate(-50%, 10%)'
1698
- });
1699
- const BestRouteContainer = /*#__PURE__*/styled('div', {
1700
- width: '100%',
1701
- paddingTop: '$16'
1702
- });
1703
- const Alerts = /*#__PURE__*/styled('div', {
1704
- width: '100%',
1705
- paddingTop: '$16'
1706
- });
1707
- function Home() {
1708
- const isRouterInContext = useInRouterContext();
1709
- const navigate = useNavigate();
1710
- const [count, setCount] = useState(0);
1711
- const fromChain = useBestRouteStore.use.fromChain();
1545
+ function useConfirmSwap() {
1712
1546
  const fromToken = useBestRouteStore.use.fromToken();
1713
- const toChain = useBestRouteStore.use.toChain();
1714
1547
  const toToken = useBestRouteStore.use.toToken();
1715
- const setInputAmount = useBestRouteStore.use.setInputAmount();
1716
- const inputUsdValue = useBestRouteStore.use.inputUsdValue();
1717
1548
  const inputAmount = useBestRouteStore.use.inputAmount();
1718
- const outputAmount = useBestRouteStore.use.outputAmount();
1719
- const outputUsdValue = useBestRouteStore.use.outputUsdValue();
1720
- const bestRoute = useBestRouteStore.use.bestRoute();
1721
- const tokens = useMetaStore.use.meta().tokens;
1722
- const fetchingBestRoute = useBestRouteStore.use.loading();
1723
- const bestRouteError = useBestRouteStore.use.error();
1724
- const loadingMetaStatus = useMetaStore.use.loadingStatus();
1549
+ const initialRoute = useBestRouteStore.use.bestRoute();
1550
+ const setBestRoute = useBestRouteStore.use.setBestRoute();
1551
+ const inputUsdValue = useBestRouteStore.use.inputUsdValue();
1552
+ const affiliateRef = useSettingsStore.use.affiliateRef();
1725
1553
  const accounts = useWalletsStore.use.accounts();
1726
- const setCurrentPage = useUiStore.use.setCurrentPage();
1727
- const switchFromAndTo = useBestRouteStore.use.switchFromAndTo();
1728
- const errorMessage = loadingMetaStatus === 'failed' ? errorMessages.genericServerError : bestRouteError;
1729
- const needsToWarnEthOnPath = false;
1730
- const showBestRoute = inputAmount && (!!bestRoute || fetchingBestRoute || bestRouteError);
1731
- const outToInRatio = getOutputRatio(inputUsdValue, outputUsdValue);
1732
- const highValueLoss = outputRatioHasWarning(inputUsdValue, outToInRatio);
1733
- const {
1734
- fromAmountRangeError,
1735
- recommendation,
1736
- swap
1737
- } = LimitErrorMessage(bestRoute);
1738
- const priceImpactCanNotBeComputed = !canComputePriceImpact(bestRoute, inputAmount, inputUsdValue, outputUsdValue);
1739
- const swapButtonState = getSwapButtonState(loadingMetaStatus, accounts, fetchingBestRoute, bestRoute, hasLimitError(bestRoute), highValueLoss, priceImpactCanNotBeComputed, needsToWarnEthOnPath, inputAmount);
1740
- const totalFeeInUsd = getTotalFeeInUsd(bestRoute, tokens);
1741
- const highFee = hasHighFee(totalFeeInUsd);
1554
+ const selectedWallets = useWalletsStore.use.selectedWallets();
1555
+ const meta = useMetaStore.use.meta();
1556
+ const customSlippage = useSettingsStore.use.customSlippage();
1557
+ const slippage = useSettingsStore.use.slippage();
1558
+ const disabledLiquiditySources = useSettingsStore.use.disabledLiquiditySources();
1559
+ const userSlippage = customSlippage || slippage;
1560
+ const proceedAnywayRef = useRef(false);
1561
+ const confiremedRouteRef = useRef(null);
1562
+ let abortControllerRef = useRef(null);
1563
+ const [loading, setLoading] = useState(false);
1564
+ const [errors, setErrors] = useState([]);
1565
+ const [warnings, setWarnings] = useState([]);
1742
1566
  useEffect(() => {
1743
- setCurrentPage(navigationRoutes.home);
1744
- return setCurrentPage.bind(null, '');
1567
+ return () => abortControllerRef.current?.abort();
1745
1568
  }, []);
1746
- return React.createElement(Container$2, null, React.createElement(Header$1, {
1747
- title: "SWAP",
1748
- suffix: React.createElement(HeaderButtons, {
1749
- onClickRefresh: !!bestRoute ? fetchBestRoute : undefined
1750
- })
1751
- }), React.createElement(FromContainer, null, React.createElement(TokenInfo, {
1752
- type: "From",
1753
- chain: fromChain,
1754
- token: fromToken,
1755
- onAmountChange: setInputAmount,
1756
- inputAmount: inputAmount
1757
- }), React.createElement(SwitchButtonContainer, null, React.createElement(Button, {
1758
- variant: "ghost",
1759
- onClick: () => {
1760
- switchFromAndTo();
1761
- setCount(prev => prev + 1);
1569
+ if (!fromToken || !toToken || !inputAmount || !initialRoute) return {
1570
+ loading: false,
1571
+ warnings: [],
1572
+ errors: [],
1573
+ confirmSwap: null
1574
+ };
1575
+ const confirmSwap = async () => {
1576
+ if (proceedAnywayRef.current) {
1577
+ const swapSettings = {
1578
+ slippage: userSlippage.toString(),
1579
+ disabledSwappersGroups: disabledLiquiditySources
1580
+ };
1581
+ if (errors.length > 0) setErrors([]);
1582
+ if (warnings.length > 0) setWarnings([]);
1583
+ proceedAnywayRef.current = false;
1584
+ if (confiremedRouteRef.current) {
1585
+ const newSwap = calculatePendingSwap(inputAmount.toString(), confiremedRouteRef.current, getWalletsForNewSwap(selectedWallets), swapSettings, false, meta);
1586
+ return newSwap;
1587
+ }
1588
+ return;
1762
1589
  }
1763
- }, React.createElement(VerticalSwapIcon, {
1764
- size: 32
1765
- }), isRouterInContext && React.createElement(SwithFromAndTo, {
1766
- count: count
1767
- })))), React.createElement(TokenInfo, {
1768
- type: "To",
1769
- chain: toChain,
1770
- token: toToken,
1771
- outputAmount: outputAmount ? new BigNumber(outputAmount) : new BigNumber(0),
1772
- outputUsdValue: outputUsdValue
1773
- }), showBestRoute && React.createElement(BestRouteContainer, null, React.createElement(BestRoute, {
1774
- error: bestRouteError,
1775
- loading: fetchingBestRoute,
1776
- data: getFormatedBestRoute(bestRoute),
1777
- totalFee: numberToString(totalFeeInUsd, 0, 2),
1778
- feeWarning: highFee,
1779
- totalTime: secondsToString(totalArrivalTime(bestRoute))
1780
- })), (errorMessage || hasLimitError(bestRoute)) && React.createElement(Alerts, null, errorMessage && React.createElement(Alert, {
1781
- type: "error"
1782
- }, errorMessage), hasLimitError(bestRoute) && React.createElement(Alert, {
1783
- type: "error",
1784
- title: `${swap?.swapperId} Limit`
1785
- }, React.createElement(React.Fragment, null, React.createElement(Typography, {
1786
- variant: "body2"
1787
- }, `${fromAmountRangeError}, Yours: ${numberToString(swap?.fromAmount || null)} ${swap?.from.symbol}`), React.createElement(Typography, {
1788
- variant: "body2"
1789
- }, recommendation)))), React.createElement(Footer, null, React.createElement(Button, {
1790
- type: "primary",
1791
- align: "grow",
1792
- size: "large",
1793
- disabled: swapButtonState.disabled,
1794
- onClick: () => {
1795
- if (swapButtonState.title === 'Connect Wallet') navigate(navigationRoutes.wallets);else {
1796
- navigate(navigationRoutes.confirmSwap, {
1797
- replace: true
1590
+ abortControllerRef.current = new AbortController();
1591
+ setLoading(true);
1592
+ const requestBody = createBestRouteRequestBody(fromToken, toToken, inputAmount, accounts, selectedWallets, disabledLiquiditySources, userSlippage, affiliateRef, initialRoute);
1593
+ try {
1594
+ const confiremedRoute = await httpService().getBestRoute(requestBody, {
1595
+ signal: abortControllerRef.current?.signal
1596
+ });
1597
+ abortControllerRef.current = null;
1598
+ setLoading(false);
1599
+ if (!confiremedRoute.result || !new BigNumber(confiremedRoute.requestAmount).isEqualTo(new BigNumber(inputAmount || '-1'))) {
1600
+ setErrors(prevState => prevState.concat({
1601
+ type: ConfirmSwapErrorTypes.NO_ROUTE
1602
+ }));
1603
+ return;
1604
+ }
1605
+ const confirmSwapState = {
1606
+ errors: [],
1607
+ warnings: []
1608
+ };
1609
+ const routeChanged = isRouteChanged(initialRoute, confiremedRoute);
1610
+ if (routeChanged) {
1611
+ setBestRoute(confiremedRoute);
1612
+ const newRouteOutputUsdValue = new BigNumber(confiremedRoute.result?.outputAmount || '0').multipliedBy(toToken.usdPrice || 0);
1613
+ const outputRatio = getOutputRatio(inputUsdValue, newRouteOutputUsdValue);
1614
+ const highValueLoss = outputRatioHasWarning(inputUsdValue, outputRatio);
1615
+ if (highValueLoss) confirmSwapState.errors.push({
1616
+ type: ConfirmSwapErrorTypes.ROUTE_UPDATED_WITH_HIGH_VALUE_LOSS
1617
+ });else if (isOutputAmountChangedALot(initialRoute, confiremedRoute)) confirmSwapState.warnings.push({
1618
+ type: ConfirmSwapWarningTypes.ROUTE_AND_OUTPUT_AMOUNT_UPDATED,
1619
+ newOutputAmount: numberToString(getRouteOutputAmount(confiremedRoute)),
1620
+ percentageChange: numberToString(getPercentageChange(getRouteOutputAmount(initialRoute), getRouteOutputAmount(confiremedRoute)), null, 2)
1621
+ });else if (isRouteInternalCoinsUpdated(initialRoute, confiremedRoute)) confirmSwapState.warnings.push({
1622
+ type: ConfirmSwapWarningTypes.ROUTE_COINS_UPDATED
1623
+ });else if (isNumberOfSwapsChanged(initialRoute, confiremedRoute)) confirmSwapState.warnings.push({
1624
+ type: ConfirmSwapWarningTypes.ROUTE_UPDATED
1625
+ });else if (isRouteSwappersUpdated(initialRoute, confiremedRoute)) confirmSwapState.warnings.push({
1626
+ type: ConfirmSwapWarningTypes.ROUTE_SWAPPERS_UPDATED
1798
1627
  });
1799
1628
  }
1800
- }
1801
- }, swapButtonState.title), React.createElement(BottomLogo, null)));
1802
- }
1803
-
1804
- const Route = _ref => {
1805
- let {
1806
- children
1807
- } = _ref;
1808
- const location = useLocation$1();
1809
- const navigate = useNavigate$1();
1810
- const ref = useRef(true);
1811
- useEffect(() => {
1812
- if (location.pathname === navigationRoutes.confirmSwap && ref.current) navigate(navigationRoutes.home + location.search, {
1813
- state: 'redirect'
1814
- });
1815
- ref.current = false;
1816
- }, []);
1817
- if (location.pathname === navigationRoutes.confirmSwap && ref.current) return React.createElement(Home, null);
1818
- return React.createElement(React.Fragment, null, " ", children);
1819
- };
1820
- function AppRouter(_ref2) {
1821
- let {
1822
- children,
1823
- ...props
1824
- } = _ref2;
1825
- const isRouterInContext = useInRouterContext$1();
1826
- const Router = isRouterInContext ? Route : MemoryRouter;
1827
- const {
1828
- blockchains
1829
- } = useMetaStore.use.meta();
1830
- const evmChains = blockchains.filter(isEvmBlockchain);
1831
- useQueueManager({
1832
- lastConnectedWallet: props.lastConnectedWallet,
1833
- clearDisconnectedWallet: props.clearDisconnectedWallet,
1834
- disconnectedWallet: props.disconnectedWallet,
1835
- evmChains,
1836
- notifier: () => {}
1837
- });
1838
- return React.createElement(React.Fragment, null, React.createElement(Router, Object.assign({}, props), children), isRouterInContext && React.createElement(UpdateUrl, null));
1839
- }
1840
-
1841
- function useNavigateBack() {
1842
- const isRouterInContext = useInRouterContext();
1843
- const navigate = useNavigate();
1844
- const navigateBackFrom = currentRoute => {
1845
- if (currentRoute === navigationRoutes.swapDetails) return navigate(navigationRoutes.swaps, {
1846
- replace: true
1847
- });
1848
- if (!isRouterInContext || window.history.state && window.history.state.idx > 0) navigate(-1);else {
1849
- if ([navigationRoutes.fromChain, navigationRoutes.fromToken, navigationRoutes.toChain, navigationRoutes.toToken, navigationRoutes.settings, navigationRoutes.wallets, navigationRoutes.swaps, navigationRoutes.confirmSwap].includes(currentRoute)) navigate(navigationRoutes.home, {
1850
- replace: true
1851
- });else if (currentRoute === navigationRoutes.liquiditySources) navigate(navigationRoutes.settings, {
1852
- replace: true
1853
- });else if (currentRoute === navigationRoutes.swapDetails) navigate(navigationRoutes.swaps, {
1854
- replace: true
1629
+ const balanceWarnings = getBalanceWarnings(confiremedRoute, selectedWallets);
1630
+ const enoughBalance = balanceWarnings.length === 0;
1631
+ if (!enoughBalance) confirmSwapState.errors.push({
1632
+ type: ConfirmSwapErrorTypes.INSUFFICIENT_BALANCE,
1633
+ messages: balanceWarnings
1634
+ });
1635
+ const minRequiredSlippage = getMinRequiredSlippage(initialRoute);
1636
+ if (!hasProperSlippage(userSlippage.toString(), minRequiredSlippage)) confirmSwapState.errors.push({
1637
+ type: ConfirmSwapErrorTypes.INSUFFICIENT_SLIPPAGE,
1638
+ minRequiredSlippage
1855
1639
  });
1640
+ const noErrors = confirmSwapState.errors.length === 0;
1641
+ const noWarnings = confirmSwapState.warnings.length === 0;
1642
+ if ((noErrors || !noErrors && proceedAnywayRef.current) && (noWarnings || !noWarnings && proceedAnywayRef.current)) {
1643
+ const swapSettings = {
1644
+ slippage: userSlippage.toString(),
1645
+ disabledSwappersGroups: disabledLiquiditySources
1646
+ };
1647
+ const newSwap = calculatePendingSwap(inputAmount.toString(), confiremedRoute, getWalletsForNewSwap(selectedWallets), swapSettings, false, meta);
1648
+ return newSwap;
1649
+ } else if (!proceedAnywayRef.current) {
1650
+ proceedAnywayRef.current = true;
1651
+ setErrors(confirmSwapState.errors);
1652
+ setWarnings(confirmSwapState.warnings);
1653
+ confiremedRouteRef.current = confiremedRoute;
1654
+ }
1655
+ return;
1656
+ } catch (error) {
1657
+ if (error?.code === 'ERR_CANCELED') {
1658
+ return;
1659
+ }
1660
+ const status = error?.response?.status;
1661
+ setLoading(false);
1662
+ setErrors([{
1663
+ type: ConfirmSwapErrorTypes.REQUEST_FAILED,
1664
+ status
1665
+ }]);
1666
+ return;
1856
1667
  }
1857
1668
  };
1858
1669
  return {
1859
- navigateBackFrom
1670
+ loading,
1671
+ warnings,
1672
+ errors,
1673
+ confirmSwap
1860
1674
  };
1861
1675
  }
1862
1676
 
1863
- const Box$1 = /*#__PURE__*/styled('div', {
1864
- display: 'flex',
1865
- flexDirection: 'column',
1866
- width: '100%'
1677
+ function ChangeSlippageButton() {
1678
+ const navigate = useNavigate();
1679
+ return React.createElement(Button, {
1680
+ type: "primary",
1681
+ variant: "outlined",
1682
+ size: "small",
1683
+ onClick: () => navigate('/' + navigationRoutes.settings)
1684
+ }, "Change Slippage");
1685
+ }
1686
+
1687
+ const StyledMessage = /*#__PURE__*/styled(Typography, {
1688
+ color: '$error500 !important'
1867
1689
  });
1868
- const Container$3 = /*#__PURE__*/styled('div', {
1869
- boxSizing: 'border-box',
1870
- borderRadius: '$5',
1871
- padding: '$8 $16 $16 $16',
1690
+ function MinRequiredSlippage(_ref) {
1691
+ let {
1692
+ minRequiredSlippage
1693
+ } = _ref;
1694
+ return React.createElement(StyledMessage, {
1695
+ variant: "body2"
1696
+ }, "We recommend you to increase slippage to at least \u00A0", minRequiredSlippage, "\u00A0 for this route.", React.createElement(Spacer, {
1697
+ size: 8,
1698
+ direction: "vertical"
1699
+ }), React.createElement(ChangeSlippageButton, null));
1700
+ }
1701
+
1702
+ const List = /*#__PURE__*/styled('ul', {
1703
+ padding: 0,
1704
+ margin: 0,
1872
1705
  variants: {
1873
- type: {
1874
- filled: {
1875
- backgroundColor: '$neutrals300'
1876
- },
1877
- outlined: {
1878
- border: '1px solid $neutrals300'
1706
+ showListStyle: {
1707
+ true: {
1708
+ paddingLeft: '$24'
1879
1709
  }
1880
1710
  }
1881
- },
1882
- defaultVariants: {
1883
- type: 'filled'
1884
- },
1885
- '.head': {
1886
- display: 'flex',
1887
- justifyContent: 'space-between',
1888
- alignItems: 'center',
1889
- minHeight: '32px',
1890
- '.usd-value': {
1891
- paddingLeft: '$8'
1892
- }
1893
- },
1894
- '.form': {
1895
- display: 'flex',
1896
- width: '100%',
1897
- padding: '$2 0',
1898
- '.selectors': {
1899
- width: '35%',
1900
- '._text': {
1901
- whiteSpace: 'nowrap',
1902
- overflow: 'hidden',
1903
- textOverflow: 'ellipsis'
1711
+ }
1712
+ });
1713
+ const ListItem = /*#__PURE__*/styled('li', {
1714
+ variants: {
1715
+ showListStyle: {
1716
+ true: {
1717
+ listStyleType: 'disc',
1718
+ listStylePosition: 'outside'
1904
1719
  }
1905
- },
1906
- '.amount': {
1907
- width: '30%'
1908
1720
  }
1909
1721
  }
1910
1722
  });
1911
- const ImagePlaceholder$1 = /*#__PURE__*/styled('span', {
1912
- width: '24px',
1913
- height: '24px',
1914
- backgroundColor: '$neutrals300',
1915
- borderRadius: '99999px'
1916
- });
1917
- const OutputContainer$1 = /*#__PURE__*/styled('div', {
1918
- windth: '100%',
1919
- height: '$48',
1920
- borderRadius: '$5',
1921
- backgroundColor: '$background',
1922
- border: '1px solid transparent',
1923
- position: 'relative',
1924
- display: 'flex',
1925
- alignItems: 'center',
1926
- paddingLeft: '$8',
1927
- paddingRight: '$8'
1723
+ const Message = /*#__PURE__*/styled(Typography, {
1724
+ display: 'block'
1928
1725
  });
1929
- function TokenPreview(props) {
1930
- const {
1931
- chain,
1932
- token,
1933
- loadingStatus,
1934
- percentageChange
1935
- } = props;
1936
- const {
1937
- t
1938
- } = useTranslation();
1939
- const ItemSuffix = React.createElement("div", {
1940
- style: {
1941
- display: 'flex',
1942
- justifyContent: 'center',
1943
- alignItems: 'center'
1726
+ function BalanceErrors(_ref) {
1727
+ let {
1728
+ messages
1729
+ } = _ref;
1730
+ const showListStyle = messages.length > 1;
1731
+ return React.createElement(React.Fragment, null, React.createElement(Typography, {
1732
+ className: "title",
1733
+ variant: "title",
1734
+ color: 'error'
1735
+ }, "Insufficent Balance:"), React.createElement(Spacer, {
1736
+ size: 8,
1737
+ direction: "vertical"
1738
+ }), React.createElement(List, {
1739
+ showListStyle: showListStyle
1740
+ }, messages.map((warning, index) => React.createElement(ListItem, {
1741
+ showListStyle: showListStyle,
1742
+ key: index
1743
+ }, React.createElement(Message, {
1744
+ variant: "body2"
1745
+ }, warning)))));
1746
+ }
1747
+
1748
+ function ConfirmSwapErrors(errors) {
1749
+ return errors.flatMap(error => {
1750
+ switch (error.type) {
1751
+ case ConfirmSwapErrorTypes.NO_ROUTE:
1752
+ return 'No routes found. Please try again later.';
1753
+ case ConfirmSwapErrorTypes.REQUEST_FAILED:
1754
+ return `Failed to confirm swap ${error.status ? `'status': ${error.status})` : ''}, please try again.`;
1755
+ case ConfirmSwapErrorTypes.ROUTE_UPDATED_WITH_HIGH_VALUE_LOSS:
1756
+ return 'Route updated and price impact is too high, try again later!';
1757
+ case ConfirmSwapErrorTypes.INSUFFICIENT_SLIPPAGE:
1758
+ return React.createElement(MinRequiredSlippage, {
1759
+ minRequiredSlippage: error.minRequiredSlippage
1760
+ });
1761
+ case ConfirmSwapErrorTypes.INSUFFICIENT_BALANCE:
1762
+ return React.createElement(BalanceErrors, {
1763
+ messages: error.messages
1764
+ });
1765
+ default:
1766
+ return [];
1944
1767
  }
1945
- }, loadingStatus === 'failed' && React.createElement(InfoCircleIcon, {
1946
- color: "error",
1947
- size: 24
1948
- }));
1949
- return React.createElement(Box$1, null, React.createElement(Container$3, {
1950
- type: 'outlined'
1951
- }, React.createElement("div", {
1952
- className: "head"
1953
- }, React.createElement(Typography, {
1954
- variant: "body2",
1955
- color: "neutrals800"
1956
- }, props.label), React.createElement("div", null, percentageChange, props.usdValue && React.createElement(Typography, {
1957
- variant: "caption",
1958
- color: "neutrals600",
1959
- className: "usd-value"
1960
- }, `$${numberToString(props.usdValue)}`))), React.createElement("div", {
1961
- className: "form"
1962
- }, React.createElement(Button, {
1963
- className: "selectors",
1964
- variant: "outlined",
1965
- loading: loadingStatus === 'loading',
1966
- prefix: loadingStatus === 'success' && chain ? React.createElement(Image, {
1967
- src: chain.logo,
1968
- size: 24
1969
- }) : React.createElement(ImagePlaceholder$1, null),
1970
- suffix: ItemSuffix,
1971
- align: "start",
1972
- size: "large"
1973
- }, loadingStatus === 'success' && chain ? chain.displayName : t('Chain')), React.createElement(Spacer, {
1974
- size: 12
1975
- }), React.createElement(Button, {
1976
- className: "selectors",
1977
- variant: "outlined",
1978
- loading: loadingStatus === 'loading',
1979
- prefix: loadingStatus === 'success' && token ? React.createElement(Image, {
1980
- src: token.image,
1981
- size: 24
1982
- }) : React.createElement(ImagePlaceholder$1, null),
1983
- suffix: ItemSuffix,
1984
- size: "large",
1985
- align: "start"
1986
- }, loadingStatus === 'success' && token ? token.symbol : t('Token')), React.createElement(Spacer, {
1987
- size: 12
1988
- }), React.createElement("div", {
1989
- className: "amount"
1990
- }, React.createElement(OutputContainer$1, null, React.createElement(Typography, {
1991
- variant: "h4"
1992
- }, props.amount))))));
1768
+ });
1993
1769
  }
1994
1770
 
1995
- const Container$4 = /*#__PURE__*/styled('div', {
1996
- display: 'flex',
1997
- alignItems: 'center',
1998
- justifyContent: 'space-between',
1999
- padding: '$8',
2000
- borderRadius: '$5',
2001
- backgroundColor: '$neutrals300',
2002
- color: '$neutrals800',
2003
- fontSize: '$12',
2004
- '.routes': {
2005
- display: 'flex',
2006
- alignItems: 'center'
2007
- },
2008
- '.fee': {
2009
- display: 'flex',
2010
- alignItems: 'center'
2011
- }
2012
- });
2013
- function RoutesOverview(props) {
2014
- if (!props.routes) return null;
2015
- const swaps = props.routes.result?.swaps;
2016
- return React.createElement(Container$4, null, React.createElement("div", {
2017
- className: "routes"
2018
- }, swaps?.map((swap, idx) => {
2019
- const isLast = idx + 1 == swaps.length;
2020
- return React.createElement(React.Fragment, null, React.createElement("div", {
2021
- className: "route"
2022
- }, swap.from.symbol), React.createElement(ChevronRightIcon, {
2023
- size: 12
2024
- }), isLast ? React.createElement("div", {
2025
- className: "route"
2026
- }, swap.to.symbol) : null);
2027
- })), props.totalFee ? React.createElement("div", {
2028
- className: "fee"
2029
- }, React.createElement(GasIcon, {
2030
- size: 12
2031
- }), React.createElement(Spacer, {
2032
- size: 4
2033
- }), "$", props.totalFee) : null);
1771
+ function ConfirmSwapWarnings(warnings) {
1772
+ return warnings.flatMap(warning => {
1773
+ switch (warning.type) {
1774
+ case ConfirmSwapWarningTypes.ROUTE_UPDATED:
1775
+ return "Route has been updated.";
1776
+ case ConfirmSwapWarningTypes.ROUTE_AND_OUTPUT_AMOUNT_UPDATED:
1777
+ return `Output amount changed to ${warning.newOutputAmount} (${warning.percentageChange}% change).`;
1778
+ case ConfirmSwapWarningTypes.ROUTE_SWAPPERS_UPDATED:
1779
+ return "Route swappers has been updated.";
1780
+ case ConfirmSwapWarningTypes.ROUTE_COINS_UPDATED:
1781
+ return "Route internal coins has been updated.";
1782
+ default:
1783
+ return [];
1784
+ }
1785
+ });
2034
1786
  }
2035
1787
 
2036
- var ConfirmSwapErrorTypes;
2037
- (function (ConfirmSwapErrorTypes) {
2038
- ConfirmSwapErrorTypes[ConfirmSwapErrorTypes["NO_ROUTE"] = 0] = "NO_ROUTE";
2039
- ConfirmSwapErrorTypes[ConfirmSwapErrorTypes["ROUTE_UPDATED_WITH_HIGH_VALUE_LOSS"] = 1] = "ROUTE_UPDATED_WITH_HIGH_VALUE_LOSS";
2040
- ConfirmSwapErrorTypes[ConfirmSwapErrorTypes["REQUEST_FAILED"] = 2] = "REQUEST_FAILED";
2041
- ConfirmSwapErrorTypes[ConfirmSwapErrorTypes["INSUFFICIENT_SLIPPAGE"] = 3] = "INSUFFICIENT_SLIPPAGE";
2042
- ConfirmSwapErrorTypes[ConfirmSwapErrorTypes["INSUFFICIENT_BALANCE"] = 4] = "INSUFFICIENT_BALANCE";
2043
- })(ConfirmSwapErrorTypes || (ConfirmSwapErrorTypes = {}));
2044
- var ConfirmSwapWarningTypes;
2045
- (function (ConfirmSwapWarningTypes) {
2046
- ConfirmSwapWarningTypes[ConfirmSwapWarningTypes["ROUTE_UPDATED"] = 0] = "ROUTE_UPDATED";
2047
- ConfirmSwapWarningTypes[ConfirmSwapWarningTypes["ROUTE_SWAPPERS_UPDATED"] = 1] = "ROUTE_SWAPPERS_UPDATED";
2048
- ConfirmSwapWarningTypes[ConfirmSwapWarningTypes["ROUTE_COINS_UPDATED"] = 2] = "ROUTE_COINS_UPDATED";
2049
- ConfirmSwapWarningTypes[ConfirmSwapWarningTypes["ROUTE_AND_OUTPUT_AMOUNT_UPDATED"] = 3] = "ROUTE_AND_OUTPUT_AMOUNT_UPDATED";
2050
- })(ConfirmSwapWarningTypes || (ConfirmSwapWarningTypes = {}));
1788
+ function HighSlippageWarning(props) {
1789
+ const {
1790
+ selectedSlippage
1791
+ } = props;
1792
+ return React.createElement(Alert, {
1793
+ type: "warning",
1794
+ footer: React.createElement(ChangeSlippageButton, null)
1795
+ }, "Caution, your slippage is high (=", selectedSlippage, "). Your trade may be front run.");
1796
+ }
2051
1797
 
2052
- function useConfirmSwap() {
2053
- const fromToken = useBestRouteStore.use.fromToken();
2054
- const toToken = useBestRouteStore.use.toToken();
2055
- const inputAmount = useBestRouteStore.use.inputAmount();
2056
- const initialRoute = useBestRouteStore.use.bestRoute();
2057
- const setBestRoute = useBestRouteStore.use.setBestRoute();
2058
- const inputUsdValue = useBestRouteStore.use.inputUsdValue();
2059
- const affiliateRef = useSettingsStore.use.affiliateRef();
1798
+ function ConfirmSwapExtraMessages(props) {
1799
+ const {
1800
+ selectedSlippage
1801
+ } = props;
1802
+ const highSlippage = selectedSlippage >= HIGH_SLIPPAGE;
1803
+ return React.createElement(React.Fragment, null, highSlippage && React.createElement(HighSlippageWarning, {
1804
+ selectedSlippage: selectedSlippage
1805
+ }));
1806
+ }
1807
+
1808
+ function PercentageChange(props) {
1809
+ const {
1810
+ inputUsdValue,
1811
+ outputUsdValue
1812
+ } = props;
1813
+ if (!inputUsdValue || !outputUsdValue || !outputUsdValue.gt(0)) return null;
1814
+ const percentageChange = getPercentageChange(inputUsdValue.toNumber(), outputUsdValue.toNumber());
1815
+ const showPercentageChange = percentageChange?.lt(0);
1816
+ return React.createElement(React.Fragment, null, showPercentageChange && React.createElement(Typography, {
1817
+ variant: "caption",
1818
+ color: "$error500"
1819
+ }, `(${numberToString(percentageChange, 0, 2)}%)`));
1820
+ }
1821
+
1822
+ function ConfirmSwapPage() {
1823
+ const navigate = useNavigate();
1824
+ const {
1825
+ navigateBackFrom
1826
+ } = useNavigateBack();
1827
+ const bestRoute = useBestRouteStore.use.bestRoute();
1828
+ const fetchingBestRoute = useBestRouteStore.use.loading();
1829
+ const fetchingBestRouteError = useBestRouteStore.use.error();
1830
+ const setSelectedSwap = useUiStore.use.setSelectedSwap();
1831
+ const {
1832
+ blockchains,
1833
+ tokens
1834
+ } = useMetaStore.use.meta();
1835
+ const loadingMetaStatus = useMetaStore.use.loadingStatus();
2060
1836
  const accounts = useWalletsStore.use.accounts();
2061
1837
  const selectedWallets = useWalletsStore.use.selectedWallets();
2062
- const meta = useMetaStore.use.meta();
2063
- const customSlippage = useSettingsStore.use.customSlippage();
1838
+ const initSelectedWallets = useWalletsStore.use.initSelectedWallets();
1839
+ const setSelectedWallet = useWalletsStore.use.setSelectedWallet();
2064
1840
  const slippage = useSettingsStore.use.slippage();
2065
- const disabledLiquiditySources = useSettingsStore.use.disabledLiquiditySources();
2066
- const userSlippage = customSlippage || slippage;
2067
- const proceedAnywayRef = useRef(false);
2068
- const confiremedRouteRef = useRef(null);
2069
- let abortControllerRef = useRef(null);
2070
- const [loading, setLoading] = useState(false);
2071
- const [errors, setErrors] = useState([]);
2072
- const [warnings, setWarnings] = useState([]);
1841
+ const customSlippage = useSettingsStore.use.customSlippage();
1842
+ const inputUsdValue = useBestRouteStore.use.inputUsdValue();
1843
+ const outputUsdValue = useBestRouteStore.use.outputUsdValue();
1844
+ const setInputAmount = useBestRouteStore.use.setInputAmount();
1845
+ const bestRouteloadingStatus = getBestRouteStatus(fetchingBestRoute, !!fetchingBestRouteError);
1846
+ const {
1847
+ manager
1848
+ } = useManager();
1849
+ const {
1850
+ loading: fetchingConfirmedRoute,
1851
+ errors,
1852
+ warnings,
1853
+ confirmSwap
1854
+ } = useConfirmSwap();
1855
+ const selectedSlippage = customSlippage || slippage;
1856
+ const showHighSlippageWarning = !errors.find(error => error.type === ConfirmSwapErrorTypes.INSUFFICIENT_SLIPPAGE);
1857
+ const {
1858
+ getWalletInfo,
1859
+ connect
1860
+ } = useWallets();
1861
+ const confirmDisabled = fetchingBestRoute || !requiredWallets(bestRoute).every(chain => selectedWallets.map(wallet => wallet.chain).includes(chain));
1862
+ const firstStep = bestRoute?.result?.swaps[0];
1863
+ const lastStep = bestRoute?.result?.swaps[bestRoute?.result?.swaps.length - 1];
1864
+ const fromAmount = numberToString(firstStep?.fromAmount, 4, 6);
1865
+ const toAmount = numberToString(lastStep?.toAmount, 4, 6);
2073
1866
  useEffect(() => {
2074
- return () => abortControllerRef.current?.abort();
1867
+ initSelectedWallets();
2075
1868
  }, []);
2076
- if (!fromToken || !toToken || !inputAmount || !initialRoute) return {
2077
- loading: false,
2078
- warnings: [],
2079
- errors: [],
2080
- confirmSwap: null
1869
+ const selectableWallets = getSelectableWallets(accounts, selectedWallets, getWalletInfo);
1870
+ const handleConnectChain = wallet => {
1871
+ const network = wallet;
1872
+ getKeplrCompatibleConnectedWallets(selectableWallets).forEach(compatibleWallet => connect?.(compatibleWallet, network));
2081
1873
  };
2082
- const confirmSwap = async () => {
2083
- if (proceedAnywayRef.current) {
2084
- const swapSettings = {
2085
- slippage: userSlippage.toString(),
2086
- disabledSwappersGroups: disabledLiquiditySources
2087
- };
2088
- if (errors.length > 0) setErrors([]);
2089
- if (warnings.length > 0) setWarnings([]);
2090
- proceedAnywayRef.current = false;
2091
- if (confiremedRouteRef.current) {
2092
- const newSwap = calculatePendingSwap(inputAmount.toString(), confiremedRouteRef.current, getWalletsForNewSwap(selectedWallets), swapSettings, false, meta);
2093
- return newSwap;
2094
- }
2095
- return;
2096
- }
2097
- abortControllerRef.current = new AbortController();
2098
- setLoading(true);
2099
- const requestBody = createBestRouteRequestBody(fromToken, toToken, inputAmount, accounts, selectedWallets, disabledLiquiditySources, userSlippage, affiliateRef, initialRoute);
2100
- try {
2101
- const confiremedRoute = await httpService().getBestRoute(requestBody, {
2102
- signal: abortControllerRef.current?.signal
2103
- });
2104
- abortControllerRef.current = null;
2105
- setLoading(false);
2106
- if (!confiremedRoute.result || !new BigNumber(confiremedRoute.requestAmount).isEqualTo(new BigNumber(inputAmount || '-1'))) {
2107
- setErrors(prevState => prevState.concat({
2108
- type: ConfirmSwapErrorTypes.NO_ROUTE
2109
- }));
2110
- return;
2111
- }
2112
- const confirmSwapState = {
2113
- errors: [],
2114
- warnings: []
2115
- };
2116
- const routeChanged = isRouteChanged(initialRoute, confiremedRoute);
2117
- if (routeChanged) {
2118
- setBestRoute(confiremedRoute);
2119
- const newRouteOutputUsdValue = new BigNumber(confiremedRoute.result?.outputAmount || '0').multipliedBy(toToken.usdPrice || 0);
2120
- const outputRatio = getOutputRatio(inputUsdValue, newRouteOutputUsdValue);
2121
- const highValueLoss = outputRatioHasWarning(inputUsdValue, outputRatio);
2122
- if (highValueLoss) confirmSwapState.errors.push({
2123
- type: ConfirmSwapErrorTypes.ROUTE_UPDATED_WITH_HIGH_VALUE_LOSS
2124
- });else if (isOutputAmountChangedALot(initialRoute, confiremedRoute)) confirmSwapState.warnings.push({
2125
- type: ConfirmSwapWarningTypes.ROUTE_AND_OUTPUT_AMOUNT_UPDATED,
2126
- newOutputAmount: numberToString(getRouteOutputAmount(confiremedRoute)),
2127
- percentageChange: numberToString(getPercentageChange(getRouteOutputAmount(initialRoute), getRouteOutputAmount(confiremedRoute)), null, 2)
2128
- });else if (isRouteInternalCoinsUpdated(initialRoute, confiremedRoute)) confirmSwapState.warnings.push({
2129
- type: ConfirmSwapWarningTypes.ROUTE_COINS_UPDATED
2130
- });else if (isNumberOfSwapsChanged(initialRoute, confiremedRoute)) confirmSwapState.warnings.push({
2131
- type: ConfirmSwapWarningTypes.ROUTE_UPDATED
2132
- });else if (isRouteSwappersUpdated(initialRoute, confiremedRoute)) confirmSwapState.warnings.push({
2133
- type: ConfirmSwapWarningTypes.ROUTE_SWAPPERS_UPDATED
2134
- });
2135
- }
2136
- const balanceWarnings = getBalanceWarnings(confiremedRoute, selectedWallets);
2137
- const enoughBalance = balanceWarnings.length === 0;
2138
- if (!enoughBalance) confirmSwapState.errors.push({
2139
- type: ConfirmSwapErrorTypes.INSUFFICIENT_BALANCE,
2140
- messages: balanceWarnings
1874
+ const totalFeeInUsd = getTotalFeeInUsd(bestRoute, tokens);
1875
+ return React.createElement(ConfirmSwap, {
1876
+ requiredWallets: getRequiredChains(bestRoute),
1877
+ selectableWallets: selectableWallets,
1878
+ onBack: navigateBackFrom.bind(null, navigationRoutes.confirmSwap),
1879
+ onConfirm: () => {
1880
+ confirmSwap?.().then(swap => {
1881
+ if (swap) {
1882
+ manager?.create('swap', {
1883
+ swapDetails: swap
1884
+ }, {
1885
+ id: swap.requestId
1886
+ });
1887
+ setSelectedSwap(swap.requestId);
1888
+ navigate('/' + navigationRoutes.swaps + `/${swap.requestId}`, {
1889
+ replace: true
1890
+ });
1891
+ setTimeout(() => {
1892
+ setInputAmount('');
1893
+ }, 0);
1894
+ }
2141
1895
  });
2142
- const minRequiredSlippage = getMinRequiredSlippage(initialRoute);
2143
- if (!hasProperSlippage(userSlippage.toString(), minRequiredSlippage)) confirmSwapState.errors.push({
2144
- type: ConfirmSwapErrorTypes.INSUFFICIENT_SLIPPAGE,
2145
- minRequiredSlippage
1896
+ },
1897
+ onChange: wallet => setSelectedWallet(wallet),
1898
+ confirmDisabled: loadingMetaStatus !== 'success' || confirmDisabled,
1899
+ handleConnectChain: wallet => handleConnectChain(wallet),
1900
+ isExperimentalChain: wallet => getKeplrCompatibleConnectedWallets(selectableWallets).length > 0 ? isExperimentalChain(blockchains, wallet) : false,
1901
+ previewInputs: React.createElement(React.Fragment, null, React.createElement(TokenPreview, {
1902
+ chain: {
1903
+ displayName: firstStep?.from.blockchain || '',
1904
+ logo: firstStep?.from.blockchainLogo || ''
1905
+ },
1906
+ token: {
1907
+ symbol: firstStep?.from.symbol || '',
1908
+ image: firstStep?.from.logo || ''
1909
+ },
1910
+ usdValue: inputUsdValue,
1911
+ amount: fromAmount,
1912
+ label: t('From'),
1913
+ loadingStatus: loadingMetaStatus !== 'success' ? loadingMetaStatus : bestRouteloadingStatus
1914
+ }), React.createElement(Spacer, {
1915
+ size: 12,
1916
+ direction: "vertical"
1917
+ }), React.createElement(TokenPreview, {
1918
+ chain: {
1919
+ displayName: lastStep?.to.blockchain || '',
1920
+ logo: lastStep?.to.blockchainLogo || ''
1921
+ },
1922
+ token: {
1923
+ symbol: lastStep?.to.symbol || '',
1924
+ image: lastStep?.to.logo || ''
1925
+ },
1926
+ usdValue: outputUsdValue,
1927
+ amount: toAmount,
1928
+ label: t('To'),
1929
+ loadingStatus: loadingMetaStatus !== 'success' ? loadingMetaStatus : bestRouteloadingStatus,
1930
+ percentageChange: React.createElement(PercentageChange, {
1931
+ inputUsdValue: inputUsdValue,
1932
+ outputUsdValue: outputUsdValue
1933
+ })
1934
+ })),
1935
+ previewRoutes: React.createElement(RoutesOverview, {
1936
+ routes: bestRoute,
1937
+ totalFee: numberToString(totalFeeInUsd, 0, 2)
1938
+ }),
1939
+ loading: fetchingConfirmedRoute,
1940
+ errors: ConfirmSwapErrors(errors),
1941
+ warnings: ConfirmSwapWarnings(warnings),
1942
+ extraMessages: React.createElement(React.Fragment, null, loadingMetaStatus === 'failed' && React.createElement(LoadingFailedAlert, null), loadingMetaStatus === 'failed' && showHighSlippageWarning && React.createElement(Spacer, {
1943
+ direction: "vertical"
1944
+ }), showHighSlippageWarning && React.createElement(ConfirmSwapExtraMessages, {
1945
+ selectedSlippage: selectedSlippage
1946
+ })),
1947
+ confirmButtonTitle: warnings.length > 0 || errors.length > 0 ? 'Proceed anyway!' : 'Confirm swap!'
1948
+ });
1949
+ }
1950
+
1951
+ const getPendingSwaps = manager => {
1952
+ const result = [];
1953
+ manager?.getAll().forEach((q, id) => {
1954
+ const storage = q.list.getStorage();
1955
+ if (storage?.swapDetails) {
1956
+ result.push({
1957
+ id,
1958
+ swap: storage?.swapDetails
2146
1959
  });
2147
- const noErrors = confirmSwapState.errors.length === 0;
2148
- const noWarnings = confirmSwapState.warnings.length === 0;
2149
- if ((noErrors || !noErrors && proceedAnywayRef.current) && (noWarnings || !noWarnings && proceedAnywayRef.current)) {
2150
- const swapSettings = {
2151
- slippage: userSlippage.toString(),
2152
- disabledSwappersGroups: disabledLiquiditySources
2153
- };
2154
- const newSwap = calculatePendingSwap(inputAmount.toString(), confiremedRoute, getWalletsForNewSwap(selectedWallets), swapSettings, false, meta);
2155
- return newSwap;
2156
- } else if (!proceedAnywayRef.current) {
2157
- proceedAnywayRef.current = true;
2158
- setErrors(confirmSwapState.errors);
2159
- setWarnings(confirmSwapState.warnings);
2160
- confiremedRouteRef.current = confiremedRoute;
2161
- }
2162
- return;
2163
- } catch (error) {
2164
- if (error?.code === 'ERR_CANCELED') {
2165
- return;
2166
- }
2167
- const status = error?.response?.status;
2168
- setLoading(false);
2169
- setErrors([{
2170
- type: ConfirmSwapErrorTypes.REQUEST_FAILED,
2171
- status
2172
- }]);
2173
- return;
2174
1960
  }
2175
- };
2176
- return {
2177
- loading,
2178
- warnings,
2179
- errors,
2180
- confirmSwap
2181
- };
2182
- }
1961
+ });
1962
+ return result.sort((a, b) => Number(b.swap.creationTime) - Number(a.swap.creationTime));
1963
+ };
2183
1964
 
2184
- function ChangeSlippageButton() {
1965
+ const groupSwapsByDate = swaps => {
1966
+ const output = new Map([['today', {
1967
+ title: 'Today',
1968
+ swaps: []
1969
+ }], ['week', {
1970
+ title: 'This week',
1971
+ swaps: []
1972
+ }], ['month', {
1973
+ title: 'This month',
1974
+ swaps: []
1975
+ }], ['year', {
1976
+ title: 'This year',
1977
+ swaps: []
1978
+ }], ['history', {
1979
+ title: 'History',
1980
+ swaps: []
1981
+ }]]);
1982
+ const now = dayjs();
1983
+ swaps.forEach(swap => {
1984
+ const swapDate = dayjs(Number(swap.creationTime));
1985
+ if (now.isSame(swapDate, 'day')) output.get('today')?.swaps.push(swap);else if (now.isSame(swapDate, 'week')) output.get('week')?.swaps.push(swap);else if (now.isSame(swapDate, 'month')) output.get('month')?.swaps.push(swap);else if (now.isSame(swapDate, 'year')) output.get('year')?.swaps.push(swap);else output.get('history')?.swaps.push(swap);
1986
+ });
1987
+ return Array.from(output.values());
1988
+ };
1989
+
1990
+ function HistoryPage() {
1991
+ const setSelectedSwap = useUiStore.use.setSelectedSwap();
2185
1992
  const navigate = useNavigate();
2186
- return React.createElement(Button, {
2187
- type: "primary",
2188
- variant: "outlined",
2189
- size: "small",
2190
- onClick: () => navigate(navigationRoutes.settings)
2191
- }, "Change Slippage");
1993
+ const {
1994
+ navigateBackFrom
1995
+ } = useNavigateBack();
1996
+ const {
1997
+ manager,
1998
+ state
1999
+ } = useManager();
2000
+ const pendingSwaps = getPendingSwaps(manager).map(_ref => {
2001
+ let {
2002
+ swap
2003
+ } = _ref;
2004
+ return swap;
2005
+ });
2006
+ const loading = !state.loadedFromPersistor;
2007
+ return React.createElement(History, {
2008
+ list: pendingSwaps,
2009
+ groupBy: groupSwapsByDate,
2010
+ loading: loading,
2011
+ onSwapClick: requestId => {
2012
+ setSelectedSwap(requestId);
2013
+ navigate(`${requestId}`, {
2014
+ replace: true
2015
+ });
2016
+ },
2017
+ onBack: navigateBackFrom.bind(null, navigationRoutes.swaps)
2018
+ });
2192
2019
  }
2193
2020
 
2194
- const StyledMessage = /*#__PURE__*/styled(Typography, {
2195
- color: '$error500 !important'
2021
+ const Box$1 = /*#__PURE__*/styled('div', {
2022
+ display: 'flex',
2023
+ flexDirection: 'column',
2024
+ width: '100%',
2025
+ overflow: 'hidden'
2196
2026
  });
2197
- function MinRequiredSlippage(_ref) {
2198
- let {
2199
- minRequiredSlippage
2200
- } = _ref;
2201
- return React.createElement(StyledMessage, {
2202
- variant: "body2"
2203
- }, "We recommend you to increase slippage to at least \u00A0", minRequiredSlippage, "\u00A0 for this route.", React.createElement(Spacer, {
2204
- size: 8,
2205
- direction: "vertical"
2206
- }), React.createElement(ChangeSlippageButton, null));
2207
- }
2208
-
2209
- const List = /*#__PURE__*/styled('ul', {
2210
- variants: {
2211
- showListStyle: {
2212
- true: {
2213
- paddingLeft: '$24'
2027
+ const Container$2 = /*#__PURE__*/styled('div', {
2028
+ boxSizing: 'border-box',
2029
+ borderRadius: '$5',
2030
+ padding: '$8 $16 $16 $16',
2031
+ variants: {
2032
+ type: {
2033
+ filled: {
2034
+ backgroundColor: '$neutrals300'
2035
+ },
2036
+ outlined: {
2037
+ border: '1px solid $neutrals300'
2214
2038
  }
2215
2039
  }
2216
- }
2217
- });
2218
- const ListItem = /*#__PURE__*/styled('li', {
2219
- variants: {
2220
- showListStyle: {
2221
- true: {
2222
- listStyleType: 'disc',
2223
- listStylePosition: 'outside'
2040
+ },
2041
+ defaultVariants: {
2042
+ type: 'filled'
2043
+ },
2044
+ '.head': {
2045
+ display: 'flex',
2046
+ justifyContent: 'space-between',
2047
+ alignItems: 'center',
2048
+ minHeight: '32px'
2049
+ },
2050
+ '.form': {
2051
+ display: 'flex',
2052
+ width: '100%',
2053
+ padding: '$2 0',
2054
+ '.selectors': {
2055
+ width: '35%',
2056
+ '._text': {
2057
+ whiteSpace: 'nowrap',
2058
+ overflow: 'hidden',
2059
+ textOverflow: 'ellipsis'
2224
2060
  }
2061
+ },
2062
+ '.amount': {
2063
+ width: '30%'
2064
+ }
2065
+ },
2066
+ '.output-usd': {
2067
+ display: 'flex',
2068
+ div: {
2069
+ display: 'flex',
2070
+ paddingLeft: '$8'
2225
2071
  }
2226
2072
  }
2227
2073
  });
2228
- const Message = /*#__PURE__*/styled(Typography, {
2229
- display: 'block'
2074
+ const Options = /*#__PURE__*/styled('div', {
2075
+ display: 'flex',
2076
+ justifyContent: 'flex-end',
2077
+ '.balance': {
2078
+ display: 'flex',
2079
+ alignItems: 'center'
2080
+ }
2230
2081
  });
2231
- function BalanceErrors(_ref) {
2232
- let {
2233
- messages
2234
- } = _ref;
2235
- const showListStyle = messages.length > 1;
2236
- return React.createElement(React.Fragment, null, React.createElement(Typography, {
2237
- className: "title",
2238
- variant: "title",
2239
- color: 'error'
2240
- }, "Insufficent Balance:"), React.createElement(Spacer, {
2241
- size: 8,
2242
- direction: "vertical"
2243
- }), React.createElement(List, {
2244
- showListStyle: showListStyle
2245
- }, messages.map(warning => React.createElement(ListItem, {
2246
- showListStyle: showListStyle
2247
- }, React.createElement(Message, {
2248
- variant: "body2"
2249
- }, warning)))));
2250
- }
2251
-
2252
- function ConfirmSwapErrors(errors) {
2253
- return errors.flatMap(error => {
2254
- switch (error.type) {
2255
- case ConfirmSwapErrorTypes.NO_ROUTE:
2256
- return 'No routes found. Please try again later.';
2257
- case ConfirmSwapErrorTypes.REQUEST_FAILED:
2258
- return `Failed to confirm swap ${error.status ? `'status': ${error.status})` : ''}, please try again.`;
2259
- case ConfirmSwapErrorTypes.ROUTE_UPDATED_WITH_HIGH_VALUE_LOSS:
2260
- return 'Route updated and price impact is too high, try again later!';
2261
- case ConfirmSwapErrorTypes.INSUFFICIENT_SLIPPAGE:
2262
- return React.createElement(MinRequiredSlippage, {
2263
- minRequiredSlippage: error.minRequiredSlippage
2264
- });
2265
- case ConfirmSwapErrorTypes.INSUFFICIENT_BALANCE:
2266
- return React.createElement(BalanceErrors, {
2267
- messages: error.messages
2268
- });
2269
- default:
2270
- return [];
2271
- }
2272
- });
2273
- }
2274
-
2275
- function ConfirmSwapWarnings(warnings) {
2276
- return warnings.flatMap(warning => {
2277
- switch (warning.type) {
2278
- case ConfirmSwapWarningTypes.ROUTE_UPDATED:
2279
- return "Route has been updated.";
2280
- case ConfirmSwapWarningTypes.ROUTE_AND_OUTPUT_AMOUNT_UPDATED:
2281
- return `Output amount changed to ${warning.newOutputAmount} (${warning.percentageChange}% change).`;
2282
- case ConfirmSwapWarningTypes.ROUTE_SWAPPERS_UPDATED:
2283
- return "Route swappers has been updated.";
2284
- case ConfirmSwapWarningTypes.ROUTE_COINS_UPDATED:
2285
- return "Route internal coins has been updated.";
2286
- default:
2287
- return [];
2288
- }
2289
- });
2290
- }
2291
-
2292
- function HighSlippageWarning(props) {
2293
- const {
2294
- selectedSlippage
2295
- } = props;
2296
- return React.createElement(Alert, {
2297
- type: "warning",
2298
- footer: React.createElement(ChangeSlippageButton, null)
2299
- }, "Caution, your slippage is high (=", selectedSlippage, "). Your trade may be front run.");
2300
- }
2301
-
2302
- function ConfirmSwapExtraMessages(props) {
2082
+ const ImagePlaceholder$1 = /*#__PURE__*/styled('span', {
2083
+ width: '24px',
2084
+ height: '24px',
2085
+ backgroundColor: '$neutrals300',
2086
+ borderRadius: '99999px'
2087
+ });
2088
+ const OutputContainer$1 = /*#__PURE__*/styled('div', {
2089
+ windth: '100%',
2090
+ height: '$48',
2091
+ borderRadius: '$5',
2092
+ backgroundColor: '$background',
2093
+ border: '1px solid transparent',
2094
+ position: 'relative',
2095
+ display: 'flex',
2096
+ alignItems: 'center',
2097
+ paddingLeft: '$8',
2098
+ paddingRight: '$8'
2099
+ });
2100
+ function TokenInfo(props) {
2303
2101
  const {
2304
- selectedSlippage
2102
+ type,
2103
+ chain,
2104
+ token
2305
2105
  } = props;
2306
- const highSlippage = selectedSlippage >= HIGH_SLIPPAGE;
2307
- return React.createElement(React.Fragment, null, highSlippage && React.createElement(HighSlippageWarning, {
2308
- selectedSlippage: selectedSlippage
2309
- }));
2310
- }
2311
-
2312
- function ConfirmSwapPage() {
2313
- const navigate = useNavigate();
2314
- const {
2315
- navigateBackFrom
2316
- } = useNavigateBack();
2317
- const bestRoute = useBestRouteStore.use.bestRoute();
2318
- const fetchingBestRoute = useBestRouteStore.use.loading();
2319
- const fetchingBestRouteError = useBestRouteStore.use.error();
2320
- const setSelectedSwap = useUiStore.use.setSelectedSwap();
2321
- const {
2322
- blockchains,
2323
- tokens
2324
- } = useMetaStore.use.meta();
2325
- const accounts = useWalletsStore.use.accounts();
2326
- const selectedWallets = useWalletsStore.use.selectedWallets();
2327
- const initSelectedWallets = useWalletsStore.use.initSelectedWallets();
2328
- const setSelectedWallet = useWalletsStore.use.setSelectedWallet();
2329
- const slippage = useSettingsStore.use.slippage();
2330
- const customSlippage = useSettingsStore.use.customSlippage();
2106
+ const loadingStatus = useMetaStore.use.loadingStatus();
2107
+ const fromChain = useBestRouteStore.use.fromChain();
2108
+ const toChain = useBestRouteStore.use.toChain();
2331
2109
  const inputUsdValue = useBestRouteStore.use.inputUsdValue();
2332
- const outputUsdValue = useBestRouteStore.use.outputUsdValue();
2110
+ const fromToken = useBestRouteStore.use.fromToken();
2333
2111
  const setInputAmount = useBestRouteStore.use.setInputAmount();
2334
- const bestRouteloadingStatus = getBestRouteStatus(fetchingBestRoute, !!fetchingBestRouteError);
2335
- const {
2336
- manager
2337
- } = useManager();
2338
- const {
2339
- loading,
2340
- errors,
2341
- warnings,
2342
- confirmSwap
2343
- } = useConfirmSwap();
2344
- const selectedSlippage = customSlippage || slippage;
2345
- const showHighSlippageWarning = !errors.find(error => error.type === ConfirmSwapErrorTypes.INSUFFICIENT_SLIPPAGE);
2112
+ const bestRoute = useBestRouteStore.use.bestRoute();
2113
+ const inputAmount = useBestRouteStore.use.inputAmount();
2114
+ const balances = useWalletsStore.use.balances();
2115
+ const fetchingBestRoute = useBestRouteStore.use.loading();
2116
+ const navigate = useNavigate();
2346
2117
  const {
2347
- getWalletInfo,
2348
- connect
2349
- } = useWallets();
2350
- const confirmDisabled = fetchingBestRoute || !requiredWallets(bestRoute).every(chain => selectedWallets.map(wallet => wallet.chain).includes(chain));
2351
- const firstStep = bestRoute?.result?.swaps[0];
2352
- const lastStep = bestRoute?.result?.swaps[bestRoute?.result?.swaps.length - 1];
2353
- const fromAmount = decimalNumber(firstStep?.fromAmount, 3);
2354
- const toAmount = decimalNumber(lastStep?.toAmount, 3);
2355
- useEffect(() => {
2356
- initSelectedWallets();
2357
- }, []);
2358
- const selectableWallets = getSelectableWallets(accounts, selectedWallets, getWalletInfo);
2359
- const handleConnectChain = wallet => {
2360
- const network = wallet;
2361
- getKeplrCompatibleConnectedWallets(selectableWallets).forEach(compatibleWallet => connect?.(compatibleWallet, network));
2362
- };
2363
- const totalFeeInUsd = getTotalFeeInUsd(bestRoute, tokens);
2364
- return React.createElement(ConfirmSwap, {
2365
- requiredWallets: getRequiredChains(bestRoute),
2366
- selectableWallets: selectableWallets,
2367
- onBack: navigateBackFrom.bind(null, navigationRoutes.confirmSwap),
2368
- onConfirm: () => {
2369
- confirmSwap?.().then(swap => {
2370
- if (swap) {
2371
- manager?.create('swap', {
2372
- swapDetails: swap
2373
- }, {
2374
- id: swap.requestId
2375
- });
2376
- setSelectedSwap(swap.requestId);
2377
- navigate(navigationRoutes.swaps + `/${swap.requestId}`, {
2378
- replace: true
2379
- });
2380
- setTimeout(() => {
2381
- setInputAmount('');
2382
- }, 0);
2383
- }
2384
- });
2118
+ t
2119
+ } = useTranslation();
2120
+ const tokenBalance = !!fromChain && !!fromToken ? numberToString(getBalanceFromWallet(balances, fromChain?.name, fromToken?.symbol, fromToken?.address)?.amount || '0', 8) : '0';
2121
+ const tokenBalanceReal = !!fromChain && !!fromToken ? numberToString(getBalanceFromWallet(balances, fromChain?.name, fromToken?.symbol, fromToken?.address)?.amount || '0', getBalanceFromWallet(balances, fromChain?.name, fromToken?.symbol, fromToken?.address)?.decimal) : '0';
2122
+ const ItemSuffix = React.createElement("div", {
2123
+ style: {
2124
+ display: 'flex',
2125
+ justifyContent: 'center',
2126
+ alignItems: 'center'
2127
+ }
2128
+ }, loadingStatus === 'failed' && React.createElement(InfoCircleIcon, {
2129
+ color: "error",
2130
+ size: 24
2131
+ }), React.createElement(AngleDownIcon, null));
2132
+ return React.createElement(Box$1, null, React.createElement(Container$2, {
2133
+ type: props.type === 'From' ? 'filled' : 'outlined'
2134
+ }, React.createElement("div", {
2135
+ className: "head"
2136
+ }, React.createElement(Typography, {
2137
+ variant: "body2",
2138
+ color: "neutrals800"
2139
+ }, t(type)), props.type === 'From' ? React.createElement(Options, null, React.createElement("div", {
2140
+ className: "balance",
2141
+ onClick: () => {
2142
+ if (tokenBalance !== '0') setInputAmount(tokenBalanceReal.split(',').join(''));
2143
+ }
2144
+ }, React.createElement(Typography, {
2145
+ variant: "body3",
2146
+ color: "neutrals600"
2147
+ }, `${t('Balance')}: ${tokenBalance} ${fromToken?.symbol || ''}`), React.createElement(Spacer, {
2148
+ size: 4
2149
+ }), React.createElement(Button, {
2150
+ type: "primary",
2151
+ variant: "ghost",
2152
+ size: "compact"
2153
+ }, t('Max')))) : React.createElement("div", {
2154
+ className: "output-usd"
2155
+ }, React.createElement(PercentageChange, {
2156
+ inputUsdValue: inputUsdValue,
2157
+ outputUsdValue: props.outputUsdValue
2158
+ }), React.createElement("div", null, React.createElement(Typography, {
2159
+ variant: "caption",
2160
+ color: "neutrals600"
2161
+ }, `$${numberToString(props.outputUsdValue)}`)))), React.createElement("div", {
2162
+ className: "form"
2163
+ }, React.createElement(Button, {
2164
+ className: "selectors",
2165
+ onClick: () => {
2166
+ navigate(`${props.type.toLowerCase()}-chain`);
2385
2167
  },
2386
- onChange: wallet => setSelectedWallet(wallet),
2387
- confirmDisabled: confirmDisabled,
2388
- handleConnectChain: wallet => handleConnectChain(wallet),
2389
- isExperimentalChain: wallet => getKeplrCompatibleConnectedWallets(selectableWallets).length > 0 ? isExperimentalChain(blockchains, wallet) : false,
2390
- previewInputs: React.createElement(React.Fragment, null, React.createElement(TokenPreview, {
2391
- chain: {
2392
- displayName: firstStep?.from.blockchain || '',
2393
- logo: firstStep?.from.blockchainLogo || ''
2394
- },
2395
- token: {
2396
- symbol: firstStep?.from.symbol || '',
2397
- image: firstStep?.from.logo || ''
2398
- },
2399
- usdValue: inputUsdValue,
2400
- amount: fromAmount,
2401
- label: t('From'),
2402
- loadingStatus: bestRouteloadingStatus
2403
- }), React.createElement(Spacer, {
2404
- size: 12,
2405
- direction: "vertical"
2406
- }), React.createElement(TokenPreview, {
2407
- chain: {
2408
- displayName: lastStep?.to.blockchain || '',
2409
- logo: lastStep?.to.blockchainLogo || ''
2410
- },
2411
- token: {
2412
- symbol: lastStep?.to.symbol || '',
2413
- image: lastStep?.to.logo || ''
2414
- },
2415
- usdValue: outputUsdValue,
2416
- amount: toAmount,
2417
- label: t('To'),
2418
- loadingStatus: bestRouteloadingStatus,
2419
- percentageChange: React.createElement(PercentageChange, {
2420
- inputUsdValue: inputUsdValue,
2421
- outputUsdValue: outputUsdValue
2422
- })
2423
- })),
2424
- previewRoutes: React.createElement(RoutesOverview, {
2425
- routes: bestRoute,
2426
- totalFee: numberToString(totalFeeInUsd, 0, 2)
2427
- }),
2428
- loading: loading,
2429
- errors: ConfirmSwapErrors(errors),
2430
- warnings: ConfirmSwapWarnings(warnings),
2431
- extraMessages: showHighSlippageWarning && React.createElement(ConfirmSwapExtraMessages, {
2432
- selectedSlippage: selectedSlippage
2433
- }),
2434
- confirmButtonTitle: warnings.length > 0 || errors.length > 0 ? 'Proceed anyway!' : 'Confirm swap!'
2435
- });
2168
+ variant: "outlined",
2169
+ disabled: loadingStatus === 'failed',
2170
+ loading: loadingStatus === 'loading',
2171
+ prefix: loadingStatus === 'success' && chain ? React.createElement(Image, {
2172
+ src: chain.logo,
2173
+ size: 24
2174
+ }) : React.createElement(ImagePlaceholder$1, null),
2175
+ suffix: ItemSuffix,
2176
+ align: "start",
2177
+ size: "large"
2178
+ }, loadingStatus === 'success' && chain ? chain.displayName : t('Chain')), React.createElement(Spacer, {
2179
+ size: 12
2180
+ }), React.createElement(Button, {
2181
+ className: "selectors",
2182
+ onClick: () => {
2183
+ navigate(`${props.type.toLowerCase()}-token`);
2184
+ },
2185
+ variant: "outlined",
2186
+ disabled: loadingStatus === 'failed' || type === 'From' && !fromChain || type === 'To' && !toChain,
2187
+ loading: loadingStatus === 'loading',
2188
+ prefix: loadingStatus === 'success' && token ? React.createElement(Image, {
2189
+ src: token.image,
2190
+ size: 24
2191
+ }) : React.createElement(ImagePlaceholder$1, null),
2192
+ suffix: ItemSuffix,
2193
+ size: "large",
2194
+ align: "start"
2195
+ }, loadingStatus === 'success' && token ? token.symbol : t('Token')), React.createElement(Spacer, {
2196
+ size: 12
2197
+ }), React.createElement("div", {
2198
+ className: "amount"
2199
+ }, props.type === 'From' ? React.createElement(TextField, {
2200
+ type: "number",
2201
+ size: "large",
2202
+ autoFocus: true,
2203
+ placeholder: "0",
2204
+ style: {
2205
+ position: 'relative',
2206
+ backgroundColor: '$background !important'
2207
+ },
2208
+ suffix: React.createElement("span", {
2209
+ style: {
2210
+ position: 'absolute',
2211
+ right: '4px',
2212
+ bottom: '2px'
2213
+ }
2214
+ }, React.createElement(Typography, {
2215
+ variant: "caption",
2216
+ color: "neutrals800"
2217
+ }, `$${numberToString(inputUsdValue)}`)),
2218
+ value: props.inputAmount || '',
2219
+ min: 0,
2220
+ onChange: props.type === 'From' ? event => {
2221
+ props.onAmountChange(event.target.value);
2222
+ } : undefined
2223
+ }) : React.createElement(OutputContainer$1, null, React.createElement(Typography, {
2224
+ variant: "h4"
2225
+ }, fetchingBestRoute && '?', !!bestRoute?.result && `≈ ${numberToString(props.outputAmount)}`, (!inputAmount || inputAmount === '0') && '0'))))));
2436
2226
  }
2437
2227
 
2438
- const getPendingSwaps = manager => {
2439
- const result = [];
2440
- manager?.getAll().forEach((q, id) => {
2441
- const storage = q.list.getStorage();
2442
- if (storage?.swapDetails) {
2443
- result.push({
2444
- id,
2445
- swap: storage?.swapDetails
2228
+ const Container$3 = /*#__PURE__*/styled$1('div', {
2229
+ display: 'flex',
2230
+ width: '100%',
2231
+ justifyContent: 'end',
2232
+ alignItems: 'center',
2233
+ paddingTop: '$16'
2234
+ });
2235
+ const Logo = /*#__PURE__*/styled$1('svg', {
2236
+ fill: '$foreground',
2237
+ width: '$24',
2238
+ margin: '0 $8 0 $16'
2239
+ });
2240
+ const StyledAnchor = /*#__PURE__*/styled$1('a', {
2241
+ display: 'flex',
2242
+ justifyContent: 'center',
2243
+ alignItems: 'center',
2244
+ textDecoration: 'none'
2245
+ });
2246
+ function BottomLogo() {
2247
+ const {
2248
+ t
2249
+ } = useTranslation();
2250
+ return React.createElement(Container$3, null, React.createElement(Typography, {
2251
+ variant: "caption",
2252
+ color: '$neutrals600'
2253
+ }, t('Powered By')), React.createElement(StyledAnchor, {
2254
+ href: "https://rango.exchange",
2255
+ target: "_blank"
2256
+ }, React.createElement(Logo, {
2257
+ xmlns: "http://www.w3.org/2000/svg",
2258
+ viewBox: "0 0 33.68 29"
2259
+ }, React.createElement("defs", null), React.createElement("g", {
2260
+ id: "Layer_2",
2261
+ "data-name": "Layer 2"
2262
+ }, React.createElement("g", {
2263
+ id: "Layer_1-2",
2264
+ "data-name": "Layer 1"
2265
+ }, React.createElement("path", {
2266
+ d: "M33.68,18.05A17.93,17.93,0,0,0,28.34,5.29,18.31,18.31,0,0,0,15.45,0H13.54V7.41L6.07,0H.69L9.83,9.07H0V11A17.93,17.93,0,0,0,5.34,23.71,18.32,18.32,0,0,0,18.24,29h1.9V21.59l7.38,7.31h5.39l-9-9h9.82ZM17.37,16.16H12.49a1.93,1.93,0,0,0-1.35.55,1.89,1.89,0,0,0-.56,1.34,1.85,1.85,0,0,0,.56,1.33,1.93,1.93,0,0,0,1.35.55h3.84V25.1A14.43,14.43,0,0,1,8,21a14.21,14.21,0,0,1-4.1-8.2H21.2a1.86,1.86,0,0,0,.74-.13,1.92,1.92,0,0,0,.64-.4,2,2,0,0,0,.43-.62,1.88,1.88,0,0,0,0-1.47,2,2,0,0,0-.43-.62,1.92,1.92,0,0,0-.64-.4,1.86,1.86,0,0,0-.74-.13H17.35V3.9A14.43,14.43,0,0,1,25.64,8a14.19,14.19,0,0,1,4.11,8.2Zm2.12-5.27a1.43,1.43,0,0,1,.26-.83,1.52,1.52,0,0,1,.67-.56,1.55,1.55,0,0,1,.88-.08,1.51,1.51,0,0,1,.77.4,1.54,1.54,0,0,1,.42.77,1.41,1.41,0,0,1-.09.86,1.47,1.47,0,0,1-.55.68,1.56,1.56,0,0,1-.84.25,1.52,1.52,0,0,1-1.52-1.49Z"
2267
+ }), React.createElement("path", {
2268
+ d: "M21.7,11.57a.68.68,0,0,0-.12-.38.64.64,0,0,0-.31-.25.68.68,0,0,0-.75.15.61.61,0,0,0-.19.35.62.62,0,0,0,0,.4.67.67,0,0,0,.25.3.69.69,0,0,0,.39.12.7.7,0,0,0,.49-.2A.68.68,0,0,0,21.7,11.57Z"
2269
+ })))), React.createElement(Typography, {
2270
+ variant: "body2"
2271
+ }, "RANGO")));
2272
+ }
2273
+
2274
+ function SwithFromAndTo(_ref) {
2275
+ let {
2276
+ count
2277
+ } = _ref;
2278
+ const firstRender = useRef(true);
2279
+ const [searchParams, setSearchParams] = useSearchParams();
2280
+ const outputAmount = useBestRouteStore.use.outputAmount();
2281
+ useEffect(() => {
2282
+ if (!firstRender.current) {
2283
+ const fromChainString = searchParams.get(SearchParams.FROM_CHAIN);
2284
+ const fromTokenString = searchParams.get(SearchParams.FROM_TOKEN);
2285
+ const toChainString = searchParams.get(SearchParams.TO_CHAIN);
2286
+ const toTokenString = searchParams.get(SearchParams.TO_TOKEN);
2287
+ setSearchParams({
2288
+ ...(toChainString && {
2289
+ [SearchParams.FROM_CHAIN]: toChainString
2290
+ }),
2291
+ ...(toTokenString && {
2292
+ [SearchParams.FROM_TOKEN]: toTokenString
2293
+ }),
2294
+ ...(fromChainString && {
2295
+ [SearchParams.TO_CHAIN]: fromChainString
2296
+ }),
2297
+ ...(fromTokenString && {
2298
+ [SearchParams.TO_TOKEN]: fromTokenString
2299
+ }),
2300
+ ...(outputAmount && {
2301
+ [SearchParams.FROM_AMOUNT]: outputAmount.toString()
2302
+ })
2446
2303
  });
2304
+ } else {
2305
+ firstRender.current = false;
2447
2306
  }
2448
- });
2449
- return result.sort((a, b) => Number(b.swap.creationTime) - Number(a.swap.creationTime));
2450
- };
2307
+ }, [count]);
2308
+ return null;
2309
+ }
2451
2310
 
2452
- const groupSwapsByDate = swaps => {
2453
- const output = new Map([['today', {
2454
- title: 'Today',
2455
- swaps: []
2456
- }], ['week', {
2457
- title: 'This week',
2458
- swaps: []
2459
- }], ['month', {
2460
- title: 'This month',
2461
- swaps: []
2462
- }], ['year', {
2463
- title: 'This year',
2464
- swaps: []
2465
- }], ['history', {
2466
- title: 'History',
2467
- swaps: []
2468
- }]]);
2469
- const now = dayjs();
2470
- swaps.forEach(swap => {
2471
- const swapDate = dayjs(Number(swap.creationTime));
2472
- if (now.isSame(swapDate, 'day')) output.get('today')?.swaps.push(swap);else if (now.isSame(swapDate, 'week')) output.get('week')?.swaps.push(swap);else if (now.isSame(swapDate, 'month')) output.get('month')?.swaps.push(swap);else if (now.isSame(swapDate, 'year')) output.get('year')?.swaps.push(swap);else output.get('history')?.swaps.push(swap);
2473
- });
2474
- return Array.from(output.values());
2311
+ const Footer = /*#__PURE__*/styled('div', {
2312
+ display: 'flex',
2313
+ flexDirection: 'column',
2314
+ width: '100%',
2315
+ paddingTop: '$16'
2316
+ });
2317
+
2318
+ const errorMessages = {
2319
+ genericServerError: 'Error connecting server, please reload the app and try again'
2475
2320
  };
2476
2321
 
2477
- function HistoryPage() {
2478
- const setSelectedSwap = useUiStore.use.setSelectedSwap();
2479
- const navigate = useNavigate();
2322
+ const ButtonsContainer = /*#__PURE__*/styled('div', {
2323
+ display: 'flex'
2324
+ });
2325
+ function HeaderButtons(props) {
2480
2326
  const {
2481
- navigateBackFrom
2482
- } = useNavigateBack();
2327
+ onClickRefresh
2328
+ } = props;
2329
+ const navigate = useNavigate();
2330
+ return React.createElement(ButtonsContainer, null, React.createElement(Tooltip, {
2331
+ content: "Refresh"
2332
+ }, React.createElement(Button, {
2333
+ variant: "ghost",
2334
+ onClick: onClickRefresh,
2335
+ disabled: !onClickRefresh
2336
+ }, React.createElement(RetryIcon, {
2337
+ size: 24,
2338
+ disabled: !onClickRefresh
2339
+ }))), React.createElement(Tooltip, {
2340
+ content: "Transactions History"
2341
+ }, React.createElement(Button, {
2342
+ variant: "ghost",
2343
+ onClick: () => navigate(navigationRoutes.swaps)
2344
+ }, React.createElement(HistoryIcon, {
2345
+ size: 24
2346
+ }))), React.createElement(Tooltip, {
2347
+ content: "Settings"
2348
+ }, React.createElement(Button, {
2349
+ variant: "ghost",
2350
+ onClick: () => navigate(navigationRoutes.settings)
2351
+ }, React.createElement(SettingsIcon, {
2352
+ size: 24
2353
+ }))));
2354
+ }
2355
+
2356
+ const Container$4 = /*#__PURE__*/styled('div', {
2357
+ display: 'flex',
2358
+ flexDirection: 'column'
2359
+ });
2360
+ const FromContainer = /*#__PURE__*/styled('div', {
2361
+ position: 'relative',
2362
+ paddingBottom: '$12'
2363
+ });
2364
+ const SwitchButtonContainer = /*#__PURE__*/styled('div', {
2365
+ position: 'absolute',
2366
+ bottom: '-12px',
2367
+ left: '50%',
2368
+ transform: 'translate(-50%, 10%)'
2369
+ });
2370
+ const BestRouteContainer = /*#__PURE__*/styled('div', {
2371
+ width: '100%',
2372
+ paddingTop: '$16'
2373
+ });
2374
+ const Alerts = /*#__PURE__*/styled('div', {
2375
+ width: '100%',
2376
+ paddingTop: '$16'
2377
+ });
2378
+ function Home() {
2379
+ const isRouterInContext = useInRouterContext$1();
2380
+ const navigate = useNavigate();
2381
+ const [count, setCount] = useState(0);
2382
+ const fromChain = useBestRouteStore.use.fromChain();
2383
+ const fromToken = useBestRouteStore.use.fromToken();
2384
+ const toChain = useBestRouteStore.use.toChain();
2385
+ const toToken = useBestRouteStore.use.toToken();
2386
+ const setInputAmount = useBestRouteStore.use.setInputAmount();
2387
+ const inputUsdValue = useBestRouteStore.use.inputUsdValue();
2388
+ const inputAmount = useBestRouteStore.use.inputAmount();
2389
+ const outputAmount = useBestRouteStore.use.outputAmount();
2390
+ const outputUsdValue = useBestRouteStore.use.outputUsdValue();
2391
+ const bestRoute = useBestRouteStore.use.bestRoute();
2392
+ const tokens = useMetaStore.use.meta().tokens;
2393
+ const fetchingBestRoute = useBestRouteStore.use.loading();
2394
+ const bestRouteError = useBestRouteStore.use.error();
2395
+ const loadingMetaStatus = useMetaStore.use.loadingStatus();
2396
+ const accounts = useWalletsStore.use.accounts();
2397
+ const setCurrentPage = useUiStore.use.setCurrentPage();
2398
+ const switchFromAndTo = useBestRouteStore.use.switchFromAndTo();
2399
+ const errorMessage = loadingMetaStatus === 'failed' ? errorMessages.genericServerError : bestRouteError;
2400
+ const needsToWarnEthOnPath = false;
2401
+ const showBestRoute = inputAmount && (!!bestRoute || fetchingBestRoute || bestRouteError);
2402
+ const outToInRatio = getOutputRatio(inputUsdValue, outputUsdValue);
2403
+ const highValueLoss = outputRatioHasWarning(inputUsdValue, outToInRatio);
2483
2404
  const {
2484
- manager,
2485
- state
2486
- } = useManager();
2487
- const pendingSwaps = getPendingSwaps(manager).map(_ref => {
2488
- let {
2489
- swap
2490
- } = _ref;
2491
- return swap;
2492
- });
2493
- const loading = !state.loadedFromPersistor;
2494
- return React.createElement(History, {
2495
- list: pendingSwaps,
2496
- groupBy: groupSwapsByDate,
2497
- loading: loading,
2498
- onSwapClick: requestId => {
2499
- setSelectedSwap(requestId);
2500
- navigate(navigationRoutes.swaps + `/${requestId}`, {
2501
- replace: true
2502
- });
2503
- },
2504
- onBack: navigateBackFrom.bind(null, navigationRoutes.swaps)
2505
- });
2405
+ fromAmountRangeError,
2406
+ recommendation,
2407
+ swap
2408
+ } = LimitErrorMessage(bestRoute);
2409
+ const priceImpactCanNotBeComputed = !canComputePriceImpact(bestRoute, inputAmount, inputUsdValue, outputUsdValue);
2410
+ const swapButtonState = getSwapButtonState(loadingMetaStatus, accounts, fetchingBestRoute, bestRoute, hasLimitError(bestRoute), highValueLoss, priceImpactCanNotBeComputed, needsToWarnEthOnPath, inputAmount);
2411
+ const totalFeeInUsd = getTotalFeeInUsd(bestRoute, tokens);
2412
+ const highFee = hasHighFee(totalFeeInUsd);
2413
+ useEffect(() => {
2414
+ setCurrentPage(navigationRoutes.home);
2415
+ return setCurrentPage.bind(null, '');
2416
+ }, []);
2417
+ return React.createElement(Container$4, null, React.createElement(Header$1, {
2418
+ title: "SWAP",
2419
+ suffix: React.createElement(HeaderButtons, {
2420
+ onClickRefresh: !!bestRoute || bestRouteError ? fetchBestRoute : undefined
2421
+ })
2422
+ }), React.createElement(FromContainer, null, React.createElement(TokenInfo, {
2423
+ type: "From",
2424
+ chain: fromChain,
2425
+ token: fromToken,
2426
+ onAmountChange: setInputAmount,
2427
+ inputAmount: inputAmount
2428
+ }), React.createElement(SwitchButtonContainer, null, React.createElement(Button, {
2429
+ variant: "ghost",
2430
+ onClick: () => {
2431
+ switchFromAndTo();
2432
+ setCount(prev => prev + 1);
2433
+ }
2434
+ }, React.createElement(VerticalSwapIcon, {
2435
+ size: 32
2436
+ }), isRouterInContext && React.createElement(SwithFromAndTo, {
2437
+ count: count
2438
+ })))), React.createElement(TokenInfo, {
2439
+ type: "To",
2440
+ chain: toChain,
2441
+ token: toToken,
2442
+ outputAmount: outputAmount ? new BigNumber(outputAmount) : new BigNumber(0),
2443
+ outputUsdValue: outputUsdValue
2444
+ }), showBestRoute && React.createElement(BestRouteContainer, null, React.createElement(BestRoute, {
2445
+ error: bestRouteError,
2446
+ loading: fetchingBestRoute,
2447
+ data: getFormatedBestRoute(bestRoute),
2448
+ totalFee: numberToString(totalFeeInUsd, 0, 2),
2449
+ feeWarning: highFee,
2450
+ totalTime: secondsToString(totalArrivalTime(bestRoute))
2451
+ })), (errorMessage || hasLimitError(bestRoute)) && React.createElement(Alerts, null, errorMessage && React.createElement(Alert, {
2452
+ type: "error"
2453
+ }, errorMessage), hasLimitError(bestRoute) && React.createElement(Alert, {
2454
+ type: "error",
2455
+ title: `${swap?.swapperId} Limit`
2456
+ }, React.createElement(React.Fragment, null, React.createElement(Typography, {
2457
+ variant: "body2"
2458
+ }, `${fromAmountRangeError}, Yours: ${numberToString(swap?.fromAmount || null)} ${swap?.from.symbol}`), React.createElement(Typography, {
2459
+ variant: "body2"
2460
+ }, recommendation)))), React.createElement(Footer, null, React.createElement(Button, {
2461
+ type: "primary",
2462
+ align: "grow",
2463
+ size: "large",
2464
+ disabled: swapButtonState.disabled,
2465
+ onClick: () => {
2466
+ if (swapButtonState.title === 'Connect Wallet') navigate(navigationRoutes.wallets);else {
2467
+ navigate(navigationRoutes.confirmSwap, {
2468
+ replace: true
2469
+ });
2470
+ }
2471
+ }
2472
+ }, swapButtonState.title), React.createElement(BottomLogo, null)));
2506
2473
  }
2507
2474
 
2508
2475
  function LiquiditySourcePage(_ref) {
@@ -2745,24 +2712,6 @@ function WalletsPage(_ref) {
2745
2712
  }))))));
2746
2713
  }
2747
2714
 
2748
- function useCopyToClipboard(resetInterval) {
2749
- const [isCopied, setCopied] = React.useState(false);
2750
- const handleCopy = React.useCallback(text => {
2751
- copy(text.toString());
2752
- setCopied(true);
2753
- }, []);
2754
- React.useEffect(() => {
2755
- let timeout;
2756
- if (isCopied && resetInterval) {
2757
- timeout = setTimeout(() => setCopied(false), resetInterval);
2758
- }
2759
- return () => {
2760
- clearTimeout(timeout);
2761
- };
2762
- }, [isCopied, resetInterval]);
2763
- return [isCopied, handleCopy];
2764
- }
2765
-
2766
2715
  function timeSince(timeMillis) {
2767
2716
  const seconds = Math.floor((new Date().getTime() - timeMillis) / 1000);
2768
2717
  let intervalType;
@@ -2942,50 +2891,50 @@ function AppRoutes(props) {
2942
2891
  config
2943
2892
  } = props;
2944
2893
  return useRoutes([{
2945
- path: getAbsolutePath(navigationRoutes.home),
2894
+ path: navigationRoutes.home,
2946
2895
  element: React.createElement(Home, null)
2947
2896
  }, {
2948
- path: getAbsolutePath(navigationRoutes.fromChain),
2897
+ path: navigationRoutes.fromChain,
2949
2898
  element: React.createElement(SelectChainPage, {
2950
2899
  type: "from",
2951
2900
  supportedChains: config?.from?.blockchains
2952
2901
  })
2953
2902
  }, {
2954
- path: getAbsolutePath(navigationRoutes.toChain),
2903
+ path: navigationRoutes.toChain,
2955
2904
  element: React.createElement(SelectChainPage, {
2956
2905
  type: "to",
2957
2906
  supportedChains: config?.to?.blockchains
2958
2907
  })
2959
2908
  }, {
2960
- path: getAbsolutePath(navigationRoutes.fromToken),
2909
+ path: navigationRoutes.fromToken,
2961
2910
  element: React.createElement(SelectTokenPage, {
2962
2911
  type: "from",
2963
2912
  supportedTokens: config?.from?.tokens
2964
2913
  })
2965
2914
  }, {
2966
- path: getAbsolutePath(navigationRoutes.toToken),
2915
+ path: navigationRoutes.toToken,
2967
2916
  element: React.createElement(SelectTokenPage, {
2968
2917
  type: "to",
2969
2918
  supportedTokens: config?.to?.tokens
2970
2919
  })
2971
2920
  }, {
2972
- path: getAbsolutePath(navigationRoutes.settings),
2921
+ path: navigationRoutes.settings,
2973
2922
  element: React.createElement(SettingsPage, {
2974
2923
  supportedSwappers: config?.liquiditySources
2975
2924
  })
2976
2925
  }, {
2977
- path: getAbsolutePath(navigationRoutes.liquiditySources),
2926
+ path: navigationRoutes.liquiditySources,
2978
2927
  element: React.createElement(LiquiditySourcePage, {
2979
2928
  supportedSwappers: config?.liquiditySources
2980
2929
  })
2981
2930
  }, {
2982
- path: getAbsolutePath(navigationRoutes.swaps),
2931
+ path: navigationRoutes.swaps,
2983
2932
  element: React.createElement(HistoryPage, null)
2984
2933
  }, {
2985
2934
  path: navigationRoutes.swapDetails,
2986
2935
  element: React.createElement(SwapDetailsPage, null)
2987
2936
  }, {
2988
- path: getAbsolutePath(navigationRoutes.wallets),
2937
+ path: navigationRoutes.wallets,
2989
2938
  element: React.createElement(WalletsPage, {
2990
2939
  supportedWallets: config?.wallets,
2991
2940
  multiWallets: typeof config?.multiWallets === 'undefined' ? true : config.multiWallets
@@ -3007,7 +2956,9 @@ const Header = /*#__PURE__*/styled('div', {
3007
2956
  const WalletImageContainer = /*#__PURE__*/styled('div', {
3008
2957
  marginLeft: -15,
3009
2958
  marginRight: '$6',
3010
- borderRadius: '99999px'
2959
+ '& img': {
2960
+ borderRadius: '50%'
2961
+ }
3011
2962
  });
3012
2963
  function Layout(_ref) {
3013
2964
  let {
@@ -3084,28 +3035,6 @@ function Layout(_ref) {
3084
3035
  }));
3085
3036
  }
3086
3037
 
3087
- const globalStyles = /*#__PURE__*/globalCss({
3088
- '*': {
3089
- boxSizing: 'border-box',
3090
- margin: 0,
3091
- padding: 0,
3092
- listStyleType: 'none',
3093
- '&::-webkit-scrollbar': {
3094
- width: '$8',
3095
- height: '$8'
3096
- },
3097
- '&::-webkit-scrollbar-thumb': {
3098
- backgroundColor: '$neutrals400',
3099
- borderRadius: '$10'
3100
- },
3101
- '&::-webkit-scrollbar-thumb:hover': {
3102
- backgroundColor: '$neutrals500'
3103
- },
3104
- '&::-webkit-scrollbar-track': {
3105
- backgroundColor: '$neutrals300'
3106
- }
3107
- }
3108
- });
3109
3038
  const globalFont = fontFamily => globalCss({
3110
3039
  '@import': ["url('https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap')", "url('https://fonts.cdnfonts.com/css/times-new-roman')"],
3111
3040
  body: {
@@ -3336,6 +3265,8 @@ function QueueManager(props) {
3336
3265
  API_KEY: getConfig('API_KEY')
3337
3266
  });
3338
3267
  }, []);
3268
+ const getOneOfWalletsDetails = useWalletsStore.use.getOneOfWalletsDetails();
3269
+ const accounts = useWalletsStore.use.accounts();
3339
3270
  const {
3340
3271
  blockchains
3341
3272
  } = useMetaStore.use.meta();
@@ -3362,6 +3293,17 @@ function QueueManager(props) {
3362
3293
  return walletAndSupportedChainsNames(supportedChains);
3363
3294
  };
3364
3295
  const allProviders = providers();
3296
+ const notifier = data => {
3297
+ const lastStep = data.swap?.steps[data.swap.steps.length - 1];
3298
+ const outputAmount = data.step?.outputAmount || '';
3299
+ const step = data.step || lastStep;
3300
+ if (data.eventType === 'task_completed' || data.eventType === 'step_completed_with_output' && lastStep?.id !== data.step?.id || !!outputAmount) {
3301
+ const fromAccount = accounts.find(account => account.chain === step?.fromBlockchain);
3302
+ const toAccount = step?.fromBlockchain !== step?.toBlockchain && accounts.find(account => account.chain === step?.toBlockchain);
3303
+ fromAccount && getOneOfWalletsDetails(fromAccount);
3304
+ toAccount && getOneOfWalletsDetails(toAccount);
3305
+ }
3306
+ };
3365
3307
  const context = {
3366
3308
  meta: {
3367
3309
  blockchains: allBlockchains,
@@ -3377,9 +3319,7 @@ function QueueManager(props) {
3377
3319
  switchNetwork,
3378
3320
  connect,
3379
3321
  state,
3380
- notifier: message => {
3381
- console.log('[notifier]', message);
3382
- }
3322
+ notifier
3383
3323
  };
3384
3324
  return React.createElement(Provider
3385
3325
  //@ts-ignore
@@ -3398,7 +3338,6 @@ const Widget = _ref => {
3398
3338
  let {
3399
3339
  config
3400
3340
  } = _ref;
3401
- globalStyles();
3402
3341
  globalFont(config?.theme?.fontFamily || 'Roboto');
3403
3342
  const {
3404
3343
  activeTheme
@@ -3463,7 +3402,6 @@ const Widget = _ref => {
3463
3402
  providers: providers,
3464
3403
  onUpdateState: onUpdateState
3465
3404
  }, React.createElement("div", {
3466
- id: "pageContainer",
3467
3405
  className: activeTheme
3468
3406
  }, React.createElement(QueueManager, null, React.createElement(SwapContainer, {
3469
3407
  fixedHeight: currentPage !== navigationRoutes.home