@lifi/widget 3.37.0 → 3.38.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 +26 -0
- package/dist/esm/components/AmountInput/PriceFormHelperText.style.js +3 -0
- package/dist/esm/components/AmountInput/PriceFormHelperText.style.js.map +1 -1
- package/dist/esm/components/AppContainer.js +1 -0
- package/dist/esm/components/AppContainer.js.map +1 -1
- package/dist/esm/components/Avatar/AccountAvatar.js +3 -3
- package/dist/esm/components/Avatar/AccountAvatar.js.map +1 -1
- package/dist/esm/components/Avatar/Avatar.d.ts +2 -0
- package/dist/esm/components/Avatar/Avatar.js +4 -3
- package/dist/esm/components/Avatar/Avatar.js.map +1 -1
- package/dist/esm/components/Avatar/ChainBadgeContent.d.ts +7 -0
- package/dist/esm/components/Avatar/ChainBadgeContent.js +10 -0
- package/dist/esm/components/Avatar/ChainBadgeContent.js.map +1 -0
- package/dist/esm/components/Avatar/TokenAvatar.js +3 -3
- package/dist/esm/components/Avatar/TokenAvatar.js.map +1 -1
- package/dist/esm/components/Chains/AllChainsAvatar.js +31 -5
- package/dist/esm/components/Chains/AllChainsAvatar.js.map +1 -1
- package/dist/esm/components/Chains/ChainSearchInput.js +7 -1
- package/dist/esm/components/Chains/ChainSearchInput.js.map +1 -1
- package/dist/esm/components/Header/NavigationHeader.js +5 -1
- package/dist/esm/components/Header/NavigationHeader.js.map +1 -1
- package/dist/esm/components/SelectTokenButton/SelectTokenButton.js +3 -1
- package/dist/esm/components/SelectTokenButton/SelectTokenButton.js.map +1 -1
- package/dist/esm/components/TokenList/TokenListItem.js +8 -2
- package/dist/esm/components/TokenList/TokenListItem.js.map +1 -1
- package/dist/esm/config/version.d.ts +1 -1
- package/dist/esm/config/version.js +1 -1
- package/dist/esm/hooks/useFilteredByTokenBalances.js +8 -2
- package/dist/esm/hooks/useFilteredByTokenBalances.js.map +1 -1
- package/dist/esm/hooks/useRoutes.js +10 -19
- package/dist/esm/hooks/useRoutes.js.map +1 -1
- package/dist/esm/hooks/useTokenSearch.js +15 -8
- package/dist/esm/hooks/useTokenSearch.js.map +1 -1
- package/dist/esm/hooks/useTokens.js +33 -53
- package/dist/esm/hooks/useTokens.js.map +1 -1
- package/dist/esm/i18n/en.json +1 -0
- package/dist/esm/pages/LanguagesPage.js +6 -7
- package/dist/esm/pages/LanguagesPage.js.map +1 -1
- package/dist/esm/stores/StoreProvider.js +2 -1
- package/dist/esm/stores/StoreProvider.js.map +1 -1
- package/dist/esm/stores/chains/ChainOrderStore.js +20 -2
- package/dist/esm/stores/chains/ChainOrderStore.js.map +1 -1
- package/dist/esm/types/token.d.ts +6 -1
- package/dist/esm/types/widget.d.ts +11 -2
- package/dist/esm/types/widget.js +1 -0
- package/dist/esm/types/widget.js.map +1 -1
- package/dist/esm/utils/token.d.ts +12 -1
- package/dist/esm/utils/token.js +44 -0
- package/dist/esm/utils/token.js.map +1 -1
- package/dist/esm/utils/tokenList.js +2 -0
- package/dist/esm/utils/tokenList.js.map +1 -1
- package/dist/esm/utils/variant.d.ts +2 -0
- package/dist/esm/utils/variant.js +10 -0
- package/dist/esm/utils/variant.js.map +1 -0
- package/package.json +7 -7
- package/package.json.tmp +9 -9
- package/src/components/AmountInput/PriceFormHelperText.style.tsx +3 -0
- package/src/components/AppContainer.tsx +1 -0
- package/src/components/Avatar/AccountAvatar.tsx +3 -15
- package/src/components/Avatar/Avatar.tsx +6 -7
- package/src/components/Avatar/ChainBadgeContent.tsx +22 -0
- package/src/components/Avatar/TokenAvatar.tsx +3 -11
- package/src/components/Chains/AllChainsAvatar.tsx +56 -8
- package/src/components/Chains/ChainSearchInput.tsx +9 -1
- package/src/components/Header/NavigationHeader.tsx +5 -1
- package/src/components/SelectTokenButton/SelectTokenButton.tsx +9 -1
- package/src/components/TokenList/TokenListItem.tsx +23 -1
- package/src/config/version.ts +1 -1
- package/src/hooks/useFilteredByTokenBalances.ts +8 -4
- package/src/hooks/useRoutes.ts +17 -23
- package/src/hooks/useTokenSearch.ts +17 -10
- package/src/hooks/useTokens.ts +51 -83
- package/src/i18n/en.json +1 -0
- package/src/pages/LanguagesPage.tsx +1 -2
- package/src/stores/StoreProvider.tsx +2 -1
- package/src/stores/chains/ChainOrderStore.tsx +24 -2
- package/src/types/token.ts +5 -0
- package/src/types/widget.ts +10 -1
- package/src/utils/token.ts +65 -1
- package/src/utils/tokenList.ts +2 -0
- package/src/utils/variant.ts +16 -0
package/src/hooks/useTokens.ts
CHANGED
|
@@ -4,17 +4,23 @@ import {
|
|
|
4
4
|
getTokens,
|
|
5
5
|
type TokensExtendedResponse,
|
|
6
6
|
} from '@lifi/sdk'
|
|
7
|
-
import { useQuery
|
|
7
|
+
import { useQuery } from '@tanstack/react-query'
|
|
8
8
|
import { useMemo } from 'react'
|
|
9
9
|
import { useWidgetConfig } from '../providers/WidgetProvider/WidgetProvider.js'
|
|
10
10
|
import type { FormType } from '../stores/form/types.js'
|
|
11
|
+
import type { TokensByChain } from '../types/token.js'
|
|
11
12
|
import {
|
|
12
13
|
defaultChainIdsByType,
|
|
13
14
|
getChainTypeFromAddress,
|
|
14
15
|
} from '../utils/chainType.js'
|
|
15
16
|
import { isItemAllowed } from '../utils/item.js'
|
|
16
17
|
import { getQueryKey } from '../utils/queries.js'
|
|
17
|
-
import {
|
|
18
|
+
import {
|
|
19
|
+
filterAllowedTokens,
|
|
20
|
+
mergeVerifiedWithSearchTokens,
|
|
21
|
+
} from '../utils/token.js'
|
|
22
|
+
|
|
23
|
+
const refetchInterval = 300_000
|
|
18
24
|
|
|
19
25
|
export const useTokens = (
|
|
20
26
|
formType?: FormType,
|
|
@@ -27,12 +33,8 @@ export const useTokens = (
|
|
|
27
33
|
keyPrefix,
|
|
28
34
|
} = useWidgetConfig()
|
|
29
35
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
chainId
|
|
33
|
-
)
|
|
34
|
-
|
|
35
|
-
const { data, isLoading } = useQuery({
|
|
36
|
+
// Main tokens cache - verified tokens from API
|
|
37
|
+
const { data: verifiedTokens, isLoading } = useQuery({
|
|
36
38
|
queryKey: [getQueryKey('tokens', keyPrefix)],
|
|
37
39
|
queryFn: async ({ signal }) => {
|
|
38
40
|
const chainTypes = [
|
|
@@ -41,6 +43,7 @@ export const useTokens = (
|
|
|
41
43
|
ChainType.UTXO,
|
|
42
44
|
ChainType.MVM,
|
|
43
45
|
].filter((chainType) => isItemAllowed(chainType, chainsConfig?.types))
|
|
46
|
+
|
|
44
47
|
const tokensResponse: TokensExtendedResponse = await getTokens(
|
|
45
48
|
{
|
|
46
49
|
chainTypes,
|
|
@@ -50,45 +53,37 @@ export const useTokens = (
|
|
|
50
53
|
},
|
|
51
54
|
{ signal }
|
|
52
55
|
)
|
|
53
|
-
return tokensResponse
|
|
54
|
-
},
|
|
55
|
-
refetchInterval: 300_000,
|
|
56
|
-
staleTime: 300_000,
|
|
57
|
-
})
|
|
58
|
-
|
|
59
|
-
const allTokens = useMemo(() => {
|
|
60
|
-
return filterAllowedTokens(
|
|
61
|
-
data?.tokens,
|
|
62
|
-
configTokens,
|
|
63
|
-
chainsConfig,
|
|
64
|
-
formType
|
|
65
|
-
)
|
|
66
|
-
}, [data?.tokens, configTokens, chainsConfig, formType])
|
|
67
56
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
57
|
+
// Mark all tokens as verified
|
|
58
|
+
const tokens: TokensByChain = Object.fromEntries(
|
|
59
|
+
Object.entries(tokensResponse.tokens).map(([chainId, tokens]) => [
|
|
60
|
+
chainId,
|
|
61
|
+
tokens.map((token) => ({ ...token, verified: true })),
|
|
62
|
+
])
|
|
63
|
+
)
|
|
74
64
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
const queryClient = useQueryClient()
|
|
65
|
+
return tokens
|
|
66
|
+
},
|
|
67
|
+
refetchInterval,
|
|
68
|
+
staleTime: refetchInterval,
|
|
69
|
+
})
|
|
81
70
|
|
|
82
|
-
|
|
71
|
+
// Search tokens cache - unverified tokens from search
|
|
72
|
+
const { data: searchTokens, isLoading: isSearchLoading } = useQuery({
|
|
83
73
|
queryKey: [getQueryKey('tokens-search', keyPrefix), search, chainId],
|
|
84
74
|
queryFn: async ({ queryKey, signal }) => {
|
|
85
|
-
const [, searchQuery,
|
|
75
|
+
const [, searchQuery, searchChainId] = queryKey as [
|
|
76
|
+
string,
|
|
77
|
+
string,
|
|
78
|
+
number,
|
|
79
|
+
]
|
|
86
80
|
const chainTypes = [
|
|
87
81
|
ChainType.EVM,
|
|
88
82
|
ChainType.SVM,
|
|
89
83
|
ChainType.UTXO,
|
|
90
84
|
ChainType.MVM,
|
|
91
85
|
].filter((chainType) => isItemAllowed(chainType, chainsConfig?.types))
|
|
86
|
+
|
|
92
87
|
const tokensResponse: TokensExtendedResponse = await getTokens(
|
|
93
88
|
{
|
|
94
89
|
chainTypes,
|
|
@@ -101,7 +96,7 @@ const useBackgroundTokenSearch = (search?: string, chainId?: number) => {
|
|
|
101
96
|
)
|
|
102
97
|
|
|
103
98
|
// If the chainId is not provided, try to get it from the search query
|
|
104
|
-
let _chainId =
|
|
99
|
+
let _chainId = searchChainId
|
|
105
100
|
if (!_chainId) {
|
|
106
101
|
const chainType = getChainTypeFromAddress(searchQuery)
|
|
107
102
|
if (chainType) {
|
|
@@ -121,57 +116,30 @@ const useBackgroundTokenSearch = (search?: string, chainId?: number) => {
|
|
|
121
116
|
}
|
|
122
117
|
}
|
|
123
118
|
|
|
124
|
-
//
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
(
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
const clonedData = { ...data, tokens: { ...data.tokens } }
|
|
134
|
-
|
|
135
|
-
Object.entries(tokensResponse.tokens).forEach(
|
|
136
|
-
([chainId, searchTokens]) => {
|
|
137
|
-
const chainIdNum = Number(chainId)
|
|
138
|
-
const existingTokens = clonedData.tokens[chainIdNum] || []
|
|
139
|
-
|
|
140
|
-
const existingTokenAddresses = new Set(
|
|
141
|
-
existingTokens.map((token) => token.address.toLowerCase())
|
|
142
|
-
)
|
|
143
|
-
|
|
144
|
-
// Find tokens in search results that don't exist in the main list
|
|
145
|
-
const newTokens = searchTokens.filter(
|
|
146
|
-
(searchToken) =>
|
|
147
|
-
!existingTokenAddresses.has(
|
|
148
|
-
searchToken.address.toLowerCase()
|
|
149
|
-
)
|
|
150
|
-
)
|
|
151
|
-
|
|
152
|
-
// Add new tokens to the main list
|
|
153
|
-
if (newTokens.length > 0) {
|
|
154
|
-
clonedData.tokens[chainIdNum] = [
|
|
155
|
-
...existingTokens,
|
|
156
|
-
...newTokens,
|
|
157
|
-
]
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
)
|
|
161
|
-
|
|
162
|
-
return clonedData
|
|
163
|
-
}
|
|
164
|
-
)
|
|
165
|
-
}
|
|
119
|
+
// Mark all search tokens as unverified
|
|
120
|
+
const tokens: TokensByChain = Object.fromEntries(
|
|
121
|
+
Object.entries(tokensResponse.tokens).map(([chainId, tokens]) => [
|
|
122
|
+
chainId,
|
|
123
|
+
tokens.map((token) => ({ ...token, verified: false })),
|
|
124
|
+
])
|
|
125
|
+
)
|
|
166
126
|
|
|
167
|
-
return
|
|
127
|
+
return tokens
|
|
168
128
|
},
|
|
169
129
|
enabled: !!search,
|
|
170
|
-
refetchInterval
|
|
171
|
-
staleTime:
|
|
130
|
+
refetchInterval,
|
|
131
|
+
staleTime: refetchInterval,
|
|
172
132
|
})
|
|
173
133
|
|
|
134
|
+
// Merge tokens at read time - single place where caches are combined
|
|
135
|
+
const allTokens = useMemo(() => {
|
|
136
|
+
const merged = mergeVerifiedWithSearchTokens(verifiedTokens, searchTokens)
|
|
137
|
+
return filterAllowedTokens(merged, configTokens, chainsConfig, formType)
|
|
138
|
+
}, [verifiedTokens, searchTokens, configTokens, chainsConfig, formType])
|
|
139
|
+
|
|
174
140
|
return {
|
|
175
|
-
|
|
141
|
+
allTokens,
|
|
142
|
+
isLoading,
|
|
143
|
+
isSearchLoading,
|
|
176
144
|
}
|
|
177
145
|
}
|
package/src/i18n/en.json
CHANGED
|
@@ -127,6 +127,7 @@
|
|
|
127
127
|
"deleteTransactionHistory": "Transaction history is only stored locally and can't be recovered if you delete it.",
|
|
128
128
|
"fundsLossPrevention": "Always ensure smart contract accounts are properly set up on the destination chain and avoid direct transfers to exchanges to prevent fund loss.",
|
|
129
129
|
"highValueLoss": "The value of the received tokens is significantly lower than the exchanged tokens and transaction cost.",
|
|
130
|
+
"unverifiedToken": "Unverified token. Always do your own research before proceeding.",
|
|
130
131
|
"insufficientFunds": "You don't have enough funds to complete the transaction.",
|
|
131
132
|
"insufficientGas": "You don't have enough gas to complete the transaction. You need to add at least:",
|
|
132
133
|
"minFromAmountUSD": "Minimum amount is {{amount, currencyExt(currency: USD)}}. Please enter a higher amount.",
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import Check from '@mui/icons-material/Check'
|
|
2
1
|
import { List } from '@mui/material'
|
|
3
2
|
import { useTranslation } from 'react-i18next'
|
|
4
3
|
import { ListItemText } from '../components/ListItemText.js'
|
|
@@ -33,6 +32,7 @@ export const LanguagesPage: React.FC = () => {
|
|
|
33
32
|
<SettingsListItemButton
|
|
34
33
|
key={language}
|
|
35
34
|
onClick={() => setLanguageWithCode(language)}
|
|
35
|
+
selected={selectedLanguageCode === language}
|
|
36
36
|
>
|
|
37
37
|
<ListItemText
|
|
38
38
|
primary={
|
|
@@ -43,7 +43,6 @@ export const LanguagesPage: React.FC = () => {
|
|
|
43
43
|
language
|
|
44
44
|
}
|
|
45
45
|
/>
|
|
46
|
-
{selectedLanguageCode === language && <Check color="primary" />}
|
|
47
46
|
</SettingsListItemButton>
|
|
48
47
|
))}
|
|
49
48
|
</List>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { PropsWithChildren } from 'react'
|
|
2
2
|
import type { WidgetConfigProps } from '../types/widget.js'
|
|
3
|
+
import { getSplitSubvariant } from '../utils/variant.js'
|
|
3
4
|
import { BookmarkStoreProvider } from './bookmarks/BookmarkStore.js'
|
|
4
5
|
import { ChainOrderStoreProvider } from './chains/ChainOrderStore.js'
|
|
5
6
|
import { FormStoreProvider } from './form/FormStore.js'
|
|
@@ -16,7 +17,7 @@ export const StoreProvider: React.FC<PropsWithChildren<WidgetConfigProps>> = ({
|
|
|
16
17
|
<SplitSubvariantStoreProvider
|
|
17
18
|
state={
|
|
18
19
|
config.subvariant === 'split'
|
|
19
|
-
? config.subvariantOptions?.split
|
|
20
|
+
? getSplitSubvariant(config.subvariantOptions?.split)
|
|
20
21
|
: undefined
|
|
21
22
|
}
|
|
22
23
|
>
|
|
@@ -3,8 +3,10 @@ import type { StoreApi } from 'zustand'
|
|
|
3
3
|
import { useShallow } from 'zustand/shallow'
|
|
4
4
|
import type { UseBoundStoreWithEqualityFn } from 'zustand/traditional'
|
|
5
5
|
import { useChains } from '../../hooks/useChains.js'
|
|
6
|
+
import { useSwapOnly } from '../../hooks/useSwapOnly.js'
|
|
6
7
|
import { useExternalWalletProvider } from '../../providers/WalletProvider/useExternalWalletProvider.js'
|
|
7
8
|
import { useWidgetConfig } from '../../providers/WidgetProvider/WidgetProvider.js'
|
|
9
|
+
import { HiddenUI } from '../../types/widget.js'
|
|
8
10
|
import { getConfigItemSets, isItemAllowedForSets } from '../../utils/item.js'
|
|
9
11
|
import type { FormType } from '../form/types.js'
|
|
10
12
|
import { useFieldActions } from '../form/useFieldActions.js'
|
|
@@ -20,10 +22,11 @@ export function ChainOrderStoreProvider({
|
|
|
20
22
|
children,
|
|
21
23
|
...props
|
|
22
24
|
}: PersistStoreProviderProps) {
|
|
23
|
-
const { chains: chainsConfig } = useWidgetConfig()
|
|
25
|
+
const { chains: chainsConfig, hiddenUI } = useWidgetConfig()
|
|
24
26
|
const storeRef = useRef<ChainOrderStore>(null)
|
|
25
27
|
const { chains } = useChains()
|
|
26
28
|
const { setFieldValue, getFieldValues } = useFieldActions()
|
|
29
|
+
const swapOnly = useSwapOnly()
|
|
27
30
|
const { variant, subvariantOptions } = useWidgetConfig()
|
|
28
31
|
const { externalChainTypes, useExternalWalletProvidersOnly } =
|
|
29
32
|
useExternalWalletProvider()
|
|
@@ -62,18 +65,35 @@ export function ChainOrderStoreProvider({
|
|
|
62
65
|
key
|
|
63
66
|
)
|
|
64
67
|
|
|
68
|
+
const isSwapTo = swapOnly && key === 'to'
|
|
69
|
+
|
|
65
70
|
// Show "All networks" button if there are multiple networks
|
|
66
|
-
const showAllNetworks =
|
|
71
|
+
const showAllNetworks =
|
|
72
|
+
filteredChains.length > 1 &&
|
|
73
|
+
!hiddenUI?.includes(HiddenUI.AllNetworks) &&
|
|
74
|
+
!isSwapTo
|
|
67
75
|
if (!showAllNetworks) {
|
|
68
76
|
storeRef.current?.getState().setIsAllNetworks(false, key)
|
|
69
77
|
}
|
|
70
78
|
storeRef.current?.getState().setShowAllNetworks(showAllNetworks, key)
|
|
71
79
|
|
|
80
|
+
// If swap only, set the to chain to the from chain
|
|
81
|
+
if (isSwapTo) {
|
|
82
|
+
const [fromChainValue] = getFieldValues('fromChain')
|
|
83
|
+
setFieldValue('toChain', fromChainValue)
|
|
84
|
+
}
|
|
85
|
+
|
|
72
86
|
const [chainValue] = getFieldValues(`${key}Chain`)
|
|
73
87
|
if (chainValue) {
|
|
74
88
|
return
|
|
75
89
|
}
|
|
76
90
|
|
|
91
|
+
// If no chain is selected (e.g., removed from URL params) and
|
|
92
|
+
// showAllNetworks is enabled, reset isAllNetworks to true
|
|
93
|
+
if (showAllNetworks) {
|
|
94
|
+
storeRef.current?.getState().setIsAllNetworks(true, key)
|
|
95
|
+
}
|
|
96
|
+
|
|
77
97
|
const firstAllowedPinnedChain = storeRef.current
|
|
78
98
|
?.getState()
|
|
79
99
|
.pinnedChains?.find((chainId) =>
|
|
@@ -99,6 +119,8 @@ export function ChainOrderStoreProvider({
|
|
|
99
119
|
useExternalWalletProvidersOnly,
|
|
100
120
|
variant,
|
|
101
121
|
subvariantOptions?.wide?.enableChainSidebar,
|
|
122
|
+
hiddenUI,
|
|
123
|
+
swapOnly,
|
|
102
124
|
])
|
|
103
125
|
|
|
104
126
|
return (
|
package/src/types/token.ts
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
TokenAmount as SDKTokenAmount,
|
|
3
3
|
TokenAmountExtended as SDKTokenAmountExtended,
|
|
4
|
+
TokenExtended,
|
|
4
5
|
} from '@lifi/sdk'
|
|
5
6
|
|
|
6
7
|
interface TokenFlags {
|
|
7
8
|
featured?: boolean
|
|
8
9
|
popular?: boolean
|
|
10
|
+
verified?: boolean
|
|
9
11
|
}
|
|
10
12
|
|
|
11
13
|
export interface TokenAmount extends SDKTokenAmount, TokenFlags {}
|
|
@@ -13,3 +15,6 @@ export interface TokenAmount extends SDKTokenAmount, TokenFlags {}
|
|
|
13
15
|
export interface TokenAmountExtended
|
|
14
16
|
extends SDKTokenAmountExtended,
|
|
15
17
|
TokenFlags {}
|
|
18
|
+
|
|
19
|
+
export type TokenWithVerified = TokenExtended & { verified?: boolean }
|
|
20
|
+
export type TokensByChain = Record<number, TokenWithVerified[]>
|
package/src/types/widget.ts
CHANGED
|
@@ -38,12 +38,20 @@ import type { DefaultFieldValues } from '../stores/form/types.js'
|
|
|
38
38
|
export type WidgetVariant = 'compact' | 'wide' | 'drawer'
|
|
39
39
|
export type WidgetSubvariant = 'default' | 'split' | 'custom' | 'refuel'
|
|
40
40
|
export type SplitSubvariant = 'bridge' | 'swap'
|
|
41
|
+
export type SplitSubvariantOptions = {
|
|
42
|
+
defaultTab: SplitSubvariant
|
|
43
|
+
}
|
|
41
44
|
export type CustomSubvariant = 'checkout' | 'deposit'
|
|
42
45
|
export type WideSubvariant = {
|
|
43
46
|
enableChainSidebar?: boolean
|
|
44
47
|
}
|
|
45
48
|
export interface SubvariantOptions {
|
|
46
|
-
|
|
49
|
+
/**
|
|
50
|
+
* Configure split subvariant behavior:
|
|
51
|
+
* - 'bridge' | 'swap': Single mode without tabs
|
|
52
|
+
* - { defaultTab: 'bridge' | 'swap' }: Tabs mode with configurable default tab
|
|
53
|
+
*/
|
|
54
|
+
split?: SplitSubvariant | SplitSubvariantOptions
|
|
47
55
|
custom?: CustomSubvariant
|
|
48
56
|
wide?: WideSubvariant
|
|
49
57
|
}
|
|
@@ -125,6 +133,7 @@ export enum HiddenUI {
|
|
|
125
133
|
SearchTokenInput = 'searchTokenInput',
|
|
126
134
|
InsufficientGasMessage = 'insufficientGasMessage',
|
|
127
135
|
ContactSupport = 'contactSupport',
|
|
136
|
+
AllNetworks = 'allNetworks',
|
|
128
137
|
}
|
|
129
138
|
export type HiddenUIType = `${HiddenUI}`
|
|
130
139
|
|
package/src/utils/token.ts
CHANGED
|
@@ -1,8 +1,72 @@
|
|
|
1
|
-
import type { BaseToken, TokenExtended } from '@lifi/sdk'
|
|
1
|
+
import type { BaseToken, Token, TokenExtended } from '@lifi/sdk'
|
|
2
2
|
import type { FormType } from '../stores/form/types.js'
|
|
3
|
+
import type { TokensByChain } from '../types/token.js'
|
|
3
4
|
import type { WidgetChains, WidgetTokens } from '../types/widget.js'
|
|
4
5
|
import { getConfigItemSets, isFormItemAllowed } from './item.js'
|
|
5
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Merges verified tokens with search tokens.
|
|
9
|
+
* Verified tokens take priority - search tokens are only added if they don't already exist.
|
|
10
|
+
*/
|
|
11
|
+
export const mergeVerifiedWithSearchTokens = (
|
|
12
|
+
verifiedTokens?: TokensByChain,
|
|
13
|
+
searchTokens?: TokensByChain
|
|
14
|
+
): TokensByChain | undefined => {
|
|
15
|
+
if (!verifiedTokens) {
|
|
16
|
+
return searchTokens
|
|
17
|
+
}
|
|
18
|
+
if (!searchTokens) {
|
|
19
|
+
return verifiedTokens
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const result = { ...verifiedTokens }
|
|
23
|
+
|
|
24
|
+
for (const [chainId, tokens] of Object.entries(searchTokens)) {
|
|
25
|
+
const chainIdNum = Number(chainId)
|
|
26
|
+
const existingTokens = result[chainIdNum] || []
|
|
27
|
+
const existingAddresses = new Set(
|
|
28
|
+
existingTokens.map((t) => t.address.toLowerCase())
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
const newTokens = tokens.filter(
|
|
32
|
+
(t) => !existingAddresses.has(t.address.toLowerCase())
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
if (newTokens.length) {
|
|
36
|
+
result[chainIdNum] = [...existingTokens, ...newTokens]
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return result
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Updates a token in the cache by chainId and address.
|
|
45
|
+
* Returns a new cache object with the token updated, or the original if not found.
|
|
46
|
+
*/
|
|
47
|
+
export const updateTokenInCache = (
|
|
48
|
+
data: TokensByChain | undefined,
|
|
49
|
+
token: Token
|
|
50
|
+
): TokensByChain | undefined => {
|
|
51
|
+
if (!data) {
|
|
52
|
+
return data
|
|
53
|
+
}
|
|
54
|
+
const chainTokens = data[token.chainId]
|
|
55
|
+
if (!chainTokens) {
|
|
56
|
+
return data
|
|
57
|
+
}
|
|
58
|
+
const index = chainTokens.findIndex((t) => t.address === token.address)
|
|
59
|
+
if (index < 0) {
|
|
60
|
+
return data
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
...data,
|
|
64
|
+
[token.chainId]: chainTokens.map((t, i) =>
|
|
65
|
+
i === index ? { ...t, ...token } : t
|
|
66
|
+
),
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
6
70
|
export const filterAllowedTokens = (
|
|
7
71
|
dataTokens: { [chainId: number]: TokenExtended[] } | undefined,
|
|
8
72
|
configTokens?: WidgetTokens,
|
package/src/utils/tokenList.ts
CHANGED
|
@@ -91,6 +91,8 @@ const processedTypedTokens = (
|
|
|
91
91
|
typedTokens?.forEach((token) => {
|
|
92
92
|
const tokenAmount = { ...token } as TokenAmount
|
|
93
93
|
tokenAmount[tokenType] = true
|
|
94
|
+
// Config tokens are explicitly set by integrator, mark as verified
|
|
95
|
+
tokenAmount.verified = true
|
|
94
96
|
|
|
95
97
|
const match = filteredTokensMap.get(token.address)
|
|
96
98
|
if (match?.priceUSD) {
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
SplitSubvariant,
|
|
3
|
+
SplitSubvariantOptions,
|
|
4
|
+
} from '../types/widget.js'
|
|
5
|
+
|
|
6
|
+
export const getSplitSubvariant = (
|
|
7
|
+
split?: SplitSubvariant | SplitSubvariantOptions
|
|
8
|
+
): SplitSubvariant => {
|
|
9
|
+
if (!split) {
|
|
10
|
+
return 'swap'
|
|
11
|
+
}
|
|
12
|
+
if (typeof split === 'string') {
|
|
13
|
+
return split
|
|
14
|
+
}
|
|
15
|
+
return split.defaultTab
|
|
16
|
+
}
|