@lifi/widget 1.9.0 → 1.10.2

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.
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
  });
@@ -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).
@@ -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
  };
@@ -0,0 +1,5 @@
1
+ export interface SwapButtonProps {
2
+ onClick?(): void;
3
+ text?: string;
4
+ loading?: boolean;
5
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -17,7 +17,7 @@ import { StepActions } from '../StepActions';
17
17
  import { StepToken } from '../StepToken';
18
18
  import { Card, Check, Label } from './SwapRouteCard.style';
19
19
  export const SwapRouteCard = (_a) => {
20
- var _b;
20
+ var _b, _c;
21
21
  var { route, active, dense } = _a, other = __rest(_a, ["route", "active", "dense"]);
22
22
  const { t } = useTranslation();
23
23
  const label = ((_b = route.tags) === null || _b === void 0 ? void 0 : _b.length)
@@ -32,7 +32,7 @@ export const SwapRouteCard = (_a) => {
32
32
  : null, _jsxs(Box, Object.assign({ sx: {
33
33
  display: 'flex',
34
34
  justifyContent: 'space-between',
35
- } }, { children: [_jsxs(Box, { children: [_jsx(Typography, Object.assign({ fontSize: 18, fontWeight: "500" }, { children: t(`swap.currency`, { value: route.gasCostUSD }) })), _jsx(Typography, Object.assign({ fontSize: 12, color: "text.secondary" }, { children: t(`swap.gas`) }))] }), _jsxs(Box, { children: [_jsxs(Typography, Object.assign({ fontSize: 18, fontWeight: "500", display: "flex", justifyContent: "flex-end" }, { children: ["~", (route.steps
35
+ } }, { children: [_jsxs(Box, { children: [_jsx(Typography, Object.assign({ fontSize: 18, fontWeight: "500" }, { children: t(`swap.currency`, { value: (_c = route.gasCostUSD) !== null && _c !== void 0 ? _c : 0 }) })), _jsx(Typography, Object.assign({ fontSize: 12, color: "text.secondary" }, { children: t(`swap.gas`) }))] }), _jsxs(Box, { children: [_jsxs(Typography, Object.assign({ fontSize: 18, fontWeight: "500", display: "flex", justifyContent: "flex-end" }, { children: ["~", (route.steps
36
36
  .map((step) => step.estimate.executionDuration)
37
37
  .reduce((cumulated, x) => cumulated + x) / 60).toFixed(0)] })), _jsx(Typography, Object.assign({ fontSize: 12, color: "text.secondary", textAlign: "end" }, { children: t(`swap.minutes`) }))] })] }))] }) })));
38
38
  };
@@ -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.9.0";
2
+ export declare const version = "1.10.2";
package/config/version.js CHANGED
@@ -1,2 +1,2 @@
1
1
  export const name = '@lifi/widget';
2
- export const version = '1.9.0';
2
+ export const version = '1.10.2';
@@ -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: [
@@ -21,9 +23,9 @@ export const useHasSufficientBalance = () => {
21
23
  const { tokens: fromChainTokenBalances } = useTokenBalances(fromChainId);
22
24
  const { tokens: toChainTokenBalances } = useTokenBalances((_a = lastStep === null || lastStep === void 0 ? void 0 : lastStep.action.fromChainId) !== null && _a !== void 0 ? _a : toChainId);
23
25
  const hasGasOnStartChain = useMemo(() => {
24
- var _a, _b, _c, _d, _e;
26
+ var _a, _b, _c;
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 || !fromAmount) {
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);
@@ -32,30 +34,36 @@ export const useHasSufficientBalance = () => {
32
34
  .reduce((big, step) => { var _a; return big.plus(Big(((_a = step.estimate.gasCosts) === null || _a === void 0 ? void 0 : _a[0].amount) || 0)); }, Big(0))
33
35
  .div(Math.pow(10, gasToken.decimals));
34
36
  if (route.fromToken.address === gasToken.address) {
35
- const tokenBalance = Big((_e = (_d = fromChainTokenBalances === null || fromChainTokenBalances === void 0 ? void 0 : fromChainTokenBalances.find((t) => t.address === route.fromToken.address)) === null || _d === void 0 ? void 0 : _d.amount) !== null && _e !== void 0 ? _e : 0);
36
- requiredAmount = requiredAmount.plus(tokenBalance);
37
+ requiredAmount = requiredAmount.plus(Big(fromAmount));
37
38
  }
38
39
  return gasTokenBalance.gt(0) && gasTokenBalance.gte(requiredAmount);
39
- }, [fromChainTokenBalances, route]);
40
+ }, [
41
+ account.isActive,
42
+ fromAmount,
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';
@@ -12,7 +12,7 @@ import { useEffect } from 'react';
12
12
  import { useWatch } from 'react-hook-form';
13
13
  import { useQuery, useQueryClient } from 'react-query';
14
14
  import { useDebouncedWatch, useToken } from '.';
15
- import { LiFi } from '../lifi';
15
+ import { LiFi } from '../config/lifi';
16
16
  import { SwapFormKey } from '../providers/SwapFormProvider';
17
17
  import { useWallet } from '../providers/WalletProvider';
18
18
  import { useCurrentRoute, useSettings } from '../stores';
@@ -38,13 +38,14 @@ export const useSwapRoutes = () => {
38
38
  });
39
39
  const [fromTokenAmount] = useDebouncedWatch([SwapFormKey.FromAmount], 250);
40
40
  const { token } = useToken(fromChainId, fromTokenAddress);
41
- const isEnabled = Boolean(account.address) &&
42
- !isNaN(fromChainId) &&
41
+ const isEnabled =
42
+ // Boolean(account.address) &&
43
+ !isNaN(fromChainId) &&
43
44
  !isNaN(toChainId) &&
44
45
  Boolean(fromTokenAddress) &&
45
46
  Boolean(toTokenAddress) &&
46
- Boolean(fromTokenAmount) &&
47
47
  !isNaN(fromTokenAmount) &&
48
+ Number(fromTokenAmount) > 0 &&
48
49
  !Number.isNaN(slippage);
49
50
  const queryKey = [
50
51
  'routes',
@@ -95,11 +96,12 @@ export const useSwapRoutes = () => {
95
96
  // check that the current route is selected from existing routes
96
97
  const isCurrentRouteInSet = data === null || data === void 0 ? void 0 : data.routes.some((route) => route.id === (currentRoute === null || currentRoute === void 0 ? void 0 : currentRoute.id));
97
98
  const recommendedRoute = data === null || data === void 0 ? void 0 : data.routes[0];
98
- // we don't want to set the current route again if it's already selected from existing routes
99
- if (!isCurrentRouteInSet && currentRoute !== recommendedRoute) {
99
+ // we don't want to set the current route again on mount if it's already selected from existing routes
100
+ if (!isCurrentRouteInSet) {
100
101
  setCurrentRoute(recommendedRoute);
101
102
  }
102
- }, [currentRoute, data === null || data === void 0 ? void 0 : data.routes, setCurrentRoute]);
103
+ // eslint-disable-next-line react-hooks/exhaustive-deps
104
+ }, [data === null || data === void 0 ? void 0 : data.routes, setCurrentRoute]);
103
105
  return {
104
106
  routes: data === null || data === void 0 ? void 0 : data.routes,
105
107
  isLoading: isEnabled && isLoading,
@@ -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",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lifi/widget",
3
- "version": "1.9.0",
3
+ "version": "1.10.2",
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.1",
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",
@@ -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
+ };
@@ -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))), status === 'idle' ? _jsx(InsufficientGasOrFundsMessage, { mt: 2 }) : null, 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
  };
@@ -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/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
- });