@lifi/widget 1.8.1 → 1.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/App.js +1 -1
  2. package/AppDrawer.js +8 -1
  3. package/AppDrawer.style.d.ts +5 -1
  4. package/AppDrawer.style.js +20 -3
  5. package/README.md +82 -6
  6. package/components/ReverseTokensButton/ReverseTokensButton.style.d.ts +1 -1
  7. package/components/StepActions/StepActions.js +5 -2
  8. package/components/SwapButton/SwapButton.d.ts +2 -1
  9. package/components/SwapButton/SwapButton.js +6 -15
  10. package/components/SwapButton/SwapButton.style.d.ts +1 -1
  11. package/components/SwapButton/types.d.ts +5 -0
  12. package/components/SwapButton/types.js +1 -0
  13. package/components/SwapInput/SwapInput.style.d.ts +1 -1
  14. package/components/SwapInput/SwapInputAdornment.style.d.ts +1 -1
  15. package/components/SwapRouteCard/SwapRouteCardSkeleton.d.ts +4 -0
  16. package/components/SwapRouteCard/SwapRouteCardSkeleton.js +32 -0
  17. package/components/SwapRouteCard/SwapRouteNotFoundCard.d.ts +4 -0
  18. package/components/SwapRouteCard/SwapRouteNotFoundCard.js +27 -0
  19. package/components/SwapRouteCard/index.d.ts +2 -0
  20. package/components/SwapRouteCard/index.js +2 -0
  21. package/components/SwapRouteCard/types.d.ts +5 -0
  22. package/components/SwapRoutes/SwapRoutes.js +7 -9
  23. package/config/lifi.d.ts +3 -0
  24. package/config/lifi.js +11 -0
  25. package/config/version.d.ts +1 -1
  26. package/config/version.js +1 -1
  27. package/hooks/useChains.js +1 -1
  28. package/hooks/useHasSufficientBalance.js +14 -6
  29. package/hooks/useRouteExecution.js +1 -1
  30. package/hooks/useSwapRoutes.d.ts +1 -0
  31. package/hooks/useSwapRoutes.js +8 -7
  32. package/hooks/useTokenBalance.js +1 -1
  33. package/hooks/useTokenBalances.js +1 -1
  34. package/hooks/useTokens.js +1 -1
  35. package/hooks/useTools.js +1 -1
  36. package/i18n/en/translation.json +12 -4
  37. package/i18n/index.d.ts +8 -0
  38. package/package.json +4 -4
  39. package/pages/MainPage/MainPage.js +2 -2
  40. package/pages/MainPage/MainSwapButton.d.ts +2 -0
  41. package/pages/MainPage/MainSwapButton.js +31 -0
  42. package/pages/SettingsPage/ColorSchemeButtonGroup.style.d.ts +1 -1
  43. package/pages/SwapPage/ExecutionItem.style.d.ts +1 -1
  44. package/pages/SwapPage/SwapPage.js +22 -5
  45. package/pages/SwapPage/SwapPage.style.d.ts +1 -1
  46. package/pages/SwapRoutesPage/SwapRoutesPage.js +12 -13
  47. package/providers/WidgetProvider/WidgetProvider.js +10 -2
  48. package/stores/route/useRouteStore.js +1 -1
  49. package/types/widget.d.ts +1 -0
  50. package/utils/format.js +3 -3
  51. package/lifi.d.ts +0 -2
  52. package/lifi.js +0 -7
package/App.js CHANGED
@@ -23,5 +23,5 @@ export const AppDefault = () => {
23
23
  attemptEagerConnect();
24
24
  // eslint-disable-next-line react-hooks/exhaustive-deps
25
25
  }, []);
26
- return (_jsxs(AppContainer, { children: [_jsx(Header, {}), _jsxs(Routes, { children: [_jsx(Route, { path: routes.home, element: _jsx(MainPage, {}) }), _jsx(Route, { path: routes.selectWallet, element: _jsx(SelectWalletPage, {}) }), _jsx(Route, { path: routes.settings, element: _jsx(SettingsPage, {}) }), _jsx(Route, { path: routes.fromToken, element: _jsx(SelectTokenPage, { formType: "from" }) }), _jsx(Route, { path: routes.toToken, element: _jsx(SelectTokenPage, { formType: "to" }) }), _jsx(Route, { path: routes.swapRoutes, element: _jsx(SwapRoutesPage, {}) }), _jsx(Route, { path: `${routes.swapRoutes}/${routes.swap}`, element: _jsx(SwapPage, {}) }), _jsx(Route, { path: routes.swap, element: _jsx(SwapPage, {}) }), _jsx(Route, { path: "*", element: _jsx(NotFound, {}) })] }), _jsx(Initializer, {})] }));
26
+ return (_jsxs(AppContainer, { children: [_jsx(Header, {}), _jsxs(Routes, { children: [_jsx(Route, { path: routes.home, element: _jsx(MainPage, {}) }), _jsx(Route, { path: routes.selectWallet, element: _jsx(SelectWalletPage, {}) }), _jsx(Route, { path: `${routes.swapRoutes}/${routes.swap}/${routes.selectWallet}`, element: _jsx(SelectWalletPage, {}) }), _jsx(Route, { path: routes.settings, element: _jsx(SettingsPage, {}) }), _jsx(Route, { path: routes.fromToken, element: _jsx(SelectTokenPage, { formType: "from" }) }), _jsx(Route, { path: routes.toToken, element: _jsx(SelectTokenPage, { formType: "to" }) }), _jsx(Route, { path: routes.swapRoutes, element: _jsx(SwapRoutesPage, {}) }), _jsx(Route, { path: `${routes.swapRoutes}/${routes.swap}`, element: _jsx(SwapPage, {}) }), _jsx(Route, { path: routes.swap, element: _jsx(SwapPage, {}) }), _jsx(Route, { path: "*", element: _jsx(NotFound, {}) })] }), _jsx(Initializer, {})] }));
27
27
  };
package/AppDrawer.js CHANGED
@@ -7,6 +7,7 @@ import { AppDefault } from './App';
7
7
  import { DrawerButton, DrawerButtonTypography } from './AppDrawer.style';
8
8
  import { AppProvider } from './AppProvider';
