@lifi/widget 4.10.0 → 4.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 (50) hide show
  1. package/README.md +2 -7
  2. package/dist/esm/config/version.d.ts +1 -1
  3. package/dist/esm/config/version.js +1 -1
  4. package/dist/esm/config/version.js.map +1 -1
  5. package/dist/esm/hooks/usePacedValue.js +1 -1
  6. package/dist/esm/hooks/usePacedValue.js.map +1 -1
  7. package/dist/esm/hooks/useRouteExecutionMessage.d.ts.map +1 -1
  8. package/dist/esm/hooks/useRouteExecutionMessage.js +4 -8
  9. package/dist/esm/hooks/useRouteExecutionMessage.js.map +1 -1
  10. package/dist/esm/i18n/bn.json +567 -270
  11. package/dist/esm/i18n/de.json +552 -255
  12. package/dist/esm/i18n/en.json +7 -61
  13. package/dist/esm/i18n/es.json +522 -225
  14. package/dist/esm/i18n/fr.json +541 -244
  15. package/dist/esm/i18n/hi.json +592 -295
  16. package/dist/esm/i18n/id.json +485 -188
  17. package/dist/esm/i18n/it.json +546 -249
  18. package/dist/esm/i18n/ja.json +512 -215
  19. package/dist/esm/i18n/ko.json +553 -256
  20. package/dist/esm/i18n/pl.json +598 -301
  21. package/dist/esm/i18n/pt.json +512 -215
  22. package/dist/esm/i18n/th.json +554 -257
  23. package/dist/esm/i18n/tr.json +538 -241
  24. package/dist/esm/i18n/uk.json +514 -217
  25. package/dist/esm/i18n/vi.json +550 -253
  26. package/dist/esm/i18n/zh.json +528 -231
  27. package/dist/esm/pages/TransactionPage/TransactionFailedButtons.js +70 -18
  28. package/dist/esm/pages/TransactionPage/TransactionFailedButtons.js.map +1 -1
  29. package/dist/esm/pages/TransactionPage/utils.d.ts +3 -0
  30. package/dist/esm/pages/TransactionPage/utils.d.ts.map +1 -1
  31. package/dist/esm/pages/TransactionPage/utils.js +27 -1
  32. package/dist/esm/pages/TransactionPage/utils.js.map +1 -1
  33. package/dist/esm/shared.d.ts +2 -2
  34. package/dist/esm/shared.js +2 -2
  35. package/dist/esm/stores/routes/utils.d.ts +1 -1
  36. package/dist/esm/stores/routes/utils.d.ts.map +1 -1
  37. package/dist/esm/stores/routes/utils.js +13 -1
  38. package/dist/esm/stores/routes/utils.js.map +1 -1
  39. package/dist/esm/utils/getErrorMessage.js +4 -0
  40. package/dist/esm/utils/getErrorMessage.js.map +1 -1
  41. package/package.json +4 -4
  42. package/src/config/version.ts +1 -1
  43. package/src/hooks/usePacedValue.ts +1 -1
  44. package/src/hooks/useRouteExecutionMessage.ts +10 -13
  45. package/src/pages/TransactionPage/TransactionFailedButtons.test.tsx +497 -0
  46. package/src/pages/TransactionPage/TransactionFailedButtons.tsx +78 -9
  47. package/src/pages/TransactionPage/utils.ts +81 -0
  48. package/src/shared.ts +1 -0
  49. package/src/stores/routes/utils.ts +24 -1
  50. package/src/utils/getErrorMessage.ts +5 -0
@@ -1,14 +1,19 @@
1
1
  import { useWidgetEvents } from "../../hooks/useWidgetEvents.js";
2
2
  import "../../types/events.js";
3
3
  import { useWidgetConfig } from "../../providers/WidgetProvider/WidgetProvider.js";
4
+ import { navigationRoutes } from "../../utils/navigationRoutes.js";
5
+ import { useSwapOnly } from "../../hooks/useSwapOnly.js";
6
+ import { useBookmarkActions } from "../../stores/bookmarks/useBookmarkActions.js";
7
+ import { useFieldActions } from "../../stores/form/useFieldActions.js";
4
8
  import { getAccumulatedFeeCostsBreakdown } from "../../utils/fees.js";
5
9
  import { useNavigateBack } from "../../hooks/useNavigateBack.js";
6
10
  import { useAddressActivity } from "../../hooks/useAddressActivity.js";
7
11
  import { ConfirmToAddressSheet } from "./ConfirmToAddressSheet.js";
8
12
  import { StartTransactionButton } from "./StartTransactionButton.js";
9
- import { calculateValueLossPercentage, getRetryGates, getTokenValueLossThreshold, openNextGate } from "./utils.js";
13
+ import { calculateValueLossPercentage, canStartNewSwap, getNewSwapFormValues, getRetryGates, getTokenValueLossThreshold, isCallBundleNotFound, openNextGate } from "./utils.js";
10
14
  import { TokenValueBottomSheet } from "./TokenValueBottomSheet.js";
11
15
  import { useRef } from "react";
16
+ import { useNavigate } from "@tanstack/react-router";
12
17
  import { Box, Button } from "@mui/material";
13
18
  import { jsx, jsxs } from "react/jsx-runtime";
14
19
  import { useTranslation } from "react-i18next";
