-
Notifications
You must be signed in to change notification settings - Fork 48
Phantom EVM wallet unavailable in popup flows due to long URL params #2467
Description
Problem
Phantom's browser extension does not inject its EVM provider (window.phantom.ethereum) when a page is opened via window.open() with very long URL query parameters. This affects both popup auth (connect) and session registration flows.
Affected flows:
- Popup auth (
popupConnect) — connect/signup flow viaopenPopupAuth({ action: "connect", ... }) - Session registration (
createSessionViaPopup) — session creation viaopenPopupAuth({ action: "create-session", ... })
Both flows forward URL params from the iframe to the popup in openPopupAuth() (packages/keychain/src/utils/connection/popup.ts), including policies which contains large double-encoded JSON.
Root Cause
Phantom's content script skips EVM provider injection when the URL exceeds a certain length. The policies param is the culprit — it contains URL-encoded JSON that can be very large.
Key finding: Passing just preset as a URL param works fine — Phantom injects normally. It's specifically the large policies encoding that causes the issue.
Evidence:
window.open("localhost:3001/popup-auth?channel_id=xxx&action=connect")→window.phantom.ethereumexistswindow.open("localhost:3001/popup-auth?channel_id=xxx&action=connect&policies=<large encoded JSON>")→window.phantom.ethereumis undefined- MetaMask, Rabby, and Temple all inject correctly regardless of URL length
Proposed Fix
Move large params (policies, signers) off the URL and deliver them via BroadcastChannel (already used for auth-complete/auth-error signaling):
openPopupAuth()opens popup with onlychannel_id+actionin URL- Popup sends
{ type: "popup-ready" }on mount - Opener responds with
{ type: "popup-params", policies, preset, rpcUrl, signers, origin } - Popup injects received params into URL via
setSearchParams(or state) so the connection hook picks them up
This keeps the initial URL short so Phantom injects, and params arrive shortly after via the channel.
Files
packages/keychain/src/utils/connection/popup.ts—openPopupAuth(), builds popup URLpackages/keychain/src/components/PopupAuth.tsx— popup page, reads params from URLpackages/keychain/src/components/ConnectRoute.tsx—createSessionViaPopup(), callsopenPopupAuth()packages/keychain/src/utils/connection/index.ts—popupConnect(), callsopenPopupAuth()packages/keychain/src/hooks/connection.ts— connection hook that consumes URL params