@rango-dev/widget-embedded 0.1.13-next.4 → 0.1.13

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.
@@ -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, useCopyToClipboard, 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,29 +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';
20
+ import { styled as styled$1 } from '@rango-dev/ui/src/theme';
21
21
  import Backend from 'i18next-http-backend';
22
22
  import LanguageDetector from 'i18next-browser-languagedetector';
23
23
 
24
- const navigationRoutes = {
25
- home: '/',
26
- fromChain: '/from-chain',
27
- fromToken: '/from-token',
28
- toChain: '/to-chain',
29
- toToken: '/to-token',
30
- settings: '/settings',
31
- liquiditySources: '/settings/liquidity-sources',
32
- swaps: '/swaps',
33
- wallets: '/wallets',
34
- confirmSwap: '/confirm-swap',
35
- swapDetails: '/swaps/:requestId'
36
- };
37
-
38
24
  const ZERO = /*#__PURE__*/new BigNumber(0);
39
25
 
40
26
  function removeDuplicateFrom(array) {
@@ -1195,6 +1181,20 @@ var SearchParams;
1195
1181
  SearchParams["FROM_AMOUNT"] = "fromAmount";
1196
1182
  })(SearchParams || (SearchParams = {}));
1197
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
+
1198
1198
  const useUiStore = /*#__PURE__*/createSelectors( /*#__PURE__*/create()(set => ({
1199
1199
  connectWalletsButtonDisabled: false,
1200
1200
  selectedSwapRequestId: null,
@@ -1242,37 +1242,6 @@ function UpdateUrl() {
1242
1242
  if (requestId) setSelectedSwap(requestId);
1243
1243
  }, []);
1244
1244
  useEffect(() => {
1245
- let fromChainString = '',
1246
- fromTokenString = '',
1247
- toChainString = '',
1248
- toTokenString = '',
1249
- fromAmount = '';
1250
- if (loadingStatus !== 'success' && location.pathname != navigationRoutes.confirmSwap) {
1251
- fromChainString = searchParamsRef.current[SearchParams.FROM_CHAIN];
1252
- fromTokenString = searchParamsRef.current[SearchParams.FROM_TOKEN];
1253
- toChainString = searchParamsRef.current[SearchParams.TO_CHAIN];
1254
- toTokenString = searchParamsRef.current[SearchParams.TO_TOKEN];
1255
- fromAmount = searchParamsRef.current[SearchParams.FROM_AMOUNT];
1256
- setSearchParams({
1257
- ...(fromChainString && {
1258
- [SearchParams.FROM_CHAIN]: fromChainString
1259
- }),
1260
- ...(fromTokenString && {
1261
- [SearchParams.FROM_TOKEN]: fromTokenString
1262
- }),
1263
- ...(toChainString && {
1264
- [SearchParams.TO_CHAIN]: toChainString
1265
- }),
1266
- ...(toTokenString && {
1267
- [SearchParams.TO_TOKEN]: toTokenString
1268
- }),
1269
- ...(fromAmount && {
1270
- [SearchParams.FROM_AMOUNT]: fromAmount.toString()
1271
- })
1272
- }, {
1273
- replace: true
1274
- });
1275
- }
1276
1245
  if (!firstRender.current) {
1277
1246
  let fromChainString = '',
1278
1247
  fromTokenString = '',
@@ -1284,7 +1253,7 @@ function UpdateUrl() {
1284
1253
  fromTokenString = searchParamsRef.current[SearchParams.FROM_TOKEN];
1285
1254
  toChainString = searchParamsRef.current[SearchParams.TO_CHAIN];
1286
1255
  toTokenString = searchParamsRef.current[SearchParams.TO_TOKEN];
1287
- fromAmount = searchParamsRef.current[SearchParams.FROM_AMOUNT];
1256
+ fromAmount = searchParamsRef.current[SearchParams.FROM_AMOUNT] || inputAmount;
1288
1257
  } else {
1289
1258
  if (location.state === 'redirect') return;
1290
1259
  fromChainString = fromChain?.name || '';
@@ -1292,29 +1261,29 @@ function UpdateUrl() {
1292
1261
  toChainString = toChain?.name || '';
1293
1262
  toTokenString = (toToken?.symbol || '') + (toToken?.address ? `--${toToken?.address}` : '');
1294
1263
  fromAmount = inputAmount;
1295
- setSearchParams({
1296
- ...(fromChainString && {
1297
- [SearchParams.FROM_CHAIN]: fromChainString
1298
- }),
1299
- ...(fromTokenString && {
1300
- [SearchParams.FROM_TOKEN]: fromTokenString
1301
- }),
1302
- ...(toChainString && {
1303
- [SearchParams.TO_CHAIN]: toChainString
1304
- }),
1305
- ...(toTokenString && {
1306
- [SearchParams.TO_TOKEN]: toTokenString
1307
- }),
1308
- ...(fromAmount && {
1309
- [SearchParams.FROM_AMOUNT]: fromAmount.toString()
1310
- })
1311
- }, {
1312
- replace: true
1313
- });
1314
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
+ });
1315
1284
  }
1316
1285
  firstRender.current = false;
1317
- }, [location.pathname, inputAmount]);
1286
+ }, [location.pathname, inputAmount, fromChain, fromToken, toChain, toToken]);
1318
1287
  useEffect(() => {
1319
1288
  if (loadingStatus === 'success') {
1320
1289
  const fromChainString = searchParams.get(SearchParams.FROM_CHAIN);
@@ -1340,18 +1309,45 @@ function UpdateUrl() {
1340
1309
  return null;
1341
1310
  }
1342
1311
 
1343
- 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;
1344
1319
  const {
1345
- inputUsdValue,
1346
- outputUsdValue
1347
- } = props;
1348
- if (!inputUsdValue || !outputUsdValue || !outputUsdValue.gt(0)) return null;
1349
- const percentageChange = getPercentageChange(inputUsdValue.toNumber(), outputUsdValue.toNumber());
1350
- const showPercentageChange = percentageChange?.lt(0);
1351
- return React.createElement(React.Fragment, null, showPercentageChange && React.createElement(Typography, {
1352
- variant: "caption",
1353
- color: "$error500"
1354
- }, `(${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
+ };
1355
1351
  }
1356
1352
 
1357
1353
  const Box = /*#__PURE__*/styled('div', {
@@ -1381,7 +1377,10 @@ const Container = /*#__PURE__*/styled('div', {
1381
1377
  display: 'flex',
1382
1378
  justifyContent: 'space-between',
1383
1379
  alignItems: 'center',
1384
- minHeight: '32px'
1380
+ minHeight: '32px',
1381
+ '.usd-value': {
1382
+ paddingLeft: '$8'
1383
+ }
1385
1384
  },
1386
1385
  '.form': {
1387
1386
  display: 'flex',
@@ -1398,21 +1397,6 @@ const Container = /*#__PURE__*/styled('div', {
1398
1397
  '.amount': {
1399
1398
  width: '30%'
1400
1399
  }
1401
- },
1402
- '.output-usd': {
1403
- display: 'flex',
1404
- div: {
1405
- display: 'flex',
1406
- paddingLeft: '$8'
1407
- }
1408
- }
1409
- });
1410
- const Options = /*#__PURE__*/styled('div', {
1411
- display: 'flex',
1412
- justifyContent: 'flex-end',
1413
- '.balance': {
1414
- display: 'flex',
1415
- alignItems: 'center'
1416
1400
  }
1417
1401
  });
1418
1402
  const ImagePlaceholder = /*#__PURE__*/styled('span', {
@@ -1433,28 +1417,16 @@ const OutputContainer = /*#__PURE__*/styled('div', {
1433
1417
  paddingLeft: '$8',
1434
1418
  paddingRight: '$8'
1435
1419
  });
1436
- function TokenInfo(props) {
1420
+ function TokenPreview(props) {
1437
1421
  const {
1438
- type,
1439
1422
  chain,
1440
- token
1423
+ token,
1424
+ loadingStatus,
1425
+ percentageChange
1441
1426
  } = props;
1442
- const loadingStatus = useMetaStore.use.loadingStatus();
1443
- const fromChain = useBestRouteStore.use.fromChain();
1444
- const toChain = useBestRouteStore.use.toChain();
1445
- const inputUsdValue = useBestRouteStore.use.inputUsdValue();
1446
- const fromToken = useBestRouteStore.use.fromToken();
1447
- const setInputAmount = useBestRouteStore.use.setInputAmount();
1448
- const bestRoute = useBestRouteStore.use.bestRoute();
1449
- const inputAmount = useBestRouteStore.use.inputAmount();
1450
- const balances = useWalletsStore.use.balances();
1451
- const fetchingBestRoute = useBestRouteStore.use.loading();
1452
- const navigate = useNavigate();
1453
1427
  const {
1454
1428
  t
1455
1429
  } = useTranslation();
1456
- const tokenBalance = !!fromChain && !!fromToken ? numberToString(getBalanceFromWallet(balances, fromChain?.name, fromToken?.symbol, fromToken?.address)?.amount || '0', 8) : '0';
1457
- 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';
1458
1430
  const ItemSuffix = React.createElement("div", {
1459
1431
  style: {
1460
1432
  display: 'flex',
@@ -1464,45 +1436,23 @@ function TokenInfo(props) {
1464
1436
  }, loadingStatus === 'failed' && React.createElement(InfoCircleIcon, {
1465
1437
  color: "error",
1466
1438
  size: 24
1467
- }), React.createElement(AngleDownIcon, null));
1439
+ }));
1468
1440
  return React.createElement(Box, null, React.createElement(Container, {
1469
- type: props.type === 'From' ? 'filled' : 'outlined'
1441
+ type: 'outlined'
1470
1442
  }, React.createElement("div", {
1471
1443
  className: "head"
1472
1444
  }, React.createElement(Typography, {
1473
1445
  variant: "body2",
1474
1446
  color: "neutrals800"
1475
- }, t(type)), props.type === 'From' ? React.createElement(Options, null, React.createElement("div", {
1476
- className: "balance",
1477
- onClick: () => {
1478
- if (tokenBalance !== '0') setInputAmount(tokenBalanceReal.split(',').join(''));
1479
- }
1480
- }, React.createElement(Typography, {
1481
- variant: "body3",
1482
- color: "neutrals600"
1483
- }, `${t('Balance')}: ${tokenBalance} ${fromToken?.symbol || ''}`), React.createElement(Spacer, {
1484
- size: 4
1485
- }), React.createElement(Button, {
1486
- type: "primary",
1487
- variant: "ghost",
1488
- size: "compact"
1489
- }, t('Max')))) : React.createElement("div", {
1490
- className: "output-usd"
1491
- }, React.createElement(PercentageChange, {
1492
- inputUsdValue: inputUsdValue,
1493
- outputUsdValue: props.outputUsdValue
1494
- }), React.createElement("div", null, React.createElement(Typography, {
1447
+ }, props.label), React.createElement("div", null, percentageChange, props.usdValue && React.createElement(Typography, {
1495
1448
  variant: "caption",
1496
- color: "neutrals600"
1497
- }, `$${numberToString(props.outputUsdValue)}`)))), React.createElement("div", {
1449
+ color: "neutrals600",
1450
+ className: "usd-value"
1451
+ }, `$${numberToString(props.usdValue)}`))), React.createElement("div", {
1498
1452
  className: "form"
1499
1453
  }, React.createElement(Button, {
1500
1454
  className: "selectors",
1501
- onClick: () => {
1502
- navigate(`/${props.type.toLowerCase()}-chain`);
1503
- },
1504
1455
  variant: "outlined",
1505
- disabled: loadingStatus === 'failed',
1506
1456
  loading: loadingStatus === 'loading',
1507
1457
  prefix: loadingStatus === 'success' && chain ? React.createElement(Image, {
1508
1458
  src: chain.logo,
@@ -1515,11 +1465,7 @@ function TokenInfo(props) {
1515
1465
  size: 12
1516
1466
  }), React.createElement(Button, {
1517
1467
  className: "selectors",
1518
- onClick: () => {
1519
- navigate(`/${props.type.toLowerCase()}-token`);
1520
- },
1521
1468
  variant: "outlined",
1522
- disabled: loadingStatus === 'failed' || type === 'From' && !fromChain || type === 'To' && !toChain,
1523
1469
  loading: loadingStatus === 'loading',
1524
1470
  prefix: loadingStatus === 'success' && token ? React.createElement(Image, {
1525
1471
  src: token.image,
@@ -1532,989 +1478,998 @@ function TokenInfo(props) {
1532
1478
  size: 12
1533
1479
  }), React.createElement("div", {
1534
1480
  className: "amount"
1535
- }, props.type === 'From' ? React.createElement(TextField, {
1536
- type: "number",
1537
- size: "large",
1538
- autoFocus: true,
1539
- placeholder: "0",
1540
- style: {
1541
- position: 'relative',
1542
- backgroundColor: '$background !important'
1543
- },
1544
- suffix: React.createElement("span", {
1545
- style: {
1546
- position: 'absolute',
1547
- right: '4px',
1548
- bottom: '2px'
1549
- }
1550
- }, React.createElement(Typography, {
1551
- variant: "caption",
1552
- color: "neutrals800"
1553
- }, `$${numberToString(inputUsdValue)}`)),
1554
- value: props.inputAmount || '',
1555
- min: 0,
1556
- onChange: props.type === 'From' ? event => {
1557
- props.onAmountChange(event.target.value);
1558
- } : undefined
1559
- }) : React.createElement(OutputContainer, null, React.createElement(Typography, {
1481
+ }, React.createElement(OutputContainer, null, React.createElement(Typography, {
1560
1482
  variant: "h4"
1561
- }, fetchingBestRoute && '?', !!bestRoute?.result && `≈ ${numberToString(props.outputAmount)}`, (!inputAmount || inputAmount === '0') && '0'))))));
1483
+ }, props.amount))))));
1562
1484
  }
1563
1485
 
1564
- const Container$1 = /*#__PURE__*/styled$1('div', {
1565
- display: 'flex',
1566
- width: '100%',
1567
- justifyContent: 'end',
1568
- alignItems: 'center',
1569
- paddingTop: '$16'
1570
- });
1571
- const Logo = /*#__PURE__*/styled$1('svg', {
1572
- fill: '$foreground',
1573
- width: '$24',
1574
- margin: '0 $8 0 $16'
1575
- });
1576
- const StyledAnchor = /*#__PURE__*/styled$1('a', {
1486
+ const Container$1 = /*#__PURE__*/styled('div', {
1577
1487
  display: 'flex',
1578
- justifyContent: 'center',
1579
1488
  alignItems: 'center',
1580
- textDecoration: 'none'
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
+ }
1581
1503
  });
1582
- function BottomLogo() {
1583
- const {
1584
- t
1585
- } = useTranslation();
1586
- return React.createElement(Container$1, null, React.createElement(Typography, {
1587
- variant: "caption",
1588
- color: '$neutrals600'
1589
- }, t('Powered By')), React.createElement(StyledAnchor, {
1590
- href: "https://rango.exchange",
1591
- target: "_blank"
1592
- }, React.createElement(Logo, {
1593
- xmlns: "http://www.w3.org/2000/svg",
1594
- viewBox: "0 0 33.68 29"
1595
- }, React.createElement("defs", null), React.createElement("g", {
1596
- id: "Layer_2",
1597
- "data-name": "Layer 2"
1598
- }, React.createElement("g", {
1599
- id: "Layer_1-2",
1600
- "data-name": "Layer 1"
1601
- }, React.createElement("path", {
1602
- 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"
1603
- }), React.createElement("path", {
1604
- 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"
1605
- })))), React.createElement(Typography, {
1606
- variant: "body2"
1607
- }, "RANGO")));
1608
- }
1609
-
1610
- function SwithFromAndTo(_ref) {
1611
- let {
1612
- count
1613
- } = _ref;
1614
- const firstRender = useRef(true);
1615
- const [searchParams, setSearchParams] = useSearchParams();
1616
- const outputAmount = useBestRouteStore.use.outputAmount();
1617
- useEffect(() => {
1618
- if (!firstRender.current) {
1619
- const fromChainString = searchParams.get(SearchParams.FROM_CHAIN);
1620
- const fromTokenString = searchParams.get(SearchParams.FROM_TOKEN);
1621
- const toChainString = searchParams.get(SearchParams.TO_CHAIN);
1622
- const toTokenString = searchParams.get(SearchParams.TO_TOKEN);
1623
- setSearchParams({
1624
- ...(toChainString && {
1625
- [SearchParams.FROM_CHAIN]: toChainString
1626
- }),
1627
- ...(toTokenString && {
1628
- [SearchParams.FROM_TOKEN]: toTokenString
1629
- }),
1630
- ...(fromChainString && {
1631
- [SearchParams.TO_CHAIN]: fromChainString
1632
- }),
1633
- ...(fromTokenString && {
1634
- [SearchParams.TO_TOKEN]: fromTokenString
1635
- }),
1636
- ...(outputAmount && {
1637
- [SearchParams.FROM_AMOUNT]: outputAmount.toString()
1638
- })
1639
- });
1640
- } else {
1641
- firstRender.current = false;
1642
- }
1643
- }, [count]);
1644
- 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);
1645
1527
  }
1646
1528
 
1647
- const Footer = /*#__PURE__*/styled('div', {
1648
- display: 'flex',
1649
- flexDirection: 'column',
1650
- width: '100%',
1651
- paddingTop: '$16'
1652
- });
1653
-
1654
- const errorMessages = {
1655
- genericServerError: 'Error connecting server, please reload the app and try again'
1656
- };
1657
-
1658
- const ButtonsContainer = /*#__PURE__*/styled('div', {
1659
- display: 'flex'
1660
- });
1661
- function HeaderButtons(props) {
1662
- const {
1663
- onClickRefresh
1664
- } = props;
1665
- const navigate = useNavigate();
1666
- return React.createElement(ButtonsContainer, null, React.createElement(Tooltip, {
1667
- content: "Refresh"
1668
- }, React.createElement(Button, {
1669
- variant: "ghost",
1670
- onClick: onClickRefresh,
1671
- disabled: !onClickRefresh
1672
- }, React.createElement(RetryIcon, {
1673
- size: 24,
1674
- disabled: !onClickRefresh
1675
- }))), React.createElement(Tooltip, {
1676
- content: "Transactions History"
1677
- }, React.createElement(Button, {
1678
- variant: "ghost",
1679
- onClick: () => navigate(navigationRoutes.swaps)
1680
- }, React.createElement(HistoryIcon, {
1681
- size: 24
1682
- }))), React.createElement(Tooltip, {
1683
- content: "Settings"
1684
- }, React.createElement(Button, {
1685
- variant: "ghost",
1686
- onClick: () => navigate(navigationRoutes.settings)
1687
- }, React.createElement(SettingsIcon, {
1688
- size: 24
1689
- }))));
1690
- }
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 = {}));
1691
1544
 
1692
- const Container$2 = /*#__PURE__*/styled('div', {
1693
- display: 'flex',
1694
- flexDirection: 'column'
1695
- });
1696
- const FromContainer = /*#__PURE__*/styled('div', {
1697
- position: 'relative',
1698
- paddingBottom: '$12'
1699
- });
1700
- const SwitchButtonContainer = /*#__PURE__*/styled('div', {
1701
- position: 'absolute',
1702
- bottom: '-12px',
1703
- left: '50%',
1704
- transform: 'translate(-50%, 10%)'
1705
- });
1706
- const BestRouteContainer = /*#__PURE__*/styled('div', {
1707
- width: '100%',
1708
- paddingTop: '$16'
1709
- });
1710
- const Alerts = /*#__PURE__*/styled('div', {
1711
- width: '100%',
1712
- paddingTop: '$16'
1713
- });
1714
- function Home() {
1715
- const isRouterInContext = useInRouterContext();
1716
- const navigate = useNavigate();
1717
- const [count, setCount] = useState(0);
1718
- const fromChain = useBestRouteStore.use.fromChain();
1545
+ function useConfirmSwap() {
1719
1546
  const fromToken = useBestRouteStore.use.fromToken();
1720
- const toChain = useBestRouteStore.use.toChain();
1721
1547
  const toToken = useBestRouteStore.use.toToken();
1722
- const setInputAmount = useBestRouteStore.use.setInputAmount();
1723
- const inputUsdValue = useBestRouteStore.use.inputUsdValue();
1724
1548
  const inputAmount = useBestRouteStore.use.inputAmount();
1725
- const outputAmount = useBestRouteStore.use.outputAmount();
1726
- const outputUsdValue = useBestRouteStore.use.outputUsdValue();
1727
- const bestRoute = useBestRouteStore.use.bestRoute();
1728
- const tokens = useMetaStore.use.meta().tokens;
1729
- const fetchingBestRoute = useBestRouteStore.use.loading();
1730
- const bestRouteError = useBestRouteStore.use.error();
1731
- 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();
1732
1553
  const accounts = useWalletsStore.use.accounts();
1733
- const setCurrentPage = useUiStore.use.setCurrentPage();
1734
- const switchFromAndTo = useBestRouteStore.use.switchFromAndTo();
1735
- const errorMessage = loadingMetaStatus === 'failed' ? errorMessages.genericServerError : bestRouteError;
1736
- const needsToWarnEthOnPath = false;
1737
- const showBestRoute = inputAmount && (!!bestRoute || fetchingBestRoute || bestRouteError);
1738
- const outToInRatio = getOutputRatio(inputUsdValue, outputUsdValue);
1739
- const highValueLoss = outputRatioHasWarning(inputUsdValue, outToInRatio);
1740
- const {
1741
- fromAmountRangeError,
1742
- recommendation,
1743
- swap
1744
- } = LimitErrorMessage(bestRoute);
1745
- const priceImpactCanNotBeComputed = !canComputePriceImpact(bestRoute, inputAmount, inputUsdValue, outputUsdValue);
1746
- const swapButtonState = getSwapButtonState(loadingMetaStatus, accounts, fetchingBestRoute, bestRoute, hasLimitError(bestRoute), highValueLoss, priceImpactCanNotBeComputed, needsToWarnEthOnPath, inputAmount);
1747
- const totalFeeInUsd = getTotalFeeInUsd(bestRoute, tokens);
1748
- 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([]);
1749
1566
  useEffect(() => {
1750
- setCurrentPage(navigationRoutes.home);
1751
- return setCurrentPage.bind(null, '');
1567
+ return () => abortControllerRef.current?.abort();
1752
1568
  }, []);
1753
- return React.createElement(Container$2, null, React.createElement(Header$1, {
1754
- title: "SWAP",
1755
- suffix: React.createElement(HeaderButtons, {
1756
- onClickRefresh: !!bestRoute || bestRouteError ? fetchBestRoute : undefined
1757
- })
1758
- }), React.createElement(FromContainer, null, React.createElement(TokenInfo, {
1759
- type: "From",
1760
- chain: fromChain,
1761
- token: fromToken,
1762
- onAmountChange: setInputAmount,
1763
- inputAmount: inputAmount
1764
- }), React.createElement(SwitchButtonContainer, null, React.createElement(Button, {
1765
- variant: "ghost",
1766
- onClick: () => {
1767
- switchFromAndTo();
1768
- 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;
1769
1589
  }
1770
- }, React.createElement(VerticalSwapIcon, {
1771
- size: 32
1772
- }), isRouterInContext && React.createElement(SwithFromAndTo, {
1773
- count: count
1774
- })))), React.createElement(TokenInfo, {
1775
- type: "To",
1776
- chain: toChain,
1777
- token: toToken,
1778
- outputAmount: outputAmount ? new BigNumber(outputAmount) : new BigNumber(0),
1779
- outputUsdValue: outputUsdValue
1780
- }), showBestRoute && React.createElement(BestRouteContainer, null, React.createElement(BestRoute, {
1781
- error: bestRouteError,
1782
- loading: fetchingBestRoute,
1783
- data: getFormatedBestRoute(bestRoute),
1784
- totalFee: numberToString(totalFeeInUsd, 0, 2),
1785
- feeWarning: highFee,
1786
- totalTime: secondsToString(totalArrivalTime(bestRoute))
1787
- })), (errorMessage || hasLimitError(bestRoute)) && React.createElement(Alerts, null, errorMessage && React.createElement(Alert, {
1788
- type: "error"
1789
- }, errorMessage), hasLimitError(bestRoute) && React.createElement(Alert, {
1790
- type: "error",
1791
- title: `${swap?.swapperId} Limit`
1792
- }, React.createElement(React.Fragment, null, React.createElement(Typography, {
1793
- variant: "body2"
1794
- }, `${fromAmountRangeError}, Yours: ${numberToString(swap?.fromAmount || null)} ${swap?.from.symbol}`), React.createElement(Typography, {
1795
- variant: "body2"
1796
- }, recommendation)))), React.createElement(Footer, null, React.createElement(Button, {
1797
- type: "primary",
1798
- align: "grow",
1799
- size: "large",
1800
- disabled: swapButtonState.disabled,
1801
- onClick: () => {
1802
- if (swapButtonState.title === 'Connect Wallet') navigate(navigationRoutes.wallets);else {
1803
- navigate(navigationRoutes.confirmSwap, {
1804
- 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
1805
1627
  });
1806
1628
  }
1807
- }
1808
- }, swapButtonState.title), React.createElement(BottomLogo, null)));
1809
- }
1810
-
1811
- const Route = _ref => {
1812
- let {
1813
- children
1814
- } = _ref;
1815
- const location = useLocation$1();
1816
- const navigate = useNavigate$1();
1817
- const ref = useRef(true);
1818
- useEffect(() => {
1819
- if (location.pathname === navigationRoutes.confirmSwap && ref.current) navigate(navigationRoutes.home + location.search, {
1820
- state: 'redirect'
1821
- });
1822
- ref.current = false;
1823
- }, []);
1824
- if (location.pathname === navigationRoutes.confirmSwap && ref.current) return React.createElement(Home, null);
1825
- return React.createElement(React.Fragment, null, " ", children);
1826
- };
1827
- function AppRouter(_ref2) {
1828
- let {
1829
- children,
1830
- ...props
1831
- } = _ref2;
1832
- const isRouterInContext = useInRouterContext$1();
1833
- const Router = isRouterInContext ? Route : MemoryRouter;
1834
- const {
1835
- blockchains
1836
- } = useMetaStore.use.meta();
1837
- const evmChains = blockchains.filter(isEvmBlockchain);
1838
- useQueueManager({
1839
- lastConnectedWallet: props.lastConnectedWallet,
1840
- clearDisconnectedWallet: props.clearDisconnectedWallet,
1841
- disconnectedWallet: props.disconnectedWallet,
1842
- evmChains,
1843
- notifier: () => {}
1844
- });
1845
- return React.createElement(React.Fragment, null, React.createElement(Router, Object.assign({}, props), children), isRouterInContext && React.createElement(UpdateUrl, null));
1846
- }
1847
-
1848
- function useNavigateBack() {
1849
- const isRouterInContext = useInRouterContext();
1850
- const navigate = useNavigate();
1851
- const navigateBackFrom = currentRoute => {
1852
- if (currentRoute === navigationRoutes.swapDetails) return navigate(navigationRoutes.swaps, {
1853
- replace: true
1854
- });
1855
- if (!isRouterInContext || window.history.state && window.history.state.idx > 0) navigate(-1);else {
1856
- if ([navigationRoutes.fromChain, navigationRoutes.fromToken, navigationRoutes.toChain, navigationRoutes.toToken, navigationRoutes.settings, navigationRoutes.wallets, navigationRoutes.swaps, navigationRoutes.confirmSwap].includes(currentRoute)) navigate(navigationRoutes.home, {
1857
- replace: true
1858
- });else if (currentRoute === navigationRoutes.liquiditySources) navigate(navigationRoutes.settings, {
1859
- replace: true
1860
- });else if (currentRoute === navigationRoutes.swapDetails) navigate(navigationRoutes.swaps, {
1861
- 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
1862
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;
1863
1667
  }
1864
1668
  };
1865
1669
  return {
1866
- navigateBackFrom
1670
+ loading,
1671
+ warnings,
1672
+ errors,
1673
+ confirmSwap
1867
1674
  };
1868
1675
  }
1869
1676
 
1870
- const Box$1 = /*#__PURE__*/styled('div', {
1871
- display: 'flex',
1872
- flexDirection: 'column',
1873
- width: '100%',
1874
- overflow: 'hidden'
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'
1875
1689
  });
1876
- const Container$3 = /*#__PURE__*/styled('div', {
1877
- boxSizing: 'border-box',
1878
- borderRadius: '$5',
1879
- 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,
1880
1705
  variants: {
1881
- type: {
1882
- filled: {
1883
- backgroundColor: '$neutrals300'
1884
- },
1885
- outlined: {
1886
- border: '1px solid $neutrals300'
1706
+ showListStyle: {
1707
+ true: {
1708
+ paddingLeft: '$24'
1887
1709
  }
1888
1710
  }
1889
- },
1890
- defaultVariants: {
1891
- type: 'filled'
1892
- },
1893
- '.head': {
1894
- display: 'flex',
1895
- justifyContent: 'space-between',
1896
- alignItems: 'center',
1897
- minHeight: '32px',
1898
- '.usd-value': {
1899
- paddingLeft: '$8'
1900
- }
1901
- },
1902
- '.form': {
1903
- display: 'flex',
1904
- width: '100%',
1905
- padding: '$2 0',
1906
- '.selectors': {
1907
- width: '35%',
1908
- '._text': {
1909
- whiteSpace: 'nowrap',
1910
- overflow: 'hidden',
1911
- textOverflow: 'ellipsis'
1711
+ }
1712
+ });
1713
+ const ListItem = /*#__PURE__*/styled('li', {
1714
+ variants: {
1715
+ showListStyle: {
1716
+ true: {
1717
+ listStyleType: 'disc',
1718
+ listStylePosition: 'outside'
1912
1719
  }
1913
- },
1914
- '.amount': {
1915
- width: '30%'
1916
1720
  }
1917
1721
  }
1918
1722
  });
1919
- const ImagePlaceholder$1 = /*#__PURE__*/styled('span', {
1920
- width: '24px',
1921
- height: '24px',
1922
- backgroundColor: '$neutrals300',
1923
- borderRadius: '99999px'
1924
- });
1925
- const OutputContainer$1 = /*#__PURE__*/styled('div', {
1926
- windth: '100%',
1927
- height: '$48',
1928
- borderRadius: '$5',
1929
- backgroundColor: '$background',
1930
- border: '1px solid transparent',
1931
- position: 'relative',
1932
- display: 'flex',
1933
- alignItems: 'center',
1934
- paddingLeft: '$8',
1935
- paddingRight: '$8'
1723
+ const Message = /*#__PURE__*/styled(Typography, {
1724
+ display: 'block'
1936
1725
  });
1937
- function TokenPreview(props) {
1938
- const {
1939
- chain,
1940
- token,
1941
- loadingStatus,
1942
- percentageChange
1943
- } = props;
1944
- const {
1945
- t
1946
- } = useTranslation();
1947
- const ItemSuffix = React.createElement("div", {
1948
- style: {
1949
- display: 'flex',
1950
- justifyContent: 'center',
1951
- alignItems: 'center'
1952
- }
1953
- }, loadingStatus === 'failed' && React.createElement(InfoCircleIcon, {
1954
- color: "error",
1955
- size: 24
1956
- }));
1957
- return React.createElement(Box$1, null, React.createElement(Container$3, {
1958
- type: 'outlined'
1959
- }, React.createElement("div", {
1960
- className: "head"
1961
- }, React.createElement(Typography, {
1962
- variant: "body2",
1963
- color: "neutrals800"
1964
- }, props.label), React.createElement("div", null, percentageChange, props.usdValue && React.createElement(Typography, {
1965
- variant: "caption",
1966
- color: "neutrals600",
1967
- className: "usd-value"
1968
- }, `$${numberToString(props.usdValue)}`))), React.createElement("div", {
1969
- className: "form"
1970
- }, React.createElement(Button, {
1971
- className: "selectors",
1972
- variant: "outlined",
1973
- loading: loadingStatus === 'loading',
1974
- prefix: loadingStatus === 'success' && chain ? React.createElement(Image, {
1975
- src: chain.logo,
1976
- size: 24
1977
- }) : React.createElement(ImagePlaceholder$1, null),
1978
- suffix: ItemSuffix,
1979
- align: "start",
1980
- size: "large"
1981
- }, loadingStatus === 'success' && chain ? chain.displayName : t('Chain')), React.createElement(Spacer, {
1982
- size: 12
1983
- }), React.createElement(Button, {
1984
- className: "selectors",
1985
- variant: "outlined",
1986
- loading: loadingStatus === 'loading',
1987
- prefix: loadingStatus === 'success' && token ? React.createElement(Image, {
1988
- src: token.image,
1989
- size: 24
1990
- }) : React.createElement(ImagePlaceholder$1, null),
1991
- suffix: ItemSuffix,
1992
- size: "large",
1993
- align: "start"
1994
- }, loadingStatus === 'success' && token ? token.symbol : t('Token')), React.createElement(Spacer, {
1995
- size: 12
1996
- }), React.createElement("div", {
1997
- className: "amount"
1998
- }, React.createElement(OutputContainer$1, null, React.createElement(Typography, {
1999
- variant: "h4"
2000
- }, props.amount))))));
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)))));
2001
1746
  }
2002
1747
 
2003
- const Container$4 = /*#__PURE__*/styled('div', {
2004
- display: 'flex',
2005
- alignItems: 'center',
2006
- justifyContent: 'space-between',
2007
- padding: '$8',
2008
- borderRadius: '$5',
2009
- backgroundColor: '$neutrals300',
2010
- color: '$neutrals800',
2011
- fontSize: '$12',
2012
- '.routes': {
2013
- display: 'flex',
2014
- alignItems: 'center'
2015
- },
2016
- '.fee': {
2017
- display: 'flex',
2018
- alignItems: 'center'
2019
- }
2020
- });
2021
- function RoutesOverview(props) {
2022
- if (!props.routes) return null;
2023
- const swaps = props.routes.result?.swaps;
2024
- return React.createElement(Container$4, null, React.createElement("div", {
2025
- className: "routes"
2026
- }, swaps?.map((swap, idx) => {
2027
- const isLast = idx + 1 == swaps.length;
2028
- return React.createElement(React.Fragment, {
2029
- key: idx
2030
- }, React.createElement("div", {
2031
- className: "route"
2032
- }, swap.from.symbol), React.createElement(ChevronRightIcon, {
2033
- size: 12
2034
- }), isLast ? React.createElement("div", {
2035
- className: "route"
2036
- }, swap.to.symbol) : null);
2037
- })), props.totalFee ? React.createElement("div", {
2038
- className: "fee"
2039
- }, React.createElement(GasIcon, {
2040
- size: 12
2041
- }), React.createElement(Spacer, {
2042
- size: 4
2043
- }), "$", props.totalFee) : null);
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 [];
1767
+ }
1768
+ });
2044
1769
  }
2045
1770
 
2046
- var ConfirmSwapErrorTypes;
2047
- (function (ConfirmSwapErrorTypes) {
2048
- ConfirmSwapErrorTypes[ConfirmSwapErrorTypes["NO_ROUTE"] = 0] = "NO_ROUTE";
2049
- ConfirmSwapErrorTypes[ConfirmSwapErrorTypes["ROUTE_UPDATED_WITH_HIGH_VALUE_LOSS"] = 1] = "ROUTE_UPDATED_WITH_HIGH_VALUE_LOSS";
2050
- ConfirmSwapErrorTypes[ConfirmSwapErrorTypes["REQUEST_FAILED"] = 2] = "REQUEST_FAILED";
2051
- ConfirmSwapErrorTypes[ConfirmSwapErrorTypes["INSUFFICIENT_SLIPPAGE"] = 3] = "INSUFFICIENT_SLIPPAGE";
2052
- ConfirmSwapErrorTypes[ConfirmSwapErrorTypes["INSUFFICIENT_BALANCE"] = 4] = "INSUFFICIENT_BALANCE";
2053
- })(ConfirmSwapErrorTypes || (ConfirmSwapErrorTypes = {}));
2054
- var ConfirmSwapWarningTypes;
2055
- (function (ConfirmSwapWarningTypes) {
2056
- ConfirmSwapWarningTypes[ConfirmSwapWarningTypes["ROUTE_UPDATED"] = 0] = "ROUTE_UPDATED";
2057
- ConfirmSwapWarningTypes[ConfirmSwapWarningTypes["ROUTE_SWAPPERS_UPDATED"] = 1] = "ROUTE_SWAPPERS_UPDATED";
2058
- ConfirmSwapWarningTypes[ConfirmSwapWarningTypes["ROUTE_COINS_UPDATED"] = 2] = "ROUTE_COINS_UPDATED";
2059
- ConfirmSwapWarningTypes[ConfirmSwapWarningTypes["ROUTE_AND_OUTPUT_AMOUNT_UPDATED"] = 3] = "ROUTE_AND_OUTPUT_AMOUNT_UPDATED";
2060
- })(ConfirmSwapWarningTypes || (ConfirmSwapWarningTypes = {}));
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
+ });
1786
+ }
2061
1787
 
2062
- function useConfirmSwap() {
2063
- const fromToken = useBestRouteStore.use.fromToken();
2064
- const toToken = useBestRouteStore.use.toToken();
2065
- const inputAmount = useBestRouteStore.use.inputAmount();
2066
- const initialRoute = useBestRouteStore.use.bestRoute();
2067
- const setBestRoute = useBestRouteStore.use.setBestRoute();
2068
- const inputUsdValue = useBestRouteStore.use.inputUsdValue();
2069
- const affiliateRef = useSettingsStore.use.affiliateRef();
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
+ }
1797
+
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();
2070
1836
  const accounts = useWalletsStore.use.accounts();
2071
1837
  const selectedWallets = useWalletsStore.use.selectedWallets();
2072
- const meta = useMetaStore.use.meta();
2073
- const customSlippage = useSettingsStore.use.customSlippage();
1838
+ const initSelectedWallets = useWalletsStore.use.initSelectedWallets();
1839
+ const setSelectedWallet = useWalletsStore.use.setSelectedWallet();
2074
1840
  const slippage = useSettingsStore.use.slippage();
2075
- const disabledLiquiditySources = useSettingsStore.use.disabledLiquiditySources();
2076
- const userSlippage = customSlippage || slippage;
2077
- const proceedAnywayRef = useRef(false);
2078
- const confiremedRouteRef = useRef(null);
2079
- let abortControllerRef = useRef(null);
2080
- const [loading, setLoading] = useState(false);
2081
- const [errors, setErrors] = useState([]);
2082
- 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);
2083
1866
  useEffect(() => {
2084
- return () => abortControllerRef.current?.abort();
1867
+ initSelectedWallets();
2085
1868
  }, []);
2086
- if (!fromToken || !toToken || !inputAmount || !initialRoute) return {
2087
- loading: false,
2088
- warnings: [],
2089
- errors: [],
2090
- 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));
2091
1873
  };
2092
- const confirmSwap = async () => {
2093
- if (proceedAnywayRef.current) {
2094
- const swapSettings = {
2095
- slippage: userSlippage.toString(),
2096
- disabledSwappersGroups: disabledLiquiditySources
2097
- };
2098
- if (errors.length > 0) setErrors([]);
2099
- if (warnings.length > 0) setWarnings([]);
2100
- proceedAnywayRef.current = false;
2101
- if (confiremedRouteRef.current) {
2102
- const newSwap = calculatePendingSwap(inputAmount.toString(), confiremedRouteRef.current, getWalletsForNewSwap(selectedWallets), swapSettings, false, meta);
2103
- return newSwap;
2104
- }
2105
- return;
2106
- }
2107
- abortControllerRef.current = new AbortController();
2108
- setLoading(true);
2109
- const requestBody = createBestRouteRequestBody(fromToken, toToken, inputAmount, accounts, selectedWallets, disabledLiquiditySources, userSlippage, affiliateRef, initialRoute);
2110
- try {
2111
- const confiremedRoute = await httpService().getBestRoute(requestBody, {
2112
- signal: abortControllerRef.current?.signal
2113
- });
2114
- abortControllerRef.current = null;
2115
- setLoading(false);
2116
- if (!confiremedRoute.result || !new BigNumber(confiremedRoute.requestAmount).isEqualTo(new BigNumber(inputAmount || '-1'))) {
2117
- setErrors(prevState => prevState.concat({
2118
- type: ConfirmSwapErrorTypes.NO_ROUTE
2119
- }));
2120
- return;
2121
- }
2122
- const confirmSwapState = {
2123
- errors: [],
2124
- warnings: []
2125
- };
2126
- const routeChanged = isRouteChanged(initialRoute, confiremedRoute);
2127
- if (routeChanged) {
2128
- setBestRoute(confiremedRoute);
2129
- const newRouteOutputUsdValue = new BigNumber(confiremedRoute.result?.outputAmount || '0').multipliedBy(toToken.usdPrice || 0);
2130
- const outputRatio = getOutputRatio(inputUsdValue, newRouteOutputUsdValue);
2131
- const highValueLoss = outputRatioHasWarning(inputUsdValue, outputRatio);
2132
- if (highValueLoss) confirmSwapState.errors.push({
2133
- type: ConfirmSwapErrorTypes.ROUTE_UPDATED_WITH_HIGH_VALUE_LOSS
2134
- });else if (isOutputAmountChangedALot(initialRoute, confiremedRoute)) confirmSwapState.warnings.push({
2135
- type: ConfirmSwapWarningTypes.ROUTE_AND_OUTPUT_AMOUNT_UPDATED,
2136
- newOutputAmount: numberToString(getRouteOutputAmount(confiremedRoute)),
2137
- percentageChange: numberToString(getPercentageChange(getRouteOutputAmount(initialRoute), getRouteOutputAmount(confiremedRoute)), null, 2)
2138
- });else if (isRouteInternalCoinsUpdated(initialRoute, confiremedRoute)) confirmSwapState.warnings.push({
2139
- type: ConfirmSwapWarningTypes.ROUTE_COINS_UPDATED
2140
- });else if (isNumberOfSwapsChanged(initialRoute, confiremedRoute)) confirmSwapState.warnings.push({
2141
- type: ConfirmSwapWarningTypes.ROUTE_UPDATED
2142
- });else if (isRouteSwappersUpdated(initialRoute, confiremedRoute)) confirmSwapState.warnings.push({
2143
- type: ConfirmSwapWarningTypes.ROUTE_SWAPPERS_UPDATED
2144
- });
2145
- }
2146
- const balanceWarnings = getBalanceWarnings(confiremedRoute, selectedWallets);
2147
- const enoughBalance = balanceWarnings.length === 0;
2148
- if (!enoughBalance) confirmSwapState.errors.push({
2149
- type: ConfirmSwapErrorTypes.INSUFFICIENT_BALANCE,
2150
- 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
+ }
2151
1895
  });
2152
- const minRequiredSlippage = getMinRequiredSlippage(initialRoute);
2153
- if (!hasProperSlippage(userSlippage.toString(), minRequiredSlippage)) confirmSwapState.errors.push({
2154
- type: ConfirmSwapErrorTypes.INSUFFICIENT_SLIPPAGE,
2155
- 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
2156
1959
  });
2157
- const noErrors = confirmSwapState.errors.length === 0;
2158
- const noWarnings = confirmSwapState.warnings.length === 0;
2159
- if ((noErrors || !noErrors && proceedAnywayRef.current) && (noWarnings || !noWarnings && proceedAnywayRef.current)) {
2160
- const swapSettings = {
2161
- slippage: userSlippage.toString(),
2162
- disabledSwappersGroups: disabledLiquiditySources
2163
- };
2164
- const newSwap = calculatePendingSwap(inputAmount.toString(), confiremedRoute, getWalletsForNewSwap(selectedWallets), swapSettings, false, meta);
2165
- return newSwap;
2166
- } else if (!proceedAnywayRef.current) {
2167
- proceedAnywayRef.current = true;
2168
- setErrors(confirmSwapState.errors);
2169
- setWarnings(confirmSwapState.warnings);
2170
- confiremedRouteRef.current = confiremedRoute;
2171
- }
2172
- return;
2173
- } catch (error) {
2174
- if (error?.code === 'ERR_CANCELED') {
2175
- return;
2176
- }
2177
- const status = error?.response?.status;
2178
- setLoading(false);
2179
- setErrors([{
2180
- type: ConfirmSwapErrorTypes.REQUEST_FAILED,
2181
- status
2182
- }]);
2183
- return;
2184
1960
  }
2185
- };
2186
- return {
2187
- loading,
2188
- warnings,
2189
- errors,
2190
- confirmSwap
2191
- };
2192
- }
1961
+ });
1962
+ return result.sort((a, b) => Number(b.swap.creationTime) - Number(a.swap.creationTime));
1963
+ };
2193
1964
 
2194
- 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();
2195
1992
  const navigate = useNavigate();
2196
- return React.createElement(Button, {
2197
- type: "primary",
2198
- variant: "outlined",
2199
- size: "small",
2200
- onClick: () => navigate(navigationRoutes.settings)
2201
- }, "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
+ });
2202
2019
  }
2203
2020
 
2204
- const StyledMessage = /*#__PURE__*/styled(Typography, {
2205
- color: '$error500 !important'
2021
+ const Box$1 = /*#__PURE__*/styled('div', {
2022
+ display: 'flex',
2023
+ flexDirection: 'column',
2024
+ width: '100%',
2025
+ overflow: 'hidden'
2206
2026
  });
2207
- function MinRequiredSlippage(_ref) {
2208
- let {
2209
- minRequiredSlippage
2210
- } = _ref;
2211
- return React.createElement(StyledMessage, {
2212
- variant: "body2"
2213
- }, "We recommend you to increase slippage to at least \u00A0", minRequiredSlippage, "\u00A0 for this route.", React.createElement(Spacer, {
2214
- size: 8,
2215
- direction: "vertical"
2216
- }), React.createElement(ChangeSlippageButton, null));
2217
- }
2218
-
2219
- const List = /*#__PURE__*/styled('ul', {
2220
- padding: 0,
2221
- margin: 0,
2027
+ const Container$2 = /*#__PURE__*/styled('div', {
2028
+ boxSizing: 'border-box',
2029
+ borderRadius: '$5',
2030
+ padding: '$8 $16 $16 $16',
2222
2031
  variants: {
2223
- showListStyle: {
2224
- true: {
2225
- paddingLeft: '$24'
2032
+ type: {
2033
+ filled: {
2034
+ backgroundColor: '$neutrals300'
2035
+ },
2036
+ outlined: {
2037
+ border: '1px solid $neutrals300'
2226
2038
  }
2227
2039
  }
2228
- }
2229
- });
2230
- const ListItem = /*#__PURE__*/styled('li', {
2231
- variants: {
2232
- showListStyle: {
2233
- true: {
2234
- listStyleType: 'disc',
2235
- 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'
2236
2060
  }
2061
+ },
2062
+ '.amount': {
2063
+ width: '30%'
2064
+ }
2065
+ },
2066
+ '.output-usd': {
2067
+ display: 'flex',
2068
+ div: {
2069
+ display: 'flex',
2070
+ paddingLeft: '$8'
2237
2071
  }
2238
2072
  }
2239
2073
  });
2240
- const Message = /*#__PURE__*/styled(Typography, {
2241
- display: 'block'
2074
+ const Options = /*#__PURE__*/styled('div', {
2075
+ display: 'flex',
2076
+ justifyContent: 'flex-end',
2077
+ '.balance': {
2078
+ display: 'flex',
2079
+ alignItems: 'center'
2080
+ }
2242
2081
  });
2243
- function BalanceErrors(_ref) {
2244
- let {
2245
- messages
2246
- } = _ref;
2247
- const showListStyle = messages.length > 1;
2248
- return React.createElement(React.Fragment, null, React.createElement(Typography, {
2249
- className: "title",
2250
- variant: "title",
2251
- color: 'error'
2252
- }, "Insufficent Balance:"), React.createElement(Spacer, {
2253
- size: 8,
2254
- direction: "vertical"
2255
- }), React.createElement(List, {
2256
- showListStyle: showListStyle
2257
- }, messages.map(warning => React.createElement(ListItem, {
2258
- showListStyle: showListStyle
2259
- }, React.createElement(Message, {
2260
- variant: "body2"
2261
- }, warning)))));
2262
- }
2263
-
2264
- function ConfirmSwapErrors(errors) {
2265
- return errors.flatMap(error => {
2266
- switch (error.type) {
2267
- case ConfirmSwapErrorTypes.NO_ROUTE:
2268
- return 'No routes found. Please try again later.';
2269
- case ConfirmSwapErrorTypes.REQUEST_FAILED:
2270
- return `Failed to confirm swap ${error.status ? `'status': ${error.status})` : ''}, please try again.`;
2271
- case ConfirmSwapErrorTypes.ROUTE_UPDATED_WITH_HIGH_VALUE_LOSS:
2272
- return 'Route updated and price impact is too high, try again later!';
2273
- case ConfirmSwapErrorTypes.INSUFFICIENT_SLIPPAGE:
2274
- return React.createElement(MinRequiredSlippage, {
2275
- minRequiredSlippage: error.minRequiredSlippage
2276
- });
2277
- case ConfirmSwapErrorTypes.INSUFFICIENT_BALANCE:
2278
- return React.createElement(BalanceErrors, {
2279
- messages: error.messages
2280
- });
2281
- default:
2282
- return [];
2283
- }
2284
- });
2285
- }
2286
-
2287
- function ConfirmSwapWarnings(warnings) {
2288
- return warnings.flatMap(warning => {
2289
- switch (warning.type) {
2290
- case ConfirmSwapWarningTypes.ROUTE_UPDATED:
2291
- return "Route has been updated.";
2292
- case ConfirmSwapWarningTypes.ROUTE_AND_OUTPUT_AMOUNT_UPDATED:
2293
- return `Output amount changed to ${warning.newOutputAmount} (${warning.percentageChange}% change).`;
2294
- case ConfirmSwapWarningTypes.ROUTE_SWAPPERS_UPDATED:
2295
- return "Route swappers has been updated.";
2296
- case ConfirmSwapWarningTypes.ROUTE_COINS_UPDATED:
2297
- return "Route internal coins has been updated.";
2298
- default:
2299
- return [];
2300
- }
2301
- });
2302
- }
2303
-
2304
- function HighSlippageWarning(props) {
2305
- const {
2306
- selectedSlippage
2307
- } = props;
2308
- return React.createElement(Alert, {
2309
- type: "warning",
2310
- footer: React.createElement(ChangeSlippageButton, null)
2311
- }, "Caution, your slippage is high (=", selectedSlippage, "). Your trade may be front run.");
2312
- }
2313
-
2314
- 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) {
2315
2101
  const {
2316
- selectedSlippage
2102
+ type,
2103
+ chain,
2104
+ token
2317
2105
  } = props;
2318
- const highSlippage = selectedSlippage >= HIGH_SLIPPAGE;
2319
- return React.createElement(React.Fragment, null, highSlippage && React.createElement(HighSlippageWarning, {
2320
- selectedSlippage: selectedSlippage
2321
- }));
2322
- }
2323
-
2324
- function ConfirmSwapPage() {
2325
- const navigate = useNavigate();
2326
- const {
2327
- navigateBackFrom
2328
- } = useNavigateBack();
2329
- const bestRoute = useBestRouteStore.use.bestRoute();
2330
- const fetchingBestRoute = useBestRouteStore.use.loading();
2331
- const fetchingBestRouteError = useBestRouteStore.use.error();
2332
- const setSelectedSwap = useUiStore.use.setSelectedSwap();
2333
- const {
2334
- blockchains,
2335
- tokens
2336
- } = useMetaStore.use.meta();
2337
- const accounts = useWalletsStore.use.accounts();
2338
- const selectedWallets = useWalletsStore.use.selectedWallets();
2339
- const initSelectedWallets = useWalletsStore.use.initSelectedWallets();
2340
- const setSelectedWallet = useWalletsStore.use.setSelectedWallet();
2341
- const slippage = useSettingsStore.use.slippage();
2342
- const customSlippage = useSettingsStore.use.customSlippage();
2106
+ const loadingStatus = useMetaStore.use.loadingStatus();
2107
+ const fromChain = useBestRouteStore.use.fromChain();
2108
+ const toChain = useBestRouteStore.use.toChain();
2343
2109
  const inputUsdValue = useBestRouteStore.use.inputUsdValue();
2344
- const outputUsdValue = useBestRouteStore.use.outputUsdValue();
2110
+ const fromToken = useBestRouteStore.use.fromToken();
2345
2111
  const setInputAmount = useBestRouteStore.use.setInputAmount();
2346
- const bestRouteloadingStatus = getBestRouteStatus(fetchingBestRoute, !!fetchingBestRouteError);
2347
- const {
2348
- manager
2349
- } = useManager();
2350
- const {
2351
- loading,
2352
- errors,
2353
- warnings,
2354
- confirmSwap
2355
- } = useConfirmSwap();
2356
- const selectedSlippage = customSlippage || slippage;
2357
- 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();
2358
2117
  const {
2359
- getWalletInfo,
2360
- connect
2361
- } = useWallets();
2362
- const confirmDisabled = fetchingBestRoute || !requiredWallets(bestRoute).every(chain => selectedWallets.map(wallet => wallet.chain).includes(chain));
2363
- const firstStep = bestRoute?.result?.swaps[0];
2364
- const lastStep = bestRoute?.result?.swaps[bestRoute?.result?.swaps.length - 1];
2365
- const fromAmount = numberToString(firstStep?.fromAmount, 4, 6);
2366
- const toAmount = numberToString(lastStep?.toAmount, 4, 6);
2367
- useEffect(() => {
2368
- initSelectedWallets();
2369
- }, []);
2370
- const selectableWallets = getSelectableWallets(accounts, selectedWallets, getWalletInfo);
2371
- const handleConnectChain = wallet => {
2372
- const network = wallet;
2373
- getKeplrCompatibleConnectedWallets(selectableWallets).forEach(compatibleWallet => connect?.(compatibleWallet, network));
2374
- };
2375
- const totalFeeInUsd = getTotalFeeInUsd(bestRoute, tokens);
2376
- return React.createElement(ConfirmSwap, {
2377
- requiredWallets: getRequiredChains(bestRoute),
2378
- selectableWallets: selectableWallets,
2379
- onBack: navigateBackFrom.bind(null, navigationRoutes.confirmSwap),
2380
- onConfirm: () => {
2381
- confirmSwap?.().then(swap => {
2382
- if (swap) {
2383
- manager?.create('swap', {
2384
- swapDetails: swap
2385
- }, {
2386
- id: swap.requestId
2387
- });
2388
- setSelectedSwap(swap.requestId);
2389
- navigate(navigationRoutes.swaps + `/${swap.requestId}`, {
2390
- replace: true
2391
- });
2392
- setTimeout(() => {
2393
- setInputAmount('');
2394
- }, 0);
2395
- }
2396
- });
2397
- },
2398
- onChange: wallet => setSelectedWallet(wallet),
2399
- confirmDisabled: confirmDisabled,
2400
- handleConnectChain: wallet => handleConnectChain(wallet),
2401
- isExperimentalChain: wallet => getKeplrCompatibleConnectedWallets(selectableWallets).length > 0 ? isExperimentalChain(blockchains, wallet) : false,
2402
- previewInputs: React.createElement(React.Fragment, null, React.createElement(TokenPreview, {
2403
- chain: {
2404
- displayName: firstStep?.from.blockchain || '',
2405
- logo: firstStep?.from.blockchainLogo || ''
2406
- },
2407
- token: {
2408
- symbol: firstStep?.from.symbol || '',
2409
- image: firstStep?.from.logo || ''
2410
- },
2411
- usdValue: inputUsdValue,
2412
- amount: fromAmount,
2413
- label: t('From'),
2414
- loadingStatus: bestRouteloadingStatus
2415
- }), React.createElement(Spacer, {
2416
- size: 12,
2417
- direction: "vertical"
2418
- }), React.createElement(TokenPreview, {
2419
- chain: {
2420
- displayName: lastStep?.to.blockchain || '',
2421
- logo: lastStep?.to.blockchainLogo || ''
2422
- },
2423
- token: {
2424
- symbol: lastStep?.to.symbol || '',
2425
- image: lastStep?.to.logo || ''
2426
- },
2427
- usdValue: outputUsdValue,
2428
- amount: toAmount,
2429
- label: t('To'),
2430
- loadingStatus: bestRouteloadingStatus,
2431
- percentageChange: React.createElement(PercentageChange, {
2432
- inputUsdValue: inputUsdValue,
2433
- outputUsdValue: outputUsdValue
2434
- })
2435
- })),
2436
- previewRoutes: React.createElement(RoutesOverview, {
2437
- routes: bestRoute,
2438
- totalFee: numberToString(totalFeeInUsd, 0, 2)
2439
- }),
2440
- loading: loading,
2441
- errors: ConfirmSwapErrors(errors),
2442
- warnings: ConfirmSwapWarnings(warnings),
2443
- extraMessages: showHighSlippageWarning && React.createElement(ConfirmSwapExtraMessages, {
2444
- selectedSlippage: selectedSlippage
2445
- }),
2446
- confirmButtonTitle: warnings.length > 0 || errors.length > 0 ? 'Proceed anyway!' : 'Confirm swap!'
2447
- });
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`);
2167
+ },
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'))))));
2448
2226
  }
2449
2227
 
2450
- const getPendingSwaps = manager => {
2451
- const result = [];
2452
- manager?.getAll().forEach((q, id) => {
2453
- const storage = q.list.getStorage();
2454
- if (storage?.swapDetails) {
2455
- result.push({
2456
- id,
2457
- 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
+ })
2458
2303
  });
2304
+ } else {
2305
+ firstRender.current = false;
2459
2306
  }
2460
- });
2461
- return result.sort((a, b) => Number(b.swap.creationTime) - Number(a.swap.creationTime));
2462
- };
2307
+ }, [count]);
2308
+ return null;
2309
+ }
2463
2310
 
