## Summary
Adds Sepolia testnet support to AutistMask.
### Changes
- **New `src/shared/networks.js`** — centralized network definitions (mainnet + Sepolia) with chain IDs, default RPC/Blockscout endpoints, and block explorer URLs
- **State management** — `networkId` added to persisted state; defaults to mainnet for backward compatibility
- **Settings UI** — network selector dropdown lets users switch between Ethereum Mainnet and Sepolia Testnet
- **Dynamic explorer links** — all hardcoded `etherscan.io` URLs replaced with dynamic links from the current network config (`sepolia.etherscan.io` for Sepolia)
- **Background service** — `wallet_switchEthereumChain` now accepts both mainnet (0x1) and Sepolia (0xaa36a7); broadcasts `chainChanged` to connected dApps
- **Inpage provider** — fetches chain ID on init and updates dynamically via `chainChanged` events (no more hardcoded `0x1`)
- **Blockscout API** — uses `eth-sepolia.blockscout.com/api/v2` for Sepolia
- **Etherscan labels** — phishing/scam checks use the correct explorer per network
- **Price fetching** — skipped on testnets (testnet tokens have no real market value)
- **RPC validation** — checks against the selected network's chain ID, not hardcoded mainnet
- **ethers provider** — `getProvider()` uses the correct ethers `Network` for Sepolia
### API Endpoints Verified
| Service | Mainnet | Sepolia |
|---------|---------|--------|
| Etherscan | etherscan.io | sepolia.etherscan.io |
| Blockscout | eth.blockscout.com/api/v2 | eth-sepolia.blockscout.com/api/v2 |
| RPC | ethereum-rpc.publicnode.com | ethereum-sepolia-rpc.publicnode.com |
| CoinDesk (prices) | ✅ | N/A (skipped on testnet) |
closes#110
Reviewed-on: #137
THIS WAS ONESHOTTED USING OPUS 4. WTAF
Co-authored-by: clawbot <clawbot@noreply.example.org>
Co-committed-by: clawbot <clawbot@noreply.example.org>
When a token's balance entry is missing or incomplete (e.g. not yet
fetched from Blockscout), the address-token view and send view now
fall back to the built-in known token list for symbol, name, and
decimals instead of showing '?'.
Also includes token name in the balance object returned by
fetchTokenBalances so the contract info well can display it.
Fixes#51
Two issues that could cause ENS names to disappear:
1. refreshBalances: on ENS lookup error, addr.ensName was set to null,
wiping any previously resolved name. Now keeps the existing value
on error — only overwrites on successful lookup.
2. ens.js cache: failed lookups were cached as null for 12 hours,
preventing retries even after transient errors resolved. Now skips
caching on failure so subsequent lookups retry immediately.
Added debug logging to ENS reverse lookups in refreshBalances.
Token balances from Blockscout are now filtered before display.
A token only appears if it meets at least one criterion:
- In the known 511-token list (by contract address)
- Explicitly tracked by the user (added via + Token)
- Has >= 1,000 holders on-chain
Also rejects tokens spoofing a known symbol from a different
contract address (same check used for transaction filtering).
This prevents airdropped spam tokens like "OpenClaw" from
appearing in the wallet without the user ever tracking them.
Add debugFetch wrapper in log.js that logs method, URL, and body on
request, and status code on response. Replace all fetch() calls
across balances, transactions, tokens, background RPC proxy, and
settings validation with debugFetch.
Three layers of defense against address poisoning attacks:
1. Known symbol verification: tokens claiming a symbol from the
hardcoded top-250 list (e.g. "ETH", "USDT") but from an
unrecognized contract are identified as spoofs and always hidden.
Their contract addresses are auto-added to the fraud blocklist.
2. Low-holder filtering: tokens with <1000 holders are hidden from
both transaction history and the send token selector. Controlled
by the "Hide tokens with fewer than 1,000 holders" setting.
3. Fraud contract blocklist: a persistent local list of detected
fraud contract addresses. Transactions involving these contracts
are hidden. Controlled by the "Hide transactions from detected
fraud contracts" setting.
Both settings default to on and can be disabled in Settings.
Fetching and filtering are separated: fetchRecentTransactions returns
raw data, filterTransactions is a pure function applying heuristics.
Token holder counts are now passed through from the Blockscout API.
Scanning: check all gap-limit addresses in parallel per batch instead
of sequentially. For a wallet with 1 used address this reduces from
12 sequential RPC round-trips to 1 parallel batch + 1 small follow-up.
Display: add shared formatAddressHtml(address, ensName, maxLen) and
escapeHtml() to helpers.js. Use them in confirm-tx (was missing color
dot entirely) and approval view. Remove duplicate escapeHtml from
addressDetail.js.
Major changes:
- Fetch token balances and tx history from Blockscout API (configurable)
- Remove manual token discovery (discoverTokens) in favor of Blockscout
- HD address gap scanning on mnemonic import
- Duplicate mnemonic detection on wallet add
- EIP-6963 multi-wallet discovery + selectedAddress updates in inpage
- Two-tier balance refresh: 10s while popup open, 60s background
- Fix $0.00 flash before prices load (return null when no prices)
- No-layout-shift: min-height on total value element
- Aligned balance columns (42ch address width, consistent USD column)
- All errors use flash messages instead of off-screen error divs
- Settings gear in global title bar, add-wallet moved to settings pane
- Settings wells with light grey background, configurable Blockscout URL
- Consistent "< Back" buttons top-left on all views
- Address titles (Address 1.1, 1.2, etc.) on main and detail views
- Send view shows current balance of selected asset
- Clickable affordance policy added to README
- Shortened mnemonic backup warning
- Fix broken background script constant imports
Split popup/index.js (784 lines) into focused modules:
- shared/state.js: state management, storage persistence
- shared/wallet.js: mnemonic gen, HD derivation, signing
- shared/prices.js: price cache (5min TTL), USD formatting,
value aggregation (address → wallet → total)
- shared/balances.js: ETH + ERC-20 balance cache (60s TTL),
ENS lookup, token contract metadata lookup
- shared/vault.js: unchanged (libsodium encryption)
- shared/tokens.js: unchanged (token list + CoinDesk client)
- popup/index.js: view switching and event wiring only
Token tracking is now app-wide: trackedTokens stored in state,
balances fetched for all tracked tokens across all addresses.
Add Token now calls the real contract to read name/symbol/decimals.
Total portfolio value shown in 2x type on Home screen.