fix: a popup reload no longer logs the requests it cancels on most screens (closes #475)
check / check (push) Successful in 5m41s
e2e / e2e-chrome (push) Successful in 5m13s
e2e / e2e-firefox (push) Successful in 3m24s

The transaction lists and ENS name lookups on the address and token
screens, the address scan after a wallet is created, the endpoint checks
in Settings, the wait screen's receipt check, the Send screen's Max fee
estimate and the token lookup on both add-token screens now check the
signal the popup aborts on pagehide before reporting a failed request.
scanForAddresses(), resolveEnsNames() and lookupTokenInfo() take the
signal.

End-to-end tests reload the popup on the address screen and during the
address scan with their requests held. Jest tests show each of these
reports a real failure and stays silent once the popup has closed. The
transaction detail and confirmation screens are left out: they discard
the popup context that carries the signal.

Model: opus-5-5
This commit was merged in pull request #477.
This commit is contained in:
2026-10-06 22:09:08 +02:00
parent cb23611a17
commit ad1b4f0557
21 changed files with 762 additions and 49 deletions
+23 -13
View File
@@ -294,7 +294,8 @@ async function refreshBalances(
// Look up token metadata from its contract.
// Calls symbol() and decimals() to verify it implements ERC-20.
async function lookupTokenInfo(contractAddress, rpcUrl, networkId) {
// `signal` is as for fetchTokenBalances().
async function lookupTokenInfo(contractAddress, rpcUrl, networkId, signal) {
log.debugf("lookupTokenInfo", contractAddress, "rpc:", urlOrigin(rpcUrl));
const provider = getProvider(rpcUrl, networkId);
const contract = new Contract(contractAddress, ERC20_ABI, provider);
@@ -304,7 +305,9 @@ async function lookupTokenInfo(contractAddress, rpcUrl, networkId) {
symbol = await contract.symbol();
log.debugf("symbol() =", symbol);
} catch (e) {
log.errorf("symbol() failed:", e.shortMessage || e.message);
if (!signal?.aborted) {
log.errorf("symbol() failed:", e.shortMessage || e.message);
}
throw new Error("Not a valid ERC-20 token (symbol() failed).");
}
@@ -312,7 +315,9 @@ async function lookupTokenInfo(contractAddress, rpcUrl, networkId) {
decimals = await contract.decimals();
log.debugf("decimals() =", decimals);
} catch (e) {
log.errorf("decimals() failed:", e.shortMessage || e.message);
if (!signal?.aborted) {
log.errorf("decimals() failed:", e.shortMessage || e.message);
}
throw new Error("Not a valid ERC-20 token (decimals() failed).");
}
@@ -320,10 +325,12 @@ async function lookupTokenInfo(contractAddress, rpcUrl, networkId) {
name = await contract.name();
log.debugf("name() =", name);
} catch (e) {
log.warnf(
"name() failed, using symbol as name:",
e.shortMessage || e.message,
);
if (!signal?.aborted) {
log.warnf(
"name() failed, using symbol as name:",
e.shortMessage || e.message,
);
}
name = symbol;
}
@@ -339,7 +346,8 @@ async function lookupTokenInfo(contractAddress, rpcUrl, networkId) {
// Checks gapLimit addresses in parallel per batch. Stops when an entire
// batch has no used addresses (i.e. gapLimit consecutive empty addresses).
// Returns { addresses: [{ address, index }], nextIndex }.
async function scanForAddresses(xpub, rpcUrl, networkId, gapLimit = 5) {
// `signal` is as for fetchTokenBalances().
async function scanForAddresses(xpub, rpcUrl, networkId, signal, gapLimit = 5) {
log.debugf("scanForAddresses start, gapLimit:", gapLimit);
const provider = getProvider(rpcUrl, networkId);
const used = [];
@@ -362,11 +370,13 @@ async function scanForAddresses(xpub, rpcUrl, networkId, gapLimit = 5) {
]);
return { addr, index, isUsed: balance > 0n || txCount > 0 };
} catch (e) {
log.errorf(
"scanForAddresses check failed",
addr,
e.shortMessage || e.message,
);
if (!signal?.aborted) {
log.errorf(
"scanForAddresses check failed",
addr,
e.shortMessage || e.message,
);
}
return { addr, index, isUsed: false };
}
}),