@lifi/widget 3.29.1 → 3.30.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.
- package/CHANGELOG.md +12 -0
- package/dist/esm/components/AmountInput/AmountInputEndAdornment.d.ts +1 -1
- package/dist/esm/components/AmountInput/AmountInputEndAdornment.js +3 -2
- package/dist/esm/components/AmountInput/AmountInputEndAdornment.js.map +1 -1
- package/dist/esm/components/AmountInput/PriceFormHelperText.d.ts +1 -1
- package/dist/esm/components/AmountInput/PriceFormHelperText.js +3 -2
- package/dist/esm/components/AmountInput/PriceFormHelperText.js.map +1 -1
- package/dist/esm/components/ChainSelect/ChainSelect.js +35 -18
- package/dist/esm/components/ChainSelect/ChainSelect.js.map +1 -1
- package/dist/esm/components/ChainSelect/useChainSelect.d.ts +1 -1
- package/dist/esm/components/ChainSelect/useChainSelect.js +3 -3
- package/dist/esm/components/ChainSelect/useChainSelect.js.map +1 -1
- package/dist/esm/components/Chains/AllChainsAvatar.d.ts +7 -0
- package/dist/esm/components/Chains/AllChainsAvatar.js +77 -0
- package/dist/esm/components/Chains/AllChainsAvatar.js.map +1 -0
- package/dist/esm/components/Chains/ChainList.d.ts +2 -1
- package/dist/esm/components/Chains/ChainList.js +2 -2
- package/dist/esm/components/Chains/ChainList.js.map +1 -1
- package/dist/esm/components/Chains/ChainSearchInput.js +2 -2
- package/dist/esm/components/Chains/ChainSearchInput.js.map +1 -1
- package/dist/esm/components/Chains/SelectChainContent.js +1 -1
- package/dist/esm/components/Chains/SelectChainContent.js.map +1 -1
- package/dist/esm/components/Chains/VirtualizedChainList.d.ts +2 -1
- package/dist/esm/components/Chains/VirtualizedChainList.js +42 -10
- package/dist/esm/components/Chains/VirtualizedChainList.js.map +1 -1
- package/dist/esm/components/RouteCard/RouteCardEssentials.js +1 -1
- package/dist/esm/components/RouteCard/RouteCardEssentials.js.map +1 -1
- package/dist/esm/components/TokenList/TokenDetailsSheet.d.ts +1 -5
- package/dist/esm/components/TokenList/TokenDetailsSheet.js +4 -2
- package/dist/esm/components/TokenList/TokenDetailsSheet.js.map +1 -1
- package/dist/esm/components/TokenList/TokenDetailsSheetContent.js +2 -2
- package/dist/esm/components/TokenList/TokenDetailsSheetContent.js.map +1 -1
- package/dist/esm/components/TokenList/TokenList.js +11 -53
- package/dist/esm/components/TokenList/TokenList.js.map +1 -1
- package/dist/esm/components/TokenList/TokenListItem.d.ts +1 -1
- package/dist/esm/components/TokenList/TokenListItem.js +29 -25
- package/dist/esm/components/TokenList/TokenListItem.js.map +1 -1
- package/dist/esm/components/TokenList/VirtualizedTokenList.js +56 -37
- package/dist/esm/components/TokenList/VirtualizedTokenList.js.map +1 -1
- package/dist/esm/components/TokenList/types.d.ts +6 -10
- package/dist/esm/components/TokenList/useTokenSelect.js +3 -4
- package/dist/esm/components/TokenList/useTokenSelect.js.map +1 -1
- package/dist/esm/components/TransactionDetails.js +2 -2
- 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/hooks/useAccountsBalancesData.d.ts +6 -0
- package/dist/esm/hooks/useAccountsBalancesData.js +64 -0
- package/dist/esm/hooks/useAccountsBalancesData.js.map +1 -0
- package/dist/esm/hooks/useFilteredByTokenBalances.d.ts +8 -0
- package/dist/esm/hooks/useFilteredByTokenBalances.js +69 -0
- package/dist/esm/hooks/useFilteredByTokenBalances.js.map +1 -0
- package/dist/esm/hooks/useListHeight.d.ts +0 -1
- package/dist/esm/hooks/useListHeight.js +0 -1
- package/dist/esm/hooks/useListHeight.js.map +1 -1
- package/dist/esm/hooks/useToken.d.ts +2 -2
- package/dist/esm/hooks/useToken.js +13 -11
- package/dist/esm/hooks/useToken.js.map +1 -1
- package/dist/esm/hooks/useTokenAddressBalance.d.ts +2 -3
- package/dist/esm/hooks/useTokenAddressBalance.js +10 -14
- package/dist/esm/hooks/useTokenAddressBalance.js.map +1 -1
- package/dist/esm/hooks/useTokenBalances.d.ts +6 -9
- package/dist/esm/hooks/useTokenBalances.js +57 -72
- package/dist/esm/hooks/useTokenBalances.js.map +1 -1
- package/dist/esm/hooks/useTokenBalancesQueries.d.ts +11 -0
- package/dist/esm/hooks/useTokenBalancesQueries.js +74 -0
- package/dist/esm/hooks/useTokenBalancesQueries.js.map +1 -0
- package/dist/esm/hooks/useTokens.d.ts +6 -6
- package/dist/esm/hooks/useTokens.js +78 -70
- package/dist/esm/hooks/useTokens.js.map +1 -1
- package/dist/esm/i18n/bn.json +3 -3
- package/dist/esm/i18n/de.json +3 -3
- package/dist/esm/i18n/en.json +3 -3
- package/dist/esm/i18n/es.json +3 -3
- package/dist/esm/i18n/fr.json +3 -3
- package/dist/esm/i18n/hi.json +3 -3
- package/dist/esm/i18n/id.json +3 -3
- package/dist/esm/i18n/it.json +3 -3
- package/dist/esm/i18n/ja.json +3 -3
- package/dist/esm/i18n/ko.json +3 -3
- package/dist/esm/i18n/pl.json +3 -3
- package/dist/esm/i18n/pt.json +3 -3
- package/dist/esm/i18n/th.json +3 -3
- package/dist/esm/i18n/tr.json +3 -3
- package/dist/esm/i18n/uk.json +3 -3
- package/dist/esm/i18n/vi.json +3 -3
- package/dist/esm/i18n/zh.json +3 -3
- package/dist/esm/pages/SelectTokenPage/SearchTokenInput.js +6 -1
- package/dist/esm/pages/SelectTokenPage/SearchTokenInput.js.map +1 -1
- package/dist/esm/pages/SelectTokenPage/SelectTokenPage.js +2 -4
- package/dist/esm/pages/SelectTokenPage/SelectTokenPage.js.map +1 -1
- package/dist/esm/pages/TransactionPage/TokenValueBottomSheet.js +1 -1
- package/dist/esm/pages/TransactionPage/TokenValueBottomSheet.js.map +1 -1
- package/dist/esm/stores/chains/createChainOrderStore.d.ts +3 -2
- package/dist/esm/stores/chains/createChainOrderStore.js +13 -8
- package/dist/esm/stores/chains/createChainOrderStore.js.map +1 -1
- package/dist/esm/stores/chains/types.d.ts +2 -0
- package/dist/esm/stores/chains/useChainOrder.js +5 -1
- package/dist/esm/stores/chains/useChainOrder.js.map +1 -1
- package/dist/esm/types/token.d.ts +7 -2
- package/dist/esm/utils/chainType.d.ts +1 -0
- package/dist/esm/utils/chainType.js +2 -0
- package/dist/esm/utils/chainType.js.map +1 -1
- package/dist/esm/utils/token.d.ts +8 -0
- package/dist/esm/utils/token.js +29 -0
- package/dist/esm/utils/token.js.map +1 -0
- package/dist/esm/utils/tokenList.d.ts +13 -0
- package/dist/esm/utils/tokenList.js +106 -0
- package/dist/esm/utils/tokenList.js.map +1 -0
- package/package.json +7 -7
- package/package.json.tmp +6 -6
- package/src/components/AmountInput/AmountInputEndAdornment.tsx +3 -2
- package/src/components/AmountInput/PriceFormHelperText.tsx +3 -2
- package/src/components/ChainSelect/ChainSelect.tsx +112 -40
- package/src/components/ChainSelect/useChainSelect.ts +3 -3
- package/src/components/Chains/AllChainsAvatar.tsx +113 -0
- package/src/components/Chains/ChainList.tsx +3 -0
- package/src/components/Chains/ChainSearchInput.tsx +2 -2
- package/src/components/Chains/SelectChainContent.tsx +1 -0
- package/src/components/Chains/VirtualizedChainList.tsx +80 -12
- package/src/components/RouteCard/RouteCardEssentials.tsx +1 -1
- package/src/components/TokenList/TokenDetailsSheet.tsx +4 -9
- package/src/components/TokenList/TokenDetailsSheetContent.tsx +2 -6
- package/src/components/TokenList/TokenList.tsx +57 -129
- package/src/components/TokenList/TokenListItem.tsx +191 -166
- package/src/components/TokenList/VirtualizedTokenList.tsx +88 -48
- package/src/components/TokenList/types.ts +14 -10
- package/src/components/TokenList/useTokenSelect.ts +3 -4
- package/src/components/TransactionDetails.tsx +2 -2
- package/src/config/version.ts +1 -1
- package/src/hooks/useAccountsBalancesData.ts +101 -0
- package/src/hooks/useFilteredByTokenBalances.ts +101 -0
- package/src/hooks/useListHeight.ts +0 -1
- package/src/hooks/useToken.ts +26 -14
- package/src/hooks/useTokenAddressBalance.ts +14 -20
- package/src/hooks/useTokenBalances.ts +81 -80
- package/src/hooks/useTokenBalancesQueries.ts +94 -0
- package/src/hooks/useTokens.ts +118 -90
- package/src/i18n/bn.json +3 -3
- package/src/i18n/de.json +3 -3
- package/src/i18n/en.json +3 -3
- package/src/i18n/es.json +3 -3
- package/src/i18n/fr.json +3 -3
- package/src/i18n/hi.json +3 -3
- package/src/i18n/id.json +3 -3
- package/src/i18n/it.json +3 -3
- package/src/i18n/ja.json +3 -3
- package/src/i18n/ko.json +3 -3
- package/src/i18n/pl.json +3 -3
- package/src/i18n/pt.json +3 -3
- package/src/i18n/th.json +3 -3
- package/src/i18n/tr.json +3 -3
- package/src/i18n/uk.json +3 -3
- package/src/i18n/vi.json +3 -3
- package/src/i18n/zh.json +3 -3
- package/src/pages/SelectTokenPage/SearchTokenInput.tsx +5 -0
- package/src/pages/SelectTokenPage/SelectTokenPage.tsx +7 -13
- package/src/pages/TransactionPage/TokenValueBottomSheet.tsx +1 -1
- package/src/stores/chains/createChainOrderStore.ts +17 -8
- package/src/stores/chains/types.ts +2 -0
- package/src/stores/chains/useChainOrder.ts +5 -1
- package/src/types/token.ts +11 -2
- package/src/utils/chainType.ts +2 -0
- package/src/utils/token.ts +65 -0
- package/src/utils/tokenList.ts +172 -0
- package/dist/esm/components/TokenList/utils.d.ts +0 -2
- package/dist/esm/components/TokenList/utils.js +0 -35
- package/dist/esm/components/TokenList/utils.js.map +0 -1
- package/src/components/TokenList/utils.ts +0 -42
|
@@ -1,96 +1,97 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { useAccount } from '@lifi/wallet-management'
|
|
3
|
-
import { useQuery } from '@tanstack/react-query'
|
|
4
|
-
import { formatUnits } from 'viem'
|
|
1
|
+
import { useMemo } from 'react'
|
|
5
2
|
import { useWidgetConfig } from '../providers/WidgetProvider/WidgetProvider.js'
|
|
6
|
-
import type {
|
|
7
|
-
import {
|
|
3
|
+
import type { FormType } from '../stores/form/types.js'
|
|
4
|
+
import { isSearchMatch, processTokenBalances } from '../utils/tokenList.js'
|
|
5
|
+
import { useAccountsBalancesData } from './useAccountsBalancesData.js'
|
|
6
|
+
import { useTokenBalancesQueries } from './useTokenBalancesQueries.js'
|
|
8
7
|
import { useTokens } from './useTokens.js'
|
|
9
8
|
|
|
10
|
-
const
|
|
9
|
+
export const useTokenBalances = (
|
|
10
|
+
selectedChainId?: number,
|
|
11
|
+
formType?: FormType,
|
|
12
|
+
isAllNetworks?: boolean,
|
|
13
|
+
search?: string
|
|
14
|
+
) => {
|
|
15
|
+
const {
|
|
16
|
+
allTokens,
|
|
17
|
+
isLoading: isTokensLoading,
|
|
18
|
+
isSearchLoading,
|
|
19
|
+
} = useTokens(formType, search)
|
|
11
20
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
useTokens(selectedChainId)
|
|
15
|
-
const { account } = useAccount({ chainType: chain?.chainType })
|
|
16
|
-
const { keyPrefix } = useWidgetConfig()
|
|
21
|
+
const { data: accountsWithAllTokens, isLoading: isAccountsLoading } =
|
|
22
|
+
useAccountsBalancesData(selectedChainId, formType, isAllNetworks, allTokens)
|
|
17
23
|
|
|
18
24
|
const isBalanceLoadingEnabled =
|
|
19
|
-
Boolean(
|
|
20
|
-
Boolean(tokens?.length) &&
|
|
21
|
-
Boolean(selectedChainId)
|
|
25
|
+
Boolean(accountsWithAllTokens) && !isAccountsLoading
|
|
22
26
|
|
|
23
|
-
const {
|
|
24
|
-
|
|
25
|
-
isLoading: isBalanceLoading,
|
|
26
|
-
refetch,
|
|
27
|
-
} = useQuery({
|
|
28
|
-
queryKey: [
|
|
29
|
-
getQueryKey('token-balances', keyPrefix),
|
|
30
|
-
account.address,
|
|
31
|
-
selectedChainId,
|
|
32
|
-
tokens?.length,
|
|
33
|
-
],
|
|
34
|
-
queryFn: async ({ queryKey: [, accountAddress] }) => {
|
|
35
|
-
const tokensWithBalance: TokenAmount[] = await getTokenBalances(
|
|
36
|
-
accountAddress as string,
|
|
37
|
-
tokens!
|
|
38
|
-
)
|
|
27
|
+
const { data: allTokensWithBalances, isLoading: isBalanceQueriesLoading } =
|
|
28
|
+
useTokenBalancesQueries(accountsWithAllTokens, isBalanceLoadingEnabled)
|
|
39
29
|
|
|
40
|
-
|
|
41
|
-
return tokens as TokenAmount[]
|
|
42
|
-
}
|
|
30
|
+
const { tokens: configTokens } = useWidgetConfig()
|
|
43
31
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
Number.parseFloat(formatUnits(a.amount ?? 0n, a.decimals)) *
|
|
48
|
-
Number.parseFloat(a.priceUSD ?? '0')
|
|
32
|
+
const isBalanceLoading =
|
|
33
|
+
(isBalanceQueriesLoading || isAccountsLoading) &&
|
|
34
|
+
!allTokensWithBalances?.length
|
|
49
35
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
36
|
+
const displayedTokensList = useMemo(() => {
|
|
37
|
+
const tokensByChain = isAllNetworks
|
|
38
|
+
? Object.values(allTokens ?? {}).flat()
|
|
39
|
+
: selectedChainId
|
|
40
|
+
? allTokens?.[selectedChainId]
|
|
41
|
+
: undefined
|
|
42
|
+
return tokensByChain?.filter((t) => isSearchMatch(t, search)) ?? []
|
|
43
|
+
}, [allTokens, isAllNetworks, selectedChainId, search])
|
|
54
44
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
45
|
+
const displayedTokensWithBalances = useMemo(() => {
|
|
46
|
+
const balancesByChain = isAllNetworks
|
|
47
|
+
? allTokensWithBalances
|
|
48
|
+
: selectedChainId
|
|
49
|
+
? allTokensWithBalances?.filter((t) => t.chainId === selectedChainId)
|
|
50
|
+
: undefined
|
|
51
|
+
const displayedTokensSet = new Set(
|
|
52
|
+
displayedTokensList?.map(
|
|
53
|
+
(t) => `${t.chainId}-${t.address.toLowerCase()}`
|
|
54
|
+
) || []
|
|
55
|
+
)
|
|
56
|
+
return balancesByChain?.filter((token) => {
|
|
57
|
+
const tokenKey = `${token.chainId}-${token.address.toLowerCase()}`
|
|
58
|
+
// Check if token is in displayed list and has amount
|
|
59
|
+
const isInDisplayedList = displayedTokensSet.has(tokenKey) && token.amount
|
|
60
|
+
// Check if it matches search (for cached appended tokens)
|
|
61
|
+
const matchesSearch = isSearchMatch(token, search)
|
|
62
|
+
return isInDisplayedList || matchesSearch
|
|
63
|
+
})
|
|
64
|
+
}, [
|
|
65
|
+
allTokensWithBalances,
|
|
66
|
+
displayedTokensList,
|
|
67
|
+
search,
|
|
68
|
+
selectedChainId,
|
|
69
|
+
isAllNetworks,
|
|
70
|
+
])
|
|
70
71
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
72
|
+
const { processedTokens, withCategories } = useMemo(() => {
|
|
73
|
+
return processTokenBalances(
|
|
74
|
+
isBalanceLoading,
|
|
75
|
+
isAllNetworks ?? false,
|
|
76
|
+
configTokens,
|
|
77
|
+
selectedChainId,
|
|
78
|
+
displayedTokensList,
|
|
79
|
+
displayedTokensWithBalances
|
|
80
|
+
)
|
|
81
|
+
}, [
|
|
82
|
+
isBalanceLoading,
|
|
83
|
+
isAllNetworks,
|
|
84
|
+
configTokens,
|
|
85
|
+
selectedChainId,
|
|
86
|
+
displayedTokensList,
|
|
87
|
+
displayedTokensWithBalances,
|
|
88
|
+
])
|
|
85
89
|
|
|
86
90
|
return {
|
|
87
|
-
tokens,
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
isLoading,
|
|
93
|
-
isBalanceLoading: isBalanceLoading && isBalanceLoadingEnabled,
|
|
94
|
-
refetch,
|
|
91
|
+
tokens: processedTokens ?? [],
|
|
92
|
+
withCategories,
|
|
93
|
+
isTokensLoading,
|
|
94
|
+
isSearchLoading,
|
|
95
|
+
isBalanceLoading,
|
|
95
96
|
}
|
|
96
97
|
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { getTokenBalances, type TokenExtended } from '@lifi/sdk'
|
|
2
|
+
import { useQueries } from '@tanstack/react-query'
|
|
3
|
+
import { useMemo, useRef } from 'react'
|
|
4
|
+
import { useWidgetConfig } from '../providers/WidgetProvider/WidgetProvider.js'
|
|
5
|
+
import type { TokenAmount, TokenAmountExtended } from '../types/token.js'
|
|
6
|
+
import { getQueryKey } from '../utils/queries.js'
|
|
7
|
+
|
|
8
|
+
const defaultRefetchInterval = 32_000
|
|
9
|
+
|
|
10
|
+
export const useTokenBalancesQueries = (
|
|
11
|
+
accountsWithTokens?: Record<string, Record<number, TokenExtended[]>>,
|
|
12
|
+
isBalanceLoadingEnabled?: boolean
|
|
13
|
+
) => {
|
|
14
|
+
const { keyPrefix } = useWidgetConfig()
|
|
15
|
+
const firstLoadStartRef = useRef<number | null>(null)
|
|
16
|
+
|
|
17
|
+
const queryConfig = useMemo(() => {
|
|
18
|
+
if (!accountsWithTokens) {
|
|
19
|
+
return []
|
|
20
|
+
}
|
|
21
|
+
return Object.entries(accountsWithTokens).flatMap(
|
|
22
|
+
([accountAddress, chainTokens]) =>
|
|
23
|
+
Object.entries(chainTokens).map(([chainIdStr, tokens]) => {
|
|
24
|
+
const chainId = Number(chainIdStr)
|
|
25
|
+
return {
|
|
26
|
+
queryKey: [
|
|
27
|
+
getQueryKey('token-balances', keyPrefix),
|
|
28
|
+
accountAddress,
|
|
29
|
+
chainId,
|
|
30
|
+
tokens.length,
|
|
31
|
+
],
|
|
32
|
+
queryFn: async (): Promise<TokenAmountExtended[]> => {
|
|
33
|
+
if (!accountAddress || !tokens) {
|
|
34
|
+
return []
|
|
35
|
+
}
|
|
36
|
+
return await getTokenBalances(accountAddress, tokens)
|
|
37
|
+
},
|
|
38
|
+
enabled: isBalanceLoadingEnabled,
|
|
39
|
+
refetchInterval: defaultRefetchInterval,
|
|
40
|
+
staleTime: defaultRefetchInterval,
|
|
41
|
+
keepPreviousData: true,
|
|
42
|
+
}
|
|
43
|
+
})
|
|
44
|
+
)
|
|
45
|
+
}, [accountsWithTokens, isBalanceLoadingEnabled, keyPrefix])
|
|
46
|
+
|
|
47
|
+
const result = useQueries({
|
|
48
|
+
queries: queryConfig,
|
|
49
|
+
combine: (results) => {
|
|
50
|
+
const now = Date.now()
|
|
51
|
+
|
|
52
|
+
const hasLoadingQueries = results.some((result) => result.isLoading)
|
|
53
|
+
if (hasLoadingQueries && firstLoadStartRef.current === null) {
|
|
54
|
+
firstLoadStartRef.current = now
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const allComplete = results.every(
|
|
58
|
+
(result) => result.isSuccess || result.isError
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
// Reset the start time when all queries complete
|
|
62
|
+
if (allComplete) {
|
|
63
|
+
firstLoadStartRef.current = null
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Calculate time since first load started
|
|
67
|
+
const timeSinceStart = firstLoadStartRef.current
|
|
68
|
+
? now - firstLoadStartRef.current
|
|
69
|
+
: 0
|
|
70
|
+
|
|
71
|
+
// Return results if all complete OR if 500ms have passed since first query started
|
|
72
|
+
const shouldReturnResults = allComplete || timeSinceStart >= 500
|
|
73
|
+
|
|
74
|
+
if (shouldReturnResults) {
|
|
75
|
+
const data: TokenAmount[] = results
|
|
76
|
+
.flatMap((result) => result.data || [])
|
|
77
|
+
.filter((token) => token.amount)
|
|
78
|
+
return {
|
|
79
|
+
data,
|
|
80
|
+
isLoading: !allComplete,
|
|
81
|
+
isError: results.some((result) => result.isError),
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return {
|
|
86
|
+
data: undefined,
|
|
87
|
+
isLoading: true,
|
|
88
|
+
isError: false,
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
return result
|
|
94
|
+
}
|
package/src/hooks/useTokens.ts
CHANGED
|
@@ -1,111 +1,139 @@
|
|
|
1
|
-
import { ChainType, getTokens } from '@lifi/sdk'
|
|
2
|
-
import { useQuery } from '@tanstack/react-query'
|
|
1
|
+
import { ChainType, getTokens, type TokensExtendedResponse } from '@lifi/sdk'
|
|
2
|
+
import { useQuery, useQueryClient } from '@tanstack/react-query'
|
|
3
3
|
import { useMemo } from 'react'
|
|
4
4
|
import { useWidgetConfig } from '../providers/WidgetProvider/WidgetProvider.js'
|
|
5
|
-
import type {
|
|
5
|
+
import type { FormType } from '../stores/form/types.js'
|
|
6
|
+
import { isItemAllowed } from '../utils/item.js'
|
|
6
7
|
import { getQueryKey } from '../utils/queries.js'
|
|
7
|
-
import {
|
|
8
|
+
import { filterAllowedTokens } from '../utils/token.js'
|
|
9
|
+
|
|
10
|
+
export const useTokens = (formType?: FormType, search?: string) => {
|
|
11
|
+
const {
|
|
12
|
+
tokens: configTokens,
|
|
13
|
+
chains: chainsConfig,
|
|
14
|
+
keyPrefix,
|
|
15
|
+
} = useWidgetConfig()
|
|
16
|
+
|
|
17
|
+
const { isLoading: isSearchLoading } = useBackgroundTokenSearch(search)
|
|
8
18
|
|
|
9
|
-
export const useTokens = (selectedChainId?: number) => {
|
|
10
|
-
const { tokens: configTokens, keyPrefix } = useWidgetConfig()
|
|
11
19
|
const { data, isLoading } = useQuery({
|
|
12
20
|
queryKey: [getQueryKey('tokens', keyPrefix)],
|
|
13
|
-
queryFn: () =>
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
queryFn: async ({ signal }) => {
|
|
22
|
+
const chainTypes = [
|
|
23
|
+
ChainType.EVM,
|
|
24
|
+
ChainType.SVM,
|
|
25
|
+
ChainType.UTXO,
|
|
26
|
+
ChainType.MVM,
|
|
27
|
+
].filter((chainType) => isItemAllowed(chainType, chainsConfig?.types))
|
|
28
|
+
const tokensResponse: TokensExtendedResponse = await getTokens(
|
|
29
|
+
{
|
|
30
|
+
chainTypes,
|
|
31
|
+
orderBy: 'volumeUSD24H',
|
|
32
|
+
extended: true,
|
|
33
|
+
limit: 1000,
|
|
34
|
+
},
|
|
35
|
+
{ signal }
|
|
36
|
+
)
|
|
37
|
+
return tokensResponse
|
|
38
|
+
},
|
|
24
39
|
refetchInterval: 300_000,
|
|
25
40
|
staleTime: 300_000,
|
|
26
41
|
})
|
|
27
|
-
const {
|
|
28
|
-
chains,
|
|
29
|
-
isLoading: isSupportedChainsLoading,
|
|
30
|
-
getChainById,
|
|
31
|
-
} = useChains()
|
|
32
|
-
|
|
33
|
-
const filteredData = useMemo(() => {
|
|
34
|
-
if (isSupportedChainsLoading || !data) {
|
|
35
|
-
return
|
|
36
|
-
}
|
|
37
|
-
const chain = getChainById(selectedChainId, chains)
|
|
38
|
-
const chainAllowed = selectedChainId && chain
|
|
39
|
-
if (!chainAllowed) {
|
|
40
|
-
return
|
|
41
|
-
}
|
|
42
|
-
let filteredTokens = data.tokens?.[selectedChainId] || []
|
|
43
|
-
const includedTokens = configTokens?.include?.filter(
|
|
44
|
-
(token) => token.chainId === selectedChainId
|
|
45
|
-
)
|
|
46
|
-
if (includedTokens?.length) {
|
|
47
|
-
filteredTokens = [...includedTokens, ...filteredTokens]
|
|
48
|
-
}
|
|
49
42
|
|
|
50
|
-
|
|
51
|
-
|
|
43
|
+
const allTokens = useMemo(() => {
|
|
44
|
+
return filterAllowedTokens(
|
|
45
|
+
data?.tokens,
|
|
46
|
+
configTokens,
|
|
47
|
+
chainsConfig,
|
|
48
|
+
formType
|
|
52
49
|
)
|
|
50
|
+
}, [data?.tokens, configTokens, chainsConfig, formType])
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
allTokens,
|
|
54
|
+
isLoading,
|
|
55
|
+
isSearchLoading,
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// This hook is used to search for tokens in the background.
|
|
60
|
+
// It updates the main tokens cache with the search results,
|
|
61
|
+
// if any of the tokens are not already in the cache.
|
|
62
|
+
const useBackgroundTokenSearch = (search?: string) => {
|
|
63
|
+
const { chains: chainsConfig, keyPrefix } = useWidgetConfig()
|
|
64
|
+
const queryClient = useQueryClient()
|
|
53
65
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
const
|
|
58
|
-
|
|
66
|
+
const { isLoading: isSearchLoading } = useQuery({
|
|
67
|
+
queryKey: [getQueryKey('tokens-search', keyPrefix), search],
|
|
68
|
+
queryFn: async ({ queryKey: [, searchQuery], signal }) => {
|
|
69
|
+
const chainTypes = [
|
|
70
|
+
ChainType.EVM,
|
|
71
|
+
ChainType.SVM,
|
|
72
|
+
ChainType.UTXO,
|
|
73
|
+
ChainType.MVM,
|
|
74
|
+
].filter((chainType) => isItemAllowed(chainType, chainsConfig?.types))
|
|
75
|
+
const tokensResponse: TokensExtendedResponse = await getTokens(
|
|
76
|
+
{
|
|
77
|
+
chainTypes,
|
|
78
|
+
orderBy: 'volumeUSD24H',
|
|
79
|
+
extended: true,
|
|
80
|
+
search: searchQuery,
|
|
81
|
+
limit: 1000,
|
|
82
|
+
},
|
|
83
|
+
{ signal }
|
|
59
84
|
)
|
|
60
85
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
86
|
+
// Merge search results into main tokens cache
|
|
87
|
+
if (searchQuery) {
|
|
88
|
+
queryClient.setQueriesData<TokensExtendedResponse>(
|
|
89
|
+
{ queryKey: [getQueryKey('tokens', keyPrefix)] },
|
|
90
|
+
(data) => {
|
|
91
|
+
if (!data) {
|
|
92
|
+
return data
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const clonedData = { ...data, tokens: { ...data.tokens } }
|
|
96
|
+
|
|
97
|
+
Object.entries(tokensResponse.tokens).forEach(
|
|
98
|
+
([chainId, searchTokens]) => {
|
|
99
|
+
const chainIdNum = Number(chainId)
|
|
100
|
+
const existingTokens = clonedData.tokens[chainIdNum] || []
|
|
101
|
+
|
|
102
|
+
const existingTokenAddresses = new Set(
|
|
103
|
+
existingTokens.map((token) => token.address.toLowerCase())
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
// Find tokens in search results that don't exist in the main list
|
|
107
|
+
const newTokens = searchTokens.filter(
|
|
108
|
+
(searchToken) =>
|
|
109
|
+
!existingTokenAddresses.has(
|
|
110
|
+
searchToken.address.toLowerCase()
|
|
111
|
+
)
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
// Add new tokens to the main list
|
|
115
|
+
if (newTokens.length > 0) {
|
|
116
|
+
clonedData.tokens[chainIdNum] = [
|
|
117
|
+
...existingTokens,
|
|
118
|
+
...newTokens,
|
|
119
|
+
]
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
return clonedData
|
|
125
|
+
}
|
|
81
126
|
)
|
|
82
|
-
populatedConfigTokens.push(...filteredTokens)
|
|
83
|
-
filteredTokens = populatedConfigTokens
|
|
84
127
|
}
|
|
85
128
|
|
|
86
|
-
return
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
popularTokens,
|
|
93
|
-
chain,
|
|
94
|
-
}
|
|
95
|
-
}, [
|
|
96
|
-
chains,
|
|
97
|
-
configTokens,
|
|
98
|
-
data,
|
|
99
|
-
getChainById,
|
|
100
|
-
isSupportedChainsLoading,
|
|
101
|
-
selectedChainId,
|
|
102
|
-
])
|
|
129
|
+
return tokensResponse
|
|
130
|
+
},
|
|
131
|
+
enabled: !!search,
|
|
132
|
+
refetchInterval: 300_000,
|
|
133
|
+
staleTime: 300_000,
|
|
134
|
+
})
|
|
103
135
|
|
|
104
136
|
return {
|
|
105
|
-
|
|
106
|
-
featuredTokens: filteredData?.featuredTokens,
|
|
107
|
-
popularTokens: filteredData?.popularTokens,
|
|
108
|
-
chain: filteredData?.chain,
|
|
109
|
-
isLoading,
|
|
137
|
+
isLoading: isSearchLoading,
|
|
110
138
|
}
|
|
111
139
|
}
|
package/src/i18n/bn.json
CHANGED
|
@@ -212,6 +212,7 @@
|
|
|
212
212
|
"slippage": ""
|
|
213
213
|
},
|
|
214
214
|
"main": {
|
|
215
|
+
"allNetworks": "",
|
|
215
216
|
"allTokens": "",
|
|
216
217
|
"bridgeStepDetails": "",
|
|
217
218
|
"checkoutStepDetails": "",
|
|
@@ -310,10 +311,9 @@
|
|
|
310
311
|
"tokenOnChainAmount": "",
|
|
311
312
|
"tokenSearch": "",
|
|
312
313
|
"valueLoss": "মান ক্ষতি",
|
|
313
|
-
"searchChain": "",
|
|
314
|
-
"searchChains": "",
|
|
315
314
|
"searchBridges": "",
|
|
316
|
-
"searchExchanges": ""
|
|
315
|
+
"searchExchanges": "",
|
|
316
|
+
"searchNetwork": ""
|
|
317
317
|
},
|
|
318
318
|
"settings": {
|
|
319
319
|
"appearance": "",
|
package/src/i18n/de.json
CHANGED
|
@@ -212,6 +212,7 @@
|
|
|
212
212
|
"slippage": ""
|
|
213
213
|
},
|
|
214
214
|
"main": {
|
|
215
|
+
"allNetworks": "",
|
|
215
216
|
"allTokens": "",
|
|
216
217
|
"bridgeStepDetails": "",
|
|
217
218
|
"checkoutStepDetails": "",
|
|
@@ -310,10 +311,9 @@
|
|
|
310
311
|
"tokenOnChainAmount": "",
|
|
311
312
|
"tokenSearch": "",
|
|
312
313
|
"valueLoss": "Wertverlust",
|
|
313
|
-
"searchChain": "",
|
|
314
|
-
"searchChains": "",
|
|
315
314
|
"searchBridges": "",
|
|
316
|
-
"searchExchanges": ""
|
|
315
|
+
"searchExchanges": "",
|
|
316
|
+
"searchNetwork": ""
|
|
317
317
|
},
|
|
318
318
|
"settings": {
|
|
319
319
|
"appearance": "",
|
package/src/i18n/en.json
CHANGED
|
@@ -212,6 +212,7 @@
|
|
|
212
212
|
"slippage": "The maximum percentage difference between the expected price, and the actual price at which a transfer is executed. This value can be changed in settings."
|
|
213
213
|
},
|
|
214
214
|
"main": {
|
|
215
|
+
"allNetworks": "All networks",
|
|
215
216
|
"allTokens": "All tokens",
|
|
216
217
|
"bridgeStepDetails": "Bridge from {{from}} to {{to}} via {{tool}}",
|
|
217
218
|
"checkoutStepDetails": "Purchase via {{tool}}",
|
|
@@ -310,10 +311,9 @@
|
|
|
310
311
|
"tokenOnChainAmount": "{{amount, numberExt}} {{tokenSymbol}} on {{chainName}}",
|
|
311
312
|
"tokenSearch": "Search by token or address",
|
|
312
313
|
"valueLoss": "Value loss",
|
|
313
|
-
"searchChain": "Search chain",
|
|
314
|
-
"searchChains": "Search by chain name",
|
|
315
314
|
"searchBridges": "Search by bridge name",
|
|
316
|
-
"searchExchanges": "Search by exchange name"
|
|
315
|
+
"searchExchanges": "Search by exchange name",
|
|
316
|
+
"searchNetwork": "Search network"
|
|
317
317
|
},
|
|
318
318
|
"settings": {
|
|
319
319
|
"appearance": "Appearance",
|
package/src/i18n/es.json
CHANGED
|
@@ -212,6 +212,7 @@
|
|
|
212
212
|
"slippage": "El porcentaje máximo de diferencia entre el precio esperado, y el precio real al que se ejecuta una transferencia. Este valor puede cambiarse en ajustes."
|
|
213
213
|
},
|
|
214
214
|
"main": {
|
|
215
|
+
"allNetworks": "",
|
|
215
216
|
"allTokens": "Todos los tokens",
|
|
216
217
|
"bridgeStepDetails": "Puente de {{from}} a {{to}} vía {{tool}}",
|
|
217
218
|
"checkoutStepDetails": "Comprar a través de {{tool}}",
|
|
@@ -310,10 +311,9 @@
|
|
|
310
311
|
"tokenOnChainAmount": "",
|
|
311
312
|
"tokenSearch": "",
|
|
312
313
|
"valueLoss": "Valor perdido",
|
|
313
|
-
"searchChain": "",
|
|
314
|
-
"searchChains": "Buscar por nombre de cadena",
|
|
315
314
|
"searchBridges": "Buscar por nombre de puente",
|
|
316
|
-
"searchExchanges": "Buscar por nombre de intercambio"
|
|
315
|
+
"searchExchanges": "Buscar por nombre de intercambio",
|
|
316
|
+
"searchNetwork": ""
|
|
317
317
|
},
|
|
318
318
|
"settings": {
|
|
319
319
|
"appearance": "",
|
package/src/i18n/fr.json
CHANGED
|
@@ -212,6 +212,7 @@
|
|
|
212
212
|
"slippage": ""
|
|
213
213
|
},
|
|
214
214
|
"main": {
|
|
215
|
+
"allNetworks": "",
|
|
215
216
|
"allTokens": "Tous les tokens",
|
|
216
217
|
"bridgeStepDetails": "Transférer de {{from}} à {{to}} via {{tool}}",
|
|
217
218
|
"checkoutStepDetails": "Achat via {{tool}}",
|
|
@@ -310,10 +311,9 @@
|
|
|
310
311
|
"tokenOnChainAmount": "",
|
|
311
312
|
"tokenSearch": "",
|
|
312
313
|
"valueLoss": "Perte de valeur",
|
|
313
|
-
"searchChain": "",
|
|
314
|
-
"searchChains": "",
|
|
315
314
|
"searchBridges": "",
|
|
316
|
-
"searchExchanges": ""
|
|
315
|
+
"searchExchanges": "",
|
|
316
|
+
"searchNetwork": ""
|
|
317
317
|
},
|
|
318
318
|
"settings": {
|
|
319
319
|
"appearance": "",
|
package/src/i18n/hi.json
CHANGED
|
@@ -212,6 +212,7 @@
|
|
|
212
212
|
"slippage": ""
|
|
213
213
|
},
|
|
214
214
|
"main": {
|
|
215
|
+
"allNetworks": "",
|
|
215
216
|
"allTokens": "",
|
|
216
217
|
"bridgeStepDetails": "",
|
|
217
218
|
"checkoutStepDetails": "",
|
|
@@ -310,10 +311,9 @@
|
|
|
310
311
|
"tokenOnChainAmount": "",
|
|
311
312
|
"tokenSearch": "",
|
|
312
313
|
"valueLoss": "",
|
|
313
|
-
"searchChain": "",
|
|
314
|
-
"searchChains": "",
|
|
315
314
|
"searchBridges": "",
|
|
316
|
-
"searchExchanges": ""
|
|
315
|
+
"searchExchanges": "",
|
|
316
|
+
"searchNetwork": ""
|
|
317
317
|
},
|
|
318
318
|
"settings": {
|
|
319
319
|
"appearance": "",
|
package/src/i18n/id.json
CHANGED
|
@@ -212,6 +212,7 @@
|
|
|
212
212
|
"slippage": "Perbedaan persentase maksimum antara harga yang diharapkan dan harga sebenarnya saat transfer dilakukan. Nilai ini dapat diubah dalam pengaturan."
|
|
213
213
|
},
|
|
214
214
|
"main": {
|
|
215
|
+
"allNetworks": "",
|
|
215
216
|
"allTokens": "Semua Token",
|
|
216
217
|
"bridgeStepDetails": "Bridge dari {{from}} to {{to}} via {{tool}}",
|
|
217
218
|
"checkoutStepDetails": "Dapatkan melalui {{tool}}",
|
|
@@ -310,10 +311,9 @@
|
|
|
310
311
|
"tokenOnChainAmount": "{{amount, numberExt}} {{tokenSymbol}} di {{chainName}}",
|
|
311
312
|
"tokenSearch": "",
|
|
312
313
|
"valueLoss": "Kehilangan nilai",
|
|
313
|
-
"searchChain": "",
|
|
314
|
-
"searchChains": "Cari berdasarkan nama rantai",
|
|
315
314
|
"searchBridges": "Cari berdasarkan nama bridge",
|
|
316
|
-
"searchExchanges": "Cari berdasarkan nama exchange"
|
|
315
|
+
"searchExchanges": "Cari berdasarkan nama exchange",
|
|
316
|
+
"searchNetwork": ""
|
|
317
317
|
},
|
|
318
318
|
"settings": {
|
|
319
319
|
"appearance": "",
|
package/src/i18n/it.json
CHANGED
|
@@ -212,6 +212,7 @@
|
|
|
212
212
|
"slippage": ""
|
|
213
213
|
},
|
|
214
214
|
"main": {
|
|
215
|
+
"allNetworks": "",
|
|
215
216
|
"allTokens": "",
|
|
216
217
|
"bridgeStepDetails": "",
|
|
217
218
|
"checkoutStepDetails": "",
|
|
@@ -310,10 +311,9 @@
|
|
|
310
311
|
"tokenOnChainAmount": "",
|
|
311
312
|
"tokenSearch": "",
|
|
312
313
|
"valueLoss": "Perdita di valore",
|
|
313
|
-
"searchChain": "",
|
|
314
|
-
"searchChains": "",
|
|
315
314
|
"searchBridges": "",
|
|
316
|
-
"searchExchanges": ""
|
|
315
|
+
"searchExchanges": "",
|
|
316
|
+
"searchNetwork": ""
|
|
317
317
|
},
|
|
318
318
|
"settings": {
|
|
319
319
|
"appearance": "",
|