@lifi/widget 3.14.0-beta.0 → 3.14.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.
- package/CHANGELOG.md +22 -0
- package/dist/esm/components/ActiveTransactions/ActiveTransactionItem.js +0 -1
- package/dist/esm/components/ActiveTransactions/ActiveTransactionItem.js.map +1 -1
- package/dist/esm/components/AlertMessage/AlertMessage.d.ts +2 -2
- package/dist/esm/components/AlertMessage/AlertMessage.js +1 -1
- package/dist/esm/components/AlertMessage/AlertMessage.js.map +1 -1
- package/dist/esm/components/AmountInput/PriceFormHelperText.js +7 -4
- package/dist/esm/components/AmountInput/PriceFormHelperText.js.map +1 -1
- package/dist/esm/components/FeeBreakdownTooltip.js +3 -4
- package/dist/esm/components/FeeBreakdownTooltip.js.map +1 -1
- package/dist/esm/components/GasMessage/FundsSufficiencyMessage.js +1 -1
- package/dist/esm/components/GasMessage/FundsSufficiencyMessage.js.map +1 -1
- package/dist/esm/components/RouteCard/RouteCard.js +4 -8
- package/dist/esm/components/RouteCard/RouteCard.js.map +1 -1
- package/dist/esm/components/Step/CircularProgress.js +1 -2
- package/dist/esm/components/Step/CircularProgress.js.map +1 -1
- package/dist/esm/components/Step/CircularProgress.style.js +2 -13
- package/dist/esm/components/Step/CircularProgress.style.js.map +1 -1
- package/dist/esm/components/Step/StepProcess.js +1 -2
- package/dist/esm/components/Step/StepProcess.js.map +1 -1
- package/dist/esm/components/Step/StepTimer.js +1 -2
- package/dist/esm/components/Step/StepTimer.js.map +1 -1
- package/dist/esm/components/StepActions/StepActions.js +8 -8
- package/dist/esm/components/StepActions/StepActions.js.map +1 -1
- package/dist/esm/components/ToAddressRequiredMessage.js +1 -1
- package/dist/esm/components/ToAddressRequiredMessage.js.map +1 -1
- package/dist/esm/components/Token/Token.js +3 -3
- package/dist/esm/components/Token/Token.js.map +1 -1
- package/dist/esm/components/TokenList/TokenListItem.js +4 -6
- package/dist/esm/components/TokenList/TokenListItem.js.map +1 -1
- package/dist/esm/components/TokenRate/TokenRate.js +5 -7
- package/dist/esm/components/TokenRate/TokenRate.js.map +1 -1
- package/dist/esm/components/TransactionDetails.js +3 -7
- package/dist/esm/components/TransactionDetails.js.map +1 -1
- package/dist/esm/config/version.d.ts +1 -1
- package/dist/esm/config/version.js +1 -1
- package/dist/esm/config/version.js.map +1 -1
- package/dist/esm/hooks/useProcessMessage.js +6 -18
- package/dist/esm/hooks/useProcessMessage.js.map +1 -1
- package/dist/esm/hooks/useRoutes.d.ts +2 -2
- package/dist/esm/hooks/useRoutes.js +58 -99
- package/dist/esm/hooks/useRoutes.js.map +1 -1
- package/dist/esm/hooks/useSetContentHeight.d.ts +1 -1
- package/dist/esm/hooks/useSetContentHeight.js +3 -2
- package/dist/esm/hooks/useSetContentHeight.js.map +1 -1
- package/dist/esm/i18n/en.json +14 -16
- package/dist/esm/index.d.ts +3 -0
- package/dist/esm/index.js +3 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/pages/SendToWallet/ConfirmAddressSheet.d.ts +1 -0
- package/dist/esm/pages/SendToWallet/ConfirmAddressSheet.js +22 -14
- package/dist/esm/pages/SendToWallet/ConfirmAddressSheet.js.map +1 -1
- package/dist/esm/pages/SendToWallet/SendToWalletPage.js +5 -3
- package/dist/esm/pages/SendToWallet/SendToWalletPage.js.map +1 -1
- package/dist/esm/pages/TransactionPage/ExchangeRateBottomSheet.js +2 -2
- package/dist/esm/pages/TransactionPage/ExchangeRateBottomSheet.js.map +1 -1
- package/dist/esm/providers/I18nProvider/I18nProvider.js +4 -2
- package/dist/esm/providers/I18nProvider/I18nProvider.js.map +1 -1
- package/dist/esm/providers/WalletProvider/SDKProviders.js +15 -2
- package/dist/esm/providers/WalletProvider/SDKProviders.js.map +1 -1
- package/dist/esm/providers/WalletProvider/getSafeMultisigConfig.d.ts +8 -0
- package/dist/esm/providers/WalletProvider/getSafeMultisigConfig.js +95 -0
- package/dist/esm/providers/WalletProvider/getSafeMultisigConfig.js.map +1 -0
- package/dist/esm/types/widget.d.ts +0 -1
- package/dist/esm/utils/compactNumberFormatter.d.ts +10 -0
- package/dist/esm/utils/compactNumberFormatter.js +81 -0
- package/dist/esm/utils/compactNumberFormatter.js.map +1 -0
- package/dist/esm/utils/compactNumberFormatter.test.d.ts +1 -0
- package/dist/esm/utils/compactNumberFormatter.test.js +64 -0
- package/dist/esm/utils/compactNumberFormatter.test.js.map +1 -0
- package/dist/esm/utils/converters.js +2 -2
- package/dist/esm/utils/converters.js.map +1 -1
- package/dist/esm/utils/currencyExtendedFormatter.js.map +1 -0
- package/dist/esm/utils/fees.js +2 -3
- package/dist/esm/utils/fees.js.map +1 -1
- package/dist/esm/utils/format.d.ts +1 -10
- package/dist/esm/utils/format.js +8 -47
- package/dist/esm/utils/format.js.map +1 -1
- package/dist/esm/utils/getPriceImpact.js +7 -6
- package/dist/esm/utils/getPriceImpact.js.map +1 -1
- package/dist/esm/utils/percentFormatter.js.map +1 -0
- package/package.json +8 -8
- package/src/components/ActiveTransactions/ActiveTransactionItem.tsx +0 -1
- package/src/components/AlertMessage/AlertMessage.tsx +3 -3
- package/src/components/AmountInput/PriceFormHelperText.tsx +8 -4
- package/src/components/FeeBreakdownTooltip.tsx +3 -4
- package/src/components/GasMessage/FundsSufficiencyMessage.tsx +1 -1
- package/src/components/RouteCard/RouteCard.tsx +6 -9
- package/src/components/Step/CircularProgress.style.tsx +2 -13
- package/src/components/Step/CircularProgress.tsx +1 -2
- package/src/components/Step/StepProcess.tsx +1 -2
- package/src/components/Step/StepTimer.tsx +1 -3
- package/src/components/StepActions/StepActions.tsx +16 -13
- package/src/components/ToAddressRequiredMessage.tsx +1 -1
- package/src/components/Token/Token.tsx +7 -2
- package/src/components/TokenList/TokenListItem.tsx +9 -9
- package/src/components/TokenRate/TokenRate.tsx +5 -11
- package/src/components/TransactionDetails.tsx +4 -8
- package/src/config/version.ts +1 -1
- package/src/hooks/useProcessMessage.ts +5 -24
- package/src/hooks/useRoutes.ts +66 -127
- package/src/hooks/useSetContentHeight.ts +4 -2
- package/src/i18n/en.json +14 -16
- package/src/index.ts +3 -0
- package/src/pages/SendToWallet/ConfirmAddressSheet.tsx +81 -40
- package/src/pages/SendToWallet/SendToWalletPage.tsx +8 -2
- package/src/pages/TransactionPage/ExchangeRateBottomSheet.tsx +2 -2
- package/src/providers/I18nProvider/I18nProvider.tsx +4 -2
- package/src/providers/WalletProvider/SDKProviders.tsx +16 -2
- package/src/providers/WalletProvider/getSafeMultisigConfig.ts +144 -0
- package/src/types/widget.ts +0 -1
- package/src/utils/compactNumberFormatter.test.ts +67 -0
- package/src/utils/compactNumberFormatter.ts +91 -0
- package/src/utils/converters.ts +6 -4
- package/src/utils/fees.ts +6 -4
- package/src/utils/format.ts +14 -60
- package/src/utils/getPriceImpact.ts +15 -6
- package/dist/esm/providers/I18nProvider/currencyExtendedFormatter.js.map +0 -1
- package/dist/esm/providers/I18nProvider/percentFormatter.js.map +0 -1
- /package/dist/esm/{providers/I18nProvider → utils}/currencyExtendedFormatter.d.ts +0 -0
- /package/dist/esm/{providers/I18nProvider → utils}/currencyExtendedFormatter.js +0 -0
- /package/dist/esm/{providers/I18nProvider → utils}/percentFormatter.d.ts +0 -0
- /package/dist/esm/{providers/I18nProvider → utils}/percentFormatter.js +0 -0
- /package/src/{providers/I18nProvider → utils}/currencyExtendedFormatter.ts +0 -0
- /package/src/{providers/I18nProvider → utils}/percentFormatter.ts +0 -0
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
import { Info, Wallet } from '@mui/icons-material'
|
|
2
|
-
import { Button, Typography } from '@mui/material'
|
|
1
|
+
import { Info, Wallet, Warning } from '@mui/icons-material'
|
|
2
|
+
import { Box, Button, Typography } from '@mui/material'
|
|
3
3
|
import type { MutableRefObject } from 'react'
|
|
4
|
-
import { forwardRef } from 'react'
|
|
4
|
+
import { forwardRef, useRef } from 'react'
|
|
5
5
|
import { useTranslation } from 'react-i18next'
|
|
6
6
|
import { AlertMessage } from '../../components/AlertMessage/AlertMessage.js'
|
|
7
7
|
import { BottomSheet } from '../../components/BottomSheet/BottomSheet.js'
|
|
8
8
|
import type { BottomSheetBase } from '../../components/BottomSheet/types.js'
|
|
9
|
+
import { useIsContractAddress } from '../../hooks/useIsContractAddress.js'
|
|
9
10
|
import { useNavigateBack } from '../../hooks/useNavigateBack.js'
|
|
11
|
+
import { useSetContentHeight } from '../../hooks/useSetContentHeight.js'
|
|
10
12
|
import type { Bookmark } from '../../stores/bookmarks/types.js'
|
|
11
13
|
import { useFieldActions } from '../../stores/form/useFieldActions.js'
|
|
12
14
|
import { useSendToWalletActions } from '../../stores/settings/useSendToWalletStore.js'
|
|
@@ -21,20 +23,46 @@ import {
|
|
|
21
23
|
interface ConfirmAddressSheetProps {
|
|
22
24
|
onConfirm: (wallet: Bookmark) => void
|
|
23
25
|
validatedBookmark?: Bookmark
|
|
26
|
+
chainId?: number
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
interface ConfirmAddressSheetContentProps extends ConfirmAddressSheetProps {
|
|
30
|
+
onClose: () => void
|
|
24
31
|
}
|
|
25
32
|
|
|
26
33
|
export const ConfirmAddressSheet = forwardRef<
|
|
27
34
|
BottomSheetBase,
|
|
28
35
|
ConfirmAddressSheetProps
|
|
29
|
-
>((
|
|
36
|
+
>((props, ref) => {
|
|
37
|
+
const handleClose = () => {
|
|
38
|
+
;(ref as MutableRefObject<BottomSheetBase>).current?.close()
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return (
|
|
42
|
+
<BottomSheet ref={ref}>
|
|
43
|
+
<ConfirmAddressSheetContent {...props} onClose={handleClose} />
|
|
44
|
+
</BottomSheet>
|
|
45
|
+
)
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
const ConfirmAddressSheetContent: React.FC<ConfirmAddressSheetContentProps> = ({
|
|
49
|
+
validatedBookmark,
|
|
50
|
+
onConfirm,
|
|
51
|
+
chainId,
|
|
52
|
+
onClose,
|
|
53
|
+
}) => {
|
|
30
54
|
const { t } = useTranslation()
|
|
31
55
|
const { navigateBack } = useNavigateBack()
|
|
32
56
|
const { setFieldValue } = useFieldActions()
|
|
33
57
|
const { setSendToWallet } = useSendToWalletActions()
|
|
58
|
+
const isContractAddress = useIsContractAddress(
|
|
59
|
+
validatedBookmark?.address,
|
|
60
|
+
chainId,
|
|
61
|
+
validatedBookmark?.chainType
|
|
62
|
+
)
|
|
34
63
|
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
}
|
|
64
|
+
const containerRef = useRef<HTMLElement>(null)
|
|
65
|
+
useSetContentHeight(containerRef, isContractAddress)
|
|
38
66
|
|
|
39
67
|
const handleConfirm = () => {
|
|
40
68
|
if (validatedBookmark) {
|
|
@@ -44,48 +72,61 @@ export const ConfirmAddressSheet = forwardRef<
|
|
|
44
72
|
})
|
|
45
73
|
onConfirm?.(validatedBookmark)
|
|
46
74
|
setSendToWallet(true)
|
|
47
|
-
|
|
75
|
+
onClose()
|
|
48
76
|
navigateBack()
|
|
49
77
|
}
|
|
50
78
|
}
|
|
51
79
|
|
|
52
80
|
return (
|
|
53
|
-
<
|
|
54
|
-
<
|
|
55
|
-
<
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
81
|
+
<SendToWalletSheetContainer ref={containerRef}>
|
|
82
|
+
<IconContainer>
|
|
83
|
+
<Wallet sx={{ fontSize: 40 }} />
|
|
84
|
+
</IconContainer>
|
|
85
|
+
<SheetTitle>{t('sendToWallet.confirmWalletAddress')}</SheetTitle>
|
|
86
|
+
<SheetAddressContainer>
|
|
87
|
+
{validatedBookmark?.name ? (
|
|
88
|
+
<Typography
|
|
89
|
+
sx={{
|
|
90
|
+
fontWeight: 600,
|
|
91
|
+
mb: 0.5,
|
|
92
|
+
}}
|
|
93
|
+
>
|
|
94
|
+
{validatedBookmark?.name}
|
|
95
|
+
</Typography>
|
|
96
|
+
) : null}
|
|
97
|
+
<Typography>{validatedBookmark?.address}</Typography>
|
|
98
|
+
</SheetAddressContainer>
|
|
99
|
+
<AlertMessage
|
|
100
|
+
title={
|
|
101
|
+
<Box sx={{ display: 'grid', gap: 1 }}>
|
|
102
|
+
<Typography variant="body2" fontWeight={500}>
|
|
103
|
+
{t('info.message.fundsToExchange')}
|
|
68
104
|
</Typography>
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
105
|
+
</Box>
|
|
106
|
+
}
|
|
107
|
+
icon={<Info />}
|
|
108
|
+
multiline
|
|
109
|
+
/>
|
|
110
|
+
{isContractAddress ? (
|
|
72
111
|
<AlertMessage
|
|
73
112
|
title={
|
|
74
|
-
<Typography variant="body2">
|
|
75
|
-
{t('info.message.
|
|
113
|
+
<Typography variant="body2" fontWeight={500}>
|
|
114
|
+
{t('info.message.smartContractAccount')}
|
|
76
115
|
</Typography>
|
|
77
116
|
}
|
|
78
|
-
icon={<
|
|
117
|
+
icon={<Warning />}
|
|
118
|
+
severity="warning"
|
|
119
|
+
multiline
|
|
79
120
|
/>
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
</
|
|
88
|
-
</
|
|
89
|
-
</
|
|
121
|
+
) : null}
|
|
122
|
+
<SendToWalletButtonRow>
|
|
123
|
+
<Button variant="text" onClick={onClose} fullWidth>
|
|
124
|
+
{t('button.cancel')}
|
|
125
|
+
</Button>
|
|
126
|
+
<Button variant="contained" onClick={handleConfirm} fullWidth>
|
|
127
|
+
{t('button.confirm')}
|
|
128
|
+
</Button>
|
|
129
|
+
</SendToWalletButtonRow>
|
|
130
|
+
</SendToWalletSheetContainer>
|
|
90
131
|
)
|
|
91
|
-
}
|
|
132
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ChainType } from '@lifi/sdk'
|
|
1
2
|
import { useAccount } from '@lifi/wallet-management'
|
|
2
3
|
import {
|
|
3
4
|
Error as ErrorIcon,
|
|
@@ -58,8 +59,6 @@ export const SendToWalletPage = () => {
|
|
|
58
59
|
const [validatedWallet, setValidatedWallet] = useState<Bookmark>()
|
|
59
60
|
const [errorMessage, setErrorMessage] = useState('')
|
|
60
61
|
const { validateAddress, isValidating } = useAddressValidation()
|
|
61
|
-
const { accounts } = useAccount()
|
|
62
|
-
const connectedWallets = accounts.filter((account) => account.isConnected)
|
|
63
62
|
const { requiredToChainType } = useToAddressRequirements()
|
|
64
63
|
const [toChainId] = useFieldValues('toChain')
|
|
65
64
|
const { chain: toChain } = useChain(toChainId)
|
|
@@ -67,6 +66,12 @@ export const SendToWalletPage = () => {
|
|
|
67
66
|
const [isBookmarkButtonLoading, setIsBookmarkButtonLoading] = useState(false)
|
|
68
67
|
const { variant } = useWidgetConfig()
|
|
69
68
|
|
|
69
|
+
const { accounts } = useAccount()
|
|
70
|
+
const connectedWallets = accounts.filter((account) => account.isConnected)
|
|
71
|
+
const connectedEVMChainId = connectedWallets.find(
|
|
72
|
+
(account) => account.chainType === ChainType.EVM
|
|
73
|
+
)?.chainId
|
|
74
|
+
|
|
70
75
|
useHeader(t('header.sendToWallet'))
|
|
71
76
|
|
|
72
77
|
const handleInputChange = (e: ChangeEvent) => {
|
|
@@ -241,6 +246,7 @@ export const SendToWalletPage = () => {
|
|
|
241
246
|
ref={confirmAddressSheetRef}
|
|
242
247
|
validatedBookmark={validatedWallet}
|
|
243
248
|
onConfirm={handleOnConfirm}
|
|
249
|
+
chainId={connectedEVMChainId || toChainId}
|
|
244
250
|
/>
|
|
245
251
|
<BookmarkAddressSheet
|
|
246
252
|
ref={bookmarkAddressSheetRef}
|
|
@@ -146,7 +146,7 @@ const ExchangeRateBottomSheetContent: React.FC<
|
|
|
146
146
|
fontWeight: 600,
|
|
147
147
|
}}
|
|
148
148
|
>
|
|
149
|
-
{t('format.
|
|
149
|
+
{t('format.tokenAmount', {
|
|
150
150
|
value: formatTokenAmount(
|
|
151
151
|
BigInt(data.oldToAmount),
|
|
152
152
|
data.toToken.decimals
|
|
@@ -168,7 +168,7 @@ const ExchangeRateBottomSheetContent: React.FC<
|
|
|
168
168
|
fontWeight: 600,
|
|
169
169
|
}}
|
|
170
170
|
>
|
|
171
|
-
{t('format.
|
|
171
|
+
{t('format.tokenAmount', {
|
|
172
172
|
value: formatTokenAmount(
|
|
173
173
|
BigInt(data?.newToAmount),
|
|
174
174
|
data?.toToken.decimals
|
|
@@ -4,11 +4,12 @@ import { useMemo } from 'react'
|
|
|
4
4
|
import { I18nextProvider } from 'react-i18next'
|
|
5
5
|
import * as supportedLanguages from '../../i18n/index.js'
|
|
6
6
|
import { useSettings } from '../../stores/settings/useSettings.js'
|
|
7
|
+
import { compactNumberFormatter } from '../../utils/compactNumberFormatter.js'
|
|
8
|
+
import { currencyExtendedFormatter } from '../../utils/currencyExtendedFormatter.js'
|
|
7
9
|
import { deepMerge } from '../../utils/deepMerge.js'
|
|
8
10
|
import { isItemAllowed } from '../../utils/item.js'
|
|
11
|
+
import { percentFormatter } from '../../utils/percentFormatter.js'
|
|
9
12
|
import { useWidgetConfig } from '../WidgetProvider/WidgetProvider.js'
|
|
10
|
-
import { currencyExtendedFormatter } from './currencyExtendedFormatter.js'
|
|
11
|
-
import { percentFormatter } from './percentFormatter.js'
|
|
12
13
|
import type { LanguageKey, LanguageTranslationResources } from './types.js'
|
|
13
14
|
|
|
14
15
|
export const I18nProvider: React.FC<React.PropsWithChildren> = ({
|
|
@@ -63,6 +64,7 @@ export const I18nProvider: React.FC<React.PropsWithChildren> = ({
|
|
|
63
64
|
|
|
64
65
|
i18n.init()
|
|
65
66
|
|
|
67
|
+
i18n.services.formatter?.addCached('numberExt', compactNumberFormatter)
|
|
66
68
|
i18n.services.formatter?.addCached('currencyExt', currencyExtendedFormatter)
|
|
67
69
|
i18n.services.formatter?.addCached('percent', percentFormatter)
|
|
68
70
|
|
|
@@ -5,18 +5,20 @@ import { ChainType, EVM, Solana, UTXO, config } from '@lifi/sdk'
|
|
|
5
5
|
import type { SignerWalletAdapter } from '@solana/wallet-adapter-base'
|
|
6
6
|
import { useWallet } from '@solana/wallet-adapter-react'
|
|
7
7
|
import { useEffect } from 'react'
|
|
8
|
-
import { useConfig as useWagmiConfig } from 'wagmi'
|
|
8
|
+
import { useAccount, useConfig as useWagmiConfig } from 'wagmi'
|
|
9
9
|
import {
|
|
10
10
|
getConnectorClient as getWagmiConnectorClient,
|
|
11
11
|
switchChain,
|
|
12
12
|
} from 'wagmi/actions'
|
|
13
13
|
import { useWidgetConfig } from '../WidgetProvider/WidgetProvider.js'
|
|
14
|
+
import { getSafeMultisigConfig } from './getSafeMultisigConfig.js'
|
|
14
15
|
|
|
15
16
|
export const SDKProviders = () => {
|
|
16
17
|
const { sdkConfig } = useWidgetConfig()
|
|
17
18
|
const { wallet } = useWallet()
|
|
18
19
|
const wagmiConfig = useWagmiConfig()
|
|
19
20
|
const bigmiConfig = useBigmiConfig()
|
|
21
|
+
const account = useAccount({ config: wagmiConfig })
|
|
20
22
|
|
|
21
23
|
useEffect(() => {
|
|
22
24
|
// Configure SDK Providers
|
|
@@ -31,6 +33,11 @@ export const SDKProviders = () => {
|
|
|
31
33
|
(provider) => provider.type === ChainType.UTXO
|
|
32
34
|
)
|
|
33
35
|
if (!hasConfiguredEVMProvider) {
|
|
36
|
+
// TODO: refactor this in favor of EIP-5792: Wallet Call API
|
|
37
|
+
const multisig =
|
|
38
|
+
account.connector?.id === 'safe'
|
|
39
|
+
? getSafeMultisigConfig(account.connector)
|
|
40
|
+
: undefined
|
|
34
41
|
providers.push(
|
|
35
42
|
EVM({
|
|
36
43
|
getWalletClient: () => getWagmiConnectorClient(wagmiConfig),
|
|
@@ -38,6 +45,7 @@ export const SDKProviders = () => {
|
|
|
38
45
|
const chain = await switchChain(wagmiConfig, { chainId })
|
|
39
46
|
return getWagmiConnectorClient(wagmiConfig, { chainId: chain.id })
|
|
40
47
|
},
|
|
48
|
+
multisig,
|
|
41
49
|
})
|
|
42
50
|
)
|
|
43
51
|
}
|
|
@@ -61,7 +69,13 @@ export const SDKProviders = () => {
|
|
|
61
69
|
providers.push(...sdkConfig.providers)
|
|
62
70
|
}
|
|
63
71
|
config.setProviders(providers)
|
|
64
|
-
}, [
|
|
72
|
+
}, [
|
|
73
|
+
account.connector,
|
|
74
|
+
bigmiConfig,
|
|
75
|
+
sdkConfig?.providers,
|
|
76
|
+
wagmiConfig,
|
|
77
|
+
wallet?.adapter,
|
|
78
|
+
])
|
|
65
79
|
|
|
66
80
|
return null
|
|
67
81
|
}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
import type { MultisigTransaction, MultisigTxDetails } from '@lifi/sdk'
|
|
3
|
+
import type { Connector } from 'wagmi'
|
|
4
|
+
|
|
5
|
+
enum TransactionStatus {
|
|
6
|
+
AWAITING_CONFIRMATIONS = 'AWAITING_CONFIRMATIONS',
|
|
7
|
+
AWAITING_EXECUTION = 'AWAITING_EXECUTION',
|
|
8
|
+
CANCELLED = 'CANCELLED',
|
|
9
|
+
FAILED = 'FAILED',
|
|
10
|
+
SUCCESS = 'SUCCESS',
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
type GatewayTransactionDetails = {
|
|
14
|
+
safeAddress: string
|
|
15
|
+
txId: string
|
|
16
|
+
executedAt?: number
|
|
17
|
+
txStatus: TransactionStatus
|
|
18
|
+
txHash?: string
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const getSafeMultisigConfig = (connector: Connector) => {
|
|
22
|
+
const getMultisigTransactionDetails = async (
|
|
23
|
+
txHash: string,
|
|
24
|
+
chainId: number,
|
|
25
|
+
updateIntermediateStatus?: () => void
|
|
26
|
+
): Promise<MultisigTxDetails> => {
|
|
27
|
+
const safeAppProvider = (await connector.getProvider()) as any
|
|
28
|
+
const safeProviderSDK = safeAppProvider.sdk
|
|
29
|
+
|
|
30
|
+
const safeTransactionDetails: GatewayTransactionDetails =
|
|
31
|
+
await safeProviderSDK.txs.getBySafeTxHash(txHash)
|
|
32
|
+
|
|
33
|
+
const safeTxHash = safeTransactionDetails.txId
|
|
34
|
+
|
|
35
|
+
const safeApiTransactionResponse = await fetch(
|
|
36
|
+
`https://safe-client.safe.global/v1/chains/${chainId}/transactions/${safeTxHash}`
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
const safeApiTransactionDetails = await safeApiTransactionResponse.json()
|
|
40
|
+
|
|
41
|
+
const nonTerminalStatus = [
|
|
42
|
+
TransactionStatus.SUCCESS,
|
|
43
|
+
TransactionStatus.CANCELLED,
|
|
44
|
+
TransactionStatus.FAILED,
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
const isSafeStatusPending =
|
|
48
|
+
!nonTerminalStatus.includes(safeTransactionDetails.txStatus) &&
|
|
49
|
+
!nonTerminalStatus.includes(safeApiTransactionDetails.txStatus)
|
|
50
|
+
|
|
51
|
+
const isAwaitingExecution = [
|
|
52
|
+
safeTransactionDetails.txStatus,
|
|
53
|
+
safeApiTransactionDetails.txStatus,
|
|
54
|
+
].includes(TransactionStatus.AWAITING_EXECUTION)
|
|
55
|
+
|
|
56
|
+
if (isAwaitingExecution) {
|
|
57
|
+
updateIntermediateStatus?.()
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (isSafeStatusPending) {
|
|
61
|
+
await new Promise((resolve) => {
|
|
62
|
+
setTimeout(resolve, 5000)
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
return await getMultisigTransactionDetails(
|
|
66
|
+
txHash,
|
|
67
|
+
chainId,
|
|
68
|
+
updateIntermediateStatus
|
|
69
|
+
)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (
|
|
73
|
+
[
|
|
74
|
+
safeTransactionDetails.txStatus,
|
|
75
|
+
safeApiTransactionDetails.txStatus,
|
|
76
|
+
].includes(TransactionStatus.SUCCESS)
|
|
77
|
+
) {
|
|
78
|
+
return {
|
|
79
|
+
status: 'DONE',
|
|
80
|
+
txHash: `0x${safeTransactionDetails.txHash?.slice(2)}`,
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (
|
|
85
|
+
[
|
|
86
|
+
safeTransactionDetails.txStatus,
|
|
87
|
+
safeApiTransactionDetails.txStatus,
|
|
88
|
+
].includes(TransactionStatus.FAILED)
|
|
89
|
+
) {
|
|
90
|
+
return {
|
|
91
|
+
status: 'FAILED',
|
|
92
|
+
txHash: `0x${safeTransactionDetails.txHash?.slice(2)}`,
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (
|
|
97
|
+
[
|
|
98
|
+
safeTransactionDetails.txStatus,
|
|
99
|
+
safeApiTransactionDetails.txStatus,
|
|
100
|
+
].includes(TransactionStatus.CANCELLED)
|
|
101
|
+
) {
|
|
102
|
+
return {
|
|
103
|
+
status: 'CANCELLED',
|
|
104
|
+
txHash: `0x${safeTransactionDetails.txHash?.slice(2)}`,
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (isSafeStatusPending) {
|
|
109
|
+
return {
|
|
110
|
+
status: 'PENDING',
|
|
111
|
+
txHash: `0x${safeTransactionDetails.txHash?.slice(2)}`,
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return {
|
|
116
|
+
status: 'PENDING',
|
|
117
|
+
txHash: `0x${safeTransactionDetails.txHash?.slice(2)}`,
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const sendBatchTransaction = async (
|
|
122
|
+
batchTransactions: MultisigTransaction[]
|
|
123
|
+
): Promise<`0x${string}`> => {
|
|
124
|
+
const safeAppProvider = (await connector.getProvider()) as any
|
|
125
|
+
const safeProviderSDK = safeAppProvider.sdk
|
|
126
|
+
|
|
127
|
+
try {
|
|
128
|
+
const { safeTxHash } = await safeProviderSDK.txs.send({
|
|
129
|
+
txs: batchTransactions,
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
return `0x${safeTxHash.slice(2)}`
|
|
133
|
+
} catch (error) {
|
|
134
|
+
throw new Error(error as string)
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return {
|
|
139
|
+
isMultisigWalletClient: connector?.id === 'safe',
|
|
140
|
+
shouldBatchTransactions: connector?.id === 'safe',
|
|
141
|
+
sendBatchTransaction,
|
|
142
|
+
getMultisigTransactionDetails,
|
|
143
|
+
}
|
|
144
|
+
}
|
package/src/types/widget.ts
CHANGED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
import { compactNumberFormatter } from './compactNumberFormatter.js'
|
|
3
|
+
|
|
4
|
+
describe('Compact Number Formatter', () => {
|
|
5
|
+
describe('basic formatting', () => {
|
|
6
|
+
const testCases = [
|
|
7
|
+
{ input: '0.123456789', expected: '0.123456' },
|
|
8
|
+
{ input: '0.0123456', expected: '0.012345' },
|
|
9
|
+
{ input: '0.00123456', expected: '0.001234' },
|
|
10
|
+
{ input: '0.000123456', expected: '0.000123' },
|
|
11
|
+
{ input: '0.06942', expected: '0.06942' },
|
|
12
|
+
{ input: '0.006942', expected: '0.006942' },
|
|
13
|
+
{ input: '0.0006942', expected: '0.000694' },
|
|
14
|
+
{ input: '0.00006942', expected: '0.0₄6942' },
|
|
15
|
+
{ input: '0.00000123456', expected: '0.0₅1234' },
|
|
16
|
+
{ input: '0.000006942', expected: '0.0₅6942' },
|
|
17
|
+
{ input: '0.00000000001', expected: '0.0₁₀1' },
|
|
18
|
+
{ input: '0.00000006942', expected: '0.0₇6942' },
|
|
19
|
+
{ input: '0.0000000694269', expected: '0.0₇6942' },
|
|
20
|
+
{ input: '0.0000000694069', expected: '0.0₇694' },
|
|
21
|
+
{ input: '0.000000006942', expected: '0.0₈6942' },
|
|
22
|
+
{
|
|
23
|
+
input: '0.000000000000006942',
|
|
24
|
+
expected: '0.0₁₄6942',
|
|
25
|
+
},
|
|
26
|
+
{ input: '-0.0000042', expected: '-0.0₅42' },
|
|
27
|
+
{ input: '-0.000000042', expected: '-0.0₇42' },
|
|
28
|
+
{ input: '1.0000000042', expected: '1.0₈42' },
|
|
29
|
+
{ input: '123456789.00042', expected: '123456789.00042' },
|
|
30
|
+
{
|
|
31
|
+
input: '123456789.000042',
|
|
32
|
+
expected: '123456789.0₄42',
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
input: '123456789.0000042',
|
|
36
|
+
expected: '123456789.0₅42',
|
|
37
|
+
},
|
|
38
|
+
{ input: '1234567.000000042', expected: '1234567.0₇42' },
|
|
39
|
+
{
|
|
40
|
+
input: '1234567.000000042',
|
|
41
|
+
expected: '1,234,567.0₇42',
|
|
42
|
+
lng: 'en',
|
|
43
|
+
useGrouping: true,
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
input: '1234567.987654321',
|
|
47
|
+
expected: '1,234,567.987654',
|
|
48
|
+
lng: 'en',
|
|
49
|
+
useGrouping: true,
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
input: '1234567.000000042',
|
|
53
|
+
expected: '1.234.567,0₇42',
|
|
54
|
+
lng: 'de',
|
|
55
|
+
useGrouping: true,
|
|
56
|
+
},
|
|
57
|
+
]
|
|
58
|
+
|
|
59
|
+
testCases.forEach(({ input, expected, lng, useGrouping = false }) => {
|
|
60
|
+
it(`should format ${input} correctly`, () => {
|
|
61
|
+
expect(compactNumberFormatter(lng, { useGrouping })(input)).toBe(
|
|
62
|
+
expected
|
|
63
|
+
)
|
|
64
|
+
})
|
|
65
|
+
})
|
|
66
|
+
})
|
|
67
|
+
})
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Converts a non-negative integer to its subscript representation using Unicode subscript characters.
|
|
3
|
+
* @param n - The number to convert to subscript
|
|
4
|
+
* @returns A string where each digit is converted to its subscript equivalent
|
|
5
|
+
* @example
|
|
6
|
+
* toSubscript(5) => '₅'
|
|
7
|
+
* toSubscript(10) => '₁₀'
|
|
8
|
+
*/
|
|
9
|
+
function toSubscript(n: number): string {
|
|
10
|
+
return n
|
|
11
|
+
.toString()
|
|
12
|
+
.split('')
|
|
13
|
+
.map((digit) => String.fromCharCode(8320 + Number(digit)))
|
|
14
|
+
.join('')
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Formats numbers with special handling for small decimal values, converting runs of leading zeros
|
|
19
|
+
* into a more compact subscript notation.
|
|
20
|
+
*
|
|
21
|
+
* @param value - The numeric value to format (expected to be a string representing a BigInt)
|
|
22
|
+
* @param lng - The locale string for number formatting
|
|
23
|
+
* @param options - Formatting options including decimals and Intl.NumberFormat options
|
|
24
|
+
* @returns A formatted string with subscript notation for leading zeros
|
|
25
|
+
*/
|
|
26
|
+
export const compactNumberFormatter = (
|
|
27
|
+
lng: string | undefined,
|
|
28
|
+
options: any
|
|
29
|
+
) => {
|
|
30
|
+
const formatter = new Intl.NumberFormat(lng, {
|
|
31
|
+
notation: 'standard',
|
|
32
|
+
roundingPriority: 'morePrecision',
|
|
33
|
+
maximumSignificantDigits: 21,
|
|
34
|
+
maximumFractionDigits: 21,
|
|
35
|
+
...options,
|
|
36
|
+
})
|
|
37
|
+
return (value: any) => {
|
|
38
|
+
if (!Number.parseFloat(value) || Number.isNaN(Number(value))) {
|
|
39
|
+
return '0'
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const parts = formatter.formatToParts(value as Intl.StringNumericLiteral)
|
|
43
|
+
let integerPart = ''
|
|
44
|
+
let fractionPart = ''
|
|
45
|
+
let decimalSeparator = ''
|
|
46
|
+
let minusSign = ''
|
|
47
|
+
|
|
48
|
+
for (const p of parts) {
|
|
49
|
+
switch (p.type) {
|
|
50
|
+
case 'integer':
|
|
51
|
+
case 'group':
|
|
52
|
+
integerPart += p.value
|
|
53
|
+
break
|
|
54
|
+
case 'fraction':
|
|
55
|
+
fractionPart += p.value
|
|
56
|
+
break
|
|
57
|
+
case 'decimal':
|
|
58
|
+
decimalSeparator = p.value
|
|
59
|
+
break
|
|
60
|
+
case 'minusSign':
|
|
61
|
+
minusSign = p.value
|
|
62
|
+
break
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// For numbers with no decimal part, return early
|
|
67
|
+
if (!fractionPart) {
|
|
68
|
+
return `${minusSign}${integerPart}`
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Count consecutive leading zeros in the fraction part
|
|
72
|
+
const match = fractionPart.match(/^0+/)
|
|
73
|
+
const leadingZerosCount = match ? match[0].length : 0
|
|
74
|
+
|
|
75
|
+
// For numbers with few leading zeros (≤ 3), format normally
|
|
76
|
+
// but limit the total length and trim trailing zeros
|
|
77
|
+
if (leadingZerosCount <= 3) {
|
|
78
|
+
fractionPart = fractionPart.slice(0, 6).replace(/0+$/, '')
|
|
79
|
+
return `${minusSign}${integerPart}${decimalSeparator}${fractionPart}`
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// For numbers with many leading zeros (> 3), use subscript notation
|
|
83
|
+
// Format: "0.0₍number_of_zeros₎significant_digits"
|
|
84
|
+
const zerosSubscript = toSubscript(leadingZerosCount)
|
|
85
|
+
const remainder = fractionPart
|
|
86
|
+
.slice(leadingZerosCount, leadingZerosCount + 4)
|
|
87
|
+
.replace(/0+$/, '')
|
|
88
|
+
|
|
89
|
+
return `${minusSign}${integerPart}${decimalSeparator}0${zerosSubscript}${remainder}`
|
|
90
|
+
}
|
|
91
|
+
}
|
package/src/utils/converters.ts
CHANGED
|
@@ -8,8 +8,8 @@ import type {
|
|
|
8
8
|
TokenAmount,
|
|
9
9
|
ToolsResponse,
|
|
10
10
|
} from '@lifi/sdk'
|
|
11
|
-
import { formatUnits } from 'viem'
|
|
12
11
|
import type { RouteExecution } from '../stores/routes/types.js'
|
|
12
|
+
import { formatTokenPrice } from './format.js'
|
|
13
13
|
|
|
14
14
|
const buildProcessFromTxHistory = (tx: FullStatusData): Process[] => {
|
|
15
15
|
const sending = tx.sending as ExtendedTransactionInfo
|
|
@@ -105,9 +105,11 @@ export const buildRouteFromTxHistory = (
|
|
|
105
105
|
: sendingValue
|
|
106
106
|
const sendingFeeAmountUsd =
|
|
107
107
|
sending.gasToken.priceUSD && sendingFeeAmount
|
|
108
|
-
?
|
|
109
|
-
|
|
110
|
-
|
|
108
|
+
? formatTokenPrice(
|
|
109
|
+
sendingFeeAmount,
|
|
110
|
+
sending.gasToken.priceUSD,
|
|
111
|
+
sending.gasToken.decimals
|
|
112
|
+
)
|
|
111
113
|
: 0
|
|
112
114
|
|
|
113
115
|
const feeCosts: FeeCost[] | undefined = sendingFeeAmount
|
package/src/utils/fees.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { FeeCost, GasCost, RouteExtended, Token } from '@lifi/sdk'
|
|
2
|
-
import {
|
|
2
|
+
import { formatTokenPrice } from './format.js'
|
|
3
3
|
|
|
4
4
|
export interface FeesBreakdown {
|
|
5
5
|
amount: bigint
|
|
@@ -109,9 +109,11 @@ export const getStepFeeCostsBreakdown = (
|
|
|
109
109
|
const { amount, amountUSD } = feeCosts.reduce(
|
|
110
110
|
(acc, feeCost) => {
|
|
111
111
|
const feeAmount = BigInt(Number(feeCost.amount).toFixed(0) || 0)
|
|
112
|
-
const amountUSD =
|
|
113
|
-
|
|
114
|
-
|
|
112
|
+
const amountUSD = formatTokenPrice(
|
|
113
|
+
feeAmount,
|
|
114
|
+
feeCost.token.priceUSD,
|
|
115
|
+
feeCost.token.decimals
|
|
116
|
+
)
|
|
115
117
|
|
|
116
118
|
acc.amount += feeAmount
|
|
117
119
|
acc.amountUSD += amountUSD
|