Compare commits

...

2 Commits

Author SHA1 Message Date
clawbot
585664f9d2 fix: move the UTC Timestamps checkbox into the Display well (closes #212)
Some checks failed
check / check (push) Has been cancelled
The `settings-utc-timestamps` checkbox sat inside the Token Spam Protection
well, immediately after the dust-threshold input. It is a display preference
and has nothing to do with spam filtering, so it now renders in the Display
well next to the theme selector.

Markup move only. The checkbox is wired by id — `$("settings-utc-timestamps")`
in `src/popup/views/settings.js`, where `$` is `document.getElementById` — for
both the initial `checked` assignment and the `change` handler, so nothing in
the wiring depends on the element's parent or siblings. `state.utcTimestamps`,
`saveState`/`loadState` and the `helpers.js` formatting path are untouched.

Both Settings descriptions follow the markup: the `README.md` Screen Map and
the `docs/README.md` Settings list each now name the UTC control under Display
and no longer under Token Spam Protection.

`tests/settingsUtcTimestamps.test.js` pins both halves down: the checkbox
appears exactly once and inside the Display well rather than the spam well,
and the setting still round-trips through storage.
2026-08-11 12:46:59 +00:00
cf5f582be9 docs: correct three README claims contradicted by the code (closes #213)
Some checks failed
check / check (push) Has been cancelled
2026-08-11 14:41:16 +02:00
5 changed files with 167 additions and 30 deletions

View File

@@ -346,17 +346,32 @@ The core hierarchy is **Wallets → Addresses**:
address scan on import, but imported from an extended private key rather address scan on import, but imported from an extended private key rather
than a recovery phrase. It therefore has no recovery phrase to display or than a recovery phrase. It therefore has no recovery phrase to display or
back up. back up.
- An **address** holds ETH and any user-added ERC-20 tokens. - An **address** holds ETH and ERC-20 tokens.
- The user can have multiple wallets, each with multiple addresses (HD) or a - The user can have multiple wallets, each with multiple addresses (HD) or a
single address (key). single address (key).
Which tokens an address shows is decided by `fetchTokenBalances()` in
`src/shared/balances.js`, from the Blockscout `token-balances` response, so
tokens do appear without the user adding them. An ERC-20 is shown when its
balance is nonzero and it is in the bundled top-250 token list, is tracked by
the user, or has 1,000 or more holders; a token claiming a symbol from the
bundled list from any other contract address is always dropped. 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.
Tracked tokens with a zero balance are listed as well while "Show tracked tokens
with zero balance" is on.
#### Navigation #### Navigation
The main view shows all addresses grouped by wallet, with ETH balances inline. The main view shows all addresses grouped by wallet, with ETH balances inline.
The user taps an address to see its detail view (full address, balance, tokens, The user taps an address to see its detail view (full address, balance, tokens,
send/receive). Navigation is flat — every view has a "Back" or "Cancel" button send/receive). Navigation is a stack: each forward action pushes the current
that returns to the previous context. No deep nesting, no tabs, no hamburger screen, and every view has a "Back" or "Cancel" button that pops back to it (see
menus. the Screen Map below). There is no hamburger menu and no persistent tab bar; the
Settings gear in the title bar is the only global control. Two screens carry an
in-screen control beyond that: AddWallet uses three tabs to select the import
mode, and AddressDetail keeps its one rarely-used action ("Export Private Key")
behind a "···" menu.
### Screen Map ### Screen Map
@@ -393,7 +408,7 @@ screen, including ExportPrivKey, falls back to Home.
- **When**: At least one wallet exists. This is the root screen. - **When**: At least one wallet exists. This is the root screen.
- **Elements**: - **Elements**:
- Active address ETH balance (large) + USD value in parentheses - Active address ETH balance (large) + USD value in parentheses
- "Total:" USD value across ETH and all tracked tokens of the active address - "Total:" USD value across ETH and every token shown for the active address
- Active address (color dot, full address, etherscan link, tap to copy) - Active address (color dot, full address, etherscan link, tap to copy)
- Send / Receive quick-action buttons, both acting on the active address - Send / Receive quick-action buttons, both acting on the active address
- ETH/USD price display - ETH/USD price display
@@ -401,7 +416,7 @@ screen, including ExportPrivKey, falls back to Home.
button for HD and xprv wallets, then one block per address with "Address button for HD and xprv wallets, then one block per address with "Address
N" (bold when active), the ENS name if resolved, the full address, an N" (bold when active), the ENS name if resolved, the full address, an
`[info]` button, the address USD total, and a balance line for ETH and for `[info]` button, the address USD total, and a balance line for ETH and for
each tracked token each token shown for that address
- "Recent Transactions": up to 25 transactions merged across every address - "Recent Transactions": up to 25 transactions merged across every address
of every wallet, deduplicated by hash and filtered of every wallet, deduplicated by hash and filtered
- "Add additional wallet..." link at bottom - "Add additional wallet..." link at bottom
@@ -454,8 +469,8 @@ screen, including ExportPrivKey, falls back to Home.
- ENS name (if resolved, bold above the address) - ENS name (if resolved, bold above the address)
- Full address (color dot, etherscan link, tap to copy) - Full address (color dot, etherscan link, tap to copy)
- USD total for address - USD total for address
- Balance list: ETH + tracked ERC-20 tokens (4 decimal places, USD inline). - Balance list: ETH + the ERC-20 tokens shown for this address (4 decimal
Each balance row is clickable → **AddressToken** places, USD inline). Each balance row is clickable → **AddressToken**
- Send / Receive / + Token buttons and a "···" menu button - Send / Receive / + Token buttons and a "···" menu button
- "···" dropdown containing a single "Export Private Key" entry - "···" dropdown containing a single "Export Private Key" entry
- Transaction list (with ENS resolution for counterparties) - Transaction list (with ENS resolution for counterparties)
@@ -680,8 +695,8 @@ screen, including ExportPrivKey, falls back to Home.
`[x]` delete button, plus a "+ Add wallet" button `[x]` delete button, plus a "+ Add wallet" button
- Tracked Tokens: one row per tracked token with an `[x]` remove button, - Tracked Tokens: one row per tracked token with an `[x]` remove button,
plus a "+ Add token" button plus a "+ Add token" button
- Display: "Show tracked tokens with zero balance" checkbox and a Theme - Display: "Show tracked tokens with zero balance" checkbox, "UTC
selector (System / Light / Dark) Timestamps" checkbox, and a Theme selector (System / Light / Dark)
- Network: network selector (Ethereum Mainnet / Sepolia Testnet); switching - Network: network selector (Ethereum Mainnet / Sepolia Testnet); switching
resets the RPC and Blockscout endpoints to that network's defaults resets the RPC and Blockscout endpoints to that network's defaults
- Ethereum RPC: endpoint URL input + "Save" button (validated against - Ethereum RPC: endpoint URL input + "Save" button (validated against
@@ -692,7 +707,6 @@ screen, including ExportPrivKey, falls back to Home.
- "Hide tokens with fewer than 1,000 holders" checkbox - "Hide tokens with fewer than 1,000 holders" checkbox
- "Hide transactions from detected fraud contracts" checkbox - "Hide transactions from detected fraud contracts" checkbox
- "Hide dust transactions below N gwei" checkbox + threshold input - "Hide dust transactions below N gwei" checkbox + threshold input
- "UTC Timestamps" checkbox
- Allowed Sites: list with remove buttons - Allowed Sites: list with remove buttons
- Denied Sites: list with remove buttons - Denied Sites: list with remove buttons
- About: project link, license, author, version, release date, and the - About: project link, license, author, version, release date, and the
@@ -861,7 +875,7 @@ communicates with three external services to function as a wallet:
What the extension does NOT do: What the extension does NOT do:
- No analytics or telemetry services - No analytics or telemetry services
- No token list APIs (user adds tokens manually by contract address) - No token list APIs (the top-250 token list is bundled at build time)
- No Infura/Alchemy dependency (any JSON-RPC endpoint works) - No Infura/Alchemy dependency (any JSON-RPC endpoint works)
- No backend servers operated by the developer - No backend servers operated by the developer
@@ -984,7 +998,8 @@ hardcoded test phrase.
- Add multiple addresses within an HD wallet - Add multiple addresses within an HD wallet
- Manage multiple wallets simultaneously - Manage multiple wallets simultaneously
- View ETH balance per address - View ETH balance per address
- View ERC-20 token balances (user adds token by contract address) - View ERC-20 token balances (bundled top-250 tokens, tokens with 1,000 or more
holders, and tokens the user adds by contract address)
- Send ETH to an address - Send ETH to an address
- Send ERC-20 tokens to an address - Send ERC-20 tokens to an address
- Receive ETH/tokens (display address, copy to clipboard, QR code) - Receive ETH/tokens (display address, copy to clipboard, QR code)
@@ -1130,7 +1145,8 @@ Currently supported:
- Built in token swaps (use a DEX in the browser) - Built in token swaps (use a DEX in the browser)
- Analytics, telemetry, or tracking of any kind - Analytics, telemetry, or tracking of any kind
- Advertisements or promotions - Advertisements or promotions
- Obscure token list auto-discovery (user adds tokens manually) - Obscure token list auto-discovery — nothing outside the bundled list, the
1,000-holder floor, and the tokens the user added by contract address
- We detect common/popular ERC20s in the basic case - We detect common/popular ERC20s in the basic case
- Fiat on/off ramps - Fiat on/off ramps
- Extensive transaction decoding/parsing - Extensive transaction decoding/parsing
@@ -1187,14 +1203,18 @@ This repository includes data files from third-party projects that are not
covered by the GPL-3.0 license above. These files, their copyright holders, and covered by the GPL-3.0 license above. These files, their copyright holders, and
their licenses are: their licenses are:
| File | Source | Copyright | License | | File | Source | Copyright | License |
| ---------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- | --------------------------------- | -------------------------------------------------------------- | | ---------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- | --------------------------------- | -------------------------------------------------------------- |
| `src/shared/phishingBlocklist.json` | [eth-phishing-detect](https://github.com/AugurProject/eth-phishing-detect) community-maintained phishing domain blocklist | Copyright (c) 2018 kumavis | [DBAD (Don't Be a Dick)](https://github.com/philsturgeon/dbad) | | `src/shared/phishingBlocklist.json` | `eth-phishing-detect` community-maintained phishing domain blocklist, vendored from its `src/config.json` | Copyright (c) 2018 kumavis | [DBAD (Don't Be a Dick)](https://github.com/philsturgeon/dbad) |
| `src/shared/scamlist.js` (address data from MyEtherWallet) | [ethereum-lists](https://github.com/MyEtherWallet/ethereum-lists) `addresses-darklist.json` | Copyright (c) 2020 MyEtherWallet | MIT | | `src/shared/scamlist.js` (address data from MyEtherWallet) | [ethereum-lists](https://github.com/MyEtherWallet/ethereum-lists) `addresses-darklist.json` | Copyright (c) 2020 MyEtherWallet | MIT |
| `src/shared/scamlist.js` (address data from EtherScamDB) | [EtherScamDB](https://github.com/MrLuit/EtherScamDB) `scams.yaml` | Copyright (c) 2018 Luit Hollander | MIT | | `src/shared/scamlist.js` (address data from EtherScamDB) | [EtherScamDB](https://github.com/MrLuit/EtherScamDB) `scams.yaml` | Copyright (c) 2018 Luit Hollander | MIT |
The full license texts for these third-party files are included in the The full license texts for these third-party files are included in the
[LICENSE](LICENSE) file. [LICENSE](LICENSE) file. The `eth-phishing-detect` row carries no repository
link because the upstream is hosted under a competitor's organization name,
which project policy keeps out of code and documentation; the vendored copy and
the runtime refresh both come from that upstream, whose URL is the
`BLOCKLIST_URL` constant in `src/shared/phishingDomains.js`.
## Author ## Author

View File

@@ -44,6 +44,12 @@ undefined identifiers, which is how
# Completed Steps # Completed Steps
- 2026-08-11: UTC Timestamps checkbox moved from the Token Spam Protection well
into Display, next to the theme selector
([#212](https://git.eeqj.de/sneak/AutistMask/issues/212)).
- 2026-08-11: Three `README.md` claims corrected against the code — blocklist
attribution, token-display rule, navigation model
([#213](https://git.eeqj.de/sneak/AutistMask/issues/213)).
- 2026-08-11: README Screen Map rebuilt from the code — every screen, element - 2026-08-11: README Screen Map rebuilt from the code — every screen, element
and transition re-verified against `src/popup/` and transition re-verified against `src/popup/`
([#164](https://git.eeqj.de/sneak/AutistMask/issues/164)). ([#164](https://git.eeqj.de/sneak/AutistMask/issues/164)).

View File

@@ -359,16 +359,16 @@ Click the gear icon on the home screen to access settings:
- **Wallets**: Your wallets, and "+ Add wallet". - **Wallets**: Your wallets, and "+ Add wallet".
- **Tracked Tokens**: The ERC-20 tokens tracked across all addresses, and "+ Add - **Tracked Tokens**: The ERC-20 tokens tracked across all addresses, and "+ Add
token". token".
- **Display**: Toggle whether tracked tokens with zero balance are shown, and - **Display**: Toggle whether tracked tokens with zero balance are shown, switch
choose the theme (System, Light, or Dark). timestamps to UTC, and choose the theme (System, Light, or Dark).
- **Network**: Switch between Ethereum Mainnet and Sepolia Testnet. Switching - **Network**: Switch between Ethereum Mainnet and Sepolia Testnet. Switching
resets the RPC and Blockscout endpoints to that network's defaults. resets the RPC and Blockscout endpoints to that network's defaults.
- **Ethereum RPC**: Change the Ethereum node endpoint. Default is a public RPC. - **Ethereum RPC**: Change the Ethereum node endpoint. Default is a public RPC.
You can use your own node for maximum privacy. You can use your own node for maximum privacy.
- **Blockscout API**: Change the Blockscout instance used for token balances and - **Blockscout API**: Change the Blockscout instance used for token balances and
transaction history. You can use a self-hosted instance. transaction history. You can use a self-hosted instance.
- **Token Spam Protection**: Toggle individual scam filters, set the dust - **Token Spam Protection**: Toggle individual scam filters and set the dust
transaction threshold, and switch timestamps to UTC. transaction threshold.
- **Allowed Sites / Denied Sites**: View and manage web3 site permissions. - **Allowed Sites / Denied Sites**: View and manage web3 site permissions.
- **About**: License, author, version, release date, and a link to the commit - **About**: License, author, version, release date, and a link to the commit
this build came from. this build came from.

View File

@@ -869,6 +869,12 @@
/> />
Show tracked tokens with zero balance Show tracked tokens with zero balance
</label> </label>
<label
class="text-xs flex items-center gap-1 cursor-pointer mb-2"
>
<input type="checkbox" id="settings-utc-timestamps" />
UTC Timestamps
</label>
<div class="text-xs flex items-center gap-1"> <div class="text-xs flex items-center gap-1">
<label for="settings-theme">Theme:</label> <label for="settings-theme">Theme:</label>
<select <select
@@ -979,12 +985,6 @@
/> />
<span class="text-xs text-muted">gwei</span> <span class="text-xs text-muted">gwei</span>
</div> </div>
<label
class="text-xs flex items-center gap-1 cursor-pointer mb-1"
>
<input type="checkbox" id="settings-utc-timestamps" />
UTC Timestamps
</label>
</div> </div>
<div class="bg-well p-3 mx-1 mb-3"> <div class="bg-well p-3 mx-1 mb-3">

View File

@@ -0,0 +1,111 @@
// Tests for the UTC Timestamps setting.
//
// The checkbox was moved out of the Token Spam Protection well and into the
// Display well next to the theme selector. It is wired by id through the $()
// helper, so the move cannot break the handler — but nothing in the suite said
// so. These tests pin both halves down: the markup lives in Display and
// nowhere else, and the value still round-trips through storage.
const fs = require("fs");
const path = require("path");
const POPUP_HTML = fs.readFileSync(
path.join(__dirname, "..", "src", "popup", "index.html"),
"utf8",
);
// The body of one `<div class="bg-well ...">` well, selected by its heading.
function wellWithHeading(html, heading) {
const headingIndex = html.indexOf(
'<h3 class="font-bold mb-1">' + heading + "</h3>",
);
expect(headingIndex).toBeGreaterThan(-1);
const start = html.lastIndexOf('<div class="bg-well', headingIndex);
const end = html.indexOf('<div class="bg-well', headingIndex);
return html.slice(start, end === -1 ? html.length : end);
}
describe("the UTC Timestamps checkbox placement", () => {
test("the checkbox appears exactly once in the popup markup", () => {
const matches = POPUP_HTML.match(/id="settings-utc-timestamps"/g);
expect(matches).toHaveLength(1);
});
test("it renders in the Display well, alongside the theme selector", () => {
const display = wellWithHeading(POPUP_HTML, "Display");
expect(display).toContain('id="settings-utc-timestamps"');
expect(display).toContain('id="settings-theme"');
});
test("it does not render in the Token Spam Protection well", () => {
const spam = wellWithHeading(POPUP_HTML, "Token Spam Protection");
expect(spam).not.toContain('id="settings-utc-timestamps"');
// The filters that do belong there are untouched.
expect(spam).toContain('id="settings-hide-low-holders"');
expect(spam).toContain('id="settings-hide-fraud-contracts"');
expect(spam).toContain('id="settings-hide-dust"');
expect(spam).toContain('id="settings-dust-threshold"');
});
});
describe("the UTC Timestamps setting round-trips through storage", () => {
let store;
function loadStateModule() {
store = {};
global.chrome = {
storage: {
local: {
get: async (key) =>
key in store ? { [key]: store[key] } : {},
set: async (obj) => Object.assign(store, obj),
},
},
};
jest.resetModules();
return require("../src/shared/state");
}
afterEach(() => {
delete global.chrome;
});
test("defaults to off with nothing persisted", async () => {
const { state, loadState } = loadStateModule();
await loadState();
expect(state.utcTimestamps).toBe(false);
});
test("an enabled checkbox is persisted and read back", async () => {
const first = loadStateModule();
// What the change handler in views/settings.js does.
first.state.utcTimestamps = true;
await first.saveState();
expect(store.autistmask.utcTimestamps).toBe(true);
// A fresh popup load sees it.
jest.resetModules();
const second = require("../src/shared/state");
expect(second.state.utcTimestamps).toBe(false);
await second.loadState();
expect(second.state.utcTimestamps).toBe(true);
});
test("turning it back off is persisted too", async () => {
const { state, saveState, loadState } = loadStateModule();
state.utcTimestamps = true;
await saveState();
state.utcTimestamps = false;
await saveState();
state.utcTimestamps = true;
await loadState();
expect(state.utcTimestamps).toBe(false);
});
});