@lifi/widget 3.2.2 → 3.4.0-beta.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 (88) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/_esm/components/ActiveTransactions/ActiveTransactionItem.js +1 -1
  3. package/_esm/components/Card/CardIconButton.d.ts +4 -1
  4. package/_esm/components/Card/CardIconButton.js.map +1 -1
  5. package/_esm/components/FeeBreakdownTooltip.d.ts +0 -2
  6. package/_esm/components/FeeBreakdownTooltip.js +2 -5
  7. package/_esm/components/FeeBreakdownTooltip.js.map +1 -1
  8. package/_esm/components/IconTypography.d.ts +3 -3
  9. package/_esm/components/IconTypography.js +2 -2
  10. package/_esm/components/IconTypography.js.map +1 -1
  11. package/_esm/components/RouteCard/RouteCardEssentials.js +10 -11
  12. package/_esm/components/RouteCard/RouteCardEssentials.js.map +1 -1
  13. package/_esm/components/Step/DestinationWalletAddress.js +2 -2
  14. package/_esm/components/Step/DestinationWalletAddress.js.map +1 -1
  15. package/_esm/components/Step/Step.js +1 -1
  16. package/_esm/components/Step/StepProcess.js +3 -3
  17. package/_esm/components/Step/StepProcess.js.map +1 -1
  18. package/_esm/components/Step/StepTimer.js +44 -27
  19. package/_esm/components/Step/StepTimer.js.map +1 -1
  20. package/_esm/components/StepActions/StepActions.js +32 -12
  21. package/_esm/components/StepActions/StepActions.js.map +1 -1
  22. package/_esm/components/StepActions/StepActions.style.d.ts +0 -3
  23. package/_esm/components/StepActions/StepActions.style.js +0 -6
  24. package/_esm/components/StepActions/StepActions.style.js.map +1 -1
  25. package/_esm/components/StepActions/types.d.ts +2 -3
  26. package/_esm/components/TransactionDetails.js +24 -9
  27. package/_esm/components/TransactionDetails.js.map +1 -1
  28. package/_esm/config/version.d.ts +1 -1
  29. package/_esm/config/version.js +1 -1
  30. package/_esm/config/version.js.map +1 -1
  31. package/_esm/hooks/timer/useTimer.js +2 -2
  32. package/_esm/hooks/timer/useTimer.js.map +1 -1
  33. package/_esm/i18n/en.json +4 -2
  34. package/_esm/i18n/index.js +15 -15
  35. package/_esm/i18n/index.js.map +1 -1
  36. package/_esm/pages/TransactionDetailsPage/TransactionDetailsPage.js +3 -2
  37. package/_esm/pages/TransactionDetailsPage/TransactionDetailsPage.js.map +1 -1
  38. package/_esm/pages/TransactionPage/TokenValueBottomSheet.d.ts +0 -1
  39. package/_esm/pages/TransactionPage/TokenValueBottomSheet.js +7 -14
  40. package/_esm/pages/TransactionPage/TokenValueBottomSheet.js.map +1 -1
  41. package/_esm/pages/TransactionPage/TransactionPage.js +16 -8
  42. package/_esm/pages/TransactionPage/TransactionPage.js.map +1 -1
  43. package/_esm/pages/TransactionPage/utils.d.ts +2 -2
  44. package/_esm/pages/TransactionPage/utils.js +9 -5
  45. package/_esm/pages/TransactionPage/utils.js.map +1 -1
  46. package/_esm/stores/routes/types.d.ts +6 -6
  47. package/_esm/stores/routes/types.js +6 -6
  48. package/_esm/stores/routes/types.js.map +1 -1
  49. package/_esm/types/events.d.ts +5 -4
  50. package/_esm/types/widget.d.ts +7 -1
  51. package/_esm/types/widget.js +1 -0
  52. package/_esm/types/widget.js.map +1 -1
  53. package/_esm/utils/converters.js +1 -1
  54. package/_esm/utils/converters.js.map +1 -1
  55. package/_esm/utils/fees.d.ts +7 -0
  56. package/_esm/utils/fees.js +14 -0
  57. package/_esm/utils/fees.js.map +1 -1
  58. package/components/ActiveTransactions/ActiveTransactionItem.tsx +1 -1
  59. package/components/Card/CardIconButton.tsx +4 -1
  60. package/components/FeeBreakdownTooltip.tsx +4 -10
  61. package/components/IconTypography.ts +2 -2
  62. package/components/RouteCard/RouteCardEssentials.tsx +19 -15
  63. package/components/Step/DestinationWalletAddress.tsx +3 -3
  64. package/components/Step/Step.tsx +1 -1
  65. package/components/Step/StepProcess.tsx +6 -6
  66. package/components/Step/StepTimer.tsx +77 -32
  67. package/components/StepActions/StepActions.style.tsx +0 -8
  68. package/components/StepActions/StepActions.tsx +45 -28
  69. package/components/StepActions/types.ts +2 -2
  70. package/components/TransactionDetails.tsx +80 -44
  71. package/config/version.ts +1 -1
  72. package/hooks/timer/useTimer.ts +4 -2
  73. package/i18n/en.json +4 -2
  74. package/i18n/index.ts +15 -15
  75. package/package.json +10 -10
  76. package/pages/TransactionDetailsPage/TransactionDetailsPage.tsx +6 -5
  77. package/pages/TransactionPage/TokenValueBottomSheet.tsx +32 -19
  78. package/pages/TransactionPage/TransactionPage.tsx +27 -10
  79. package/pages/TransactionPage/utils.ts +23 -8
  80. package/stores/routes/types.ts +6 -6
  81. package/types/events.ts +5 -4
  82. package/types/widget.ts +7 -0
  83. package/utils/converters.ts +1 -1
  84. package/utils/fees.ts +24 -0
  85. package/_esm/components/Step/StepProcess.style.d.ts +0 -9
  86. package/_esm/components/Step/StepProcess.style.js +0 -6
  87. package/_esm/components/Step/StepProcess.style.js.map +0 -1
  88. package/components/Step/StepProcess.style.tsx +0 -9
