fix: Settings refuses an endpoint URL whose network changed before it was stored (closes #663)
check / check (push) Canceled after 0s
e2e / e2e-chrome (push) Canceled after 0s
e2e / e2e-firefox (push) Canceled after 0s

The RPC and Blockscout "Save" buttons in Settings now set the URL
inside the save, holding the lock. The save is refused if the network
active when the user tapped "Save" is no longer active, on the page or
in the stored record. The flash message then says that the network
changed, and "Saved." is shown only for a stored URL.

Before, a popup that followed a switch saved elsewhere could replace
the URL before the write and still show "Saved.". It could also write
the previous network's URL as the new network's.

Model: opus-5-5
This commit is contained in:
2026-10-27 03:31:40 +00:00
parent b4e166cdc7
commit bccc86b6ea
3 changed files with 95 additions and 7 deletions
+27 -7
View File
@@ -319,6 +319,28 @@ function showNewSettings() {
updateDebugBanner(state.currentView);
}
// Saves `url` as `field` ("rpcUrl" or "blockscoutUrl") of the network
// `networkId`, the one active when the user tapped "Save". The URL is set in
// `state` inside the save, holding the lock. So the page cannot follow a switch
// saved elsewhere (followStoredSettings() in src/popup/index.js) between
// setting the URL and writing it. If the active network is no longer
// `networkId`, on this page or in the stored record, nothing is saved. The
// flash message then says that the network changed.
async function saveEndpoint(field, url, networkId) {
let refused = false;
await saveState((stored) => {
refused =
state.networkId !== networkId || stored.networkId !== networkId;
if (refused) return false;
state[field] = url;
});
if (refused) {
showFlash("The URL was not saved because the network changed.");
} else {
showFlash("Saved.");
}
}
function init(_ctx) {
ctx = _ctx;
deleteWallet.init(ctx);
@@ -330,6 +352,8 @@ function init(_ctx) {
showFlash("Please enter an RPC URL.");
return;
}
// The URL is for the network active when "Save" is tapped.
const net = currentNetwork();
showFlash("Testing endpoint...");
try {
const resp = await debugFetch(url, {
@@ -348,7 +372,6 @@ function init(_ctx) {
showFlash("Endpoint returned an error.");
return;
}
const net = currentNetwork();
if (json.result !== net.chainId) {
showFlash("Wrong network: expected " + net.name + ".");
return;
@@ -364,9 +387,7 @@ function init(_ctx) {
showFlash("Could not reach endpoint.");
return;
}
state.rpcUrl = url;
await saveState();
showFlash("Saved.");
await saveEndpoint("rpcUrl", url, net.id);
});
$("btn-save-blockscout").addEventListener("click", async () => {
@@ -375,6 +396,7 @@ function init(_ctx) {
showFlash("Please enter a Blockscout API URL.");
return;
}
const networkId = state.networkId;
showFlash("Testing endpoint...");
try {
const resp = await debugFetch(url + "/stats");
@@ -389,9 +411,7 @@ function init(_ctx) {
showFlash("Could not reach endpoint.");
return;
}
state.blockscoutUrl = url;
await saveState();
showFlash("Saved.");
await saveEndpoint("blockscoutUrl", url, networkId);
});
// Each change is made inside the save, holding the lock. So