fix: filter a fake ETH token from the balance list too (closes #235)
All checks were successful
check / check (push) Successful in 26s

KNOWN_SYMBOLS maps "ETH" to null, and the three surfaces that show tokens
disagreed about what that means. The transaction history and the Send
token selector read it as "no contract may bear this symbol" and filtered
a fake ETH ERC-20; the balance list's guard required a non-null mapping,
so the same token was listed as a holding named ETH next to the user's
real ETH. That is the surface where the user forms their belief about
what they own.

The rule now lives in src/shared/symbolSpoof.js and all three sites call
it, so a fourth reading is not available to a future call site. A symbol
mapped to null belongs to the native asset and may be borne by no
contract at all; the native exemption is "has no contract address", not
"the symbol is ETH", so a second null-mapped entry needs no call-site
change.

The user's real ETH balance is untouched: it is read over RPC in
refreshBalances and never enters fetchTokenBalances, whose loop only
considers explorer rows of type ERC-20.

tests/symbolSpoof.test.js drives the same fake ETH token through all
three surfaces plus refreshBalances, which reports the native balance
unchanged while the fake token is gone. Its two balance-list cases were
watched failing against the unmodified call sites first.
This commit is contained in:
2026-08-12 08:46:02 +00:00
parent bd4bdcafc7
commit 88a5c92547
7 changed files with 383 additions and 54 deletions

View File

@@ -44,6 +44,15 @@ undefined identifiers, which is how
# Completed Steps
- 2026-08-12: The known-symbol spoof rule moved into `src/shared/symbolSpoof.js`
and is now the only copy. The balance list had exempted symbols the token list
maps to `null``"ETH"` alone — so a fake ETH ERC-20 was hidden from the
transaction history and the Send selector but listed as a holding named ETH. A
symbol with no legitimate contract may now be borne by no contract on any of
the three surfaces, and the native exemption is "has no contract address", so
a second null-mapped symbol needs no call-site change. The user's real ETH
balance is read over RPC and never passes through the rule
([#235](https://git.eeqj.de/sneak/AutistMask/issues/235)).
- 2026-08-12: An xprv wallet already in storage that was imported from a
non-master key is detected from the depth of its stored `xpub`, explained in
the wallet list, and blocked from signing, sending and private-key export