@lifi/widget 1.18.9 → 1.20.0

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 (167) hide show
  1. package/App.js +3 -3
  2. package/cjs/App.js +3 -3
  3. package/cjs/components/ActiveSwaps/ActiveSwaps.js +1 -1
  4. package/cjs/components/ActiveSwaps/ActiveSwaps.style.d.ts +0 -14
  5. package/cjs/components/ActiveSwaps/ActiveSwaps.style.js +1 -9
  6. package/cjs/components/AppContainer.d.ts +11 -1
  7. package/cjs/components/AppContainer.js +2 -6
  8. package/cjs/components/BottomSheet/BottomSheet.js +9 -31
  9. package/cjs/components/BottomSheet/types.d.ts +2 -2
  10. package/cjs/components/Card/Card.js +1 -1
  11. package/cjs/components/Card/CardHeader.d.ts +1 -1
  12. package/cjs/components/ChainSelect/ChainSelect.js +1 -1
  13. package/cjs/components/ChainSelect/useChainSelect.js +2 -4
  14. package/cjs/components/Dialog.d.ts +22 -1
  15. package/cjs/components/Dialog.js +23 -19
  16. package/cjs/components/GasSufficiencyMessage/GasSufficiencyMessage.js +19 -22
  17. package/cjs/components/Header/NavigationHeader.js +1 -1
  18. package/cjs/components/Header/WalletHeader.js +2 -2
  19. package/cjs/components/PoweredBy/PoweredBy.js +1 -1
  20. package/cjs/components/ProgressToNextUpdate/ProgressToNextUpdate.js +1 -1
  21. package/cjs/components/ReverseTokensButton/ReverseTokensButton.js +6 -6
  22. package/cjs/components/SelectTokenButton/SelectTokenButton.style.d.ts +1 -1
  23. package/cjs/components/SendToWallet/SendToWallet.d.ts +1 -0
  24. package/cjs/components/SendToWallet/SendToWallet.js +10 -5
  25. package/cjs/components/SendToWallet/SendToWalletButton.js +2 -2
  26. package/cjs/components/Step/StepProcess.js +1 -1
  27. package/cjs/components/SwapButton/SwapButton.js +4 -4
  28. package/cjs/components/SwapButton/types.d.ts +2 -0
  29. package/cjs/components/SwapInput/SwapInput.js +6 -2
  30. package/cjs/components/SwapInput/SwapInputAdornment.js +4 -2
  31. package/cjs/components/SwapInput/SwapInputAdornment.style.js +2 -14
  32. package/cjs/components/SwapRouteCard/SwapRouteCard.js +7 -6
  33. package/cjs/components/SwapRoutes/SwapRoutes.js +4 -4
  34. package/cjs/components/SwapRoutes/SwapRoutesExpanded.d.ts +1 -0
  35. package/cjs/components/SwapRoutes/SwapRoutesExpanded.js +17 -12
  36. package/cjs/components/SwapRoutes/useSetRecommendedRoute.d.ts +2 -0
  37. package/cjs/components/SwapRoutes/useSetRecommendedRoute.js +13 -0
  38. package/cjs/components/TokenList/TokenList.js +9 -6
  39. package/cjs/config/theme.js +22 -8
  40. package/cjs/config/version.d.ts +1 -1
  41. package/cjs/config/version.js +1 -1
  42. package/cjs/hooks/index.d.ts +1 -0
  43. package/cjs/hooks/index.js +1 -0
  44. package/cjs/hooks/useContentHeight.d.ts +2 -0
  45. package/cjs/hooks/useContentHeight.js +18 -1
  46. package/cjs/hooks/useExpandableVariant.d.ts +1 -0
  47. package/cjs/hooks/useExpandableVariant.js +14 -0
  48. package/cjs/hooks/useGasSufficiency.d.ts +3 -2
  49. package/cjs/hooks/useGasSufficiency.js +50 -26
  50. package/cjs/hooks/useSwapRoutes.js +4 -2
  51. package/cjs/hooks/useTokenBalance.js +2 -2
  52. package/cjs/i18n/en/translation.json +15 -7
  53. package/cjs/i18n/index.d.ts +13 -5
  54. package/cjs/pages/ActiveSwapsPage/ActiveSwapsPage.js +21 -4
  55. package/cjs/pages/MainPage/MainPage.js +3 -3
  56. package/cjs/pages/SelectWalletPage/SelectWalletPage.js +1 -1
  57. package/cjs/pages/SwapDetailsPage/SwapDetailsPage.js +2 -2
  58. package/cjs/pages/SwapHistoryPage/SwapHistoryPage.js +2 -2
  59. package/cjs/pages/SwapPage/StatusBottomSheet.js +4 -4
  60. package/cjs/pages/SwapPage/StatusBottomSheet.style.d.ts +0 -4
  61. package/cjs/pages/SwapPage/StatusBottomSheet.style.js +23 -17
  62. package/cjs/pages/SwapPage/SwapPage.js +38 -17
  63. package/cjs/pages/SwapPage/TokenValueBottomSheet.d.ts +11 -0
  64. package/cjs/pages/SwapPage/TokenValueBottomSheet.js +42 -0
  65. package/cjs/providers/SwapFormProvider/SwapFormProvider.js +3 -2
  66. package/cjs/providers/SwapFormProvider/URLSearchParamsBuilder.d.ts +1 -0
  67. package/cjs/providers/SwapFormProvider/URLSearchParamsBuilder.js +46 -0
  68. package/cjs/providers/SwapFormProvider/types.d.ts +4 -4
  69. package/cjs/providers/SwapFormProvider/types.js +2 -2
  70. package/cjs/providers/WalletProvider/WalletFormUpdate.d.ts +5 -0
  71. package/cjs/providers/WalletProvider/WalletFormUpdate.js +64 -0
  72. package/cjs/providers/WalletProvider/WalletProvider.js +3 -58
  73. package/cjs/providers/WidgetProvider/WidgetProvider.js +12 -5
  74. package/cjs/stores/routes/index.d.ts +1 -1
  75. package/cjs/stores/routes/index.js +1 -1
  76. package/cjs/stores/routes/types.d.ts +5 -5
  77. package/cjs/stores/routes/useRecommendedRouteStore.d.ts +4 -0
  78. package/cjs/stores/routes/{useSelectedRouteStore.js → useRecommendedRouteStore.js} +4 -4
  79. package/cjs/stores/routes/useRouteExecutionStore.js +9 -2
  80. package/cjs/types/widget.d.ts +1 -0
  81. package/components/ActiveSwaps/ActiveSwaps.js +3 -3
  82. package/components/ActiveSwaps/ActiveSwaps.style.d.ts +0 -14
  83. package/components/ActiveSwaps/ActiveSwaps.style.js +1 -9
  84. package/components/AppContainer.d.ts +11 -1
  85. package/components/AppContainer.js +1 -4
  86. package/components/BottomSheet/BottomSheet.js +10 -32
  87. package/components/BottomSheet/types.d.ts +2 -2
  88. package/components/Card/Card.js +1 -1
  89. package/components/Card/CardHeader.d.ts +1 -1
  90. package/components/ChainSelect/ChainSelect.js +1 -1
  91. package/components/ChainSelect/useChainSelect.js +2 -4
  92. package/components/Dialog.d.ts +22 -1
  93. package/components/Dialog.js +23 -19
  94. package/components/GasSufficiencyMessage/GasSufficiencyMessage.js +21 -24
  95. package/components/Header/NavigationHeader.js +2 -2
  96. package/components/Header/WalletHeader.js +2 -2
  97. package/components/PoweredBy/PoweredBy.js +1 -1
  98. package/components/ProgressToNextUpdate/ProgressToNextUpdate.js +1 -1
  99. package/components/ReverseTokensButton/ReverseTokensButton.js +6 -6
  100. package/components/SelectTokenButton/SelectTokenButton.style.d.ts +1 -1
  101. package/components/SendToWallet/SendToWallet.d.ts +1 -0
  102. package/components/SendToWallet/SendToWallet.js +9 -5
  103. package/components/SendToWallet/SendToWalletButton.js +2 -2
  104. package/components/Step/StepProcess.js +1 -1
  105. package/components/SwapButton/SwapButton.js +4 -4
  106. package/components/SwapButton/types.d.ts +2 -0
  107. package/components/SwapInput/SwapInput.js +6 -2
  108. package/components/SwapInput/SwapInputAdornment.js +4 -2
  109. package/components/SwapInput/SwapInputAdornment.style.js +3 -15
  110. package/components/SwapRouteCard/SwapRouteCard.js +8 -7
  111. package/components/SwapRoutes/SwapRoutes.js +4 -4
  112. package/components/SwapRoutes/SwapRoutesExpanded.d.ts +1 -0
  113. package/components/SwapRoutes/SwapRoutesExpanded.js +16 -12
  114. package/components/SwapRoutes/useSetRecommendedRoute.d.ts +2 -0
  115. package/components/SwapRoutes/useSetRecommendedRoute.js +9 -0
  116. package/components/TokenList/TokenList.js +9 -6
  117. package/config/theme.js +22 -8
  118. package/config/version.d.ts +1 -1
  119. package/config/version.js +1 -1
  120. package/hooks/index.d.ts +1 -0
  121. package/hooks/index.js +1 -0
  122. package/hooks/useContentHeight.d.ts +2 -0
  123. package/hooks/useContentHeight.js +16 -0
  124. package/hooks/useExpandableVariant.d.ts +1 -0
  125. package/hooks/useExpandableVariant.js +10 -0
  126. package/hooks/useGasSufficiency.d.ts +3 -2
  127. package/hooks/useGasSufficiency.js +50 -26
  128. package/hooks/useSwapRoutes.js +4 -2
  129. package/hooks/useTokenBalance.js +2 -2
  130. package/i18n/en/translation.json +15 -7
  131. package/i18n/index.d.ts +13 -5
  132. package/package.json +11 -11
  133. package/pages/ActiveSwapsPage/ActiveSwapsPage.js +24 -7
  134. package/pages/MainPage/MainPage.js +3 -3
  135. package/pages/SelectWalletPage/SelectWalletPage.js +1 -1
  136. package/pages/SwapDetailsPage/SwapDetailsPage.js +2 -2
  137. package/pages/SwapHistoryPage/SwapHistoryPage.js +2 -2
  138. package/pages/SwapPage/StatusBottomSheet.js +5 -5
  139. package/pages/SwapPage/StatusBottomSheet.style.d.ts +0 -4
  140. package/pages/SwapPage/StatusBottomSheet.style.js +23 -17
  141. package/pages/SwapPage/SwapPage.js +41 -20
  142. package/pages/SwapPage/TokenValueBottomSheet.d.ts +11 -0
  143. package/pages/SwapPage/TokenValueBottomSheet.js +38 -0
  144. package/providers/SwapFormProvider/SwapFormProvider.js +4 -3
  145. package/providers/SwapFormProvider/URLSearchParamsBuilder.d.ts +1 -0
  146. package/providers/SwapFormProvider/URLSearchParamsBuilder.js +42 -0
  147. package/providers/SwapFormProvider/types.d.ts +4 -4
  148. package/providers/SwapFormProvider/types.js +2 -2
  149. package/providers/WalletProvider/WalletFormUpdate.d.ts +5 -0
  150. package/providers/WalletProvider/WalletFormUpdate.js +60 -0
  151. package/providers/WalletProvider/WalletProvider.js +5 -60
  152. package/providers/WidgetProvider/WidgetProvider.js +12 -5
  153. package/stores/routes/index.d.ts +1 -1
  154. package/stores/routes/index.js +1 -1
  155. package/stores/routes/types.d.ts +5 -5
  156. package/stores/routes/useRecommendedRouteStore.d.ts +4 -0
  157. package/stores/routes/useRecommendedRouteStore.js +9 -0
  158. package/stores/routes/useRouteExecutionStore.js +9 -2
  159. package/tsconfig.cjs.tsbuildinfo +1 -1
  160. package/types/widget.d.ts +1 -0
  161. package/cjs/components/SwapRoutes/useSetSelectedRoute.d.ts +0 -2
  162. package/cjs/components/SwapRoutes/useSetSelectedRoute.js +0 -13
  163. package/cjs/stores/routes/useSelectedRouteStore.d.ts +0 -4
  164. package/components/SwapRoutes/useSetSelectedRoute.d.ts +0 -2
  165. package/components/SwapRoutes/useSetSelectedRoute.js +0 -9
  166. package/stores/routes/useSelectedRouteStore.d.ts +0 -4
  167. package/stores/routes/useSelectedRouteStore.js +0 -9
