@lifi/widget 4.8.0 → 4.10.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.
Files changed (136) hide show
  1. package/README.md +26 -3
  2. package/dist/esm/components/AmountInputCard/AmountInputCardPair.js +5 -2
  3. package/dist/esm/components/AmountInputCard/AmountInputCardPair.js.map +1 -1
  4. package/dist/esm/components/SelectChainAndToken.js +5 -2
  5. package/dist/esm/components/SelectChainAndToken.js.map +1 -1
  6. package/dist/esm/components/SendToWallet/SendToWalletButton.js +5 -4
  7. package/dist/esm/components/SendToWallet/SendToWalletButton.js.map +1 -1
  8. package/dist/esm/components/TokenList/TokenDetailsSheet.js +5 -8
  9. package/dist/esm/components/TokenList/TokenDetailsSheet.js.map +1 -1
  10. package/dist/esm/components/TokenList/TokenDetailsSheetContent.js +30 -2
  11. package/dist/esm/components/TokenList/TokenDetailsSheetContent.js.map +1 -1
  12. package/dist/esm/components/TokenList/TokenListItem.js +36 -47
  13. package/dist/esm/components/TokenList/TokenListItem.js.map +1 -1
  14. package/dist/esm/components/TokenList/VirtualizedTokenList.d.ts.map +1 -1
  15. package/dist/esm/components/TokenList/VirtualizedTokenList.js +2 -2
  16. package/dist/esm/components/TokenList/VirtualizedTokenList.js.map +1 -1
  17. package/dist/esm/components/TokenList/tokenVerificationIcons.js +29 -0
  18. package/dist/esm/components/TokenList/tokenVerificationIcons.js.map +1 -0
  19. package/dist/esm/components/TokenList/useTokenSelect.d.ts.map +1 -1
  20. package/dist/esm/components/TokenList/useTokenSelect.js +10 -0
  21. package/dist/esm/components/TokenList/useTokenSelect.js.map +1 -1
  22. package/dist/esm/config/constants.js.map +1 -1
  23. package/dist/esm/config/version.d.ts +1 -1
  24. package/dist/esm/config/version.js +1 -1
  25. package/dist/esm/config/version.js.map +1 -1
  26. package/dist/esm/hooks/useAccountsBalancesData.js +5 -2
  27. package/dist/esm/hooks/useAccountsBalancesData.js.map +1 -1
  28. package/dist/esm/hooks/useAddressValidation.d.ts +3 -2
  29. package/dist/esm/hooks/useAddressValidation.d.ts.map +1 -1
  30. package/dist/esm/hooks/useAddressValidation.js +48 -21
  31. package/dist/esm/hooks/useAddressValidation.js.map +1 -1
  32. package/dist/esm/hooks/useGasRefuel.js +4 -1
  33. package/dist/esm/hooks/useGasRefuel.js.map +1 -1
  34. package/dist/esm/hooks/useRoutes.d.ts.map +1 -1
  35. package/dist/esm/hooks/useRoutes.js +11 -6
  36. package/dist/esm/hooks/useRoutes.js.map +1 -1
  37. package/dist/esm/hooks/useToAddressAutoPopulate.js +6 -8
  38. package/dist/esm/hooks/useToAddressAutoPopulate.js.map +1 -1
  39. package/dist/esm/hooks/useToAddressRequirements.d.ts +3 -2
  40. package/dist/esm/hooks/useToAddressRequirements.d.ts.map +1 -1
  41. package/dist/esm/hooks/useToAddressRequirements.js +8 -7
  42. package/dist/esm/hooks/useToAddressRequirements.js.map +1 -1
  43. package/dist/esm/hooks/useToAddressReset.js +6 -3
  44. package/dist/esm/hooks/useToAddressReset.js.map +1 -1
  45. package/dist/esm/hooks/useTokenBalance.js +2 -1
  46. package/dist/esm/hooks/useTokenBalance.js.map +1 -1
  47. package/dist/esm/hooks/useTokens.js +1 -1
  48. package/dist/esm/i18n/bn.json +7 -2
  49. package/dist/esm/i18n/de.json +7 -2
  50. package/dist/esm/i18n/en.json +7 -2
  51. package/dist/esm/i18n/es.json +7 -2
  52. package/dist/esm/i18n/fr.json +7 -2
  53. package/dist/esm/i18n/hi.json +7 -2
  54. package/dist/esm/i18n/id.json +7 -2
  55. package/dist/esm/i18n/it.json +7 -2
  56. package/dist/esm/i18n/ja.json +7 -2
  57. package/dist/esm/i18n/ko.json +7 -2
  58. package/dist/esm/i18n/pl.json +7 -2
  59. package/dist/esm/i18n/pt.json +7 -2
  60. package/dist/esm/i18n/th.json +7 -2
  61. package/dist/esm/i18n/tr.json +7 -2
  62. package/dist/esm/i18n/uk.json +7 -2
  63. package/dist/esm/i18n/vi.json +7 -2
  64. package/dist/esm/i18n/zh.json +7 -2
  65. package/dist/esm/pages/SendToWallet/BookmarkAddressSheet.js +7 -4
  66. package/dist/esm/pages/SendToWallet/BookmarkAddressSheet.js.map +1 -1
  67. package/dist/esm/pages/SendToWallet/BookmarksPage.js +35 -31
  68. package/dist/esm/pages/SendToWallet/BookmarksPage.js.map +1 -1
  69. package/dist/esm/pages/SendToWallet/ConnectedWalletsPage.js +4 -3
  70. package/dist/esm/pages/SendToWallet/ConnectedWalletsPage.js.map +1 -1
  71. package/dist/esm/pages/SendToWallet/RecentWalletsPage.js +43 -39
  72. package/dist/esm/pages/SendToWallet/RecentWalletsPage.js.map +1 -1
  73. package/dist/esm/pages/SendToWallet/SendToConfiguredWalletPage.js +32 -26
  74. package/dist/esm/pages/SendToWallet/SendToConfiguredWalletPage.js.map +1 -1
  75. package/dist/esm/pages/SendToWallet/SendToWalletPage.js +5 -10
  76. package/dist/esm/pages/SendToWallet/SendToWalletPage.js.map +1 -1
  77. package/dist/esm/providers/WalletProvider/WalletProvider.d.ts.map +1 -1
  78. package/dist/esm/providers/WalletProvider/WalletProvider.js +14 -2
  79. package/dist/esm/providers/WalletProvider/WalletProvider.js.map +1 -1
  80. package/dist/esm/providers/WidgetProvider/WidgetProvider.d.ts.map +1 -1
  81. package/dist/esm/providers/WidgetProvider/WidgetProvider.js +10 -14
  82. package/dist/esm/providers/WidgetProvider/WidgetProvider.js.map +1 -1
  83. package/dist/esm/stores/bookmarks/types.d.ts +3 -0
  84. package/dist/esm/stores/bookmarks/types.d.ts.map +1 -1
  85. package/dist/esm/stores/chains/ChainOrderStore.d.ts.map +1 -1
  86. package/dist/esm/stores/chains/ChainOrderStore.js +4 -1
  87. package/dist/esm/stores/chains/ChainOrderStore.js.map +1 -1
  88. package/dist/esm/stores/form/FormStore.js +3 -2
  89. package/dist/esm/stores/form/FormStore.js.map +1 -1
  90. package/dist/esm/stores/form/URLSearchParamsBuilder.js +7 -3
  91. package/dist/esm/stores/form/URLSearchParamsBuilder.js.map +1 -1
  92. package/dist/esm/stores/form/getDefaultValuesFromQueryString.js +4 -1
  93. package/dist/esm/stores/form/getDefaultValuesFromQueryString.js.map +1 -1
  94. package/dist/esm/utils/chainType.js +32 -1
  95. package/dist/esm/utils/chainType.js.map +1 -1
  96. package/dist/esm/utils/customReceiver.js +6 -1
  97. package/dist/esm/utils/customReceiver.js.map +1 -1
  98. package/dist/esm/utils/token.js +13 -1
  99. package/dist/esm/utils/token.js.map +1 -1
  100. package/package.json +7 -7
  101. package/src/components/AmountInputCard/AmountInputCardPair.tsx +6 -2
  102. package/src/components/SelectChainAndToken.tsx +5 -1
  103. package/src/components/SendToWallet/SendToWalletButton.tsx +13 -8
  104. package/src/components/TokenList/TokenDetailsSheet.tsx +5 -9
  105. package/src/components/TokenList/TokenDetailsSheetContent.tsx +46 -4
  106. package/src/components/TokenList/TokenListItem.tsx +44 -68
  107. package/src/components/TokenList/VirtualizedTokenList.tsx +3 -6
  108. package/src/components/TokenList/tokenVerificationIcons.ts +15 -0
  109. package/src/components/TokenList/types.ts +3 -11
  110. package/src/components/TokenList/useTokenSelect.ts +15 -0
  111. package/src/config/constants.ts +3 -0
  112. package/src/config/version.ts +1 -1
  113. package/src/hooks/useAccountsBalancesData.ts +6 -2
  114. package/src/hooks/useAddressValidation.ts +87 -32
  115. package/src/hooks/useGasRefuel.ts +11 -1
  116. package/src/hooks/useRoutes.ts +23 -18
  117. package/src/hooks/useToAddressAutoPopulate.ts +13 -17
  118. package/src/hooks/useToAddressRequirements.ts +19 -4
  119. package/src/hooks/useToAddressReset.ts +13 -4
  120. package/src/hooks/useTokenBalance.ts +6 -1
  121. package/src/pages/SendToWallet/BookmarkAddressSheet.tsx +5 -1
  122. package/src/pages/SendToWallet/BookmarksPage.tsx +42 -52
  123. package/src/pages/SendToWallet/ConnectedWalletsPage.tsx +4 -14
  124. package/src/pages/SendToWallet/RecentWalletsPage.tsx +59 -66
  125. package/src/pages/SendToWallet/SendToConfiguredWalletPage.tsx +45 -50
  126. package/src/pages/SendToWallet/SendToWalletPage.tsx +4 -16
  127. package/src/providers/WalletProvider/WalletProvider.tsx +28 -3
  128. package/src/providers/WidgetProvider/WidgetProvider.tsx +20 -19
  129. package/src/stores/bookmarks/types.ts +3 -0
  130. package/src/stores/chains/ChainOrderStore.tsx +4 -1
  131. package/src/stores/form/FormStore.tsx +2 -0
  132. package/src/stores/form/URLSearchParamsBuilder.tsx +4 -2
  133. package/src/stores/form/getDefaultValuesFromQueryString.ts +19 -0
  134. package/src/utils/chainType.ts +73 -1
  135. package/src/utils/customReceiver.ts +36 -0
  136. package/src/utils/token.ts +48 -0
