fix: two pages switching networks no longer lose tracked tokens (closes #701)
A page that had not yet taken another page's network switch could lose tracked tokens. - Its save of an added or removed token wrote its own network's list as the new network's list. saveState() now keeps the stored list. It merges the add or removal into the stored list of the page's own network in networkTrackedTokens. - Its own switch in Settings wrote its old lists of tracked tokens per network over the stored ones. onChainSwitch() now first takes the stored switch with takeStoredNetwork(), and then switches from there. - takeStoredNetwork() replaced the page's tracked tokens with the stored ones. It now keeps the page's unsaved change in the list of the page's network. This also fixes #706. Model: opus-5-5
This commit is contained in:
@@ -61,20 +61,31 @@ function clearPopupCaches() {
|
||||
// (https://git.eeqj.de/sneak/AutistMask/issues/653,
|
||||
// https://git.eeqj.de/sneak/AutistMask/issues/692).
|
||||
//
|
||||
// When the stored record is on another network, a switch saved elsewhere has
|
||||
// not reached this page yet. This page first takes that switch with
|
||||
// takeStoredNetwork() (state.js), as followStoredSettings() does. The switch to
|
||||
// `newNetworkId` is then made from the stored record's network. So every
|
||||
// network's list of tracked tokens in the stored record is kept
|
||||
// (https://git.eeqj.de/sneak/AutistMask/issues/701). When the stored record is
|
||||
// already on `newNetworkId`, the switch made from there only resets the
|
||||
// balances and caches.
|
||||
//
|
||||
// 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.
|
||||
// added on.
|
||||
async function onChainSwitch(newNetworkId) {
|
||||
const { state, saveState, takeStoredTrackedTokens } = require("./state");
|
||||
const {
|
||||
state,
|
||||
saveState,
|
||||
takeStoredNetwork,
|
||||
takeStoredTrackedTokens,
|
||||
} = require("./state");
|
||||
let net = null;
|
||||
await saveState((stored) => {
|
||||
if (state.networkId === newNetworkId) return false;
|
||||
if (stored.networkId === state.networkId) {
|
||||
takeStoredTrackedTokens(stored);
|
||||
}
|
||||
if (stored.networkId !== state.networkId) takeStoredNetwork(stored);
|
||||
takeStoredTrackedTokens(stored);
|
||||
net = applyChainSwitchFields(state, newNetworkId);
|
||||
stored.lastBalanceRefresh = 0;
|
||||
stored.fraudContracts = [];
|
||||
|
||||
+47
-4
@@ -455,6 +455,11 @@ function mergeNetworkEndpoints(base, ours, theirs) {
|
||||
// own UI scratch space, not data another page has any reason to share
|
||||
// membership of.
|
||||
//
|
||||
// One exception: when the stored record is on another network than this
|
||||
// page's, a save keeps the stored `trackedTokens`. It merges this page's change
|
||||
// into the list in `networkTrackedTokens` for this page's network, by contract
|
||||
// address.
|
||||
//
|
||||
// This does not make two pages that both change the SAME leaf concurrently
|
||||
// safe: last write wins on that one leaf, same as before. What it removes
|
||||
// is the cross-field (and now cross-membership-vs-leaf) clobber — a page
|
||||
@@ -527,6 +532,26 @@ async function saveStateOnce(beforeWrite) {
|
||||
merged[key] = current[key];
|
||||
}
|
||||
}
|
||||
// When the merged record names a network other than this page's, this page
|
||||
// has not yet taken a switch saved elsewhere. This page's `trackedTokens`
|
||||
// is then the list of this page's network. The stored record keeps the
|
||||
// list of this page's network in `networkTrackedTokens`. So a token that
|
||||
// this page added or removed since its last save is added to or removed
|
||||
// from that stored list. The merged record keeps the stored `trackedTokens`
|
||||
// (https://git.eeqj.de/sneak/AutistMask/issues/701).
|
||||
if (merged.networkId !== current.networkId) {
|
||||
merged.trackedTokens = fresh.trackedTokens;
|
||||
merged.networkTrackedTokens = {
|
||||
...fresh.networkTrackedTokens,
|
||||
[current.networkId]: mergeListByIdentity(
|
||||
baseline.trackedTokens,
|
||||
current.trackedTokens,
|
||||
fresh.networkTrackedTokens[current.networkId],
|
||||
(token) => token.address.toLowerCase(),
|
||||
(base, ours) => ours,
|
||||
),
|
||||
};
|
||||
}
|
||||
merged.hasWallet = Boolean(merged.wallets && merged.wallets.length > 0);
|
||||
// Stamped on every write, never merged or diffed: the record that goes to
|
||||
// storage is in THIS build's shape whatever shape it was read in, which is
|
||||
@@ -607,15 +632,33 @@ function saveState(beforeWrite) {
|
||||
return turn;
|
||||
}
|
||||
|
||||
// Give this page the network switch held by `stored`, a record a save of this
|
||||
// page has just read (followStoredSettings() in src/popup/index.js calls this
|
||||
// from `beforeWrite`), in `state` and in `baseline` alike, as loadState() does
|
||||
// with a whole record. The switch is then not this page's own change, even when
|
||||
// Give this page the network switch held by `stored`, in `state` and in
|
||||
// `baseline` alike, as loadState() does with a whole record. `stored` is the
|
||||
// record that a save of this page has just read. followStoredSettings() in
|
||||
// src/popup/index.js and onChainSwitch() in src/shared/chainSwitch.js call this
|
||||
// from `beforeWrite`. The switch is then not this page's own change, even when
|
||||
// that save fails to write: a later switch back to the previous network still
|
||||
// differs from `baseline`, and is stored.
|
||||
//
|
||||
// A token that this page tracked or removed since its last save was tracked or
|
||||
// removed on this page's network before the switch. `state` keeps that change
|
||||
// in the list in `networkTrackedTokens` for that network, merged with the
|
||||
// stored list by contract address. `baseline` takes the stored list, so the
|
||||
// save stores the change (https://git.eeqj.de/sneak/AutistMask/issues/706).
|
||||
function takeStoredNetwork(stored) {
|
||||
const networkTrackedTokens = {
|
||||
...stored.networkTrackedTokens,
|
||||
[rawState.networkId]: mergeListByIdentity(
|
||||
baseline.trackedTokens,
|
||||
rawState.trackedTokens,
|
||||
stored.networkTrackedTokens[rawState.networkId],
|
||||
(token) => token.address.toLowerCase(),
|
||||
(base, ours) => ours,
|
||||
),
|
||||
};
|
||||
copyChainSwitchFields(rawState, stored);
|
||||
copyChainSwitchFields(baseline, structuredClone(stored));
|
||||
rawState.networkTrackedTokens = networkTrackedTokens;
|
||||
}
|
||||
|
||||
// Give this page the tracked tokens of `stored`, a record on this page's
|
||||
|
||||
Reference in New Issue
Block a user