@@ -8,8 +8,10 @@ import type { CardProps } from '@mui/material';
8
8
  import { Box, Collapse, Tooltip, Typography } from '@mui/material';
9
9
  import { useState } from 'react';
10
10
  import { useTranslation } from 'react-i18next';
11
+ import { formatUnits } from 'viem';
12
+ import { useWidgetConfig } from '../providers/WidgetProvider/WidgetProvider.js';
11
13
  import { isRouteDone } from '../stores/routes/utils.js';
12
- import { getFeeCostsBreakdown, getGasCostsBreakdown } from '../utils/fees.js';
14
+ import { getAccumulatedFeeCostsBreakdown } from '../utils/fees.js';
13
15
  import {
14
16
  convertToSubscriptFormat,
15
17
  formatTokenAmount,
@@ -30,23 +32,14 @@ export const TransactionDetails: React.FC<TransactionDetailsProps> = ({
30
32
  ...props
31
33
  }) => {
32
34
  const { t } = useTranslation();
35
+ const { feeTool } = useWidgetConfig();
33
36
  const [cardExpanded, setCardExpanded] = useState(false);
34
37
 
35
38
  const toggleCard = () => {
36
39
  setCardExpanded((cardExpanded) => !cardExpanded);
37
40
  };
38
-
39
- const gasCosts = getGasCostsBreakdown(route);
40
- const feeCosts = getFeeCostsBreakdown(route, false);
41
- const gasCostUSD = gasCosts.reduce(
42
- (sum, gasCost) => sum + gasCost.amountUSD,
43
- 0,
44
- );
45
- const feeCostUSD = feeCosts.reduce(
46
- (sum, feeCost) => sum + feeCost.amountUSD,
47
- 0,
48
- );
49
- const fees = gasCostUSD + feeCostUSD;
41
+ const { gasCosts, feeCosts, gasCostUSD, feeCostUSD, combinedFeesUSD } =
42
+ getAccumulatedFeeCostsBreakdown(route);
50
43
 
51
44
  const fromTokenAmount = formatTokenAmount(
52
45
  BigInt(route.fromAmount),
@@ -74,38 +67,58 @@ export const TransactionDetails: React.FC<TransactionDetailsProps> = ({
74
67
  roundingMode: 'trunc',
75
68
  });
76
69
 
70
+ const feeCollectionStep = route.steps[0].includedSteps.find(
71
+ (includedStep) => includedStep.tool === 'feeCollection',
72
+ );
73
+
74
+ let feeAmountUSD: number = 0;
75
+
76
+ if (feeCollectionStep) {
77
+ const estimatedFromAmount =
78
+ BigInt(feeCollectionStep.estimate.fromAmount) -
79
+ BigInt(feeCollectionStep.estimate.toAmount);
80
+
81
+ const feeAmount = formatUnits(
82
+ estimatedFromAmount,
83
+ feeCollectionStep.action.fromToken.decimals,
84
+ );
85
+
86
+ feeAmountUSD =
87
+ parseFloat(feeAmount) *
88
+ parseFloat(feeCollectionStep.action.fromToken.priceUSD);
89
+ }
90
+
77
91
  return (
78
92
  <Card selectionColor="secondary" {...props}>
79
93
  <Box display="flex" alignItems="center" px={2} py={1.75}>
80
94
  <Box display="flex" flex={1} alignItems="center" justifyContent="left">
81
95
  <TokenRate route={route} />
82
96
  </Box>
83
- <FeeBreakdownTooltip
84
- route={route}
85
- gasCosts={gasCosts}
86
- feeCosts={feeCosts}
87
- >
88
- <Box
89
- display="flex"
90
- alignItems="center"
91
- onClick={toggleCard}
92
- role="button"
93
- sx={{ cursor: 'pointer' }}
94
- px={1}
95
- >
96
- <IconTypography mr={0.5} fontSize={16}>
97
- <LocalGasStationRounded fontSize="inherit" />
98
- </IconTypography>
99
- <Typography
100
- fontSize={14}
101
- color="text.primary"
102
- fontWeight="600"
103
- lineHeight={1.429}
97
+ <Collapse timeout={100} in={!cardExpanded} mountOnEnter>
98
+ <FeeBreakdownTooltip gasCosts={gasCosts} feeCosts={feeCosts}>
99
+ <Box
100
+ display="flex"
101
+ alignItems="center"
102
+ onClick={toggleCard}
103
+ role="button"
104
+ sx={{ cursor: 'pointer' }}
105
+ px={1}
104
106
  >
105
- {t(`format.currency`, { value: fees })}
106
- </Typography>
107
- </Box>
108
- </FeeBreakdownTooltip>
107
+ <IconTypography mr={0.5} fontSize={16}>
108
+ <LocalGasStationRounded fontSize="inherit" />
109
+ </IconTypography>
110
+ <Typography
111
+ fontSize={14}
112
+ color="text.primary"
113
+ fontWeight="600"
114
+ lineHeight={1.429}
115
+ data-value={combinedFeesUSD}
116
+ >
117
+ {t(`format.currency`, { value: combinedFeesUSD })}
118
+ </Typography>
119
+ </Box>
120
+ </FeeBreakdownTooltip>
121
+ </Collapse>
109
122
  <CardIconButton onClick={toggleCard} size="small">
110
123
  {cardExpanded ? (
111
124
  <ExpandLess fontSize="inherit" />
@@ -118,7 +131,7 @@ export const TransactionDetails: React.FC<TransactionDetailsProps> = ({
118
131
  <Box px={2} pb={2}>
119
132
  <Box display="flex" justifyContent="space-between" mb={0.5}>
120
133
  <Typography variant="body2">{t('main.fees.network')}</Typography>
121
- <FeeBreakdownTooltip route={route} feeCosts={[]}>
134
+ <FeeBreakdownTooltip gasCosts={gasCosts}>
122
135
  <Typography variant="body2">
123
136
  {t(`format.currency`, {
124
137
  value: gasCostUSD,
@@ -129,11 +142,7 @@ export const TransactionDetails: React.FC<TransactionDetailsProps> = ({
129
142
  {feeCosts.length ? (
130
143
  <Box display="flex" justifyContent="space-between" mb={0.5}>
131
144
  <Typography variant="body2">{t('main.fees.provider')}</Typography>
132
- <FeeBreakdownTooltip
133
- route={route}
134
- gasCosts={[]}
135
- feeCosts={feeCosts}
136
- >
145
+ <FeeBreakdownTooltip feeCosts={feeCosts}>
137
146
  <Typography variant="body2">
138
147
  {t(`format.currency`, {
139
148
  value: feeCostUSD,
@@ -142,6 +151,33 @@ export const TransactionDetails: React.FC<TransactionDetailsProps> = ({
142
151
  </FeeBreakdownTooltip>
143
152
  </Box>
144
153
  ) : null}
154
+ {feeAmountUSD ? (
155
+ <Box display="flex" justifyContent="space-between" mb={0.5}>
156
+ <Typography variant="body2">
157
+ {feeTool?.name
158
+ ? t('main.fees.integrator', { tool: feeTool.name })
159
+ : t('main.fees.defaultIntegrator')}
160
+ </Typography>
161
+ {feeTool?.name ? (
162
+ <Tooltip
163
+ title={t('tooltip.feeCollection', { tool: feeTool.name })}
164
+ sx={{ cursor: 'help' }}
165
+ >
166
+ <Typography variant="body2">
167
+ {t(`format.currency`, {
168
+ value: feeAmountUSD,
169
+ })}
170
+ </Typography>
171
+ </Tooltip>
172
+ ) : (
173
+ <Typography variant="body2">
174
+ {t(`format.currency`, {
175
+ value: feeAmountUSD,
176
+ })}
177
+ </Typography>
178
+ )}
179
+ </Box>
180
+ ) : null}
145
181
  <Box display="flex" justifyContent="space-between" mb={0.5}>
146
182
  <Typography variant="body2">{t('main.priceImpact')}</Typography>
147
183
  <Tooltip title={t('tooltip.priceImpact')} sx={{ cursor: 'help' }}>
package/config/version.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  export const name = '@lifi/widget';
2
- export const version = '3.2.2';
2
+ export const version = '3.4.0-beta.0';
@@ -23,10 +23,12 @@ export function useTimer({
23
23
  autoStart = true,
24
24
  }: UseTimerProps) {
25
25
  const [expiryTimestamp, setExpiryTimestamp] = useState(expiry);
26
- const [seconds, setSeconds] = useState(getSecondsFromExpiry(expiryTimestamp));
26
+ const [seconds, setSeconds] = useState(() =>
27
+ getSecondsFromExpiry(expiryTimestamp),
28
+ );
27
29
  const [isRunning, setIsRunning] = useState(autoStart);
28
30
  const [didStart, setDidStart] = useState(autoStart);
29
- const [delay, setDelay] = useState(
31
+ const [delay, setDelay] = useState(() =>
30
32
  getDelayFromExpiryTimestamp(expiryTimestamp, DEFAULT_DELAY),
31
33
  );
32
34
 
package/i18n/en.json CHANGED
@@ -169,7 +169,8 @@
169
169
  },
170
170
  "tooltip": {
171
171
  "deselectAll": "Deselect all",
172
- "estimatedTime": "Estimated execution time in minutes.",
172
+ "estimatedTime": "Estimated time to complete the swap or bridge transaction, excluding chain switching and token approval.",
173
+ "feeCollection": "The fee is applied to selected token pairs and ensures the best experience with {{tool}}.",
173
174
  "minReceived": "The estimated minimum amount may change until the swapping/bridging transaction is signed. For 2-step transfers, this applies until the second step transaction is signed.",
174
175
  "notFound": {
175
176
  "text": "We couldn't find this page.",
@@ -190,13 +191,14 @@
190
191
  "depositStepDetails": "Deposit via {{tool}}",
191
192
  "featuredTokens": "Featured tokens",
192
193
  "fees": {
194
+ "defaultIntegrator": "Integrator fee",
193
195
  "estimated": "estimated costs",
196
+ "integrator": "{{tool}} fee",
194
197
  "network": "Network cost",
195
198
  "paid": "paid costs",
196
199
  "provider": "Provider fee"
197
200
  },
198
201
  "from": "From",
199
- "gasCost": "Gas cost",
200
202
  "inProgress": "in progress",
201
203
  "maxSlippage": "Max. slippage",
202
204
  "minReceived": "Min. received",
package/i18n/index.ts CHANGED
@@ -1,17 +1,17 @@
1
- import bn from './bn.json' assert { type: 'json' };
2
- import de from './de.json' assert { type: 'json' };
3
- import en from './en.json' assert { type: 'json' };
4
- import es from './es.json' assert { type: 'json' };
5
- import fr from './fr.json' assert { type: 'json' };
6
- import id from './id.json' assert { type: 'json' };
7
- import it from './it.json' assert { type: 'json' };
8
- import ja from './ja.json' assert { type: 'json' };
9
- import ko from './ko.json' assert { type: 'json' };
10
- import pt from './pt.json' assert { type: 'json' };
11
- import th from './th.json' assert { type: 'json' };
12
- import tr from './tr.json' assert { type: 'json' };
13
- import uk from './uk.json' assert { type: 'json' };
14
- import vi from './vi.json' assert { type: 'json' };
15
- import zh from './zh.json' assert { type: 'json' };
1
+ import bn from './bn.json' with { type: 'json' };
2
+ import de from './de.json' with { type: 'json' };
3
+ import en from './en.json' with { type: 'json' };
4
+ import es from './es.json' with { type: 'json' };
5
+ import fr from './fr.json' with { type: 'json' };
6
+ import id from './id.json' with { type: 'json' };
7
+ import it from './it.json' with { type: 'json' };
8
+ import ja from './ja.json' with { type: 'json' };
9
+ import ko from './ko.json' with { type: 'json' };
10
+ import pt from './pt.json' with { type: 'json' };
11
+ import th from './th.json' with { type: 'json' };
12
+ import tr from './tr.json' with { type: 'json' };
13
+ import uk from './uk.json' with { type: 'json' };
14
+ import vi from './vi.json' with { type: 'json' };
15
+ import zh from './zh.json' with { type: 'json' };
16
16
 
17
17
  export { bn, de, en, es, fr, id, it, ja, ko, pt, th, tr, uk, vi, zh };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lifi/widget",
3
- "version": "3.2.2",
3
+ "version": "3.4.0-beta.0",
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": "./_esm/index.js",
@@ -35,15 +35,15 @@
35
35
  "@emotion/react": "^11.13.0",
36
36
  "@emotion/styled": "^11.13.0",
37
37
  "@lifi/sdk": "^3.1.3",
38
- "@lifi/wallet-management": "^3.0.5",
39
- "@mui/icons-material": "^5.16.4",
40
- "@mui/lab": "^5.0.0-alpha.172",
41
- "@mui/material": "^5.16.4",
38
+ "@lifi/wallet-management": "^3.0.7-beta.0",
39
+ "@mui/icons-material": "^5.16.5",
40
+ "@mui/lab": "^5.0.0-alpha.173",
41
+ "@mui/material": "^5.16.5",
42
42
  "@solana/wallet-adapter-base": "^0.9.23",
43
43
  "@solana/wallet-adapter-react": "^0.15.35",
44
- "@solana/web3.js": "^1.95.1",
45
- "@tanstack/react-query": "^5.51.11",
46
- "@tanstack/react-virtual": "^3.8.3",
44
+ "@solana/web3.js": "^1.95.2",
45
+ "@tanstack/react-query": "^5.51.15",
46
+ "@tanstack/react-virtual": "^3.8.4",
47
47
  "i18next": "^23.12.2",
48
48
  "microdiff": "^1.4.0",
49
49
  "mitt": "^3.0.1",
@@ -53,8 +53,8 @@
53
53
  "react-intersection-observer": "^9.13.0",
54
54
  "react-router-dom": "^6.25.1",
55
55
  "uuid": "^10.0.0",
56
- "viem": "^2.17.11",
57
- "wagmi": "^2.12.0",
56
+ "viem": "^2.18.5",
57
+ "wagmi": "^2.12.1",
58
58
  "zustand": "^4.5.4"
59
59
  },
60
60
  "peerDependencies": {
@@ -1,10 +1,11 @@
1
1
  import type { FullStatusData } from '@lifi/sdk';
2
2
  import { ContentCopyRounded } from '@mui/icons-material';
3
- import { Box, IconButton, Typography } from '@mui/material';
3
+ import { Box, Typography } from '@mui/material';
4
4
  import { useEffect, useMemo } from 'react';
5
5
  import { useTranslation } from 'react-i18next';
6
6
  import { useLocation } from 'react-router-dom';
7
7
  import { Card } from '../../components/Card/Card.js';
8
+ import { CardIconButton } from '../../components/Card/CardIconButton.js';
8
9
  import { CardTitle } from '../../components/Card/CardTitle.js';
9
10
  import { ContractComponent } from '../../components/ContractComponent/ContractComponent.js';
10
11
  import { PageContainer } from '../../components/PageContainer.js';
@@ -124,10 +125,10 @@ export const TransactionDetailsPage: React.FC = () => {
124
125
  }}
125
126
  >
126
127
  <CardTitle flex={1}>{t('main.supportId')}</CardTitle>
127
- <Box mr={1} mt={1}>
128
- <IconButton size="medium" onClick={copySupportId}>
129
- <ContentCopyRounded fontSize="small" />
130
- </IconButton>
128
+ <Box mr={2} mt={1}>
129
+ <CardIconButton size="small" onClick={copySupportId}>
130
+ <ContentCopyRounded fontSize="inherit" />
131
+ </CardIconButton>
131
132
  </Box>
132
133
  </Box>
133
134
  <Typography
@@ -6,9 +6,11 @@ import { forwardRef, useRef } from 'react';
6
6
  import { useTranslation } from 'react-i18next';
7
7
  import { BottomSheet } from '../../components/BottomSheet/BottomSheet.js';
8
8
  import type { BottomSheetBase } from '../../components/BottomSheet/types.js';
9
+ import { FeeBreakdownTooltip } from '../../components/FeeBreakdownTooltip.js';
9
10
  import { useSetContentHeight } from '../../hooks/useContentHeight.js';
11
+ import { getAccumulatedFeeCostsBreakdown } from '../../utils/fees.js';
10
12
  import { CenterContainer, IconCircle } from './StatusBottomSheet.style.js';
11
- import { calcValueLoss } from './utils.js';
13
+ import { calculateValueLossPercentage } from './utils.js';
12
14
 
13
15
  interface TokenValueBottomSheetProps {
14
16
  route: Route;
@@ -44,6 +46,10 @@ const TokenValueBottomSheetContent: React.FC<TokenValueBottomSheetProps> = ({
44
46
  const { t } = useTranslation();
45
47
  const ref = useRef<HTMLElement>();
46
48
  useSetContentHeight(ref);
49
+ const { gasCosts, feeCosts, gasCostUSD, feeCostUSD } =
50
+ getAccumulatedFeeCostsBreakdown(route);
51
+ const fromAmountUSD = parseFloat(route.fromAmountUSD);
52
+ const toAmountUSD = parseFloat(route.toAmountUSD);
47
53
  return (
48
54
  <Box p={3} ref={ref}>
49
55
  <CenterContainer>
@@ -62,11 +68,23 @@ const TokenValueBottomSheetContent: React.FC<TokenValueBottomSheetProps> = ({
62
68
  </Typography>
63
69
  </Box>
64
70
  <Box display="flex" justifyContent="space-between" mt={0.25}>
65
- <Typography>{t('main.gasCost')}</Typography>
66
- <Typography fontWeight={600}>
67
- {t('format.currency', { value: route.gasCostUSD })}
68
- </Typography>
71
+ <Typography>{t('main.fees.network')}</Typography>
72
+ <FeeBreakdownTooltip gasCosts={gasCosts}>
73
+ <Typography fontWeight={600}>
74
+ {t('format.currency', { value: gasCostUSD })}
75
+ </Typography>
76
+ </FeeBreakdownTooltip>
69
77
  </Box>
78
+ {feeCostUSD ? (
79
+ <Box display="flex" justifyContent="space-between" mt={0.25}>
80
+ <Typography>{t('main.fees.provider')}</Typography>
81
+ <FeeBreakdownTooltip feeCosts={feeCosts}>
82
+ <Typography fontWeight={600}>
83
+ {t('format.currency', { value: feeCostUSD })}
84
+ </Typography>
85
+ </FeeBreakdownTooltip>
86
+ </Box>
87
+ ) : null}
70
88
  <Box display="flex" justifyContent="space-between" mt={0.25}>
71
89
  <Typography>{t('main.receiving')}</Typography>
72
90
  <Typography fontWeight={600}>
@@ -75,7 +93,15 @@ const TokenValueBottomSheetContent: React.FC<TokenValueBottomSheetProps> = ({
75
93
  </Box>
76
94
  <Box display="flex" justifyContent="space-between" mt={0.25}>
77
95
  <Typography>{t('main.valueLoss')}</Typography>
78
- <Typography fontWeight={600}>{calcValueLoss(route)}</Typography>
96
+ <Typography fontWeight={600}>
97
+ {calculateValueLossPercentage(
98
+ fromAmountUSD,
99
+ toAmountUSD,
100
+ gasCostUSD,
101
+ feeCostUSD,
102
+ )}
103
+ %
104
+ </Typography>
79
105
  </Box>
80
106
  <Box display="flex" mt={3}>
81
107
  <Button variant="text" onClick={onCancel} fullWidth>
@@ -89,16 +115,3 @@ const TokenValueBottomSheetContent: React.FC<TokenValueBottomSheetProps> = ({
89
115
  </Box>
90
116
  );
91
117
  };
92
-
93
- export const getTokenValueLossThreshold = (route?: Route) => {
94
- if (!route) {
95
- return false;
96
- }
97
- const fromAmountUSD = Number(route.fromAmountUSD || 0);
98
- const toAmountUSD = Number(route.toAmountUSD || 0);
99
- const gasCostUSD = Number(route.gasCostUSD || 0);
100
- if (!fromAmountUSD && !toAmountUSD) {
101
- return false;
102
- }
103
- return toAmountUSD / (fromAmountUSD + gasCostUSD) < 0.9;
104
- };
@@ -18,16 +18,17 @@ import { useWidgetConfig } from '../../providers/WidgetProvider/WidgetProvider.j
18
18
  import { useFieldActions } from '../../stores/form/useFieldActions.js';
19
19
  import { RouteExecutionStatus } from '../../stores/routes/types.js';
20
20
  import { WidgetEvent } from '../../types/events.js';
21
+ import { getAccumulatedFeeCostsBreakdown } from '../../utils/fees.js';
21
22
  import type { ExchangeRateBottomSheetBase } from './ExchangeRateBottomSheet.js';
22
23
  import { ExchangeRateBottomSheet } from './ExchangeRateBottomSheet.js';
23
24
  import { RouteTracker } from './RouteTracker.js';
24
25
  import { StartTransactionButton } from './StartTransactionButton.js';
25
26
  import { StatusBottomSheet } from './StatusBottomSheet.js';
27
+ import { TokenValueBottomSheet } from './TokenValueBottomSheet.js';
26
28
  import {
27
- TokenValueBottomSheet,
29
+ calculateValueLossPercentage,
28
30
  getTokenValueLossThreshold,
29
- } from './TokenValueBottomSheet.js';
30
- import { calcValueLoss } from './utils.js';
31
+ } from './utils.js';
31
32
 
32
33
  export const TransactionPage: React.FC = () => {
33
34
  const { t } = useTranslation();
@@ -99,15 +100,22 @@ export const TransactionPage: React.FC = () => {
99
100
  return null;
100
101
  }
101
102
 
102
- const tokenValueLossThresholdExceeded = getTokenValueLossThreshold(route);
103
-
104
103
  const handleExecuteRoute = () => {
105
104
  if (tokenValueBottomSheetRef.current?.isOpen()) {
105
+ const { gasCostUSD, feeCostUSD } = getAccumulatedFeeCostsBreakdown(route);
106
+ const fromAmountUSD = parseFloat(route.fromAmountUSD);
107
+ const toAmountUSD = parseFloat(route.toAmountUSD);
106
108
  emitter.emit(WidgetEvent.RouteHighValueLoss, {
107
- fromAmountUsd: route.fromAmountUSD,
108
- gasCostUSD: route.gasCostUSD,
109
- toAmountUSD: route.toAmountUSD,
110
- valueLoss: calcValueLoss(route),
109
+ fromAmountUSD,
110
+ toAmountUSD,
111
+ gasCostUSD,
112
+ feeCostUSD,
113
+ valueLoss: calculateValueLossPercentage(
114
+ fromAmountUSD,
115
+ toAmountUSD,
116
+ gasCostUSD,
117
+ feeCostUSD,
118
+ ),
111
119
  });
112
120
  }
113
121
  tokenValueBottomSheetRef.current?.close();
@@ -121,6 +129,15 @@ export const TransactionPage: React.FC = () => {
121
129
 
122
130
  const handleStartClick = async () => {
123
131
  if (status === RouteExecutionStatus.Idle) {
132
+ const { gasCostUSD, feeCostUSD } = getAccumulatedFeeCostsBreakdown(route);
133
+ const fromAmountUSD = parseFloat(route.fromAmountUSD);
134
+ const toAmountUSD = parseFloat(route.toAmountUSD);
135
+ const tokenValueLossThresholdExceeded = getTokenValueLossThreshold(
136
+ fromAmountUSD,
137
+ toAmountUSD,
138
+ gasCostUSD,
139
+ feeCostUSD,
140
+ );
124
141
  if (tokenValueLossThresholdExceeded && subvariant !== 'custom') {
125
142
  tokenValueBottomSheetRef.current?.open();
126
143
  } else {
@@ -197,7 +214,7 @@ export const TransactionPage: React.FC = () => {
197
214
  </>
198
215
  ) : null}
199
216
  {status ? <StatusBottomSheet status={status} route={route} /> : null}
200
- {tokenValueLossThresholdExceeded && subvariant !== 'custom' ? (
217
+ {subvariant !== 'custom' ? (
201
218
  <TokenValueBottomSheet
202
219
  route={route}
203
220
  ref={tokenValueBottomSheetRef}
@@ -1,10 +1,25 @@
1
- import type { Route } from '@lifi/sdk';
1
+ export const calculateValueLossPercentage = (
2
+ fromAmountUSD: number,
3
+ toAmountUSD: number,
4
+ gasCostUSD: number,
5
+ feeCostUSD: number,
6
+ ) => {
7
+ return parseFloat(
8
+ (
9
+ (toAmountUSD / (fromAmountUSD + gasCostUSD + feeCostUSD) - 1) *
10
+ 100
11
+ ).toFixed(2),
12
+ );
13
+ };
2
14
 
3
- export const calcValueLoss = (route: Route) => {
4
- return `${(
5
- (Number(route.toAmountUSD || 0) /
6
- (Number(route.fromAmountUSD || 0) + Number(route.gasCostUSD || 0)) -
7
- 1) *
8
- 100
9
- ).toFixed(2)}%`;
15
+ export const getTokenValueLossThreshold = (
16
+ fromAmountUSD: number,
17
+ toAmountUSD: number,
18
+ gasCostUSD: number,
19
+ feeCostUSD: number,
20
+ ) => {
21
+ if (!fromAmountUSD || !toAmountUSD) {
22
+ return false;
23
+ }
24
+ return toAmountUSD / (fromAmountUSD + gasCostUSD + feeCostUSD) < 0.9;
10
25
  };
@@ -15,10 +15,10 @@ export interface RouteExecutionState {
15
15
  }
16
16
 
17
17
  export enum RouteExecutionStatus {
18
- Idle = 0,
19
- Pending = 1 << 0,
20
- Done = 1 << 1,
21
- Failed = 1 << 2,
22
- Partial = 1 << 3,
23
- Refunded = 1 << 4,
18
+ Idle = 1 << 0,
19
+ Pending = 1 << 1,
20
+ Done = 1 << 2,
21
+ Failed = 1 << 3,
22
+ Partial = 1 << 4,
23
+ Refunded = 1 << 5,
24
24
  }
package/types/events.ts CHANGED
@@ -37,10 +37,11 @@ export interface ContactSupport {
37
37
  }
38
38
 
39
39
  export interface RouteHighValueLossUpdate {
40
- fromAmountUsd: string;
41
- gasCostUSD?: string;
42
- toAmountUSD: string;
43
- valueLoss: string;
40
+ fromAmountUSD: number;
41
+ toAmountUSD: number;
42
+ gasCostUSD?: number;
43
+ feeCostUSD?: number;
44
+ valueLoss: number;
44
45
  }
45
46
 
46
47
  export interface RouteExecutionUpdate {
package/types/widget.ts CHANGED
@@ -83,6 +83,7 @@ export enum HiddenUI {
83
83
  ToAddress = 'toAddress',
84
84
  ToToken = 'toToken',
85
85
  WalletMenu = 'walletMenu',
86
+ FeeCollectionStepDetails = 'feeCollectionStepDetails',
86
87
  }
87
88
  export type HiddenUIType = `${HiddenUI}`;
88
89
 
@@ -114,6 +115,11 @@ export interface WidgetContractTool {
114
115
  name: string;
115
116
  }
116
117
 
118
+ export interface WidgetFeeTool {
119
+ logoURI: string;
120
+ name: string;
121
+ }
122
+
117
123
  export interface ToAddress {
118
124
  name?: string;
119
125
  address: string;
@@ -145,6 +151,7 @@ export interface WidgetConfig {
145
151
  integrator: string;
146
152
  apiKey?: string;
147
153
  fee?: number;
154
+ feeTool?: WidgetFeeTool;
148
155
  referrer?: string;
149
156
 
150
157
  routePriority?: Order;
@@ -167,7 +167,7 @@ export const buildRouteFromTxHistory = (
167
167
  toAmountMin: receiving.amount ?? '',
168
168
  toAmount: receiving.amount ?? '',
169
169
  toAmountUSD: receiving.amountUSD ?? '',
170
- executionDuration: 30,
170
+ executionDuration: 0,
171
171
  },
172
172
  includedSteps: [
173
173
  {
package/utils/fees.ts CHANGED
@@ -7,6 +7,30 @@ export interface FeesBreakdown {
7
7
  token: Token;
8
8
  }
9
9
 
10
+ export const getAccumulatedFeeCostsBreakdown = (
11
+ route: RouteExtended,
12
+ included: boolean = false,
13
+ ) => {
14
+ const gasCosts = getGasCostsBreakdown(route);
15
+ const feeCosts = getFeeCostsBreakdown(route, included);
16
+ const gasCostUSD = gasCosts.reduce(
17
+ (sum, gasCost) => sum + gasCost.amountUSD,
18
+ 0,
19
+ );
20
+ const feeCostUSD = feeCosts.reduce(
21
+ (sum, feeCost) => sum + feeCost.amountUSD,
22
+ 0,
23
+ );
24
+ const combinedFeesUSD = gasCostUSD + feeCostUSD;
25
+ return {
26
+ gasCosts,
27
+ feeCosts,
28
+ gasCostUSD,
29
+ feeCostUSD,
30
+ combinedFeesUSD,
31
+ };
32
+ };
33
+
10
34
  export const getGasCostsBreakdown = (route: RouteExtended): FeesBreakdown[] => {
11
35
  return Array.from(
12
36
  route.steps
@@ -1,9 +0,0 @@
1
- export declare const LinkButton: import("@emotion/styled").StyledComponent<import("@mui/material").IconButtonOwnProps & Omit<import("@mui/material").ButtonBaseOwnProps, "classes"> & import("@mui/material/OverridableComponent.js").CommonProps & Omit<Omit<import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "ref"> & {
2
- ref?: ((instance: HTMLButtonElement | null) => void | import("react").DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES[keyof import("react").DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES]) | import("react").RefObject<HTMLButtonElement> | null | undefined;
3
- }, "color" | "children" | "sx" | "style" | "className" | "tabIndex" | "disabled" | "action" | "size" | "classes" | "centerRipple" | "disableRipple" | "disableTouchRipple" | "focusRipple" | "focusVisibleClassName" | "LinkComponent" | "onFocusVisible" | "TouchRippleProps" | "touchRippleRef" | "disableFocusRipple" | "edge"> & import("@mui/system").MUIStyledCommonProps<import("@mui/material").Theme> & {
4
- component?: import("react").ElementType;
5
- } & import("@mui/material").LinkOwnProps & Omit<Omit<import("react").DetailedHTMLProps<import("react").AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>, "ref"> & {
6
- ref?: ((instance: HTMLAnchorElement | null) => void | import("react").DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES[keyof import("react").DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES]) | import("react").RefObject<HTMLAnchorElement> | null | undefined;
7
- }, "border" | "borderTop" | "borderRight" | "borderBottom" | "borderLeft" | "borderColor" | "borderRadius" | "display" | "displayPrint" | "overflow" | "textOverflow" | "visibility" | "whiteSpace" | "flexBasis" | "flexDirection" | "flexWrap" | "justifyContent" | "alignItems" | "alignContent" | "order" | "flex" | "flexGrow" | "flexShrink" | "alignSelf" | "justifyItems" | "justifySelf" | "gap" | "columnGap" | "rowGap" | "gridColumn" | "gridRow" | "gridAutoFlow" | "gridAutoColumns" | "gridAutoRows" | "gridTemplateColumns" | "gridTemplateRows" | "gridTemplateAreas" | "gridArea" | "bgcolor" | "color" | "zIndex" | "position" | "top" | "right" | "bottom" | "left" | "boxShadow" | "width" | "maxWidth" | "minWidth" | "height" | "maxHeight" | "minHeight" | "boxSizing" | "m" | "mt" | "mr" | "mb" | "ml" | "mx" | "my" | "p" | "pt" | "pr" | "pb" | "pl" | "px" | "py" | "margin" | "marginTop" | "marginRight" | "marginBottom" | "marginLeft" | "marginX" | "marginY" | "marginInline" | "marginInlineStart" | "marginInlineEnd" | "marginBlock" | "marginBlockStart" | "marginBlockEnd" | "padding" | "paddingTop" | "paddingRight" | "paddingBottom" | "paddingLeft" | "paddingX" | "paddingY" | "paddingInline" | "paddingInlineStart" | "paddingInlineEnd" | "paddingBlock" | "paddingBlockStart" | "paddingBlockEnd" | "typography" | "fontFamily" | "fontSize" | "fontStyle" | "fontWeight" | "letterSpacing" | "lineHeight" | "textAlign" | "textTransform" | "children" | "sx" | "style" | "className" | "align" | "classes" | "gutterBottom" | "noWrap" | "paragraph" | "variant" | "variantMapping" | "TypographyClasses" | "underline"> & {
8
- component?: import("react").ElementType;
9
- }, {}, {}>;
@@ -1,6 +0,0 @@
1
- import { styled } from '@mui/material';
2
- import { CardIconButton } from '../Card/CardIconButton.js';
3
- export const LinkButton = styled(CardIconButton)(({ theme }) => ({
4
- padding: theme.spacing(0.5),
5
- }));
6
- //# sourceMappingURL=StepProcess.style.js.map