diff --git a/.claude/settings.local.json b/.claude/settings.local.json index b8092c79..bdaef3f3 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -16,7 +16,8 @@ "Bash(node:*)", "Bash(npx tsc:*)", "Bash(pnpm add:*)", - "WebFetch(domain:www.heroui.com)" + "WebFetch(domain:www.heroui.com)", + "WebSearch" ], "deny": [] } diff --git a/app/layout.tsx b/app/layout.tsx index e94421fc..69471197 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -2,6 +2,7 @@ import './global.css'; import GoogleAnalytics from '@/components/GoogleAnalytics/GoogleAnalytics'; import { ClientProviders } from '@/components/providers/ClientProviders'; +import { QueryProvider } from '@/components/providers/QueryProvider'; import RiskNotificationModal from '@/components/RiskNotificationModal'; import OnchainProviders from '@/OnchainProviders'; @@ -30,12 +31,14 @@ export default function RootLayout({ children }: { children: React.ReactNode }) > - - - {children} - - - + + + + {children} + + + + diff --git a/src/OnchainProviders.tsx b/src/OnchainProviders.tsx index 348da33b..ae69556a 100644 --- a/src/OnchainProviders.tsx +++ b/src/OnchainProviders.tsx @@ -1,8 +1,7 @@ 'use client'; -import { ReactNode, useMemo } from 'react'; +import { ReactNode } from 'react'; import { RainbowKitProvider, darkTheme, lightTheme } from '@rainbow-me/rainbowkit'; -import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { WagmiProvider } from 'wagmi'; import { createWagmiConfig } from '@/store/createWagmiConfig'; import { ConnectRedirectProvider } from './components/providers/ConnectRedirectProvider'; @@ -10,68 +9,45 @@ import { CustomRpcProvider, useCustomRpcContext } from './components/providers/C type Props = { children: ReactNode }; -const queryClient = new QueryClient({ - defaultOptions: { - queries: { - retry: (failureCount, error) => { - // Don't retry on GraphQL errors, network errors, or client errors - if ( - error?.message?.includes('GraphQL') || - error?.message?.includes('Network response was not ok') - ) { - return false; - } - // Retry up to 2 times for other errors - return failureCount < 2; - }, - retryDelay: (attemptIndex) => Math.min(1000 * 2 ** attemptIndex, 30000), - // Prevent queries from throwing and crashing the app - throwOnError: false, - }, - mutations: { - // Prevent mutations from throwing and crashing the app - throwOnError: false, - }, - }, -}); const projectId = process.env.NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID ?? ''; +if (!projectId) { + if (process.env.NODE_ENV !== 'production') { + console.warn('NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID is not set; WagmiProvider disabled.'); + } + throw new Error('NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID is not set'); +} -// eslint-disable-next-line @typescript-eslint/promise-function-async -function WagmiConfigProvider({ children }: Props) { - const { customRpcUrls, rpcConfigVersion } = useCustomRpcContext(); - - // Create wagmi config with custom RPCs, recreating when RPC config changes - const wagmiConfig = useMemo(() => { - return createWagmiConfig(projectId, customRpcUrls); - }, [customRpcUrls, rpcConfigVersion]); +const staticWagmiConfig = createWagmiConfig(projectId); - if (!projectId) { - if (process.env.NODE_ENV !== 'production') { - console.warn('NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID is not set; WagmiProvider disabled.'); - } - return children; - } +function WagmiConfigProvider({ children }: Props) { + const { customRpcUrls } = useCustomRpcContext(); + + // Only use dynamic config when custom RPCs are explicitly set + const hasCustomRpcs = Object.keys(customRpcUrls).length > 0; + const wagmiConfig = hasCustomRpcs + ? createWagmiConfig(projectId, customRpcUrls) + : staticWagmiConfig; return ( - - - - {children} - - + + + + {children} + + ); } diff --git a/src/components/layout/header/Navbar.tsx b/src/components/layout/header/Navbar.tsx index e5106492..85e7db22 100644 --- a/src/components/layout/header/Navbar.tsx +++ b/src/components/layout/header/Navbar.tsx @@ -102,7 +102,11 @@ export function Navbar() { )} - + {error &&

{error}

} diff --git a/src/hooks/useTransactionWithToast.tsx b/src/hooks/useTransactionWithToast.tsx index c34a8465..33c49b02 100644 --- a/src/hooks/useTransactionWithToast.tsx +++ b/src/hooks/useTransactionWithToast.tsx @@ -33,12 +33,10 @@ export function useTransactionWithToast({ error: txError, sendTransactionAsync, } = useSendTransaction(); - const { isLoading: isConfirming, isSuccess: isConfirmed } = useWaitForTransactionReceipt({ + const { isLoading: isConfirming, isSuccess: isConfirmed, isError } = useWaitForTransactionReceipt({ hash, }); - console.log('isConfirming', isConfirming); - const onClick = useCallback(() => { if (hash) { // if chainId is not supported, use 1 @@ -58,7 +56,7 @@ export function useTransactionWithToast({ }, ); } - }, [isConfirming, pendingText, pendingDescription, toastId, onClick]); + }, [isConfirming, pendingText, pendingDescription, toastId, onClick, hash]); useEffect(() => { if (isConfirmed) { @@ -80,9 +78,9 @@ export function useTransactionWithToast({ onSuccess(); } } - if (txError) { + if (isError || txError) { toast.update(toastId, { - render: , + render: , type: 'error', isLoading: false, autoClose: 5000, @@ -91,7 +89,9 @@ export function useTransactionWithToast({ }); } }, [ + hash, isConfirmed, + isError, txError, successText, successDescription, @@ -99,8 +99,6 @@ export function useTransactionWithToast({ toastId, onClick, onSuccess, - toast, - hash, ]); return { sendTransactionAsync, sendTransaction, isConfirming, isConfirmed };