@@ -8,7 +8,7 @@ import { useFieldValues } from "../stores/form/useFieldValues.js";
8
8
  import { useIntermediateRoutesStore } from "../stores/routes/useIntermediateRoutesStore.js";
9
9
  import { useSetExecutableRoute } from "../stores/routes/useSetExecutableRoute.js";
10
10
  import { useSettings } from "../stores/settings/useSettings.js";
11
- import { isCustomReceiverBlocked } from "../utils/customReceiver.js";
11
+ import { canQuoteWithToAddress, isCustomReceiverBlocked, isSignerInvalidReceiver } from "../utils/customReceiver.js";
12
12
  import { getQueryKey } from "../utils/queries.js";
13
13
  import { updateTokenInCache } from "../utils/token.js";
14
14
  import { useChain } from "./useChain.js";
@@ -19,7 +19,7 @@ import { useToken } from "./useToken.js";
19
19
  import { ChainType, LiFiErrorCode, convertQuoteToRoute, getContractCallsQuote, getRelayerQuote, getRoutes, parseUnits } from "@lifi/sdk";
20
20
  import { useCallback, useMemo } from "react";
21
21
  import { keepPreviousData, useQuery, useQueryClient } from "@tanstack/react-query";
22
- import { useChainTypeFromAddress, useEthereumContext } from "@lifi/widget-provider";
22
+ import { useAddressForChain, useEthereumContext } from "@lifi/widget-provider";
23
23
  import { useAccount } from "@lifi/wallet-management";
