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