]*>Request exceeds defined limit\.<\/div><\/div>$/)
+})
diff --git a/src/components/guides/Demo.tsx b/src/components/guides/Demo.tsx
index b00d8267f..7e5865ea2 100644
--- a/src/components/guides/Demo.tsx
+++ b/src/components/guides/Demo.tsx
@@ -1,8 +1,17 @@
'use client'
+import { useQueryClient } from '@tanstack/react-query'
import * as React from 'react'
-import type { Address, BaseError } from 'viem'
+import { type Address, type BaseError, isAddressEqual } from 'viem'
import { tempoModerato } from 'viem/chains'
-import { useAccount, useConnect, useConnections, useDisconnect } from 'wagmi'
+import { Abis } from 'viem/tempo'
+import {
+ useAccount,
+ useConnect,
+ useConnections,
+ useDisconnect,
+ useReadContract,
+ useWatchContractEvent,
+} from 'wagmi'
import { Hooks } from 'wagmi/tempo'
import { cx, type Props as StyleProps } from 'zyzz'
import LucideCheck from '~icons/lucide/check'
@@ -217,41 +226,19 @@ export function Container(
export namespace Container {
function BalancesFooterItem(props: { address: Address; token: Address }) {
const { address, token } = props
- const {
- data: balance,
- isPending: balanceIsPending,
- refetch: balanceRefetch,
- } = Hooks.token.useGetBalance({
+ const { data: balance, isPending: balanceIsPending } = Hooks.token.useGetBalance({
account: address,
token,
})
- const { data: metadata, isPending: metadataIsPending } = Hooks.token.useGetMetadata({
- token,
- })
- const onTransfer = React.useCallback(() => {
- void balanceRefetch()
- }, [balanceRefetch])
-
- Hooks.token.useWatchTransfer({
- token,
- args: {
- to: address,
- },
- onTransfer,
- enabled: !!address,
- })
-
- Hooks.token.useWatchTransfer({
- token,
- args: {
- from: address,
- },
- onTransfer,
- enabled: !!address,
+ // The footer shows only the symbol; full token metadata costs one RPC call per field.
+ const { data: symbol, isPending: symbolIsPending } = useReadContract({
+ address: token,
+ abi: Abis.tip20,
+ functionName: 'symbol',
})
- const isPending = balanceIsPending || metadataIsPending
- const isUndefined = balance === undefined || metadata === undefined
+ const isPending = balanceIsPending || symbolIsPending
+ const isUndefined = balance === undefined || symbol === undefined
return (
@@ -260,16 +247,46 @@ export namespace Container {
) : (
{balance.formatted}
- {metadata.symbol}
+ {symbol}
)}
)
}
+ // One filter per transfer direction covers every token, so a footer with five balances polls
+ // the public RPC as often as one with a single balance and stays under its per-client limit.
+ function useWatchBalanceTransfers(address: Address | undefined, tokens: Address[]) {
+ const queryClient = useQueryClient()
+ const onLogs = (logs: readonly { address: Address }[]) => {
+ for (const token of tokens)
+ if (logs.some((log) => isAddressEqual(log.address, token)))
+ queryClient.invalidateQueries({ queryKey: ['getBalance', { account: address, token }] })
+ }
+
+ useWatchContractEvent({
+ address: tokens,
+ abi: Abis.tip20,
+ eventName: 'Transfer',
+ args: { to: address },
+ enabled: !!address,
+ onLogs,
+ })
+
+ useWatchContractEvent({
+ address: tokens,
+ abi: Abis.tip20,
+ eventName: 'Transfer',
+ args: { from: address },
+ enabled: !!address,
+ onLogs,
+ })
+ }
+
export function BalancesFooter(props: { address?: string | undefined; tokens: Address[] }) {
const { address, tokens } = props
const personalBalanceLabel = tokens.length > 1 ? 'Personal balances' : 'Personal balance'
+ useWatchBalanceTransfers(address as Address | undefined, tokens)
return (