// Consolidated chain-switch handler. // // Every state change required when the active network changes is // performed here so that callers (settings UI, background // wallet_switchEthereumChain, future chain additions) all go // through a single code path. // // Adding a new chain (e.g. ETC) requires only a new entry in // networks.js — no per-caller wiring is needed. const { networkById } = require("./networks"); const { clearPrices } = require("./prices"); // Switch the active chain and reset all chain-specific cached state. // Returns the network configuration object for the new chain. async function onChainSwitch(newNetworkId) { const { state, saveState } = require("./state"); 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. // // state.rpcUrl / state.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. state.networkEndpoints[state.networkId] = { rpcUrl: state.rpcUrl, blockscoutUrl: state.blockscoutUrl, }; const remembered = state.networkEndpoints[net.id] || {}; state.networkId = net.id; state.rpcUrl = remembered.rpcUrl || net.defaultRpcUrl; state.blockscoutUrl = remembered.blockscoutUrl || net.defaultBlockscoutUrl; // --- price cache --- // Prices are chain-specific (testnet tokens are worthless, // ETC has different pricing, etc.). clearPrices(); // --- balance / refresh state --- // Reset last-refresh timestamp so the next polling cycle // triggers an immediate balance refresh on the new chain. state.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 state.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. state.tokenHolderCache = {}; state.fraudContracts = []; await saveState(); return net; } module.exports = { onChainSwitch };