24
24
  //#region src/hooks/useRoutes.ts
25
25
  const refetchTime = 6e4;
@@ -49,16 +49,21 @@ const useRoutes = ({ observableRoute, quoteFromAddress, keepPreviousData: keepPr
49
49
  const { chain: fromChain } = useChain(fromChainId);
50
50
  const { chain: toChain } = useChain(toChainId);
51
51
  const { enabled: enabledRefuel, fromAmount: gasRecommendationFromAmount } = useGasRefuel();
52
- const { getChainTypeFromAddress } = useChainTypeFromAddress();
52
+ const { isAddressForChain } = useAddressForChain();
53
53
  const { isGaslessStep, disableMessageSigning } = useEthereumContext();
54
54
  const { account } = useAccount({ chainType: fromChain?.chainType });
55
55
  const { isBatchingSupported, isBatchingSupportedLoading } = useIsBatchingSupported(fromChain, account.address);
56
56
  const hasAmount = mode === "limit" ? Number(fromTokenAmount) > 0 && Number(toTokenAmount) > 0 : Number(fromTokenAmount) > 0 || Number(toTokenAmount) > 0;
57
57
  const customType = mode === "custom" ? modeOptions?.custom?.type : void 0;
58
58
  const contractCallQuoteEnabled = mode === "custom" && Boolean(contractCalls?.length) ? Boolean(account.address) : mode !== "custom" || customType === "deposit";
59
- const effectiveFromAddress = account.address ?? quoteFromAddress;
60
- const hasToAddressAndChainTypeSatisfied = !!toChain && !!toAddress && getChainTypeFromAddress(toAddress) === toChain.chainType;
61
- const isToAddressSatisfied = toAddress ? hasToAddressAndChainTypeSatisfied : true;
59
+ const effectiveFromAddress = isSignerInvalidReceiver({
60
+ signerAddress: account.address,
61
+ toAddress,
62
+ fromChain,
63
+ toChain,
64
+ isAddressForChain
65
+ }) ? quoteFromAddress : account.address ?? quoteFromAddress;
66
+ const isToAddressSatisfied = canQuoteWithToAddress(toAddress, toChain, isAddressForChain);
62
67
  const customReceiverBlocked = isCustomReceiverBlocked({
63
68
  fromChainType: fromChain?.chainType,
64
69
  toChainType: toChain?.chainType,
@@ -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 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 { 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', 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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"}
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 { useChainTypeFromAddress } from "@lifi/widget-provider";
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 { getChainTypeFromAddress } = useChainTypeFromAddress();
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 destinationChainType = formType === "from" ? selectedOppositeChain.chainType : selectedChain.chainType;
23
- if (selectedToAddress) {
24
- if (destinationChainType === getChainTypeFromAddress(selectedToAddress)) return;
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
- getChainTypeFromAddress
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 { useChainTypeFromAddress } 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 { getChainTypeFromAddress } = useChainTypeFromAddress()\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 // Identify the destination chain type based on the bridge direction ('from' or 'to')\n const destinationChainType =\n formType === 'from'\n ? selectedOppositeChain.chainType\n : selectedChain.chainType\n // If toAddress is already selected, verify that it matches the destination chain type\n if (selectedToAddress) {\n const selectedToAddressChainType =\n getChainTypeFromAddress(selectedToAddress)\n if (destinationChainType === selectedToAddressChainType) {\n return\n }\n }\n // Find connected account compatible with the destination chain type\n const destinationAccount = accounts?.find(\n (account) => account.chainType === destinationChainType\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 getChainTypeFromAddress,\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,4BAA4B,wBAAwB;CAE5D,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;EAGF,MAAM,uBACJ,aAAa,SACT,sBAAsB,YACtB,cAAc;EAEpB,IAAI,mBAGE;OAAA,yBADF,wBAAwB,iBAC4B,GACpD;EAAA;EAIJ,MAAM,qBAAqB,UAAU,MAClC,YAAY,QAAQ,cAAc,oBACrC;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
+ {"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 { ChainType, RouteExtended } from "@lifi/sdk";
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
- requiredToChainType: ChainType | undefined;
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;EACA,qBAAqB;EACrB;EACA;EACA;EACA;EACA;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 requiredToAddress = Boolean((isDifferentChainType || isCrossChainContractAddress || requiredUI?.toAddress) && !hiddenUI?.toAddress && !unsupportedToAddress);
34
- const accountNotDeployedAtDestination = Boolean(isFromContractAddress && !fromContractCodeHasDelegationIndicator && !isToContractAddress && fromAddress?.toLowerCase() === toAddress?.toLowerCase());
35
- const accountDeployedAtDestination = Boolean(isFromContractAddress && isToContractAddress && !fromContractCodeHasDelegationIndicator && fromAddress?.toLowerCase() === toAddress?.toLowerCase());
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
- requiredToChainType: toChain?.chainType,
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 { ChainType, RouteExtended } from '@lifi/sdk'\nimport { useAccount } from '@lifi/wallet-management'\nimport { 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 requiredToChainType: ChainType | undefined\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\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 const requiredToAddress = Boolean(\n (isDifferentChainType ||\n isCrossChainContractAddress ||\n requiredUI?.toAddress) &&\n !hiddenUI?.toAddress &&\n !unsupportedToAddress\n )\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 requiredToChainType: toChain?.chainType,\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,UAaG;CACH,MAAM,EAAE,YAAY,aAAa,gBAAgB;CACjD,MAAM,CAAC,iBAAiB,eAAe,iBAAiB,eACtD,aACA,WACA,WACF;CACA,MAAM,EAAE,+BAA+B,mBAAmB;CAE1D,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;CAED,MAAM,oBAAoB,SACvB,wBACC,+BACA,YAAY,cACZ,CAAC,UAAU,aACX,CAAC,oBACL;CAEA,MAAM,kCAAkC,QACtC,yBACE,CAAC,0CACD,CAAC,uBACD,aAAa,YAAY,MAAM,WAAW,YAAY,CAC1D;CAEA,MAAM,+BAA+B,QACnC,yBACE,uBACA,CAAC,0CACD,aAAa,YAAY,MAAM,WAAW,YAAY,CAC1D;CAEA,OAAO;EACL;EACA;EACA;EACA,qBAAqB,SAAS;EAC9B;EACA;EACA;EACA;EACA;EACA,WAAW,yBAAyB;EACpC,WAAW,yBAAyB;CACtC;AACF"}
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 bookmarkSatisfiesToChainType = selectedBookmark?.chainType === toChain?.chainType;
15
- if (!requiredToAddress && !bookmarkSatisfiesToChainType) {
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 bookmarkSatisfiesToChainType =\n selectedBookmark?.chainType === toChain?.chainType\n\n const shouldResetToAddress =\n !requiredToAddress && !bookmarkSatisfiesToChainType\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 [setFieldValue, setSelectedBookmark, requiredUI, selectedBookmark]\n )\n\n return {\n tryResetToAddress,\n }\n}\n"],"mappings":";;;;;;AAOA,MAAa,0BAER;CACH,MAAM,EAAE,eAAe,gBAAgB;CACvC,MAAM,EAAE,kBAAkB,gBAAgB;CAC1C,MAAM,EAAE,qBAAqB,aAAa;CAC1C,MAAM,EAAE,wBAAwB,mBAAmB;CAsBnD,OAAO,EACL,mBArBwB,aACvB,YAA2B;EAC1B,MAAM,oBAAoB,YAAY;EAEtC,MAAM,+BACJ,kBAAkB,cAAc,SAAS;EAO3C,IAJE,CAAC,qBAAqB,CAAC,8BAIC;GACxB,cAAc,aAAa,IAAI,EAAE,WAAW,KAAK,CAAC;GAClD,oBAAoB;EACtB;CACF,GACA;EAAC;EAAe;EAAqB;EAAY;CAAgB,CAIjD,EAClB;AACF"}
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";
@@ -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 { 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 enabled: Boolean(accountAddress && token),\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":";;;;;;;AAYA,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;EAEA,SAAS,QAAQ,kBAAkB,KAAK;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"}
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"}
@@ -1,11 +1,11 @@
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
5
  import { useAvailableChains } from "./useAvailableChains.js";
5
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";
@@ -195,7 +195,8 @@
195
195
  "walletAddressInvalid_chain": "",
196
196
  "walletAddressRequired": "ওয়ালেট ঠিকানা প্রয়োজন।",
197
197
  "walletChainTypeInvalid": "",
198
- "walletMismatch": ""
198
+ "walletMismatch": "",
199
+ "zcashAddressInvalid": ""
199
200
  }
200
201
  },
201
202
  "tooltip": {
@@ -363,6 +364,10 @@
363
364
  "currentPrice": "",
364
365
  "contractAddress": "",
365
366
  "marketCap": "",
366
- "volume24h": ""
367
+ "volume24h": "",
368
+ "status": "",
369
+ "statusFlagged": "",
370
+ "statusUnverified": "",
371
+ "statusVerified": ""
367
372
  }
368
373
  }
@@ -195,7 +195,8 @@
195
195
  "walletAddressInvalid_chain": "",
196
196
  "walletAddressRequired": "Wallet-Adresse ist erforderlich.",
197
197
  "walletChainTypeInvalid": "",
198
- "walletMismatch": ""
198
+ "walletMismatch": "",
199
+ "zcashAddressInvalid": ""
199
200
  }
200
201
  },
201
202
  "tooltip": {
@@ -363,6 +364,10 @@
363
364
  "currentPrice": "",
364
365
  "contractAddress": "",
365
366
  "marketCap": "",
366
- "volume24h": ""
367
+ "volume24h": "",
368
+ "status": "",
369
+ "statusFlagged": "",
370
+ "statusUnverified": "",
371
+ "statusVerified": ""
367
372
  }
368
373
  }
@@ -227,7 +227,8 @@
227
227
  "walletAddressInvalid_chain": "Wallet address or domain name is invalid for selected destination chain {{chainName}}",
228
228
  "walletAddressRequired": "Wallet address is required.",
229
229
  "walletChainTypeInvalid": "Wallet address doesn't match the selected destination chain {{chainName}}",
230
- "walletMismatch": "Wallet address mismatch"
230
+ "walletMismatch": "Wallet address mismatch",
231
+ "zcashAddressInvalid": "Enter a transparent Zcash address (t1 or t3) or a unified address (u1) with an Orchard receiver. Sapling (zs1) and TEX addresses are not supported."
231
232
  }
232
233
  },
