fix: add fallback popup window for tx and sign approval requests (closes #4)
All checks were successful
check / check (push) Successful in 22s

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.
This commit is contained in:
2026-02-27 12:30:32 -08:00
committed by user
parent 4eefe4c1af
commit 65cb4d2f64

View File

@@ -148,7 +148,7 @@ function requestApproval(origin, hostname) {
} }
// Open a tx-approval popup and return a promise that resolves with txHash or error. // 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) { function requestTxApproval(origin, hostname, txParams) {
return new Promise((resolve) => { return new Promise((resolve) => {
const id = crypto.randomUUID(); const id = crypto.randomUUID();
@@ -160,27 +160,26 @@ function requestTxApproval(origin, hostname, txParams) {
type: "tx", type: "tx",
}; };
if (actionApi && typeof actionApi.setPopup === "function") { if (actionApi && typeof actionApi.openPopup === "function") {
actionApi.setPopup({ actionApi.setPopup({
popup: "src/popup/index.html?approval=" + id, popup: "src/popup/index.html?approval=" + id,
}); });
}
if (actionApi && typeof actionApi.openPopup === "function") {
try { try {
const result = actionApi.openPopup(); const result = actionApi.openPopup();
if (result && typeof result.catch === "function") { if (result && typeof result.catch === "function") {
result.catch(() => {}); result.catch(() => openApprovalWindow(id));
} }
} catch { } 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 }. // 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 // Tries the toolbar popup first, falls back to a standalone window.
// popup URL is still set, so the user can click the toolbar icon to respond.
function requestSignApproval(origin, hostname, signParams) { function requestSignApproval(origin, hostname, signParams) {
return new Promise((resolve) => { return new Promise((resolve) => {
const id = crypto.randomUUID(); const id = crypto.randomUUID();
@@ -192,20 +191,20 @@ function requestSignApproval(origin, hostname, signParams) {
type: "sign", type: "sign",
}; };
if (actionApi && typeof actionApi.setPopup === "function") { if (actionApi && typeof actionApi.openPopup === "function") {
actionApi.setPopup({ actionApi.setPopup({
popup: "src/popup/index.html?approval=" + id, popup: "src/popup/index.html?approval=" + id,
}); });
}
if (actionApi && typeof actionApi.openPopup === "function") {
try { try {
const result = actionApi.openPopup(); const result = actionApi.openPopup();
if (result && typeof result.catch === "function") { if (result && typeof result.catch === "function") {
result.catch(() => {}); result.catch(() => openApprovalWindow(id));
} }
} catch { } catch {
// openPopup unsupported — user clicks toolbar icon openApprovalWindow(id);
} }
} else {
openApprovalWindow(id);
} }
}); });
} }