fix: a chain switch gives trackedTokens its own copy of the network's list (closes #719) #730
@@ -42,11 +42,15 @@ function applyChainSwitchFields(s, newNetworkId) {
|
|||||||
// Tracked tokens are kept per network the same way, because a contract
|
// Tracked tokens are kept per network the same way, because a contract
|
||||||
// address names a token on one network only. s.trackedTokens stays the
|
// address names a token on one network only. s.trackedTokens stays the
|
||||||
// active network's list, so nothing that reads it changes: the outgoing
|
// active network's list, so nothing that reads it changes: the outgoing
|
||||||
// list is put away under its network, and the incoming network's list, or
|
// list is put away under its network, and a copy of the incoming network's
|
||||||
// an empty one, takes its place.
|
// list, or an empty list, takes its place.
|
||||||
|
//
|
||||||
|
// It is a copy because a save writes a changed s.networkTrackedTokens whole,
|
||||||
|
// over any list another page stored. An add or removal on the active network
|
||||||
|
// must change only s.trackedTokens.
|
||||||
if (!s.networkTrackedTokens) s.networkTrackedTokens = {};
|
if (!s.networkTrackedTokens) s.networkTrackedTokens = {};
|
||||||
s.networkTrackedTokens[s.networkId] = s.trackedTokens;
|
s.networkTrackedTokens[s.networkId] = s.trackedTokens;
|
||||||
s.trackedTokens = s.networkTrackedTokens[net.id] || [];
|
s.trackedTokens = structuredClone(s.networkTrackedTokens[net.id] || []);
|
||||||
|
|
||||||
s.networkId = net.id;
|
s.networkId = net.id;
|
||||||
s.rpcUrl = remembered.rpcUrl || net.defaultRpcUrl;
|
s.rpcUrl = remembered.rpcUrl || net.defaultRpcUrl;
|
||||||
|
|||||||
@@ -466,6 +466,56 @@ test("a token another page removed on Ethereum Mainnet stays removed when this p
|
|||||||
expect(stored.trackedTokens).toEqual([]);
|
expect(stored.trackedTokens).toEqual([]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// This page switches to Sepolia, where TST is tracked. Another popup page has
|
||||||
|
// not taken that switch, and its save tracks DAI on Ethereum Mainnet. This page
|
||||||
|
// then adds a token on Sepolia. Its save changes only `trackedTokens`, so DAI
|
||||||
|
// stays on Ethereum Mainnet's list.
|
||||||
|
test("a token another page added on Ethereum Mainnet stays when this page adds a token on Sepolia", async () => {
|
||||||
|
const boot = await bootOnAddToken("mainnet", {
|
||||||
|
networkTrackedTokens: { sepolia: [SEPOLIA_TOKEN] },
|
||||||
|
});
|
||||||
|
expect(boot.pageErrors).toEqual([]);
|
||||||
|
await gearSwitchBack(boot);
|
||||||
|
boot.storage.write("autistmask", {
|
||||||
|
...boot.storage.read("autistmask"),
|
||||||
|
networkTrackedTokens: {
|
||||||
|
mainnet: [MAINNET_TOKEN],
|
||||||
|
sepolia: [SEPOLIA_TOKEN],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const added = await addNewToken(boot);
|
||||||
|
|
||||||
|
const stored = boot.storage.read("autistmask");
|
||||||
|
expect(stored.networkTrackedTokens.mainnet).toEqual([MAINNET_TOKEN]);
|
||||||
|
expect(stored.networkTrackedTokens.sepolia).toEqual([SEPOLIA_TOKEN]);
|
||||||
|
expect(stored.trackedTokens).toEqual([SEPOLIA_TOKEN, added]);
|
||||||
|
});
|
||||||
|
|
||||||
|
// This page tracks DAI on Ethereum Mainnet and switches to Sepolia, where TST is
|
||||||
|
// tracked. Another popup page has not taken that switch, and its save removes
|
||||||
|
// DAI from Ethereum Mainnet's list. This page then adds a token on Sepolia. Its
|
||||||
|
// save changes only `trackedTokens`, so DAI does not come back.
|
||||||
|
test("a token another page removed on Ethereum Mainnet stays removed when this page adds a token on Sepolia", async () => {
|
||||||
|
const boot = await bootOnAddToken("mainnet", {
|
||||||
|
trackedTokens: [MAINNET_TOKEN],
|
||||||
|
networkTrackedTokens: { sepolia: [SEPOLIA_TOKEN] },
|
||||||
|
});
|
||||||
|
expect(boot.pageErrors).toEqual([]);
|
||||||
|
await gearSwitchBack(boot);
|
||||||
|
boot.storage.write("autistmask", {
|
||||||
|
...boot.storage.read("autistmask"),
|
||||||
|
networkTrackedTokens: { mainnet: [], sepolia: [SEPOLIA_TOKEN] },
|
||||||
|
});
|
||||||
|
|
||||||
|
const added = await addNewToken(boot);
|
||||||
|
|
||||||
|
const stored = boot.storage.read("autistmask");
|
||||||
|
expect(stored.networkTrackedTokens.mainnet).toEqual([]);
|
||||||
|
expect(stored.networkTrackedTokens.sepolia).toEqual([SEPOLIA_TOKEN]);
|
||||||
|
expect(stored.trackedTokens).toEqual([SEPOLIA_TOKEN, added]);
|
||||||
|
});
|
||||||
|
|
||||||
// Another popup page records a fraud contract on Ethereum Mainnet after this
|
// Another popup page records a fraud contract on Ethereum Mainnet after this
|
||||||
// page's last save. The switch to Sepolia drops that fraud contract, as the
|
// page's last save. The switch to Sepolia drops that fraud contract, as the
|
||||||
// switch drops this page's own.
|
// switch drops this page's own.
|
||||||
|
|||||||
Reference in New Issue
Block a user