2464
- const groupSwapsByDate = swaps => {
2465
- const output = new Map([['today', {
2466
- title: 'Today',
2467
- swaps: []
2468
- }], ['week', {
2469
- title: 'This week',
2470
- swaps: []
2471
- }], ['month', {
2472
- title: 'This month',
2473
- swaps: []
2474
- }], ['year', {
2475
- title: 'This year',
2476
- swaps: []
2477
- }], ['history', {
2478
- title: 'History',
2479
- swaps: []
2480
- }]]);
2481
- const now = dayjs();
2482
- swaps.forEach(swap => {
2483
- const swapDate = dayjs(Number(swap.creationTime));
2484
- 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);
2485
- });
2486
- 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'
2487
2320
  };
2488
2321
 
2489
- function HistoryPage() {
2490
- const setSelectedSwap = useUiStore.use.setSelectedSwap();
2491
- const navigate = useNavigate();
2322
+ const ButtonsContainer = /*#__PURE__*/styled('div', {
2323
+ display: 'flex'
2324
+ });
2325
+ function HeaderButtons(props) {
2492
2326
  const {
2493
- navigateBackFrom
2494
- } = 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);
2495
2404
  const {
2496
- manager,
2497
- state
2498
- } = useManager();
2499
- const pendingSwaps = getPendingSwaps(manager).map(_ref => {
2500
- let {
2501
- swap
2502
- } = _ref;
2503
- return swap;
2504
- });
2505
- const loading = !state.loadedFromPersistor;
2506
- return React.createElement(History, {
2507
- list: pendingSwaps,
2508
- groupBy: groupSwapsByDate,
2509
- loading: loading,
2510
- onSwapClick: requestId => {
2511
- setSelectedSwap(requestId);
2512
- navigate(navigationRoutes.swaps + `/${requestId}`, {
2513
- replace: true
2514
- });
2515
- },
2516
- onBack: navigateBackFrom.bind(null, navigationRoutes.swaps)
2517
- });
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)));
2518
2473
  }
