fix: answer eth_chainId and net_version from loaded state (closes #317)
Both methods answered from the module-level state singleton, which the MV3
worker never populates, so a cold worker reported mainnet 0x1 to a page whose
user was on Sepolia.
They now answer from getState(), the per-call detached storage read the other
read handlers already use. An earlier revision of this fix used loadState()
instead and was rejected in review: it replaces the whole singleton, and these
methods are page-callable with no connection gate (inpage.js sends eth_chainId
on every page load), so a load landing inside backgroundRefresh()'s network
round trip detached the address objects being mutated in place — persisting
pre-refresh balances while still stamping lastBalanceRefresh, letting a polling
page suppress background refreshes indefinitely.
The test stub now structured-clones on get and set, as chrome.storage.local
does. The aliasing stub it replaces was independently measured to hide this
defect class entirely: with the aliasing get restored and the defective handler
in place, the suite passes 794/794.
Verified failing first three ways: a plain singleton read fails the three
cold-worker cases; the rejected loadState() revision fails only the new
mid-refresh case ("1.5" expected, "0" received); moving saveState() ahead of
refreshBalances() fails that case and only it.
This commit was merged in pull request #319.
This commit is contained in:
18
TODO.md
18
TODO.md
@@ -44,6 +44,24 @@ but the review is broader than any of them.
|
||||
|
||||
# Completed Steps
|
||||
|
||||
- 2026-08-20: A page asking which chain the wallet is on is told the chain the
|
||||
user is actually on ([#317](https://git.eeqj.de/sneak/AutistMask/issues/317)).
|
||||
`eth_chainId` and `net_version` answered from `currentNetwork()`, which reads
|
||||
the module-level `state` singleton that nothing populates at module scope, so
|
||||
a service worker revived by the page's own message answered out of
|
||||
`DEFAULT_STATE` and reported mainnet `0x1`/`1` to a user on Sepolia — a dApp
|
||||
building its interaction for the wrong chain. Both now answer from
|
||||
`getState()`, the per-call detached storage read the other read handlers use,
|
||||
rather than from the singleton: these two are reachable by any page on every
|
||||
provider init, and mutating the shared singleton on that path would detach the
|
||||
wallet objects an in-flight `backgroundRefresh()` is mutating. The read side
|
||||
of the background was audited with it: the remaining singleton reads are the
|
||||
chain switch, the transaction verification path and `backgroundRefresh`, which
|
||||
each already load, and everything else answers from storage per call through
|
||||
`getState()`. One stale read is left named but unfixed, outside this issue's
|
||||
scope: `handleSendTransaction` builds its provider with no network name, so
|
||||
`getProvider()` falls back to the same unloaded singleton for ethers' static
|
||||
network hint.
|
||||
- 2026-08-20: The dApp approval screen no longer shows a token transfer it
|
||||
cannot scale as `0.0000`
|
||||
([#306](https://git.eeqj.de/sneak/AutistMask/issues/306)). `decodeCalldata`
|
||||
|
||||
Reference in New Issue
Block a user