feat: add support for coinbase wallet with auto connect and metamask

This commit is contained in:
veganbeef
2025-05-08 10:47:59 -07:00
parent d8c53ceab7
commit eda896e478
6 changed files with 127 additions and 60 deletions

View File

@@ -8,6 +8,13 @@ import React from "react";
interface FrameContextType {
isSDKLoaded: boolean;
context: Context.FrameContext | undefined;
openUrl: (url: string) => Promise<void>;
close: () => Promise<void>;
added: boolean;
notificationDetails: FrameNotificationDetails | null;
lastEvent: string;
addFrame: () => Promise<void>;
addFrameResult: string;
}
const FrameContext = React.createContext<FrameContextType | undefined>(undefined);
@@ -20,10 +27,26 @@ export function useFrame() {
const [lastEvent, setLastEvent] = useState("");
const [addFrameResult, setAddFrameResult] = useState("");
// SDK actions only work in mini app clients, so this pattern supports browser actions as well
const openUrl = useCallback(async (url: string) => {
if (context) {
await sdk.actions.openUrl(url);
} else {
window.open(url, '_blank');
}
}, [context]);
const close = useCallback(async () => {
if (context) {
await sdk.actions.close();
} else {
window.close();
}
}, [context]);
const addFrame = useCallback(async () => {
try {
setNotificationDetails(null);
const result = await sdk.actions.addFrame();
if (result.notificationDetails) {
@@ -35,15 +58,11 @@ export function useFrame() {
: "Added, got no notification details"
);
} catch (error) {
if (error instanceof AddFrame.RejectedByUser) {
if (error instanceof AddFrame.RejectedByUser || error instanceof AddFrame.InvalidDomainManifest) {
setAddFrameResult(`Not added: ${error.message}`);
}else {
setAddFrameResult(`Error: ${error}`);
}
if (error instanceof AddFrame.InvalidDomainManifest) {
setAddFrameResult(`Not added: ${error.message}`);
}
setAddFrameResult(`Error: ${error}`);
}
}, []);
@@ -111,18 +130,28 @@ export function useFrame() {
}
}, [isSDKLoaded]);
return { isSDKLoaded, context, added, notificationDetails, lastEvent, addFrame, addFrameResult };
return {
isSDKLoaded,
context,
added,
notificationDetails,
lastEvent,
addFrame,
addFrameResult,
openUrl,
close,
};
}
export function FrameProvider({ children }: { children: React.ReactNode }) {
const { isSDKLoaded, context } = useFrame();
const frameContext = useFrame();
if (!isSDKLoaded) {
if (!frameContext.isSDKLoaded) {
return <div>Loading...</div>;
}
return (
<FrameContext.Provider value={{ isSDKLoaded, context }}>
<FrameContext.Provider value={frameContext}>
{children}
</FrameContext.Provider>
);

View File

@@ -4,6 +4,42 @@ import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { farcasterFrame } from "@farcaster/frame-wagmi-connector";
import { coinbaseWallet, metaMask } from 'wagmi/connectors';
import { APP_NAME, APP_ICON_URL, APP_URL } from "~/lib/constants";
import { useEffect, useState } from "react";
import { useConnect, useAccount } from "wagmi";
import React from "react";
// Custom hook for Coinbase Wallet detection and auto-connection
function useCoinbaseWalletAutoConnect() {
const [isCoinbaseWallet, setIsCoinbaseWallet] = useState(false);
const { connect, connectors } = useConnect();
const { isConnected } = useAccount();
useEffect(() => {
// Check if we're running in Coinbase Wallet
const checkCoinbaseWallet = () => {
const isInCoinbaseWallet = window.ethereum?.isCoinbaseWallet ||
window.ethereum?.isCoinbaseWalletExtension ||
window.ethereum?.isCoinbaseWalletBrowser;
setIsCoinbaseWallet(!!isInCoinbaseWallet);
};
checkCoinbaseWallet();
window.addEventListener('ethereum#initialized', checkCoinbaseWallet);
return () => {
window.removeEventListener('ethereum#initialized', checkCoinbaseWallet);
};
}, []);
useEffect(() => {
// Auto-connect if in Coinbase Wallet and not already connected
if (isCoinbaseWallet && !isConnected) {
connect({ connector: connectors[1] }); // Coinbase Wallet connector
}
}, [isCoinbaseWallet, isConnected, connect, connectors]);
return isCoinbaseWallet;
}
export const config = createConfig({
chains: [base, optimism, mainnet, degen, unichain],
@@ -32,10 +68,20 @@ export const config = createConfig({
const queryClient = new QueryClient();
// Wrapper component that provides Coinbase Wallet auto-connection
function CoinbaseWalletAutoConnect({ children }: { children: React.ReactNode }) {
useCoinbaseWalletAutoConnect();
return <>{children}</>;
}
export default function Provider({ children }: { children: React.ReactNode }) {
return (
<WagmiProvider config={config}>
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
<QueryClientProvider client={queryClient}>
<CoinbaseWalletAutoConnect>
{children}
</CoinbaseWalletAutoConnect>
</QueryClientProvider>
</WagmiProvider>
);
}