@@ -17,7 +22,11 @@ const TransactionFailedButtons = ({ route, restartRoute, deleteRoute }) => {
17
22
  const { t } = useTranslation();
18
23
  const emitter = useWidgetEvents();
19
24
  const navigateBack = useNavigateBack();
20
- const { mode, hiddenUI } = useWidgetConfig();
25
+ const navigate = useNavigate();
26
+ const { mode, hiddenUI, disabledUI, requiredUI } = useWidgetConfig();
27
+ const swapOnly = useSwapOnly();
28
+ const { setFieldValue, getFieldValues } = useFieldActions();
29
+ const { setSelectedBookmark, getSelectedBookmark } = useBookmarkActions();
21
30
  const tokenValueBottomSheetRef = useRef(null);
22
31
  const confirmToAddressSheetRef = useRef(null);
23
32
  const { toAddress, hasActivity, isLoading: isLoadingAddressActivity, isFetched: isActivityAddressFetched } = useAddressActivity(route.toChainId);
@@ -25,6 +34,36 @@ const TransactionFailedButtons = ({ route, restartRoute, deleteRoute }) => {
25
34
  navigateBack();
26
35
  deleteRoute();
27
36
  };
37
+ const callBundleNotFound = isCallBundleNotFound(route);
38
+ const showStartNewSwap = callBundleNotFound && canStartNewSwap({
39
+ route,
40
+ mode,
41
+ swapOnly
42
+ });
43
+ const showRetry = !callBundleNotFound;
44
+ const handleStartNewSwap = () => {
45
+ const [formReceiver] = getFieldValues("toAddress");
46
+ const keepReceiver = Boolean((disabledUI?.toAddress || hiddenUI?.toAddress) && formReceiver);
47
+ const values = getNewSwapFormValues(route, {
48
+ keepReceiver,
49
+ receiverRequired: requiredUI?.toAddress
50
+ });
51
+ const fieldNames = Object.keys(values);
52
+ const receiver = keepReceiver ? formReceiver : values.toAddress;
53
+ navigate({
54
+ to: navigationRoutes.home,
55
+ replace: true
56
+ }).then(() => {
57
+ for (const fieldName of fieldNames) setFieldValue(fieldName, values[fieldName], {
58
+ isDirty: true,
59
+ isTouched: true
60
+ });
61
+ if (getSelectedBookmark()?.address.toLowerCase() !== receiver?.toLowerCase()) setSelectedBookmark();
62
+ }).catch((error) => {
63
+ console.warn("Filling the new swap failed.", error);
64
+ });
65
+ deleteRoute();
66
+ };
28
67
  const retryGates = (() => {
29
68
  const { gasCostUSD, feeCostUSD } = getAccumulatedFeeCostsBreakdown(route);
30
69
  return getRetryGates({
@@ -71,22 +110,35 @@ const TransactionFailedButtons = ({ route, restartRoute, deleteRoute }) => {
71
110
  display: "flex",
72
111
  gap: 1.5
73
112
  },
74
- children: [/* @__PURE__ */ jsx(Box, {
75
- sx: { flex: 1 },
76
- children: /* @__PURE__ */ jsx(Button, {
77
- onClick: handleRemoveRoute,
78
- fullWidth: true,
79
- children: t("button.delete")
80
- })
81
- }), /* @__PURE__ */ jsx(Box, {
82
- sx: { flex: 1 },
83
- children: /* @__PURE__ */ jsx(StartTransactionButton, {
84
- text: t("button.tryAgain"),
85
- onClick: handleRetryClick,
86
- route,
87
- loading: isLoadingAddressActivity
88
- })
89
- })]
113
+ children: [
114
+ /* @__PURE__ */ jsx(Box, {
115
+ sx: { flex: 1 },
116
+ children: /* @__PURE__ */ jsx(Button, {
117
+ onClick: handleRemoveRoute,
118
+ fullWidth: true,
119
+ children: t("button.delete")
120
+ })
121
+ }),
122
+ showStartNewSwap ? /* @__PURE__ */ jsx(Box, {
123
+ sx: { flex: 1 },
124
+ children: /* @__PURE__ */ jsx(Button, {
125
+ variant: "contained",
126
+ color: "primary",
127
+ onClick: handleStartNewSwap,
128
+ fullWidth: true,
129
+ children: t("button.startNewSwap")
130
+ })
131
+ }) : null,
132
+ showRetry ? /* @__PURE__ */ jsx(Box, {
133
+ sx: { flex: 1 },
134
+ children: /* @__PURE__ */ jsx(StartTransactionButton, {
135
+ text: t("button.tryAgain"),
136
+ onClick: handleRetryClick,
137
+ route,
138
+ loading: isLoadingAddressActivity
139
+ })
140
+ }) : null
141
+ ]
90
142
  }),
91
143
  mode !== "custom" ? /* @__PURE__ */ jsx(TokenValueBottomSheet, {
92
144
  route,
@@ -1 +1 @@
1
- {"version":3,"file":"TransactionFailedButtons.js","names":[],"sources":["../../../../src/pages/TransactionPage/TransactionFailedButtons.tsx"],"sourcesContent":["import type { RouteExtended } from '@lifi/sdk'\nimport { Box, Button } from '@mui/material'\nimport { useRef } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport type { BottomSheetBase } from '../../components/BottomSheet/types.js'\nimport { useAddressActivity } from '../../hooks/useAddressActivity.js'\nimport { useNavigateBack } from '../../hooks/useNavigateBack.js'\nimport { useWidgetEvents } from '../../hooks/useWidgetEvents.js'\nimport { useWidgetConfig } from '../../providers/WidgetProvider/WidgetProvider.js'\nimport { WidgetEvent } from '../../types/events.js'\nimport { getAccumulatedFeeCostsBreakdown } from '../../utils/fees.js'\nimport { ConfirmToAddressSheet } from './ConfirmToAddressSheet.js'\nimport { StartTransactionButton } from './StartTransactionButton.js'\nimport { TokenValueBottomSheet } from './TokenValueBottomSheet.js'\nimport type { RetryGate } from './utils.js'\nimport {\n calculateValueLossPercentage,\n getRetryGates,\n getTokenValueLossThreshold,\n openNextGate,\n} from './utils.js'\n\ninterface TransactionFailedButtonsProps {\n route: RouteExtended\n restartRoute: () => void\n deleteRoute: () => void\n}\n\nexport const TransactionFailedButtons: React.FC<\n TransactionFailedButtonsProps\n> = ({ route, restartRoute, deleteRoute }) => {\n const { t } = useTranslation()\n const emitter = useWidgetEvents()\n const navigateBack = useNavigateBack()\n const { mode, hiddenUI } = useWidgetConfig()\n\n const tokenValueBottomSheetRef = useRef<BottomSheetBase>(null)\n const confirmToAddressSheetRef = useRef<BottomSheetBase>(null)\n\n const {\n toAddress,\n hasActivity,\n isLoading: isLoadingAddressActivity,\n isFetched: isActivityAddressFetched,\n } = useAddressActivity(route.toChainId)\n\n const handleRemoveRoute = () => {\n navigateBack()\n deleteRoute()\n }\n\n const retryGates = (() => {\n const { gasCostUSD, feeCostUSD } = getAccumulatedFeeCostsBreakdown(route)\n return getRetryGates({\n toAddress,\n hasActivity,\n isLoadingAddressActivity,\n isActivityAddressFetched,\n confirmationHidden: Boolean(hiddenUI?.lowAddressActivityConfirmation),\n valueLossExceeded: getTokenValueLossThreshold(\n Number.parseFloat(route.fromAmountUSD),\n Number.parseFloat(route.toAmountUSD),\n gasCostUSD,\n feeCostUSD\n ),\n isCustomMode: mode === 'custom',\n })\n })()\n\n const openGate = (after?: RetryGate) =>\n openNextGate(\n retryGates,\n {\n address: () => confirmToAddressSheetRef.current?.open(),\n value: () => tokenValueBottomSheetRef.current?.open(),\n },\n handleRestartRoute,\n after\n )\n\n const handleRestartRoute = () => {\n if (tokenValueBottomSheetRef.current?.isOpen()) {\n const { gasCostUSD, feeCostUSD } = getAccumulatedFeeCostsBreakdown(route)\n const fromAmountUSD = Number.parseFloat(route.fromAmountUSD)\n const toAmountUSD = Number.parseFloat(route.toAmountUSD)\n emitter.emit(WidgetEvent.RouteHighValueLoss, {\n fromAmountUSD,\n toAmountUSD,\n gasCostUSD,\n feeCostUSD,\n valueLoss: calculateValueLossPercentage(\n fromAmountUSD,\n toAmountUSD,\n gasCostUSD,\n feeCostUSD\n ),\n })\n }\n tokenValueBottomSheetRef.current?.close()\n restartRoute()\n }\n\n const handleRetryClick = () => openGate()\n\n const handleConfirmToAddressContinue = () => openGate('address')\n\n return (\n <Box sx={{ display: 'flex', flexDirection: 'column', gap: 1.5 }}>\n <Box sx={{ display: 'flex', gap: 1.5 }}>\n <Box sx={{ flex: 1 }}>\n <Button onClick={handleRemoveRoute} fullWidth>\n {t('button.delete')}\n </Button>\n </Box>\n <Box sx={{ flex: 1 }}>\n <StartTransactionButton\n text={t('button.tryAgain')}\n onClick={handleRetryClick}\n route={route}\n loading={isLoadingAddressActivity}\n />\n </Box>\n </Box>\n {mode !== 'custom' ? (\n <TokenValueBottomSheet\n route={route}\n ref={tokenValueBottomSheetRef}\n onContinue={handleRestartRoute}\n />\n ) : null}\n {!hiddenUI?.lowAddressActivityConfirmation ? (\n <ConfirmToAddressSheet\n ref={confirmToAddressSheetRef}\n onContinue={handleConfirmToAddressContinue}\n toAddress={toAddress!}\n toChainId={route.toChainId!}\n />\n ) : null}\n </Box>\n )\n}\n"],"mappings":";;;;;;;;;;;;;;;AA4BA,MAAa,4BAER,EAAE,OAAO,cAAc,kBAAkB;CAC5C,MAAM,EAAE,MAAM,eAAe;CAC7B,MAAM,UAAU,gBAAgB;CAChC,MAAM,eAAe,gBAAgB;CACrC,MAAM,EAAE,MAAM,aAAa,gBAAgB;CAE3C,MAAM,2BAA2B,OAAwB,IAAI;CAC7D,MAAM,2BAA2B,OAAwB,IAAI;CAE7D,MAAM,EACJ,WACA,aACA,WAAW,0BACX,WAAW,6BACT,mBAAmB,MAAM,SAAS;CAEtC,MAAM,0BAA0B;EAC9B,aAAa;EACb,YAAY;CACd;CAEA,MAAM,oBAAoB;EACxB,MAAM,EAAE,YAAY,eAAe,gCAAgC,KAAK;EACxE,OAAO,cAAc;GACnB;GACA;GACA;GACA;GACA,oBAAoB,QAAQ,UAAU,8BAA8B;GACpE,mBAAmB,2BACjB,OAAO,WAAW,MAAM,aAAa,GACrC,OAAO,WAAW,MAAM,WAAW,GACnC,YACA,UACF;GACA,cAAc,SAAS;EACzB,CAAC;CACH,EAAA,CAAG;CAEH,MAAM,YAAY,UAChB,aACE,YACA;EACE,eAAe,yBAAyB,SAAS,KAAK;EACtD,aAAa,yBAAyB,SAAS,KAAK;CACtD,GACA,oBACA,KACF;CAEF,MAAM,2BAA2B;EAC/B,IAAI,yBAAyB,SAAS,OAAO,GAAG;GAC9C,MAAM,EAAE,YAAY,eAAe,gCAAgC,KAAK;GACxE,MAAM,gBAAgB,OAAO,WAAW,MAAM,aAAa;GAC3D,MAAM,cAAc,OAAO,WAAW,MAAM,WAAW;GACvD,QAAQ,KAAA,sBAAqC;IAC3C;IACA;IACA;IACA;IACA,WAAW,6BACT,eACA,aACA,YACA,UACF;GACF,CAAC;EACH;EACA,yBAAyB,SAAS,MAAM;EACxC,aAAa;CACf;CAEA,MAAM,yBAAyB,SAAS;CAExC,MAAM,uCAAuC,SAAS,SAAS;CAE/D,OACE,qBAAC,KAAD;EAAK,IAAI;GAAE,SAAS;GAAQ,eAAe;GAAU,KAAK;EAAI;EAA9D,UAAA;GACE,qBAAC,KAAD;IAAK,IAAI;KAAE,SAAS;KAAQ,KAAK;IAAI;IAArC,UAAA,CACE,oBAAC,KAAD;KAAK,IAAI,EAAE,MAAM,EAAE;KACjB,UAAA,oBAAC,QAAD;MAAQ,SAAS;MAAmB,WAAA;MACjC,UAAA,EAAE,eAAe;KACZ,CAAA;IACL,CAAA,GACL,oBAAC,KAAD;KAAK,IAAI,EAAE,MAAM,EAAE;KACjB,UAAA,oBAAC,wBAAD;MACE,MAAM,EAAE,iBAAiB;MACzB,SAAS;MACF;MACP,SAAS;KACV,CAAA;IACE,CAAA,CACF;;GACJ,SAAS,WACR,oBAAC,uBAAD;IACS;IACP,KAAK;IACL,YAAY;GACb,CAAA,IACC;GACH,CAAC,UAAU,iCACV,oBAAC,uBAAD;IACE,KAAK;IACL,YAAY;IACD;IACX,WAAW,MAAM;GAClB,CAAA,IACC;EACD;;AAET"}
1
+ {"version":3,"file":"TransactionFailedButtons.js","names":[],"sources":["../../../../src/pages/TransactionPage/TransactionFailedButtons.tsx"],"sourcesContent":["import type { RouteExtended } from '@lifi/sdk'\nimport { Box, Button } from '@mui/material'\nimport { useNavigate } from '@tanstack/react-router'\nimport { useRef } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport type { BottomSheetBase } from '../../components/BottomSheet/types.js'\nimport { useAddressActivity } from '../../hooks/useAddressActivity.js'\nimport { useNavigateBack } from '../../hooks/useNavigateBack.js'\nimport { useSwapOnly } from '../../hooks/useSwapOnly.js'\nimport { useWidgetEvents } from '../../hooks/useWidgetEvents.js'\nimport { useWidgetConfig } from '../../providers/WidgetProvider/WidgetProvider.js'\nimport { useBookmarkActions } from '../../stores/bookmarks/useBookmarkActions.js'\nimport { useFieldActions } from '../../stores/form/useFieldActions.js'\nimport { WidgetEvent } from '../../types/events.js'\nimport { getAccumulatedFeeCostsBreakdown } from '../../utils/fees.js'\nimport { navigationRoutes } from '../../utils/navigationRoutes.js'\nimport { ConfirmToAddressSheet } from './ConfirmToAddressSheet.js'\nimport { StartTransactionButton } from './StartTransactionButton.js'\nimport { TokenValueBottomSheet } from './TokenValueBottomSheet.js'\nimport type { RetryGate } from './utils.js'\nimport {\n calculateValueLossPercentage,\n canStartNewSwap,\n getNewSwapFormValues,\n getRetryGates,\n getTokenValueLossThreshold,\n isCallBundleNotFound,\n openNextGate,\n} from './utils.js'\n\ninterface TransactionFailedButtonsProps {\n route: RouteExtended\n restartRoute: () => void\n deleteRoute: () => void\n}\n\nexport const TransactionFailedButtons: React.FC<\n TransactionFailedButtonsProps\n> = ({ route, restartRoute, deleteRoute }) => {\n const { t } = useTranslation()\n const emitter = useWidgetEvents()\n const navigateBack = useNavigateBack()\n const navigate = useNavigate()\n const { mode, hiddenUI, disabledUI, requiredUI } = useWidgetConfig()\n const swapOnly = useSwapOnly()\n const { setFieldValue, getFieldValues } = useFieldActions()\n const { setSelectedBookmark, getSelectedBookmark } = useBookmarkActions()\n\n const tokenValueBottomSheetRef = useRef<BottomSheetBase>(null)\n const confirmToAddressSheetRef = useRef<BottomSheetBase>(null)\n\n const {\n toAddress,\n hasActivity,\n isLoading: isLoadingAddressActivity,\n isFetched: isActivityAddressFetched,\n } = useAddressActivity(route.toChainId)\n\n const handleRemoveRoute = () => {\n navigateBack()\n deleteRoute()\n }\n\n const callBundleNotFound = isCallBundleNotFound(route)\n const showStartNewSwap =\n callBundleNotFound && canStartNewSwap({ route, mode, swapOnly })\n // Try again would only wait for the same bundle again.\n const showRetry = !callBundleNotFound\n\n // Home, not back: after a reload, the route is opened from Activities.\n const handleStartNewSwap = () => {\n // An empty hidden or locked field still needs the route's receiver.\n const [formReceiver] = getFieldValues('toAddress')\n const keepReceiver = Boolean(\n (disabledUI?.toAddress || hiddenUI?.toAddress) && formReceiver\n )\n const values = getNewSwapFormValues(route, {\n keepReceiver,\n receiverRequired: requiredUI?.toAddress,\n })\n const fieldNames = Object.keys(values) as (keyof typeof values)[]\n const receiver = keepReceiver ? formReceiver : values.toAddress\n // Fill after navigate resolves: this page's unmount cleanup has run by then,\n // as TransactionFailedButtons.test.tsx checks.\n navigate({ to: navigationRoutes.home, replace: true })\n .then(() => {\n for (const fieldName of fieldNames) {\n setFieldValue(fieldName, values[fieldName], {\n isDirty: true,\n isTouched: true,\n })\n }\n // A bookmark name from an earlier receiver must not label this one.\n if (\n getSelectedBookmark()?.address.toLowerCase() !==\n receiver?.toLowerCase()\n ) {\n setSelectedBookmark()\n }\n })\n .catch((error) => {\n console.warn('Filling the new swap failed.', error)\n })\n deleteRoute()\n }\n\n const retryGates = (() => {\n const { gasCostUSD, feeCostUSD } = getAccumulatedFeeCostsBreakdown(route)\n return getRetryGates({\n toAddress,\n hasActivity,\n isLoadingAddressActivity,\n isActivityAddressFetched,\n confirmationHidden: Boolean(hiddenUI?.lowAddressActivityConfirmation),\n valueLossExceeded: getTokenValueLossThreshold(\n Number.parseFloat(route.fromAmountUSD),\n Number.parseFloat(route.toAmountUSD),\n gasCostUSD,\n feeCostUSD\n ),\n isCustomMode: mode === 'custom',\n })\n })()\n\n const openGate = (after?: RetryGate) =>\n openNextGate(\n retryGates,\n {\n address: () => confirmToAddressSheetRef.current?.open(),\n value: () => tokenValueBottomSheetRef.current?.open(),\n },\n handleRestartRoute,\n after\n )\n\n const handleRestartRoute = () => {\n if (tokenValueBottomSheetRef.current?.isOpen()) {\n const { gasCostUSD, feeCostUSD } = getAccumulatedFeeCostsBreakdown(route)\n const fromAmountUSD = Number.parseFloat(route.fromAmountUSD)\n const toAmountUSD = Number.parseFloat(route.toAmountUSD)\n emitter.emit(WidgetEvent.RouteHighValueLoss, {\n fromAmountUSD,\n toAmountUSD,\n gasCostUSD,\n feeCostUSD,\n valueLoss: calculateValueLossPercentage(\n fromAmountUSD,\n toAmountUSD,\n gasCostUSD,\n feeCostUSD\n ),\n })\n }\n tokenValueBottomSheetRef.current?.close()\n restartRoute()\n }\n\n const handleRetryClick = () => openGate()\n\n const handleConfirmToAddressContinue = () => openGate('address')\n\n return (\n <Box sx={{ display: 'flex', flexDirection: 'column', gap: 1.5 }}>\n <Box sx={{ display: 'flex', gap: 1.5 }}>\n <Box sx={{ flex: 1 }}>\n <Button onClick={handleRemoveRoute} fullWidth>\n {t('button.delete')}\n </Button>\n </Box>\n {showStartNewSwap ? (\n <Box sx={{ flex: 1 }}>\n <Button\n variant=\"contained\"\n color=\"primary\"\n onClick={handleStartNewSwap}\n fullWidth\n >\n {t('button.startNewSwap')}\n </Button>\n </Box>\n ) : null}\n {showRetry ? (\n <Box sx={{ flex: 1 }}>\n <StartTransactionButton\n text={t('button.tryAgain')}\n onClick={handleRetryClick}\n route={route}\n loading={isLoadingAddressActivity}\n />\n </Box>\n ) : null}\n </Box>\n {mode !== 'custom' ? (\n <TokenValueBottomSheet\n route={route}\n ref={tokenValueBottomSheetRef}\n onContinue={handleRestartRoute}\n />\n ) : null}\n {!hiddenUI?.lowAddressActivityConfirmation ? (\n <ConfirmToAddressSheet\n ref={confirmToAddressSheetRef}\n onContinue={handleConfirmToAddressContinue}\n toAddress={toAddress!}\n toChainId={route.toChainId!}\n />\n ) : null}\n </Box>\n )\n}\n"],"mappings":"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"}
@@ -1,5 +1,8 @@
1
+ import "../../types/widget.js";
2
+ import { RouteExtended } from "@lifi/sdk";
1
3
  //#region src/pages/TransactionPage/utils.d.ts
2
4
  export declare const calculateValueLossPercentage: (fromAmountUSD: number, toAmountUSD: number, gasCostUSD: number, feeCostUSD: number) => number;
3
5
  export declare const getTokenValueLossThreshold: (fromAmountUSD: number, toAmountUSD: number, gasCostUSD: number, feeCostUSD: number) => boolean;
6
+ export declare const isCallBundleNotFound: (route: RouteExtended) => boolean;
4
7
  //#endregion
5
8
  //# sourceMappingURL=utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","names":[],"sources":["../../../../src/pages/TransactionPage/utils.ts"],"mappings":";qBAAa,+BACX,uBACA,qBACA,oBACA;qBAUW,6BACX,uBACA,qBACA,oBACA"}
1
+ {"version":3,"file":"utils.d.ts","names":[],"sources":["../../../../src/pages/TransactionPage/utils.ts"],"mappings":";;;qBAKa,+BACX,uBACA,qBACA,oBACA;qBAUW,6BACX,uBACA,qBACA,oBACA;qBA6FW,uBAAwB,OAAO"}
@@ -1,3 +1,6 @@
1
+ import { formatTokenAmount } from "../../utils/format.js";
2
+ import { getFailedStepAction } from "../../stores/routes/utils.js";
3
+ import { LiFiErrorCode } from "@lifi/sdk";
1
4
  //#region src/pages/TransactionPage/utils.ts
2
5
  const calculateValueLossPercentage = (fromAmountUSD, toAmountUSD, gasCostUSD, feeCostUSD) => {
3
6
  return Number.parseFloat(((toAmountUSD / (fromAmountUSD + gasCostUSD + feeCostUSD) - 1) * 100).toFixed(2));
@@ -28,7 +31,30 @@ const getStartGates = (input) => [
28
31
  ["address", needsAddressConfirmation(input)],
29
32
  ["value", input.valueLossExceeded && !input.isCustomMode]
30
33
  ];
34
+ const newSwapModes = [
35
+ void 0,
36
+ "default",
37
+ "split"
38
+ ];
39
+ const isCallBundleNotFound = (route) => getFailedStepAction(route)?.action.error?.code === LiFiErrorCode.CallBundleNotFound;
40
+ const canStartNewSwap = ({ route, mode, swapOnly }) => {
41
+ const failed = getFailedStepAction(route);
42
+ if (!failed || !isCallBundleNotFound(route)) return false;
43
+ return failed.step === route.steps[0] && route.steps.every((step) => step === failed.step || !step.execution?.actions?.length) && newSwapModes.includes(mode) && !(swapOnly && route.fromChainId !== route.toChainId);
44
+ };
45
+ const getNewSwapFormValues = (route, { keepReceiver = false, receiverRequired = false } = {}) => {
46
+ const receiver = route.toAddress || route.fromAddress;
47
+ const values = {
48
+ fromChain: route.fromChainId,
49
+ fromToken: route.fromToken.address,
50
+ fromAmount: formatTokenAmount(BigInt(route.fromAmount), route.fromToken.decimals),
51
+ toChain: route.toChainId,
52
+ toToken: route.toToken.address
53
+ };
54
+ if (!keepReceiver) values.toAddress = receiver && (receiverRequired || receiver.toLowerCase() !== route.fromAddress?.toLowerCase()) ? receiver : "";
55
+ return values;
56
+ };
31
57
  //#endregion
32
- export { calculateValueLossPercentage, getRetryGates, getStartGates, getTokenValueLossThreshold, nextGate, openNextGate };
58
+ export { calculateValueLossPercentage, canStartNewSwap, getNewSwapFormValues, getRetryGates, getStartGates, getTokenValueLossThreshold, isCallBundleNotFound, nextGate, openNextGate };
33
59
 
34
60
  //# sourceMappingURL=utils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","names":[],"sources":["../../../../src/pages/TransactionPage/utils.ts"],"sourcesContent":["export const calculateValueLossPercentage = (\n fromAmountUSD: number,\n toAmountUSD: number,\n gasCostUSD: number,\n feeCostUSD: number\n): number => {\n return Number.parseFloat(\n (\n (toAmountUSD / (fromAmountUSD + gasCostUSD + feeCostUSD) - 1) *\n 100\n ).toFixed(2)\n )\n}\n\nexport const getTokenValueLossThreshold = (\n fromAmountUSD: number,\n toAmountUSD: number,\n gasCostUSD: number,\n feeCostUSD: number\n): boolean => {\n if (!fromAmountUSD || !toAmountUSD) {\n return false\n }\n return toAmountUSD / (fromAmountUSD + gasCostUSD + feeCostUSD) < 0.9\n}\n\ninterface AddressGateInput {\n toAddress: string | undefined\n hasActivity: boolean | undefined\n isLoadingAddressActivity: boolean\n isActivityAddressFetched: boolean\n confirmationHidden: boolean\n}\n\nconst needsAddressConfirmation = ({\n toAddress,\n hasActivity,\n isLoadingAddressActivity,\n isActivityAddressFetched,\n confirmationHidden,\n}: AddressGateInput): boolean =>\n Boolean(\n toAddress &&\n !hasActivity &&\n !isLoadingAddressActivity &&\n isActivityAddressFetched &&\n !confirmationHidden\n )\n\nexport type RetryGate = 'address' | 'value'\n\nexport const getRetryGates = (\n input: AddressGateInput & {\n valueLossExceeded: boolean\n isCustomMode: boolean\n }\n): readonly (readonly [gate: RetryGate, needed: boolean])[] => [\n ['address', needsAddressConfirmation(input)],\n ['value', input.valueLossExceeded && !input.isCustomMode],\n]\n\n/** Ordering lives here so no sheet decides what follows it — that is how gates came to be skipped. */\nexport const nextGate = <T extends string>(\n gates: readonly (readonly [gate: T, needed: boolean])[],\n after?: T\n): T | undefined => {\n if (!after) {\n return gates.find(([, needed]) => needed)?.[0]\n }\n const index = gates.findIndex(([gate]) => gate === after)\n if (index < 0) {\n return undefined\n }\n return gates.slice(index + 1).find(([, needed]) => needed)?.[0]\n}\n\nexport const openNextGate = <T extends string>(\n gates: readonly (readonly [gate: T, needed: boolean])[],\n open: Record<T, () => void>,\n done: () => void,\n after?: T\n): void => {\n const gate = nextGate(gates, after)\n if (gate) {\n open[gate]()\n return\n }\n done()\n}\n\nexport type StartGate = 'flagged' | 'address' | 'value'\n\nexport const getStartGates = (\n input: AddressGateInput & {\n flaggedTokenCount: number\n valueLossExceeded: boolean\n isCustomMode: boolean\n }\n): readonly (readonly [gate: StartGate, needed: boolean])[] => [\n ['flagged', input.flaggedTokenCount > 0],\n ['address', needsAddressConfirmation(input)],\n ['value', input.valueLossExceeded && !input.isCustomMode],\n]\n"],"mappings":";AAAA,MAAa,gCACX,eACA,aACA,YACA,eACW;CACX,OAAO,OAAO,aAET,eAAe,gBAAgB,aAAa,cAAc,KAC3D,IAAA,CACA,QAAQ,CAAC,CACb;AACF;AAEA,MAAa,8BACX,eACA,aACA,YACA,eACY;CACZ,IAAI,CAAC,iBAAiB,CAAC,aACrB,OAAO;CAET,OAAO,eAAe,gBAAgB,aAAa,cAAc;AACnE;AAUA,MAAM,4BAA4B,EAChC,WACA,aACA,0BACA,0BACA,yBAEA,QACE,aACE,CAAC,eACD,CAAC,4BACD,4BACA,CAAC,kBACL;AAIF,MAAa,iBACX,UAI6D,CAC7D,CAAC,WAAW,yBAAyB,KAAK,CAAC,GAC3C,CAAC,SAAS,MAAM,qBAAqB,CAAC,MAAM,YAAY,CAC1D;;AAGA,MAAa,YACX,OACA,UACkB;CAClB,IAAI,CAAC,OACH,OAAO,MAAM,MAAM,GAAG,YAAY,MAAM,CAAC,GAAG;CAE9C,MAAM,QAAQ,MAAM,WAAW,CAAC,UAAU,SAAS,KAAK;CACxD,IAAI,QAAQ,GACV;CAEF,OAAO,MAAM,MAAM,QAAQ,CAAC,CAAC,CAAC,MAAM,GAAG,YAAY,MAAM,CAAC,GAAG;AAC/D;AAEA,MAAa,gBACX,OACA,MACA,MACA,UACS;CACT,MAAM,OAAO,SAAS,OAAO,KAAK;CAClC,IAAI,MAAM;EACR,KAAK,KAAK,CAAC;EACX;CACF;CACA,KAAK;AACP;AAIA,MAAa,iBACX,UAK6D;CAC7D,CAAC,WAAW,MAAM,oBAAoB,CAAC;CACvC,CAAC,WAAW,yBAAyB,KAAK,CAAC;CAC3C,CAAC,SAAS,MAAM,qBAAqB,CAAC,MAAM,YAAY;AAC1D"}
1
+ {"version":3,"file":"utils.js","names":[],"sources":["../../../../src/pages/TransactionPage/utils.ts"],"sourcesContent":["import { LiFiErrorCode, type RouteExtended } from '@lifi/sdk'\nimport { getFailedStepAction } from '../../stores/routes/utils.js'\nimport type { WidgetMode } from '../../types/widget.js'\nimport { formatTokenAmount } from '../../utils/format.js'\n\nexport const calculateValueLossPercentage = (\n fromAmountUSD: number,\n toAmountUSD: number,\n gasCostUSD: number,\n feeCostUSD: number\n): number => {\n return Number.parseFloat(\n (\n (toAmountUSD / (fromAmountUSD + gasCostUSD + feeCostUSD) - 1) *\n 100\n ).toFixed(2)\n )\n}\n\nexport const getTokenValueLossThreshold = (\n fromAmountUSD: number,\n toAmountUSD: number,\n gasCostUSD: number,\n feeCostUSD: number\n): boolean => {\n if (!fromAmountUSD || !toAmountUSD) {\n return false\n }\n return toAmountUSD / (fromAmountUSD + gasCostUSD + feeCostUSD) < 0.9\n}\n\ninterface AddressGateInput {\n toAddress: string | undefined\n hasActivity: boolean | undefined\n isLoadingAddressActivity: boolean\n isActivityAddressFetched: boolean\n confirmationHidden: boolean\n}\n\nconst needsAddressConfirmation = ({\n toAddress,\n hasActivity,\n isLoadingAddressActivity,\n isActivityAddressFetched,\n confirmationHidden,\n}: AddressGateInput): boolean =>\n Boolean(\n toAddress &&\n !hasActivity &&\n !isLoadingAddressActivity &&\n isActivityAddressFetched &&\n !confirmationHidden\n )\n\nexport type RetryGate = 'address' | 'value'\n\nexport const getRetryGates = (\n input: AddressGateInput & {\n valueLossExceeded: boolean\n isCustomMode: boolean\n }\n): readonly (readonly [gate: RetryGate, needed: boolean])[] => [\n ['address', needsAddressConfirmation(input)],\n ['value', input.valueLossExceeded && !input.isCustomMode],\n]\n\n/** Ordering lives here so no sheet decides what follows it — that is how gates came to be skipped. */\nexport const nextGate = <T extends string>(\n gates: readonly (readonly [gate: T, needed: boolean])[],\n after?: T\n): T | undefined => {\n if (!after) {\n return gates.find(([, needed]) => needed)?.[0]\n }\n const index = gates.findIndex(([gate]) => gate === after)\n if (index < 0) {\n return undefined\n }\n return gates.slice(index + 1).find(([, needed]) => needed)?.[0]\n}\n\nexport const openNextGate = <T extends string>(\n gates: readonly (readonly [gate: T, needed: boolean])[],\n open: Record<T, () => void>,\n done: () => void,\n after?: T\n): void => {\n const gate = nextGate(gates, after)\n if (gate) {\n open[gate]()\n return\n }\n done()\n}\n\nexport type StartGate = 'flagged' | 'address' | 'value'\n\nexport const getStartGates = (\n input: AddressGateInput & {\n flaggedTokenCount: number\n valueLossExceeded: boolean\n isCustomMode: boolean\n }\n): readonly (readonly [gate: StartGate, needed: boolean])[] => [\n ['flagged', input.flaggedTokenCount > 0],\n ['address', needsAddressConfirmation(input)],\n ['value', input.valueLossExceeded && !input.isCustomMode],\n]\n\n// Only these modes show the plain from/to swap form.\nconst newSwapModes: readonly (WidgetMode | undefined)[] = [\n undefined,\n 'default',\n 'split',\n]\n\nexport const isCallBundleNotFound = (route: RouteExtended): boolean =>\n getFailedStepAction(route)?.action.error?.code ===\n LiFiErrorCode.CallBundleNotFound\n\n// A new swap repeats the whole route.\nexport const canStartNewSwap = ({\n route,\n mode,\n swapOnly,\n}: {\n route: RouteExtended\n mode: WidgetMode | undefined\n swapOnly: boolean\n}): boolean => {\n const failed = getFailedStepAction(route)\n if (!failed || !isCallBundleNotFound(route)) {\n return false\n }\n return (\n failed.step === route.steps[0] &&\n route.steps.every(\n (step) => step === failed.step || !step.execution?.actions?.length\n ) &&\n newSwapModes.includes(mode) &&\n // A swap-only form requests no bridges.\n !(swapOnly && route.fromChainId !== route.toChainId)\n )\n}\n\ninterface NewSwapFormValues {\n fromChain: number\n fromToken: string\n fromAmount: string\n toChain: number\n toToken: string\n toAddress?: string\n}\n\nexport const getNewSwapFormValues = (\n route: RouteExtended,\n {\n keepReceiver = false,\n receiverRequired = false,\n }: { keepReceiver?: boolean; receiverRequired?: boolean } = {}\n): NewSwapFormValues => {\n const receiver = route.toAddress || route.fromAddress\n const values: NewSwapFormValues = {\n fromChain: route.fromChainId,\n fromToken: route.fromToken.address,\n // The quote's amount, not a step amount trimmed to the balance: the new quote checks it.\n fromAmount: formatTokenAmount(\n BigInt(route.fromAmount),\n route.fromToken.decimals\n ),\n toChain: route.toChainId,\n toToken: route.toToken.address,\n }\n if (!keepReceiver) {\n // A required receiver stays, also when it is the sender.\n values.toAddress =\n receiver &&\n (receiverRequired ||\n receiver.toLowerCase() !== route.fromAddress?.toLowerCase())\n ? receiver\n : ''\n }\n return values\n}\n"],"mappings":";;;;AAKA,MAAa,gCACX,eACA,aACA,YACA,eACW;CACX,OAAO,OAAO,aAET,eAAe,gBAAgB,aAAa,cAAc,KAC3D,IAAA,CACA,QAAQ,CAAC,CACb;AACF;AAEA,MAAa,8BACX,eACA,aACA,YACA,eACY;CACZ,IAAI,CAAC,iBAAiB,CAAC,aACrB,OAAO;CAET,OAAO,eAAe,gBAAgB,aAAa,cAAc;AACnE;AAUA,MAAM,4BAA4B,EAChC,WACA,aACA,0BACA,0BACA,yBAEA,QACE,aACE,CAAC,eACD,CAAC,4BACD,4BACA,CAAC,kBACL;AAIF,MAAa,iBACX,UAI6D,CAC7D,CAAC,WAAW,yBAAyB,KAAK,CAAC,GAC3C,CAAC,SAAS,MAAM,qBAAqB,CAAC,MAAM,YAAY,CAC1D;;AAGA,MAAa,YACX,OACA,UACkB;CAClB,IAAI,CAAC,OACH,OAAO,MAAM,MAAM,GAAG,YAAY,MAAM,CAAC,GAAG;CAE9C,MAAM,QAAQ,MAAM,WAAW,CAAC,UAAU,SAAS,KAAK;CACxD,IAAI,QAAQ,GACV;CAEF,OAAO,MAAM,MAAM,QAAQ,CAAC,CAAC,CAAC,MAAM,GAAG,YAAY,MAAM,CAAC,GAAG;AAC/D;AAEA,MAAa,gBACX,OACA,MACA,MACA,UACS;CACT,MAAM,OAAO,SAAS,OAAO,KAAK;CAClC,IAAI,MAAM;EACR,KAAK,KAAK,CAAC;EACX;CACF;CACA,KAAK;AACP;AAIA,MAAa,iBACX,UAK6D;CAC7D,CAAC,WAAW,MAAM,oBAAoB,CAAC;CACvC,CAAC,WAAW,yBAAyB,KAAK,CAAC;CAC3C,CAAC,SAAS,MAAM,qBAAqB,CAAC,MAAM,YAAY;AAC1D;AAGA,MAAM,eAAoD;CACxD,KAAA;CACA;CACA;AACF;AAEA,MAAa,wBAAwB,UACnC,oBAAoB,KAAK,CAAC,EAAE,OAAO,OAAO,SAC1C,cAAc;AAGhB,MAAa,mBAAmB,EAC9B,OACA,MACA,eAKa;CACb,MAAM,SAAS,oBAAoB,KAAK;CACxC,IAAI,CAAC,UAAU,CAAC,qBAAqB,KAAK,GACxC,OAAO;CAET,OACE,OAAO,SAAS,MAAM,MAAM,MAC5B,MAAM,MAAM,OACT,SAAS,SAAS,OAAO,QAAQ,CAAC,KAAK,WAAW,SAAS,MAC9D,KACA,aAAa,SAAS,IAAI,KAE1B,EAAE,YAAY,MAAM,gBAAgB,MAAM;AAE9C;AAWA,MAAa,wBACX,OACA,EACE,eAAe,OACf,mBAAmB,UACuC,CAAC,MACvC;CACtB,MAAM,WAAW,MAAM,aAAa,MAAM;CAC1C,MAAM,SAA4B;EAChC,WAAW,MAAM;EACjB,WAAW,MAAM,UAAU;EAE3B,YAAY,kBACV,OAAO,MAAM,UAAU,GACvB,MAAM,UAAU,QAClB;EACA,SAAS,MAAM;EACf,SAAS,MAAM,QAAQ;CACzB;CACA,IAAI,CAAC,cAEH,OAAO,YACL,aACC,oBACC,SAAS,YAAY,MAAM,MAAM,aAAa,YAAY,KACxD,WACA;CAER,OAAO;AACT"}
@@ -85,7 +85,7 @@ import { RouteTracker } from "./pages/TransactionPage/RouteTracker.js";
85
85
  import { StartTransactionButton } from "./pages/TransactionPage/StartTransactionButton.js";
86
86
  import { TokenValueBottomSheet } from "./pages/TransactionPage/TokenValueBottomSheet.js";
87
87
  import { TransactionDoneButtons } from "./pages/TransactionPage/TransactionDoneButtons.js";
88
- import { calculateValueLossPercentage, getTokenValueLossThreshold } from "./pages/TransactionPage/utils.js";
88
+ import { calculateValueLossPercentage, getTokenValueLossThreshold, isCallBundleNotFound } from "./pages/TransactionPage/utils.js";
89
89
  import { I18nProvider } from "./providers/I18nProvider/I18nProvider.js";
90
90
  import { QueryClientProvider } from "./providers/QueryClientProvider.js";
91
91
  import { SDKClientProvider, useSDKClient } from "./providers/SDKClientProvider.js";
@@ -106,4 +106,4 @@ import { fitInputText } from "./utils/input.js";
106
106
  import { resolveStorageScopeKey } from "./utils/scopeKeys.js";
107
107
  import { isHttpUrl, openInNewTab } from "./utils/url.js";
108
108
  import { shortenAddress } from "./utils/wallet.js";
109
- export { ActionRow, AddressType, AmountInputEndAdornment, AvatarBadgedDefault, BaseTransactionButton, BookmarkStoreProvider, type BottomSheetBase, ButtonTertiary, Card, CardIconButton, CardTitle, ChainAvatar, ChainSelect, ConfirmToAddressSheet, ContactSupportButton, ContractComponent, DateLabelContainer, DateLabelText, DetailInfoIcon, DetailLabel, DetailLabelContainer, DetailRow, DetailValue, ElementId, ExchangeRateBottomSheet, type ExchangeRateBottomSheetBase, ExecutionDoneCard, type ExecutionRow, ExecutionStatusCard, ExternalLink, FeeBreakdownTooltip, FormControl, FormKeyHelper, type FormRef, type FormType, type FormTypeProps, I18nProvider, IconCircle, IconTypography, Input, InputCard, InputPriceButton, ListItemButton, MainWarningMessages, PageContainer, PoweredBy, ProgressToNextUpdate, QueryClientProvider, RouteCard, RouteCardSkeleton, RouteDetails, RouteExecutionStatus, RouteNotFoundCard, RouteTokens, RouteTracker, SDKClientProvider, SearchInput, SearchTokenInput, SelectChainPage, SendToWalletButton, SentToWalletRow, SettingsStoreProvider, Stack, StartTransactionButton, StatusIcon, StepActionsList, StoreProvider, Token, TokenAvatar, TokenNotFound, TokenRate, TokenValueBottomSheet, TransactionDoneButtons, VirtualizedTokenList, WalletProvider, WarningMessages, type WidgetConfig, WidgetEvent, WidgetProvider, type WidgetTheme, buildRouteFromTxHistory, calculateValueLossPercentage, createElementId, createTheme, fitInputText, formatDuration, formatInputAmount, formatTokenAmount, formatTokenPrice, getAccumulatedFeeCostsBreakdown, getPriceImpact, getSourceTxHash, getTokenValueLossThreshold, hasEnumFlag, isHttpUrl, isRouteActive, isRouteDone, isRouteFailed, navigationRoutes, openInNewTab, priceToTokenAmount, resolveStorageScopeKey, shortenAddress, usdDecimals, useAddressActivity, useAddressValidation, useAvailableChains, useChain, useChainOrderStore, useContactSupport, useDebouncedWatch, useExecutionRows, useExplorer, useFieldActions, useFieldValues, useHeader, useHeaderStore, useInputModeStore, useListHeight, useNavigateBack, useRouteExecution, useRouteExecutionMessage, useRouteExecutionStore, useRouteExecutionStoreContext, useRoutes, useSDKClient, useSetHeaderHeight, useSettingsStoreContext, useToAddressRequirements, useToken, useTokenAddressBalance, useTokenBalances, useTokenList, useTokenSelect, useTools, useWidgetConfig, useWidgetEvents };
109
+ export { ActionRow, AddressType, AmountInputEndAdornment, AvatarBadgedDefault, BaseTransactionButton, BookmarkStoreProvider, type BottomSheetBase, ButtonTertiary, Card, CardIconButton, CardTitle, ChainAvatar, ChainSelect, ConfirmToAddressSheet, ContactSupportButton, ContractComponent, DateLabelContainer, DateLabelText, DetailInfoIcon, DetailLabel, DetailLabelContainer, DetailRow, DetailValue, ElementId, ExchangeRateBottomSheet, type ExchangeRateBottomSheetBase, ExecutionDoneCard, type ExecutionRow, ExecutionStatusCard, ExternalLink, FeeBreakdownTooltip, FormControl, FormKeyHelper, type FormRef, type FormType, type FormTypeProps, I18nProvider, IconCircle, IconTypography, Input, InputCard, InputPriceButton, ListItemButton, MainWarningMessages, PageContainer, PoweredBy, ProgressToNextUpdate, QueryClientProvider, RouteCard, RouteCardSkeleton, RouteDetails, RouteExecutionStatus, RouteNotFoundCard, RouteTokens, RouteTracker, SDKClientProvider, SearchInput, SearchTokenInput, SelectChainPage, SendToWalletButton, SentToWalletRow, SettingsStoreProvider, Stack, StartTransactionButton, StatusIcon, StepActionsList, StoreProvider, Token, TokenAvatar, TokenNotFound, TokenRate, TokenValueBottomSheet, TransactionDoneButtons, VirtualizedTokenList, WalletProvider, WarningMessages, type WidgetConfig, WidgetEvent, WidgetProvider, type WidgetTheme, buildRouteFromTxHistory, calculateValueLossPercentage, createElementId, createTheme, fitInputText, formatDuration, formatInputAmount, formatTokenAmount, formatTokenPrice, getAccumulatedFeeCostsBreakdown, getPriceImpact, getSourceTxHash, getTokenValueLossThreshold, hasEnumFlag, isCallBundleNotFound, isHttpUrl, isRouteActive, isRouteDone, isRouteFailed, navigationRoutes, openInNewTab, priceToTokenAmount, resolveStorageScopeKey, shortenAddress, usdDecimals, useAddressActivity, useAddressValidation, useAvailableChains, useChain, useChainOrderStore, useContactSupport, useDebouncedWatch, useExecutionRows, useExplorer, useFieldActions, useFieldValues, useHeader, useHeaderStore, useInputModeStore, useListHeight, useNavigateBack, useRouteExecution, useRouteExecutionMessage, useRouteExecutionStore, useRouteExecutionStoreContext, useRoutes, useSDKClient, useSetHeaderHeight, useSettingsStoreContext, useToAddressRequirements, useToken, useTokenAddressBalance, useTokenBalances, useTokenList, useTokenSelect, useTools, useWidgetConfig, useWidgetEvents };
@@ -96,7 +96,7 @@ import { TransactionDoneButtons } from "./pages/TransactionPage/TransactionDoneB
96
96
  import { useAddressActivity } from "./hooks/useAddressActivity.js";
97
97
  import { ConfirmToAddressSheet } from "./pages/TransactionPage/ConfirmToAddressSheet.js";
98
98
  import { StartTransactionButton } from "./pages/TransactionPage/StartTransactionButton.js";
99
- import { calculateValueLossPercentage, getTokenValueLossThreshold } from "./pages/TransactionPage/utils.js";
99
+ import { calculateValueLossPercentage, getTokenValueLossThreshold, isCallBundleNotFound } from "./pages/TransactionPage/utils.js";
100
100
  import { TokenValueBottomSheet } from "./pages/TransactionPage/TokenValueBottomSheet.js";
101
101
  import { I18nProvider } from "./providers/I18nProvider/I18nProvider.js";
102
102
  import { QueryClientProvider } from "./providers/QueryClientProvider.js";
@@ -104,4 +104,4 @@ import { createTheme } from "./themes/createTheme.js";
104
104
  import { WalletProvider } from "./providers/WalletProvider/WalletProvider.js";
105
105
  import { StoreProvider } from "./stores/StoreProvider.js";
106
106
  import { useTokenList } from "./hooks/useTokenList.js";
107
- export { ActionRow, AddressType, AmountInputEndAdornment, AvatarBadgedDefault, BaseTransactionButton, BookmarkStoreProvider, ButtonTertiary, Card, CardIconButton, CardTitle, ChainAvatar, ChainSelect, ConfirmToAddressSheet, ContactSupportButton, ContractComponent, DateLabelContainer, DateLabelText, DetailInfoIcon, DetailLabel, DetailLabelContainer, DetailRow, DetailValue, ElementId, ExchangeRateBottomSheet, ExecutionDoneCard, ExecutionStatusCard, ExternalLink, FeeBreakdownTooltip, FormControl, FormKeyHelper, I18nProvider, IconCircle, IconTypography, Input, InputCard, InputPriceButton, ListItemButton, MainWarningMessages, PageContainer, PoweredBy, ProgressToNextUpdate, QueryClientProvider, RouteCard, RouteCardSkeleton, RouteDetails, RouteExecutionStatus, RouteNotFoundCard, RouteTokens, RouteTracker, SDKClientProvider, SearchInput, SearchTokenInput, SelectChainPage, SendToWalletButton, SentToWalletRow, SettingsStoreProvider, Stack, StartTransactionButton, StatusIcon, StepActionsList, StoreProvider, Token, TokenAvatar, TokenNotFound, TokenRate, TokenValueBottomSheet, TransactionDoneButtons, VirtualizedTokenList, WalletProvider, WarningMessages, WidgetEvent, WidgetProvider, buildRouteFromTxHistory, calculateValueLossPercentage, createElementId, createTheme, fitInputText, formatDuration, formatInputAmount, formatTokenAmount, formatTokenPrice, getAccumulatedFeeCostsBreakdown, getPriceImpact, getSourceTxHash, getTokenValueLossThreshold, hasEnumFlag, isHttpUrl, isRouteActive, isRouteDone, isRouteFailed, navigationRoutes, openInNewTab, priceToTokenAmount, resolveStorageScopeKey, shortenAddress, usdDecimals, useAddressActivity, useAddressValidation, useAvailableChains, useChain, useChainOrderStore, useContactSupport, useDebouncedWatch, useExecutionRows, useExplorer, useFieldActions, useFieldValues, useHeader, useHeaderStore, useInputModeStore, useListHeight, useNavigateBack, useRouteExecution, useRouteExecutionMessage, useRouteExecutionStore, useRouteExecutionStoreContext, useRoutes, useSDKClient, useSetHeaderHeight, useSettingsStoreContext, useToAddressRequirements, useToken, useTokenAddressBalance, useTokenBalances, useTokenList, useTokenSelect, useTools, useWidgetConfig, useWidgetEvents };
107
+ export { ActionRow, AddressType, AmountInputEndAdornment, AvatarBadgedDefault, BaseTransactionButton, BookmarkStoreProvider, ButtonTertiary, Card, CardIconButton, CardTitle, ChainAvatar, ChainSelect, ConfirmToAddressSheet, ContactSupportButton, ContractComponent, DateLabelContainer, DateLabelText, DetailInfoIcon, DetailLabel, DetailLabelContainer, DetailRow, DetailValue, ElementId, ExchangeRateBottomSheet, ExecutionDoneCard, ExecutionStatusCard, ExternalLink, FeeBreakdownTooltip, FormControl, FormKeyHelper, I18nProvider, IconCircle, IconTypography, Input, InputCard, InputPriceButton, ListItemButton, MainWarningMessages, PageContainer, PoweredBy, ProgressToNextUpdate, QueryClientProvider, RouteCard, RouteCardSkeleton, RouteDetails, RouteExecutionStatus, RouteNotFoundCard, RouteTokens, RouteTracker, SDKClientProvider, SearchInput, SearchTokenInput, SelectChainPage, SendToWalletButton, SentToWalletRow, SettingsStoreProvider, Stack, StartTransactionButton, StatusIcon, StepActionsList, StoreProvider, Token, TokenAvatar, TokenNotFound, TokenRate, TokenValueBottomSheet, TransactionDoneButtons, VirtualizedTokenList, WalletProvider, WarningMessages, WidgetEvent, WidgetProvider, buildRouteFromTxHistory, calculateValueLossPercentage, createElementId, createTheme, fitInputText, formatDuration, formatInputAmount, formatTokenAmount, formatTokenPrice, getAccumulatedFeeCostsBreakdown, getPriceImpact, getSourceTxHash, getTokenValueLossThreshold, hasEnumFlag, isCallBundleNotFound, isHttpUrl, isRouteActive, isRouteDone, isRouteFailed, navigationRoutes, openInNewTab, priceToTokenAmount, resolveStorageScopeKey, shortenAddress, usdDecimals, useAddressActivity, useAddressValidation, useAvailableChains, useChain, useChainOrderStore, useContactSupport, useDebouncedWatch, useExecutionRows, useExplorer, useFieldActions, useFieldValues, useHeader, useHeaderStore, useInputModeStore, useListHeight, useNavigateBack, useRouteExecution, useRouteExecutionMessage, useRouteExecutionStore, useRouteExecutionStoreContext, useRoutes, useSDKClient, useSetHeaderHeight, useSettingsStoreContext, useToAddressRequirements, useToken, useTokenAddressBalance, useTokenBalances, useTokenList, useTokenSelect, useTools, useWidgetConfig, useWidgetEvents };
@@ -1,4 +1,4 @@
1
- import { ExecutionAction, RouteExtended } from "@lifi/sdk";
1
+ import { ExecutionAction, LiFiStepExtended, RouteExtended } from "@lifi/sdk";
2
2
  //#region src/stores/routes/utils.d.ts
3
3
  export declare const isRouteDone: (route: RouteExtended) => boolean;
4
4
  export declare const isRouteFailed: (route: RouteExtended) => boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","names":[],"sources":["../../../../src/stores/routes/utils.ts"],"mappings":";;qBAGa,cAAe,OAAO;qBAgBtB,gBAAiB,OAAO;qBAIxB,gBAAiB,QAAQ;qBAgCzB,kBAAmB,QAAQ"}
1
+ {"version":3,"file":"utils.d.ts","names":[],"sources":["../../../../src/stores/routes/utils.ts"],"mappings":";;qBAQa,cAAe,OAAO;qBAgBtB,gBAAiB,OAAO;qBAsBxB,gBAAiB,QAAQ;qBAgCzB,kBAAmB,QAAQ"}
@@ -12,6 +12,18 @@ const isRouteRefunded = (route) => {
12
12
  const isRouteFailed = (route) => {
13
13
  return route.steps.some((step) => step.execution?.status === "FAILED");
14
14
  };
15
+ const getFailedStepAction = (route) => {
16
+ const step = route.steps.find((step) => step.execution?.status === "FAILED");
17
+ if (!step) return;
18
+ return {
19
+ step,
20
+ action: step.execution?.actions?.find((action) => action.status === "FAILED") || {
21
+ status: "FAILED",
22
+ type: "EXECUTION",
23
+ error: step.execution?.error
24
+ }
25
+ };
26
+ };
15
27
  const isRouteActive = (route) => {
16
28
  if (!route) return false;
17
29
  const isDone = isRouteDone(route);
@@ -30,6 +42,6 @@ const getSourceTxHash = (route) => {
30
42
  return sourceAction?.txHash || sourceAction?.taskId;
31
43
  };
32
44
  //#endregion
33
- export { getSourceTxHash, getUpdatedAction, isRouteActive, isRouteDone, isRouteFailed, isRoutePartiallyDone, isRouteRefunded };
45
+ export { getFailedStepAction, getSourceTxHash, getUpdatedAction, isRouteActive, isRouteDone, isRouteFailed, isRoutePartiallyDone, isRouteRefunded };
34
46
 
35
47
  //# sourceMappingURL=utils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","names":[],"sources":["../../../../src/stores/routes/utils.ts"],"sourcesContent":["import type { ExecutionAction, RouteExtended } from '@lifi/sdk'\nimport microdiff from 'microdiff'\n\nexport const isRouteDone = (route: RouteExtended): boolean => {\n return route.steps.every((step) => step.execution?.status === 'DONE')\n}\n\nexport const isRoutePartiallyDone = (route: RouteExtended): boolean => {\n return route.steps.some((step) =>\n step.execution?.actions?.some((action) => action.substatus === 'PARTIAL')\n )\n}\n\nexport const isRouteRefunded = (route: RouteExtended): boolean => {\n return route.steps.some((step) =>\n step.execution?.actions?.some((action) => action.substatus === 'REFUNDED')\n )\n}\n\nexport const isRouteFailed = (route: RouteExtended): boolean => {\n return route.steps.some((step) => step.execution?.status === 'FAILED')\n}\n\nexport const isRouteActive = (route?: RouteExtended): boolean => {\n if (!route) {\n return false\n }\n const isDone = isRouteDone(route)\n const isFailed = isRouteFailed(route)\n const alreadyStarted = route.steps.some((step) => step.execution)\n return !isDone && !isFailed && alreadyStarted\n}\n\nexport const getUpdatedAction = (\n currentRoute: RouteExtended,\n updatedRoute: RouteExtended\n): ExecutionAction | undefined => {\n const actionDiff = microdiff(currentRoute, updatedRoute).find((diff) =>\n diff.path.includes('actions')\n )\n if (!actionDiff) {\n return undefined\n }\n // Find action index in the diff array so we can slice the complete action object\n // e.g. ['steps', 0, 'execution', 'actions', 0, 'message']\n const actionDiffIndex = actionDiff.path.indexOf('actions') + 2\n const actionPathSlice = actionDiff.path.slice(0, actionDiffIndex)\n // Reduce updated route using the diff path to get updated process\n const action = actionPathSlice.reduce(\n (obj, path) => obj[path],\n updatedRoute as any\n ) as ExecutionAction\n return action\n}\n\nexport const getSourceTxHash = (route?: RouteExtended): string | undefined => {\n const sourceAction = route?.steps[0].execution?.actions\n ?.filter(\n (action) => !['RESET_ALLOWANCE', 'SET_ALLOWANCE'].includes(action.type)\n )\n .find((action) => action.txHash || action.taskId)\n return sourceAction?.txHash || sourceAction?.taskId\n}\n"],"mappings":";;AAGA,MAAa,eAAe,UAAkC;CAC5D,OAAO,MAAM,MAAM,OAAO,SAAS,KAAK,WAAW,WAAW,MAAM;AACtE;AAEA,MAAa,wBAAwB,UAAkC;CACrE,OAAO,MAAM,MAAM,MAAM,SACvB,KAAK,WAAW,SAAS,MAAM,WAAW,OAAO,cAAc,SAAS,CAC1E;AACF;AAEA,MAAa,mBAAmB,UAAkC;CAChE,OAAO,MAAM,MAAM,MAAM,SACvB,KAAK,WAAW,SAAS,MAAM,WAAW,OAAO,cAAc,UAAU,CAC3E;AACF;AAEA,MAAa,iBAAiB,UAAkC;CAC9D,OAAO,MAAM,MAAM,MAAM,SAAS,KAAK,WAAW,WAAW,QAAQ;AACvE;AAEA,MAAa,iBAAiB,UAAmC;CAC/D,IAAI,CAAC,OACH,OAAO;CAET,MAAM,SAAS,YAAY,KAAK;CAChC,MAAM,WAAW,cAAc,KAAK;CACpC,MAAM,iBAAiB,MAAM,MAAM,MAAM,SAAS,KAAK,SAAS;CAChE,OAAO,CAAC,UAAU,CAAC,YAAY;AACjC;AAEA,MAAa,oBACX,cACA,iBACgC;CAChC,MAAM,aAAa,UAAU,cAAc,YAAY,CAAC,CAAC,MAAM,SAC7D,KAAK,KAAK,SAAS,SAAS,CAC9B;CACA,IAAI,CAAC,YACH;CAIF,MAAM,kBAAkB,WAAW,KAAK,QAAQ,SAAS,IAAI;CAO7D,OANwB,WAAW,KAAK,MAAM,GAAG,eAEpB,CAAC,CAAC,QAC5B,KAAK,SAAS,IAAI,OACnB,YAEU;AACd;AAEA,MAAa,mBAAmB,UAA8C;CAC5E,MAAM,eAAe,OAAO,MAAM,EAAE,CAAC,WAAW,SAC5C,QACC,WAAW,CAAC,CAAC,mBAAmB,eAAe,CAAC,CAAC,SAAS,OAAO,IAAI,CACxE,CAAC,CACA,MAAM,WAAW,OAAO,UAAU,OAAO,MAAM;CAClD,OAAO,cAAc,UAAU,cAAc;AAC/C"}
1
+ {"version":3,"file":"utils.js","names":[],"sources":["../../../../src/stores/routes/utils.ts"],"sourcesContent":["import type {\n ExecutionAction,\n ExecutionActionType,\n LiFiStepExtended,\n RouteExtended,\n} from '@lifi/sdk'\nimport microdiff from 'microdiff'\n\nexport const isRouteDone = (route: RouteExtended): boolean => {\n return route.steps.every((step) => step.execution?.status === 'DONE')\n}\n\nexport const isRoutePartiallyDone = (route: RouteExtended): boolean => {\n return route.steps.some((step) =>\n step.execution?.actions?.some((action) => action.substatus === 'PARTIAL')\n )\n}\n\nexport const isRouteRefunded = (route: RouteExtended): boolean => {\n return route.steps.some((step) =>\n step.execution?.actions?.some((action) => action.substatus === 'REFUNDED')\n )\n}\n\nexport const isRouteFailed = (route: RouteExtended): boolean => {\n return route.steps.some((step) => step.execution?.status === 'FAILED')\n}\n\n// A step can fail before any action, so its own error then stands in.\nexport const getFailedStepAction = (\n route: RouteExtended\n): { step: LiFiStepExtended; action: ExecutionAction } | undefined => {\n const step = route.steps.find((step) => step.execution?.status === 'FAILED')\n if (!step) {\n return undefined\n }\n const action = step.execution?.actions?.find(\n (action) => action.status === 'FAILED'\n ) || {\n status: 'FAILED',\n type: 'EXECUTION' as ExecutionActionType,\n error: step.execution?.error,\n }\n return { step, action }\n}\n\nexport const isRouteActive = (route?: RouteExtended): boolean => {\n if (!route) {\n return false\n }\n const isDone = isRouteDone(route)\n const isFailed = isRouteFailed(route)\n const alreadyStarted = route.steps.some((step) => step.execution)\n return !isDone && !isFailed && alreadyStarted\n}\n\nexport const getUpdatedAction = (\n currentRoute: RouteExtended,\n updatedRoute: RouteExtended\n): ExecutionAction | undefined => {\n const actionDiff = microdiff(currentRoute, updatedRoute).find((diff) =>\n diff.path.includes('actions')\n )\n if (!actionDiff) {\n return undefined\n }\n // Find action index in the diff array so we can slice the complete action object\n // e.g. ['steps', 0, 'execution', 'actions', 0, 'message']\n const actionDiffIndex = actionDiff.path.indexOf('actions') + 2\n const actionPathSlice = actionDiff.path.slice(0, actionDiffIndex)\n // Reduce updated route using the diff path to get updated process\n const action = actionPathSlice.reduce(\n (obj, path) => obj[path],\n updatedRoute as any\n ) as ExecutionAction\n return action\n}\n\nexport const getSourceTxHash = (route?: RouteExtended): string | undefined => {\n const sourceAction = route?.steps[0].execution?.actions\n ?.filter(\n (action) => !['RESET_ALLOWANCE', 'SET_ALLOWANCE'].includes(action.type)\n )\n .find((action) => action.txHash || action.taskId)\n return sourceAction?.txHash || sourceAction?.taskId\n}\n"],"mappings":";;AAQA,MAAa,eAAe,UAAkC;CAC5D,OAAO,MAAM,MAAM,OAAO,SAAS,KAAK,WAAW,WAAW,MAAM;AACtE;AAEA,MAAa,wBAAwB,UAAkC;CACrE,OAAO,MAAM,MAAM,MAAM,SACvB,KAAK,WAAW,SAAS,MAAM,WAAW,OAAO,cAAc,SAAS,CAC1E;AACF;AAEA,MAAa,mBAAmB,UAAkC;CAChE,OAAO,MAAM,MAAM,MAAM,SACvB,KAAK,WAAW,SAAS,MAAM,WAAW,OAAO,cAAc,UAAU,CAC3E;AACF;AAEA,MAAa,iBAAiB,UAAkC;CAC9D,OAAO,MAAM,MAAM,MAAM,SAAS,KAAK,WAAW,WAAW,QAAQ;AACvE;AAGA,MAAa,uBACX,UACoE;CACpE,MAAM,OAAO,MAAM,MAAM,MAAM,SAAS,KAAK,WAAW,WAAW,QAAQ;CAC3E,IAAI,CAAC,MACH;CASF,OAAO;EAAE;EAAM,QAPA,KAAK,WAAW,SAAS,MACrC,WAAW,OAAO,WAAW,QAChC,KAAK;GACH,QAAQ;GACR,MAAM;GACN,OAAO,KAAK,WAAW;EACzB;CACsB;AACxB;AAEA,MAAa,iBAAiB,UAAmC;CAC/D,IAAI,CAAC,OACH,OAAO;CAET,MAAM,SAAS,YAAY,KAAK;CAChC,MAAM,WAAW,cAAc,KAAK;CACpC,MAAM,iBAAiB,MAAM,MAAM,MAAM,SAAS,KAAK,SAAS;CAChE,OAAO,CAAC,UAAU,CAAC,YAAY;AACjC;AAEA,MAAa,oBACX,cACA,iBACgC;CAChC,MAAM,aAAa,UAAU,cAAc,YAAY,CAAC,CAAC,MAAM,SAC7D,KAAK,KAAK,SAAS,SAAS,CAC9B;CACA,IAAI,CAAC,YACH;CAIF,MAAM,kBAAkB,WAAW,KAAK,QAAQ,SAAS,IAAI;CAO7D,OANwB,WAAW,KAAK,MAAM,GAAG,eAEpB,CAAC,CAAC,QAC5B,KAAK,SAAS,IAAI,OACnB,YAEU;AACd;AAEA,MAAa,mBAAmB,UAA8C;CAC5E,MAAM,eAAe,OAAO,MAAM,EAAE,CAAC,WAAW,SAC5C,QACC,WAAW,CAAC,CAAC,mBAAmB,eAAe,CAAC,CAAC,SAAS,OAAO,IAAI,CACxE,CAAC,CACA,MAAM,WAAW,OAAO,UAAU,OAAO,MAAM;CAClD,OAAO,cAAc,UAAU,cAAc;AAC/C"}
@@ -99,6 +99,10 @@ function getErrorMessage(t, getChainById, step, failedAction) {
99
99
  chainName: getChainById(step.action.fromChainId)?.name ?? ""
100
100
  });
101
101
  break;
102
+ case LiFiErrorCode.CallBundleNotFound:
103
+ title = t("error.title.callBundleNotFound");
104
+ message = t("error.message.callBundleNotFound");
105
+ break;
102
106
  default:
103
107
  title = t("error.title.unknown");
104
108
  if (failedAction?.txHash) message = t("error.message.transactionFailed");
@@ -1 +1 @@
1
- {"version":3,"file":"getErrorMessage.js","names":[],"sources":["../../../src/utils/getErrorMessage.ts"],"sourcesContent":["import {\n type EVMChain,\n type ExecutionAction,\n LiFiErrorCode,\n type LiFiStepExtended,\n} from '@lifi/sdk'\nimport type { TFunction } from 'i18next'\nimport { formatTokenAmount, wrapLongWords } from '../utils/format.js'\n\nexport function getErrorMessage(\n t: TFunction,\n getChainById: (chainId: number) => EVMChain | undefined,\n step: LiFiStepExtended,\n failedAction?: ExecutionAction\n): { title: string; message: string } {\n const error = failedAction?.error\n if (!error) {\n return {\n title: t('error.title.unknown'),\n message: t('error.message.unknown'),\n }\n }\n\n const getDefaultErrorMessage = (key?: string) =>\n `${t((key as any) ?? 'error.message.transactionNotSent')} ${t(\n 'error.message.remainInYourWallet',\n {\n amount: formatTokenAmount(\n BigInt(step.action.fromAmount),\n step.action.fromToken.decimals\n ),\n tokenSymbol: step.action.fromToken.symbol,\n chainName: getChainById(step.action.fromChainId)?.name ?? '',\n }\n )}`\n\n let title = ''\n let message = ''\n switch (error.code) {\n case LiFiErrorCode.AllowanceRequired:\n title = t('error.title.allowanceRequired')\n message = t('error.message.allowanceRequired', {\n tokenSymbol: step.action.fromToken.symbol,\n })\n break\n case LiFiErrorCode.BalanceError:\n title = t('error.title.balanceIsTooLow')\n message = getDefaultErrorMessage()\n break\n case LiFiErrorCode.ChainSwitchError:\n title = t('error.title.chainSwitch')\n message = getDefaultErrorMessage()\n break\n case LiFiErrorCode.GasLimitError:\n title = t('error.title.gasLimitIsTooLow')\n message = getDefaultErrorMessage()\n break\n case LiFiErrorCode.InsufficientFunds:\n title = t('error.title.insufficientFunds')\n message = `${t(\n 'error.message.insufficientFunds'\n )} ${getDefaultErrorMessage()}`\n break\n case LiFiErrorCode.InsufficientGas:\n title = t('error.title.insufficientGas')\n message = `${t(\n 'error.message.insufficientFunds'\n )} ${getDefaultErrorMessage()}`\n break\n case LiFiErrorCode.SlippageError:\n title = t('error.title.slippageNotMet')\n message = t('error.message.slippageThreshold')\n break\n case LiFiErrorCode.TransactionFailed:\n title = t('error.title.transactionFailed')\n message = t('error.message.transactionFailed')\n break\n case LiFiErrorCode.TransactionExpired:\n title = t('error.title.transactionExpired')\n message = t('error.message.transactionExpired')\n break\n case LiFiErrorCode.TransactionSimulationFailed:\n title = t('error.title.transactionSimulationFailed')\n message = t('error.message.transactionSimulationFailed')\n break\n case LiFiErrorCode.WalletChangedDuringExecution:\n title = t('error.title.walletMismatch')\n message = t('error.message.walletChangedDuringExecution')\n break\n case LiFiErrorCode.RateLimitExceeded:\n title = t('error.title.rateLimitExceeded')\n message = t('error.message.rateLimitExceeded')\n break\n case LiFiErrorCode.ThirdPartyError:\n title = t('error.title.thirdPartyError')\n message = t('error.message.thirdPartyError')\n break\n case LiFiErrorCode.TransactionUnderpriced:\n title = t('error.title.transactionUnderpriced')\n message = getDefaultErrorMessage()\n break\n case LiFiErrorCode.TransactionUnprepared:\n title = t('error.title.transactionUnprepared')\n message = getDefaultErrorMessage()\n break\n case LiFiErrorCode.TransactionCanceled:\n title = t('error.title.transactionCanceled')\n message = getDefaultErrorMessage('error.message.transactionCanceled')\n break\n case LiFiErrorCode.TransactionRejected:\n title = t('error.title.transactionRejected')\n message = getDefaultErrorMessage('error.message.transactionRejected')\n break\n case LiFiErrorCode.TransactionConflict:\n title = t('error.title.transactionConflict')\n message = getDefaultErrorMessage('error.message.transactionConflict')\n break\n case LiFiErrorCode.ExchangeRateUpdateCanceled:\n title = t('error.title.exchangeRateUpdateCanceled')\n message = getDefaultErrorMessage()\n break\n case LiFiErrorCode.SignatureRejected:\n title = t('error.title.signatureRejected')\n message = t('error.message.signatureRejected', {\n amount: formatTokenAmount(\n BigInt(step.action.fromAmount),\n step.action.fromToken.decimals\n ),\n tokenSymbol: step.action.fromToken.symbol,\n chainName: getChainById(step.action.fromChainId)?.name ?? '',\n })\n break\n default:\n title = t('error.title.unknown')\n if (failedAction?.txHash) {\n message = t('error.message.transactionFailed')\n } else {\n message = error.message || t('error.message.unknown')\n }\n break\n }\n message = wrapLongWords(message)\n return { title, message }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"getErrorMessage.js","names":[],"sources":["../../../src/utils/getErrorMessage.ts"],"sourcesContent":["import {\n type EVMChain,\n type ExecutionAction,\n LiFiErrorCode,\n type LiFiStepExtended,\n} from '@lifi/sdk'\nimport type { TFunction } from 'i18next'\nimport { formatTokenAmount, wrapLongWords } from '../utils/format.js'\n\nexport function getErrorMessage(\n t: TFunction,\n getChainById: (chainId: number) => EVMChain | undefined,\n step: LiFiStepExtended,\n failedAction?: ExecutionAction\n): { title: string; message: string } {\n const error = failedAction?.error\n if (!error) {\n return {\n title: t('error.title.unknown'),\n message: t('error.message.unknown'),\n }\n }\n\n const getDefaultErrorMessage = (key?: string) =>\n `${t((key as any) ?? 'error.message.transactionNotSent')} ${t(\n 'error.message.remainInYourWallet',\n {\n amount: formatTokenAmount(\n BigInt(step.action.fromAmount),\n step.action.fromToken.decimals\n ),\n tokenSymbol: step.action.fromToken.symbol,\n chainName: getChainById(step.action.fromChainId)?.name ?? '',\n }\n )}`\n\n let title = ''\n let message = ''\n switch (error.code) {\n case LiFiErrorCode.AllowanceRequired:\n title = t('error.title.allowanceRequired')\n message = t('error.message.allowanceRequired', {\n tokenSymbol: step.action.fromToken.symbol,\n })\n break\n case LiFiErrorCode.BalanceError:\n title = t('error.title.balanceIsTooLow')\n message = getDefaultErrorMessage()\n break\n case LiFiErrorCode.ChainSwitchError:\n title = t('error.title.chainSwitch')\n message = getDefaultErrorMessage()\n break\n case LiFiErrorCode.GasLimitError:\n title = t('error.title.gasLimitIsTooLow')\n message = getDefaultErrorMessage()\n break\n case LiFiErrorCode.InsufficientFunds:\n title = t('error.title.insufficientFunds')\n message = `${t(\n 'error.message.insufficientFunds'\n )} ${getDefaultErrorMessage()}`\n break\n case LiFiErrorCode.InsufficientGas:\n title = t('error.title.insufficientGas')\n message = `${t(\n 'error.message.insufficientFunds'\n )} ${getDefaultErrorMessage()}`\n break\n case LiFiErrorCode.SlippageError:\n title = t('error.title.slippageNotMet')\n message = t('error.message.slippageThreshold')\n break\n case LiFiErrorCode.TransactionFailed:\n title = t('error.title.transactionFailed')\n message = t('error.message.transactionFailed')\n break\n case LiFiErrorCode.TransactionExpired:\n title = t('error.title.transactionExpired')\n message = t('error.message.transactionExpired')\n break\n case LiFiErrorCode.TransactionSimulationFailed:\n title = t('error.title.transactionSimulationFailed')\n message = t('error.message.transactionSimulationFailed')\n break\n case LiFiErrorCode.WalletChangedDuringExecution:\n title = t('error.title.walletMismatch')\n message = t('error.message.walletChangedDuringExecution')\n break\n case LiFiErrorCode.RateLimitExceeded:\n title = t('error.title.rateLimitExceeded')\n message = t('error.message.rateLimitExceeded')\n break\n case LiFiErrorCode.ThirdPartyError:\n title = t('error.title.thirdPartyError')\n message = t('error.message.thirdPartyError')\n break\n case LiFiErrorCode.TransactionUnderpriced:\n title = t('error.title.transactionUnderpriced')\n message = getDefaultErrorMessage()\n break\n case LiFiErrorCode.TransactionUnprepared:\n title = t('error.title.transactionUnprepared')\n message = getDefaultErrorMessage()\n break\n case LiFiErrorCode.TransactionCanceled:\n title = t('error.title.transactionCanceled')\n message = getDefaultErrorMessage('error.message.transactionCanceled')\n break\n case LiFiErrorCode.TransactionRejected:\n title = t('error.title.transactionRejected')\n message = getDefaultErrorMessage('error.message.transactionRejected')\n break\n case LiFiErrorCode.TransactionConflict:\n title = t('error.title.transactionConflict')\n message = getDefaultErrorMessage('error.message.transactionConflict')\n break\n case LiFiErrorCode.ExchangeRateUpdateCanceled:\n title = t('error.title.exchangeRateUpdateCanceled')\n message = getDefaultErrorMessage()\n break\n case LiFiErrorCode.SignatureRejected:\n title = t('error.title.signatureRejected')\n message = t('error.message.signatureRejected', {\n amount: formatTokenAmount(\n BigInt(step.action.fromAmount),\n step.action.fromToken.decimals\n ),\n tokenSymbol: step.action.fromToken.symbol,\n chainName: getChainById(step.action.fromChainId)?.name ?? '',\n })\n break\n // No \"remain in your wallet\" suffix: the funds may already be gone.\n case LiFiErrorCode.CallBundleNotFound:\n title = t('error.title.callBundleNotFound')\n message = t('error.message.callBundleNotFound')\n break\n default:\n title = t('error.title.unknown')\n if (failedAction?.txHash) {\n message = t('error.message.transactionFailed')\n } else {\n message = error.message || t('error.message.unknown')\n }\n break\n }\n message = wrapLongWords(message)\n return { title, message }\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lifi/widget",
3
- "version": "4.10.0",
3
+ "version": "4.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
  "type": "module",
6
6
  "main": "./dist/esm/index.js",
@@ -57,9 +57,9 @@
57
57
  "dependencies": {
58
58
  "@emotion/react": "^11.14.0",
59
59
  "@emotion/styled": "^11.14.1",
60
- "@lifi/sdk": "^4.11.0",
61
- "@lifi/wallet-management": "4.3.2",
62
- "@lifi/widget-provider": "4.6.0",
60
+ "@lifi/sdk": "^4.12.0",
61
+ "@lifi/wallet-management": "4.3.3",
62
+ "@lifi/widget-provider": "4.6.1",
63
63
  "@mui/icons-material": "^9.4.0",
64
64
  "@mui/material": "^9.4.0",
65
65
  "@mui/system": "^9.4.0",
@@ -1,2 +1,2 @@
1
1
  export const name = '@lifi/widget'
2
- export const version = '4.10.0'
2
+ export const version = '4.10.1'
@@ -1,7 +1,7 @@
1
1
  import { useEffect, useRef, useState } from 'react'
2
2
 
3
3
  /** Smallest gap between UI updates, in milliseconds. */
4
- const DISPLAY_INTERVAL = 1200
4
+ export const DISPLAY_INTERVAL = 1200
5
5
 
6
6
  /**
7
7
  * Returns `live`, but changes it at most once every {@link DISPLAY_INTERVAL}
@@ -1,7 +1,8 @@
1
- import type { ExecutionActionType, RouteExtended } from '@lifi/sdk'
1
+ import type { RouteExtended } from '@lifi/sdk'
2
2
  import { useTranslation } from 'react-i18next'
3
3
  import { useWidgetConfig } from '../providers/WidgetProvider/WidgetProvider.js'
4
4
  import { RouteExecutionStatus } from '../stores/routes/types.js'
5
+ import { getFailedStepAction } from '../stores/routes/utils.js'
5
6
  import { getActionMessage } from '../utils/getActionMessage.js'
6
7
  import { getErrorMessage } from '../utils/getErrorMessage.js'
7
8
  import { useAvailableChains } from './useAvailableChains.js'
@@ -76,20 +77,16 @@ export const useRouteExecutionMessage = (
76
77
  break
77
78
  }
78
79
  case RouteExecutionStatus.Failed: {
79
- const step = route.steps.find(
80
- (step) => step.execution?.status === 'FAILED'
81
- )
82
- if (!step) {
80
+ const failed = getFailedStepAction(route)
81
+ if (!failed) {
83
82
  break
84
83
  }
85
- const action = step.execution?.actions?.find(
86
- (action) => action.status === 'FAILED'
87
- ) || {
88
- status: 'FAILED',
89
- type: 'EXECUTION' as ExecutionActionType,
90
- error: step.execution?.error,
91
- } // synthetic action to represent a failed execution with no actions
92
- const actionMessage = getErrorMessage(t, getChainById, step, action)
84
+ const actionMessage = getErrorMessage(
85
+ t,
86
+ getChainById,
87
+ failed.step,
88
+ failed.action
89
+ )
93
90
  title = actionMessage.title
94
91
  message = actionMessage.message
95
92
  break