// The field mutations a chain switch performs, applied to a state record // handed in rather than to the module-level `state` singleton. // // Split out of chainSwitch.js so the background can perform a chain switch // without the singleton being reachable from its bundle at all. The popup // still goes through onChainSwitch() (chainSwitch.js), which applies this to // the singleton and saves; the background applies it to the detached record of // its own read-modify-write (src/background/state.js). // // Everything here is synchronous and touches nothing but the object it is // given: no storage, no caches, no imports beyond the network table. That is // what makes it usable on a record that has been read fresh from storage // microseconds earlier and is about to be written back. const { networkById } = require("./networks"); // Switch `s` to `newNetworkId` and reset every piece of chain-specific state // it carries. Returns the network configuration object for the new chain. function applyChainSwitchFields(s, newNetworkId) { const net = networkById(newNetworkId); // --- core identity --- // Endpoints are remembered per network rather than reset to the // defaults, because a user who points the wallet at their own node has // no way to get that URL back once it is gone: overwriting it moved // every address and every transaction onto a third-party endpoint // silently and permanently. // // s.rpcUrl / s.blockscoutUrl stay the live endpoints of the active // network, so nothing that reads them changes. The invariant is that for // the ACTIVE network those two fields are authoritative and the map entry // may be stale (Settings writes the fields directly); for every other // network the map is authoritative. Snapshotting the outgoing network // here, before the switch, is what reconciles them. if (!s.networkEndpoints) s.networkEndpoints = {}; s.networkEndpoints[s.networkId] = { rpcUrl: s.rpcUrl, blockscoutUrl: s.blockscoutUrl, }; const remembered = s.networkEndpoints[net.id] || {}; s.networkId = net.id; s.rpcUrl = remembered.rpcUrl || net.defaultRpcUrl; s.blockscoutUrl = remembered.blockscoutUrl || net.defaultBlockscoutUrl; // --- balance / refresh state --- // Reset last-refresh timestamp so the next polling cycle // triggers an immediate balance refresh on the new chain. s.lastBalanceRefresh = 0; // Clear per-address balances and token balances so stale data // from the previous chain is never displayed while the first // refresh on the new chain is in flight. for (const wallet of s.wallets || []) { for (const addr of wallet.addresses || []) { addr.balance = "0"; addr.tokenBalances = []; } } // --- chain-specific caches --- // Token holder counts and fraud contract lists are // chain-specific and must not carry over. s.tokenHolderCache = {}; s.fraudContracts = []; return net; } module.exports = { applyChainSwitchFields };