From f2adf11a2b89f133f0b58b9cf976e5ca7f22e01b Mon Sep 17 00:00:00 2001 From: Cho Young-Hwi Date: Thu, 2 Apr 2026 10:33:26 +0100 Subject: [PATCH 1/5] [#744] Add Farcaster wallet option to RainbowKit wallet picker Custom Farcaster wallet adapter wraps farcasterMiniApp() connector and appears as first option in the RainbowKit modal. Hidden outside Farcaster (iframe detection). Provides manual fallback when auto-connect fails. Auto-connect via standalone farcasterMiniApp() connector remains intact. Fixes #744 Co-Authored-By: Claude Opus 4.6 (1M context) --- lib/wagmi.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/lib/wagmi.ts b/lib/wagmi.ts index 813b8b03..d8497404 100644 --- a/lib/wagmi.ts +++ b/lib/wagmi.ts @@ -2,6 +2,7 @@ import { http, createConfig } from "wagmi"; import { base, baseSepolia } from "wagmi/chains"; import { farcasterMiniApp } from "@farcaster/miniapp-wagmi-connector"; import { connectorsForWallets } from "@rainbow-me/rainbowkit"; +import type { Wallet } from "@rainbow-me/rainbowkit"; import { metaMaskWallet, baseAccount, @@ -15,12 +16,23 @@ import { DATA_SUFFIX } from "./builder-code"; const IS_MAINNET = process.env.NEXT_PUBLIC_CHAIN_ID === "8453"; const projectId = process.env.NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID || "placeholder"; +// Custom Farcaster wallet — manual fallback when auto-connect fails +const farcasterWallet = (): Wallet => ({ + id: "farcaster", + name: "Farcaster", + iconUrl: "https://warpcast.com/favicon.ico", + iconBackground: "#855DCD", + hidden: () => typeof window === "undefined" || !window.parent || window.parent === window, + createConnector: () => farcasterMiniApp(), +}); + // RainbowKit wallet list const walletConnectors = connectorsForWallets( [ { groupName: "Recommended", wallets: [ + farcasterWallet, metaMaskWallet, baseAccount, trustWallet, From c2e2ccced76129f114a0d7f998af3be08b1469cc Mon Sep 17 00:00:00 2001 From: Cho Young-Hwi Date: Thu, 2 Apr 2026 10:35:16 +0100 Subject: [PATCH 2/5] [#744] Replace warpcast.com favicon with inline Farcaster logo SVG MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Uses the official Farcaster brand logo as a data URI — no external dependency on warpcast.com. Co-Authored-By: Claude Opus 4.6 (1M context) --- lib/wagmi.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/wagmi.ts b/lib/wagmi.ts index d8497404..888dac70 100644 --- a/lib/wagmi.ts +++ b/lib/wagmi.ts @@ -20,7 +20,7 @@ const projectId = process.env.NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID || "placehold const farcasterWallet = (): Wallet => ({ id: "farcaster", name: "Farcaster", - iconUrl: "https://warpcast.com/favicon.ico", + iconUrl: "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1000 1000' fill='%23855DCD'%3E%3Cpath d='M257.778 155.556H742.222V844.444H671.111V528.889H670.414C662.554 441.677 589.258 373.333 500 373.333C410.742 373.333 337.446 441.677 329.586 528.889H328.889V844.444H257.778V155.556Z'/%3E%3Cpath d='M128.889 253.333L157.778 351.111H182.222V746.667C169.949 746.667 160 756.616 160 768.889V795.556H155.556C143.283 795.556 133.333 805.505 133.333 817.778V844.444H382.222V817.778C382.222 805.505 372.273 795.556 360 795.556H355.556V768.889C355.556 756.616 345.606 746.667 333.333 746.667H306.667V351.111H328.889V253.333H128.889Z'/%3E%3Cpath d='M671.111 253.333V351.111H693.333V746.667C681.06 746.667 671.111 756.616 671.111 768.889V795.556H666.667C654.394 795.556 644.444 805.505 644.444 817.778V844.444H893.333V817.778C893.333 805.505 883.384 795.556 871.111 795.556H866.667V768.889C866.667 756.616 856.717 746.667 844.444 746.667V351.111H868.889L897.778 253.333H671.111Z'/%3E%3C/svg%3E", iconBackground: "#855DCD", hidden: () => typeof window === "undefined" || !window.parent || window.parent === window, createConnector: () => farcasterMiniApp(), From a7465ab15ede3f39bca94f2482b2b3f1c45735ae Mon Sep 17 00:00:00 2001 From: Cho Young-Hwi Date: Thu, 2 Apr 2026 10:41:34 +0100 Subject: [PATCH 3/5] [#744] Use Farcaster SDK heuristic for wallet visibility Replace generic iframe check with the same heuristic used by @farcaster/miniapp-sdk: ReactNativeWebView (mobile) or iframe embed (web). Only shows Farcaster wallet option in likely Farcaster contexts, not arbitrary iframes. Co-Authored-By: Claude Opus 4.6 (1M context) --- lib/wagmi.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/wagmi.ts b/lib/wagmi.ts index 888dac70..34e9f6d0 100644 --- a/lib/wagmi.ts +++ b/lib/wagmi.ts @@ -13,6 +13,15 @@ import { import { createFallbackTransport } from "./rpc"; import { DATA_SUFFIX } from "./builder-code"; +/** Synchronous check: likely inside a Farcaster Mini App (same heuristic as SDK) */ +function isLikelyFarcasterContext(): boolean { + if (typeof window === "undefined") return false; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const w = window as any; + // ReactNativeWebView = Farcaster mobile, iframe = Farcaster web embed + return !!w.ReactNativeWebView || w !== w.parent; +} + const IS_MAINNET = process.env.NEXT_PUBLIC_CHAIN_ID === "8453"; const projectId = process.env.NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID || "placeholder"; @@ -22,7 +31,7 @@ const farcasterWallet = (): Wallet => ({ name: "Farcaster", iconUrl: "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1000 1000' fill='%23855DCD'%3E%3Cpath d='M257.778 155.556H742.222V844.444H671.111V528.889H670.414C662.554 441.677 589.258 373.333 500 373.333C410.742 373.333 337.446 441.677 329.586 528.889H328.889V844.444H257.778V155.556Z'/%3E%3Cpath d='M128.889 253.333L157.778 351.111H182.222V746.667C169.949 746.667 160 756.616 160 768.889V795.556H155.556C143.283 795.556 133.333 805.505 133.333 817.778V844.444H382.222V817.778C382.222 805.505 372.273 795.556 360 795.556H355.556V768.889C355.556 756.616 345.606 746.667 333.333 746.667H306.667V351.111H328.889V253.333H128.889Z'/%3E%3Cpath d='M671.111 253.333V351.111H693.333V746.667C681.06 746.667 671.111 756.616 671.111 768.889V795.556H666.667C654.394 795.556 644.444 805.505 644.444 817.778V844.444H893.333V817.778C893.333 805.505 883.384 795.556 871.111 795.556H866.667V768.889C866.667 756.616 856.717 746.667 844.444 746.667V351.111H868.889L897.778 253.333H671.111Z'/%3E%3C/svg%3E", iconBackground: "#855DCD", - hidden: () => typeof window === "undefined" || !window.parent || window.parent === window, + hidden: () => !isLikelyFarcasterContext(), createConnector: () => farcasterMiniApp(), }); From ff658863efb2b258c66d4fa0621f6ea7e2b73664 Mon Sep 17 00:00:00 2001 From: Cho Young-Hwi Date: Thu, 2 Apr 2026 10:45:32 +0100 Subject: [PATCH 4/5] [#744] Use SDK context-backed Farcaster detection for wallet visibility MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace heuristic iframe check with actual Farcaster SDK context probe. Async check runs at module load and caches result — wallet defaults to hidden until SDK confirms Farcaster Mini App context. Co-Authored-By: Claude Opus 4.6 (1M context) --- lib/wagmi.ts | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/lib/wagmi.ts b/lib/wagmi.ts index 34e9f6d0..6cb23c1a 100644 --- a/lib/wagmi.ts +++ b/lib/wagmi.ts @@ -13,13 +13,18 @@ import { import { createFallbackTransport } from "./rpc"; import { DATA_SUFFIX } from "./builder-code"; -/** Synchronous check: likely inside a Farcaster Mini App (same heuristic as SDK) */ -function isLikelyFarcasterContext(): boolean { - if (typeof window === "undefined") return false; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const w = window as any; - // ReactNativeWebView = Farcaster mobile, iframe = Farcaster web embed - return !!w.ReactNativeWebView || w !== w.parent; +/** + * SDK-backed Farcaster detection — probes once at module load, caches result. + * hidden() reads the cached boolean (defaults to hidden until confirmed). + */ +let _isFarcaster = false; +if (typeof window !== "undefined") { + import("@farcaster/miniapp-sdk") + .then(async ({ sdk }) => { + const ctx = await sdk.context; + _isFarcaster = !!ctx; + }) + .catch(() => {}); } const IS_MAINNET = process.env.NEXT_PUBLIC_CHAIN_ID === "8453"; @@ -31,7 +36,7 @@ const farcasterWallet = (): Wallet => ({ name: "Farcaster", iconUrl: "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1000 1000' fill='%23855DCD'%3E%3Cpath d='M257.778 155.556H742.222V844.444H671.111V528.889H670.414C662.554 441.677 589.258 373.333 500 373.333C410.742 373.333 337.446 441.677 329.586 528.889H328.889V844.444H257.778V155.556Z'/%3E%3Cpath d='M128.889 253.333L157.778 351.111H182.222V746.667C169.949 746.667 160 756.616 160 768.889V795.556H155.556C143.283 795.556 133.333 805.505 133.333 817.778V844.444H382.222V817.778C382.222 805.505 372.273 795.556 360 795.556H355.556V768.889C355.556 756.616 345.606 746.667 333.333 746.667H306.667V351.111H328.889V253.333H128.889Z'/%3E%3Cpath d='M671.111 253.333V351.111H693.333V746.667C681.06 746.667 671.111 756.616 671.111 768.889V795.556H666.667C654.394 795.556 644.444 805.505 644.444 817.778V844.444H893.333V817.778C893.333 805.505 883.384 795.556 871.111 795.556H866.667V768.889C866.667 756.616 856.717 746.667 844.444 746.667V351.111H868.889L897.778 253.333H671.111Z'/%3E%3C/svg%3E", iconBackground: "#855DCD", - hidden: () => !isLikelyFarcasterContext(), + hidden: () => !_isFarcaster, createConnector: () => farcasterMiniApp(), }); From fa54d01b16947a6be1b92852f322769436541300 Mon Sep 17 00:00:00 2001 From: Cho Young-Hwi Date: Thu, 2 Apr 2026 10:49:17 +0100 Subject: [PATCH 5/5] [#744] Use SDK's own sync heuristic for Farcaster wallet visibility hidden() is evaluated at connector-list construction time (not render time), so async SDK context is not viable. Switch to the same sync heuristic @farcaster/miniapp-sdk uses: ReactNativeWebView (mobile) or iframe (web). The connector itself gracefully fails outside Farcaster. Co-Authored-By: Claude Opus 4.6 (1M context) --- lib/wagmi.ts | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/lib/wagmi.ts b/lib/wagmi.ts index 6cb23c1a..00cbe38e 100644 --- a/lib/wagmi.ts +++ b/lib/wagmi.ts @@ -14,17 +14,16 @@ import { createFallbackTransport } from "./rpc"; import { DATA_SUFFIX } from "./builder-code"; /** - * SDK-backed Farcaster detection — probes once at module load, caches result. - * hidden() reads the cached boolean (defaults to hidden until confirmed). + * Synchronous Farcaster detection — matches @farcaster/miniapp-sdk's own + * short-circuit heuristic (ReactNativeWebView for mobile, iframe for web). + * This is the only viable sync check since hidden() runs at connector-list + * construction time. The connector itself gracefully fails outside Farcaster. */ -let _isFarcaster = false; -if (typeof window !== "undefined") { - import("@farcaster/miniapp-sdk") - .then(async ({ sdk }) => { - const ctx = await sdk.context; - _isFarcaster = !!ctx; - }) - .catch(() => {}); +function isLikelyFarcasterContext(): boolean { + if (typeof window === "undefined") return false; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const w = window as any; + return !!w.ReactNativeWebView || w !== w.parent; } const IS_MAINNET = process.env.NEXT_PUBLIC_CHAIN_ID === "8453"; @@ -36,7 +35,7 @@ const farcasterWallet = (): Wallet => ({ name: "Farcaster", iconUrl: "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1000 1000' fill='%23855DCD'%3E%3Cpath d='M257.778 155.556H742.222V844.444H671.111V528.889H670.414C662.554 441.677 589.258 373.333 500 373.333C410.742 373.333 337.446 441.677 329.586 528.889H328.889V844.444H257.778V155.556Z'/%3E%3Cpath d='M128.889 253.333L157.778 351.111H182.222V746.667C169.949 746.667 160 756.616 160 768.889V795.556H155.556C143.283 795.556 133.333 805.505 133.333 817.778V844.444H382.222V817.778C382.222 805.505 372.273 795.556 360 795.556H355.556V768.889C355.556 756.616 345.606 746.667 333.333 746.667H306.667V351.111H328.889V253.333H128.889Z'/%3E%3Cpath d='M671.111 253.333V351.111H693.333V746.667C681.06 746.667 671.111 756.616 671.111 768.889V795.556H666.667C654.394 795.556 644.444 805.505 644.444 817.778V844.444H893.333V817.778C893.333 805.505 883.384 795.556 871.111 795.556H866.667V768.889C866.667 756.616 856.717 746.667 844.444 746.667V351.111H868.889L897.778 253.333H671.111Z'/%3E%3C/svg%3E", iconBackground: "#855DCD", - hidden: () => !_isFarcaster, + hidden: () => !isLikelyFarcasterContext(), createConnector: () => farcasterMiniApp(), });