fix: Blockscout and Etherscan lookups are off until the user turns them on (closes #668)
check / check (push) Waiting to run
e2e / e2e-chrome (push) Waiting to run
e2e / e2e-firefox (push) Waiting to run

Out of the box the wallet sent the user's addresses to Blockscout for history
and token lookups, and each recipient to Etherscan for its label. Two settings,
"Use Blockscout" and "Check recipients on Etherscan", now gate those requests
where they are made. Both are off in a new profile and offered unticked on
Welcome and in Settings. While one is off, the screens that relied on it say so
in a plain line naming the setting; after either changes in Settings, Back
draws the screen it lands on again. README and the user guide say what is
contacted by default and what each setting adds.

Model: opus-5-5
This commit is contained in:
2026-10-21 14:29:38 +00:00
parent c316d9ee78
commit bd2b5ce96a
49 changed files with 1342 additions and 139 deletions
+156 -59
View File
@@ -14,14 +14,18 @@ None of the common alternatives work on Firefox.
Hence, a minimally viable ERC20 browser wallet/signer that works cross-platform.
Everything you need, nothing you don't. We import as few libraries as possible,
don't implement any crypto, and don't send user-specific data anywhere but a
(user-configurable) Ethereum RPC endpoint (which defaults to a public node). The
extension contacts three user-configurable services: the configured RPC node for
blockchain interactions, a public CoinDesk API (no API key) for realtime price
information, and a Blockscout block-explorer API for transaction history and
token balances. It also performs best-effort Etherscan address label lookups
during transaction confirmation. A community-maintained phishing domain
blocklist is built into the extension at build time and checked locally; nothing
is fetched for it at runtime.
(user-configurable) Ethereum RPC endpoint (which defaults to a public node)
unless the user turns on one of the two lookups below. Out of the box the
extension contacts the configured RPC node for blockchain interactions and a
public CoinDesk API (no API key) for realtime price information, which is sent
token symbols and nothing else. Two more services are sent none of the user's
data until the user turns them on, on the Welcome screen or in Settings: a
Blockscout block-explorer API for transaction history, the tokens the user has
not tracked and transaction details ("Use Blockscout"), and best-effort
Etherscan address label lookups during transaction confirmation ("Check
recipients on Etherscan"). A community-maintained phishing domain blocklist is
built into the extension at build time and checked locally; nothing is fetched
for it at runtime.
In the extension is a hardcoded list of the top ERC20 contract addresses. You
can add any ERC20 contract by contract address if you wish, but the hardcoded
@@ -422,6 +426,24 @@ It also covers the red banner on the Settings screen: switching the network
there to Sepolia must put up the `[TESTNET]` banner, and switching back to
mainnet must take it down, both while Settings is still on screen.
It also covers what a new install sends to Blockscout and Etherscan
([#668](https://git.eeqj.de/sneak/AutistMask/issues/668)). The route handler
records every request the extension makes, from its pages and its background
worker, from when the harness installs it, before the first popup page opens; a
request the background worker makes while it starts up, before then, is not
recorded. Welcome must offer "Use Blockscout" and "Check recipients on
Etherscan" unticked. With neither changed, Home, AddressDetail, AddressToken and
ConfirmTx must show the lines saying what is off; the popup is then closed until
the background has run a balance refresh of its own, and not one recorded
request may have gone to Blockscout or Etherscan. "Use Blockscout" is then
ticked from AddressDetail's gear: on "Back", AddressDetail must ask Blockscout
for its history and no longer say it is off, and Blockscout must then be asked
for the token balances. "Check recipients on Etherscan" is ticked from
ConfirmTx's gear: on "Back", ConfirmTx must ask Etherscan about the recipient
and show the label the stub page gives it. Both stay on for the rest of the run.
TransactionDetail with "Use Blockscout" off is not driven here, since no history
row leads to it then; the unit tests cover it.
It also covers the confirmation screen, for both a native ETH send and an ERC-20
send: Send disabled while the fee estimate is in flight, enabled once it lands,
the fee block quoting the expected cost and the reserve separately, the distinct
@@ -845,7 +867,8 @@ src/
views/ — one JS module per screen (home, send, approval, etc.)
shared/ — modules used by both popup and background
alarms.js — recurring background jobs (extension alarms API)
balances.js — ETH and tracked token balances via RPC, others via Blockscout
balances.js — ETH and tracked token balances via RPC, others via
Blockscout while "Use Blockscout" is on
constants.js — chain IDs, default RPC endpoint, ERC-20 ABI
ens.js — ENS forward/reverse resolution (popup only)
holders.js — holder-count parsing and the low-holder rule
@@ -1388,23 +1411,28 @@ that token's previous entry, as a failed ETH balance keeps its figure, or takes
Blockscout's entry from the same refresh when there is none. Every other token
comes from the Blockscout `token-balances` response (`fetchTokenBalances()`), so
tokens do appear without the user adding them, and they keep their previous
figures while Blockscout fails. 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. A token claiming a symbol
from the bundled list from any other contract address is always dropped, tracked
or not, and so is any token claiming a symbol that belongs to the native asset
and therefore has no legitimate contract at all (`"ETH"`, and every network's
`nativeCurrency`, such as `"SepoliaETH"`, on every network). 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
figures while Blockscout fails. Blockscout is asked only while the user has "Use
Blockscout" on. While it is off, as it is until the user turns it on, a tracked
token's entry has no holder count and no `decimals` of Blockscout's, so its
balance is stated at the scale the bundled list or the tracked token records,
and no other token is listed, those from earlier refreshes included. 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. A token claiming a symbol from the bundled list from any other
contract address is always dropped, tracked or not, and so is any token claiming
a symbol that belongs to the native asset and therefore has no legitimate
contract at all (`"ETH"`, and every network's `nativeCurrency`, such as
`"SepoliaETH"`, on every network). 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.
@@ -1576,7 +1604,10 @@ renders as it goes, and `viewRouter.js` records every screen that reaches
more — rendering it a second time would re-fetch and overwrite what it holds,
such as an edit typed into Settings and not yet saved. Home is the one screen
"Back" always re-renders, so the wallet list reflects anything that changed
while the user was away from it.
while the user was away from it. Changing "Use Blockscout" or "Check recipients
on Etherscan" in Settings makes every screen but Settings count as not yet
rendered, so "Back" renders the screen it lands on under the new setting; the
stack is left as it is.
A network switch leaves every screen on the page showing the previous network.
The user makes it in Settings, or approves a site's request and the background
@@ -1619,8 +1650,15 @@ view would leave a wallet one click from deletion.
screen in that case.
- **Elements**:
- "Welcome! To get started, add a wallet." text
- A well saying that the wallet sends the user's data only to the Ethereum
RPC endpoint unless one of the two settings in it is turned on, here or
later in Settings: the "Use Blockscout" and "Check recipients on
Etherscan" checkboxes, the same two as in Settings, each with its sentence
on what it sends and to whom. Both are unticked until the user ticks them
- "Add wallet" button
- **Transitions**:
- Ticking or unticking either checkbox → stores the setting, as Settings
does (no screen change)
- "Add wallet" → **AddWallet**
#### Home (`main`)
@@ -1641,6 +1679,8 @@ view would leave a wallet one click from deletion.
holding more than one address); the ENS name, if resolved, is below it;
then the full address on a row of its own, followed by the address USD
total and a balance line for ETH and for each token shown for that address
- While "Use Blockscout" is off, a line under the wallet list: "Only tracked
tokens are listed, because "Use Blockscout" is off in Settings."
- "Recent Transactions": up to 25 transactions merged across every address
of every wallet, deduplicated by hash and filtered. Each row is three
lines: age and direction, then the counterparty's colour dot (with our own
@@ -1648,7 +1688,11 @@ view would leave a wallet one click from deletion.
counterparty's full address on a row of its own. A contract creation has
no counterparty: its second line is the amount alone and its third line
says "This transaction creates a new contract. It has no recipient." The
transaction lists on AddressDetail and AddressToken draw the same rows
transaction lists on AddressDetail and AddressToken draw the same rows.
The history comes from Blockscout. While "Use Blockscout" is off,
Blockscout is not asked, and this list and those two show the one line "No
transaction history is shown, because "Use Blockscout" is off in
Settings."
- "Add additional wallet..." link at bottom
- **Transitions**:
- Tap address row → sets the active address and broadcasts
@@ -1716,10 +1760,13 @@ view would leave a wallet one click from deletion.
- Full address (color dot, etherscan link, tap to copy)
- USD total for address (see [Partial USD totals](#partial-usd-totals))
- Balance list: ETH + the ERC-20 tokens shown for this address (4 decimal
places, USD inline). Each balance row is clickable → **AddressToken**
places, USD inline). Each balance row is clickable → **AddressToken**.
While "Use Blockscout" is off, the line Home has under its wallet list
follows it
- Send / Receive / + Token buttons and a "···" menu button
- "···" dropdown containing a single "Export Private Key" entry
- Transaction list (with ENS resolution for counterparties)
- Transaction list (with ENS resolution for counterparties), or the line
Home's list shows while "Use Blockscout" is off
- **Transitions**:
- Tap balance row → **AddressToken** (for that token)
- "Send" → **Send** (refuses with a flash message on a zero balance)
@@ -1788,8 +1835,10 @@ view would leave a wallet one click from deletion.
etherscan link) plus name, symbol, decimals, holder count and project
website where known. The "Holders:" row is left out, not shown as 0, when
the token's balance-list entry has no holder count: the explorer did not
report a readable one, or the token is not in the balance list
- Token-filtered transaction list (only this token's transfers)
report a readable one, "Use Blockscout" is off, or the token is not in the
balance list
- Token-filtered transaction list (only this token's transfers), or the line
Home's list shows while "Use Blockscout" is off
- **Transitions**:
- "Send" → **Send** (token locked: the dropdown is replaced by a static
symbol and contract address)
@@ -1875,7 +1924,12 @@ view would leave a wallet one click from deletion.
recipient that has never sent a transaction and holds no ETH, recipient is
a contract, burn address, and an Etherscan phishing/scam label. An address
that has received ETH but never sent a transaction still holds that ETH,
so it gets no warning
so it gets no warning. The Etherscan label check is made only while "Check
recipients on Etherscan" is on. While it is off, the Etherscan box is left
out and a line in its place says "This address was not checked on
Etherscan, because "Check recipients on Etherscan" is off in Settings."
Which of the two is there is known when the screen is drawn, so neither
moves anything later
- Errors (an invalid amount), plus five reserved error boxes, so the balance
and the fee arriving later move nothing — the amount exceeds the balance
(for a token whose scale is unknown it says the token's balance is
@@ -1921,8 +1975,8 @@ view would leave a wallet one click from deletion.
are that network's, so a testnet transaction shows none, its From, To and
token contract links open that network's explorer, the balance read, the
fee estimate and the contract and never-sent recipient checks ask that
network's RPC endpoint, and the Etherscan label check asks that network's
explorer
network's RPC endpoint, and the Etherscan label check, when it is made,
asks that network's explorer
- "Sign & Send" (correct password) when the gas limit, a fee per gas or the
total fee the RPC endpoint fills in at signing is over its bound in
`assertWithinCeilings()` (`src/shared/approvalVerify.js`) → nothing is
@@ -2041,7 +2095,12 @@ view would leave a wallet one click from deletion.
AddressToken. The screen describes the transaction on the network it was sent
on, whichever network is active: its block, network details, decoded details
and raw data are read from that network's Blockscout, the one Settings has for
it, and its etherscan links open that network's explorer.
it, and its etherscan links open that network's explorer. They are read only
while "Use Blockscout" is on. The screen can still be shown with it off, when
the popup reopens onto it after the user turned the setting off; then
Blockscout is not asked, and a line in their place says "No block, decoded
details, network details or raw data are shown, because "Use Blockscout" is
off in Settings."
- **Elements** (grouped into logical blocks using light well containers; field
labels are self-explanatory so groups have no headings):
- "Transaction" heading, "Back" button
@@ -2124,8 +2183,18 @@ view would leave a wallet one click from deletion.
already active changes nothing and sends nothing
- Ethereum RPC: endpoint URL input + "Save" button (validated against
`eth_chainId` before being saved)
- Blockscout API: endpoint URL input + "Save" button (validated against
`/stats` before being saved)
- Blockscout API: a "Use Blockscout" checkbox, unticked until the user ticks
it, with a sentence saying it sends the user's addresses, and the hash of
each transaction opened, to the Blockscout API below, for transaction
history, tokens not tracked, and transaction details; then the endpoint
URL input + "Save" button (validated against `/stats` before being saved,
a request the user presses for that carries no user data, made whether or
not the checkbox is ticked)
- Etherscan: a "Check recipients on Etherscan" checkbox, unticked until the
user ticks it, with a sentence saying it sends the address about to be
sent to, to Etherscan, to look for a phishing or scam label on it. Both
checkboxes are one setting each for every network, and Welcome offers the
same two
- Token Spam Protection:
- "Hide fake tokens impersonating a known symbol" checkbox
- "Hide tokens with fewer than 1,000 holders" checkbox
@@ -2149,6 +2218,9 @@ view would leave a wallet one click from deletion.
- Debug: hidden until revealed, then an "Enable debug mode" checkbox that
turns on the red banner and verbose logging
- **Transitions**:
- Ticking or unticking "Use Blockscout" or "Check recipients on Etherscan" →
stores the setting (no screen change). The next balance refresh and every
screen drawn after that follow it
- "+ Add wallet" → **AddWallet**
- "+ Add token" → **SettingsAddToken**
- `[recovery phrase]` on an HD wallet → **ShowRecoveryPhrase**
@@ -2665,8 +2737,15 @@ view would leave a wallet one click from deletion.
### External Services
AutistMask is not a fully self-contained offline tool. It necessarily
communicates with three external services to function as a wallet:
AutistMask is not a fully self-contained offline tool. By default it sends the
user's data to one service only, the Ethereum RPC endpoint, and asks one more,
the CoinDesk price API, for prices with nothing but token symbols. Two more
services are sent none of the user's data until the user turns on the setting
for each, on the Welcome screen or in Settings: Blockscout ("Use Blockscout")
and Etherscan ("Check recipients on Etherscan"). Both settings are off in a new
profile, and each is one setting for every network.
Contacted by default:
- **Ethereum JSON-RPC endpoint**: The extension needs an Ethereum node to query
balances (`eth_getBalance`), read ERC-20 token contracts (`eth_call`), among
@@ -2687,13 +2766,36 @@ communicates with three external services to function as a wallet:
- **Data sent**: Token symbol strings only (e.g. "ETH", "USDC"). No
addresses or user-specific data.
- **Blockscout block-explorer API**: Used to fetch transaction history (normal
transactions and ERC-20 token transfers), ERC-20 token balances, and token
holder counts (for spam filtering). The default endpoint is
`https://eth.blockscout.com/api/v2` (configurable by the user in Settings).
- **Data sent**: Ethereum addresses. Blockscout receives the user's
addresses to query their transaction history and token balances. No
private keys, passwords, or signing operations are sent.
Contacted only while the user has turned the setting on:
- **Blockscout block-explorer API** ("Use Blockscout"): Used to fetch
transaction history (normal transactions and ERC-20 token transfers) for Home,
AddressDetail and AddressToken, the balances of the ERC-20 tokens the user has
not tracked, token holder counts (for spam filtering), and a transaction's
block, network details and calldata for TransactionDetail. The default
endpoint is `https://eth.blockscout.com/api/v2` (configurable by the user in
Settings). While the setting is off, those screens say in a plain line what is
not shown and that this setting turns it on, and only tracked tokens are
listed, their balances read through the RPC endpoint. The endpoint check
Settings makes when the user presses "Save" beside the URL asks only for
`/stats` and carries no user data; it is made whether or not the setting is
on.
- **Data sent**: Ethereum addresses, and the hash of each transaction the
user opens. Blockscout receives the user's addresses to query their
transaction history and token balances. No private keys, passwords, or
signing operations are sent.
- **Etherscan address labels** ("Check recipients on Etherscan"): When
confirming a transaction, the extension performs a best-effort lookup of the
recipient address on Etherscan to check for phishing/scam labels. This is a
direct page fetch with no API key; the user's browser makes the request. While
the setting is off, ConfirmTx says that no Etherscan check was made.
- **Data sent**: the recipient address. The user's own addresses are not
sent.
The etherscan links on the screens open a page in the browser when the user
clicks one. They are not requests the wallet makes, and nothing is fetched from
them until then.
What the extension does NOT do:
@@ -2702,16 +2804,9 @@ What the extension does NOT do:
- No Infura/Alchemy dependency (any JSON-RPC endpoint works)
- No backend servers operated by the developer
In addition to the three user-configurable services above (RPC endpoint,
CoinDesk price API, and Blockscout API), AutistMask also contacts:
- **Etherscan address labels**: When confirming a transaction, the extension
performs a best-effort lookup of the recipient address on Etherscan to check
for phishing/scam labels. This is a direct page fetch with no API key; the
user's browser makes the request.
Users who want maximum privacy can point the RPC and Blockscout URLs at their
own self-hosted instances (price fetching can be disabled in a future version).
Users who want maximum privacy can point the RPC URL at their own node, and,
when they turn Blockscout on, the Blockscout URL at their own instance (price
fetching can be disabled in a future version).
### Dependencies
@@ -2893,8 +2988,10 @@ logged.
- Add multiple addresses within an HD wallet
- Manage multiple wallets simultaneously
- View ETH balance per address
- View ERC-20 token balances (tokens on the bundled known-token list, tokens
with 1,000 or more holders, and tokens the user adds by contract address)
- View ERC-20 token balances (tokens the user adds by contract address, and,
while "Use Blockscout" is on, tokens on the bundled known-token list and
tokens with 1,000 or more holders)
- View transaction history and transaction details, while "Use Blockscout" is on
- Send ETH to an address
- Send ERC-20 tokens to an address
- Receive ETH/tokens (display address, copy to clipboard, QR code)