diff --git a/README.md b/README.md
index f4e8ae7..c71e45d 100644
--- a/README.md
+++ b/README.md
@@ -12,16 +12,27 @@ intercepts tx status links to their own site instead of going to Etherscan, etc.
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.
+Everything you need, nothing you don't. We import as few libraries as possible
+and don't implement any crypto. By default the wallet sends user-specific data
+only to the Ethereum RPC endpoint. The user can change that endpoint in
+Settings; it defaults to a public node.
+
+Out of the box the extension contacts two services:
+
+- the configured RPC node, for blockchain interactions
+- a public CoinDesk API (no API key), for realtime prices. It is sent token
+ symbols and nothing else.
+
+Two more services are sent none of the user's data until the user turns them on.
+Each has a checkbox on the Welcome screen and in Settings:
+
+- "Use Blockscout": a Blockscout block-explorer API, for transaction history,
+ the tokens the user has not tracked, and transaction details
+- "Check recipients on Etherscan": a best-effort Etherscan label lookup of the
+ recipient 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.
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 +433,35 @@ 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 harness installs
+a route handler before the first popup page opens. From then on, the handler
+records every request the extension makes, from its pages and from its
+background worker. A request the background worker makes while it starts up
+comes earlier and is not recorded. The tests take these steps in order:
+
+- Welcome must offer "Use Blockscout" and "Check recipients on Etherscan"
+ unticked.
+- With neither ticked, Home, AddressDetail, AddressToken and ConfirmTx must each
+ show the line saying what is off.
+- The popup is then closed until the background has run a balance refresh of its
+ own. No recorded request may have gone to Blockscout or Etherscan.
+- "Use Blockscout" is ticked from AddressDetail's gear. On "Back", AddressDetail
+ must ask Blockscout for its history and no longer say the setting is off.
+ Blockscout must then be asked for the token balances.
+- The stub Blockscout then reports a token the user has not tracked. Home lists
+ it. "Use Blockscout" is unticked from AddressDetail's gear. On "Back", the
+ token must be gone from AddressDetail, from Send's token dropdown and from
+ Home. Those three screens must each show the line saying the setting is off.
+ The setting is then ticked again.
+- "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 settings stay on for the rest of the run. TransactionDetail with "Use
+Blockscout" off is not driven here, because 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 +885,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 +1429,36 @@ 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.
+
+The refresh asks Blockscout only while the user has "Use Blockscout" on. The
+setting is off until the user turns it on. While it is off:
+
+- Only tracked tokens are listed. Turning the setting off in Settings drops
+ every other token from every address at once.
+- A tracked token's entry has no holder count and no `decimals` from Blockscout.
+- A tracked token's balance uses the decimals from the bundled list, or else the
+ decimals saved when the token was tracked.
+
+A refresh that started before the setting changed saves nothing when it returns.
+
+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.
@@ -1578,6 +1632,13 @@ 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.
+Changing "Use Blockscout" or "Check recipients on Etherscan" in Settings makes
+every screen but Settings count as not yet rendered. "Back" then renders again
+any screen a reopened popup can render. A change to "Use Blockscout" also cuts
+the stack, as a network switch does (below). The cut drops Send, whose token
+dropdown was filled under the old setting. "Back" cannot render Send again. A
+change to "Check recipients on Etherscan" leaves the stack 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
saves it. Any other popup open meanwhile takes the switch from the stored
@@ -1619,8 +1680,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 with a line saying that the wallet sends the user's data only to
+ the Ethereum RPC endpoint unless one of the two checkboxes below is ticked
+ - In the well, the "Use Blockscout" and "Check recipients on Etherscan"
+ checkboxes, the same two as in Settings. Each has a sentence saying what
+ it sends and where. 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 +1709,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 +1718,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. This list then shows only the 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
@@ -1717,9 +1791,13 @@ view would leave a wallet one click from deletion.
- 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**
+ - While "Use Blockscout" is off, a line under the balance list: "Only
+ tracked tokens are listed, because "Use Blockscout" is off in Settings."
- 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). While "Use
+ Blockscout" is off, it shows only the line "No transaction history is
+ shown, because "Use Blockscout" is off in Settings."
- **Transitions**:
- Tap balance row → **AddressToken** (for that token)
- "Send" → **Send** (refuses with a flash message on a zero balance)
@@ -1787,9 +1865,13 @@ view would leave a wallet one click from deletion.
- Token contract well (ERC-20 only): full contract address (tap to copy,
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)
+ the token's balance-list entry has no holder count. That happens when:
+ - the explorer did not report a readable one
+ - "Use Blockscout" is off
+ - the token is not in the balance list
+ - Token-filtered transaction list (only this token's transfers). While "Use
+ Blockscout" is off, it shows only the line "No transaction history is
+ shown, because "Use Blockscout" is off in Settings."
- **Transitions**:
- "Send" → **Send** (token locked: the dropdown is replaced by a static
symbol and contract address)
@@ -1806,6 +1888,9 @@ view would leave a wallet one click from deletion.
- From: address with color dot + etherscan link
- What to send: token dropdown (or static display with contract address when
locked from AddressToken)
+ - While "Use Blockscout" is off, a line under the token dropdown: "Only
+ tracked tokens are listed, because "Use Blockscout" is off in Settings."
+ The line is hidden with the dropdown when Send is opened from AddressToken
- To: address or ENS name input, with an inline validation message
- Amount input with current balance display, which reads
`Current balance: unknown (SYMBOL)` for a token whose scale is unknown, as
@@ -1875,7 +1960,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. A line in its place says "This address was not checked on Etherscan,
+ because "Check recipients on Etherscan" is off in Settings." The box or
+ the line is chosen 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
@@ -2041,7 +2131,11 @@ 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. The block, network
+ details, decoded details and raw data are read only while "Use Blockscout" is
+ on. While it is off, 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 +2218,21 @@ 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:
+ - "Use Blockscout" checkbox, unticked until the user ticks it
+ - A sentence saying what it shows and what it sends. It sends the
+ Blockscout API the user's addresses and the hash of each transaction
+ opened
+ - Endpoint URL input + "Save" button. "Save" checks the URL by asking it
+ for `/stats` before saving it. That request carries no user data. It
+ is made whether or not "Use Blockscout" is ticked.
+ - Etherscan:
+ - "Check recipients on Etherscan" checkbox, unticked until the user
+ ticks it
+ - A sentence saying it sends each recipient's address to Etherscan to
+ check it for a phishing or scam label
+ - Each of the two settings applies to every network. Welcome offers the same
+ two checkboxes
- Token Spam Protection:
- "Hide fake tokens impersonating a known symbol" checkbox
- "Hide tokens with fewer than 1,000 holders" checkbox
@@ -2149,6 +2256,10 @@ 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. Unticking "Use Blockscout" also drops
+ every token the user has not tracked from every address
- "+ Add wallet" → **AddWallet**
- "+ Add token" → **SettingsAddToken**
- `[recovery phrase]` on an HD wallet → **ShowRecoveryPhrase**
@@ -2167,7 +2278,8 @@ view would leave a wallet one click from deletion.
nothing and tells the background nothing
- Ten clicks on the version → reveals the Debug well (no screen change)
- "Back" (or Settings gear again) → previous screen (Home); after a network
- switch, the stack is cut first (see the top of Screen Map)
+ switch or a change to "Use Blockscout", the stack is cut first (see the
+ top of Screen Map)
#### ShowRecoveryPhrase (`show-phrase`)
@@ -2324,6 +2436,8 @@ view would leave a wallet one click from deletion.
money. The predicate is `addressHoldsFunds()` in
`src/popup/views/helpers.js`, unrounded and token-aware. A balance is a
warning, never a refusal.
+ - While "Use Blockscout" is off, a line under the warning: "Only tracked
+ tokens are listed, because "Use Blockscout" is off in Settings."
- The rule that a wallet always keeps at least one address, and that
removing the last one means deleting the wallet from Settings
- Error line
@@ -2665,17 +2779,31 @@ 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 only to the Ethereum RPC endpoint. It also asks the CoinDesk price
+API for prices, sending token symbols and nothing else.
+
+Two more services are sent none of the user's data until the user turns on their
+settings:
+
+- Blockscout, with "Use Blockscout"
+- Etherscan, with "Check recipients on Etherscan"
+
+Both settings are on the Welcome screen and in Settings. Both are off in a new
+install. Each setting applies to 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
them the balance of every tracked token at every address (`balanceOf`),
estimate gas (`eth_estimateGas`), fetch nonces (`eth_getTransactionCount`),
broadcast transactions (`eth_sendRawTransaction`), and check transaction
- receipts. The default endpoint is a public RPC (configurable by the user to
- any endpoint they prefer, including a local node). By default the extension
- talks to `https://ethereum-rpc.publicnode.com`.
+ receipts. Every ENS lookup is made through it alone. A name whose resolver
+ says it is resolved off-chain therefore does not resolve. The default endpoint
+ is a public RPC (configurable by the user to any endpoint they prefer,
+ including a local node). By default the extension talks to
+ `https://ethereum-rpc.publicnode.com`.
- **Data sent**: Ethereum addresses, transaction data, contract call
parameters. The RPC endpoint can see all on-chain queries and submitted
transactions.
@@ -2687,13 +2815,39 @@ 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
+Sent the user's data only while the user has turned the setting on:
+
+- **Blockscout block-explorer API** ("Use Blockscout"): 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.
+ - **Used for**:
+ - 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, for Home,
+ AddressDetail, Send and DeleteAddress
+ - token holder counts, for spam filtering
+ - a transaction's block, network details and calldata, for
+ TransactionDetail
+ - **While the setting is off**: each of those screens shows a line saying
+ what it leaves out and that "Use Blockscout" is off. Only tracked tokens
+ are listed.
+ - **Saving the URL**: pressing "Save" beside the URL in Settings asks that
+ URL for `/stats`. This request 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's address and nothing else.
+
+The etherscan links on the screens open a page in the browser when the user
+clicks one. They are not requests the wallet makes. Nothing is fetched from them
+until the user clicks.
What the extension does NOT do:
@@ -2702,16 +2856,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. With
+"Use Blockscout" on, they can point the Blockscout URL at their own instance
+too.
### Dependencies
@@ -2893,8 +3040,11 @@ 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
+ - 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)
diff --git a/docs/README.md b/docs/README.md
index 424d7a2..67b1f68 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -57,11 +57,12 @@ analytics, use a portfolio tracker. The wallet is not the place for any of that.
- **No NFT galleries or portfolio views.** This is a wallet, not a dashboard.
-- **No third-party token list APIs.** Token balances come from the same block
- explorer you configure for transaction history, and the extension ships its
- own hardcoded list of top ERC-20 contract addresses for symbol-spoofing
- detection. Any token you want tracked across all your addresses, you add
- yourself by contract address.
+- **No third-party token list APIs.** The balances of the tokens you track are
+ read from your RPC endpoint. While "Use Blockscout" is on, the other tokens
+ come from the same block explorer you configure for transaction history. The
+ extension ships its own hardcoded list of top ERC-20 contract addresses for
+ symbol-spoofing detection. Any token you want tracked across all your
+ addresses, you add yourself by contract address.
- **No backend servers operated by the developer.** Nothing is sent to any
server run by AutistMask. Every network destination is listed below.
@@ -69,8 +70,13 @@ analytics, use a portfolio tracker. The wallet is not the place for any of that.
## How It Works
AutistMask is a browser extension that runs entirely in your browser. It does
-not have a backend server. It communicates with five external destinations:
-three you configure yourself, and two fixed ones used for scam detection.
+not have a backend server. Out of the box it sends your data only to the
+Ethereum RPC endpoint. It also asks the CoinDesk price API for prices, sending
+token symbols and nothing else.
+
+Blockscout and Etherscan are sent none of your data until you turn them on.
+Their settings are "Use Blockscout" and "Check recipients on Etherscan", on the
+Welcome screen and in Settings. Both are off in a new install.
### External Services
@@ -96,16 +102,31 @@ addresses are necessarily visible to the RPC provider when querying balances.
**Blockscout API** (default: `eth.blockscout.com/api/v2`;
`eth-sepolia.blockscout.com/api/v2` on Sepolia)
-Used to fetch token balances and transaction history. Blockscout is an
-open-source blockchain explorer. AutistMask queries it for your ERC-20 token
-balances (including the holder counts used for spam filtering) and your recent
-transactions and token transfers. You can change this in Settings to a
-self-hosted Blockscout instance.
+Blockscout is an open-source blockchain explorer. AutistMask uses it only while
+"Use Blockscout" is on. It then asks Blockscout for:
-When it is contacted: on every balance refresh, and whenever a screen showing
-transaction history is opened.
+- your recent transactions and token transfers
+- the balances of the tokens you have not tracked, with the holder counts used
+ for spam filtering
+- the block, fees and calldata of a transaction you open
-What gets sent: your Ethereum addresses (to look up balances and transactions).
+You can change this in Settings to a self-hosted Blockscout instance. While the
+setting is off, each screen that would show Blockscout's data says so instead.
+Only the tokens you track are listed. When you turn the setting off, every other
+token leaves the lists at once.
+
+When it is contacted, while "Use Blockscout" is on:
+
+- on every balance refresh
+- whenever a screen showing transaction history is opened
+- when you open a transaction
+
+Pressing "Save" beside the Blockscout URL in Settings also contacts it, even
+with the setting off. That request checks the URL by asking it for `/stats`. It
+sends none of your data.
+
+What gets sent: your Ethereum addresses (to look up balances and transactions)
+and the hash of each transaction you open.
**CoinDesk CADLI price API** (`data-api.coindesk.com`)
@@ -122,16 +143,19 @@ address.
**Etherscan address labels** (`etherscan.io`; `sepolia.etherscan.io` on Sepolia)
-When you review a send, AutistMask fetches the recipient's public Etherscan
-address page and looks for a "Fake_Phishing"/"Phish/Hack" label or a scam
-warning, and shows a red warning if it finds one. This is a plain page fetch
-with no API key, made by your browser. It is best-effort: if it fails, it is
-silently ignored. This endpoint is not user-configurable.
+Off until you turn on "Check recipients on Etherscan". When you review a send,
+AutistMask fetches the recipient's public Etherscan address page. It looks for a
+"Fake_Phishing"/"Phish/Hack" label or a scam warning, and shows a red warning if
+it finds one. This is a plain page fetch with no API key, made by your browser.
+It is best-effort: if it fails, it is silently ignored. This endpoint is not
+user-configurable. While it is off, the confirmation screen says that no
+Etherscan check was made.
-When it is contacted: each time you reach the send confirmation screen.
+When it is contacted: only while "Check recipients on Etherscan" is on, each
+time you reach the send confirmation screen.
-What gets sent: the recipient address you are about to send to, and your IP
-address. Your own addresses are not sent.
+What gets sent: the recipient's address and nothing else. As with any request,
+Etherscan sees your IP address.
Etherscan links shown elsewhere in the UI (on addresses, transactions, and token
contracts) are ordinary links. They contact nothing until you click them.
@@ -185,6 +209,9 @@ password.
1. Click the AutistMask icon in your browser toolbar.
2. Click "Add wallet" (on first use), or open Settings and click "+ Add wallet".
+ On first use, the screen with "Add wallet" also offers "Use Blockscout" and
+ "Check recipients on Etherscan", both off. Tick either if you want what it
+ does (see External Services). You can change both later in Settings.
3. On the "From Phrase" tab, click the die button to generate a random 12-word
recovery phrase.
4. **Write down the recovery phrase and store it safely.** Anyone with these
@@ -220,10 +247,14 @@ always produce the same sequence of addresses.
### Adding ERC-20 Tokens
-Tokens you hold show up automatically only if they are in the extension's
-bundled list of well-known tokens or have at least 1,000 holders; everything
-else is treated as spam and hidden. To track a token explicitly (which also
-shows it at zero balance), add it by contract address:
+Tokens you hold show up automatically only while "Use Blockscout" is on. Even
+then, a token shows up only if it is in the extension's bundled list of
+well-known tokens or has at least 1,000 holders. Everything else is treated as
+spam and hidden.
+
+A token you track is shown whether or not "Use Blockscout" is on. By default it
+is shown at zero balance too (see Display in Settings). To track a token, add it
+by contract address:
1. Go to an address detail view (click `[info]` on any address).
2. Click "+ Token".
@@ -389,8 +420,9 @@ Click the gear icon on the home screen to access settings:
that network's defaults if you have not used it before.
- **Ethereum RPC**: Change the Ethereum node endpoint. Default is a public RPC.
You can use your own node for maximum privacy.
-- **Blockscout API**: Change the Blockscout instance used for token balances and
- transaction history. You can use a self-hosted instance.
+- **Blockscout API**: the "Use Blockscout" checkbox, off until you tick it, and
+ the URL of the Blockscout instance. You can use a self-hosted instance.
+- **Etherscan**: "Check recipients on Etherscan", off until you tick it.
- **Token Spam Protection**: Toggle individual scam filters and set the dust
transaction threshold.
- **Allowed Sites / Denied Sites**: View and manage web3 site permissions.
diff --git a/src/background/index.js b/src/background/index.js
index f9d6b9d..6ae51ed 100644
--- a/src/background/index.js
+++ b/src/background/index.js
@@ -1386,6 +1386,10 @@ const RECENT_BALANCE_REFRESH_MS = Math.floor(BALANCE_REFRESH_PERIOD_MS / 2);
// back over them (https://git.eeqj.de/sneak/AutistMask/issues/577).
// lastBalanceRefresh is left as the switch set it, so the next tick refreshes
// the new network.
+//
+// Nothing is applied either when "Use Blockscout" stored NOW is not the one the
+// refresh ran with. Turning it off dropped the tokens the user has not tracked
+// (src/popup/views/settings.js), and this refresh must not bring them back.
async function backgroundRefresh() {
const s = await getState();
const now = Date.now();
@@ -1397,6 +1401,7 @@ async function backgroundRefresh() {
wallets,
s.rpcUrl,
s.blockscoutUrl,
+ s.useBlockscout,
s.trackedTokens,
s.networkId,
);
@@ -1410,6 +1415,7 @@ async function backgroundRefresh() {
await updateState((fresh) => {
if (fresh.networkId !== s.networkId) return;
+ if (fresh.useBlockscout !== s.useBlockscout) return;
for (const wallet of fresh.wallets) {
for (const addr of wallet.addresses || []) {
const got = refreshed.get(String(addr.address).toLowerCase());
diff --git a/src/popup/index.html b/src/popup/index.html
index b41cf9e..001c7e8 100644
--- a/src/popup/index.html
+++ b/src/popup/index.html
@@ -43,6 +43,38 @@
Welcome! To get started, add a wallet.
+
+
+ This wallet sends your data only to the Ethereum RPC
+ endpoint, unless you turn on one of these. You can
+ change them later in Settings.
+
+
+
+ Shows transaction history, tokens you have not tracked
+ and transaction details. Sends your addresses, and the
+ hash of each transaction you open, to the Blockscout
+ API.
+
+
+
+ Sends each recipient's address to Etherscan to check it
+ for a phishing or scam label.
+
+
-
+
+
+
+
+ Only tracked tokens are listed, because "Use
+ Blockscout" is off in Settings.
+
+
@@ -660,6 +714,13 @@
phishing/scam. Do not send funds to this address.
+
+ This address was not checked on Etherscan, because "Check
+ recipients on Etherscan" is off in Settings.
+
Blockscout API
+
+
+ Shows transaction history, tokens you have not tracked
+ and transaction details. Sends your addresses, and the
+ hash of each transaction you open, to the Blockscout API
+ below.
+
- Used to fetch token balances and transaction history.
Change this if you run your own Blockscout instance.
+
+
Etherscan
+
+
+ Sends each recipient's address to Etherscan to check it
+ for a phishing or scam label.
+
+
+
Token Spam Protection
@@ -1291,6 +1380,13 @@
>
+
+ Only tracked tokens are listed, because "Use Blockscout" is
+ off in Settings.
+
A wallet always keeps at least one address. To remove the
last one, delete the whole wallet from Settings instead.
@@ -1504,6 +1600,16 @@
+
+
+ No block, decoded details, network details or raw data are
+ shown, because "Use Blockscout" is off in Settings.
+
+
diff --git a/src/popup/index.js b/src/popup/index.js
index f05a031..11b7a37 100644
--- a/src/popup/index.js
+++ b/src/popup/index.js
@@ -79,14 +79,17 @@ let refreshTimer = null;
// A switch while the refresh ran cleared every address's balances
// (applyChainSwitchFields() in src/shared/chainSwitchFields.js), and the
// previous network's must not come back over them
-// (https://git.eeqj.de/sneak/AutistMask/issues/577). A dropped refresh is not
-// recorded as done. Results are copied by address, so an address added or
-// removed meanwhile is left as it is.
+// (https://git.eeqj.de/sneak/AutistMask/issues/577). The same holds when "Use
+// Blockscout" changed while the refresh ran. Turning it off dropped the tokens
+// the user has not tracked (views/settings.js), and this refresh must not bring
+// them back. A dropped refresh is not recorded as done. Results are copied by
+// address, so an address added or removed meanwhile is left as it is.
async function doRefreshAndRender() {
if (refreshInFlight) return;
refreshInFlight = true;
try {
const networkId = state.networkId;
+ const useBlockscout = state.useBlockscout;
const wallets = structuredClone(state.wallets);
await Promise.all([
refreshPrices(),
@@ -94,6 +97,7 @@ async function doRefreshAndRender() {
wallets,
state.rpcUrl,
state.blockscoutUrl,
+ useBlockscout,
state.trackedTokens,
networkId,
pageClosed.signal,
@@ -108,6 +112,8 @@ async function doRefreshAndRender() {
await saveState((stored) => {
if (state.networkId !== networkId) return false;
if (stored.networkId !== networkId) return false;
+ if (state.useBlockscout !== useBlockscout) return false;
+ if (stored.useBlockscout !== useBlockscout) return false;
for (const wallet of state.wallets) {
for (const addr of wallet.addresses) {
const got = refreshed.get(addr.address);
@@ -397,7 +403,7 @@ async function init() {
followNetworkSwitch();
if (!state.hasWallet) {
- showView("welcome");
+ welcome.show();
} else {
renderWalletList();
restoreView();
diff --git a/src/popup/viewRouter.js b/src/popup/viewRouter.js
index f0bf051..9055e59 100644
--- a/src/popup/viewRouter.js
+++ b/src/popup/viewRouter.js
@@ -38,10 +38,15 @@ function markViewRendered(view) {
if (view) renderedViews.add(view);
}
-// Begin a fresh page-load scope. The popup gets one by being loaded, and
-// asks for one after a network switch, because every screen then on the page
-// shows the previous network (showNewNetwork() in views/settings.js); the
-// unit tests, which simulate several page loads against one module
+// Begin a fresh page-load scope. The popup gets one by being loaded. It also
+// asks for one when every screen on the page is out of date:
+//
+// - after a network switch, since those screens show the previous network
+// (showNewNetwork() in views/settings.js)
+// - after "Use Blockscout" or "Check recipients on Etherscan" changes in
+// Settings, since those screens were drawn under the old setting
+//
+// The unit tests, which simulate several page loads against one module
// instance, ask for one too.
function resetRenderedViews() {
renderedViews.clear();
diff --git a/src/popup/views/addressDetail.js b/src/popup/views/addressDetail.js
index fa6646e..b022283 100644
--- a/src/popup/views/addressDetail.js
+++ b/src/popup/views/addressDetail.js
@@ -4,6 +4,7 @@ const {
showFlash,
balanceLinesForAddress,
txCounterpartyHtml,
+ HISTORY_OFF_TEXT,
addressTitle,
escapeHtml,
displaySymbol,
@@ -83,6 +84,8 @@ function show() {
ctx.showAddressToken();
});
});
+ // Tokens the user has not tracked are Blockscout's to report.
+ $("address-tokens-note").classList.toggle("hidden", !!state.useBlockscout);
renderSendTokenSelect(addr);
$("tx-list").innerHTML =
'
Loading...
';
@@ -99,6 +102,7 @@ async function loadTransactions(address) {
const rawTxs = await fetchRecentTransactions(
address,
state.blockscoutUrl,
+ state.useBlockscout,
currentNetwork().chainId,
);
const result = filterTransactions(rawTxs, {
@@ -155,6 +159,10 @@ async function loadTransactions(address) {
function renderTransactions(txs) {
const list = $("tx-list");
+ if (!state.useBlockscout) {
+ list.innerHTML = `
';
@@ -324,7 +330,7 @@ function init(_ctx) {
$("send-token").value = tokenId;
}
// Hide dropdown, show static token display
- $("send-token").classList.add("hidden");
+ $("send-token-dropdown").classList.add("hidden");
let staticHtml = `
${escapeHtml(displaySymbol(currentSymbol))}
`;
if (tokenId !== "ETH") {
staticHtml += `
${renderAddressHtml(tokenId)}
`;
diff --git a/src/popup/views/confirmTx.js b/src/popup/views/confirmTx.js
index 42a4ca8..14ad6ed 100644
--- a/src/popup/views/confirmTx.js
+++ b/src/popup/views/confirmTx.js
@@ -334,6 +334,11 @@ function show(txInfo) {
$("confirm-contract-warning").style.visibility = "hidden";
$("confirm-burn-warning").style.visibility = "hidden";
$("confirm-etherscan-warning").style.visibility = "hidden";
+ // While "Check recipients on Etherscan" is off, there is no Etherscan
+ // warning to reserve space for. A line in its place says so.
+ const etherscanOn = !!state.checkRecipientsOnEtherscan;
+ $("confirm-etherscan-warning").classList.toggle("hidden", !etherscanOn);
+ $("confirm-etherscan-note").classList.toggle("hidden", etherscanOn);
// Show burn warning via reserved element (in addition to inline warning)
if (isBurnAddress(txInfo.to)) {
@@ -612,6 +617,7 @@ async function checkRecipientHistory(txInfo) {
const asyncWarnings = await getFullWarnings(txInfo.to, provider, {
fromAddress: txInfo.from,
chainId: txInfo.chainId,
+ checkRecipientsOnEtherscan: state.checkRecipientsOnEtherscan,
});
// The user may have left this transaction while the checks were in
// flight; its warnings must not reach another recipient's screen.
diff --git a/src/popup/views/deleteAddress.js b/src/popup/views/deleteAddress.js
index fab26f9..9105ca6 100644
--- a/src/popup/views/deleteAddress.js
+++ b/src/popup/views/deleteAddress.js
@@ -119,6 +119,11 @@ function show(walletIdx, addrIdx) {
$("delete-address-recovery").textContent = recoveryPathText(wallet);
$("delete-address-balance").innerHTML = balanceWarningHtml(addr);
+ // Tokens the user has not tracked are Blockscout's to report.
+ $("delete-address-tokens-note").classList.toggle(
+ "hidden",
+ !!state.useBlockscout,
+ );
setFlash("");
showView("delete-address-confirm");
diff --git a/src/popup/views/deleteWallet.js b/src/popup/views/deleteWallet.js
index 384224f..b0a31e4 100644
--- a/src/popup/views/deleteWallet.js
+++ b/src/popup/views/deleteWallet.js
@@ -16,6 +16,7 @@ const {
broadcastActiveChanged,
} = require("../../shared/walletDelete");
const { INVISIBLE_CHARACTERS } = require("../../shared/symbolSpoof");
+const welcome = require("./welcome");
let deleteWalletIndex = null;
let lostPasswordIndex = null;
@@ -135,7 +136,7 @@ async function finishDelete(walletIdx) {
// Save before broadcasting: the background reads the active
// address back out of storage to build accountsChanged.
if (activeAddressChanged) broadcastActiveChanged();
- showView("welcome");
+ welcome.show();
return;
}
diff --git a/src/popup/views/helpers.js b/src/popup/views/helpers.js
index cd9fa8d..7022d8c 100644
--- a/src/popup/views/helpers.js
+++ b/src/popup/views/helpers.js
@@ -534,6 +534,11 @@ function addressTitle(address, wallets) {
const CONTRACT_CREATION_TEXT =
"This transaction creates a new contract. It has no recipient.";
+// What the transaction lists on Home, AddressDetail and AddressToken say while
+// the user has "Use Blockscout" off. Their history comes from Blockscout alone.
+const HISTORY_OFF_TEXT =
+ 'No transaction history is shown, because "Use Blockscout" is off in Settings.';
+
// The last two lines of a transaction history row: the counterparty's colour
// dot and name beside the amount, then its full address. A contract creation
// the user sent has no counterparty (its `to` is ""), so its row has the
@@ -799,6 +804,7 @@ module.exports = {
displaySymbol,
addressTitle,
CONTRACT_CREATION_TEXT,
+ HISTORY_OFF_TEXT,
txCounterpartyHtml,
formatAddressHtml,
renderAddressHtml,
diff --git a/src/popup/views/home.js b/src/popup/views/home.js
index dc542bc..275c4bb 100644
--- a/src/popup/views/home.js
+++ b/src/popup/views/home.js
@@ -7,6 +7,7 @@ const {
timeAgo,
addressDotHtml,
txCounterpartyHtml,
+ HISTORY_OFF_TEXT,
addressTitle,
escapeHtml,
displaySymbol,
@@ -100,6 +101,10 @@ let homeTxs = [];
function renderHomeTxList(ctx) {
const list = $("home-tx-list");
if (!list) return;
+ if (!state.useBlockscout) {
+ list.innerHTML = `