From 140616a3e4cd79d63abac12cc8e0ed62725db1c2 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Mon, 7 Sep 2026 12:59:04 +0200 Subject: [PATCH] Fix wallet bridge on Firefox: use postMessage instead of CustomEvent Manual testing on Zen/Firefox surfaced "Uncaught Error: Permission denied to access property 'id'" the moment the isolated-world relay dispatched a CustomEvent to the world:'MAIN' injected script. That's a Firefox-specific Xray-wrapper restriction: a CustomEvent's `detail` object created in one world can't have its properties read from the other, even though the event itself fires fine. Chromium doesn't enforce this, which is why it wasn't caught until testing on the actual target browser (Zen). Switched both sides of the bridge (wallet-bridge/inject.ts, wallet-bridge/relay.ts) to window.postMessage with a `channel` field and same-window source check, since postMessage structured-clones its payload across the boundary correctly on both browsers -- the same approach Phantom's own inpage<->content-script bridge uses. Also added [nexa/...]-prefixed console.debug breadcrumbs through the wallet-connect/wallet-bridge/wallet-auth chain, since diagnosing this without them (previous commit shipped none) took several rounds of "nothing happened" back and forth. Still not fully verified end-to-end against live Phantom -- the crash is fixed, but a full connect -> sign -> verify round trip hasn't been confirmed yet. See CLAUDE.md. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01YXiHuScXrjxBh7yFGAPq3B --- CLAUDE.md | 7 ++-- src/background/wallet-auth.ts | 4 +++ src/content-scripts/wallet-bridge/inject.ts | 40 ++++++++++++++------- src/content-scripts/wallet-bridge/relay.ts | 33 ++++++++++------- src/content-scripts/wallet-connect.ts | 10 ++++-- src/entrypoints/background.ts | 2 +- 6 files changed, 66 insertions(+), 30 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 6ae69e0..84ee045 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -95,12 +95,13 @@ Note the naming mismatch with the wire protocol below: the frontend's internal ` Real wallet signing, not a stub keypair. Phantom (and any wallet injecting a compatible `window.solana`) is only reachable from a **page's own JS world** — a normal (isolated-world) content script cannot call into it directly, hence the two-content-script bridge below. This is the standard pattern for extensions that need to talk to page-injected wallet providers. -- `src/entrypoints/wallet-bridge.content.ts` + `src/content-scripts/wallet-bridge/inject.ts` — a **second, `world: 'MAIN'`** content script on axiom.trade (Manifest V3 native main-world injection — no `web_accessible_resources`/dynamic `