Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a72f301fe1 |
@@ -1474,23 +1474,24 @@ tracked.
|
||||
|
||||
A tracked token is shown when its balance is nonzero, and any other ERC-20 when
|
||||
its balance is nonzero and it is in the bundled known-token list or has 1,000 or
|
||||
more holders. On Ethereum Mainnet, a token claiming a symbol from the bundled
|
||||
list from any other contract address is always dropped, tracked or not. On every
|
||||
network, a token claiming a label of the native asset is always dropped. Those
|
||||
labels are `"ETH"` and each network's `nativeCurrency`, such as `"SepoliaETH"`.
|
||||
That filter is unconditional — the "Hide tokens with fewer than 1,000 holders"
|
||||
setting governs the transaction history and the send-screen token selector, not
|
||||
this list. A token's holder count is unknown when the explorer reports none, or
|
||||
reports anything other than a whole number written in digits alone, such as
|
||||
`1,000` or `1e3` (`parseHoldersCount()` in `src/shared/holders.js`). This list
|
||||
does not take an unknown count as 1,000 or more, so such a token is shown only
|
||||
when it is on the bundled list or tracked. Every nonzero holding of a token
|
||||
shown is stored exactly, however small, but a holding below 0.000001 is left out
|
||||
of the balance lists, the send-screen token selector, the address total and the
|
||||
remove-address warning (`isBelowOneMillionth()` in
|
||||
`src/shared/amountDisplay.js`). The Send and confirmation screens show it when
|
||||
its token is the one being sent. Tracked tokens with a zero balance are listed
|
||||
as well while "Show tracked tokens with zero balance" is on.
|
||||
more holders. On Ethereum Mainnet, a token that claims a bundled token's symbol
|
||||
from another contract is always dropped, tracked or not. On every network, a
|
||||
token claiming a label of the native asset is always dropped. Those labels are
|
||||
`"ETH"` and each network's `nativeCurrency`, such as `"SepoliaETH"`. The balance
|
||||
list applies all three rules whatever the settings say. The "Hide tokens with
|
||||
fewer than 1,000 holders" setting governs only the transaction history and the
|
||||
send-screen token selector. A token's holder count is unknown when the explorer
|
||||
reports none, or reports anything other than a whole number written in digits
|
||||
alone, such as `1,000` or `1e3` (`parseHoldersCount()` in
|
||||
`src/shared/holders.js`). This list does not take an unknown count as 1,000 or
|
||||
more, so such a token is shown only when it is on the bundled list or tracked.
|
||||
Every nonzero holding of a token shown is stored exactly, however small, but a
|
||||
holding below 0.000001 is left out of the balance lists, the send-screen token
|
||||
selector, the address total and the remove-address warning
|
||||
(`isBelowOneMillionth()` in `src/shared/amountDisplay.js`). The Send and
|
||||
confirmation screens show it when its token is the one being sent. Tracked
|
||||
tokens with a zero balance are listed as well while "Show tracked tokens with
|
||||
zero balance" is on.
|
||||
|
||||
#### Stored state and its version
|
||||
|
||||
@@ -3198,27 +3199,25 @@ indexes it as a real token transfer.
|
||||
Ethereum mainnet ERC-20s taken from the CoinGecko API, with decimals verified
|
||||
on-chain and addresses EIP-55 checksummed; `TOKENS` in
|
||||
`src/shared/tokenList.js` is the authoritative set. It is bundled at build
|
||||
time and only changes when that file is regenerated. On Ethereum Mainnet, any
|
||||
token transfer claiming a symbol from this list (e.g. "ETH", "USDT", "USDC")
|
||||
but originating from an unrecognized contract address is identified as a spoof
|
||||
and filtered from display. On another network, the list's symbols are not
|
||||
checked, because the list holds mainnet contracts. The fake "Ethereum" token
|
||||
in the attack above used symbol "ETH" from contract
|
||||
`0xD05339f9Ea5ab9d9F03B9d57F671d2abD1F55c82`, which does not match the known
|
||||
WETH contract — so it would be caught by this check. Detecting a spoof is also
|
||||
what adds a contract to the fraud contract blocklist below; that is the only
|
||||
thing that populates it. In the transaction history the check is the "Hide
|
||||
fake tokens impersonating a known symbol" setting, on by default; with it off,
|
||||
spoofed transfers are shown and no new blocklist entries are learned from
|
||||
them. The send-screen token selector and the balance list apply the same check
|
||||
unconditionally, because they decide which tokens the user can act on and what
|
||||
the user believes they own rather than what the history displays. All three
|
||||
surfaces read the rule from `src/shared/symbolSpoof.js`, so they cannot answer
|
||||
the question differently. A symbol the list maps to no contract at all — the
|
||||
native asset's labels: `"ETH"` and every network's `nativeCurrency`, such as
|
||||
`"SepoliaETH"`, on every network — may be borne by no contract, so every
|
||||
ERC-20 claiming it is a spoof on all three. The user's real ETH balance is not
|
||||
an ERC-20 and is read over RPC, so the rule never sees it.
|
||||
time and only changes when that file is regenerated. On Ethereum Mainnet, a
|
||||
token that claims a symbol from this list, such as "USDT" or "USDC", is a
|
||||
spoof unless its contract is the listed one. The wallet hides it. The fake
|
||||
"Ethereum" token in the attack above used symbol "ETH" from contract
|
||||
`0xD05339f9Ea5ab9d9F03B9d57F671d2abD1F55c82`. No contract may bear "ETH", so
|
||||
that token is a spoof. Detecting a spoof is also what adds a contract to the
|
||||
fraud contract blocklist below; that is the only thing that populates it. In
|
||||
the transaction history the check is the "Hide fake tokens impersonating a
|
||||
known symbol" setting, on by default; with it off, spoofed transfers are shown
|
||||
and no new blocklist entries are learned from them. The send-screen token
|
||||
selector and the balance list apply the same check unconditionally, because
|
||||
they decide which tokens the user can act on and what the user believes they
|
||||
own rather than what the history displays. All three surfaces read the rule
|
||||
from `src/shared/symbolSpoof.js`, so they cannot answer the question
|
||||
differently. A symbol the list maps to no contract at all — the native asset's
|
||||
labels: `"ETH"` and every network's `nativeCurrency`, such as `"SepoliaETH"`,
|
||||
on every network — may be borne by no contract, so every ERC-20 claiming it is
|
||||
a spoof on all three. The user's real ETH balance is not an ERC-20 and is read
|
||||
over RPC, so the rule never sees it.
|
||||
|
||||
- **Low-holder token filtering**: Token transfers from ERC-20 contracts with
|
||||
fewer than 1,000 holders are hidden from transaction history by default.
|
||||
|
||||
@@ -3978,7 +3978,8 @@ function bundledToken(address, chainId) {
|
||||
// hides from the balance list, the history and the send selector at its own
|
||||
// address, so the user cannot spend it (issue #276). Naming every address
|
||||
// that bears the symbol is the only shape that says what is true; it does not
|
||||
// loosen the rule, because a contract outside the set is still a spoof.
|
||||
// loosen the rule. On Ethereum Mainnet, a contract outside the set is still a
|
||||
// spoof.
|
||||
const KNOWN_SYMBOLS = new Map();
|
||||
KNOWN_SYMBOLS.set("ETH", null);
|
||||
for (const network of Object.values(NETWORKS)) {
|
||||
|
||||
Reference in New Issue
Block a user