A network switch in Settings filed under the new network a token or fraud contract that another page stored since this page's last save, because the switch's save writes only the fields this page changed. Before the switch, onChainSwitch() now takes the stored tracked tokens into the page's own list with takeStoredTrackedTokens(), matched by contract address, so a token either page added or removed stays as that page left it. The switch then files that list under the previous network. When the stored record is on another network, no tokens are taken. Fraud contracts are cleared on every switch, as before. Model: opus-5-5
93 lines
4.2 KiB
JavaScript
93 lines
4.2 KiB
JavaScript
// The popup's network switch.
|
|
//
|
|
// A network switch reaches the popup's `state` in one of two ways:
|
|
//
|
|
// - onChainSwitch() below makes the switch the user picks in Settings, with
|
|
// applyChainSwitchFields() (chainSwitchFields.js).
|
|
// - followStoredSettings() in src/popup/index.js takes a switch the background
|
|
// or another popup page saved, from the stored record, with
|
|
// takeStoredNetwork() (state.js), which copies it with
|
|
// copyChainSwitchFields() (chainSwitchFields.js).
|
|
//
|
|
// Both change `state` inside a save, holding the lock, and both reset the
|
|
// popup's own caches through clearPopupCaches(), so a reset added there
|
|
// reaches both. A field applyChainSwitchFields() sets has to be copied by
|
|
// copyChainSwitchFields() too.
|
|
//
|
|
// Adding a new chain (e.g. ETC) requires only a new entry in
|
|
// networks.js — no per-caller wiring is needed.
|
|
//
|
|
// The background does NOT come through here: this function mutates the
|
|
// module-level `state` singleton, which the MV3 service worker never
|
|
// populates, and a background switch performed on it wrote DEFAULT_STATE over
|
|
// the user's whole profile
|
|
// (https://git.eeqj.de/sneak/AutistMask/issues/316). The field mutations
|
|
// themselves live in chainSwitchFields.js, which takes the record to mutate as
|
|
// an argument; src/background/state.js applies them inside a read-modify-write
|
|
// against storage, and the singleton is not reachable from the background
|
|
// bundle at all (enforced by the ESLint rule in eslint.config.js).
|
|
|
|
const { applyChainSwitchFields } = require("./chainSwitchFields");
|
|
const { clearPrices } = require("./prices");
|
|
|
|
// The popup's own caches a network switch resets. Prices are chain-specific
|
|
// (testnet tokens are worthless, ETC has different pricing, etc.). In-memory
|
|
// and per bundle, so this is the popup's own cache — the only context that
|
|
// ever fills it.
|
|
function clearPopupCaches() {
|
|
clearPrices();
|
|
}
|
|
|
|
// Switch the active chain and reset all chain-specific cached state.
|
|
// Returns the network configuration object for the new chain, or null when
|
|
// `state` already has that network once the save holds the lock, and nothing
|
|
// is switched.
|
|
//
|
|
// `state` is switched inside the save that stores the switch, holding the
|
|
// lock, so it is never switched while a follow of a switch saved elsewhere
|
|
// waits for the lock (followStoredSettings() in src/popup/index.js): that
|
|
// follow runs first, and this switch is made after it.
|
|
//
|
|
// The save writes only the fields that differ from what this page last saved.
|
|
// When this page last saved a balance of "0", clearing that balance is no
|
|
// change. So the switch also resets these fields in the stored record:
|
|
//
|
|
// - every address's balance and token balances;
|
|
// - the time of the last balance refresh;
|
|
// - the fraud contracts.
|
|
//
|
|
// A balance or a fraud contract that the background or another page stored
|
|
// since this page's last save is then not kept under the new network
|
|
// (https://git.eeqj.de/sneak/AutistMask/issues/653,
|
|
// https://git.eeqj.de/sneak/AutistMask/issues/692).
|
|
//
|
|
// Before the switch, `state` takes the tracked tokens that another page stored
|
|
// since this page's last save (takeStoredTrackedTokens() in state.js). The
|
|
// switch then puts them away under the previous network, the network they were
|
|
// added on. When the stored record is on another network, a switch saved
|
|
// elsewhere has not reached this page yet. The stored record's tokens are then
|
|
// that network's, and none are taken.
|
|
async function onChainSwitch(newNetworkId) {
|
|
const { state, saveState, takeStoredTrackedTokens } = require("./state");
|
|
let net = null;
|
|
await saveState((stored) => {
|
|
if (state.networkId === newNetworkId) return false;
|
|
if (stored.networkId === state.networkId) {
|
|
takeStoredTrackedTokens(stored);
|
|
}
|
|
net = applyChainSwitchFields(state, newNetworkId);
|
|
stored.lastBalanceRefresh = 0;
|
|
stored.fraudContracts = [];
|
|
for (const wallet of stored.wallets) {
|
|
for (const addr of wallet.addresses) {
|
|
addr.balance = "0";
|
|
addr.tokenBalances = [];
|
|
}
|
|
}
|
|
clearPopupCaches();
|
|
});
|
|
return net;
|
|
}
|
|
|
|
module.exports = { onChainSwitch, clearPopupCaches };
|