@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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useRoutes.js","names":[],"sources":["../../../src/hooks/useRoutes.ts"],"sourcesContent":["import type { ExtendedChain, Route, Token } from '@lifi/sdk'\nimport {\n ChainType,\n convertQuoteToRoute,\n getContractCallsQuote,\n getRelayerQuote,\n getRoutes,\n LiFiErrorCode,\n parseUnits,\n} from '@lifi/sdk'\nimport { useAccount } from '@lifi/wallet-management'\nimport {\n useChainTypeFromAddress,\n useEthereumContext,\n} from '@lifi/widget-provider'\nimport {\n keepPreviousData,\n useQuery,\n useQueryClient,\n} from '@tanstack/react-query'\nimport { useCallback, useMemo } from 'react'\nimport { useSDKClient } from '../providers/SDKClientProvider.js'\nimport { useWidgetConfig } from '../providers/WidgetProvider/WidgetProvider.js'\nimport { useFieldValues } from '../stores/form/useFieldValues.js'\nimport { useNavigationTabsStore } from '../stores/navigationTabs/useNavigationTabsStore.js'\nimport { useIntermediateRoutesStore } from '../stores/routes/useIntermediateRoutesStore.js'\nimport { useSetExecutableRoute } from '../stores/routes/useSetExecutableRoute.js'\nimport { defaultSlippage } from '../stores/settings/createSettingsStore.js'\nimport { useSettings } from '../stores/settings/useSettings.js'\nimport { WidgetEvent } from '../types/events.js'\nimport type { TokensByChain } from '../types/token.js'\nimport { isCustomReceiverBlocked } from '../utils/customReceiver.js'\nimport { getQueryKey } from '../utils/queries.js'\nimport { updateTokenInCache } from '../utils/token.js'\nimport { useChain } from './useChain.js'\nimport { useDebouncedWatch } from './useDebouncedWatch.js'\nimport { useGasRefuel } from './useGasRefuel.js'\nimport { useIsBatchingSupported } from './useIsBatchingSupported.js'\nimport { useSwapOnly } from './useSwapOnly.js'\nimport { useToken } from './useToken.js'\nimport { useWidgetEvents } from './useWidgetEvents.js'\n\nconst refetchTime = 60_000\n\ninterface RoutesProps {\n observableRoute?: Route\n /**\n * Address to quote from when no wallet is connected. Treated as a non-signing\n * placeholder, so signer-dependent (relayer/permit2) quotes are skipped.\n */\n quoteFromAddress?: string\n /**\n * Keep showing the previous result while a new query (e.g. a token/amount\n * change) is fetching, instead of clearing to a loading state.\n */\n keepPreviousData?: boolean\n}\n\nexport const useRoutes = ({\n observableRoute,\n quoteFromAddress,\n keepPreviousData: keepPreviousDataEnabled,\n}: RoutesProps = {}): {\n routes: Route[] | undefined\n isLoading: boolean\n isFetching: boolean\n isFetched: boolean\n isError: boolean\n dataUpdatedAt: number\n refetchTime: number\n refetch: () => void\n fromChain: ExtendedChain | undefined\n toChain: ExtendedChain | undefined\n queryKey: readonly unknown[]\n setReviewableRoute: (route: Route) => void\n} => {\n const {\n mode,\n modeOptions,\n contractTool,\n bridges,\n exchanges,\n feeConfig,\n useRelayerRoutes,\n keyPrefix,\n } = useWidgetConfig()\n const sdkClient = useSDKClient()\n const setExecutableRoute = useSetExecutableRoute()\n const queryClient = useQueryClient()\n const emitter = useWidgetEvents()\n const swapOnly = useSwapOnly()\n const isPrivate = useNavigationTabsStore(\n (state) => state.activeTab === 'private'\n )\n\n const {\n disabledBridges,\n disabledExchanges,\n enabledBridges,\n enabledExchanges,\n enabledAutoRefuel,\n routePriority,\n slippage,\n } = useSettings([\n 'disabledBridges',\n 'disabledExchanges',\n 'enabledBridges',\n 'enabledExchanges',\n 'enabledAutoRefuel',\n 'routePriority',\n 'slippage',\n ])\n const [fromTokenAmount] = useDebouncedWatch(500, 'fromAmount')\n // Debounce toAmount like fromAmount to avoid a request per keystroke\n const [toTokenAmount] = useDebouncedWatch(500, 'toAmount')\n const [\n fromChainId,\n fromTokenAddress,\n toAddress,\n toChainId,\n toTokenAddress,\n contractCalls,\n ] = useFieldValues(\n 'fromChain',\n 'fromToken',\n 'toAddress',\n 'toChain',\n 'toToken',\n 'contractCalls'\n )\n const [validUntilDuration, partiallyFillable] = useFieldValues(\n 'validUntil',\n 'partiallyFillable'\n )\n const { token: fromToken } = useToken(fromChainId, fromTokenAddress)\n const { token: toToken } = useToken(toChainId, toTokenAddress)\n const { chain: fromChain } = useChain(fromChainId)\n const { chain: toChain } = useChain(toChainId)\n const { enabled: enabledRefuel, fromAmount: gasRecommendationFromAmount } =\n useGasRefuel()\n const { getChainTypeFromAddress } = useChainTypeFromAddress()\n const { isGaslessStep, disableMessageSigning } = useEthereumContext()\n const { account } = useAccount({ chainType: fromChain?.chainType })\n const { isBatchingSupported, isBatchingSupportedLoading } =\n useIsBatchingSupported(fromChain, account.address)\n\n // In limit mode toAmount is the user's limit target, derived from the sell\n // amount and limit price. It's keyed and sent to the backend so changing the\n // limit fetches a fresh quote. The receive card is read-only (it displays the\n // quote and never writes toAmount back), so keying on it can't loop. Both a\n // sell amount and a limit price (→ toAmount) are required before fetching.\n const hasAmount =\n mode === 'limit'\n ? Number(fromTokenAmount) > 0 && Number(toTokenAmount) > 0\n : Number(fromTokenAmount) > 0 || Number(toTokenAmount) > 0\n\n const customType = mode === 'custom' ? modeOptions?.custom?.type : undefined\n const isContractCallQuote =\n mode === 'custom' && Boolean(contractCalls?.length)\n // A contract-call quote needs a connected wallet to resolve fromAddress.\n // Deposit funding quotes a plain route with no contract calls and no wallet\n // (a placeholder fromAddress arrives via quoteFromAddress); every other custom\n // flow stays gated on a real wallet, as before.\n const contractCallQuoteEnabled: boolean = isContractCallQuote\n ? Boolean(account.address)\n : mode !== 'custom' || customType === 'deposit'\n\n const effectiveFromAddress = account.address ?? quoteFromAddress\n\n // When we bridge between ecosystems we need to be sure toAddress is set and has the same chainType as toChain\n // If toAddress is set, it must have the same chainType as toChain\n const hasToAddressAndChainTypeSatisfied: boolean =\n !!toChain &&\n !!toAddress &&\n getChainTypeFromAddress(toAddress) === toChain.chainType\n // We need to check for toAddress only if it is set\n const isToAddressSatisfied = toAddress\n ? hasToAddressAndChainTypeSatisfied\n : true\n\n // Not `effectiveFromAddress`: a quote placeholder must never match a receiver.\n const customReceiverBlocked = isCustomReceiverBlocked({\n fromChainType: fromChain?.chainType,\n toChainType: toChain?.chainType,\n toAddress,\n signerAddress: account.address,\n })\n\n // toAddress might be an empty string, but we need to pass undefined if there is no value\n const toWalletAddress = toAddress || undefined\n\n // We need to send the full allowed tools array if custom tool settings are applied\n const allowedBridges =\n bridges?.allow?.length || bridges?.deny?.length ? enabledBridges : undefined\n const allowedExchanges =\n exchanges?.allow?.length || exchanges?.deny?.length\n ? enabledExchanges\n : undefined\n const allowSwitchChain = sdkClient.config?.routeOptions?.allowSwitchChain\n\n const isEnabled =\n Boolean(Number(fromChain?.id)) &&\n Boolean(Number(toChain?.id)) &&\n Boolean(fromToken?.address) &&\n Boolean(toToken?.address) &&\n !Number.isNaN(slippage) &&\n hasAmount &&\n isToAddressSatisfied &&\n !customReceiverBlocked &&\n contractCallQuoteEnabled &&\n !isBatchingSupportedLoading\n\n // Some values should be strictly typed and isEnabled ensures that\n const queryKey = useMemo(\n () =>\n [\n getQueryKey('routes', keyPrefix),\n effectiveFromAddress,\n fromChain?.id as number,\n fromToken?.address as string,\n fromTokenAmount,\n toWalletAddress,\n toChain?.id as number,\n toToken?.address as string,\n toTokenAmount,\n validUntilDuration,\n partiallyFillable,\n contractCalls,\n slippage,\n swapOnly,\n disabledBridges,\n disabledExchanges,\n allowedBridges,\n allowedExchanges,\n routePriority,\n mode,\n allowSwitchChain,\n enabledRefuel && enabledAutoRefuel,\n gasRecommendationFromAmount,\n feeConfig?.fee,\n disableMessageSigning,\n !!isBatchingSupported,\n isPrivate,\n observableRoute?.id,\n ] as const,\n [\n keyPrefix,\n effectiveFromAddress,\n fromChain?.id,\n fromToken?.address,\n fromTokenAmount,\n toWalletAddress,\n toChain?.id,\n toToken?.address,\n toTokenAmount,\n validUntilDuration,\n partiallyFillable,\n contractCalls,\n slippage,\n swapOnly,\n disabledBridges,\n disabledExchanges,\n allowedBridges,\n allowedExchanges,\n routePriority,\n mode,\n allowSwitchChain,\n enabledRefuel,\n enabledAutoRefuel,\n gasRecommendationFromAmount,\n feeConfig?.fee,\n disableMessageSigning,\n isBatchingSupported,\n isPrivate,\n observableRoute?.id,\n ]\n )\n\n const { getIntermediateRoutes, setIntermediateRoutes } =\n useIntermediateRoutesStore()\n\n const {\n data,\n isLoading,\n isFetching,\n isFetched,\n isError,\n dataUpdatedAt,\n refetch,\n } = useQuery({\n queryKey,\n queryFn: async ({\n queryKey: [\n _,\n fromAddress,\n fromChainId,\n fromTokenAddress,\n fromTokenAmount,\n toAddress,\n toChainId,\n toTokenAddress,\n toTokenAmount,\n validUntilDuration,\n partiallyFillable,\n contractCalls,\n slippage = defaultSlippage,\n swapOnly,\n disabledBridges,\n disabledExchanges,\n allowedBridges,\n allowedExchanges,\n routePriority,\n mode,\n allowSwitchChain,\n enabledRefuel,\n gasRecommendationFromAmount,\n configuredFee,\n disableMessageSigning,\n isBatchingSupported,\n isPrivate,\n // _observableRouteId must be the last element in the query key\n _observableRouteId,\n ],\n signal,\n }) => {\n const fromAmount = parseUnits(fromTokenAmount, fromToken!.decimals)\n const toAmount = toTokenAmount\n ? parseUnits(toTokenAmount, toToken!.decimals)\n : undefined\n const formattedSlippage = slippage\n ? Number.parseFloat(slippage) / 100\n : defaultSlippage\n\n const allowBridges = swapOnly\n ? []\n : observableRoute\n ? observableRoute.steps.flatMap((step) =>\n step.includedSteps.reduce((toolKeys, includedStep) => {\n if (includedStep.type === 'cross') {\n toolKeys.push(includedStep.toolDetails.key)\n }\n return toolKeys\n }, [] as string[])\n )\n : allowedBridges\n const allowExchanges = observableRoute\n ? observableRoute.steps.flatMap((step) =>\n step.includedSteps.reduce((toolKeys, includedStep) => {\n if (includedStep.type === 'swap') {\n toolKeys.push(includedStep.toolDetails.key)\n }\n return toolKeys\n }, [] as string[])\n )\n : allowedExchanges\n\n const calculatedFee = await feeConfig?.calculateFee?.({\n fromChain: fromChain!,\n toChain: toChain!,\n fromToken: fromToken!,\n toToken: toToken!,\n fromAddress,\n toAddress,\n fromAmount,\n toAmount,\n slippage: formattedSlippage,\n })\n\n if (mode === 'custom' && contractCalls?.length && toAmount) {\n const contractCallQuote = await getContractCallsQuote(\n sdkClient,\n {\n // Contract calls are enabled only when fromAddress is set\n fromAddress: fromAddress as string,\n fromChain: fromChainId,\n fromToken: fromTokenAddress,\n toAmount: toAmount.toString(),\n toChain: toChainId,\n toToken: toTokenAddress,\n contractCalls,\n denyBridges: disabledBridges.length ? disabledBridges : undefined,\n denyExchanges: disabledExchanges.length\n ? disabledExchanges\n : undefined,\n allowBridges,\n allowExchanges,\n toFallbackAddress: toAddress,\n slippage: formattedSlippage,\n fee: calculatedFee || configuredFee,\n },\n { signal }\n )\n\n contractCallQuote.action.toToken = toToken!\n\n const customStep =\n mode === 'custom'\n ? contractCallQuote.includedSteps?.find(\n (step) => step.type === 'custom'\n )\n : undefined\n\n if (customStep && contractTool) {\n const toolDetails = {\n key: contractTool.name,\n name: contractTool.name,\n logoURI: contractTool.logoURI,\n }\n customStep.toolDetails = toolDetails\n contractCallQuote.toolDetails = toolDetails\n }\n\n const route: Route = convertQuoteToRoute(contractCallQuote)\n\n return [route]\n }\n\n // Prevent sending a request for the same chain token combinations.\n // Exception: proceed anyway if mode is custom and modeOptions custom type is deposit\n if (\n fromChainId === toChainId &&\n fromTokenAddress === toTokenAddress &&\n !(mode === 'custom' && modeOptions?.custom?.type === 'deposit')\n ) {\n return\n }\n\n const isObservableRelayerRoute = observableRoute?.steps?.some(\n (step) => !!isGaslessStep?.(step, fromChain)\n )\n\n const shouldUseMainRoutes = !observableRoute || !isObservableRelayerRoute\n const shouldUseRelayerQuote =\n // Relayer quotes don't support limit-order params\n mode !== 'limit' &&\n account.address &&\n fromAddress &&\n fromChain?.chainType === ChainType.EVM &&\n fromChain.permit2 &&\n fromChain.permit2Proxy &&\n fromChain.relayerSupported &&\n fromChain.nativeToken.address !== fromTokenAddress &&\n useRelayerRoutes &&\n !isBatchingSupported &&\n (!observableRoute || isObservableRelayerRoute)\n\n const limitOrderRouteParams =\n mode === 'limit'\n ? {\n toAmount: toAmount?.toString(),\n validUntil: Math.floor(Date.now() / 1000) + validUntilDuration,\n partiallyFillable: partiallyFillable,\n }\n : undefined\n\n const mainRoutesPromise = shouldUseMainRoutes\n ? getRoutes(\n sdkClient,\n {\n fromAddress,\n fromAmount: fromAmount.toString(),\n fromChainId,\n fromTokenAddress,\n toAddress,\n toChainId,\n toTokenAddress,\n fromAmountForGas:\n enabledRefuel && gasRecommendationFromAmount\n ? gasRecommendationFromAmount\n : undefined,\n ...limitOrderRouteParams,\n options: {\n allowSwitchChain: mode === 'refuel' ? false : allowSwitchChain,\n bridges:\n allowBridges?.length || disabledBridges.length\n ? {\n allow: allowBridges,\n deny: disabledBridges.length\n ? disabledBridges\n : undefined,\n }\n : undefined,\n exchanges:\n allowExchanges?.length || disabledExchanges.length\n ? {\n allow: allowExchanges,\n deny: disabledExchanges.length\n ? disabledExchanges\n : undefined,\n }\n : undefined,\n order: routePriority,\n slippage: formattedSlippage,\n fee: calculatedFee || configuredFee,\n executionType: disableMessageSigning ? 'transaction' : 'all',\n ...(isPrivate && { private: true }),\n },\n },\n { signal }\n )\n : Promise.resolve(null)\n\n const relayerQuotePromise = shouldUseRelayerQuote\n ? getRelayerQuote(\n sdkClient,\n {\n fromAddress,\n fromAmount: fromAmount.toString(),\n fromChain: fromChainId,\n fromToken: fromTokenAddress,\n toAddress,\n toChain: toChainId,\n toToken: toTokenAddress,\n fromAmountForGas:\n enabledRefuel && gasRecommendationFromAmount\n ? gasRecommendationFromAmount\n : undefined,\n order: routePriority,\n slippage: formattedSlippage,\n fee: calculatedFee || configuredFee,\n ...(allowBridges?.length || disabledBridges.length\n ? {\n allowBridges: allowBridges,\n denyBridges: disabledBridges.length\n ? disabledBridges\n : undefined,\n }\n : undefined),\n ...(allowExchanges?.length || disabledExchanges.length\n ? {\n allowExchanges: allowExchanges,\n denyExchanges: disabledExchanges.length\n ? disabledExchanges\n : undefined,\n }\n : undefined),\n },\n { signal }\n )\n .then(convertQuoteToRoute)\n .catch(() => null)\n : Promise.resolve(null)\n\n // Wait for the main routes to complete first\n const routesResult = await mainRoutesPromise\n\n if (routesResult?.routes[0] && fromAddress) {\n // Update local tokens cache to keep priceUSD in sync\n const { fromToken, toToken } = routesResult.routes[0]\n ;[fromToken, toToken].forEach((token) => {\n // Update main tokens cache (verified)\n queryClient.setQueriesData<TokensByChain>(\n { queryKey: [getQueryKey('tokens', keyPrefix)] },\n (data) => updateTokenInCache(data, token)\n )\n\n // Update search tokens cache (unverified) - matches any search query\n queryClient.setQueriesData<TokensByChain>(\n {\n queryKey: [getQueryKey('tokens-search', keyPrefix)],\n exact: false,\n },\n (data) => updateTokenInCache(data, token)\n )\n\n queryClient.setQueriesData<Token[]>(\n {\n queryKey: [\n getQueryKey('token-balances', keyPrefix),\n fromAddress,\n token.chainId,\n ],\n },\n (data) => {\n if (data) {\n const clonedData = [...data]\n const index = clonedData.findIndex(\n (dataToken) => dataToken.address === token.address\n )\n if (index >= 0) {\n clonedData[index] = {\n ...clonedData[index],\n ...token,\n }\n }\n return clonedData\n }\n }\n )\n })\n }\n\n const initialRoutes = routesResult?.routes ?? []\n\n if (shouldUseRelayerQuote && initialRoutes.length) {\n setIntermediateRoutes(queryKey, initialRoutes)\n emitter.emit(WidgetEvent.AvailableRoutes, initialRoutes)\n // Return early if we're only using main routes\n } else if (shouldUseMainRoutes) {\n // If we don't need relayer quote, return the initial routes\n emitter.emit(WidgetEvent.AvailableRoutes, initialRoutes)\n return initialRoutes\n }\n\n const relayerRouteResult = await relayerQuotePromise\n // If we have a relayer route, add it to the routes array\n if (relayerRouteResult) {\n // Insert the relayer route at position 1 (after the first route)\n initialRoutes.splice(1, 0, relayerRouteResult)\n // Emit the updated routes\n emitter.emit(WidgetEvent.AvailableRoutes, initialRoutes)\n }\n\n return initialRoutes\n },\n enabled: isEnabled,\n staleTime: refetchTime,\n placeholderData: keepPreviousDataEnabled ? keepPreviousData : undefined,\n refetchInterval(query) {\n return Math.min(\n Math.abs(refetchTime - (Date.now() - query.state.dataUpdatedAt)),\n refetchTime\n )\n },\n retry(failureCount, error: any) {\n if (process.env.NODE_ENV === 'development') {\n console.warn('Route query failed:', { failureCount, error })\n }\n if (failureCount >= 3) {\n return false\n }\n if (error?.code === LiFiErrorCode.NotFound) {\n return false\n }\n return true\n },\n })\n\n const setReviewableRoute = useCallback(\n (route: Route) => {\n const queryDataKey = queryKey.toSpliced(queryKey.length - 1, 1, route.id)\n queryClient.setQueryData(queryDataKey, [route], {\n updatedAt: dataUpdatedAt || Date.now(),\n })\n setExecutableRoute(route)\n },\n [queryClient, dataUpdatedAt, setExecutableRoute, queryKey]\n )\n\n return {\n routes: data || getIntermediateRoutes(queryKey),\n isLoading: isEnabled && isLoading,\n isFetching,\n isFetched,\n isError,\n dataUpdatedAt,\n refetchTime,\n refetch,\n fromChain,\n toChain,\n queryKey,\n setReviewableRoute,\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"useRoutes.js","names":[],"sources":["../../../src/hooks/useRoutes.ts"],"sourcesContent":["import type { ExtendedChain, Route, Token } from '@lifi/sdk'\nimport {\n ChainType,\n convertQuoteToRoute,\n getContractCallsQuote,\n getRelayerQuote,\n getRoutes,\n LiFiErrorCode,\n parseUnits,\n} from '@lifi/sdk'\nimport { useAccount } from '@lifi/wallet-management'\nimport { useAddressForChain, useEthereumContext } from '@lifi/widget-provider'\nimport {\n keepPreviousData,\n useQuery,\n useQueryClient,\n} from '@tanstack/react-query'\nimport { useCallback, useMemo } from 'react'\nimport { useSDKClient } from '../providers/SDKClientProvider.js'\nimport { useWidgetConfig } from '../providers/WidgetProvider/WidgetProvider.js'\nimport { useFieldValues } from '../stores/form/useFieldValues.js'\nimport { useNavigationTabsStore } from '../stores/navigationTabs/useNavigationTabsStore.js'\nimport { useIntermediateRoutesStore } from '../stores/routes/useIntermediateRoutesStore.js'\nimport { useSetExecutableRoute } from '../stores/routes/useSetExecutableRoute.js'\nimport { defaultSlippage } from '../stores/settings/createSettingsStore.js'\nimport { useSettings } from '../stores/settings/useSettings.js'\nimport { WidgetEvent } from '../types/events.js'\nimport type { TokensByChain } from '../types/token.js'\nimport {\n canQuoteWithToAddress,\n isCustomReceiverBlocked,\n isSignerInvalidReceiver,\n} from '../utils/customReceiver.js'\nimport { getQueryKey } from '../utils/queries.js'\nimport { updateTokenInCache } from '../utils/token.js'\nimport { useChain } from './useChain.js'\nimport { useDebouncedWatch } from './useDebouncedWatch.js'\nimport { useGasRefuel } from './useGasRefuel.js'\nimport { useIsBatchingSupported } from './useIsBatchingSupported.js'\nimport { useSwapOnly } from './useSwapOnly.js'\nimport { useToken } from './useToken.js'\nimport { useWidgetEvents } from './useWidgetEvents.js'\n\nconst refetchTime = 60_000\n\ninterface RoutesProps {\n observableRoute?: Route\n /**\n * Address to quote from when no wallet is connected. Treated as a non-signing\n * placeholder, so signer-dependent (relayer/permit2) quotes are skipped.\n */\n quoteFromAddress?: string\n /**\n * Keep showing the previous result while a new query (e.g. a token/amount\n * change) is fetching, instead of clearing to a loading state.\n */\n keepPreviousData?: boolean\n}\n\nexport const useRoutes = ({\n observableRoute,\n quoteFromAddress,\n keepPreviousData: keepPreviousDataEnabled,\n}: RoutesProps = {}): {\n routes: Route[] | undefined\n isLoading: boolean\n isFetching: boolean\n isFetched: boolean\n isError: boolean\n dataUpdatedAt: number\n refetchTime: number\n refetch: () => void\n fromChain: ExtendedChain | undefined\n toChain: ExtendedChain | undefined\n queryKey: readonly unknown[]\n setReviewableRoute: (route: Route) => void\n} => {\n const {\n mode,\n modeOptions,\n contractTool,\n bridges,\n exchanges,\n feeConfig,\n useRelayerRoutes,\n storageScopeKey,\n } = useWidgetConfig()\n const sdkClient = useSDKClient()\n const setExecutableRoute = useSetExecutableRoute()\n const queryClient = useQueryClient()\n const emitter = useWidgetEvents()\n const swapOnly = useSwapOnly()\n const isPrivate = useNavigationTabsStore(\n (state) => state.activeTab === 'private'\n )\n\n const {\n disabledBridges,\n disabledExchanges,\n enabledBridges,\n enabledExchanges,\n enabledAutoRefuel,\n routePriority,\n slippage,\n } = useSettings([\n 'disabledBridges',\n 'disabledExchanges',\n 'enabledBridges',\n 'enabledExchanges',\n 'enabledAutoRefuel',\n 'routePriority',\n 'slippage',\n ])\n const [fromTokenAmount] = useDebouncedWatch(500, 'fromAmount')\n // Debounce toAmount like fromAmount to avoid a request per keystroke\n const [toTokenAmount] = useDebouncedWatch(500, 'toAmount')\n const [\n fromChainId,\n fromTokenAddress,\n toAddress,\n toChainId,\n toTokenAddress,\n contractCalls,\n ] = useFieldValues(\n 'fromChain',\n 'fromToken',\n 'toAddress',\n 'toChain',\n 'toToken',\n 'contractCalls'\n )\n const [validUntilDuration, partiallyFillable] = useFieldValues(\n 'validUntil',\n 'partiallyFillable'\n )\n const { token: fromToken } = useToken(fromChainId, fromTokenAddress)\n const { token: toToken } = useToken(toChainId, toTokenAddress)\n const { chain: fromChain } = useChain(fromChainId)\n const { chain: toChain } = useChain(toChainId)\n const { enabled: enabledRefuel, fromAmount: gasRecommendationFromAmount } =\n useGasRefuel()\n const { isAddressForChain } = useAddressForChain()\n const { isGaslessStep, disableMessageSigning } = useEthereumContext()\n const { account } = useAccount({ chainType: fromChain?.chainType })\n const { isBatchingSupported, isBatchingSupportedLoading } =\n useIsBatchingSupported(fromChain, account.address)\n\n // In limit mode toAmount is the user's limit target, derived from the sell\n // amount and limit price. It's keyed and sent to the backend so changing the\n // limit fetches a fresh quote. The receive card is read-only (it displays the\n // quote and never writes toAmount back), so keying on it can't loop. Both a\n // sell amount and a limit price (→ toAmount) are required before fetching.\n const hasAmount =\n mode === 'limit'\n ? Number(fromTokenAmount) > 0 && Number(toTokenAmount) > 0\n : Number(fromTokenAmount) > 0 || Number(toTokenAmount) > 0\n\n const customType = mode === 'custom' ? modeOptions?.custom?.type : undefined\n const isContractCallQuote =\n mode === 'custom' && Boolean(contractCalls?.length)\n // A contract-call quote needs a connected wallet to resolve fromAddress.\n // Deposit funding quotes a plain route with no contract calls and no wallet\n // (a placeholder fromAddress arrives via quoteFromAddress); every other custom\n // flow stays gated on a real wallet, as before.\n const contractCallQuoteEnabled: boolean = isContractCallQuote\n ? Boolean(account.address)\n : mode !== 'custom' || customType === 'deposit'\n\n // Quote as if disconnected while the signer would be taken as the receiver.\n const effectiveFromAddress = isSignerInvalidReceiver({\n signerAddress: account.address,\n toAddress,\n fromChain,\n toChain,\n isAddressForChain,\n })\n ? quoteFromAddress\n : (account.address ?? quoteFromAddress)\n\n const isToAddressSatisfied = canQuoteWithToAddress(\n toAddress,\n toChain,\n isAddressForChain\n )\n\n // Not `effectiveFromAddress`: a quote placeholder must never match a receiver.\n const customReceiverBlocked = isCustomReceiverBlocked({\n fromChainType: fromChain?.chainType,\n toChainType: toChain?.chainType,\n toAddress,\n signerAddress: account.address,\n })\n\n // toAddress might be an empty string, but we need to pass undefined if there is no value\n const toWalletAddress = toAddress || undefined\n\n // We need to send the full allowed tools array if custom tool settings are applied\n const allowedBridges =\n bridges?.allow?.length || bridges?.deny?.length ? enabledBridges : undefined\n const allowedExchanges =\n exchanges?.allow?.length || exchanges?.deny?.length\n ? enabledExchanges\n : undefined\n const allowSwitchChain = sdkClient.config?.routeOptions?.allowSwitchChain\n\n const isEnabled =\n Boolean(Number(fromChain?.id)) &&\n Boolean(Number(toChain?.id)) &&\n Boolean(fromToken?.address) &&\n Boolean(toToken?.address) &&\n !Number.isNaN(slippage) &&\n hasAmount &&\n isToAddressSatisfied &&\n !customReceiverBlocked &&\n contractCallQuoteEnabled &&\n !isBatchingSupportedLoading\n\n // Some values should be strictly typed and isEnabled ensures that\n const queryKey = useMemo(\n () =>\n [\n getQueryKey('routes', storageScopeKey),\n effectiveFromAddress,\n fromChain?.id as number,\n fromToken?.address as string,\n fromTokenAmount,\n toWalletAddress,\n toChain?.id as number,\n toToken?.address as string,\n toTokenAmount,\n validUntilDuration,\n partiallyFillable,\n contractCalls,\n slippage,\n swapOnly,\n disabledBridges,\n disabledExchanges,\n allowedBridges,\n allowedExchanges,\n routePriority,\n mode,\n allowSwitchChain,\n enabledRefuel && enabledAutoRefuel,\n gasRecommendationFromAmount,\n feeConfig?.fee,\n disableMessageSigning,\n !!isBatchingSupported,\n isPrivate,\n observableRoute?.id,\n ] as const,\n [\n storageScopeKey,\n effectiveFromAddress,\n fromChain?.id,\n fromToken?.address,\n fromTokenAmount,\n toWalletAddress,\n toChain?.id,\n toToken?.address,\n toTokenAmount,\n validUntilDuration,\n partiallyFillable,\n contractCalls,\n slippage,\n swapOnly,\n disabledBridges,\n disabledExchanges,\n allowedBridges,\n allowedExchanges,\n routePriority,\n mode,\n allowSwitchChain,\n enabledRefuel,\n enabledAutoRefuel,\n gasRecommendationFromAmount,\n feeConfig?.fee,\n disableMessageSigning,\n isBatchingSupported,\n isPrivate,\n observableRoute?.id,\n ]\n )\n\n const { getIntermediateRoutes, setIntermediateRoutes } =\n useIntermediateRoutesStore()\n\n const {\n data,\n isLoading,\n isFetching,\n isFetched,\n isError,\n dataUpdatedAt,\n refetch,\n } = useQuery({\n queryKey,\n queryFn: async ({\n queryKey: [\n _,\n fromAddress,\n fromChainId,\n fromTokenAddress,\n fromTokenAmount,\n toAddress,\n toChainId,\n toTokenAddress,\n toTokenAmount,\n validUntilDuration,\n partiallyFillable,\n contractCalls,\n slippage = defaultSlippage,\n swapOnly,\n disabledBridges,\n disabledExchanges,\n allowedBridges,\n allowedExchanges,\n routePriority,\n mode,\n allowSwitchChain,\n enabledRefuel,\n gasRecommendationFromAmount,\n configuredFee,\n disableMessageSigning,\n isBatchingSupported,\n isPrivate,\n // _observableRouteId must be the last element in the query key\n _observableRouteId,\n ],\n signal,\n }) => {\n const fromAmount = parseUnits(fromTokenAmount, fromToken!.decimals)\n const toAmount = toTokenAmount\n ? parseUnits(toTokenAmount, toToken!.decimals)\n : undefined\n const formattedSlippage = slippage\n ? Number.parseFloat(slippage) / 100\n : defaultSlippage\n\n const allowBridges = swapOnly\n ? []\n : observableRoute\n ? observableRoute.steps.flatMap((step) =>\n step.includedSteps.reduce((toolKeys, includedStep) => {\n if (includedStep.type === 'cross') {\n toolKeys.push(includedStep.toolDetails.key)\n }\n return toolKeys\n }, [] as string[])\n )\n : allowedBridges\n const allowExchanges = observableRoute\n ? observableRoute.steps.flatMap((step) =>\n step.includedSteps.reduce((toolKeys, includedStep) => {\n if (includedStep.type === 'swap') {\n toolKeys.push(includedStep.toolDetails.key)\n }\n return toolKeys\n }, [] as string[])\n )\n : allowedExchanges\n\n const calculatedFee = await feeConfig?.calculateFee?.({\n fromChain: fromChain!,\n toChain: toChain!,\n fromToken: fromToken!,\n toToken: toToken!,\n fromAddress,\n toAddress,\n fromAmount,\n toAmount,\n slippage: formattedSlippage,\n })\n\n if (mode === 'custom' && contractCalls?.length && toAmount) {\n const contractCallQuote = await getContractCallsQuote(\n sdkClient,\n {\n // Contract calls are enabled only when fromAddress is set\n fromAddress: fromAddress as string,\n fromChain: fromChainId,\n fromToken: fromTokenAddress,\n toAmount: toAmount.toString(),\n toChain: toChainId,\n toToken: toTokenAddress,\n contractCalls,\n denyBridges: disabledBridges.length ? disabledBridges : undefined,\n denyExchanges: disabledExchanges.length\n ? disabledExchanges\n : undefined,\n allowBridges,\n allowExchanges,\n toFallbackAddress: toAddress,\n slippage: formattedSlippage,\n fee: calculatedFee || configuredFee,\n },\n { signal }\n )\n\n contractCallQuote.action.toToken = toToken!\n\n const customStep =\n mode === 'custom'\n ? contractCallQuote.includedSteps?.find(\n (step) => step.type === 'custom'\n )\n : undefined\n\n if (customStep && contractTool) {\n const toolDetails = {\n key: contractTool.name,\n name: contractTool.name,\n logoURI: contractTool.logoURI,\n }\n customStep.toolDetails = toolDetails\n contractCallQuote.toolDetails = toolDetails\n }\n\n const route: Route = convertQuoteToRoute(contractCallQuote)\n\n return [route]\n }\n\n // Prevent sending a request for the same chain token combinations.\n // Exception: proceed anyway if mode is custom and modeOptions custom type is deposit\n if (\n fromChainId === toChainId &&\n fromTokenAddress === toTokenAddress &&\n !(mode === 'custom' && modeOptions?.custom?.type === 'deposit')\n ) {\n return\n }\n\n const isObservableRelayerRoute = observableRoute?.steps?.some(\n (step) => !!isGaslessStep?.(step, fromChain)\n )\n\n const shouldUseMainRoutes = !observableRoute || !isObservableRelayerRoute\n const shouldUseRelayerQuote =\n // Relayer quotes don't support limit-order params\n mode !== 'limit' &&\n account.address &&\n fromAddress &&\n fromChain?.chainType === ChainType.EVM &&\n fromChain.permit2 &&\n fromChain.permit2Proxy &&\n fromChain.relayerSupported &&\n fromChain.nativeToken.address !== fromTokenAddress &&\n useRelayerRoutes &&\n !isBatchingSupported &&\n (!observableRoute || isObservableRelayerRoute)\n\n const limitOrderRouteParams =\n mode === 'limit'\n ? {\n toAmount: toAmount?.toString(),\n validUntil: Math.floor(Date.now() / 1000) + validUntilDuration,\n partiallyFillable: partiallyFillable,\n }\n : undefined\n\n const mainRoutesPromise = shouldUseMainRoutes\n ? getRoutes(\n sdkClient,\n {\n fromAddress,\n fromAmount: fromAmount.toString(),\n fromChainId,\n fromTokenAddress,\n toAddress,\n toChainId,\n toTokenAddress,\n fromAmountForGas:\n enabledRefuel && gasRecommendationFromAmount\n ? gasRecommendationFromAmount\n : undefined,\n ...limitOrderRouteParams,\n options: {\n allowSwitchChain: mode === 'refuel' ? false : allowSwitchChain,\n bridges:\n allowBridges?.length || disabledBridges.length\n ? {\n allow: allowBridges,\n deny: disabledBridges.length\n ? disabledBridges\n : undefined,\n }\n : undefined,\n exchanges:\n allowExchanges?.length || disabledExchanges.length\n ? {\n allow: allowExchanges,\n deny: disabledExchanges.length\n ? disabledExchanges\n : undefined,\n }\n : undefined,\n order: routePriority,\n slippage: formattedSlippage,\n fee: calculatedFee || configuredFee,\n executionType: disableMessageSigning ? 'transaction' : 'all',\n ...(isPrivate && { private: true }),\n },\n },\n { signal }\n )\n : Promise.resolve(null)\n\n const relayerQuotePromise = shouldUseRelayerQuote\n ? getRelayerQuote(\n sdkClient,\n {\n fromAddress,\n fromAmount: fromAmount.toString(),\n fromChain: fromChainId,\n fromToken: fromTokenAddress,\n toAddress,\n toChain: toChainId,\n toToken: toTokenAddress,\n fromAmountForGas:\n enabledRefuel && gasRecommendationFromAmount\n ? gasRecommendationFromAmount\n : undefined,\n order: routePriority,\n slippage: formattedSlippage,\n fee: calculatedFee || configuredFee,\n ...(allowBridges?.length || disabledBridges.length\n ? {\n allowBridges: allowBridges,\n denyBridges: disabledBridges.length\n ? disabledBridges\n : undefined,\n }\n : undefined),\n ...(allowExchanges?.length || disabledExchanges.length\n ? {\n allowExchanges: allowExchanges,\n denyExchanges: disabledExchanges.length\n ? disabledExchanges\n : undefined,\n }\n : undefined),\n },\n { signal }\n )\n .then(convertQuoteToRoute)\n .catch(() => null)\n : Promise.resolve(null)\n\n // Wait for the main routes to complete first\n const routesResult = await mainRoutesPromise\n\n if (routesResult?.routes[0] && fromAddress) {\n // Update local tokens cache to keep priceUSD in sync\n const { fromToken, toToken } = routesResult.routes[0]\n ;[fromToken, toToken].forEach((token) => {\n // Update main tokens cache (verified)\n queryClient.setQueriesData<TokensByChain>(\n { queryKey: [getQueryKey('tokens', storageScopeKey)] },\n (data) => updateTokenInCache(data, token)\n )\n\n // Update search tokens cache (unverified) - matches any search query\n queryClient.setQueriesData<TokensByChain>(\n {\n queryKey: [getQueryKey('tokens-search', storageScopeKey)],\n exact: false,\n },\n (data) => updateTokenInCache(data, token)\n )\n\n queryClient.setQueriesData<Token[]>(\n {\n queryKey: [\n getQueryKey('token-balances', storageScopeKey),\n fromAddress,\n token.chainId,\n ],\n },\n (data) => {\n if (data) {\n const clonedData = [...data]\n const index = clonedData.findIndex(\n (dataToken) => dataToken.address === token.address\n )\n if (index >= 0) {\n clonedData[index] = {\n ...clonedData[index],\n ...token,\n }\n }\n return clonedData\n }\n }\n )\n })\n }\n\n const initialRoutes = routesResult?.routes ?? []\n\n if (shouldUseRelayerQuote && initialRoutes.length) {\n setIntermediateRoutes(queryKey, initialRoutes)\n emitter.emit(WidgetEvent.AvailableRoutes, initialRoutes)\n // Return early if we're only using main routes\n } else if (shouldUseMainRoutes) {\n // If we don't need relayer quote, return the initial routes\n emitter.emit(WidgetEvent.AvailableRoutes, initialRoutes)\n return initialRoutes\n }\n\n const relayerRouteResult = await relayerQuotePromise\n // If we have a relayer route, add it to the routes array\n if (relayerRouteResult) {\n // Insert the relayer route at position 1 (after the first route)\n initialRoutes.splice(1, 0, relayerRouteResult)\n // Emit the updated routes\n emitter.emit(WidgetEvent.AvailableRoutes, initialRoutes)\n }\n\n return initialRoutes\n },\n enabled: isEnabled,\n staleTime: refetchTime,\n placeholderData: keepPreviousDataEnabled ? keepPreviousData : undefined,\n refetchInterval(query) {\n return Math.min(\n Math.abs(refetchTime - (Date.now() - query.state.dataUpdatedAt)),\n refetchTime\n )\n },\n retry(failureCount, error: any) {\n if (process.env.NODE_ENV === 'development') {\n console.warn('Route query failed:', { failureCount, error })\n }\n if (failureCount >= 3) {\n return false\n }\n if (error?.code === LiFiErrorCode.NotFound) {\n return false\n }\n return true\n },\n })\n\n const setReviewableRoute = useCallback(\n (route: Route) => {\n const queryDataKey = queryKey.toSpliced(queryKey.length - 1, 1, route.id)\n queryClient.setQueryData(queryDataKey, [route], {\n updatedAt: dataUpdatedAt || Date.now(),\n })\n setExecutableRoute(route)\n },\n [queryClient, dataUpdatedAt, setExecutableRoute, queryKey]\n )\n\n return {\n routes: data || getIntermediateRoutes(queryKey),\n isLoading: isEnabled && isLoading,\n isFetching,\n isFetched,\n isError,\n dataUpdatedAt,\n refetchTime,\n refetch,\n fromChain,\n toChain,\n queryKey,\n setReviewableRoute,\n }\n}\n"],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@ import { useAvailableChains } from "./useAvailableChains.js";
|
|
|
2
2
|
import { useBookmarkActions } from "../stores/bookmarks/useBookmarkActions.js";
|
|
3
3
|
import { useFieldActions } from "../stores/form/useFieldActions.js";
|
|
4
4
|
import { useCallback } from "react";
|
|
5
|
-
import {
|
|
5
|
+
import { useAddressForChain } from "@lifi/widget-provider";
|
|
6
6
|
import { useAccount } from "@lifi/wallet-management";
|
|
7
7
|
//#region src/hooks/useToAddressAutoPopulate.ts
|
|
8
8
|
/**
|
|
@@ -13,17 +13,15 @@ const useToAddressAutoPopulate = () => {
|
|
|
13
13
|
const { setSelectedBookmark } = useBookmarkActions();
|
|
14
14
|
const { getChainById } = useAvailableChains();
|
|
15
15
|
const { accounts } = useAccount();
|
|
16
|
-
const {
|
|
16
|
+
const { isAddressForChain } = useAddressForChain();
|
|
17
17
|
return useCallback(({ formType, selectedToAddress, selectedChainId, selectedOppositeTokenAddress, selectedOppositeChainId }) => {
|
|
18
18
|
if (!selectedOppositeTokenAddress || !selectedOppositeChainId || !selectedChainId || !accounts?.length) return;
|
|
19
19
|
const selectedChain = getChainById?.(selectedChainId);
|
|
20
20
|
const selectedOppositeChain = getChainById?.(selectedOppositeChainId);
|
|
21
21
|
if (!selectedChain || !selectedOppositeChain || selectedChain.chainType === selectedOppositeChain.chainType) return;
|
|
22
|
-
const
|
|
23
|
-
if (selectedToAddress)
|
|
24
|
-
|
|
25
|
-
}
|
|
26
|
-
const destinationAccount = accounts?.find((account) => account.chainType === destinationChainType);
|
|
22
|
+
const destinationChain = formType === "from" ? selectedOppositeChain : selectedChain;
|
|
23
|
+
if (selectedToAddress && isAddressForChain(selectedToAddress, destinationChain)) return;
|
|
24
|
+
const destinationAccount = accounts?.find((account) => account.address && isAddressForChain(account.address, destinationChain));
|
|
27
25
|
if (destinationAccount?.address) {
|
|
28
26
|
setFieldValue("toAddress", destinationAccount.address, {
|
|
29
27
|
isDirty: false,
|
|
@@ -42,7 +40,7 @@ const useToAddressAutoPopulate = () => {
|
|
|
42
40
|
getChainById,
|
|
43
41
|
setFieldValue,
|
|
44
42
|
setSelectedBookmark,
|
|
45
|
-
|
|
43
|
+
isAddressForChain
|
|
46
44
|
]);
|
|
47
45
|
};
|
|
48
46
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useToAddressAutoPopulate.js","names":[],"sources":["../../../src/hooks/useToAddressAutoPopulate.ts"],"sourcesContent":["import { useAccount } from '@lifi/wallet-management'\nimport {
|
|
1
|
+
{"version":3,"file":"useToAddressAutoPopulate.js","names":[],"sources":["../../../src/hooks/useToAddressAutoPopulate.ts"],"sourcesContent":["import { useAccount } from '@lifi/wallet-management'\nimport { useAddressForChain } from '@lifi/widget-provider'\nimport { useCallback } from 'react'\nimport { useBookmarkActions } from '../stores/bookmarks/useBookmarkActions.js'\nimport type { FormType } from '../stores/form/types.js'\nimport { useFieldActions } from '../stores/form/useFieldActions.js'\nimport { useAvailableChains } from './useAvailableChains.js'\n\ntype UpdateToAddressArgs = {\n formType: FormType\n selectedToAddress?: string\n selectedChainId?: number\n selectedOppositeTokenAddress?: string\n selectedOppositeChainId?: number\n}\n\n/**\n * Automatically populates toAddress field if bridging across ecosystems and compatible wallet is connected\n */\nexport const useToAddressAutoPopulate = (): ((\n args: UpdateToAddressArgs\n) => string | undefined) => {\n const { setFieldValue } = useFieldActions()\n const { setSelectedBookmark } = useBookmarkActions()\n const { getChainById } = useAvailableChains()\n const { accounts } = useAccount()\n const { isAddressForChain } = useAddressForChain()\n\n return useCallback(\n ({\n formType,\n selectedToAddress,\n selectedChainId,\n selectedOppositeTokenAddress,\n selectedOppositeChainId,\n }: UpdateToAddressArgs) => {\n if (\n !selectedOppositeTokenAddress ||\n !selectedOppositeChainId ||\n !selectedChainId ||\n !accounts?.length\n ) {\n return\n }\n const selectedChain = getChainById?.(selectedChainId)\n const selectedOppositeChain = getChainById?.(selectedOppositeChainId)\n // Proceed if both chains are defined and of different ecosystem types (indicating cross-ecosystem bridging)\n if (\n !selectedChain ||\n !selectedOppositeChain ||\n selectedChain.chainType === selectedOppositeChain.chainType\n ) {\n return\n }\n const destinationChain =\n formType === 'from' ? selectedOppositeChain : selectedChain\n if (\n selectedToAddress &&\n isAddressForChain(selectedToAddress, destinationChain)\n ) {\n return\n }\n const destinationAccount = accounts?.find(\n (account) =>\n account.address &&\n isAddressForChain(account.address, destinationChain)\n )\n // If a compatible destination account is found, set toAddress as if selecting it from the \"Send to Wallet\" connected wallets page\n if (destinationAccount?.address) {\n setFieldValue('toAddress', destinationAccount.address, {\n isDirty: false,\n isTouched: true,\n })\n setSelectedBookmark({\n name: destinationAccount.connector?.name,\n address: destinationAccount.address,\n chainType: destinationAccount.chainType,\n isConnectedAccount: true,\n })\n return destinationAccount.address\n }\n },\n [\n accounts,\n getChainById,\n setFieldValue,\n setSelectedBookmark,\n isAddressForChain,\n ]\n )\n}\n"],"mappings":";;;;;;;;;;AAmBA,MAAa,iCAEe;CAC1B,MAAM,EAAE,kBAAkB,gBAAgB;CAC1C,MAAM,EAAE,wBAAwB,mBAAmB;CACnD,MAAM,EAAE,iBAAiB,mBAAmB;CAC5C,MAAM,EAAE,aAAa,WAAW;CAChC,MAAM,EAAE,sBAAsB,mBAAmB;CAEjD,OAAO,aACJ,EACC,UACA,mBACA,iBACA,8BACA,8BACyB;EACzB,IACE,CAAC,gCACD,CAAC,2BACD,CAAC,mBACD,CAAC,UAAU,QAEX;EAEF,MAAM,gBAAgB,eAAe,eAAe;EACpD,MAAM,wBAAwB,eAAe,uBAAuB;EAEpE,IACE,CAAC,iBACD,CAAC,yBACD,cAAc,cAAc,sBAAsB,WAElD;EAEF,MAAM,mBACJ,aAAa,SAAS,wBAAwB;EAChD,IACE,qBACA,kBAAkB,mBAAmB,gBAAgB,GAErD;EAEF,MAAM,qBAAqB,UAAU,MAClC,YACC,QAAQ,WACR,kBAAkB,QAAQ,SAAS,gBAAgB,CACvD;EAEA,IAAI,oBAAoB,SAAS;GAC/B,cAAc,aAAa,mBAAmB,SAAS;IACrD,SAAS;IACT,WAAW;GACb,CAAC;GACD,oBAAoB;IAClB,MAAM,mBAAmB,WAAW;IACpC,SAAS,mBAAmB;IAC5B,WAAW,mBAAmB;IAC9B,oBAAoB;GACtB,CAAC;GACD,OAAO,mBAAmB;EAC5B;CACF,GACA;EACE;EACA;EACA;EACA;EACA;CACF,CACF;AACF"}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { RouteExtended } from "@lifi/sdk";
|
|
2
2
|
//#region src/hooks/useToAddressRequirements.d.ts
|
|
3
3
|
export declare const useToAddressRequirements: (route?: RouteExtended) => {
|
|
4
4
|
requiredToAddress: boolean;
|
|
5
5
|
unsupportedToAddress: boolean;
|
|
6
6
|
unsupportedReceiverBlocking: boolean;
|
|
7
|
-
|
|
7
|
+
/** Whether a saved or connected address can receive on the destination chain. */
|
|
8
|
+
isValidReceiver: (address?: string) => boolean;
|
|
8
9
|
accountNotDeployedAtDestination: boolean;
|
|
9
10
|
accountDeployedAtDestination: boolean;
|
|
10
11
|
toAddress: string | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useToAddressRequirements.d.ts","names":[],"sources":["../../../src/hooks/useToAddressRequirements.ts"],"mappings":";;qBAYa,2BACX,QAAQ;EAER;EACA;EACA
|
|
1
|
+
{"version":3,"file":"useToAddressRequirements.d.ts","names":[],"sources":["../../../src/hooks/useToAddressRequirements.ts"],"mappings":";;qBAYa,2BACX,QAAQ;EAER;EACA;EACA;;EAEA,kBAAkB;EAClB;EACA;EACA;EACA;EACA;EACA;EACA"}
|
|
@@ -3,13 +3,14 @@ import { useFieldValues } from "../stores/form/useFieldValues.js";
|
|
|
3
3
|
import { isCustomReceiverBlocked, isCustomReceiverUnsupported } from "../utils/customReceiver.js";
|
|
4
4
|
import { useChain } from "./useChain.js";
|
|
5
5
|
import { useIsContractAddress } from "./useIsContractAddress.js";
|
|
6
|
-
import { useEthereumContext } from "@lifi/widget-provider";
|
|
6
|
+
import { useAddressForChain, useEthereumContext } from "@lifi/widget-provider";
|
|
7
7
|
import { useAccount } from "@lifi/wallet-management";
|
|
8
8
|
//#region src/hooks/useToAddressRequirements.ts
|
|
9
9
|
const useToAddressRequirements = (route) => {
|
|
10
10
|
const { requiredUI, hiddenUI } = useWidgetConfig();
|
|
11
11
|
const [formFromChainId, formToChainId, formToAddress] = useFieldValues("fromChain", "toChain", "toAddress");
|
|
12
12
|
const { isDelegationDesignatorCode } = useEthereumContext();
|
|
13
|
+
const { isAddressForChain } = useAddressForChain();
|
|
13
14
|
const fromChainId = route?.fromChainId ?? formFromChainId;
|
|
14
15
|
const toChainId = route?.toChainId ?? formToChainId;
|
|
15
16
|
const { chain: fromChain } = useChain(fromChainId);
|
|
@@ -30,16 +31,16 @@ const useToAddressRequirements = (route) => {
|
|
|
30
31
|
signerAddress: fromAddress,
|
|
31
32
|
receiverRequired: requiredUI?.toAddress
|
|
32
33
|
});
|
|
33
|
-
const
|
|
34
|
-
const
|
|
35
|
-
const
|
|
34
|
+
const isSignerAddressInvalidAtDestination = Boolean(fromAddress && fromChain && toChain && isAddressForChain(fromAddress, fromChain) && !isAddressForChain(fromAddress, toChain));
|
|
35
|
+
const requiredToAddress = Boolean((isDifferentChainType || isCrossChainContractAddress || isSignerAddressInvalidAtDestination || requiredUI?.toAddress) && !hiddenUI?.toAddress && !unsupportedToAddress);
|
|
36
|
+
const isValidReceiver = (address) => !toChain || !!address && isAddressForChain(address, toChain);
|
|
36
37
|
return {
|
|
37
38
|
requiredToAddress,
|
|
38
39
|
unsupportedToAddress,
|
|
39
40
|
unsupportedReceiverBlocking,
|
|
40
|
-
|
|
41
|
-
accountNotDeployedAtDestination,
|
|
42
|
-
accountDeployedAtDestination,
|
|
41
|
+
isValidReceiver,
|
|
42
|
+
accountNotDeployedAtDestination: Boolean(isFromContractAddress && !fromContractCodeHasDelegationIndicator && !isToContractAddress && fromAddress?.toLowerCase() === toAddress?.toLowerCase()),
|
|
43
|
+
accountDeployedAtDestination: Boolean(isFromContractAddress && isToContractAddress && !fromContractCodeHasDelegationIndicator && fromAddress?.toLowerCase() === toAddress?.toLowerCase()),
|
|
43
44
|
toAddress,
|
|
44
45
|
isFromContractAddress,
|
|
45
46
|
isToContractAddress,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useToAddressRequirements.js","names":[],"sources":["../../../src/hooks/useToAddressRequirements.ts"],"sourcesContent":["import type {
|
|
1
|
+
{"version":3,"file":"useToAddressRequirements.js","names":[],"sources":["../../../src/hooks/useToAddressRequirements.ts"],"sourcesContent":["import type { RouteExtended } from '@lifi/sdk'\nimport { useAccount } from '@lifi/wallet-management'\nimport { useAddressForChain, useEthereumContext } from '@lifi/widget-provider'\nimport { useChain } from '../hooks/useChain.js'\nimport { useWidgetConfig } from '../providers/WidgetProvider/WidgetProvider.js'\nimport { useFieldValues } from '../stores/form/useFieldValues.js'\nimport {\n isCustomReceiverBlocked,\n isCustomReceiverUnsupported,\n} from '../utils/customReceiver.js'\nimport { useIsContractAddress } from './useIsContractAddress.js'\n\nexport const useToAddressRequirements = (\n route?: RouteExtended\n): {\n requiredToAddress: boolean\n unsupportedToAddress: boolean\n unsupportedReceiverBlocking: boolean\n /** Whether a saved or connected address can receive on the destination chain. */\n isValidReceiver: (address?: string) => boolean\n accountNotDeployedAtDestination: boolean\n accountDeployedAtDestination: boolean\n toAddress: string | undefined\n isFromContractAddress: boolean | undefined\n isToContractAddress: boolean | undefined\n isLoading: boolean\n isFetched: boolean\n} => {\n const { requiredUI, hiddenUI } = useWidgetConfig()\n const [formFromChainId, formToChainId, formToAddress] = useFieldValues(\n 'fromChain',\n 'toChain',\n 'toAddress'\n )\n const { isDelegationDesignatorCode } = useEthereumContext()\n const { isAddressForChain } = useAddressForChain()\n\n const fromChainId = route?.fromChainId ?? formFromChainId\n const toChainId = route?.toChainId ?? formToChainId\n\n const { chain: fromChain } = useChain(fromChainId)\n const { chain: toChain } = useChain(toChainId)\n const { account } = useAccount({\n chainType: fromChain?.chainType,\n })\n\n const fromAddress = route?.fromAddress ?? account.address\n const toAddress = route\n ? route.fromAddress !== route.toAddress\n ? route.toAddress\n : formToAddress\n : formToAddress\n\n const {\n isContractAddress: isFromContractAddress,\n contractCode: fromContractCode,\n isLoading: isFromContractLoading,\n isFetched: isFromContractFetched,\n } = useIsContractAddress(account.address, fromChain?.id, account.chainType)\n const {\n isContractAddress: isToContractAddress,\n isLoading: isToContractLoading,\n isFetched: isToContractFetched,\n } = useIsContractAddress(toAddress, toChain?.id, toChain?.chainType)\n\n const isDifferentChainType =\n fromChain && toChain && fromChain.chainType !== toChain.chainType\n\n // We don't want to block transfers for EIP-7702 accounts since they are designed\n // to maintain EOA-like properties while delegating execution.\n const fromContractCodeHasDelegationIndicator =\n isDelegationDesignatorCode?.(fromContractCode)\n\n const isCrossChainContractAddress =\n isFromContractAddress &&\n fromChainId !== toChainId &&\n !fromContractCodeHasDelegationIndicator\n\n const unsupportedToAddress = isCustomReceiverUnsupported(\n fromChain?.chainType,\n toChain?.chainType\n )\n\n const unsupportedReceiverBlocking = isCustomReceiverBlocked({\n fromChainType: fromChain?.chainType,\n toChainType: toChain?.chainType,\n toAddress,\n signerAddress: fromAddress,\n receiverRequired: requiredUI?.toAddress,\n })\n\n // A shared chain type is not a shared format: a Bitcoin signer cannot receive on ZEC.\n const isSignerAddressInvalidAtDestination = Boolean(\n fromAddress &&\n fromChain &&\n toChain &&\n isAddressForChain(fromAddress, fromChain) &&\n !isAddressForChain(fromAddress, toChain)\n )\n\n const requiredToAddress = Boolean(\n (isDifferentChainType ||\n isCrossChainContractAddress ||\n isSignerAddressInvalidAtDestination ||\n requiredUI?.toAddress) &&\n !hiddenUI?.toAddress &&\n !unsupportedToAddress\n )\n\n const isValidReceiver = (address?: string): boolean =>\n !toChain || (!!address && isAddressForChain(address, toChain))\n\n const accountNotDeployedAtDestination = Boolean(\n isFromContractAddress &&\n !fromContractCodeHasDelegationIndicator &&\n !isToContractAddress &&\n fromAddress?.toLowerCase() === toAddress?.toLowerCase()\n )\n\n const accountDeployedAtDestination = Boolean(\n isFromContractAddress &&\n isToContractAddress &&\n !fromContractCodeHasDelegationIndicator &&\n fromAddress?.toLowerCase() === toAddress?.toLowerCase()\n )\n\n return {\n requiredToAddress,\n unsupportedToAddress,\n unsupportedReceiverBlocking,\n isValidReceiver,\n accountNotDeployedAtDestination,\n accountDeployedAtDestination,\n toAddress,\n isFromContractAddress,\n isToContractAddress,\n isLoading: isFromContractLoading || isToContractLoading,\n isFetched: isFromContractFetched && isToContractFetched,\n }\n}\n"],"mappings":";;;;;;;;AAYA,MAAa,4BACX,UAcG;CACH,MAAM,EAAE,YAAY,aAAa,gBAAgB;CACjD,MAAM,CAAC,iBAAiB,eAAe,iBAAiB,eACtD,aACA,WACA,WACF;CACA,MAAM,EAAE,+BAA+B,mBAAmB;CAC1D,MAAM,EAAE,sBAAsB,mBAAmB;CAEjD,MAAM,cAAc,OAAO,eAAe;CAC1C,MAAM,YAAY,OAAO,aAAa;CAEtC,MAAM,EAAE,OAAO,cAAc,SAAS,WAAW;CACjD,MAAM,EAAE,OAAO,YAAY,SAAS,SAAS;CAC7C,MAAM,EAAE,YAAY,WAAW,EAC7B,WAAW,WAAW,UACxB,CAAC;CAED,MAAM,cAAc,OAAO,eAAe,QAAQ;CAClD,MAAM,YAAY,QACd,MAAM,gBAAgB,MAAM,YAC1B,MAAM,YACN,gBACF;CAEJ,MAAM,EACJ,mBAAmB,uBACnB,cAAc,kBACd,WAAW,uBACX,WAAW,0BACT,qBAAqB,QAAQ,SAAS,WAAW,IAAI,QAAQ,SAAS;CAC1E,MAAM,EACJ,mBAAmB,qBACnB,WAAW,qBACX,WAAW,wBACT,qBAAqB,WAAW,SAAS,IAAI,SAAS,SAAS;CAEnE,MAAM,uBACJ,aAAa,WAAW,UAAU,cAAc,QAAQ;CAI1D,MAAM,yCACJ,6BAA6B,gBAAgB;CAE/C,MAAM,8BACJ,yBACA,gBAAgB,aAChB,CAAC;CAEH,MAAM,uBAAuB,4BAC3B,WAAW,WACX,SAAS,SACX;CAEA,MAAM,8BAA8B,wBAAwB;EAC1D,eAAe,WAAW;EAC1B,aAAa,SAAS;EACtB;EACA,eAAe;EACf,kBAAkB,YAAY;CAChC,CAAC;CAGD,MAAM,sCAAsC,QAC1C,eACE,aACA,WACA,kBAAkB,aAAa,SAAS,KACxC,CAAC,kBAAkB,aAAa,OAAO,CAC3C;CAEA,MAAM,oBAAoB,SACvB,wBACC,+BACA,uCACA,YAAY,cACZ,CAAC,UAAU,aACX,CAAC,oBACL;CAEA,MAAM,mBAAmB,YACvB,CAAC,WAAY,CAAC,CAAC,WAAW,kBAAkB,SAAS,OAAO;CAgB9D,OAAO;EACL;EACA;EACA;EACA;EACA,iCAnBsC,QACtC,yBACE,CAAC,0CACD,CAAC,uBACD,aAAa,YAAY,MAAM,WAAW,YAAY,CAe1B;EAC9B,8BAbmC,QACnC,yBACE,uBACA,CAAC,0CACD,aAAa,YAAY,MAAM,WAAW,YAAY,CAS7B;EAC3B;EACA;EACA;EACA,WAAW,yBAAyB;EACpC,WAAW,yBAAyB;CACtC;AACF"}
|
|
@@ -3,16 +3,18 @@ import { useBookmarkActions } from "../stores/bookmarks/useBookmarkActions.js";
|
|
|
3
3
|
import { useBookmarks } from "../stores/bookmarks/useBookmarks.js";
|
|
4
4
|
import { useFieldActions } from "../stores/form/useFieldActions.js";
|
|
5
5
|
import { useCallback } from "react";
|
|
6
|
+
import { useAddressForChain } from "@lifi/widget-provider";
|
|
6
7
|
//#region src/hooks/useToAddressReset.ts
|
|
7
8
|
const useToAddressReset = () => {
|
|
8
9
|
const { requiredUI } = useWidgetConfig();
|
|
9
10
|
const { setFieldValue } = useFieldActions();
|
|
10
11
|
const { selectedBookmark } = useBookmarks();
|
|
11
12
|
const { setSelectedBookmark } = useBookmarkActions();
|
|
13
|
+
const { isAddressForChain } = useAddressForChain();
|
|
12
14
|
return { tryResetToAddress: useCallback((toChain) => {
|
|
13
15
|
const requiredToAddress = requiredUI?.toAddress;
|
|
14
|
-
const
|
|
15
|
-
if (!requiredToAddress && !
|
|
16
|
+
const bookmarkSatisfiesToChain = Boolean(selectedBookmark && isAddressForChain(selectedBookmark.address, toChain));
|
|
17
|
+
if (!requiredToAddress && !bookmarkSatisfiesToChain) {
|
|
16
18
|
setFieldValue("toAddress", "", { isTouched: true });
|
|
17
19
|
setSelectedBookmark();
|
|
18
20
|
}
|
|
@@ -20,7 +22,8 @@ const useToAddressReset = () => {
|
|
|
20
22
|
setFieldValue,
|
|
21
23
|
setSelectedBookmark,
|
|
22
24
|
requiredUI,
|
|
23
|
-
selectedBookmark
|
|
25
|
+
selectedBookmark,
|
|
26
|
+
isAddressForChain
|
|
24
27
|
]) };
|
|
25
28
|
};
|
|
26
29
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useToAddressReset.js","names":[],"sources":["../../../src/hooks/useToAddressReset.ts"],"sourcesContent":["import type { ExtendedChain } from '@lifi/sdk'\nimport { useCallback } from 'react'\nimport { useWidgetConfig } from '../providers/WidgetProvider/WidgetProvider.js'\nimport { useBookmarkActions } from '../stores/bookmarks/useBookmarkActions.js'\nimport { useBookmarks } from '../stores/bookmarks/useBookmarks.js'\nimport { useFieldActions } from '../stores/form/useFieldActions.js'\n\nexport const useToAddressReset = (): {\n tryResetToAddress: (toChain: ExtendedChain) => void\n} => {\n const { requiredUI } = useWidgetConfig()\n const { setFieldValue } = useFieldActions()\n const { selectedBookmark } = useBookmarks()\n const { setSelectedBookmark } = useBookmarkActions()\n\n const tryResetToAddress = useCallback(\n (toChain: ExtendedChain) => {\n const requiredToAddress = requiredUI?.toAddress\n\n const
|
|
1
|
+
{"version":3,"file":"useToAddressReset.js","names":[],"sources":["../../../src/hooks/useToAddressReset.ts"],"sourcesContent":["import type { ExtendedChain } from '@lifi/sdk'\nimport { useAddressForChain } from '@lifi/widget-provider'\nimport { useCallback } from 'react'\nimport { useWidgetConfig } from '../providers/WidgetProvider/WidgetProvider.js'\nimport { useBookmarkActions } from '../stores/bookmarks/useBookmarkActions.js'\nimport { useBookmarks } from '../stores/bookmarks/useBookmarks.js'\nimport { useFieldActions } from '../stores/form/useFieldActions.js'\n\nexport const useToAddressReset = (): {\n tryResetToAddress: (toChain: ExtendedChain) => void\n} => {\n const { requiredUI } = useWidgetConfig()\n const { setFieldValue } = useFieldActions()\n const { selectedBookmark } = useBookmarks()\n const { setSelectedBookmark } = useBookmarkActions()\n const { isAddressForChain } = useAddressForChain()\n\n const tryResetToAddress = useCallback(\n (toChain: ExtendedChain) => {\n const requiredToAddress = requiredUI?.toAddress\n\n const bookmarkSatisfiesToChain = Boolean(\n selectedBookmark && isAddressForChain(selectedBookmark.address, toChain)\n )\n\n const shouldResetToAddress =\n !requiredToAddress && !bookmarkSatisfiesToChain\n\n // We reset toAddress on each chain change if it's no longer required, ensuring that\n // switching chain types doesn't leave a stale toAddress from a different ecosystem.\n if (shouldResetToAddress) {\n setFieldValue('toAddress', '', { isTouched: true })\n setSelectedBookmark()\n }\n },\n [\n setFieldValue,\n setSelectedBookmark,\n requiredUI,\n selectedBookmark,\n isAddressForChain,\n ]\n )\n\n return {\n tryResetToAddress,\n }\n}\n"],"mappings":";;;;;;;AAQA,MAAa,0BAER;CACH,MAAM,EAAE,eAAe,gBAAgB;CACvC,MAAM,EAAE,kBAAkB,gBAAgB;CAC1C,MAAM,EAAE,qBAAqB,aAAa;CAC1C,MAAM,EAAE,wBAAwB,mBAAmB;CACnD,MAAM,EAAE,sBAAsB,mBAAmB;CA6BjD,OAAO,EACL,mBA5BwB,aACvB,YAA2B;EAC1B,MAAM,oBAAoB,YAAY;EAEtC,MAAM,2BAA2B,QAC/B,oBAAoB,kBAAkB,iBAAiB,SAAS,OAAO,CACzE;EAOA,IAJE,CAAC,qBAAqB,CAAC,0BAIC;GACxB,cAAc,aAAa,IAAI,EAAE,WAAW,KAAK,CAAC;GAClD,oBAAoB;EACtB;CACF,GACA;EACE;EACA;EACA;EACA;EACA;CACF,CAIgB,EAClB;AACF"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isDestinationOnlyChain } from "../utils/chainType.js";
|
|
1
2
|
import { useWidgetConfig } from "../providers/WidgetProvider/WidgetProvider.js";
|
|
2
3
|
import { useSDKClient } from "../providers/SDKClientProvider.js";
|
|
3
4
|
import { getQueryKey } from "../utils/queries.js";
|
|
@@ -8,10 +9,10 @@ import { useQuery, useQueryClient } from "@tanstack/react-query";
|
|
|
8
9
|
const defaultRefetchInterval = 3e4;
|
|
9
10
|
const useTokenBalance = (accountAddress, token) => {
|
|
10
11
|
const queryClient = useQueryClient();
|
|
11
|
-
const {
|
|
12
|
+
const { storageScopeKey } = useWidgetConfig();
|
|
12
13
|
const sdkClient = useSDKClient();
|
|
13
14
|
const tokenBalanceQueryKey = useMemo(() => [
|
|
14
|
-
getQueryKey("token-balance",
|
|
15
|
+
getQueryKey("token-balance", storageScopeKey),
|
|
15
16
|
accountAddress,
|
|
16
17
|
token?.chainId,
|
|
17
18
|
token?.address
|
|
@@ -19,7 +20,7 @@ const useTokenBalance = (accountAddress, token) => {
|
|
|
19
20
|
token?.address,
|
|
20
21
|
token?.chainId,
|
|
21
22
|
accountAddress,
|
|
22
|
-
|
|
23
|
+
storageScopeKey
|
|
23
24
|
]);
|
|
24
25
|
const { data, isLoading, refetch } = useQuery({
|
|
25
26
|
queryKey: tokenBalanceQueryKey,
|
|
@@ -33,7 +34,7 @@ const useTokenBalance = (accountAddress, token) => {
|
|
|
33
34
|
staleTime: defaultRefetchInterval
|
|
34
35
|
});
|
|
35
36
|
queryClient.setQueriesData({ queryKey: [
|
|
36
|
-
getQueryKey("token-balances",
|
|
37
|
+
getQueryKey("token-balances", storageScopeKey),
|
|
37
38
|
accountAddress,
|
|
38
39
|
tokenChainId
|
|
39
40
|
] }, (data) => {
|
|
@@ -52,7 +53,7 @@ const useTokenBalance = (accountAddress, token) => {
|
|
|
52
53
|
amount: tokenAmount
|
|
53
54
|
};
|
|
54
55
|
},
|
|
55
|
-
enabled: Boolean(accountAddress && token),
|
|
56
|
+
enabled: Boolean(accountAddress && token) && !isDestinationOnlyChain(token?.chainId),
|
|
56
57
|
refetchInterval: defaultRefetchInterval,
|
|
57
58
|
staleTime: defaultRefetchInterval
|
|
58
59
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useTokenBalance.js","names":[],"sources":["../../../src/hooks/useTokenBalance.ts"],"sourcesContent":["import {\n getTokenBalances,\n type SDKClient,\n type Token,\n type TokenAmount,\n} from '@lifi/sdk'\nimport { useQuery, useQueryClient } from '@tanstack/react-query'\nimport { useCallback, useMemo } from 'react'\nimport { useSDKClient } from '../providers/SDKClientProvider.js'\nimport { useWidgetConfig } from '../providers/WidgetProvider/WidgetProvider.js'\nimport { getQueryKey } from '../utils/queries.js'\n\nconst defaultRefetchInterval = 30_000\n\nexport const useTokenBalance = (\n accountAddress?: string,\n token?: Token\n): {\n token: TokenAmount | undefined\n isLoading: boolean\n refetch: () => void\n refetchNewBalance: () => void\n getTokenBalancesWithRetry: typeof getTokenBalancesWithRetry\n} => {\n const queryClient = useQueryClient()\n const {
|
|
1
|
+
{"version":3,"file":"useTokenBalance.js","names":[],"sources":["../../../src/hooks/useTokenBalance.ts"],"sourcesContent":["import {\n getTokenBalances,\n type SDKClient,\n type Token,\n type TokenAmount,\n} from '@lifi/sdk'\nimport { useQuery, useQueryClient } from '@tanstack/react-query'\nimport { useCallback, useMemo } from 'react'\nimport { useSDKClient } from '../providers/SDKClientProvider.js'\nimport { useWidgetConfig } from '../providers/WidgetProvider/WidgetProvider.js'\nimport { isDestinationOnlyChain } from '../utils/chainType.js'\nimport { getQueryKey } from '../utils/queries.js'\n\nconst defaultRefetchInterval = 30_000\n\nexport const useTokenBalance = (\n accountAddress?: string,\n token?: Token\n): {\n token: TokenAmount | undefined\n isLoading: boolean\n refetch: () => void\n refetchNewBalance: () => void\n getTokenBalancesWithRetry: typeof getTokenBalancesWithRetry\n} => {\n const queryClient = useQueryClient()\n const { storageScopeKey } = useWidgetConfig()\n const sdkClient = useSDKClient()\n\n const tokenBalanceQueryKey = useMemo(\n () =>\n [\n getQueryKey('token-balance', storageScopeKey),\n accountAddress,\n token?.chainId,\n token?.address,\n ] as const,\n [token?.address, token?.chainId, accountAddress, storageScopeKey]\n )\n\n const { data, isLoading, refetch } = useQuery({\n queryKey: tokenBalanceQueryKey,\n queryFn: async ({\n queryKey: [, accountAddress, tokenChainId, tokenAddress],\n }) => {\n const tokenBalances = await getTokenBalancesWithRetry(\n sdkClient,\n accountAddress as string,\n [token!]\n )\n\n if (!tokenBalances?.length) {\n throw new Error('Could not get tokens balance.')\n }\n\n const cachedTokenAmount =\n queryClient.getQueryData<TokenAmount>(tokenBalanceQueryKey)\n\n const tokenAmount = tokenBalances[0].amount\n\n if (cachedTokenAmount?.amount !== tokenAmount) {\n queryClient.setQueryDefaults(tokenBalanceQueryKey, {\n refetchInterval: defaultRefetchInterval,\n staleTime: defaultRefetchInterval,\n })\n }\n\n queryClient.setQueriesData<TokenAmount[]>(\n {\n queryKey: [\n getQueryKey('token-balances', storageScopeKey),\n accountAddress,\n tokenChainId,\n ],\n },\n (data) => {\n if (data) {\n const clonedData = [...data]\n const index = clonedData.findIndex(\n (dataToken) => dataToken.address === tokenAddress\n )\n clonedData[index] = {\n ...clonedData[index],\n amount: tokenAmount,\n }\n return clonedData\n }\n }\n )\n\n return {\n ...tokenBalances[0],\n amount: tokenAmount,\n } as TokenAmount\n },\n\n // No provider reads a balance on a destination-only chain, and a balance\n // without a block number is retried until the backoff gives up.\n enabled:\n Boolean(accountAddress && token) &&\n !isDestinationOnlyChain(token?.chainId),\n refetchInterval: defaultRefetchInterval,\n staleTime: defaultRefetchInterval,\n })\n\n const refetchNewBalance = useCallback(() => {\n queryClient.setQueryDefaults(tokenBalanceQueryKey, {\n refetchInterval: 250,\n staleTime: 250,\n })\n }, [queryClient, tokenBalanceQueryKey])\n\n return {\n token: data,\n isLoading,\n refetch,\n refetchNewBalance,\n getTokenBalancesWithRetry,\n }\n}\n\nexport const getTokenBalancesWithRetry = async (\n sdkClient: SDKClient,\n accountAddress: string,\n tokens: Token[],\n depth = 0\n): Promise<TokenAmount[] | undefined> => {\n try {\n const tokenBalances = await getTokenBalances(\n sdkClient,\n accountAddress as string,\n tokens\n )\n if (!tokenBalances.every((token) => token.blockNumber)) {\n if (depth > 10) {\n console.warn('Token balance backoff depth exceeded.')\n return undefined\n }\n await new Promise((resolve) => {\n setTimeout(resolve, 1.5 ** depth * 100)\n })\n return getTokenBalancesWithRetry(\n sdkClient,\n accountAddress,\n tokens,\n depth + 1\n )\n }\n return tokenBalances\n } catch (_error) {\n console.warn(_error)\n }\n}\n"],"mappings":";;;;;;;;AAaA,MAAM,yBAAyB;AAE/B,MAAa,mBACX,gBACA,UAOG;CACH,MAAM,cAAc,eAAe;CACnC,MAAM,EAAE,oBAAoB,gBAAgB;CAC5C,MAAM,YAAY,aAAa;CAE/B,MAAM,uBAAuB,cAEzB;EACE,YAAY,iBAAiB,eAAe;EAC5C;EACA,OAAO;EACP,OAAO;CACT,GACF;EAAC,OAAO;EAAS,OAAO;EAAS;EAAgB;CAAe,CAClE;CAEA,MAAM,EAAE,MAAM,WAAW,YAAY,SAAS;EAC5C,UAAU;EACV,SAAS,OAAO,EACd,UAAU,GAAG,gBAAgB,cAAc,oBACvC;GACJ,MAAM,gBAAgB,MAAM,0BAC1B,WACA,gBACA,CAAC,KAAM,CACT;GAEA,IAAI,CAAC,eAAe,QAClB,MAAM,IAAI,MAAM,+BAA+B;GAGjD,MAAM,oBACJ,YAAY,aAA0B,oBAAoB;GAE5D,MAAM,cAAc,cAAc,EAAE,CAAC;GAErC,IAAI,mBAAmB,WAAW,aAChC,YAAY,iBAAiB,sBAAsB;IACjD,iBAAiB;IACjB,WAAW;GACb,CAAC;GAGH,YAAY,eACV,EACE,UAAU;IACR,YAAY,kBAAkB,eAAe;IAC7C;IACA;GACF,EACF,IACC,SAAS;IACR,IAAI,MAAM;KACR,MAAM,aAAa,CAAC,GAAG,IAAI;KAC3B,MAAM,QAAQ,WAAW,WACtB,cAAc,UAAU,YAAY,YACvC;KACA,WAAW,SAAS;MAClB,GAAG,WAAW;MACd,QAAQ;KACV;KACA,OAAO;IACT;GACF,CACF;GAEA,OAAO;IACL,GAAG,cAAc;IACjB,QAAQ;GACV;EACF;EAIA,SACE,QAAQ,kBAAkB,KAAK,KAC/B,CAAC,uBAAuB,OAAO,OAAO;EACxC,iBAAiB;EACjB,WAAW;CACb,CAAC;CASD,OAAO;EACL,OAAO;EACP;EACA;EACA,mBAXwB,kBAAkB;GAC1C,YAAY,iBAAiB,sBAAsB;IACjD,iBAAiB;IACjB,WAAW;GACb,CAAC;EACH,GAAG,CAAC,aAAa,oBAAoB,CAMnB;EAChB;CACF;AACF;AAEA,MAAa,4BAA4B,OACvC,WACA,gBACA,QACA,QAAQ,MAC+B;CACvC,IAAI;EACF,MAAM,gBAAgB,MAAM,iBAC1B,WACA,gBACA,MACF;EACA,IAAI,CAAC,cAAc,OAAO,UAAU,MAAM,WAAW,GAAG;GACtD,IAAI,QAAQ,IAAI;IACd,QAAQ,KAAK,uCAAuC;IACpD;GACF;GACA,MAAM,IAAI,SAAS,YAAY;IAC7B,WAAW,SAAS,OAAO,QAAQ,GAAG;GACxC,CAAC;GACD,OAAO,0BACL,WACA,gBACA,QACA,QAAQ,CACV;EACF;EACA,OAAO;CACT,SAAS,QAAQ;EACf,QAAQ,KAAK,MAAM;CACrB;AACF"}
|
|
@@ -8,7 +8,7 @@ import { keepPreviousData, useQueries } from "@tanstack/react-query";
|
|
|
8
8
|
const defaultRefetchInterval = 32e3;
|
|
9
9
|
const balanceRevealTimeout = 2e3;
|
|
10
10
|
const useTokenBalancesQueries = (accountsWithTokens, isBalanceLoadingEnabled) => {
|
|
11
|
-
const {
|
|
11
|
+
const { storageScopeKey } = useWidgetConfig();
|
|
12
12
|
const sdkClient = useSDKClient();
|
|
13
13
|
const firstLoadStartRef = useRef(null);
|
|
14
14
|
const queryConfig = useMemo(() => {
|
|
@@ -17,7 +17,7 @@ const useTokenBalancesQueries = (accountsWithTokens, isBalanceLoadingEnabled) =>
|
|
|
17
17
|
const chainId = Number(chainIdStr);
|
|
18
18
|
return {
|
|
19
19
|
queryKey: [
|
|
20
|
-
getQueryKey("token-balances",
|
|
20
|
+
getQueryKey("token-balances", storageScopeKey),
|
|
21
21
|
accountAddress,
|
|
22
22
|
chainId,
|
|
23
23
|
tokens.length
|
|
@@ -36,7 +36,7 @@ const useTokenBalancesQueries = (accountsWithTokens, isBalanceLoadingEnabled) =>
|
|
|
36
36
|
}, [
|
|
37
37
|
accountsWithTokens,
|
|
38
38
|
isBalanceLoadingEnabled,
|
|
39
|
-
|
|
39
|
+
storageScopeKey,
|
|
40
40
|
sdkClient
|
|
41
41
|
]);
|
|
42
42
|
return useQueries({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useTokenBalancesQueries.js","names":[],"sources":["../../../src/hooks/useTokenBalancesQueries.ts"],"sourcesContent":["import { getTokenBalances, type TokenExtended } from '@lifi/sdk'\nimport { keepPreviousData, useQueries } from '@tanstack/react-query'\nimport { useMemo, useRef } from 'react'\nimport { useSDKClient } from '../providers/SDKClientProvider.js'\nimport { useWidgetConfig } from '../providers/WidgetProvider/WidgetProvider.js'\nimport type { TokenAmount, TokenAmountExtended } from '../types/token.js'\nimport { getQueryKey } from '../utils/queries.js'\n\nconst defaultRefetchInterval = 32_000\n// Max time to hold the skeleton before revealing balances in the multi-chain view.\n// Sits just below the typical full-settle time so the list reveals once, sorted,\n// instead of reordering as each chain streams in.\nconst balanceRevealTimeout = 2_000\n\nexport const useTokenBalancesQueries = (\n accountsWithTokens?: Record<string, Record<number, TokenExtended[]>>,\n isBalanceLoadingEnabled?: boolean\n): {\n data: TokenAmount[] | undefined\n isLoading: boolean\n isError: boolean\n} => {\n const {
|
|
1
|
+
{"version":3,"file":"useTokenBalancesQueries.js","names":[],"sources":["../../../src/hooks/useTokenBalancesQueries.ts"],"sourcesContent":["import { getTokenBalances, type TokenExtended } from '@lifi/sdk'\nimport { keepPreviousData, useQueries } from '@tanstack/react-query'\nimport { useMemo, useRef } from 'react'\nimport { useSDKClient } from '../providers/SDKClientProvider.js'\nimport { useWidgetConfig } from '../providers/WidgetProvider/WidgetProvider.js'\nimport type { TokenAmount, TokenAmountExtended } from '../types/token.js'\nimport { getQueryKey } from '../utils/queries.js'\n\nconst defaultRefetchInterval = 32_000\n// Max time to hold the skeleton before revealing balances in the multi-chain view.\n// Sits just below the typical full-settle time so the list reveals once, sorted,\n// instead of reordering as each chain streams in.\nconst balanceRevealTimeout = 2_000\n\nexport const useTokenBalancesQueries = (\n accountsWithTokens?: Record<string, Record<number, TokenExtended[]>>,\n isBalanceLoadingEnabled?: boolean\n): {\n data: TokenAmount[] | undefined\n isLoading: boolean\n isError: boolean\n} => {\n const { storageScopeKey } = useWidgetConfig()\n const sdkClient = useSDKClient()\n const firstLoadStartRef = useRef<number | null>(null)\n\n const queryConfig = useMemo(() => {\n if (!accountsWithTokens) {\n return []\n }\n return Object.entries(accountsWithTokens).flatMap(\n ([accountAddress, chainTokens]) =>\n Object.entries(chainTokens).map(([chainIdStr, tokens]) => {\n const chainId = Number(chainIdStr)\n return {\n queryKey: [\n getQueryKey('token-balances', storageScopeKey),\n accountAddress,\n chainId,\n tokens.length,\n ],\n queryFn: async (): Promise<TokenAmountExtended[]> => {\n if (!accountAddress || !tokens) {\n return []\n }\n return await getTokenBalances(sdkClient, accountAddress, tokens)\n },\n enabled: isBalanceLoadingEnabled,\n refetchInterval: defaultRefetchInterval,\n staleTime: defaultRefetchInterval,\n placeholderData: keepPreviousData,\n // Resolve a failed chain immediately instead of retrying past the reveal\n // window (retries would pop the chain in late and re-sort the list).\n retry: false,\n }\n })\n )\n }, [accountsWithTokens, isBalanceLoadingEnabled, storageScopeKey, sdkClient])\n\n const result = useQueries({\n queries: queryConfig,\n combine: (results) => {\n const now = Date.now()\n\n const hasLoadingQueries = results.some((result) => result.isLoading)\n if (hasLoadingQueries && firstLoadStartRef.current === null) {\n firstLoadStartRef.current = now\n }\n\n const allComplete = results.every(\n (result) => result.isSuccess || result.isError\n )\n\n // Reset the start time when all queries complete\n if (allComplete) {\n firstLoadStartRef.current = null\n }\n\n // Calculate time since first load started\n const timeSinceStart = firstLoadStartRef.current\n ? now - firstLoadStartRef.current\n : 0\n\n // Return results once all queries complete, or once the reveal timeout elapses\n const shouldReturnResults =\n allComplete || timeSinceStart >= balanceRevealTimeout\n\n if (shouldReturnResults) {\n const data: TokenAmount[] = results\n .flatMap((result) => result.data || [])\n .filter((token) => token.amount)\n return {\n data,\n isLoading: !allComplete,\n isError: results.some((result) => result.isError),\n }\n }\n\n return {\n data: undefined,\n isLoading: true,\n isError: false,\n }\n },\n })\n\n return result\n}\n"],"mappings":";;;;;;;AAQA,MAAM,yBAAyB;AAI/B,MAAM,uBAAuB;AAE7B,MAAa,2BACX,oBACA,4BAKG;CACH,MAAM,EAAE,oBAAoB,gBAAgB;CAC5C,MAAM,YAAY,aAAa;CAC/B,MAAM,oBAAoB,OAAsB,IAAI;CAEpD,MAAM,cAAc,cAAc;EAChC,IAAI,CAAC,oBACH,OAAO,CAAC;EAEV,OAAO,OAAO,QAAQ,kBAAkB,CAAC,CAAC,SACvC,CAAC,gBAAgB,iBAChB,OAAO,QAAQ,WAAW,CAAC,CAAC,KAAK,CAAC,YAAY,YAAY;GACxD,MAAM,UAAU,OAAO,UAAU;GACjC,OAAO;IACL,UAAU;KACR,YAAY,kBAAkB,eAAe;KAC7C;KACA;KACA,OAAO;IACT;IACA,SAAS,YAA4C;KACnD,IAAI,CAAC,kBAAkB,CAAC,QACtB,OAAO,CAAC;KAEV,OAAO,MAAM,iBAAiB,WAAW,gBAAgB,MAAM;IACjE;IACA,SAAS;IACT,iBAAiB;IACjB,WAAW;IACX,iBAAiB;IAGjB,OAAO;GACT;EACF,CAAC,CACL;CACF,GAAG;EAAC;EAAoB;EAAyB;EAAiB;CAAS,CAAC;CAiD5E,OA/Ce,WAAW;EACxB,SAAS;EACT,UAAU,YAAY;GACpB,MAAM,MAAM,KAAK,IAAI;GAGrB,IAD0B,QAAQ,MAAM,WAAW,OAAO,SACtC,KAAK,kBAAkB,YAAY,MACrD,kBAAkB,UAAU;GAG9B,MAAM,cAAc,QAAQ,OACzB,WAAW,OAAO,aAAa,OAAO,OACzC;GAGA,IAAI,aACF,kBAAkB,UAAU;GAI9B,MAAM,iBAAiB,kBAAkB,UACrC,MAAM,kBAAkB,UACxB;GAMJ,IAFE,eAAe,kBAAkB,sBAMjC,OAAO;IACL,MAJ0B,QACzB,SAAS,WAAW,OAAO,QAAQ,CAAC,CAAC,CAAC,CACtC,QAAQ,UAAU,MAAM,MAEtB;IACH,WAAW,CAAC;IACZ,SAAS,QAAQ,MAAM,WAAW,OAAO,OAAO;GAClD;GAGF,OAAO;IACL,MAAM,KAAA;IACN,WAAW;IACX,SAAS;GACX;EACF;CACF,CAEY;AACd"}
|
|
@@ -8,11 +8,11 @@ import { useQuery, useQueryClient } from "@tanstack/react-query";
|
|
|
8
8
|
//#region src/hooks/useTokenSearch.ts
|
|
9
9
|
const useTokenSearch = (chainId, tokenQuery, enabled, formType) => {
|
|
10
10
|
const queryClient = useQueryClient();
|
|
11
|
-
const { tokens: configTokens,
|
|
11
|
+
const { tokens: configTokens, storageScopeKey } = useWidgetConfig();
|
|
12
12
|
const sdkClient = useSDKClient();
|
|
13
13
|
const { data, isLoading } = useQuery({
|
|
14
14
|
queryKey: [
|
|
15
|
-
getQueryKey("token-search",
|
|
15
|
+
getQueryKey("token-search", storageScopeKey),
|
|
16
16
|
chainId,
|
|
17
17
|
tokenQuery
|
|
18
18
|
],
|
|
@@ -21,7 +21,7 @@ const useTokenSearch = (chainId, tokenQuery, enabled, formType) => {
|
|
|
21
21
|
if (token) {
|
|
22
22
|
const filteredConfigTokens = getChainTokenAllowSets(configTokens, token.chainId, formType);
|
|
23
23
|
if (!isFormItemAllowed(token, filteredConfigTokens, formType, (t) => t.address.toLowerCase())) return null;
|
|
24
|
-
queryClient.setQueriesData({ queryKey: [getQueryKey("tokens",
|
|
24
|
+
queryClient.setQueriesData({ queryKey: [getQueryKey("tokens", storageScopeKey)] }, (data) => {
|
|
25
25
|
if (!data) return data;
|
|
26
26
|
const chainTokens = data[chainId];
|
|
27
27
|
if (chainTokens?.some((t) => t.address.toLowerCase() === token.address.toLowerCase())) return data;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useTokenSearch.js","names":[],"sources":["../../../src/hooks/useTokenSearch.ts"],"sourcesContent":["import { type ChainId, getToken, type TokenExtended } from '@lifi/sdk'\nimport { useQuery, useQueryClient } from '@tanstack/react-query'\nimport { useSDKClient } from '../providers/SDKClientProvider.js'\nimport { useWidgetConfig } from '../providers/WidgetProvider/WidgetProvider.js'\nimport type { FormType } from '../stores/form/types.js'\nimport type { TokensByChain } from '../types/token.js'\nimport { isFormItemAllowed } from '../utils/item.js'\nimport { getQueryKey } from '../utils/queries.js'\nimport { getChainTokenAllowSets } from '../utils/token.js'\n\nexport const useTokenSearch = (\n chainId?: number,\n tokenQuery?: string,\n enabled?: boolean,\n formType?: FormType\n): {\n token: TokenExtended | undefined\n isLoading: boolean\n} => {\n const queryClient = useQueryClient()\n const { tokens: configTokens,
|
|
1
|
+
{"version":3,"file":"useTokenSearch.js","names":[],"sources":["../../../src/hooks/useTokenSearch.ts"],"sourcesContent":["import { type ChainId, getToken, type TokenExtended } from '@lifi/sdk'\nimport { useQuery, useQueryClient } from '@tanstack/react-query'\nimport { useSDKClient } from '../providers/SDKClientProvider.js'\nimport { useWidgetConfig } from '../providers/WidgetProvider/WidgetProvider.js'\nimport type { FormType } from '../stores/form/types.js'\nimport type { TokensByChain } from '../types/token.js'\nimport { isFormItemAllowed } from '../utils/item.js'\nimport { getQueryKey } from '../utils/queries.js'\nimport { getChainTokenAllowSets } from '../utils/token.js'\n\nexport const useTokenSearch = (\n chainId?: number,\n tokenQuery?: string,\n enabled?: boolean,\n formType?: FormType\n): {\n token: TokenExtended | undefined\n isLoading: boolean\n} => {\n const queryClient = useQueryClient()\n const { tokens: configTokens, storageScopeKey } = useWidgetConfig()\n const sdkClient = useSDKClient()\n\n const { data, isLoading } = useQuery({\n queryKey: [\n getQueryKey('token-search', storageScopeKey),\n chainId,\n tokenQuery,\n ],\n queryFn: async ({ queryKey: [, chainId, tokenQuery], signal }) => {\n const token = await getToken(\n sdkClient,\n chainId as ChainId,\n tokenQuery as string,\n {\n signal,\n }\n )\n\n if (token) {\n // Filter config tokens by chain before checking if token is allowed\n const filteredConfigTokens = getChainTokenAllowSets(\n configTokens,\n token.chainId,\n formType\n )\n\n // Return undefined if the token is denied\n if (\n !isFormItemAllowed(token, filteredConfigTokens, formType, (t) =>\n t.address.toLowerCase()\n )\n ) {\n return null\n }\n\n // Add token to main tokens cache\n queryClient.setQueriesData<TokensByChain>(\n { queryKey: [getQueryKey('tokens', storageScopeKey)] },\n (data) => {\n if (!data) {\n return data\n }\n const chainTokens = data[chainId as number]\n if (\n chainTokens?.some(\n (t) => t.address.toLowerCase() === token.address.toLowerCase()\n )\n ) {\n return data\n }\n return {\n ...data,\n [chainId as number]: [...(chainTokens ?? []), token],\n }\n }\n )\n }\n return token as TokenExtended\n },\n\n enabled: Boolean(chainId && tokenQuery && enabled),\n retry: false,\n })\n return {\n token: data || undefined,\n isLoading,\n }\n}\n"],"mappings":";;;;;;;;AAUA,MAAa,kBACX,SACA,YACA,SACA,aAIG;CACH,MAAM,cAAc,eAAe;CACnC,MAAM,EAAE,QAAQ,cAAc,oBAAoB,gBAAgB;CAClE,MAAM,YAAY,aAAa;CAE/B,MAAM,EAAE,MAAM,cAAc,SAAS;EACnC,UAAU;GACR,YAAY,gBAAgB,eAAe;GAC3C;GACA;EACF;EACA,SAAS,OAAO,EAAE,UAAU,GAAG,SAAS,aAAa,aAAa;GAChE,MAAM,QAAQ,MAAM,SAClB,WACA,SACA,YACA,EACE,OACF,CACF;GAEA,IAAI,OAAO;IAET,MAAM,uBAAuB,uBAC3B,cACA,MAAM,SACN,QACF;IAGA,IACE,CAAC,kBAAkB,OAAO,sBAAsB,WAAW,MACzD,EAAE,QAAQ,YAAY,CACxB,GAEA,OAAO;IAIT,YAAY,eACV,EAAE,UAAU,CAAC,YAAY,UAAU,eAAe,CAAC,EAAE,IACpD,SAAS;KACR,IAAI,CAAC,MACH,OAAO;KAET,MAAM,cAAc,KAAK;KACzB,IACE,aAAa,MACV,MAAM,EAAE,QAAQ,YAAY,MAAM,MAAM,QAAQ,YAAY,CAC/D,GAEA,OAAO;KAET,OAAO;MACL,GAAG;OACF,UAAoB,CAAC,GAAI,eAAe,CAAC,GAAI,KAAK;KACrD;IACF,CACF;GACF;GACA,OAAO;EACT;EAEA,SAAS,QAAQ,WAAW,cAAc,OAAO;EACjD,OAAO;CACT,CAAC;CACD,OAAO;EACL,OAAO,QAAQ,KAAA;EACf;CACF;AACF"}
|
|
@@ -1,25 +1,31 @@
|
|
|
1
1
|
import { isItemAllowed } from "../utils/item.js";
|
|
2
|
+
import { defaultChainIdsByType } from "../utils/chainType.js";
|
|
2
3
|
import { useWidgetConfig } from "../providers/WidgetProvider/WidgetProvider.js";
|
|
3
4
|
import { useSDKClient } from "../providers/SDKClientProvider.js";
|
|
4
|
-
import { getQueryKey } from "../utils/queries.js";
|
|
5
5
|
import { useAvailableChains } from "./useAvailableChains.js";
|
|
6
|
+
import { getQueryKey } from "../utils/queries.js";
|
|
6
7
|
import { filterAllowedTokens, getNativeTokenAddresses, mergeVerifiedWithSearchTokens } from "../utils/token.js";
|
|
7
8
|
import { isAddressQuery } from "../utils/address.js";
|
|
8
|
-
import { defaultChainIdsByType } from "../utils/chainType.js";
|
|
9
9
|
import { ChainType, getToken, getTokens } from "@lifi/sdk";
|
|
10
10
|
import { useMemo } from "react";
|
|
11
11
|
import { useQuery } from "@tanstack/react-query";
|
|
12
12
|
import { useChainTypeFromAddress } from "@lifi/widget-provider";
|
|
13
13
|
//#region src/hooks/useTokens.ts
|
|
14
14
|
const refetchInterval = 3e5;
|
|
15
|
+
const tokenListParams = {
|
|
16
|
+
orderBy: "volumeUSD24H",
|
|
17
|
+
extended: true,
|
|
18
|
+
limit: 1100,
|
|
19
|
+
minPriceUSD: 1e-6
|
|
20
|
+
};
|
|
15
21
|
const useTokens = (formType, search, chainId) => {
|
|
16
|
-
const { tokens: configTokens, chains: chainsConfig,
|
|
22
|
+
const { tokens: configTokens, chains: chainsConfig, storageScopeKey } = useWidgetConfig();
|
|
17
23
|
const sdkClient = useSDKClient();
|
|
18
24
|
const { getChainTypeFromTokenAddress } = useChainTypeFromAddress();
|
|
19
25
|
const trimmedSearch = search?.trim();
|
|
20
26
|
const isAddressSearch = useMemo(() => isAddressQuery(trimmedSearch, getChainTypeFromTokenAddress), [trimmedSearch, getChainTypeFromTokenAddress]);
|
|
21
27
|
const { data: verifiedTokens, isLoading } = useQuery({
|
|
22
|
-
queryKey: [getQueryKey("tokens",
|
|
28
|
+
queryKey: [getQueryKey("tokens", storageScopeKey)],
|
|
23
29
|
queryFn: async ({ signal }) => {
|
|
24
30
|
const chainTypes = [
|
|
25
31
|
ChainType.EVM,
|
|
@@ -30,11 +36,8 @@ const useTokens = (formType, search, chainId) => {
|
|
|
30
36
|
ChainType.STL
|
|
31
37
|
].filter((chainType) => isItemAllowed(chainType, chainsConfig?.types));
|
|
32
38
|
const tokensResponse = await getTokens(sdkClient, {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
extended: true,
|
|
36
|
-
limit: 1e3,
|
|
37
|
-
minPriceUSD: 1e-6
|
|
39
|
+
...tokenListParams,
|
|
40
|
+
chainTypes
|
|
38
41
|
}, { signal });
|
|
39
42
|
return Object.fromEntries(Object.entries(tokensResponse.tokens).map(([chainId, tokens]) => [chainId, tokens.map((token) => ({
|
|
40
43
|
...token,
|
|
@@ -46,7 +49,7 @@ const useTokens = (formType, search, chainId) => {
|
|
|
46
49
|
});
|
|
47
50
|
const { data: searchTokens, isLoading: isSearchLoading } = useQuery({
|
|
48
51
|
queryKey: [
|
|
49
|
-
getQueryKey("tokens-search",
|
|
52
|
+
getQueryKey("tokens-search", storageScopeKey),
|
|
50
53
|
trimmedSearch,
|
|
51
54
|
chainId,
|
|
52
55
|
isAddressSearch
|
|
@@ -62,12 +65,9 @@ const useTokens = (formType, search, chainId) => {
|
|
|
62
65
|
ChainType.STL
|
|
63
66
|
].filter((chainType) => isItemAllowed(chainType, chainsConfig?.types));
|
|
64
67
|
const tokensResponse = await getTokens(sdkClient, {
|
|
68
|
+
...tokenListParams,
|
|
65
69
|
chainTypes,
|
|
66
|
-
|
|
67
|
-
extended: true,
|
|
68
|
-
search: searchQuery,
|
|
69
|
-
limit: 1e3,
|
|
70
|
-
minPriceUSD: 1e-6
|
|
70
|
+
search: searchQuery
|
|
71
71
|
}, { signal });
|
|
72
72
|
if (searchQuery) {
|
|
73
73
|
const chainType = getChainTypeFromTokenAddress(searchQuery);
|