@@ -7,10 +7,10 @@ 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 { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
10
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
11
11
  import { Delete as DeleteIcon } from '@mui/icons-material';
12
- import { Box, Button } from '@mui/material';
13
- import { Fragment } from 'react';
12
+ import { Box, Button, Tooltip } from '@mui/material';
13
+ import { Fragment, useCallback, useRef } from 'react';
14
14
  import { useFormContext } from 'react-hook-form';
15
15
  import { useTranslation } from 'react-i18next';
16
16
  import { useLocation } from 'react-router-dom';
@@ -22,32 +22,51 @@ import { useNavigateBack, useRouteExecution } from '../../hooks';
22
22
  import { SwapFormKey } from '../../providers';
23
23
  import { StatusBottomSheet } from './StatusBottomSheet';
24
24
  import { Container } from './SwapPage.style';
25
+ import { getTokenValueLossThreshold, TokenValueBottomSheet, } from './TokenValueBottomSheet';
25
26
  export const SwapPage = () => {
26
27
  const { t } = useTranslation();
27
28
  const { state } = useLocation();
28
29
  const { navigateBack } = useNavigateBack();
29
- const { setValue, formState: { isValid, isValidating }, } = useFormContext();
30
+ const tokenValueBottomSheetRef = useRef(null);
31
+ const { setValue,
32
+ // formState: { isValid, isValidating },
33
+ } = useFormContext();
30
34
  const { route, status, executeRoute, restartRoute, deleteRoute } = useRouteExecution(state === null || state === void 0 ? void 0 : state.routeId);
31
- const handleRemoveRoute = () => {
32
- navigateBack();
33
- deleteRoute();
34
- };
35
+ const handleExecuteRoute = useCallback(() => {
36
+ var _a, _b;
37
+ if ((_a = tokenValueBottomSheetRef.current) === null || _a === void 0 ? void 0 : _a.isOpen()) {
38
+ (_b = tokenValueBottomSheetRef.current) === null || _b === void 0 ? void 0 : _b.close();
39
+ }
40
+ executeRoute();
41
+ setValue(SwapFormKey.FromAmount, '');
42
+ }, [executeRoute, setValue]);
35
43
  const handleSwapClick = () => __awaiter(void 0, void 0, void 0, function* () {
44
+ var _a;
36
45
  if (status === 'idle') {
37
- executeRoute();
38
- setValue(SwapFormKey.FromAmount, '');
46
+ const thresholdExceeded = getTokenValueLossThreshold(route);
47
+ if (thresholdExceeded) {
48
+ (_a = tokenValueBottomSheetRef.current) === null || _a === void 0 ? void 0 : _a.open();
49
+ }
50
+ else {
51
+ handleExecuteRoute();
52
+ }
39
53
  }
40
54
  if (status === 'error') {
41
55
  restartRoute();
42
56
  }
43
57
  });
44
- // eslint-disable-next-line consistent-return
58
+ const handleRemoveRoute = () => {
59
+ navigateBack();
60
+ deleteRoute();
61
+ };
45
62
  const getSwapButtonText = () => {
46
- if (status === 'idle') {
47
- return t('button.startSwap');
48
- }
49
- if (status === 'error') {
50
- return t('button.restartSwap');
63
+ switch (status) {
64
+ case 'idle':
65
+ return t('button.startSwap');
66
+ case 'error':
67
+ return t('button.restartSwap');
68
+ default:
69
+ return '';
51
70
  }
52
71
  };
53
72
  return (_jsxs(Container, { children: [route === null || route === void 0 ? void 0 : route.steps.map((step, index, steps) => {
@@ -55,8 +74,10 @@ export const SwapPage = () => {
55
74
  return (_jsxs(Fragment, { children: [_jsx(Step, { step: step, fromToken: index === 0
56
75
  ? Object.assign(Object.assign({}, step.action.fromToken), { amount: step.action.fromAmount }) : undefined, toToken: index === steps.length - 1
57
76
  ? Object.assign(Object.assign({}, step.action.toToken), { amount: (_b = (_a = step.execution) === null || _a === void 0 ? void 0 : _a.toAmount) !== null && _b !== void 0 ? _b : step.estimate.toAmount }) : undefined }), steps.length > 1 && index !== steps.length - 1 ? (_jsx(StepDivider, {})) : null] }, step.id));
58
- }), status === 'idle' ? (_jsx(GasSufficiencyMessage, { route: route, mt: 2 })) : null, status === 'idle' || status === 'error' ? (_jsxs(Box, Object.assign({ mt: 2, display: "flex" }, { children: [_jsx(SwapButton, { text: getSwapButtonText(), onClick: handleSwapClick, currentRoute: route, disable: status === 'idle' && (isValidating || !isValid) }), status === 'error' ? (_jsx(Button, Object.assign({ onClick: handleRemoveRoute, sx: {
59
- minWidth: 48,
60
- marginLeft: 1,
61
- } }, { children: _jsx(DeleteIcon, {}) }))) : null] }))) : null, route && status ? (_jsx(StatusBottomSheet, { status: status, route: route })) : null] }));
77
+ }), status === 'idle' || status === 'error' ? (_jsxs(_Fragment, { children: [_jsx(GasSufficiencyMessage, { route: route, mt: 2 }), _jsxs(Box, Object.assign({ mt: 2, display: "flex" }, { children: [_jsx(SwapButton, { text: getSwapButtonText(), onClick: handleSwapClick, currentRoute: route,
78
+ // disable={status === 'idle' && (isValidating || !isValid)}
79
+ enableLoading: true }), status === 'error' ? (_jsx(Tooltip, Object.assign({ title: t('button.removeSwap'), placement: "bottom-end", enterDelay: 400, arrow: true }, { children: _jsx(Button, Object.assign({ onClick: handleRemoveRoute, sx: {
80
+ minWidth: 48,
81
+ marginLeft: 1,
82
+ } }, { children: _jsx(DeleteIcon, {}) })) }))) : null] }))] })) : null, route && status ? (_jsx(StatusBottomSheet, { status: status, route: route })) : null, route ? (_jsx(TokenValueBottomSheet, { route: route, ref: tokenValueBottomSheetRef, onContinue: handleExecuteRoute })) : null] }));
62
83
  };
