@lifi/widget 4.7.1 → 4.9.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/dist/esm/components/AmountInput/AmountInput.style.d.ts.map +1 -1
- package/dist/esm/components/AmountInputCard/AmountInputCardPair.js +5 -2
- package/dist/esm/components/AmountInputCard/AmountInputCardPair.js.map +1 -1
- package/dist/esm/components/Card/Card.d.ts.map +1 -1
- package/dist/esm/components/Card/CardIconButton.d.ts.map +1 -1
- package/dist/esm/components/ContractComponent/ItemPrice.d.ts.map +1 -1
- package/dist/esm/components/ListItem/ListItemButton.d.ts.map +1 -1
- package/dist/esm/components/ListItemButton.d.ts.map +1 -1
- package/dist/esm/components/SelectChainAndToken.js +5 -2
- package/dist/esm/components/SelectChainAndToken.js.map +1 -1
- package/dist/esm/components/SendToWallet/SendToWalletButton.js +5 -4
- package/dist/esm/components/SendToWallet/SendToWalletButton.js.map +1 -1
- package/dist/esm/components/Token/Token.d.ts.map +1 -1
- package/dist/esm/components/TokenList/types.d.ts.map +1 -1
- package/dist/esm/components/TokenList/useTokenSelect.d.ts.map +1 -1
- package/dist/esm/components/TokenList/useTokenSelect.js +10 -0
- package/dist/esm/components/TokenList/useTokenSelect.js.map +1 -1
- package/dist/esm/config/constants.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/useAccountsBalancesData.js +5 -2
- package/dist/esm/hooks/useAccountsBalancesData.js.map +1 -1
- package/dist/esm/hooks/useAddressValidation.d.ts +3 -2
- package/dist/esm/hooks/useAddressValidation.d.ts.map +1 -1
- package/dist/esm/hooks/useAddressValidation.js +48 -21
- package/dist/esm/hooks/useAddressValidation.js.map +1 -1
- package/dist/esm/hooks/useAvailableChains.d.ts.map +1 -1
- package/dist/esm/hooks/useAvailableChains.js +21 -38
- package/dist/esm/hooks/useAvailableChains.js.map +1 -1
- package/dist/esm/hooks/useFromTokenSufficiency.js +3 -3
- package/dist/esm/hooks/useFromTokenSufficiency.js.map +1 -1
- package/dist/esm/hooks/useGasRecommendation.js +3 -3
- package/dist/esm/hooks/useGasRecommendation.js.map +1 -1
- package/dist/esm/hooks/useGasRefuel.js +4 -1
- package/dist/esm/hooks/useGasRefuel.js.map +1 -1
- package/dist/esm/hooks/useGasSufficiency.js +3 -3
- package/dist/esm/hooks/useGasSufficiency.js.map +1 -1
- package/dist/esm/hooks/useIsBatchingSupported.js +2 -2
- package/dist/esm/hooks/useIsBatchingSupported.js.map +1 -1
- package/dist/esm/hooks/useRouteExecution.js +6 -6
- package/dist/esm/hooks/useRouteExecution.js.map +1 -1
- package/dist/esm/hooks/useRoutes.d.ts.map +1 -1
- package/dist/esm/hooks/useRoutes.js +18 -13
- package/dist/esm/hooks/useRoutes.js.map +1 -1
- package/dist/esm/hooks/useToAddressAutoPopulate.js +6 -8
- package/dist/esm/hooks/useToAddressAutoPopulate.js.map +1 -1
- package/dist/esm/hooks/useToAddressRequirements.d.ts +3 -2
- package/dist/esm/hooks/useToAddressRequirements.d.ts.map +1 -1
- package/dist/esm/hooks/useToAddressRequirements.js +8 -7
- package/dist/esm/hooks/useToAddressRequirements.js.map +1 -1
- package/dist/esm/hooks/useToAddressReset.js +6 -3
- package/dist/esm/hooks/useToAddressReset.js.map +1 -1
- package/dist/esm/hooks/useTokenBalance.js +6 -5
- package/dist/esm/hooks/useTokenBalance.js.map +1 -1
- package/dist/esm/hooks/useTokenBalancesQueries.js +3 -3
- package/dist/esm/hooks/useTokenBalancesQueries.js.map +1 -1
- package/dist/esm/hooks/useTokenSearch.js +3 -3
- package/dist/esm/hooks/useTokenSearch.js.map +1 -1
- package/dist/esm/hooks/useTokens.js +15 -15
- package/dist/esm/hooks/useTokens.js.map +1 -1
- package/dist/esm/hooks/useTools.d.ts.map +1 -1
- package/dist/esm/hooks/useTools.js +26 -27
- package/dist/esm/hooks/useTools.js.map +1 -1
- package/dist/esm/hooks/useTransactionDetails.js +2 -2
- package/dist/esm/hooks/useTransactionDetails.js.map +1 -1
- package/dist/esm/hooks/useTransactionHistory.js +3 -3
- package/dist/esm/hooks/useTransactionHistory.js.map +1 -1
- package/dist/esm/i18n/bn.json +2 -1
- package/dist/esm/i18n/de.json +2 -1
- package/dist/esm/i18n/en.json +2 -1
- package/dist/esm/i18n/es.json +2 -1
- package/dist/esm/i18n/fr.json +2 -1
- package/dist/esm/i18n/hi.json +2 -1
- package/dist/esm/i18n/id.json +2 -1
- package/dist/esm/i18n/it.json +2 -1
- package/dist/esm/i18n/ja.json +2 -1
- package/dist/esm/i18n/ko.json +2 -1
- package/dist/esm/i18n/pl.json +2 -1
- package/dist/esm/i18n/pt.json +2 -1
- package/dist/esm/i18n/th.json +2 -1
- package/dist/esm/i18n/tr.json +2 -1
- package/dist/esm/i18n/uk.json +2 -1
- package/dist/esm/i18n/vi.json +2 -1
- package/dist/esm/i18n/zh.json +2 -1
- package/dist/esm/index.d.ts +5 -1
- package/dist/esm/index.js +3 -1
- package/dist/esm/pages/RoutesPage/RoutesPage.style.d.ts.map +1 -1
- package/dist/esm/pages/SendToWallet/BookmarkAddressSheet.js +7 -4
- package/dist/esm/pages/SendToWallet/BookmarkAddressSheet.js.map +1 -1
- package/dist/esm/pages/SendToWallet/BookmarksPage.js +35 -31
- package/dist/esm/pages/SendToWallet/BookmarksPage.js.map +1 -1
- package/dist/esm/pages/SendToWallet/ConnectedWalletsPage.js +4 -3
- package/dist/esm/pages/SendToWallet/ConnectedWalletsPage.js.map +1 -1
- package/dist/esm/pages/SendToWallet/RecentWalletsPage.js +43 -39
- package/dist/esm/pages/SendToWallet/RecentWalletsPage.js.map +1 -1
- package/dist/esm/pages/SendToWallet/SendToConfiguredWalletPage.js +32 -26
- package/dist/esm/pages/SendToWallet/SendToConfiguredWalletPage.js.map +1 -1
- package/dist/esm/pages/SendToWallet/SendToWalletPage.js +5 -10
- package/dist/esm/pages/SendToWallet/SendToWalletPage.js.map +1 -1
- package/dist/esm/providers/I18nProvider/types.d.ts.map +1 -1
- package/dist/esm/providers/WalletProvider/WalletProvider.d.ts.map +1 -1
- package/dist/esm/providers/WalletProvider/WalletProvider.js +14 -2
- package/dist/esm/providers/WalletProvider/WalletProvider.js.map +1 -1
- package/dist/esm/providers/WidgetProvider/WidgetProvider.d.ts.map +1 -1
- package/dist/esm/providers/WidgetProvider/WidgetProvider.js +15 -11
- package/dist/esm/providers/WidgetProvider/WidgetProvider.js.map +1 -1
- package/dist/esm/providers/WidgetProvider/types.d.ts +2 -0
- package/dist/esm/providers/WidgetProvider/types.d.ts.map +1 -1
- package/dist/esm/queries/getChains.d.ts +38 -0
- package/dist/esm/queries/getChains.d.ts.map +1 -0
- package/dist/esm/queries/getChains.js +51 -0
- package/dist/esm/queries/getChains.js.map +1 -0
- package/dist/esm/queries/getTools.d.ts +26 -0
- package/dist/esm/queries/getTools.d.ts.map +1 -0
- package/dist/esm/queries/getTools.js +30 -0
- package/dist/esm/queries/getTools.js.map +1 -0
- package/dist/esm/queries/index.d.ts +4 -0
- package/dist/esm/queries/index.js +3 -0
- package/dist/esm/queries/types.d.ts +25 -0
- package/dist/esm/queries/types.d.ts.map +1 -0
- package/dist/esm/shared.d.ts +2 -1
- package/dist/esm/shared.js +2 -1
- package/dist/esm/stores/StoreProvider.d.ts.map +1 -1
- package/dist/esm/stores/StoreProvider.js +16 -17
- package/dist/esm/stores/StoreProvider.js.map +1 -1
- package/dist/esm/stores/bookmarks/types.d.ts +3 -0
- package/dist/esm/stores/bookmarks/types.d.ts.map +1 -1
- package/dist/esm/stores/chains/ChainOrderStore.d.ts.map +1 -1
- package/dist/esm/stores/chains/ChainOrderStore.js +4 -1
- package/dist/esm/stores/chains/ChainOrderStore.js.map +1 -1
- package/dist/esm/stores/form/FormStore.js +3 -2
- package/dist/esm/stores/form/FormStore.js.map +1 -1
- package/dist/esm/stores/form/URLSearchParamsBuilder.js +7 -3
- package/dist/esm/stores/form/URLSearchParamsBuilder.js.map +1 -1
- package/dist/esm/stores/form/getDefaultValuesFromQueryString.js +4 -1
- package/dist/esm/stores/form/getDefaultValuesFromQueryString.js.map +1 -1
- package/dist/esm/stores/header/useHeaderStore.d.ts +1 -1
- package/dist/esm/stores/header/useHeaderStore.d.ts.map +1 -1
- package/dist/esm/stores/header/useHeaderStore.js.map +1 -1
- package/dist/esm/themes/createTheme.d.ts.map +1 -1
- package/dist/esm/types/events.d.ts.map +1 -1
- package/dist/esm/types/token.d.ts.map +1 -1
- package/dist/esm/types/widget.d.ts +30 -0
- package/dist/esm/types/widget.d.ts.map +1 -1
- package/dist/esm/types/widget.js.map +1 -1
- package/dist/esm/utils/chainType.js +32 -1
- package/dist/esm/utils/chainType.js.map +1 -1
- package/dist/esm/utils/customReceiver.js +6 -1
- package/dist/esm/utils/customReceiver.js.map +1 -1
- package/dist/esm/utils/queries.js.map +1 -1
- package/dist/esm/utils/scopeKeys.d.ts +6 -0
- package/dist/esm/utils/scopeKeys.d.ts.map +1 -0
- package/dist/esm/utils/scopeKeys.js +8 -0
- package/dist/esm/utils/scopeKeys.js.map +1 -0
- package/package.json +15 -7
- package/src/components/AmountInputCard/AmountInputCardPair.tsx +6 -2
- package/src/components/SelectChainAndToken.tsx +5 -1
- package/src/components/SendToWallet/SendToWalletButton.tsx +13 -8
- package/src/components/TokenList/useTokenSelect.ts +15 -0
- package/src/config/constants.ts +3 -0
- package/src/config/version.ts +1 -1
- package/src/hooks/useAccountsBalancesData.ts +6 -2
- package/src/hooks/useAddressValidation.ts +87 -32
- package/src/hooks/useAvailableChains.test.tsx +170 -0
- package/src/hooks/useAvailableChains.ts +29 -47
- package/src/hooks/useFromTokenSufficiency.ts +2 -2
- package/src/hooks/useGasRecommendation.ts +2 -2
- package/src/hooks/useGasRefuel.ts +11 -1
- package/src/hooks/useGasSufficiency.ts +2 -2
- package/src/hooks/useIsBatchingSupported.ts +2 -2
- package/src/hooks/useRouteExecution.ts +5 -5
- package/src/hooks/useRoutes.ts +28 -23
- package/src/hooks/useToAddressAutoPopulate.ts +13 -17
- package/src/hooks/useToAddressRequirements.ts +19 -4
- package/src/hooks/useToAddressReset.ts +13 -4
- package/src/hooks/useTokenBalance.ts +10 -5
- package/src/hooks/useTokenBalancesQueries.ts +3 -3
- package/src/hooks/useTokenSearch.ts +7 -3
- package/src/hooks/useTokens.ts +13 -14
- package/src/hooks/useTools.sharedEntry.test.tsx +155 -0
- package/src/hooks/useTools.ts +42 -37
- package/src/hooks/useTransactionDetails.ts +3 -3
- package/src/hooks/useTransactionHistory.ts +2 -2
- package/src/index.ts +2 -1
- package/src/pages/SendToWallet/BookmarkAddressSheet.tsx +5 -1
- package/src/pages/SendToWallet/BookmarksPage.tsx +42 -52
- package/src/pages/SendToWallet/ConnectedWalletsPage.tsx +4 -14
- package/src/pages/SendToWallet/RecentWalletsPage.tsx +59 -66
- package/src/pages/SendToWallet/SendToConfiguredWalletPage.tsx +45 -50
- package/src/pages/SendToWallet/SendToWalletPage.tsx +4 -16
- package/src/providers/WalletProvider/WalletProvider.tsx +28 -3
- package/src/providers/WidgetProvider/WidgetProvider.test.tsx +73 -0
- package/src/providers/WidgetProvider/WidgetProvider.tsx +28 -14
- package/src/providers/WidgetProvider/types.ts +2 -0
- package/src/queries/getChains.ts +93 -0
- package/src/queries/getTools.ts +62 -0
- package/src/queries/index.ts +30 -0
- package/src/queries/sharedCache.test.tsx +223 -0
- package/src/queries/types.ts +38 -0
- package/src/shared.ts +1 -0
- package/src/stores/StoreProvider.test.tsx +107 -0
- package/src/stores/StoreProvider.tsx +8 -6
- package/src/stores/bookmarks/types.ts +3 -0
- package/src/stores/chains/ChainOrderStore.tsx +4 -1
- package/src/stores/form/FormStore.tsx +2 -0
- package/src/stores/form/URLSearchParamsBuilder.tsx +4 -2
- package/src/stores/form/getDefaultValuesFromQueryString.ts +19 -0
- package/src/stores/header/useHeaderStore.tsx +3 -4
- package/src/types/widget.ts +30 -0
- package/src/utils/chainType.ts +73 -1
- package/src/utils/customReceiver.ts +36 -0
- package/src/utils/queries.ts +1 -0
- package/src/utils/scopeKeys.ts +18 -0
|
@@ -43,7 +43,7 @@ export const useRouteExecution = ({
|
|
|
43
43
|
const queryClient = useQueryClient()
|
|
44
44
|
const { account } = useAccount()
|
|
45
45
|
const resumedAfterMount = useRef(false)
|
|
46
|
-
const {
|
|
46
|
+
const { storageScopeKey } = useWidgetConfig()
|
|
47
47
|
const sdkClient = useSDKClient()
|
|
48
48
|
const emitter = useWidgetEvents()
|
|
49
49
|
const routeExecutionStoreContext = useRouteExecutionStoreContext()
|
|
@@ -84,16 +84,16 @@ export const useRouteExecution = ({
|
|
|
84
84
|
if (executionCompleted || executionFailed) {
|
|
85
85
|
const invalidateKeys = [
|
|
86
86
|
[
|
|
87
|
-
getQueryKey('token-balances',
|
|
87
|
+
getQueryKey('token-balances', storageScopeKey),
|
|
88
88
|
clonedUpdatedRoute.fromAddress,
|
|
89
89
|
clonedUpdatedRoute.fromChainId,
|
|
90
90
|
],
|
|
91
91
|
[
|
|
92
|
-
getQueryKey('token-balances',
|
|
92
|
+
getQueryKey('token-balances', storageScopeKey),
|
|
93
93
|
clonedUpdatedRoute.toAddress,
|
|
94
94
|
clonedUpdatedRoute.toChainId,
|
|
95
95
|
],
|
|
96
|
-
[getQueryKey('transaction-history',
|
|
96
|
+
[getQueryKey('transaction-history', storageScopeKey)],
|
|
97
97
|
]
|
|
98
98
|
for (const key of invalidateKeys) {
|
|
99
99
|
queryClient.invalidateQueries(
|
|
@@ -133,7 +133,7 @@ export const useRouteExecution = ({
|
|
|
133
133
|
throw new Error('Execution route not found.')
|
|
134
134
|
}
|
|
135
135
|
queryClient.removeQueries({
|
|
136
|
-
queryKey: [getQueryKey('routes',
|
|
136
|
+
queryKey: [getQueryKey('routes', storageScopeKey)],
|
|
137
137
|
exact: false,
|
|
138
138
|
})
|
|
139
139
|
return executeRoute(sdkClient, routeExecution.route, {
|
package/src/hooks/useRoutes.ts
CHANGED
|
@@ -9,10 +9,7 @@ import {
|
|
|
9
9
|
parseUnits,
|
|
10
10
|
} from '@lifi/sdk'
|
|
11
11
|
import { useAccount } from '@lifi/wallet-management'
|
|
12
|
-
import {
|
|
13
|
-
useChainTypeFromAddress,
|
|
14
|
-
useEthereumContext,
|
|
15
|
-
} from '@lifi/widget-provider'
|
|
12
|
+
import { useAddressForChain, useEthereumContext } from '@lifi/widget-provider'
|
|
16
13
|
import {
|
|
17
14
|
keepPreviousData,
|
|
18
15
|
useQuery,
|
|
@@ -29,7 +26,11 @@ import { defaultSlippage } from '../stores/settings/createSettingsStore.js'
|
|
|
29
26
|
import { useSettings } from '../stores/settings/useSettings.js'
|
|
30
27
|
import { WidgetEvent } from '../types/events.js'
|
|
31
28
|
import type { TokensByChain } from '../types/token.js'
|
|
32
|
-
import {
|
|
29
|
+
import {
|
|
30
|
+
canQuoteWithToAddress,
|
|
31
|
+
isCustomReceiverBlocked,
|
|
32
|
+
isSignerInvalidReceiver,
|
|
33
|
+
} from '../utils/customReceiver.js'
|
|
33
34
|
import { getQueryKey } from '../utils/queries.js'
|
|
34
35
|
import { updateTokenInCache } from '../utils/token.js'
|
|
35
36
|
import { useChain } from './useChain.js'
|
|
@@ -82,7 +83,7 @@ export const useRoutes = ({
|
|
|
82
83
|
exchanges,
|
|
83
84
|
feeConfig,
|
|
84
85
|
useRelayerRoutes,
|
|
85
|
-
|
|
86
|
+
storageScopeKey,
|
|
86
87
|
} = useWidgetConfig()
|
|
87
88
|
const sdkClient = useSDKClient()
|
|
88
89
|
const setExecutableRoute = useSetExecutableRoute()
|
|
@@ -138,7 +139,7 @@ export const useRoutes = ({
|
|
|
138
139
|
const { chain: toChain } = useChain(toChainId)
|
|
139
140
|
const { enabled: enabledRefuel, fromAmount: gasRecommendationFromAmount } =
|
|
140
141
|
useGasRefuel()
|
|
141
|
-
const {
|
|
142
|
+
const { isAddressForChain } = useAddressForChain()
|
|
142
143
|
const { isGaslessStep, disableMessageSigning } = useEthereumContext()
|
|
143
144
|
const { account } = useAccount({ chainType: fromChain?.chainType })
|
|
144
145
|
const { isBatchingSupported, isBatchingSupportedLoading } =
|
|
@@ -165,18 +166,22 @@ export const useRoutes = ({
|
|
|
165
166
|
? Boolean(account.address)
|
|
166
167
|
: mode !== 'custom' || customType === 'deposit'
|
|
167
168
|
|
|
168
|
-
|
|
169
|
+
// Quote as if disconnected while the signer would be taken as the receiver.
|
|
170
|
+
const effectiveFromAddress = isSignerInvalidReceiver({
|
|
171
|
+
signerAddress: account.address,
|
|
172
|
+
toAddress,
|
|
173
|
+
fromChain,
|
|
174
|
+
toChain,
|
|
175
|
+
isAddressForChain,
|
|
176
|
+
})
|
|
177
|
+
? quoteFromAddress
|
|
178
|
+
: (account.address ?? quoteFromAddress)
|
|
169
179
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
getChainTypeFromAddress(toAddress) === toChain.chainType
|
|
176
|
-
// We need to check for toAddress only if it is set
|
|
177
|
-
const isToAddressSatisfied = toAddress
|
|
178
|
-
? hasToAddressAndChainTypeSatisfied
|
|
179
|
-
: true
|
|
180
|
+
const isToAddressSatisfied = canQuoteWithToAddress(
|
|
181
|
+
toAddress,
|
|
182
|
+
toChain,
|
|
183
|
+
isAddressForChain
|
|
184
|
+
)
|
|
180
185
|
|
|
181
186
|
// Not `effectiveFromAddress`: a quote placeholder must never match a receiver.
|
|
182
187
|
const customReceiverBlocked = isCustomReceiverBlocked({
|
|
@@ -214,7 +219,7 @@ export const useRoutes = ({
|
|
|
214
219
|
const queryKey = useMemo(
|
|
215
220
|
() =>
|
|
216
221
|
[
|
|
217
|
-
getQueryKey('routes',
|
|
222
|
+
getQueryKey('routes', storageScopeKey),
|
|
218
223
|
effectiveFromAddress,
|
|
219
224
|
fromChain?.id as number,
|
|
220
225
|
fromToken?.address as string,
|
|
@@ -244,7 +249,7 @@ export const useRoutes = ({
|
|
|
244
249
|
observableRoute?.id,
|
|
245
250
|
] as const,
|
|
246
251
|
[
|
|
247
|
-
|
|
252
|
+
storageScopeKey,
|
|
248
253
|
effectiveFromAddress,
|
|
249
254
|
fromChain?.id,
|
|
250
255
|
fromToken?.address,
|
|
@@ -550,14 +555,14 @@ export const useRoutes = ({
|
|
|
550
555
|
;[fromToken, toToken].forEach((token) => {
|
|
551
556
|
// Update main tokens cache (verified)
|
|
552
557
|
queryClient.setQueriesData<TokensByChain>(
|
|
553
|
-
{ queryKey: [getQueryKey('tokens',
|
|
558
|
+
{ queryKey: [getQueryKey('tokens', storageScopeKey)] },
|
|
554
559
|
(data) => updateTokenInCache(data, token)
|
|
555
560
|
)
|
|
556
561
|
|
|
557
562
|
// Update search tokens cache (unverified) - matches any search query
|
|
558
563
|
queryClient.setQueriesData<TokensByChain>(
|
|
559
564
|
{
|
|
560
|
-
queryKey: [getQueryKey('tokens-search',
|
|
565
|
+
queryKey: [getQueryKey('tokens-search', storageScopeKey)],
|
|
561
566
|
exact: false,
|
|
562
567
|
},
|
|
563
568
|
(data) => updateTokenInCache(data, token)
|
|
@@ -566,7 +571,7 @@ export const useRoutes = ({
|
|
|
566
571
|
queryClient.setQueriesData<Token[]>(
|
|
567
572
|
{
|
|
568
573
|
queryKey: [
|
|
569
|
-
getQueryKey('token-balances',
|
|
574
|
+
getQueryKey('token-balances', storageScopeKey),
|
|
570
575
|
fromAddress,
|
|
571
576
|
token.chainId,
|
|
572
577
|
],
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useAccount } from '@lifi/wallet-management'
|
|
2
|
-
import {
|
|
2
|
+
import { useAddressForChain } from '@lifi/widget-provider'
|
|
3
3
|
import { useCallback } from 'react'
|
|
4
4
|
import { useBookmarkActions } from '../stores/bookmarks/useBookmarkActions.js'
|
|
5
5
|
import type { FormType } from '../stores/form/types.js'
|
|
@@ -24,7 +24,7 @@ export const useToAddressAutoPopulate = (): ((
|
|
|
24
24
|
const { setSelectedBookmark } = useBookmarkActions()
|
|
25
25
|
const { getChainById } = useAvailableChains()
|
|
26
26
|
const { accounts } = useAccount()
|
|
27
|
-
const {
|
|
27
|
+
const { isAddressForChain } = useAddressForChain()
|
|
28
28
|
|
|
29
29
|
return useCallback(
|
|
30
30
|
({
|
|
@@ -52,22 +52,18 @@ export const useToAddressAutoPopulate = (): ((
|
|
|
52
52
|
) {
|
|
53
53
|
return
|
|
54
54
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
const selectedToAddressChainType =
|
|
63
|
-
getChainTypeFromAddress(selectedToAddress)
|
|
64
|
-
if (destinationChainType === selectedToAddressChainType) {
|
|
65
|
-
return
|
|
66
|
-
}
|
|
55
|
+
const destinationChain =
|
|
56
|
+
formType === 'from' ? selectedOppositeChain : selectedChain
|
|
57
|
+
if (
|
|
58
|
+
selectedToAddress &&
|
|
59
|
+
isAddressForChain(selectedToAddress, destinationChain)
|
|
60
|
+
) {
|
|
61
|
+
return
|
|
67
62
|
}
|
|
68
|
-
// Find connected account compatible with the destination chain type
|
|
69
63
|
const destinationAccount = accounts?.find(
|
|
70
|
-
(account) =>
|
|
64
|
+
(account) =>
|
|
65
|
+
account.address &&
|
|
66
|
+
isAddressForChain(account.address, destinationChain)
|
|
71
67
|
)
|
|
72
68
|
// If a compatible destination account is found, set toAddress as if selecting it from the "Send to Wallet" connected wallets page
|
|
73
69
|
if (destinationAccount?.address) {
|
|
@@ -89,7 +85,7 @@ export const useToAddressAutoPopulate = (): ((
|
|
|
89
85
|
getChainById,
|
|
90
86
|
setFieldValue,
|
|
91
87
|
setSelectedBookmark,
|
|
92
|
-
|
|
88
|
+
isAddressForChain,
|
|
93
89
|
]
|
|
94
90
|
)
|
|
95
91
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { RouteExtended } from '@lifi/sdk'
|
|
2
2
|
import { useAccount } from '@lifi/wallet-management'
|
|
3
|
-
import { useEthereumContext } from '@lifi/widget-provider'
|
|
3
|
+
import { useAddressForChain, useEthereumContext } from '@lifi/widget-provider'
|
|
4
4
|
import { useChain } from '../hooks/useChain.js'
|
|
5
5
|
import { useWidgetConfig } from '../providers/WidgetProvider/WidgetProvider.js'
|
|
6
6
|
import { useFieldValues } from '../stores/form/useFieldValues.js'
|
|
@@ -16,7 +16,8 @@ export const useToAddressRequirements = (
|
|
|
16
16
|
requiredToAddress: boolean
|
|
17
17
|
unsupportedToAddress: boolean
|
|
18
18
|
unsupportedReceiverBlocking: boolean
|
|
19
|
-
|
|
19
|
+
/** Whether a saved or connected address can receive on the destination chain. */
|
|
20
|
+
isValidReceiver: (address?: string) => boolean
|
|
20
21
|
accountNotDeployedAtDestination: boolean
|
|
21
22
|
accountDeployedAtDestination: boolean
|
|
22
23
|
toAddress: string | undefined
|
|
@@ -32,6 +33,7 @@ export const useToAddressRequirements = (
|
|
|
32
33
|
'toAddress'
|
|
33
34
|
)
|
|
34
35
|
const { isDelegationDesignatorCode } = useEthereumContext()
|
|
36
|
+
const { isAddressForChain } = useAddressForChain()
|
|
35
37
|
|
|
36
38
|
const fromChainId = route?.fromChainId ?? formFromChainId
|
|
37
39
|
const toChainId = route?.toChainId ?? formToChainId
|
|
@@ -87,14 +89,27 @@ export const useToAddressRequirements = (
|
|
|
87
89
|
receiverRequired: requiredUI?.toAddress,
|
|
88
90
|
})
|
|
89
91
|
|
|
92
|
+
// A shared chain type is not a shared format: a Bitcoin signer cannot receive on ZEC.
|
|
93
|
+
const isSignerAddressInvalidAtDestination = Boolean(
|
|
94
|
+
fromAddress &&
|
|
95
|
+
fromChain &&
|
|
96
|
+
toChain &&
|
|
97
|
+
isAddressForChain(fromAddress, fromChain) &&
|
|
98
|
+
!isAddressForChain(fromAddress, toChain)
|
|
99
|
+
)
|
|
100
|
+
|
|
90
101
|
const requiredToAddress = Boolean(
|
|
91
102
|
(isDifferentChainType ||
|
|
92
103
|
isCrossChainContractAddress ||
|
|
104
|
+
isSignerAddressInvalidAtDestination ||
|
|
93
105
|
requiredUI?.toAddress) &&
|
|
94
106
|
!hiddenUI?.toAddress &&
|
|
95
107
|
!unsupportedToAddress
|
|
96
108
|
)
|
|
97
109
|
|
|
110
|
+
const isValidReceiver = (address?: string): boolean =>
|
|
111
|
+
!toChain || (!!address && isAddressForChain(address, toChain))
|
|
112
|
+
|
|
98
113
|
const accountNotDeployedAtDestination = Boolean(
|
|
99
114
|
isFromContractAddress &&
|
|
100
115
|
!fromContractCodeHasDelegationIndicator &&
|
|
@@ -113,7 +128,7 @@ export const useToAddressRequirements = (
|
|
|
113
128
|
requiredToAddress,
|
|
114
129
|
unsupportedToAddress,
|
|
115
130
|
unsupportedReceiverBlocking,
|
|
116
|
-
|
|
131
|
+
isValidReceiver,
|
|
117
132
|
accountNotDeployedAtDestination,
|
|
118
133
|
accountDeployedAtDestination,
|
|
119
134
|
toAddress,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ExtendedChain } from '@lifi/sdk'
|
|
2
|
+
import { useAddressForChain } from '@lifi/widget-provider'
|
|
2
3
|
import { useCallback } from 'react'
|
|
3
4
|
import { useWidgetConfig } from '../providers/WidgetProvider/WidgetProvider.js'
|
|
4
5
|
import { useBookmarkActions } from '../stores/bookmarks/useBookmarkActions.js'
|
|
@@ -12,16 +13,18 @@ export const useToAddressReset = (): {
|
|
|
12
13
|
const { setFieldValue } = useFieldActions()
|
|
13
14
|
const { selectedBookmark } = useBookmarks()
|
|
14
15
|
const { setSelectedBookmark } = useBookmarkActions()
|
|
16
|
+
const { isAddressForChain } = useAddressForChain()
|
|
15
17
|
|
|
16
18
|
const tryResetToAddress = useCallback(
|
|
17
19
|
(toChain: ExtendedChain) => {
|
|
18
20
|
const requiredToAddress = requiredUI?.toAddress
|
|
19
21
|
|
|
20
|
-
const
|
|
21
|
-
selectedBookmark
|
|
22
|
+
const bookmarkSatisfiesToChain = Boolean(
|
|
23
|
+
selectedBookmark && isAddressForChain(selectedBookmark.address, toChain)
|
|
24
|
+
)
|
|
22
25
|
|
|
23
26
|
const shouldResetToAddress =
|
|
24
|
-
!requiredToAddress && !
|
|
27
|
+
!requiredToAddress && !bookmarkSatisfiesToChain
|
|
25
28
|
|
|
26
29
|
// We reset toAddress on each chain change if it's no longer required, ensuring that
|
|
27
30
|
// switching chain types doesn't leave a stale toAddress from a different ecosystem.
|
|
@@ -30,7 +33,13 @@ export const useToAddressReset = (): {
|
|
|
30
33
|
setSelectedBookmark()
|
|
31
34
|
}
|
|
32
35
|
},
|
|
33
|
-
[
|
|
36
|
+
[
|
|
37
|
+
setFieldValue,
|
|
38
|
+
setSelectedBookmark,
|
|
39
|
+
requiredUI,
|
|
40
|
+
selectedBookmark,
|
|
41
|
+
isAddressForChain,
|
|
42
|
+
]
|
|
34
43
|
)
|
|
35
44
|
|
|
36
45
|
return {
|
|
@@ -8,6 +8,7 @@ import { useQuery, useQueryClient } from '@tanstack/react-query'
|
|
|
8
8
|
import { useCallback, useMemo } from 'react'
|
|
9
9
|
import { useSDKClient } from '../providers/SDKClientProvider.js'
|
|
10
10
|
import { useWidgetConfig } from '../providers/WidgetProvider/WidgetProvider.js'
|
|
11
|
+
import { isDestinationOnlyChain } from '../utils/chainType.js'
|
|
11
12
|
import { getQueryKey } from '../utils/queries.js'
|
|
12
13
|
|
|
13
14
|
const defaultRefetchInterval = 30_000
|
|
@@ -23,18 +24,18 @@ export const useTokenBalance = (
|
|
|
23
24
|
getTokenBalancesWithRetry: typeof getTokenBalancesWithRetry
|
|
24
25
|
} => {
|
|
25
26
|
const queryClient = useQueryClient()
|
|
26
|
-
const {
|
|
27
|
+
const { storageScopeKey } = useWidgetConfig()
|
|
27
28
|
const sdkClient = useSDKClient()
|
|
28
29
|
|
|
29
30
|
const tokenBalanceQueryKey = useMemo(
|
|
30
31
|
() =>
|
|
31
32
|
[
|
|
32
|
-
getQueryKey('token-balance',
|
|
33
|
+
getQueryKey('token-balance', storageScopeKey),
|
|
33
34
|
accountAddress,
|
|
34
35
|
token?.chainId,
|
|
35
36
|
token?.address,
|
|
36
37
|
] as const,
|
|
37
|
-
[token?.address, token?.chainId, accountAddress,
|
|
38
|
+
[token?.address, token?.chainId, accountAddress, storageScopeKey]
|
|
38
39
|
)
|
|
39
40
|
|
|
40
41
|
const { data, isLoading, refetch } = useQuery({
|
|
@@ -67,7 +68,7 @@ export const useTokenBalance = (
|
|
|
67
68
|
queryClient.setQueriesData<TokenAmount[]>(
|
|
68
69
|
{
|
|
69
70
|
queryKey: [
|
|
70
|
-
getQueryKey('token-balances',
|
|
71
|
+
getQueryKey('token-balances', storageScopeKey),
|
|
71
72
|
accountAddress,
|
|
72
73
|
tokenChainId,
|
|
73
74
|
],
|
|
@@ -93,7 +94,11 @@ export const useTokenBalance = (
|
|
|
93
94
|
} as TokenAmount
|
|
94
95
|
},
|
|
95
96
|
|
|
96
|
-
|
|
97
|
+
// No provider reads a balance on a destination-only chain, and a balance
|
|
98
|
+
// without a block number is retried until the backoff gives up.
|
|
99
|
+
enabled:
|
|
100
|
+
Boolean(accountAddress && token) &&
|
|
101
|
+
!isDestinationOnlyChain(token?.chainId),
|
|
97
102
|
refetchInterval: defaultRefetchInterval,
|
|
98
103
|
staleTime: defaultRefetchInterval,
|
|
99
104
|
})
|
|
@@ -20,7 +20,7 @@ export const useTokenBalancesQueries = (
|
|
|
20
20
|
isLoading: boolean
|
|
21
21
|
isError: boolean
|
|
22
22
|
} => {
|
|
23
|
-
const {
|
|
23
|
+
const { storageScopeKey } = useWidgetConfig()
|
|
24
24
|
const sdkClient = useSDKClient()
|
|
25
25
|
const firstLoadStartRef = useRef<number | null>(null)
|
|
26
26
|
|
|
@@ -34,7 +34,7 @@ export const useTokenBalancesQueries = (
|
|
|
34
34
|
const chainId = Number(chainIdStr)
|
|
35
35
|
return {
|
|
36
36
|
queryKey: [
|
|
37
|
-
getQueryKey('token-balances',
|
|
37
|
+
getQueryKey('token-balances', storageScopeKey),
|
|
38
38
|
accountAddress,
|
|
39
39
|
chainId,
|
|
40
40
|
tokens.length,
|
|
@@ -55,7 +55,7 @@ export const useTokenBalancesQueries = (
|
|
|
55
55
|
}
|
|
56
56
|
})
|
|
57
57
|
)
|
|
58
|
-
}, [accountsWithTokens, isBalanceLoadingEnabled,
|
|
58
|
+
}, [accountsWithTokens, isBalanceLoadingEnabled, storageScopeKey, sdkClient])
|
|
59
59
|
|
|
60
60
|
const result = useQueries({
|
|
61
61
|
queries: queryConfig,
|
|
@@ -18,11 +18,15 @@ export const useTokenSearch = (
|
|
|
18
18
|
isLoading: boolean
|
|
19
19
|
} => {
|
|
20
20
|
const queryClient = useQueryClient()
|
|
21
|
-
const { tokens: configTokens,
|
|
21
|
+
const { tokens: configTokens, storageScopeKey } = useWidgetConfig()
|
|
22
22
|
const sdkClient = useSDKClient()
|
|
23
23
|
|
|
24
24
|
const { data, isLoading } = useQuery({
|
|
25
|
-
queryKey: [
|
|
25
|
+
queryKey: [
|
|
26
|
+
getQueryKey('token-search', storageScopeKey),
|
|
27
|
+
chainId,
|
|
28
|
+
tokenQuery,
|
|
29
|
+
],
|
|
26
30
|
queryFn: async ({ queryKey: [, chainId, tokenQuery], signal }) => {
|
|
27
31
|
const token = await getToken(
|
|
28
32
|
sdkClient,
|
|
@@ -52,7 +56,7 @@ export const useTokenSearch = (
|
|
|
52
56
|
|
|
53
57
|
// Add token to main tokens cache
|
|
54
58
|
queryClient.setQueriesData<TokensByChain>(
|
|
55
|
-
{ queryKey: [getQueryKey('tokens',
|
|
59
|
+
{ queryKey: [getQueryKey('tokens', storageScopeKey)] },
|
|
56
60
|
(data) => {
|
|
57
61
|
if (!data) {
|
|
58
62
|
return data
|
package/src/hooks/useTokens.ts
CHANGED
|
@@ -25,6 +25,14 @@ import { useAvailableChains } from './useAvailableChains.js'
|
|
|
25
25
|
|
|
26
26
|
const refetchInterval = 300_000
|
|
27
27
|
|
|
28
|
+
// The main list and the search send the same list parameters.
|
|
29
|
+
const tokenListParams = {
|
|
30
|
+
orderBy: 'volumeUSD24H',
|
|
31
|
+
extended: true,
|
|
32
|
+
limit: 1100,
|
|
33
|
+
minPriceUSD: 0.000001,
|
|
34
|
+
} as const
|
|
35
|
+
|
|
28
36
|
export const useTokens = (
|
|
29
37
|
formType?: FormType,
|
|
30
38
|
search?: string,
|
|
@@ -39,7 +47,7 @@ export const useTokens = (
|
|
|
39
47
|
const {
|
|
40
48
|
tokens: configTokens,
|
|
41
49
|
chains: chainsConfig,
|
|
42
|
-
|
|
50
|
+
storageScopeKey,
|
|
43
51
|
} = useWidgetConfig()
|
|
44
52
|
const sdkClient = useSDKClient()
|
|
45
53
|
const { getChainTypeFromTokenAddress } = useChainTypeFromAddress()
|
|
@@ -55,7 +63,7 @@ export const useTokens = (
|
|
|
55
63
|
|
|
56
64
|
// Main tokens cache - verified tokens from API
|
|
57
65
|
const { data: verifiedTokens, isLoading } = useQuery({
|
|
58
|
-
queryKey: [getQueryKey('tokens',
|
|
66
|
+
queryKey: [getQueryKey('tokens', storageScopeKey)],
|
|
59
67
|
queryFn: async ({ signal }) => {
|
|
60
68
|
const chainTypes = [
|
|
61
69
|
ChainType.EVM,
|
|
@@ -68,13 +76,7 @@ export const useTokens = (
|
|
|
68
76
|
|
|
69
77
|
const tokensResponse: TokensExtendedResponse = await getTokens(
|
|
70
78
|
sdkClient,
|
|
71
|
-
{
|
|
72
|
-
chainTypes,
|
|
73
|
-
orderBy: 'volumeUSD24H',
|
|
74
|
-
extended: true,
|
|
75
|
-
limit: 1000,
|
|
76
|
-
minPriceUSD: 0.000001,
|
|
77
|
-
},
|
|
79
|
+
{ ...tokenListParams, chainTypes },
|
|
78
80
|
{ signal }
|
|
79
81
|
)
|
|
80
82
|
|
|
@@ -95,7 +97,7 @@ export const useTokens = (
|
|
|
95
97
|
// Search tokens cache - unverified tokens from search
|
|
96
98
|
const { data: searchTokens, isLoading: isSearchLoading } = useQuery({
|
|
97
99
|
queryKey: [
|
|
98
|
-
getQueryKey('tokens-search',
|
|
100
|
+
getQueryKey('tokens-search', storageScopeKey),
|
|
99
101
|
trimmedSearch,
|
|
100
102
|
chainId,
|
|
101
103
|
isAddressSearch,
|
|
@@ -114,12 +116,9 @@ export const useTokens = (
|
|
|
114
116
|
const tokensResponse: TokensExtendedResponse = await getTokens(
|
|
115
117
|
sdkClient,
|
|
116
118
|
{
|
|
119
|
+
...tokenListParams,
|
|
117
120
|
chainTypes,
|
|
118
|
-
orderBy: 'volumeUSD24H',
|
|
119
|
-
extended: true,
|
|
120
121
|
search: searchQuery,
|
|
121
|
-
limit: 1000,
|
|
122
|
-
minPriceUSD: 0.000001,
|
|
123
122
|
},
|
|
124
123
|
{ signal }
|
|
125
124
|
)
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/** @vitest-environment happy-dom */
|
|
2
|
+
|
|
3
|
+
import type * as LifiSdk from '@lifi/sdk'
|
|
4
|
+
import type { SDKClient, ToolsResponse } from '@lifi/sdk'
|
|
5
|
+
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
|
6
|
+
import { act } from 'react'
|
|
7
|
+
import { createRoot, type Root } from 'react-dom/client'
|
|
8
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
9
|
+
import type { WidgetConfig } from '../types/widget.js'
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* The tools entry is shared with the host app through
|
|
13
|
+
* `getToolsQueryOptions`, keyed by the client's API base and the widget's
|
|
14
|
+
* `queryScopeKey`. When the host fetched first, the widget must read that entry
|
|
15
|
+
* — no request of its own — and still seed its settings store from the
|
|
16
|
+
* filtered view.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
const API_URL = 'https://api.example/v1'
|
|
20
|
+
|
|
21
|
+
const mocks = vi.hoisted(() => ({
|
|
22
|
+
getTools: vi.fn(),
|
|
23
|
+
initializeTools: vi.fn(),
|
|
24
|
+
}))
|
|
25
|
+
|
|
26
|
+
vi.mock('@lifi/sdk', async (importOriginal) => ({
|
|
27
|
+
...(await importOriginal<typeof LifiSdk>()),
|
|
28
|
+
getTools: mocks.getTools,
|
|
29
|
+
}))
|
|
30
|
+
|
|
31
|
+
let widgetConfig: Partial<WidgetConfig> = {}
|
|
32
|
+
|
|
33
|
+
vi.mock('../providers/WidgetProvider/WidgetProvider.js', () => ({
|
|
34
|
+
useWidgetConfig: () => widgetConfig,
|
|
35
|
+
}))
|
|
36
|
+
|
|
37
|
+
const client = { config: { apiUrl: API_URL } } as unknown as SDKClient
|
|
38
|
+
vi.mock('../providers/SDKClientProvider.js', () => ({
|
|
39
|
+
useSDKClient: () => client,
|
|
40
|
+
}))
|
|
41
|
+
|
|
42
|
+
const settingsStore = {
|
|
43
|
+
getState: () => ({ initializeTools: mocks.initializeTools }),
|
|
44
|
+
}
|
|
45
|
+
vi.mock('../stores/settings/SettingsStore.js', () => ({
|
|
46
|
+
useSettingsStoreContext: () => settingsStore,
|
|
47
|
+
}))
|
|
48
|
+
|
|
49
|
+
import { getToolsQueryKey } from '../queries/getTools.js'
|
|
50
|
+
import { useTools } from './useTools.js'
|
|
51
|
+
|
|
52
|
+
const TOOLS = {
|
|
53
|
+
bridges: [{ key: 'across' }, { key: 'stargate' }, { key: 'hop' }],
|
|
54
|
+
exchanges: [{ key: '1inch' }, { key: 'paraswap' }],
|
|
55
|
+
} as unknown as ToolsResponse
|
|
56
|
+
|
|
57
|
+
const Probe = () => {
|
|
58
|
+
useTools()
|
|
59
|
+
return null
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
let root: Root
|
|
63
|
+
let queryClient: QueryClient
|
|
64
|
+
|
|
65
|
+
const render = async () => {
|
|
66
|
+
await act(async () => {
|
|
67
|
+
root.render(
|
|
68
|
+
<QueryClientProvider client={queryClient}>
|
|
69
|
+
<Probe />
|
|
70
|
+
</QueryClientProvider>
|
|
71
|
+
)
|
|
72
|
+
})
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
describe('useTools with a shared tools entry', () => {
|
|
76
|
+
beforeEach(() => {
|
|
77
|
+
vi.clearAllMocks()
|
|
78
|
+
mocks.getTools.mockResolvedValue(TOOLS)
|
|
79
|
+
widgetConfig = {
|
|
80
|
+
integrator: 'test',
|
|
81
|
+
queryScopeKey: 'host',
|
|
82
|
+
bridges: { allow: ['across', 'hop'] },
|
|
83
|
+
exchanges: { deny: ['paraswap'] },
|
|
84
|
+
}
|
|
85
|
+
queryClient = new QueryClient({
|
|
86
|
+
defaultOptions: { queries: { retry: false } },
|
|
87
|
+
})
|
|
88
|
+
const container = document.createElement('div')
|
|
89
|
+
document.body.appendChild(container)
|
|
90
|
+
root = createRoot(container)
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
afterEach(async () => {
|
|
94
|
+
await act(async () => root.unmount())
|
|
95
|
+
queryClient.clear()
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
it('initialises the settings store when the host already fetched the tools', async () => {
|
|
99
|
+
// The host app fetched first and filled the shared entry.
|
|
100
|
+
queryClient.setQueryData(
|
|
101
|
+
getToolsQueryKey({ apiUrl: API_URL, scopeKey: 'host' }),
|
|
102
|
+
TOOLS
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
await render()
|
|
106
|
+
|
|
107
|
+
await vi.waitFor(() => {
|
|
108
|
+
expect(mocks.initializeTools).toHaveBeenCalledWith('Bridges', [
|
|
109
|
+
'across',
|
|
110
|
+
'hop',
|
|
111
|
+
])
|
|
112
|
+
})
|
|
113
|
+
expect(mocks.initializeTools).toHaveBeenCalledWith('Exchanges', ['1inch'])
|
|
114
|
+
// The widget read the host's entry instead of sending its own request.
|
|
115
|
+
expect(mocks.getTools).not.toHaveBeenCalled()
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
it('initialises the settings store when the widget fetched the tools itself', async () => {
|
|
119
|
+
await render()
|
|
120
|
+
|
|
121
|
+
await vi.waitFor(() => {
|
|
122
|
+
expect(mocks.initializeTools).toHaveBeenCalledWith('Bridges', [
|
|
123
|
+
'across',
|
|
124
|
+
'hop',
|
|
125
|
+
])
|
|
126
|
+
})
|
|
127
|
+
expect(mocks.getTools).toHaveBeenCalledTimes(1)
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
it('initialises with the filtered view while the cache keeps the raw list', async () => {
|
|
131
|
+
await render()
|
|
132
|
+
|
|
133
|
+
await vi.waitFor(() => {
|
|
134
|
+
expect(mocks.initializeTools).toHaveBeenCalled()
|
|
135
|
+
})
|
|
136
|
+
const cached = queryClient.getQueryData<ToolsResponse>(
|
|
137
|
+
getToolsQueryKey({ apiUrl: API_URL, scopeKey: 'host' })
|
|
138
|
+
)
|
|
139
|
+
expect(cached?.bridges).toHaveLength(3)
|
|
140
|
+
expect(cached?.exchanges).toHaveLength(2)
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
it('refreshes the tools every three minutes', async () => {
|
|
144
|
+
await render()
|
|
145
|
+
await vi.waitFor(() => {
|
|
146
|
+
expect(mocks.initializeTools).toHaveBeenCalled()
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
const [observer] = queryClient.getQueryCache().find({
|
|
150
|
+
queryKey: getToolsQueryKey({ apiUrl: API_URL, scopeKey: 'host' }),
|
|
151
|
+
})!.observers
|
|
152
|
+
expect(observer.options.refetchInterval).toBe(180_000)
|
|
153
|
+
expect(observer.options.staleTime).toBe(180_000)
|
|
154
|
+
})
|
|
155
|
+
})
|