'use client'; import { Dialog } from '@/internal/components/Dialog'; import { CloseSvg } from '@/internal/svg/closeSvg'; import { coinbaseWalletSvg } from '@/internal/svg/coinbaseWalletSvg'; import { frameWalletSvg } from '@/internal/svg/frameWalletSvg'; import { metamaskSvg } from '@/internal/svg/metamaskSvg'; import { phantomSvg } from '@/internal/svg/phantomSvg'; import { rabbySvg } from '@/internal/svg/rabbySvg'; import { trustWalletSvg } from '@/internal/svg/trustWalletSvg'; import { border, cn, pressable, text } from '@/styles/theme'; import { useOnchainKit } from '@/useOnchainKit'; import { useCallback } from 'react'; import { useConnect } from 'wagmi'; import { baseAccount, coinbaseWallet, injected, metaMask, } from 'wagmi/connectors'; import { checkWalletAndRedirect } from '../utils/checkWalletAndRedirect'; import { BaseAccountSvg } from '@/internal/svg/baseAccountSvg'; type WalletProviderOption = { id: string; name: string; icon: React.ReactNode; connector: () => void; enabled: boolean; }; type WalletModalProps = { isOpen: boolean; onClose: () => void; className?: string; onError?: (error: Error) => void; }; // eslint-disable-next-line complexity export function WalletModal({ className, isOpen, onClose, onError, }: WalletModalProps) { const { connect } = useConnect(); const { config } = useOnchainKit(); const appLogo = config?.appearance?.logo ?? undefined; const appName = config?.appearance?.name ?? undefined; const privacyPolicyUrl = config?.wallet?.privacyUrl ?? undefined; const termsOfServiceUrl = config?.wallet?.termsUrl ?? undefined; const supportedWallets = config?.wallet?.supportedWallets ?? { rabby: false, trust: false, frame: false, }; const handleBaseAccountConnection = useCallback(() => { try { connect({ connector: baseAccount({ appName, appLogoUrl: appLogo, }), }); onClose(); } catch (error) { console.error('Base Account connection error:', error); if (onError) { onError( error instanceof Error ? error : new Error('Failed to connect wallet'), ); } } }, [appName, appLogo, connect, onClose, onError]); const handleCoinbaseWalletConnection = useCallback(() => { try { const cbConnector = coinbaseWallet({ preference: 'all', appName, appLogoUrl: appLogo, }); connect({ connector: cbConnector }); onClose(); } catch (error) { console.error('Coinbase Wallet connection error:', error); if (onError) { onError( error instanceof Error ? error : new Error('Failed to connect wallet'), ); } } }, [appName, appLogo, connect, onClose, onError]); const handleMetaMaskConnection = useCallback(() => { try { const metamaskConnector = metaMask({ dappMetadata: { name: appName || 'OnchainKit App', url: window.location.origin, iconUrl: appLogo, }, }); connect({ connector: metamaskConnector }); onClose(); } catch (error) { console.error('MetaMask connection error:', error); onError?.( error instanceof Error ? error : new Error('Failed to connect wallet'), ); } }, [connect, onClose, onError, appName, appLogo]); const handlePhantomConnection = useCallback(() => { try { if (!checkWalletAndRedirect('phantom')) { onClose(); return; } const phantomConnector = injected({ target: 'phantom', }); connect({ connector: phantomConnector }); onClose(); } catch (error) { console.error('Phantom connection error:', error); onError?.( error instanceof Error ? error : new Error('Failed to connect wallet'), ); } }, [connect, onClose, onError]); const handleRabbyConnection = useCallback(() => { try { if (!checkWalletAndRedirect('rabby')) { onClose(); return; } const rabbyConnector = injected({ target: 'rabby', }); connect({ connector: rabbyConnector }); onClose(); } catch (error) { console.error('Rabby connection error:', error); onError?.( error instanceof Error ? error : new Error('Failed to connect wallet'), ); } }, [connect, onClose, onError]); const handleTrustWalletConnection = useCallback(() => { try { if (!checkWalletAndRedirect('trust')) { onClose(); return; } const trustConnector = injected({ target: 'trust', }); connect({ connector: trustConnector }); onClose(); } catch (error) { console.error('Trust Wallet connection error:', error); onError?.( error instanceof Error ? error : new Error('Failed to connect wallet'), ); onClose(); } }, [connect, onClose, onError]); /** * Frame wallet doesn't respond properly to injected({ target: 'frame' }) unlike other wallets. * Solution: Verify window.ethereum.isFrame first, then use untargeted injected() connector. * This ensures the Frame button only connects to Frame wallet. */ const handleFrameWalletConnection = useCallback(() => { try { if (!window.ethereum?.isFrame) { window.open('https://frame.sh/download', '_blank'); onClose(); return; } const frameConnector = injected(); connect({ connector: frameConnector }); onClose(); } catch (error) { console.error('Frame Wallet connection error:', error); onError?.( error instanceof Error ? error : new Error('Failed to connect wallet'), ); onClose(); } }, [connect, onClose, onError]); const availableWallets: WalletProviderOption[] = [ { id: 'coinbase', name: 'Coinbase Wallet', icon: coinbaseWalletSvg, connector: handleCoinbaseWalletConnection, enabled: true, }, { id: 'metamask', name: 'MetaMask', icon: metamaskSvg, connector: handleMetaMaskConnection, enabled: true, }, { id: 'phantom', name: 'Phantom', icon: phantomSvg, connector: handlePhantomConnection, enabled: true, }, { id: 'rabby', name: 'Rabby', icon: rabbySvg, connector: handleRabbyConnection, enabled: supportedWallets.rabby === true, }, { id: 'trust', name: 'Trust Wallet', icon: trustWalletSvg, connector: handleTrustWalletConnection, enabled: supportedWallets.trust === true, }, { id: 'frame', name: 'Frame', icon: frameWalletSvg, connector: handleFrameWalletConnection, enabled: supportedWallets.frame === true, }, ].filter((wallet) => wallet.enabled); return (
{(appLogo || appName) && (
{appLogo && (
{`${appName
)} {appName && (

{appName}

)}
)}
or use another wallet
{availableWallets.map((wallet) => ( ))}
By connecting a wallet, you agree to our {termsOfServiceUrl && ( Terms of Service )}{' '} {termsOfServiceUrl && privacyPolicyUrl && 'and'}{' '} {privacyPolicyUrl && ( Privacy Policy )} .
); }