@@ -0,0 +1,11 @@
1
+ /// <reference types="react" />
2
+ import type { Route } from '@lifi/sdk';
3
+ import type { BottomSheetBase } from '../../components/BottomSheet';
4
+ interface TokenValueBottomSheetProps {
5
+ route: Route;
6
+ onContinue(): void;
7
+ onCancel?(): void;
8
+ }
9
+ export declare const TokenValueBottomSheet: import("react").ForwardRefExoticComponent<TokenValueBottomSheetProps & import("react").RefAttributes<BottomSheetBase>>;
10
+ export declare const getTokenValueLossThreshold: (route?: Route) => boolean;
11
+ export {};
@@ -0,0 +1,38 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Warning as WarningIcon } from '@mui/icons-material';
3
+ import { Box, Button, Typography } from '@mui/material';
4
+ import Big from 'big.js';
5
+ import { forwardRef, useRef } from 'react';
6
+ import { useTranslation } from 'react-i18next';
7
+ import { BottomSheet } from '../../components/BottomSheet';
8
+ import { useSetContentHeight } from '../../hooks';
9
+ import { IconCircle, IconContainer } from './StatusBottomSheet.style';
10
+ export const TokenValueBottomSheet = forwardRef(({ route, onContinue, onCancel }, ref) => {
11
+ const handleCancel = () => {
12
+ var _a;
13
+ (_a = ref.current) === null || _a === void 0 ? void 0 : _a.close();
14
+ onCancel === null || onCancel === void 0 ? void 0 : onCancel();
15
+ };
16
+ return (_jsx(BottomSheet, Object.assign({ ref: ref }, { children: _jsx(TokenValueBottomSheetContent, { route: route, onContinue: onContinue, onCancel: handleCancel }) })));
17
+ });
18
+ const TokenValueBottomSheetContent = ({ route, onCancel, onContinue, }) => {
19
+ const { t } = useTranslation();
20
+ const ref = useRef();
21
+ useSetContentHeight(ref);
22
+ return (_jsxs(Box, Object.assign({ p: 3, ref: ref }, { children: [_jsxs(IconContainer, { children: [_jsx(IconCircle, Object.assign({ status: "warning", mb: 1 }, { children: _jsx(WarningIcon, { color: "warning" }) })), _jsx(Typography, Object.assign({ py: 1, fontSize: 18, fontWeight: 700 }, { children: t('swap.warning.title.highValueLoss') }))] }), _jsx(Typography, Object.assign({ py: 1 }, { children: t('swap.warning.message.highValueLoss') })), _jsxs(Box, Object.assign({ display: "flex", justifyContent: "space-between", mt: 1 }, { children: [_jsx(Typography, { children: t('swap.swapping') }), _jsx(Typography, Object.assign({ fontWeight: 600 }, { children: t('swap.currency', { value: route.fromAmountUSD }) }))] })), _jsxs(Box, Object.assign({ display: "flex", justifyContent: "space-between", mt: 0.25 }, { children: [_jsx(Typography, { children: t('swap.gasCost') }), _jsx(Typography, Object.assign({ fontWeight: 600 }, { children: t('swap.currency', { value: route.gasCostUSD }) }))] })), _jsxs(Box, Object.assign({ display: "flex", justifyContent: "space-between", mt: 0.25 }, { children: [_jsx(Typography, { children: t('swap.receiving') }), _jsx(Typography, Object.assign({ fontWeight: 600 }, { children: t('swap.currency', { value: route.toAmountUSD }) }))] })), _jsxs(Box, Object.assign({ display: "flex", justifyContent: "space-between", mt: 0.25 }, { children: [_jsx(Typography, { children: t('swap.valueLoss') }), _jsxs(Typography, Object.assign({ fontWeight: 600 }, { children: [Big(route.toAmountUSD || 0)
23
+ .div(Big(route.fromAmountUSD || 0).plus(Big(route.gasCostUSD || 0)))
24
+ .mul(-100)
25
+ .toFixed(1), "%"] }))] })), _jsxs(Box, Object.assign({ display: "flex", mt: 3 }, { children: [_jsx(Button, Object.assign({ variant: "text", onClick: onCancel, fullWidth: true }, { children: t('button.cancel') })), _jsx(Box, { display: "flex", p: 1 }), _jsx(Button, Object.assign({ variant: "contained", onClick: onContinue, fullWidth: true }, { children: t('button.continue') }))] }))] })));
26
+ };
27
+ export const getTokenValueLossThreshold = (route) => {
28
+ if (!route) {
29
+ return false;
30
+ }
31
+ const fromAmountUSD = Big((route === null || route === void 0 ? void 0 : route.fromAmountUSD) || 0);
32
+ const toAmountUSD = Big((route === null || route === void 0 ? void 0 : route.toAmountUSD) || 0);
33
+ const gasCostUSD = Big((route === null || route === void 0 ? void 0 : route.gasCostUSD) || 0);
34
+ if (fromAmountUSD.eq(0) && toAmountUSD.eq(0)) {
35
+ return false;
36
+ }
37
+ return toAmountUSD.div(fromAmountUSD.plus(gasCostUSD)).lt(0.9);
38
+ };
@@ -1,14 +1,15 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { FormProvider, useForm } from 'react-hook-form';
3
3
  import { useWidgetConfig } from '../WidgetProvider';