233
234
  "tooltip": {
@@ -409,7 +410,11 @@
409
410
  "currentPrice": "Current price",
410
411
  "contractAddress": "Contract address",
411
412
  "marketCap": "Market cap",
412
- "volume24h": "Volume 24h"
413
+ "volume24h": "Volume 24h",
414
+ "status": "Status",
415
+ "statusFlagged": "Flagged as malicious by Hypernative. Trading this token can result in a total loss of funds.",
416
+ "statusUnverified": "Unverified by Hypernative",
417
+ "statusVerified": "Verified by Hypernative. False positives can occur, and we accept no liability for these alerts. Always do your own research before taking action."
413
418
  },
414
419
  "tags": {
415
420
  "connected": "Connected",
@@ -195,7 +195,8 @@
195
195
  "walletAddressInvalid_chain": "La dirección de la billetera o nombre de dominio no es válida para la cadena de destino seleccionada {{chainName}}",
196
196
  "walletAddressRequired": "Dirección de billetera es requerida.",
197
197
  "walletChainTypeInvalid": "La dirección de la billetera no coincide con la cadena de destino seleccionada {{chainName}}",
198
- "walletMismatch": "La dirección de la billetera no coincide"
198
+ "walletMismatch": "La dirección de la billetera no coincide",
199
+ "zcashAddressInvalid": ""
199
200
  }