9
9
  export const AppDrawer = forwardRef(({ elementRef, open, config }, ref) => {
10
+ var _a, _b, _c, _d, _e, _f;
10
11
  const { t } = useTranslation();
11
12
  const openRef = useRef(open);
12
13
  const [drawerOpen, setDrawerOpen] = useState(open);
@@ -25,10 +26,16 @@ export const AppDrawer = forwardRef(({ elementRef, open, config }, ref) => {
25
26
  openDrawer,
26
27
  closeDrawer,
27
28
  }), [closeDrawer, openDrawer, toggleDrawer]);
28
- return (_jsxs(AppProvider, Object.assign({ config: config }, { children: [_jsxs(DrawerButton, Object.assign({ variant: "contained", onClick: toggleDrawer, open: drawerOpen, disableElevation: true }, { children: [drawerOpen ? _jsx(KeyboardArrowRightIcon, {}) : _jsx(KeyboardArrowLeftIcon, {}), _jsx(DrawerButtonTypography, { children: drawerOpen ? t('button.hide') : t('button.lifiSwap') })] })), _jsx(Drawer, Object.assign({ ref: elementRef, anchor: "right", open: drawerOpen, onClose: closeDrawer, BackdropProps: {
29
+ return (_jsxs(AppProvider, Object.assign({ config: config }, { children: [_jsxs(DrawerButton, Object.assign({ variant: "contained", onClick: toggleDrawer, open: drawerOpen, drawerProps: config === null || config === void 0 ? void 0 : config.containerStyle, disableElevation: true }, { children: [drawerOpen ? _jsx(KeyboardArrowRightIcon, {}) : _jsx(KeyboardArrowLeftIcon, {}), _jsx(DrawerButtonTypography, { children: drawerOpen ? t('button.hide') : t('button.lifiSwap') })] })), _jsx(Drawer, Object.assign({ ref: elementRef, anchor: "right", open: drawerOpen, onClose: closeDrawer, BackdropProps: {
29
30
  sx: {
30
31
  backgroundColor: 'rgb(0 0 0 / 48%)',
31
32
  backdropFilter: 'blur(3px)',
32
33
  },
34
+ }, PaperProps: {
35
+ sx: {
36
+ width: (_b = (_a = config === null || config === void 0 ? void 0 : config.containerStyle) === null || _a === void 0 ? void 0 : _a.width) !== null && _b !== void 0 ? _b : '100%',
37
+ minWidth: (_d = (_c = config === null || config === void 0 ? void 0 : config.containerStyle) === null || _c === void 0 ? void 0 : _c.minWidth) !== null && _d !== void 0 ? _d : 375,
38
+ maxWidth: (_f = (_e = config === null || config === void 0 ? void 0 : config.containerStyle) === null || _e === void 0 ? void 0 : _e.maxWidth) !== null && _f !== void 0 ? _f : 392,
39
+ },
33
40
  }, keepMounted: true }, { children: _jsx(AppDefault, {}) }))] })));
34
41
  });
@@ -2,7 +2,7 @@
2
2
  export declare const DrawerButton: import("@emotion/styled").StyledComponent<{
3
3
  children?: import("react").ReactNode;
4
4
  classes?: Partial<import("@mui/material").ButtonClasses> | undefined;
5
- color?: "inherit" | "success" | "warning" | "error" | "info" | "primary" | "secondary" | undefined;
5
+ color?: "inherit" | "success" | "info" | "warning" | "error" | "primary" | "secondary" | undefined;
6
6
  disabled?: boolean | undefined;
7
7
  disableElevation?: boolean | undefined;
8
8
  disableFocusRipple?: boolean | undefined;
@@ -33,6 +33,10 @@ export declare const DrawerButton: import("@emotion/styled").StyledComponent<{
33
33
  ref?: ((instance: HTMLButtonElement | null) => void) | import("react").RefObject<HTMLButtonElement> | null | undefined;
34
34
  }, keyof import("@mui/material/OverridableComponent").CommonProps | "tabIndex" | "color" | "children" | "action" | "centerRipple" | "disabled" | "disableRipple" | "disableTouchRipple" | "focusRipple" | "focusVisibleClassName" | "LinkComponent" | "onFocusVisible" | "sx" | "TouchRippleProps" | "touchRippleRef" | "href" | "disableElevation" | "disableFocusRipple" | "endIcon" | "fullWidth" | "size" | "startIcon" | "variant"> & import("@mui/system").MUIStyledCommonProps<import("@mui/material").Theme> & {
35
35
  open?: boolean | undefined;
36
+ drawerProps?: {
37
+ width?: string | number | undefined;
38
+ maxWidth?: string | number | undefined;
39
+ } | undefined;
36
40
  }, {}, {}>;
37
41
  export declare const DrawerButtonTypography: import("@emotion/styled").StyledComponent<import("@mui/system").SystemProps<import("@mui/material").Theme> & {
38
42
  align?: "inherit" | "left" | "right" | "center" | "justify" | undefined;
@@ -1,8 +1,23 @@
1
1
  import { Button, Typography } from '@mui/material';
2
2
  import { styled } from '@mui/material/styles';
3
+ const getButtonTransformWidth = (drawerWidth, drawerMaxWidth) => {
4
+ if (typeof drawerWidth === 'number') {
5
+ return `${drawerWidth}px`;
6
+ }
7
+ if (typeof drawerWidth === 'string' && !drawerWidth.includes('%')) {
8
+ return drawerWidth;
9
+ }
10
+ if (typeof drawerMaxWidth === 'number') {
11
+ return `${drawerMaxWidth}px`;
12
+ }
13
+ if (typeof drawerMaxWidth === 'string' && !drawerMaxWidth.includes('%')) {
14
+ return drawerMaxWidth;
15
+ }
16
+ return '392px';
17
+ };
3
18
  export const DrawerButton = styled(Button, {
4
- shouldForwardProp: (prop) => prop !== 'open',
5
- })(({ theme, open }) => ({
19
+ shouldForwardProp: (prop) => !['open', 'drawerProps'].includes(prop),
20
+ })(({ theme, open, drawerProps }) => ({
6
21
  background: theme.palette.mode === 'light'
7
22
  ? theme.palette.common.black
8
23
  : theme.palette.common.white,
@@ -20,7 +35,9 @@ export const DrawerButton = styled(Button, {
20
35
  position: 'absolute',
21
36
  right: 0,
22
37
  top: 'calc(50% - 74px)',
23
- transform: `translate3d(calc(${open ? '392px' : '0px'} * -1), 0, 0)`,
38
+ transform: `translate3d(calc(${open
39
+ ? getButtonTransformWidth(drawerProps === null || drawerProps === void 0 ? void 0 : drawerProps.width, drawerProps === null || drawerProps === void 0 ? void 0 : drawerProps.maxWidth)
40
+ : '0px'} * -1), 0, 0)`,
24
41
  transition: theme.transitions.create(['transform'], {
25
42
  duration: theme.transitions.duration.enteringScreen,
26
43
  easing: theme.transitions.easing.easeOut,
package/README.md CHANGED
@@ -1,19 +1,95 @@
1
- # @lifi/widget
1
+ <div align="center">
2
2
 
3
- LI.FI Widget for cross-chain bridging and swapping. It will drive your multi-chain strategy and attract new users from everywhere.
3
+ [![license](https://img.shields.io/badge/license-Apache%202-blue)](/LICENSE.md)
4
+ [![npm latest package](https://img.shields.io/npm/v/@lifi/widget/latest.svg)](https://www.npmjs.com/package/@lifi/widget)
5
+ [![npm downloads](https://img.shields.io/npm/dm/@lifi/widget.svg)](https://www.npmjs.com/package/@lifi/widget)
6
+ [![Average time to resolve an issue](https://isitmaintained.com/badge/resolution/lifinance/widget.svg)](https://isitmaintained.com/project/lifinance/widget)
7
+ [![Follow on Twitter](https://img.shields.io/twitter/follow/lifiprotocol.svg?label=follow+LI.FI)](https://twitter.com/lifiprotocol)
8
+
9
+ </div>
10
+
11
+ <h1 align="center">LI.FI Widget</h1>
12
+
13
+ This repository contains LI.FI Widget and supporting libraries.
14
+
15
+ - [_LI.FI Widget_](https://li.fi/widget/) for cross-chain bridging and swapping. It will drive your multi-chain strategy and attract new users from everywhere.
16
+
17
+ - [_LI.FI Wallet Management_](https://www.npmjs.com/package/@lifi/wallet-management) is our library of hooks that can help you gain complete control over your app's wallet management.
4
18
 
5
19
  ## Installation
6
20
 
7
- Install the package in your project directory with:
21
+ ### LI.FI Widget
22
+
23
+ LI.FI Widget is available as an [npm package](https://www.npmjs.com/package/@lifi/widget).
24
+
25
+ **npm:**
8
26
 
9
27
  ```sh
10
- // with npm
11
28
  npm install @lifi/widget
29
+ ```
12
30
 
13
- // with yarn
31
+ **yarn:**
32
+
33
+ ```sh
14
34
  yarn add @lifi/widget
15
35
  ```
16
36
 
37
+ ### LI.FI Wallet Management
38
+
39
+ LI.FI Wallet Management is available as an [npm package](https://www.npmjs.com/package/@lifi/wallet-management).
40
+
41
+ **npm:**
42
+
43
+ ```sh
44
+ npm install @lifi/wallet-management
45
+ ```
46
+
47
+ **yarn:**
48
+
49
+ ```sh
50
+ yarn add @lifi/wallet-management
51
+ ```
52
+
53
+ ## Getting started with LI.FI Widget
54
+
55
+ Here is an example of a basic app using LI.FI Widget:
56
+
57
+ ```jsx
58
+ import { LiFiWidget, WidgetConfig } from '@lifi/widget';
59
+ import { useMemo } from 'react';
60
+
61
+ export const WidgetPage = () => {
62
+ const widgetConfig: WidgetConfig = useMemo(() => {
63
+ return {
64
+ containerStyle: {
65
+ border: `1px solid ${
66
+ window.matchMedia('(prefers-color-scheme: dark)').matches
67
+ ? 'rgb(66, 66, 66)'
68
+ : 'rgb(234, 234, 234)'
69
+ }`,
70
+ borderRadius: '16px',
71
+ display: 'flex',
72
+ },
73
+ };
74
+ }, []);
75
+
76
+ return <LiFiWidget config={widgetConfig} />;
77
+ };
78
+ ```
79
+
80
+ ## Examples
81
+
82
+ Visit our [playground](https://testing.li.finance) to see how you can customize your [LI.FI Widget](https://www.npmjs.com/package/@lifi/widget) experience.
83
+
17
84
  ## Documentation
18
85
 
19
- [The documentation.](https://docs.li.fi/)
86
+ [LI.FI Documentation](https://docs.li.fi)
87
+
88
+ ## Changelog
89
+
90
+ The [changelog](/CHANGELOG.md) is regularly updated to reflect what's changed in each new release.
91
+
92
+ ## License
93
+
94
+ This project is licensed under the terms of the
95
+ [Apache-2.0](/LICENSE.md).
@@ -2,7 +2,7 @@
2
2
  export declare const IconButton: import("@emotion/styled").StyledComponent<{
3
3
  children?: import("react").ReactNode;
4
4
  classes?: Partial<import("@mui/material").IconButtonClasses> | undefined;
5
- color?: "inherit" | "default" | "success" | "warning" | "error" | "info" | "primary" | "secondary" | undefined;
5
+ color?: "inherit" | "default" | "success" | "info" | "warning" | "error" | "primary" | "secondary" | undefined;
6
6
  disabled?: boolean | undefined;
7
7
  disableFocusRipple?: boolean | undefined;
8
8
  edge?: false | "end" | "start" | undefined;
@@ -26,7 +26,7 @@ export const StepActions = (_a) => {
26
26
  const isFullView = !dense && ((_b = step.includedSteps) === null || _b === void 0 ? void 0 : _b.length) > 1;
27
27
  return (_jsxs(Box, Object.assign({}, other, { children: [_jsxs(Box, Object.assign({ sx: { display: 'flex', alignItems: 'center' }, mb: isFullView ? 1 : 0 }, { children: [_jsx(StepAvatar, Object.assign({ variant: step.type === 'lifi' ? 'square' : 'circular', src: step.type !== 'lifi' ? step.toolDetails.logoURI : undefined, alt: step.toolDetails.name }, { children: step.type === 'lifi' ? _jsx(LiFiLogo, {}) : step.toolDetails.name[0] })), _jsx(Typography, Object.assign({ ml: 2, fontSize: 18, fontWeight: "500", textTransform: "capitalize" }, { children: step.type === 'lifi'
28
28
  ? 'LI.FI Smart Contract'
29
- : step.toolDetails.name }))] })), isFullView ? (_jsx(Stepper, Object.assign({ orientation: "vertical", connector: _jsx(StepConnector, {}), activeStep: -1 }, { children: step.includedSteps.map((step) => (_jsxs(MuiStep, Object.assign({ expanded: true }, { children: [_jsx(StepLabel, Object.assign({ StepIconComponent: StepIcon }, { children: _jsx(StepDetailsLabel, { step: step }) })), _jsx(StepContent, { children: _jsx(StepDetailsContent, { step: step }) })] }), step.id))) }))) : (_jsxs(Box, Object.assign({ ml: 6 }, { children: [_jsx(StepDetailsLabel, { step: step }), _jsx(StepDetailsContent, { step: step })] })))] })));
29
+ : step.toolDetails.name }))] })), isFullView ? (_jsx(Stepper, Object.assign({ orientation: "vertical", connector: _jsx(StepConnector, {}), activeStep: -1 }, { children: step.includedSteps.map((step) => (_jsxs(MuiStep, Object.assign({ expanded: true }, { children: [_jsx(StepLabel, Object.assign({ StepIconComponent: StepIcon }, { children: step.type === 'cross' || step.type === 'lifi' ? (_jsx(CrossStepDetailsLabel, { step: step })) : (_jsx(SwapStepDetailsLabel, { step: step })) })), _jsx(StepContent, { children: _jsx(StepDetailsContent, { step: step }) })] }), step.id))) }))) : (_jsxs(Box, Object.assign({ ml: 6 }, { children: [_jsx(StepDetailsLabel, { step: step }), _jsx(StepDetailsContent, { step: step })] })))] })));
30
30
  };
31
31
  export const StepDetailsContent = ({ step }) => {
32
32
  return (_jsxs(Typography, Object.assign({ fontSize: 12, fontWeight: "500", color: "text.secondary", alignItems: "center", display: "flex" }, { children: [formatTokenAmount(step.estimate.fromAmount, step.action.fromToken.decimals), ' ', step.action.fromToken.symbol, _jsx(ArrowForwardIcon, { sx: { fontSize: 18, paddingX: 0.5 } }), formatTokenAmount(step.estimate.toAmount, step.action.toToken.decimals), ' ', step.action.toToken.symbol] })));
@@ -42,8 +42,11 @@ export const CrossStepDetailsLabel = ({ step }) => {
42
42
  }) })));
43
43
  };
44
44
  export const SwapStepDetailsLabel = ({ step }) => {
45
+ var _a;
45
46
  const { t } = useTranslation();
47
+ const { getChainById } = useChains();
46
48
  return (_jsx(Typography, Object.assign({ fontSize: 12, fontWeight: "500", color: "text.secondary" }, { children: t('swap.swapStepDetails', {
47
- value: step.toolDetails.name,
49
+ chain: (_a = getChainById(step.action.fromChainId)) === null || _a === void 0 ? void 0 : _a.name,
50
+ tool: step.toolDetails.name,
48
51
  }) })));
49
52
  };
@@ -1,2 +1,3 @@
1
1
  /// <reference types="react" />
2
- export declare const SwapButton: React.FC;
2
+ import { SwapButtonProps } from './types';
3
+ export declare const SwapButton: React.FC<SwapButtonProps>;
@@ -12,23 +12,19 @@ import { ChainId } from '@lifi/sdk';
12
12
  import { useWatch } from 'react-hook-form';
13
13
  import { useTranslation } from 'react-i18next';
14
14
  import { useNavigate } from 'react-router-dom';
15
- import { useChains, useHasSufficientBalance, useSwapRoutes } from '../../hooks';
15
+ import { useChains, useHasSufficientBalance } from '../../hooks';
16
16
  import { SwapFormKeyHelper } from '../../providers/SwapFormProvider';
17
17
  import { useWallet } from '../../providers/WalletProvider';
18
18
  import { useWidgetConfig } from '../../providers/WidgetProvider';
19
- import { useCurrentRoute, useSetExecutableRoute } from '../../stores';
20
19
  import { routes } from '../../utils/routes';
21
20
  import { Button } from './SwapButton.style';
22
- export const SwapButton = () => {
21
+ export const SwapButton = ({ onClick, text, loading, }) => {
23
22
  var _a;
24
23
  const navigate = useNavigate();
25
24
  const { t } = useTranslation();
26
25
  const { getChainById } = useChains();
27
26
  const config = useWidgetConfig();
28
27
  const { account, switchChain, connect: walletConnect } = useWallet();
29
- const [currentRoute] = useCurrentRoute();
30
- const setExecutableRoute = useSetExecutableRoute();
31
- const { routes: swapRoutes, isLoading, isFetching } = useSwapRoutes();
32
28
  const { hasGasOnStartChain, hasGasOnCrossChain, hasSufficientBalance } = useHasSufficientBalance();
33
29
  const [chainId] = useWatch({
34
30
  name: [SwapFormKeyHelper.getChainKey('from')],
@@ -47,12 +43,8 @@ export const SwapButton = () => {
47
43
  yield switchChain(chainId);
48
44
  // check that the current route exists in the up to date route list
49
45
  }
50
- else if (currentRoute &&
51
- (swapRoutes === null || swapRoutes === void 0 ? void 0 : swapRoutes.some((route) => route.id === currentRoute.id))) {
52
- setExecutableRoute(currentRoute);
53
- navigate(routes.swap, {
54
- state: { routeId: currentRoute.id },
55
- });
46
+ else {
47
+ onClick === null || onClick === void 0 ? void 0 : onClick();
56
48
  }
57
49
  });
58
50
  const getButtonText = () => {
@@ -60,7 +52,7 @@ export const SwapButton = () => {
60
52
  if (!isCurrentChainMatch) {
61
53
  return t(`button.switchChain`);
62
54
  }
63
- return t(`button.swap`);
55
+ return text || t(`button.swap`);
64
56
  }
65
57
  return t(`button.connectWallet`);
66
58
  };
@@ -69,7 +61,6 @@ export const SwapButton = () => {
69
61
  disabled: (!hasSufficientBalance ||
70
62
  !hasGasOnStartChain ||
71
63
  !hasGasOnCrossChain ||
72
- isLoading ||
73
- isFetching) &&
64
+ loading) &&
74
65
  isCurrentChainMatch }, { children: getButtonText() })));
75
66
  };
@@ -17,7 +17,7 @@ export declare const Button: import("@emotion/styled").StyledComponent<{
17
17
  } & Omit<{
18
18
  children?: import("react").ReactNode;
19
19
  classes?: Partial<import("@mui/material").ButtonClasses> | undefined;
20
- color?: "inherit" | "success" | "warning" | "error" | "info" | "primary" | "secondary" | undefined;
20
+ color?: "inherit" | "success" | "info" | "warning" | "error" | "primary" | "secondary" | undefined;
21
21
  disabled?: boolean | undefined;
22
22
  disableElevation?: boolean | undefined;
23
23
  disableFocusRipple?: boolean | undefined;
@@ -0,0 +1,5 @@
1
+ export interface SwapButtonProps {
2
+ onClick?(): void;
3
+ text?: string;
4
+ loading?: boolean;
5
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -4,7 +4,7 @@ export declare const minInputFontSize = 14;
4
4
  export declare const FormControl: import("@emotion/styled").StyledComponent<{
5
5
  children?: import("react").ReactNode;
6
6
  classes?: Partial<import("@mui/material").FormControlClasses> | undefined;
7
- color?: "success" | "warning" | "error" | "info" | "primary" | "secondary" | undefined;
7
+ color?: "success" | "info" | "warning" | "error" | "primary" | "secondary" | undefined;
8
8
  disabled?: boolean | undefined;
9
9
  error?: boolean | undefined;
10
10
  fullWidth?: boolean | undefined;
@@ -2,7 +2,7 @@
2
2
  export declare const Button: import("@emotion/styled").StyledComponent<{
3
3
  children?: import("react").ReactNode;
4
4
  classes?: Partial<import("@mui/material").ButtonClasses> | undefined;
5
- color?: "inherit" | "success" | "warning" | "error" | "info" | "primary" | "secondary" | undefined;
5
+ color?: "inherit" | "success" | "info" | "warning" | "error" | "primary" | "secondary" | undefined;
6
6
  disabled?: boolean | undefined;
7
7
  disableElevation?: boolean | undefined;
8
8
  disableFocusRipple?: boolean | undefined;
@@ -0,0 +1,4 @@
1
+ /// <reference types="react" />
2
+ import { BoxProps } from '@mui/material';
3
+ import { SwapRouteCardSkeletonProps } from './types';
4
+ export declare const SwapRouteCardSkeleton: React.FC<SwapRouteCardSkeletonProps & BoxProps>;
@@ -0,0 +1,32 @@
1
+ var __rest = (this && this.__rest) || function (s, e) {
2
+ var t = {};
3
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
4
+ t[p] = s[p];
5
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
6
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
7
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
8
+ t[p[i]] = s[p[i]];
9
+ }
10
+ return t;
11
+ };
12
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
13
+ import { Box, Skeleton } from '@mui/material';
14
+ import { Card } from './SwapRouteCard.style';
15
+ export const SwapRouteCardSkeleton = (_a) => {
16
+ var { active, dense } = _a, other = __rest(_a, ["active", "dense"]);
17
+ return (_jsxs(Card, Object.assign({ dense: dense }, other, { children: [_jsxs(Box, Object.assign({ sx: {
18
+ display: 'flex',
19
+ alignItems: 'center',
20
+ justifyContent: 'space-between',
21
+ } }, { children: [_jsx(Skeleton, { variant: "rectangular", width: 120, height: 24, sx: { borderRadius: 0.5 } }), active ? _jsx(Skeleton, { variant: "circular", width: 24, height: 24 }) : null] })), _jsxs(Box, Object.assign({ my: 2 }, { children: [_jsxs(Box, Object.assign({ sx: {
22
+ display: 'flex',
23
+ alignItems: 'center',
24
+ } }, { children: [_jsx(Box, Object.assign({ mr: 2 }, { children: _jsx(Skeleton, { variant: "circular", width: 32, height: 32 }) })), _jsx(Skeleton, { variant: "text", width: 96, height: 32 })] })), _jsx(Box, Object.assign({ ml: 6 }, { children: _jsx(Skeleton, { variant: "text", width: 56, height: 22 }) }))] })), _jsxs(Box, Object.assign({ sx: {
25
+ display: 'flex',
26
+ justifyContent: 'space-between',
27
+ } }, { children: [_jsxs(Box, { children: [_jsx(Skeleton, { variant: "text", width: 56, height: 22 }), _jsx(Skeleton, { variant: "text", width: 52, height: 15 })] }), _jsxs(Box, Object.assign({ sx: {
28
+ display: 'flex',
29
+ alignItems: 'flex-end',
30
+ flexDirection: 'column',
31
+ } }, { children: [_jsx(Skeleton, { variant: "text", width: 40, height: 22 }), _jsx(Skeleton, { variant: "text", width: 48, height: 15 })] }))] }))] })));
32
+ };
@@ -0,0 +1,4 @@
1
+ /// <reference types="react" />
2
+ import { BoxProps } from '@mui/material';
3
+ import { SwapRouteCardSkeletonProps } from './types';
4
+ export declare const SwapRouteNotFoundCard: React.FC<SwapRouteCardSkeletonProps & BoxProps>;
@@ -0,0 +1,27 @@
1
+ var __rest = (this && this.__rest) || function (s, e) {
2
+ var t = {};
3
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
4
+ t[p] = s[p];
5
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
6
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
7
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
8
+ t[p[i]] = s[p[i]];
9
+ }
10
+ return t;
11
+ };
12
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
13
+ import { Route as RouteIcon } from '@mui/icons-material';
14
+ import { Box, Typography } from '@mui/material';
15
+ import { useTranslation } from 'react-i18next';
16
+ import { Card } from './SwapRouteCard.style';
17
+ export const SwapRouteNotFoundCard = (_a) => {
18
+ var { active, dense } = _a, other = __rest(_a, ["active", "dense"]);
19
+ const { t } = useTranslation();
20
+ return (_jsx(Card, Object.assign({ active: active, dense: dense }, other, { children: _jsxs(Box, Object.assign({ sx: {
21
+ display: 'flex',
22
+ alignItems: 'center',
23
+ justifyContent: 'center',
24
+ flexDirection: 'column',
25
+ flex: 1,
26
+ }, py: 1.375 }, { children: [_jsx(RouteIcon, { fontSize: "large" }), _jsx(Typography, Object.assign({ fontSize: 16, fontWeight: "500", mt: 2 }, { children: t('swap.info.title.routeNotFound') })), _jsx(Typography, Object.assign({ fontSize: 14, color: "text.secondary", textAlign: "center", mt: 1 }, { children: t('swap.info.message.routeNotFound') }))] })) })));
27
+ };
@@ -1 +1,3 @@
1
1
  export * from './SwapRouteCard';
2
+ export * from './SwapRouteCardSkeleton';
3
+ export * from './SwapRouteNotFoundCard';
@@ -1 +1,3 @@
1
1
  export * from './SwapRouteCard';
2
+ export * from './SwapRouteCardSkeleton';
3
+ export * from './SwapRouteNotFoundCard';
@@ -5,3 +5,8 @@ export interface SwapRouteCardProps {
5
5
  active?: boolean;
6
6
  blur?: boolean;
7
7
  }
8
+ export interface SwapRouteCardSkeletonProps {
9
+ dense?: boolean;
10
+ active?: boolean;
11
+ blur?: boolean;
12
+ }
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  /* eslint-disable react/no-array-index-key */
3
3
  import { KeyboardArrowRight as KeyboardArrowRightIcon } from '@mui/icons-material';
4
- import { Box, IconButton, Skeleton } from '@mui/material';
4
+ import { Box, IconButton } from '@mui/material';
5
5
  import { useCallback } from 'react';
6
6
  import { useTranslation } from 'react-i18next';
7
7
  import { useNavigate } from 'react-router-dom';
@@ -9,26 +9,24 @@ import { useSwapRoutes } from '../../hooks';
9
9
  import { useCurrentRoute } from '../../stores';
10
10
  import { routes } from '../../utils/routes';
11
11
  import { CardContainer, CardTitle } from '../Card';
12
- import { SwapRouteCard } from '../SwapRouteCard';
12
+ import { SwapRouteCard, SwapRouteCardSkeleton, SwapRouteNotFoundCard, } from '../SwapRouteCard';
13
13
  import { Stack } from './SwapRoutes.style';
14
14
  import { SwapRoutesUpdateProgress } from './SwapRoutesUpdateProgress';
15
15
  export const SwapRoutes = (props) => {
16
16
  const { t } = useTranslation();
17
17
  const navigate = useNavigate();
18
18
  const [currentRoute] = useCurrentRoute();
19
- const { routes: swapRoutes, isLoading, isFetching } = useSwapRoutes();
19
+ const { routes: swapRoutes, isLoading, isFetching, isFetched, } = useSwapRoutes();
20
20
  const handleCardClick = useCallback(() => {
21
21
  navigate(routes.swapRoutes);
22
22
  }, [navigate]);
23
- if (!(swapRoutes === null || swapRoutes === void 0 ? void 0 : swapRoutes.length) && !isLoading && !isFetching) {
23
+ if (!(swapRoutes === null || swapRoutes === void 0 ? void 0 : swapRoutes.length) && !isLoading && !isFetching && !isFetched) {
24
24
  return null;
25
25
  }
26
- return (_jsxs(CardContainer, Object.assign({}, props, { children: [_jsx(CardTitle, { children: t('swap.routes') }), _jsx(SwapRoutesUpdateProgress, { sx: {
26
+ const routeNotFound = !(swapRoutes === null || swapRoutes === void 0 ? void 0 : swapRoutes.length) && isFetched;
27
+ return (_jsxs(CardContainer, Object.assign({}, props, { children: [_jsx(CardTitle, { children: t('swap.routes') }), !routeNotFound ? (_jsx(SwapRoutesUpdateProgress, { sx: {
27
28
  position: 'absolute',
28
29
  top: 8,
29
30
  right: 8,
30
- } }), _jsxs(Box, Object.assign({ sx: { display: 'flex', alignItems: 'center' } }, { children: [_jsx(Stack, Object.assign({ direction: "row", py: 2, pl: 2, pr: 1 }, { children: isLoading || isFetching || !currentRoute ? (_jsx(Skeleton, { variant: "rectangular", width: "100%", height: 181, sx: (theme) => ({
31
- borderRadius: theme.shape.borderRadiusSecondary / theme.shape.borderRadius,
32
- minWidth: '100%',
33
- }) })) : (_jsx(SwapRouteCard, { minWidth: "100%", route: currentRoute, active: true, dense: true })) })), _jsx(Box, Object.assign({ py: 1, pr: 1 }, { children: _jsx(IconButton, Object.assign({ onClick: handleCardClick, size: "medium", "aria-label": "swap-routes" }, { children: _jsx(KeyboardArrowRightIcon, {}) })) }))] }))] })));
31
+ } })) : null, _jsxs(Box, Object.assign({ sx: { display: 'flex', alignItems: 'center' } }, { children: [_jsx(Stack, Object.assign({ direction: "row", py: 2, pl: 2, pr: routeNotFound ? 2 : 1 }, { children: routeNotFound ? (_jsx(SwapRouteNotFoundCard, { minWidth: "100%", dense: true })) : isLoading || isFetching || !currentRoute ? (_jsx(SwapRouteCardSkeleton, { minWidth: "100%", active: true, dense: true })) : (_jsx(SwapRouteCard, { minWidth: "100%", route: currentRoute, active: true, dense: true })) })), !routeNotFound ? (_jsx(Box, Object.assign({ py: 1, pr: 1 }, { children: _jsx(IconButton, Object.assign({ onClick: handleCardClick, size: "medium", "aria-label": "swap-routes" }, { children: _jsx(KeyboardArrowRightIcon, {}) })) }))) : null] }))] })));
34
32
  };
@@ -0,0 +1,3 @@
1
+ import LIFI, { ConfigUpdate } from '@lifi/sdk';
2
+ export declare const LiFi: LIFI;
3
+ export declare const updateLiFiConfig: (configUpdate?: ConfigUpdate) => void;
package/config/lifi.js ADDED
@@ -0,0 +1,11 @@
1
+ import LIFI from '@lifi/sdk';
2
+ const defaultConfig = {
3
+ // apiUrl: env.LIFI_API_URL,
4
+ // defaultRouteOptions: {
5
+ // integrator: 'li.fi',
6
+ // },
7
+ };
8
+ export const LiFi = new LIFI(defaultConfig);
9
+ export const updateLiFiConfig = (configUpdate) => {
10
+ LiFi.setConfig(Object.assign(Object.assign({}, defaultConfig), configUpdate));
11
+ };
@@ -1,2 +1,2 @@
1
1
  export declare const name = "@lifi/widget";
2
- export declare const version = "1.8.1";
2
+ export declare const version = "1.10.1";
package/config/version.js CHANGED
@@ -1,2 +1,2 @@
1
1
  export const name = '@lifi/widget';
2
- export const version = '1.8.1';
2
+ export const version = '1.10.1';
@@ -20,7 +20,7 @@ var __rest = (this && this.__rest) || function (s, e) {
20
20
  };
21
21
  import { useCallback } from 'react';
22
22
  import { useQuery } from 'react-query';
23
- import { LiFi } from '../lifi';
23
+ import { LiFi } from '../config/lifi';
24
24
  import { useWidgetConfig } from '../providers/WidgetProvider';
25
25
  export const useChains = () => {
26
26
  const { disabledChains } = useWidgetConfig();
@@ -4,10 +4,12 @@ import { useMemo } from 'react';
4
4
  import { useWatch } from 'react-hook-form';
5
5
  import { useDebouncedWatch } from '.';
6
6
  import { SwapFormKey, SwapFormKeyHelper } from '../providers/SwapFormProvider';
7
+ import { useWallet } from '../providers/WalletProvider';
7
8
  import { useCurrentRoute } from '../stores';
8
9
  import { useTokenBalances } from './useTokenBalances';
9
10
  export const useHasSufficientBalance = () => {
10
11
  var _a;
12
+ const { account } = useWallet();
11
13
  const [route] = useCurrentRoute();
12
14
  const [fromChainId, toChainId, fromToken] = useWatch({
13
15
  name: [
@@ -23,7 +25,7 @@ export const useHasSufficientBalance = () => {
23
25
  const hasGasOnStartChain = useMemo(() => {
24
26
  var _a, _b, _c, _d, _e;
25
27
  const gasToken = (_a = route === null || route === void 0 ? void 0 : route.steps[0].estimate.gasCosts) === null || _a === void 0 ? void 0 : _a[0].token;
26
- if (!gasToken) {
28
+ if (!account.isActive || !gasToken) {
27
29
  return true;
28
30
  }
29
31
  const gasTokenBalance = Big((_c = (_b = fromChainTokenBalances === null || fromChainTokenBalances === void 0 ? void 0 : fromChainTokenBalances.find((t) => t.address === gasToken.address)) === null || _b === void 0 ? void 0 : _b.amount) !== null && _c !== void 0 ? _c : 0);
@@ -36,26 +38,32 @@ export const useHasSufficientBalance = () => {
36
38
  requiredAmount = requiredAmount.plus(tokenBalance);
37
39
  }
38
40
  return gasTokenBalance.gt(0) && gasTokenBalance.gte(requiredAmount);
39
- }, [fromChainTokenBalances, route]);
41
+ }, [
42
+ account.isActive,
43
+ fromChainTokenBalances,
44
+ route === null || route === void 0 ? void 0 : route.fromChainId,
45
+ route === null || route === void 0 ? void 0 : route.fromToken.address,
46
+ route === null || route === void 0 ? void 0 : route.steps,
47
+ ]);
40
48
  const hasGasOnCrossChain = useMemo(() => {
41
49
  var _a, _b, _c, _d, _e, _f;
42
50
  const gasToken = (_a = lastStep === null || lastStep === void 0 ? void 0 : lastStep.estimate.gasCosts) === null || _a === void 0 ? void 0 : _a[0].token;
43
- if (!gasToken || !isSwapStep(lastStep)) {
51
+ if (!account.isActive || !gasToken || !isSwapStep(lastStep)) {
44
52
  return true;
45
53
  }
46
54
  const balance = Big((_c = (_b = toChainTokenBalances === null || toChainTokenBalances === void 0 ? void 0 : toChainTokenBalances.find((t) => t.address === gasToken.address)) === null || _b === void 0 ? void 0 : _b.amount) !== null && _c !== void 0 ? _c : 0);
47
55
  const gasEstimate = (_d = lastStep.estimate.gasCosts) === null || _d === void 0 ? void 0 : _d[0].amount;
48
56
  const requiredAmount = Big(gasEstimate || 0).div(Math.pow(10, ((_f = (_e = lastStep.estimate.gasCosts) === null || _e === void 0 ? void 0 : _e[0].token.decimals) !== null && _f !== void 0 ? _f : 0)));
49
57
  return balance.gt(0) && balance.gte(requiredAmount);
50
- }, [lastStep, toChainTokenBalances]);
58
+ }, [account.isActive, lastStep, toChainTokenBalances]);
51
59
  const hasSufficientBalance = useMemo(() => {
52
60
  var _a, _b;
53
- if (!fromToken || !fromAmount) {
61
+ if (!account.isActive || !fromToken || !fromAmount) {
54
62
  return true;
55
63
  }
56
64
  const balance = Big((_b = (_a = fromChainTokenBalances === null || fromChainTokenBalances === void 0 ? void 0 : fromChainTokenBalances.find((t) => t.address === fromToken)) === null || _a === void 0 ? void 0 : _a.amount) !== null && _b !== void 0 ? _b : 0);
57
65
  return Big(fromAmount).lte(balance);
58
- }, [fromAmount, fromChainTokenBalances, fromToken]);
66
+ }, [account.isActive, fromAmount, fromChainTokenBalances, fromToken]);
59
67
  return {
60
68
  hasGasOnStartChain,
61
69
  hasGasOnCrossChain,
@@ -10,7 +10,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  import { useCallback, useEffect, useRef } from 'react';
11
11
  import { useMutation } from 'react-query';
12
12
  import shallow from 'zustand/shallow';
13
- import { LiFi } from '../lifi';
13
+ import { LiFi } from '../config/lifi';
14
14
  import { useWallet } from '../providers/WalletProvider';
15
15
  import { useRouteStore } from '../stores';
16
16
  import { deepClone } from '../utils/deepClone';
@@ -2,6 +2,7 @@ export declare const useSwapRoutes: () => {
2
2
  routes: import("@lifi/types").Route[] | undefined;
3
3
  isLoading: boolean;
4
4
  isFetching: boolean;
5
+ isFetched: boolean;
5
6
  dataUpdatedAt: number;
6
7
  refetchTime: number;
7
8
  refetch: <TPageData>(options?: (import("react-query").RefetchOptions & import("react-query").RefetchQueryFilters<TPageData>) | undefined) => Promise<import("react-query").QueryObserverResult<import("@lifi/types").RoutesResponse, unknown>>;
@@ -7,11 +7,12 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
7
7
  step((generator = generator.apply(thisArg, _arguments || [])).next());
8
8
  });
9
9
  };
10
+ import Big from 'big.js';
10
11
  import { useEffect } from 'react';
11
12
  import { useWatch } from 'react-hook-form';
12
13
  import { useQuery, useQueryClient } from 'react-query';
13
14
  import { useDebouncedWatch, useToken } from '.';
14
- import { LiFi } from '../lifi';
15
+ import { LiFi } from '../config/lifi';
15
16
  import { SwapFormKey } from '../providers/SwapFormProvider';
16
17
  import { useWallet } from '../providers/WalletProvider';
17
18
  import { useCurrentRoute, useSettings } from '../stores';
@@ -37,8 +38,9 @@ export const useSwapRoutes = () => {
37
38
  });
38
39
  const [fromTokenAmount] = useDebouncedWatch([SwapFormKey.FromAmount], 250);
39
40
  const { token } = useToken(fromChainId, fromTokenAddress);
40
- const isEnabled = Boolean(account.address) &&
41
- !isNaN(fromChainId) &&
41
+ const isEnabled =
42
+ // Boolean(account.address) &&
43
+ !isNaN(fromChainId) &&
42
44
  !isNaN(toChainId) &&
43
45
  Boolean(fromTokenAddress) &&
44
46
  Boolean(toTokenAddress) &&
@@ -62,13 +64,11 @@ export const useSwapRoutes = () => {
62
64
  const refetchInterval = previousDataUpdatedAt
63
65
  ? Math.min(Math.abs(refetchTime - (Date.now() - previousDataUpdatedAt)), refetchTime)
64
66
  : refetchTime;
65
- const { data, isLoading, isFetching, dataUpdatedAt, refetch } = useQuery(queryKey, ({ queryKey: [_, address, fromChainId, fromTokenAddress, fromTokenAmount, toChainId, toTokenAddress, slippage, enabledBridges, enabledExchanges, routePriority,], signal, }) => __awaiter(void 0, void 0, void 0, function* () {
67
+ const { data, isLoading, isFetching, isFetched, dataUpdatedAt, refetch } = useQuery(queryKey, ({ queryKey: [_, address, fromChainId, fromTokenAddress, fromTokenAmount, toChainId, toTokenAddress, slippage, enabledBridges, enabledExchanges, routePriority,], signal, }) => __awaiter(void 0, void 0, void 0, function* () {
66
68
  var _b;
67
69
  return LiFi.getRoutes({
68
70
  fromChainId,
69
- // TODO: simplify
70
- fromAmount: (Number(fromTokenAmount) *
71
- Math.pow(10, ((_b = token === null || token === void 0 ? void 0 : token.decimals) !== null && _b !== void 0 ? _b : 0))).toFixed(0),
71
+ fromAmount: Big(Number(fromTokenAmount) * Math.pow(10, ((_b = token === null || token === void 0 ? void 0 : token.decimals) !== null && _b !== void 0 ? _b : 0))).toString(),
72
72
  fromTokenAddress,
73
73
  toChainId,
74
74
  toTokenAddress,
@@ -105,6 +105,7 @@ export const useSwapRoutes = () => {
105
105
  routes: data === null || data === void 0 ? void 0 : data.routes,
106
106
  isLoading: isEnabled && isLoading,
107
107
  isFetching,
108
+ isFetched,
108
109
  dataUpdatedAt,
109
110
  refetchTime,
110
111
  refetch,
@@ -9,7 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  };
10
10
  import { useCallback } from 'react';
11
11
  import { useQuery, useQueryClient } from 'react-query';
12
- import { LiFi } from '../lifi';
12
+ import { LiFi } from '../config/lifi';
13
13
  import { useWallet } from '../providers/WalletProvider';
14
14
  import { formatTokenAmount } from '../utils/format';
15
15
  import { useToken } from './useToken';
@@ -8,7 +8,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  });
9
9
  };
10
10
  import { useQuery } from 'react-query';
11
- import { LiFi } from '../lifi';
11
+ import { LiFi } from '../config/lifi';
12
12
  import { useWallet } from '../providers/WalletProvider';
13
13
  import { formatTokenAmount } from '../utils/format';
14
14
  import { useChains } from './useChains';
@@ -8,7 +8,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  });
9
9
  };
10
10
  import { useQuery } from 'react-query';
11
- import { LiFi } from '../lifi';
11
+ import { LiFi } from '../config/lifi';
12
12
  export const useTokens = (selectedChainId) => {
13
13
  const { data: tokens, isLoading, isFetching, } = useQuery(['tokens', selectedChainId], () => __awaiter(void 0, void 0, void 0, function* () {
14
14
  var _a;
package/hooks/useTools.js CHANGED
@@ -1,6 +1,6 @@
1
1
  /* eslint-disable no-underscore-dangle */
2
2
  import { useQuery } from 'react-query';
3
- import { LiFi } from '../lifi';
3
+ import { LiFi } from '../config/lifi';
4
4
  import { useSettingsStore } from '../stores';
5
5
  export const useTools = () => {
6
6
  const initializeTools = useSettingsStore((state) => state.initializeTools);
@@ -52,7 +52,7 @@
52
52
  "estimatedTime": "~{{value}} min.",
53
53
  "networkIsBusy": "Network is busy...",
54
54
  "crossStepDetails": "Bridge {{from}} to {{to}} via {{tool}}",
55
- "swapStepDetails": "Swap on {{value}}",
55
+ "swapStepDetails": "Swap on {{chain}} via {{tool}}",
56
56
  "tags": {
57
57
  "recommended": "Recommended",
58
58
  "fastest": "Fast",
@@ -68,14 +68,22 @@
68
68
  "fundsReceived": "You now have {{amount}} {{tokenSymbol}} in your wallet on {{chainName}} chain."
69
69
  }
70
70
  },
71
+ "info": {
72
+ "title": {
73
+ "routeNotFound": "No routes available"
74
+ },
75
+ "message": {
76
+ "routeNotFound": "Try another \"from\" and \"to\" token combination."
77
+ }
78
+ },
71
79
  "warning": {
72
80
  "title": {
73
81
  "insufficientGas": "Insufficient gas"
74
82
  },
75
83
  "message": {
76
- "insufficientFunds": "You don't have enough funds for this transaction on the start from chain.",
77
- "insufficientGasOnStartChain": "You need to have enough gas to pay for this transaction on the start from chain.",
78
- "insufficientGasOnDestinationChain": "You need to have enough gas to pay for this transaction on the destination to chain."
84
+ "insufficientFunds": "You don't have enough funds for this transaction on the start \"from\" chain.",
85
+ "insufficientGasOnStartChain": "You need to have enough gas to pay for this transaction on the start \"from\" chain.",
86
+ "insufficientGasOnDestinationChain": "You need to have enough gas to pay for this transaction on the destination \"to\" chain."
79
87
  }
80
88
  },
81
89
  "error": {
package/i18n/index.d.ts CHANGED
@@ -71,6 +71,14 @@ export declare const resources: {
71
71
  fundsReceived: string;
72
72
  };
73
73
  };
74
+ info: {
75
+ title: {
76
+ routeNotFound: string;
77
+ };
78
+ message: {
79
+ routeNotFound: string;
80
+ };
81
+ };
74
82
  warning: {
75
83
  title: {
76
84
  insufficientGas: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lifi/widget",
3
- "version": "1.8.1",
3
+ "version": "1.10.1",
4
4
  "description": "LI.FI Widget for cross-chain bridging and swapping. It will drive your multi-chain strategy and attract new users from everywhere.",
5
5
  "sideEffects": false,
6
6
  "main": "./index.js",
@@ -41,7 +41,7 @@
41
41
  "@emotion/styled": "^11.9.3",
42
42
  "@ethersproject/experimental": "^5.6.3",
43
43
  "@ethersproject/providers": "^5.6.8",
44
- "@lifi/sdk": "^1.0.0",
44
+ "@lifi/sdk": "^1.0.2",
45
45
  "@lifi/wallet-management": "^1.1.1",
46
46
  "@mui/icons-material": "^5.8.4",
47
47
  "@mui/lab": "^5.0.0-alpha.90",
@@ -50,12 +50,12 @@
50
50
  "@sentry/react": "^7.6.0",
51
51
  "@sentry/tracing": "^7.6.0",
52
52
  "big.js": "^6.2.1",
53
- "i18next": "^21.8.13",
53
+ "i18next": "^21.8.14",
54
54
  "immer": "^9.0.15",
55
55
  "react": "^18.2.0",
56
56
  "react-dom": "^18.2.0",
57
57
  "react-hook-form": "^7.33.1",
58
- "react-i18next": "^11.18.0",
58
+ "react-i18next": "^11.18.1",
59
59
  "react-query": "^4.0.0-beta.23",
60
60
  "react-resize-detector": "^7.1.2",
61
61
  "react-router-dom": "^6.3.0",
@@ -2,11 +2,11 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Box } from '@mui/material';
3
3
  import { InsufficientGasOrFundsMessage } from '../../components/InsufficientGasOrFundsMessage';
4
4
  import { SelectChainAndToken } from '../../components/SelectChainAndToken';
5
- import { SwapButton } from '../../components/SwapButton';
6
5
  import { SwapInProgress } from '../../components/SwapInProgress';
7
6
  import { SwapInput } from '../../components/SwapInput';
8
7
  import { SwapRoutes } from '../../components/SwapRoutes';
9
8
  import { FormContainer } from './MainPage.style';
9
+ import { MainSwapButton } from './MainSwapButton';
10
10
  export const MainPage = () => {
11
- return (_jsxs(FormContainer, Object.assign({ disableGutters: true }, { children: [_jsx(SwapInProgress, { mx: 3, mt: 2, mb: 1 }), _jsx(SelectChainAndToken, { mt: 2, mx: 3, mb: 3 }), _jsx(Box, Object.assign({ mx: 3, mb: 3 }, { children: _jsx(SwapInput, { formType: "from" }) })), _jsx(SwapRoutes, { mx: 3, mb: 3 }), _jsx(InsufficientGasOrFundsMessage, { mx: 3, mb: 3 }), _jsx(Box, Object.assign({ mx: 3, mb: 1 }, { children: _jsx(SwapButton, {}) }))] })));
11
+ return (_jsxs(FormContainer, Object.assign({ disableGutters: true }, { children: [_jsx(SwapInProgress, { mx: 3, mt: 2, mb: 1 }), _jsx(SelectChainAndToken, { mt: 2, mx: 3, mb: 3 }), _jsx(Box, Object.assign({ mx: 3, mb: 3 }, { children: _jsx(SwapInput, { formType: "from" }) })), _jsx(SwapRoutes, { mx: 3, mb: 3 }), _jsx(InsufficientGasOrFundsMessage, { mx: 3, mb: 3 }), _jsx(Box, Object.assign({ mx: 3, mb: 1 }, { children: _jsx(MainSwapButton, {}) }))] })));
12
12
  };
@@ -0,0 +1,2 @@
1
+ /// <reference types="react" />
2
+ export declare const MainSwapButton: React.FC;
@@ -0,0 +1,31 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { jsx as _jsx } from "react/jsx-runtime";
11
+ import { useNavigate } from 'react-router-dom';
12
+ import { SwapButton } from '../../components/SwapButton';
13
+ import { useSwapRoutes } from '../../hooks';
14
+ import { useCurrentRoute, useSetExecutableRoute } from '../../stores';
15
+ import { routes } from '../../utils/routes';
16
+ export const MainSwapButton = () => {
17
+ const navigate = useNavigate();
18
+ const [currentRoute] = useCurrentRoute();
19
+ const setExecutableRoute = useSetExecutableRoute();
20
+ const { routes: swapRoutes, isLoading, isFetching } = useSwapRoutes();
21
+ const handleClick = () => __awaiter(void 0, void 0, void 0, function* () {
22
+ if (currentRoute &&
23
+ (swapRoutes === null || swapRoutes === void 0 ? void 0 : swapRoutes.some((route) => route.id === currentRoute.id))) {
24
+ setExecutableRoute(currentRoute);
25
+ navigate(routes.swap, {
26
+ state: { routeId: currentRoute.id },
27
+ });
28
+ }
29
+ });
30
+ return _jsx(SwapButton, { onClick: handleClick, loading: isLoading || isFetching });
31
+ };
@@ -2,7 +2,7 @@
2
2
  export declare const ToggleButton: import("@emotion/styled").StyledComponent<{
3
3
  children?: import("react").ReactNode;
4
4
  classes?: Partial<import("@mui/material").ToggleButtonClasses> | undefined;
5
- color?: "success" | "warning" | "error" | "info" | "primary" | "secondary" | "standard" | undefined;
5
+ color?: "success" | "info" | "warning" | "error" | "primary" | "secondary" | "standard" | undefined;
6
6
  disabled?: boolean | undefined;
7
7
  disableFocusRipple?: boolean | undefined;
8
8
  fullWidth?: boolean | undefined;
@@ -2,7 +2,7 @@
2
2
  export declare const LinkButton: import("@emotion/styled").StyledComponent<{
3
3
  children?: import("react").ReactNode;
4
4
  classes?: Partial<import("@mui/material").IconButtonClasses> | undefined;
5
- color?: "inherit" | "default" | "success" | "warning" | "error" | "info" | "primary" | "secondary" | undefined;
5
+ color?: "inherit" | "default" | "success" | "info" | "warning" | "error" | "primary" | "secondary" | undefined;
6
6
  disabled?: boolean | undefined;
7
7
  disableFocusRipple?: boolean | undefined;
8
8
  edge?: false | "end" | "start" | undefined;
@@ -1,9 +1,11 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Box } from '@mui/material';
2
3
  import { Fragment } from 'react';
3
4
  import { useTranslation } from 'react-i18next';
4
5
  import { useLocation, useNavigate } from 'react-router-dom';
5
6
  import { InsufficientGasOrFundsMessage } from '../../components/InsufficientGasOrFundsMessage';
6
- import { useHasSufficientBalance, useRouteExecution } from '../../hooks';
7
+ import { SwapButton } from '../../components/SwapButton';
8
+ import { useRouteExecution } from '../../hooks';
7
9
  import { StatusBottomSheet } from './StatusBottomSheet';
8
10
  import { StepDivider } from './StepDivider';
9
11
  import { StepItem } from './StepItem';
@@ -12,14 +14,29 @@ export const SwapPage = () => {
12
14
  const { t } = useTranslation();
13
15
  const { state } = useLocation();
14
16
  const navigate = useNavigate();
15
- const { hasGasOnStartChain, hasGasOnCrossChain, hasSufficientBalance } = useHasSufficientBalance();
16
17
  const { route, status, executeRoute, restartRoute, removeRoute } = useRouteExecution(state.routeId);
17
18
  const handleRemoveRoute = () => {
18
19
  removeRoute();
19
20
  navigate(-1);
20
21
  };
21
- const isDisabled = !hasSufficientBalance || !hasGasOnStartChain || !hasGasOnCrossChain;
22
+ const handleSwapClick = () => {
23
+ if (status === 'idle') {
24
+ executeRoute();
25
+ }
26
+ if (status === 'error') {
27
+ restartRoute();
28
+ }
29
+ };
30
+ // eslint-disable-next-line consistent-return
31
+ const getSwapButtonText = () => {
32
+ if (status === 'idle') {
33
+ return t('button.startSwap');
34
+ }
35
+ if (status === 'error') {
36
+ return t('button.restartSwap');
37
+ }
38
+ };
22
39
  return (_jsxs(Container, { children: [route === null || route === void 0 ? void 0 : route.steps.map((step, index, steps) => (_jsxs(Fragment, { children: [_jsx(StepItem, { step: step, fromToken: index === 0
23
40
  ? Object.assign(Object.assign({}, route.fromToken), { amount: route.fromAmount }) : undefined, toToken: index === steps.length - 1
24
- ? Object.assign(Object.assign({}, route.toToken), { amount: route.toAmount }) : undefined }), steps.length > 1 && index !== steps.length - 1 ? (_jsx(StepDivider, {})) : null] }, step.id))), _jsx(InsufficientGasOrFundsMessage, { mt: 2 }), status === 'idle' ? (_jsx(Button, Object.assign({ variant: "contained", disableElevation: true, fullWidth: true, onClick: executeRoute, disabled: isDisabled }, { children: t('button.startSwap') }))) : null, status === 'error' ? (_jsxs(_Fragment, { children: [_jsx(Button, Object.assign({ variant: "contained", disableElevation: true, fullWidth: true, onClick: restartRoute, disabled: isDisabled }, { children: t('button.restartSwap') })), _jsx(Button, Object.assign({ variant: "outlined", disableElevation: true, fullWidth: true, onClick: handleRemoveRoute, disabled: isDisabled }, { children: t('button.removeSwap') }))] })) : null, _jsx(StatusBottomSheet, { status: status, route: route })] }));
41
+ ? Object.assign(Object.assign({}, route.toToken), { amount: route.toAmount }) : undefined }), steps.length > 1 && index !== steps.length - 1 ? (_jsx(StepDivider, {})) : null] }, step.id))), _jsx(InsufficientGasOrFundsMessage, { mt: 2 }), status === 'idle' || status === 'error' ? (_jsx(Box, Object.assign({ mt: 2 }, { children: _jsx(SwapButton, { onClick: handleSwapClick, text: getSwapButtonText() }) }))) : null, status === 'error' ? (_jsx(Button, Object.assign({ variant: "outlined", disableElevation: true, fullWidth: true, onClick: handleRemoveRoute }, { children: t('button.removeSwap') }))) : null, _jsx(StatusBottomSheet, { status: status, route: route })] }));
25
42
  };
@@ -12,7 +12,7 @@ export declare const Container: import("@emotion/styled").StyledComponent<{
12
12
  export declare const Button: import("@emotion/styled").StyledComponent<{
13
13
  children?: import("react").ReactNode;
14
14
  classes?: Partial<import("@mui/material").ButtonClasses> | undefined;
15
- color?: "inherit" | "success" | "warning" | "error" | "info" | "primary" | "secondary" | undefined;
15
+ color?: "inherit" | "success" | "info" | "warning" | "error" | "primary" | "secondary" | undefined;
16
16
  disabled?: boolean | undefined;
17
17
  disableElevation?: boolean | undefined;
18
18
  disableFocusRipple?: boolean | undefined;
@@ -1,28 +1,27 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import { Skeleton } from '@mui/material';
2
+ import { useEffect } from 'react';
3
3
  import { useNavigate } from 'react-router-dom';
4
- import { SwapRouteCard } from '../../components/SwapRouteCard';
4
+ import { SwapRouteCard, SwapRouteCardSkeleton, SwapRouteNotFoundCard, } from '../../components/SwapRouteCard';
5
5
  import { useSwapRoutes } from '../../hooks';
6
6
  import { useCurrentRoute, useSetExecutableRoute } from '../../stores';
7
7
  import { routes } from '../../utils/routes';
8
8
  import { Stack } from './SwapRoutesPage.style';
9
9
  export const SwapRoutesPage = () => {
10
10
  const navigate = useNavigate();
11
- const { routes: swapRoutes, isLoading, isFetching } = useSwapRoutes();
11
+ const { routes: swapRoutes, isLoading, isFetching, isFetched, } = useSwapRoutes();
12
12
  const [currentRoute] = useCurrentRoute();
13
13
  const setExecutableRoute = useSetExecutableRoute();
14
- if (!(swapRoutes === null || swapRoutes === void 0 ? void 0 : swapRoutes.length) && !isLoading && !isFetching) {
15
- // TODO: make no routes message
16
- return null;
17
- }
18
14
  const handleRouteClick = (route) => {
19
15
  setExecutableRoute(route);
20
16
  navigate(routes.swap, { state: { routeId: route.id }, replace: true });
21
17
  };
22
- // A route for this transaction does not exist yet possibly due to liquidity issues or because the amount of tokens you are sending is below the bridge minimum amount.
23
- // Please try again later or change the tokens you intend to swap.
24
- // If the problem persists, come to our Discord and leave a message in the support channel.
25
- return (_jsx(Stack, Object.assign({ direction: "column", spacing: 2 }, { children: isLoading || isFetching
26
- ? Array.from({ length: 3 }).map((_, index) => (_jsx(Skeleton, { variant: "rectangular", width: "100%", height: 196, sx: { borderRadius: 1 } }, index)))
27
- : swapRoutes === null || swapRoutes === void 0 ? void 0 : swapRoutes.map((route, index) => (_jsx(SwapRouteCard, { route: route, active: (currentRoute === null || currentRoute === void 0 ? void 0 : currentRoute.id) === route.id, onClick: () => handleRouteClick(route) }, route.id))) })));
18
+ useEffect(() => {
19
+ if (!(swapRoutes === null || swapRoutes === void 0 ? void 0 : swapRoutes.length) && !isLoading && !isFetching) {
20
+ navigate(routes.home);
21
+ }
22
+ // redirect to the home page if no routes are found on page reload
23
+ // eslint-disable-next-line react-hooks/exhaustive-deps
24
+ }, []);
25
+ const routeNotFound = !(swapRoutes === null || swapRoutes === void 0 ? void 0 : swapRoutes.length) && isFetched;
26
+ return (_jsx(Stack, Object.assign({ direction: "column", spacing: 2 }, { children: routeNotFound ? (_jsx(SwapRouteNotFoundCard, { minWidth: "100%", dense: true })) : isLoading || isFetching ? (Array.from({ length: 3 }).map((_, index) => (_jsx(SwapRouteCardSkeleton, { minWidth: "100%", dense: true }, index)))) : (swapRoutes === null || swapRoutes === void 0 ? void 0 : swapRoutes.map((route, index) => (_jsx(SwapRouteCard, { route: route, active: (currentRoute === null || currentRoute === void 0 ? void 0 : currentRoute.id) === route.id, onClick: () => handleRouteClick(route) }, route.id)))) })));
28
27
  };
@@ -11,7 +11,8 @@ var __rest = (this && this.__rest) || function (s, e) {
11
11
  };
12
12
  import { jsx as _jsx } from "react/jsx-runtime";
13
13
  import { ChainId, getChainByKey } from '@lifi/sdk';
14
- import { createContext, useContext, useMemo } from 'react';
14
+ import { updateLiFiConfig } from '@lifi/widget/config/lifi';
15
+ import { createContext, useContext, useEffect, useMemo } from 'react';
15
16
  const stub = () => {
16
17
  throw new Error('You forgot to wrap your component in <WidgetProvider>.');
17
18
  };
@@ -21,7 +22,7 @@ const initialContext = {
21
22
  const WidgetContext = createContext(initialContext);
22
23
  export const useWidgetConfig = () => useContext(WidgetContext);
23
24
  export const WidgetProvider = (_a) => {
24
- var { children } = _a, _b = _a.config, _c = _b === void 0 ? {} : _b, { fromChain, fromToken, toChain, toToken } = _c, config = __rest(_c, ["fromChain", "fromToken", "toChain", "toToken"]);
25
+ var { children } = _a, _b = _a.config, _c = _b === void 0 ? {} : _b, { fromChain, fromToken, toChain, toToken, integrator } = _c, config = __rest(_c, ["fromChain", "fromToken", "toChain", "toToken", "integrator"]);
25
26
  const value = useMemo(() => {
26
27
  try {
27
28
  return Object.assign(Object.assign({}, config), { fromChain: typeof fromChain === 'number'
@@ -39,5 +40,12 @@ export const WidgetProvider = (_a) => {
39
40
  return config;
40
41
  }
41
42
  }, [config, fromChain, fromToken, toChain, toToken]);
43
+ useEffect(() => {
44
+ updateLiFiConfig({
45
+ defaultRouteOptions: {
46
+ integrator: integrator !== null && integrator !== void 0 ? integrator : window.location.hostname,
47
+ },
48
+ });
49
+ }, [integrator]);
42
50
  return (_jsx(WidgetContext.Provider, Object.assign({ value: value }, { children: children })));
43
51
  };
@@ -56,6 +56,6 @@ export const useRouteStore = create()(persist(immer((set) => ({
56
56
  state.routes[routeId].status = 'idle';
57
57
  }),
58
58
  })), {
59
- name: 'li.fi-widget-executable-routes',
59
+ name: 'li.fi-widget-routes',
60
60
  partialize: (state) => ({ routes: state.routes }),
61
61
  }));
package/types/widget.d.ts CHANGED
@@ -27,6 +27,7 @@ interface WidgetConfigBase {
27
27
  disableAppearance?: boolean;
28
28
  disableTelemetry?: boolean;
29
29
  walletManagement?: WidgetWalletManagement;
30
+ integrator?: string;
30
31
  }
31
32
  declare type WidgetFromTokenConfig = {
32
33
  fromChain: `${ChainKey}` | number;
package/utils/format.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import Big from 'big.js';
2
- // JavaScript numbers use exponential notation for positive exponents of 21 and above.
3
- Big.PE = 21;
2
+ // JavaScript numbers use exponential notation for positive exponents of 21 and above. We need more.
3
+ Big.PE = 42;
4
4
  // JavaScript numbers use exponential notation for negative exponents of -7 and below. We need more.
5
- Big.NE = -21;
5
+ Big.NE = -42;
6
6
  /**
7
7
  * Format token amount to at least 4 decimals.
8
8
  * @param amount amount to format.
package/lifi.d.ts DELETED
@@ -1,2 +0,0 @@
1
- import LIFI from '@lifi/sdk';
2
- export declare const LiFi: LIFI;
package/lifi.js DELETED
@@ -1,7 +0,0 @@
1
- import LIFI from '@lifi/sdk';
2
- export const LiFi = new LIFI({
3
- // apiUrl: env.LIFI_API_URL,
4
- defaultRouteOptions: {
5
- integrator: 'li.fi',
6
- },
7
- });