Commit Graph

3 Commits

Author SHA1 Message Date
c8e193335d fix: a shared ticker no longer hides one of its two real tokens (closes #276)
All checks were successful
check / check (push) Successful in 33s
KNOWN_SYMBOLS maps a symbol to the set of contract addresses that bear
it, instead of to one of them.

A ticker is not unique, and the bundled list proves it: seven of its 512
tokens -- FRAX, REUSD, TON, EURE, MSUSD, MUSD and JPYC -- share a symbol
with another bundled entry at a different real contract.  The table is
built from that list first-wins, so it kept the earlier entry of each
pair and the later one was judged a spoof of its own symbol at its own
address.  A user holding any of the seven saw it filtered out of the
balance list, the transaction history and the send token selector, and
so could not spend it through the UI.

Both contracts of every pair come from the same source fetch (CoinGecko,
2026-02-27, decimals verified on-chain), so neither is stale relative to
the other and there is nothing to prefer between them.  The fix is
therefore in the shape of the table rather than in its contents: no
address was picked and none was dropped.  isSpoofedSymbol() asks set
membership where it asked equality, which does not loosen the rule --
every address in a set is one the wallet ships as a real token, and a
contract outside the set is still a spoof.  The native-asset entry stays
null and still means no contract may bear the symbol.

The suite walked KNOWN_SYMBOLS, which is derived from TOKENS, so it
could only assert that the table agreed with itself.  It now also walks
TOKENS asserting that no bundled token is filtered at its own address --
the walk that would have caught this -- pins both contracts of each of
the seven by address, asserts a third contract bearing a shared ticker
is still filtered, and asserts every address the table vouches for is a
bundled token reporting that symbol.
2026-08-12 11:14:29 +00:00
e4c3708b84 fix: fold invisible characters before the known-symbol spoof check (closes #260)
All checks were successful
check / check (push) Successful in 36s
A token calling itself " ETH " missed the known-symbol table entirely, so the
spoof check reported it was not a spoof -- while HTML collapsed the whitespace
and displayed it as ETH next to the user's real ETH. One space defeated the
filter.

The symbol is now folded before the lookup: NFKC, remove what paints nothing,
trim, uppercase. The rule is "remove what paints nothing"; the Unicode classes
are how that is spelled, which is why U+007F is named separately -- it is a
control, reached by no class, and measures identical to no character at all.

Every width in the module comment was measured in the pinned browser rather
than reasoned about, and the boundary is pinned from both sides: widening to
all control characters fails the visible-controls test, narrowing back fails
the invisible-characters test. Two default-ignorable code points do paint a
box and are folded anyway, which can only hide a token that does not resemble
the symbol it folds to -- the harmless direction, recorded rather than glossed.

Confusables that are distinct letters, bidi reordering and interior whitespace
are knowingly left open and asserted open by tests.
2026-08-12 13:06:54 +02:00
1f41a07df2 fix: filter a fake ETH token from the balance list too (closes #235)
All checks were successful
check / check (push) Successful in 30s
2026-08-12 11:10:38 +02:00