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:
clawbot 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.
// 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);
}
});
}