4
4
  import { SwapFormKey } from './types';
5
+ import { URLSearchParamsBuilder } from './URLSearchParamsBuilder';
5
6
  export const formDefaultValues = {
6
7
  [SwapFormKey.FromAmount]: '',
7
8
  [SwapFormKey.ToAddress]: '',
8
9
  [SwapFormKey.TokenSearchFilter]: '',
9
10
  };
10
11
  export const SwapFormProvider = ({ children, }) => {
11
- const { fromChain, fromToken, fromAmount, toChain, toToken, toAddress } = useWidgetConfig();
12
+ const { fromChain, fromToken, fromAmount, toChain, toToken, toAddress, buildSwapUrl, } = useWidgetConfig();
12
13
  const methods = useForm({
13
14
  defaultValues: Object.assign(Object.assign({}, formDefaultValues), { fromChain,
14
15
  fromToken, fromAmount: (typeof fromAmount === 'number'
@@ -17,5 +18,5 @@ export const SwapFormProvider = ({ children, }) => {
17
18
  toToken,
18
19
  toAddress }),
19
20
  });
20
- return _jsx(FormProvider, Object.assign({}, methods, { children: children }));
21
+ return (_jsxs(FormProvider, Object.assign({}, methods, { children: [buildSwapUrl ? _jsx(URLSearchParamsBuilder, {}) : null, children] })));
21
22
  };
@@ -0,0 +1 @@
1
+ export declare const URLSearchParamsBuilder: () => null;
@@ -0,0 +1,42 @@
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 { useEffect } from 'react';
13
+ import { useFormState, useWatch } from 'react-hook-form';
14
+ import { useLocation } from 'react-router-dom';
15
+ import { SwapFormKey } from './types';
16
+ const formValueKeys = [
17
+ SwapFormKey.FromAmount,
18
+ SwapFormKey.FromChain,
19
+ SwapFormKey.FromToken,
20
+ SwapFormKey.ToAddress,
21
+ SwapFormKey.ToChain,
22
+ SwapFormKey.ToToken,
23
+ ];
24
+ export const URLSearchParamsBuilder = () => {
25
+ const { pathname } = useLocation();
26
+ const touchedFields = __rest(useFormState().touchedFields, []);
27
+ const values = useWatch({ name: formValueKeys });
28
+ useEffect(() => {
29
+ const url = new URL(window.location);
30
+ formValueKeys.forEach((key, index) => {
31
+ if (touchedFields[key] && values[index]) {
32
+ url.searchParams.set(key, values[index]);
33
+ }
34
+ else if (url.searchParams.has(key) && !values[index]) {
35
+ url.searchParams.delete(key);
36
+ }
37
+ });
38
+ url.searchParams.sort();
39
+ window.history.replaceState(window.history.state, '', url);
40
+ }, [pathname, touchedFields, values]);
41
+ return null;
42
+ };
@@ -2,19 +2,19 @@ export declare enum SwapFormKey {
2
2
  FromAmount = "fromAmount",
3
3
  FromChain = "fromChain",
4
4
  FromToken = "fromToken",
5
- TokenSearchFilter = "tokenSearchFilter",
5
+ ToAddress = "toAddress",
6
6
  ToChain = "toChain",
7
7
  ToToken = "toToken",
8
- ToAddress = "toAddress"
8
+ TokenSearchFilter = "tokenSearchFilter"
9
9
  }
10
10
  export declare type SwapFormValues = {
11
11
  [SwapFormKey.FromAmount]: string;
12
12
  [SwapFormKey.FromChain]: number;
13
13
  [SwapFormKey.FromToken]: string;
14
- [SwapFormKey.TokenSearchFilter]: string;
14
+ [SwapFormKey.ToAddress]: string;
15
15
  [SwapFormKey.ToChain]: number;
16
16
  [SwapFormKey.ToToken]: string;
17
- [SwapFormKey.ToAddress]: string;
17
+ [SwapFormKey.TokenSearchFilter]: string;
18
18
  };
19
19
  export declare type SwapFormType = 'from' | 'to';
20
20
  export declare const SwapFormKeyHelper: {
@@ -3,10 +3,10 @@ export var SwapFormKey;
3
3
  SwapFormKey["FromAmount"] = "fromAmount";
4
4
  SwapFormKey["FromChain"] = "fromChain";
5
5
  SwapFormKey["FromToken"] = "fromToken";
6
- SwapFormKey["TokenSearchFilter"] = "tokenSearchFilter";
6
+ SwapFormKey["ToAddress"] = "toAddress";
7
7
  SwapFormKey["ToChain"] = "toChain";
8
8
  SwapFormKey["ToToken"] = "toToken";
9
- SwapFormKey["ToAddress"] = "toAddress";
9
+ SwapFormKey["TokenSearchFilter"] = "tokenSearchFilter";
10
10
  })(SwapFormKey || (SwapFormKey = {}));
11
11
  export const SwapFormKeyHelper = {
12
12
  getChainKey: (formType) => `${formType}Chain`,
@@ -0,0 +1,5 @@
1
+ /// <reference types="react" />
2
+ import type { WalletAccount } from './types';
3
+ export declare const WalletFormUpdate: React.FC<{
4
+ account: WalletAccount;
5
+ }>;
@@ -0,0 +1,60 @@
1
+ /* eslint-disable @typescript-eslint/no-unused-vars */
2
+ import { useEffect } from 'react';
3
+ import { useFormContext } from 'react-hook-form';
4
+ import { useChainOrderStore } from '../../stores';
5
+ import { SwapFormKey } from '../SwapFormProvider';
6
+ import { isItemAllowed, useWidgetConfig } from '../WidgetProvider';
7
+ export const WalletFormUpdate = ({ account, }) => {
8
+ const { fromChain, toChain, chains, disabledChains } = useWidgetConfig();
9
+ const { setValue, getValues, getFieldState,
10
+ // Subscription to touchedFields is required by getFieldState to work
11
+ formState: { touchedFields }, } = useFormContext();
12
+ // Set wallet chain as default if no chains are provided by config and if they were not changed during widget usage
13
+ useEffect(() => {
14
+ const chainAllowed = account.chainId && isItemAllowed(account.chainId, chains, disabledChains);
15
+ if (!account.isActive || !account.chainId || !chainAllowed) {
16
+ return;
17
+ }
18
+ const [fromChainValue, toChainValue] = getValues([
19
+ SwapFormKey.FromChain,
20
+ SwapFormKey.ToChain,
21
+ ]);
22
+ const { isTouched: isFromChainTouched } = getFieldState(SwapFormKey.FromChain);
23
+ const { isTouched: isToChainTouched } = getFieldState(SwapFormKey.ToChain);
24
+ const { isTouched: isFromTokenTouched } = getFieldState(SwapFormKey.FromToken);
25
+ const { isTouched: isToTokenTouched } = getFieldState(SwapFormKey.ToToken);
26
+ const { isTouched: isFromAmountTouched } = getFieldState(SwapFormKey.FromAmount);
27
+ const { chainOrder, setChain } = useChainOrderStore.getState();
28
+ // Users can switch chains in the wallet.
29
+ // If we don't have a chain in the ordered chain list we should add it.
30
+ setChain(account.chainId);
31
+ // If we ran out of slots for the ordered chain list and the current chain isn't there
32
+ // we should make a recently switched chain as current.
33
+ const hasFromChainInOrderedList = chainOrder.includes(fromChainValue);
34
+ const hasToChainInOrderedList = chainOrder.includes(toChainValue);
35
+ if ((!fromChain && !isFromChainTouched && !isFromTokenTouched) ||
36
+ !hasFromChainInOrderedList) {
37
+ setValue(SwapFormKey.FromChain, account.chainId);
38
+ setValue(SwapFormKey.FromToken, '');
39
+ if (isFromAmountTouched) {
40
+ setValue(SwapFormKey.FromAmount, '');
41
+ }
42
+ }
43
+ if ((!toChain && !isToChainTouched && !isToTokenTouched) ||
44
+ !hasToChainInOrderedList) {
45
+ setValue(SwapFormKey.ToChain, account.chainId);
46
+ setValue(SwapFormKey.ToToken, '');
47
+ }
48
+ }, [
49
+ account.chainId,
50
+ account.isActive,
51
+ chains,
52
+ disabledChains,
53
+ fromChain,
54
+ getFieldState,
55
+ getValues,
56
+ setValue,
57
+ toChain,
58
+ ]);
59
+ return null;
60
+ };
@@ -7,13 +7,11 @@ 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 { jsx as _jsx } from "react/jsx-runtime";
10
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
11
11
  import { addChain as walletAddChain, switchChain as walletSwitchChain, switchChainAndAddToken, useLiFiWalletManagement, } from '@lifi/wallet-management';
12
12
  import { createContext, useCallback, useContext, useEffect, useMemo, useState, } from 'react';
13
- import { useFormContext } from 'react-hook-form';
14
- import { useChainOrderStore } from '../../stores';
15
- import { SwapFormKey } from '../SwapFormProvider';
16
- import { isItemAllowed, useWidgetConfig } from '../WidgetProvider';
13
+ import { useWidgetConfig } from '../WidgetProvider';
14
+ import { WalletFormUpdate } from './WalletFormUpdate';
17
15
  const stub = () => {
18
16
  throw new Error('You forgot to wrap your component in <WalletProvider>.');
19
17
  };
@@ -28,8 +26,7 @@ const initialContext = {
28
26
  const WalletContext = createContext(initialContext);
29
27
  export const useWallet = () => useContext(WalletContext);
30
28
  export const WalletProvider = ({ children }) => {
31
- const { walletManagement, fromChain, toChain, chains, disabledChains } = useWidgetConfig();
32
- const methods = useFormContext();
29
+ const { walletManagement } = useWidgetConfig();
33
30
  const { connect: walletManagementConnect, disconnect: walletManagementDisconnect, signer, provider, } = useLiFiWalletManagement();
34
31
  const [account, setAccount] = useState({});
35
32
  const connect = useCallback((wallet) => __awaiter(void 0, void 0, void 0, function* () {
@@ -94,59 +91,7 @@ export const WalletProvider = ({ children }) => {
94
91
  account,
95
92
  provider,
96
93
  }), [account, addChain, addToken, connect, disconnect, provider, switchChain]);
97
- // Set wallet chain as default if no chains are provided by config and if they were not changed during widget usage
98
- useEffect(() => {
99
- const chainAllowed = account.chainId && isItemAllowed(account.chainId, chains, disabledChains);
100
- if (!account.isActive || !account.chainId || !chainAllowed) {
101
- return;
102
- }
103
- const [fromChainValue, toChainValue] = methods.getValues([
104
- SwapFormKey.FromChain,
105
- SwapFormKey.ToChain,
106
- ]);
107
- const { isDirty: isFromChainDirty } = methods.getFieldState(SwapFormKey.FromChain, methods.formState);
108
- const { isDirty: isToChainDirty } = methods.getFieldState(SwapFormKey.ToChain, methods.formState);
109
- const { isDirty: isFromTokenDirty } = methods.getFieldState(SwapFormKey.FromToken, methods.formState);
110
- const { isDirty: isToTokenDirty } = methods.getFieldState(SwapFormKey.ToToken, methods.formState);
111
- const { chainOrder, setChain } = useChainOrderStore.getState();
112
- // Users can switch chains in the wallet.
113
- // If we don't have a chain in the ordered chain list we should add it.
114
- setChain(account.chainId);
115
- // If we ran out of slots for the ordered chain list and the current chain isn't there
116
- // we should make a recently switched chain as current.
117
- const hasFromChainInOrderedList = chainOrder.includes(fromChainValue);
118
- const hasToChainInOrderedList = chainOrder.includes(toChainValue);
119
- if ((!fromChain && !isFromChainDirty && !isFromTokenDirty) ||
120
- !hasFromChainInOrderedList) {
121
- methods.setValue(SwapFormKey.FromChain, account.chainId, {
122
- shouldDirty: false,
123
- });
124
- methods.setValue(SwapFormKey.FromToken, '', {
125
- shouldDirty: false,
126
- });
127
- methods.setValue(SwapFormKey.FromAmount, '', {
128
- shouldDirty: false,
129
- });
130
- }
131
- if ((!toChain && !isToChainDirty && !isToTokenDirty) ||
132
- !hasToChainInOrderedList) {
133
- methods.setValue(SwapFormKey.ToChain, account.chainId, {
134
- shouldDirty: false,
135
- });
136
- methods.setValue(SwapFormKey.ToToken, '', {
137
- shouldDirty: false,
138
- });
139
- }
140
- }, [
141
- account.chainId,
142
- account.isActive,
143
- chains,
144
- disabledChains,
145
- fromChain,
146
- methods,
147
- toChain,
148
- ]);
149
- return (_jsx(WalletContext.Provider, Object.assign({ value: value }, { children: children })));
94
+ return (_jsxs(WalletContext.Provider, Object.assign({ value: value }, { children: [_jsx(WalletFormUpdate, { account: account }), children] })));
150
95
  };
151
96
  export const extractAccountFromSigner = (signer) => __awaiter(void 0, void 0, void 0, function* () {
152
97
  try {
@@ -12,6 +12,7 @@ var __rest = (this && this.__rest) || function (s, e) {
12
12
  import { jsx as _jsx } from "react/jsx-runtime";
13
13
  import { getChainByKey } from '@lifi/sdk';
14
14
  import { createContext, useContext, useMemo } from 'react';
15
+ import { formatAmount } from '../../utils';
15
16
  const initialContext = {
16
17
  disabledChains: [],
17
18
  };
@@ -20,27 +21,33 @@ export const useWidgetConfig = () => useContext(WidgetContext);
20
21
  export const WidgetProvider = (_a) => {
21
22
  var { children } = _a, _b = _a.config, _c = _b === void 0 ? {} : _b, { fromChain, fromToken, toChain, toToken, fromAmount } = _c, config = __rest(_c, ["fromChain", "fromToken", "toChain", "toToken", "fromAmount"]);
22
23
  const value = useMemo(() => {
23
- var _a, _b, _c, _d;
24
+ var _a, _b, _c, _d, _e, _f;
24
25
  try {
25
26
  const searchParams = Object.fromEntries(new URLSearchParams(window === null || window === void 0 ? void 0 : window.location.search));
27
+ // Prevent using fromToken/toToken params if chain is not selected
28
+ ['from', 'to'].forEach((key) => {
29
+ if (searchParams[`${key}Token`] && !searchParams[`${key}Chain`]) {
30
+ delete searchParams[`${key}Token`];
31
+ }
32
+ });
26
33
  return Object.assign(Object.assign({}, config), { fromChain: (searchParams.fromChain &&
27
34
  isNaN(parseInt(searchParams.fromChain, 10))) ||
28
35
  typeof fromChain === 'string'
29
- ? getChainByKey((_a = (searchParams.fromChain || fromChain)) === null || _a === void 0 ? void 0 : _a.toLowerCase()).id
36
+ ? (_b = getChainByKey((_a = (searchParams.fromChain || fromChain)) === null || _a === void 0 ? void 0 : _a.toLowerCase())) === null || _b === void 0 ? void 0 : _b.id
30
37
  : (searchParams.fromChain &&
31
38
  !isNaN(parseInt(searchParams.fromChain, 10))) ||
32
39
  typeof fromChain === 'number'
33
40
  ? parseInt(searchParams.fromChain, 10) || fromChain
34
41
  : undefined, toChain: (searchParams.toChain && isNaN(parseInt(searchParams.toChain, 10))) ||
35
42
  typeof toChain === 'string'
36
- ? getChainByKey((_b = (searchParams.toChain || toChain)) === null || _b === void 0 ? void 0 : _b.toLowerCase()).id
43
+ ? (_d = getChainByKey((_c = (searchParams.toChain || toChain)) === null || _c === void 0 ? void 0 : _c.toLowerCase())) === null || _d === void 0 ? void 0 : _d.id
37
44
  : (searchParams.toChain &&
38
45
  !isNaN(parseInt(searchParams.toChain, 10))) ||
39
46
  typeof toChain === 'number'
40
47
  ? parseInt(searchParams.toChain, 10) || toChain
41
- : undefined, fromToken: ((_c = searchParams.fromToken) === null || _c === void 0 ? void 0 : _c.toLowerCase()) || (fromToken === null || fromToken === void 0 ? void 0 : fromToken.toLowerCase()), toToken: ((_d = searchParams.toToken) === null || _d === void 0 ? void 0 : _d.toLowerCase()) || (toToken === null || toToken === void 0 ? void 0 : toToken.toLowerCase()), fromAmount: typeof searchParams.fromAmount === 'string' &&
48
+ : undefined, fromToken: ((_e = searchParams.fromToken) === null || _e === void 0 ? void 0 : _e.toLowerCase()) || (fromToken === null || fromToken === void 0 ? void 0 : fromToken.toLowerCase()), toToken: ((_f = searchParams.toToken) === null || _f === void 0 ? void 0 : _f.toLowerCase()) || (toToken === null || toToken === void 0 ? void 0 : toToken.toLowerCase()), fromAmount: typeof searchParams.fromAmount === 'string' &&
42
49
  !isNaN(parseFloat(searchParams.fromAmount))
43
- ? searchParams.fromAmount
50
+ ? formatAmount(searchParams.fromAmount)
44
51
  : fromAmount });
45
52
  }
46
53
  catch (e) {
@@ -1,7 +1,7 @@
1
1
  export * from './types';
2
2
  export * from './useExecutingRoutesIds';
3
+ export * from './useRecommendedRouteStore';
3
4
  export * from './useRouteExecutionStore';
4
- export * from './useSelectedRouteStore';
5
5
  export * from './useSetExecutableRoute';
6
6
  export * from './useSwapHistory';
7
7
  export * from './utils';
@@ -1,7 +1,7 @@
1
1
  export * from './types';
2
2
  export * from './useExecutingRoutesIds';
3
+ export * from './useRecommendedRouteStore';
3
4
  export * from './useRouteExecutionStore';
4
- export * from './useSelectedRouteStore';
5
5
  export * from './useSetExecutableRoute';
6
6
  export * from './useSwapHistory';
7
7
  export * from './utils';
@@ -5,14 +5,14 @@ export interface RouteExecutionStore {
5
5
  updateRoute: (route: Route) => void;
6
6
  restartRoute: (routeId: string) => void;
7
7
  deleteRoute: (routeId: string) => void;
8
- deleteRoutes: () => void;
8
+ deleteRoutes: (type: 'completed' | 'active') => void;
9
9
  }
10
- export declare type RouteExecutionStatus = 'error' | 'idle' | 'loading' | 'success';
10
+ export declare type RouteExecutionStatus = 'error' | 'idle' | 'loading' | 'success' | 'warning';
11
11
  export interface RouteExecution {
12
12
  route: Route;
13
13
  status: RouteExecutionStatus;
14
14
  }
15
- export interface SelectedRouteStore {
16
- selectedRoute?: Route;
17
- setSelectedRoute: (route?: Route) => void;
15
+ export interface RecommendedRouteStore {
16
+ recommendedRoute?: Route;
17
+ setRecommendedRoute: (route?: Route) => void;
18
18
  }
@@ -0,0 +1,4 @@
1
+ import type { RecommendedRouteStore } from './types';
2
+ export declare const useRecommendedRouteStore: import("zustand").UseBoundStore<Omit<import("zustand").StoreApi<RecommendedRouteStore>, "setState"> & {
3
+ setState(nextStateOrUpdater: RecommendedRouteStore | Partial<RecommendedRouteStore> | ((state: import("immer/dist/internal").WritableDraft<RecommendedRouteStore>) => void), shouldReplace?: boolean | undefined): void;
4
+ }>;
@@ -0,0 +1,9 @@
1
+ import create from 'zustand';
2
+ import { immer } from 'zustand/middleware/immer';
3
+ export const useRecommendedRouteStore = create()(immer((set) => ({
4
+ setRecommendedRoute: (route) => {
5
+ set((state) => {
6
+ state.recommendedRoute = route;
7
+ });
8
+ },
9
+ })));
@@ -43,8 +43,15 @@ export const useRouteExecutionStore = create()(persist(immer((set) => ({
43
43
  delete state.routes[routeId];
44
44
  }
45
45
  }),
46
- deleteRoutes: () => set((state) => {
47
- state.routes = {};
46
+ deleteRoutes: (type) => set((state) => {
47
+ Object.keys(state.routes)
48
+ .filter((routeId) => {
49
+ var _a, _b;
50
+ return type === 'completed'
51
+ ? ((_a = state.routes[routeId]) === null || _a === void 0 ? void 0 : _a.status) === 'success'
52
+ : ((_b = state.routes[routeId]) === null || _b === void 0 ? void 0 : _b.status) !== 'success';
53
+ })
54
+ .forEach((routeId) => delete state.routes[routeId]);
48
55
  }),
49
56
  })), {
50
57
  name: 'li.fi-widget-routes',