All checks were successful
check / check (push) Successful in 27s
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.
10 KiB
10 KiB