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
72 lines
2.2 KiB
JavaScript
72 lines
2.2 KiB
JavaScript
// Cached ENS reverse resolution.
|
|
// Resolves addresses to ENS names via ethers provider.lookupAddress(),
|
|
// caching results in localStorage with a 12-hour TTL.
|
|
//
|
|
// POPUP ONLY. localStorage does not exist in the Chrome MV3 service worker,
|
|
// so this module must not be pulled into src/background/. Anything the
|
|
// background context needs to cache goes in extension storage instead.
|
|
|
|
const { getProvider } = require("./balances");
|
|
const { log } = require("./log");
|
|
|
|
const CACHE_TTL_MS = 43200000; // 12 hours
|
|
const CACHE_PREFIX = "ens:";
|
|
|
|
function getCached(address) {
|
|
const key = CACHE_PREFIX + address.toLowerCase();
|
|
try {
|
|
const raw = localStorage.getItem(key);
|
|
if (!raw) return undefined;
|
|
const entry = JSON.parse(raw);
|
|
if (Date.now() - entry.ts < CACHE_TTL_MS) {
|
|
return entry.name;
|
|
}
|
|
} catch {
|
|
// Corrupt cache entry — treat as miss.
|
|
}
|
|
return undefined;
|
|
}
|
|
|
|
function setCache(address, name) {
|
|
const key = CACHE_PREFIX + address.toLowerCase();
|
|
localStorage.setItem(key, JSON.stringify({ name, ts: Date.now() }));
|
|
}
|
|
|
|
// `signal` is as for fetchTokenBalances() in src/shared/balances.js.
|
|
async function resolveEnsName(address, rpcUrl, networkId, signal) {
|
|
const cached = getCached(address);
|
|
if (cached !== undefined) return cached;
|
|
|
|
const provider = getProvider(rpcUrl, networkId);
|
|
try {
|
|
const name = (await provider.lookupAddress(address)) || null;
|
|
setCache(address, name);
|
|
return name;
|
|
} catch (e) {
|
|
if (!signal?.aborted) {
|
|
log.errorf(
|
|
"ENS reverse lookup failed",
|
|
address,
|
|
e.shortMessage || e.message,
|
|
);
|
|
}
|
|
// Don't cache failures — let subsequent lookups retry
|
|
return null;
|
|
}
|
|
}
|
|
|
|
async function resolveEnsNames(addresses, rpcUrl, networkId, signal) {
|
|
const results = new Map();
|
|
await Promise.all(
|
|
addresses.map(async (addr) => {
|
|
results.set(
|
|
addr,
|
|
await resolveEnsName(addr, rpcUrl, networkId, signal),
|
|
);
|
|
}),
|
|
);
|
|
return results;
|
|
}
|
|
|
|
module.exports = { resolveEnsName, resolveEnsNames };
|