From 65cb4d2f64455c9686b057d297d53b362021fef4 Mon Sep 17 00:00:00 2001 From: clawbot Date: Fri, 27 Feb 2026 12:30:32 -0800 Subject: [PATCH] fix: add fallback popup window for tx and sign approval requests (closes #4) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit requestTxApproval and requestSignApproval were missing the openApprovalWindow fallback that requestApproval (connection requests) already had. When chrome.action.openPopup() fails (which it does when not triggered by a user gesture in MV3), no popup appeared — the user had to manually click the toolbar icon to find the confirmation screen. Now all three approval types use the same pattern: try openPopup() first, fall back to a centered standalone window. --- src/background/index.js | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/background/index.js b/src/background/index.js index db30f43..87bf4ec 100644 --- a/src/background/index.js +++ b/src/background/index.js @@ -148,7 +148,7 @@ function requestApproval(origin, hostname) { } // Open a tx-approval popup and return a promise that resolves with txHash or error. -// Uses the toolbar popup only — no fallback window. +// Tries the toolbar popup first, falls back to a standalone window. function requestTxApproval(origin, hostname, txParams) { return new Promise((resolve) => { const id = crypto.randomUUID(); @@ -160,27 +160,26 @@ function requestTxApproval(origin, hostname, txParams) { type: "tx", }; - if (actionApi && typeof actionApi.setPopup === "function") { + if (actionApi && typeof actionApi.openPopup === "function") { actionApi.setPopup({ popup: "src/popup/index.html?approval=" + id, }); - } - if (actionApi && typeof actionApi.openPopup === "function") { try { const result = actionApi.openPopup(); if (result && typeof result.catch === "function") { - result.catch(() => {}); + result.catch(() => openApprovalWindow(id)); } } catch { - // openPopup unsupported — user clicks toolbar icon + openApprovalWindow(id); } + } else { + openApprovalWindow(id); } }); } // Open a sign-approval popup and return a promise that resolves with { signature } or { error }. -// Uses the toolbar popup only — no fallback window. If openPopup() fails the -// popup URL is still set, so the user can click the toolbar icon to respond. +// Tries the toolbar popup first, falls back to a standalone window. function requestSignApproval(origin, hostname, signParams) { return new Promise((resolve) => { const id = crypto.randomUUID(); @@ -192,20 +191,20 @@ function requestSignApproval(origin, hostname, signParams) { type: "sign", }; - if (actionApi && typeof actionApi.setPopup === "function") { + if (actionApi && typeof actionApi.openPopup === "function") { actionApi.setPopup({ popup: "src/popup/index.html?approval=" + id, }); - } - if (actionApi && typeof actionApi.openPopup === "function") { try { const result = actionApi.openPopup(); if (result && typeof result.catch === "function") { - result.catch(() => {}); + result.catch(() => openApprovalWindow(id)); } } catch { - // openPopup unsupported — user clicks toolbar icon + openApprovalWindow(id); } + } else { + openApprovalWindow(id); } }); }