fix: a dust threshold of 0 silently becomes 100,000 gwei, and isSpoofedSymbol is case-sensitive on the contract address #179
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Two small defects found while writing the first test coverage for the
anti-poisoning filters (#160 / PR #175), deliberately not fixed there. Both are
in
src/shared/transactions.jsand both are a few lines, so grouping them.1. A dust threshold of 0 is silently replaced by the default
src/shared/transactions.js:257:0is falsy, so a user who sets the threshold to0— the obvious way to say"do not hide anything as dust" — gets the 100,000 gwei default applied instead.
The wallet then hides transactions the user explicitly asked to see, with no
indication why.
This is reachable: the threshold is a free-text editable field at
src/popup/views/settings.js:305-310. It also directly contradictsREADME.md:810-814, which promises the user can "configure the wallet to showeverything unfiltered, unix-style" —
0is exactly how a user would expressthat, and it is the one value that does not work.
Requirements
??) or an explicitundefined/nulltest rather than||.0means: almost certainly "disable dustfiltering", which is also what the separate enable/disable checkbox does.
Make sure the two controls agree and neither silently overrides the other.
settings.js:305-310— confirm whathappens for empty string, negative numbers, and non-numeric input, and make
each behave sensibly rather than coercing to a surprising default. Say in
the PR what each now does.
src/shared/for the same||-as-default pattern applied to any othernumeric setting; this class of bug rarely appears once. Report what you find
even if you do not fix it here.
2.
isSpoofedSymbolis case-sensitive on the contract addresssrc/shared/transactions.js:209compares the contract address withoutnormalising case, unlike the blocklist check at
transactions.js:215-217,which lowercases correctly.
Ethereum addresses are routinely rendered in EIP-55 mixed-case checksum form.
A checksummed address for a genuine, known contract will therefore fail the
equality test and be misclassified as a spoof — a false positive that hides
a legitimate token transfer from the user's history.
The reporter notes this is currently unreachable in-app, because the addresses
reaching this function happen to already be lowercased upstream. That makes it
latent rather than live:
isSpoofedSymbolis an exported function, theinconsistency with the adjacent blocklist check is exactly the kind of thing a
later refactor trips over, and the failure direction is silent data loss from
the history view.
Requirements
transactions.js:209, thesame way
:215-217already does.transactions.jsfor the sameinconsistency and make them uniform. Prefer one shared normalisation helper
over repeating
.toLowerCase()at each site, so the next comparison addedcannot get it wrong.
not flagged as a spoof.
tests/transactions.test.jsalready has acurrent behaviour:test pinning the case-sensitive behaviour — invert itrather than deleting it.
Definition of done
0disables dust filtering rather than applying the100,000 gwei default.
the PR states what each does.
||-as-numeric-default insrc/shared/is reported.isSpoofedSymboltreats a checksummed genuine contract as genuine.transactions.jsare consistently normalised,ideally through one helper.
current behaviour:tests are inverted into regression guards.tests/transactions.test.jsstill pass unmodified.TODO.mdupdated in the same commit.make checkpasses.Additional requirement, from the mutation testing done during the review of
PR #175.
The reviewer applied 15 mutations to
src/shared/transactions.js; 13 werekilled by the new suite. One of the two survivors falls in the filter logic
this issue touches:
src/shared/transactions.js:244— removing thetx.holders !== nullguardsurvives undetected. No fixture pairs a non-null
contractAddresswith anull
holdersvalue, so the guard that stops the low-holder rule from actingon an unknown holder count is unpinned.
That is worth closing here rather than leaving it, because the failure
direction is bad: without the guard, a token whose holder count could not be
fetched (a Blockscout hiccup, a rate limit, a self-hosted instance that does
not return the field) would be treated as having zero holders and silently
filtered out of the user's history. That is over-filtering — the same class of
harm as the zero-threshold bug in part 1 of this issue, where the user asks to
see everything and the wallet hides things anyway.
Please add:
contractAddressandholders: null, asserting thetransaction is not filtered by the low-holder rule.
holders: undefinedif that is reachable from the Blockscoutresponse shape — check rather than assume.
!== nullguard,confirm at least one test fails, revert, and state the result in the PR as
PR #175 did.
Note this pairs naturally with part 1 of this issue. Both are cases where a
missing or falsy value is silently coerced into filtering behaviour the user
did not ask for —
|| 100000turning "show everything" into the defaultthreshold, and a null holder count turning "unknown" into "suspicious". Worth
checking whether there are other instances of the same shape in
transactions.jswhile you are there, and reporting them even if you do notfix them.