diff --git a/.changeset/sour-flies-post.md b/.changeset/sour-flies-post.md new file mode 100644 index 00000000000..42d5d2e51f4 --- /dev/null +++ b/.changeset/sour-flies-post.md @@ -0,0 +1,5 @@ +--- +"thirdweb": patch +--- + +Preload wallet balances on pay embed diff --git a/packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/BuyScreen.tsx b/packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/BuyScreen.tsx index 9e101e11263..d7687678040 100644 --- a/packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/BuyScreen.tsx +++ b/packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/BuyScreen.tsx @@ -63,6 +63,7 @@ import { SwapFlow } from "./swap/SwapFlow.js"; import { SwapScreenContent } from "./swap/SwapScreenContent.js"; import { TokenSelectorScreen } from "./swap/TokenSelectorScreen.js"; import { TransferFlow } from "./swap/TransferFlow.js"; +import { useWalletsAndBalances } from "./swap/fetchBalancesForWallet.js"; import { type SupportedChainAndTokens, useBuySupportedDestinations, @@ -218,6 +219,15 @@ function BuyScreenContent(props: BuyScreenContentProps) { ); }, [props.supportedTokens, supportedSourcesQuery.data, payOptions]); + // preload wallets and balances + useWalletsAndBalances({ + client: props.client, + sourceSupportedTokens: sourceSupportedTokens || [], + toChain: toChain, + toToken: toToken, + mode: payOptions.mode, + }); + const { fromChain, setFromChain, fromToken, setFromToken } = useFromTokenSelectionStates({ payOptions, diff --git a/packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/swap/TokenSelectorScreen.tsx b/packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/swap/TokenSelectorScreen.tsx index c29e1fe02e8..167b7d8420d 100644 --- a/packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/swap/TokenSelectorScreen.tsx +++ b/packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/swap/TokenSelectorScreen.tsx @@ -4,7 +4,6 @@ import { ChevronRightIcon, Cross2Icon, } from "@radix-ui/react-icons"; -import { useQuery } from "@tanstack/react-query"; import { trackPayEvent } from "../../../../../../../analytics/track/pay.js"; import type { Chain } from "../../../../../../../chains/types.js"; import type { ThirdwebClient } from "../../../../../../../client/client.js"; @@ -43,14 +42,9 @@ import { FiatValue } from "./FiatValue.js"; import { WalletRow } from "./WalletRow.js"; import { type TokenBalance, - fetchBalancesForWallet, + useWalletsAndBalances, } from "./fetchBalancesForWallet.js"; -type WalletKey = { - id: WalletId; - address: string; -}; - export function TokenSelectorScreen(props: { client: ThirdwebClient; sourceTokens: SupportedTokens | undefined; @@ -71,46 +65,12 @@ export function TokenSelectorScreen(props: { const chainInfo = useChainMetadata(props.toChain); const theme = useCustomTheme(); - const walletsAndBalances = useQuery({ - queryKey: [ - "wallets-and-balances", - props.sourceSupportedTokens, - props.toChain.id, - props.toToken, - props.tokenAmount, - props.mode, - activeAccount?.address, - connectedWallets.map((w) => w.getAccount()?.address), - ], - enabled: !!props.sourceSupportedTokens && !!chainInfo.data, - queryFn: async () => { - const entries = await Promise.all( - connectedWallets.map(async (wallet) => { - const balances = await fetchBalancesForWallet({ - wallet, - accountAddress: activeAccount?.address, - sourceSupportedTokens: props.sourceSupportedTokens || [], - toChain: props.toChain, - toToken: props.toToken, - tokenAmount: props.tokenAmount, - mode: props.mode, - client: props.client, - }); - return [ - { - id: wallet.id, - address: wallet.getAccount()?.address || "", - } as WalletKey, - balances, - ] as const; - }), - ); - const map = new Map(); - for (const entry of entries) { - map.set(entry[0], entry[1]); - } - return map; - }, + const walletsAndBalances = useWalletsAndBalances({ + client: props.client, + sourceSupportedTokens: props.sourceSupportedTokens || [], + toChain: props.toChain, + toToken: props.toToken, + mode: props.mode, }); if ( diff --git a/packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/swap/fetchBalancesForWallet.ts b/packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/swap/fetchBalancesForWallet.tsx similarity index 71% rename from packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/swap/fetchBalancesForWallet.ts rename to packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/swap/fetchBalancesForWallet.tsx index 3233ad2daa5..74ca500bc6f 100644 --- a/packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/swap/fetchBalancesForWallet.ts +++ b/packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/swap/fetchBalancesForWallet.tsx @@ -1,3 +1,4 @@ +import { useQuery } from "@tanstack/react-query"; import type { Chain } from "../../../../../../../chains/types.js"; import { getCachedChain } from "../../../../../../../chains/utils.js"; import type { ThirdwebClient } from "../../../../../../../client/client.js"; @@ -9,7 +10,11 @@ import { type GetWalletBalanceResult, getWalletBalance, } from "../../../../../../../wallets/utils/getWalletBalance.js"; +import type { WalletId } from "../../../../../../../wallets/wallet-types.js"; import type { PayUIOptions } from "../../../../../../core/hooks/connection/ConnectButtonProps.js"; +import { useChainMetadata } from "../../../../../../core/hooks/others/useChainQuery.js"; +import { useActiveAccount } from "../../../../../../core/hooks/wallets/useActiveAccount.js"; +import { useConnectedWallets } from "../../../../../../core/hooks/wallets/useConnectedWallets.js"; import type { SupportedTokens, TokenInfo, @@ -32,7 +37,6 @@ type FetchBalancesParams = { sourceSupportedTokens: SupportedTokens; toChain: Chain; toToken: ERC20OrNativeToken; - tokenAmount: string; mode: PayUIOptions["mode"]; client: ThirdwebClient; }; @@ -43,13 +47,70 @@ export type TokenBalance = { token: TokenInfo; }; -export async function fetchBalancesForWallet({ +type WalletKey = { + id: WalletId; + address: string; +}; + +export function useWalletsAndBalances(props: { + sourceSupportedTokens: SupportedTokens; + toChain: Chain; + toToken: ERC20OrNativeToken; + mode: PayUIOptions["mode"]; + client: ThirdwebClient; +}) { + const activeAccount = useActiveAccount(); + const connectedWallets = useConnectedWallets(); + const chainInfo = useChainMetadata(props.toChain); + + return useQuery({ + queryKey: [ + "wallets-and-balances", + props.sourceSupportedTokens, + props.toChain.id, + props.toToken, + props.mode, + activeAccount?.address, + connectedWallets.map((w) => w.getAccount()?.address), + ], + enabled: + !!props.sourceSupportedTokens && !!chainInfo.data && !!activeAccount, + queryFn: async () => { + const entries = await Promise.all( + connectedWallets.map(async (wallet) => { + const balances = await fetchBalancesForWallet({ + wallet, + accountAddress: activeAccount?.address, + sourceSupportedTokens: props.sourceSupportedTokens || [], + toChain: props.toChain, + toToken: props.toToken, + mode: props.mode, + client: props.client, + }); + return [ + { + id: wallet.id, + address: wallet.getAccount()?.address || "", + } as WalletKey, + balances, + ] as const; + }), + ); + const map = new Map(); + for (const entry of entries) { + map.set(entry[0], entry[1]); + } + return map; + }, + }); +} + +async function fetchBalancesForWallet({ wallet, accountAddress, sourceSupportedTokens, toChain, toToken, - tokenAmount, mode, client, }: FetchBalancesParams): Promise { @@ -133,7 +194,7 @@ export async function fetchBalancesForWallet({ b.chain.id === chainId && b.token.address.toLowerCase() === token.address.toLowerCase(), ); - if (!isNative && !isAlreadyFetched) { + if (isAlreadyFetched && !isNative) { // ERC20 on insight-enabled chain already handled by insight call continue; } @@ -148,11 +209,12 @@ export async function fetchBalancesForWallet({ }); const include = - token.address === destinationToken.address && + token.address.toLowerCase() === + destinationToken.address.toLowerCase() && chain.id === toChain.id - ? mode === "fund_wallet" && account.address === accountAddress - ? false - : Number(balance.displayValue) > Number(tokenAmount) + ? !( + mode === "fund_wallet" && account.address === accountAddress + ) : balance.value > 0n; if (include) {