2519
2474
 
2520
2475
  function LiquiditySourcePage(_ref) {
@@ -2936,50 +2891,50 @@ function AppRoutes(props) {
2936
2891
  config
2937
2892
  } = props;
2938
2893
  return useRoutes([{
2939
- path: getAbsolutePath(navigationRoutes.home),
2894
+ path: navigationRoutes.home,
2940
2895
  element: React.createElement(Home, null)
2941
2896
  }, {
2942
- path: getAbsolutePath(navigationRoutes.fromChain),
2897
+ path: navigationRoutes.fromChain,
2943
2898
  element: React.createElement(SelectChainPage, {
2944
2899
  type: "from",
2945
2900
  supportedChains: config?.from?.blockchains
2946
2901
  })
2947
2902
  }, {
2948
- path: getAbsolutePath(navigationRoutes.toChain),
2903
+ path: navigationRoutes.toChain,
2949
2904
  element: React.createElement(SelectChainPage, {
2950
2905
  type: "to",
2951
2906
  supportedChains: config?.to?.blockchains
2952
2907
  })
2953
2908
  }, {
2954
- path: getAbsolutePath(navigationRoutes.fromToken),
2909
+ path: navigationRoutes.fromToken,
2955
2910
  element: React.createElement(SelectTokenPage, {
2956
2911
  type: "from",
2957
2912
  supportedTokens: config?.from?.tokens
2958
2913
  })
2959
2914
  }, {
2960
- path: getAbsolutePath(navigationRoutes.toToken),
2915
+ path: navigationRoutes.toToken,
2961
2916
  element: React.createElement(SelectTokenPage, {
2962
2917
  type: "to",
2963
2918
  supportedTokens: config?.to?.tokens
2964
2919
  })
2965
2920
  }, {
2966
- path: getAbsolutePath(navigationRoutes.settings),
2921
+ path: navigationRoutes.settings,
2967
2922
  element: React.createElement(SettingsPage, {
2968
2923
  supportedSwappers: config?.liquiditySources
2969
2924
  })
2970
2925
  }, {
2971
- path: getAbsolutePath(navigationRoutes.liquiditySources),
2926
+ path: navigationRoutes.liquiditySources,
2972
2927
  element: React.createElement(LiquiditySourcePage, {
2973
2928
  supportedSwappers: config?.liquiditySources
2974
2929
  })
2975
2930
  }, {
2976
- path: getAbsolutePath(navigationRoutes.swaps),
2931
+ path: navigationRoutes.swaps,
2977
2932
  element: React.createElement(HistoryPage, null)
2978
2933
  }, {
2979
2934
  path: navigationRoutes.swapDetails,
2980
2935
  element: React.createElement(SwapDetailsPage, null)
2981
2936
  }, {
2982
- path: getAbsolutePath(navigationRoutes.wallets),
2937
+ path: navigationRoutes.wallets,
2983
2938
  element: React.createElement(WalletsPage, {
2984
2939
  supportedWallets: config?.wallets,
2985
2940
  multiWallets: typeof config?.multiWallets === 'undefined' ? true : config.multiWallets