200
201
  },
201
202
  "tooltip": {
@@ -363,6 +364,10 @@
363
364
  "currentPrice": "",
364
365
  "contractAddress": "",
365
366
  "marketCap": "",
366
- "volume24h": ""
367
+ "volume24h": "",
368
+ "status": "",
369
+ "statusFlagged": "",
370
+ "statusUnverified": "",
371
+ "statusVerified": ""
367
372
  }
368
373
  }
@@ -195,7 +195,8 @@
195
195
  "walletAddressInvalid_chain": "L'adresse du portefeuille ou le nom de domaine est invalide pour la chaîne de destination sélectionnée {{chainName}}",
196
196
  "walletAddressRequired": "L'adresse du portefeuille est nécessaire.",
197
197
  "walletChainTypeInvalid": "L'adresse du portefeuille ne correspond pas à la chaîne de destination sélectionnée - {{chainName}}",
198
- "walletMismatch": "Incompatibilité de l'adresse du portefeuille"
198
+ "walletMismatch": "Incompatibilité de l'adresse du portefeuille",
199
+ "zcashAddressInvalid": ""
199
200
  }
200
201
  },
201
202
  "tooltip": {
@@ -363,6 +364,10 @@
363
364
  "currentPrice": "",
364
365
  "contractAddress": "",
365
366
  "marketCap": "",
366
- "volume24h": ""
367
+ "volume24h": "",
368
+ "status": "",
369
+ "statusFlagged": "",
370
+ "statusUnverified": "",
371
+ "statusVerified": ""
367
372
  }
368
373
  }
@@ -195,7 +195,8 @@
195
195
  "walletAddressInvalid_chain": "",
196
196
  "walletAddressRequired": "",
197
197
  "walletChainTypeInvalid": "",
198
- "walletMismatch": ""
198
+ "walletMismatch": "",
199
+ "zcashAddressInvalid": ""
199
200
  }
200
201
  },
201
202
  "tooltip": {
@@ -363,6 +364,10 @@
363
364
  "currentPrice": "",
364
365
  "contractAddress": "",
365
366
  "marketCap": "",
366
- "volume24h": ""
367
+ "volume24h": "",
368
+ "status": "",
369
+ "statusFlagged": "",
370
+ "statusUnverified": "",
371
+ "statusVerified": ""
367
372
  }
368
373
  }