Compare commits
2
Commits
cd7f061806
...
de22b4edb0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
de22b4edb0 | ||
|
|
a65e84c2dd |
@@ -23,9 +23,8 @@ on: [push]
|
||||
# Gitea branch protection, which this repo does not configure, so a failure
|
||||
# here is a red mark a reviewer has to account for rather than a hard
|
||||
# block. Making e2e-chrome a required check is blocked while reports of the
|
||||
# Chrome suite failing under load are still open; the "In CI" section of
|
||||
# README.md names them. A gate that fails at random teaches people to merge
|
||||
# past red.
|
||||
# Chrome suite failing under load are still open. A gate that fails at random
|
||||
# teaches people to merge past red.
|
||||
#
|
||||
# Nothing here may pass vacuously. There is no continue-on-error and no
|
||||
# `|| true`. Both scripts exit non-zero when docker is missing, when the
|
||||
@@ -36,8 +35,7 @@ jobs:
|
||||
e2e-chrome:
|
||||
runs-on: ubuntu-latest
|
||||
# Bounds the image build, a cold cache included, and the three Chrome
|
||||
# programs, so a hung browser frees the shared runner. README.md
|
||||
# "In CI" has the measured times.
|
||||
# programs, so a hung browser frees the shared runner.
|
||||
timeout-minutes: 40
|
||||
steps:
|
||||
# actions/checkout v4.2.2, 2026-02-22
|
||||
@@ -47,8 +45,7 @@ jobs:
|
||||
e2e-firefox:
|
||||
runs-on: ubuntu-latest
|
||||
# Bounds the image build, a cold cache included, and both Firefox
|
||||
# programs, so a hung browser frees the shared runner. README.md
|
||||
# "In CI" has the measured times.
|
||||
# programs, so a hung browser frees the shared runner.
|
||||
timeout-minutes: 15
|
||||
steps:
|
||||
# actions/checkout v4.2.2, 2026-02-22
|
||||
|
||||
@@ -89,9 +89,13 @@ Load it:
|
||||
2. Turn on "Developer mode".
|
||||
3. Click "Load unpacked".
|
||||
4. Pick `dist/chrome/`.
|
||||
- Firefox: open `about:debugging#/runtime/this-firefox`, click "Load Temporary
|
||||
Add-on" and pick `dist/firefox/manifest.json`. A temporary add-on is unloaded
|
||||
when Firefox exits. Read Installing on Firefox below before relying on it.
|
||||
- Firefox:
|
||||
1. Open `about:debugging#/runtime/this-firefox`.
|
||||
2. Click "Load Temporary Add-on".
|
||||
3. Pick `dist/firefox/manifest.json`.
|
||||
|
||||
A temporary add-on is unloaded when Firefox exits. Read Installing on Firefox
|
||||
below before relying on it.
|
||||
|
||||
The user guide, [`docs/README.md`](docs/README.md), explains how to use the
|
||||
wallet. The release procedure is in [`docs/RELEASE.md`](docs/RELEASE.md).
|
||||
@@ -375,12 +379,18 @@ Three rules follow from the worker being stopped:
|
||||
worker stopping. Such a connection ends when the browser closes, when the
|
||||
active address changes, or when the site is removed in Settings.
|
||||
|
||||
Two things live only in the worker's memory and are lost when it stops: pending
|
||||
approvals and the record of broadcast nonces. An approval, and the site's
|
||||
request waiting on it, exist nowhere else. So while any approval is pending, the
|
||||
worker calls `runtime.getPlatformInfo()` every 20 seconds. Chrome counts that
|
||||
call as activity and keeps the worker running. The timer stops itself once
|
||||
nothing is pending.
|
||||
These things live only in the worker's memory and are lost when it stops:
|
||||
|
||||
- pending approvals;
|
||||
- the record of broadcast nonces;
|
||||
- the timer that keeps the worker running while an approval is pending;
|
||||
- the record of the one open transaction approval;
|
||||
- the job that sets up the alarms at every start, while it runs.
|
||||
|
||||
An approval, and the site's request waiting on it, exist nowhere else. So while
|
||||
any approval is pending, the worker calls `runtime.getPlatformInfo()` every 20
|
||||
seconds. Chrome counts that call as activity and keeps the worker running. The
|
||||
timer stops itself once nothing is pending.
|
||||
|
||||
Alarms the code no longer handles are listed in `OBSOLETE_ALARMS` and cleared on
|
||||
every start. The worker fetches nothing when it starts.
|
||||
@@ -903,7 +913,8 @@ not change. A flash message refuses:
|
||||
|
||||
- a token already tracked;
|
||||
- an address on the scam list;
|
||||
- a contract that fails the lookup.
|
||||
- a contract that fails the lookup;
|
||||
- a token that fakes a known symbol.
|
||||
|
||||
A network switch before the lookup answers adds nothing, and a flash message
|
||||
says so.
|
||||
@@ -1224,8 +1235,12 @@ holds for a new address, and for every address after a network switch. While it
|
||||
is `null`:
|
||||
|
||||
- the balance lists show "quantity unknown";
|
||||
- Home's ETH balance reads `unknown (ETH)`;
|
||||
- Send reads `Current balance: unknown (ETH)`, and "Max" fills in nothing;
|
||||
- Home's ETH balance reads `unknown (ETH)` on mainnet and `unknown (SepoliaETH)`
|
||||
on Sepolia;
|
||||
- with ETH selected, Send reads `Current balance: unknown (ETH)` on mainnet and
|
||||
`Current balance: unknown (SepoliaETH)` on Sepolia;
|
||||
- with ETH selected, "Max" fills in nothing and shows the flash message "This
|
||||
token's balance is unknown.";
|
||||
- "Send" is not refused for a zero balance;
|
||||
- the address has no total;
|
||||
- DeleteAddress shows its warning.
|
||||
@@ -1725,7 +1740,9 @@ The `Makefile` targets are thin shims over `script/`:
|
||||
|
||||
- `script/bootstrap`: install the dependencies. Node and yarn come from the
|
||||
system when present. Otherwise node comes from a pinned nvm install and yarn
|
||||
from corepack. Fails when node cannot find a package named in `package.json`.
|
||||
from corepack. When corepack and nvm are both missing, yarn comes from
|
||||
`npm install -g`. Fails when node cannot find a package named in
|
||||
`package.json`.
|
||||
- `script/setup`: `script/bootstrap`, then the git pre-commit hook.
|
||||
- `script/test`: build the `test` stage of the `Dockerfile` with `--no-cache`.
|
||||
The stage runs the jest suite, stopped at 90 seconds and rerun verbose on
|
||||
|
||||
+33
-21
@@ -60,7 +60,8 @@ settings.
|
||||
- "Check recipients on Etherscan". Etherscan is a block explorer website. With
|
||||
the setting on, the wallet fetches the recipient's Etherscan page each time
|
||||
you review a send. The wallet warns when Etherscan labels the address as
|
||||
phishing, scam, exploiter or wallet drainer. Only the recipient's address is
|
||||
phishing, scam, exploiter or wallet drainer. A wallet drainer is a contract
|
||||
that empties a wallet once given permission. Only the recipient's address is
|
||||
sent. The Etherscan server cannot be changed.
|
||||
|
||||
Each time a site's request opens a window, the wallet checks the site against a
|
||||
@@ -211,10 +212,18 @@ allowed or denied for it.
|
||||
|
||||
Getting the address back is not easy. "+" computes only addresses that this
|
||||
wallet has never listed. The removed address was listed once, so "+" skips it.
|
||||
The way back is to delete the whole wallet and import its backup again. After
|
||||
the import, the scan lists the address again if it holds ETH or has sent a
|
||||
transaction. Otherwise "+" may reach it again, because the new wallet has never
|
||||
listed it.
|
||||
The way back is to delete the whole wallet and import its backup again. The
|
||||
import lists the wallet's first address, then scans for used addresses. An
|
||||
address is used when it holds ETH or has sent a transaction. A read that fails
|
||||
during the scan counts the address as unused. The scan stops after five unused
|
||||
addresses in a row. When the scan finds two or more used addresses, the wallet
|
||||
lists those instead. The wallet does not list the removed address when:
|
||||
|
||||
- the scan finds two or more used addresses, and the address is not among them;
|
||||
- the scan finds fewer than two, and the address is not the first.
|
||||
|
||||
When the wallet does not list the address, "+" may reach it again, because the
|
||||
new wallet has never listed it.
|
||||
|
||||
### Deleting a wallet
|
||||
|
||||
@@ -245,9 +254,11 @@ else is treated as spam and hidden. Turning "Use Blockscout" off removes every
|
||||
untracked token from the lists at once.
|
||||
|
||||
The balance list and the send screen hide a token that carries a well-known
|
||||
symbol, `ETH` included, but comes from another contract. A token that fakes a
|
||||
known symbol cannot be tracked ("Not added: this token fakes a known symbol."),
|
||||
and is never listed at zero. See Scam protection.
|
||||
symbol but comes from another contract. `ETH` and `SepoliaETH` are well-known
|
||||
symbols on every network. The symbols of the built-in list are well-known on
|
||||
Ethereum Mainnet only. A token that fakes a known symbol cannot be tracked ("Not
|
||||
added: this token fakes a known symbol."), and is never listed at zero. See Scam
|
||||
protection.
|
||||
|
||||
### Tracking a token
|
||||
|
||||
@@ -263,8 +274,9 @@ From Settings, under Tracked Tokens, click "+ Add token". That screen offers the
|
||||
top 10 tokens as buttons, the top 100 in a dropdown, and a contract address
|
||||
field. The two lists are offered on Ethereum Mainnet only.
|
||||
|
||||
A line for the new token reads `quantity unknown` until a refresh has read its
|
||||
balance.
|
||||
While "Show tracked tokens with zero balance" is on, a line for the new token
|
||||
reads `quantity unknown` until a refresh has read its balance. With that setting
|
||||
off, the token has no line until a refresh has read its balance.
|
||||
|
||||
A token is tracked on the network that it was added on. Settings lists the
|
||||
tracked tokens of the active network, each with an `[x]` button that stops
|
||||
@@ -274,7 +286,8 @@ The wallet refuses to track:
|
||||
|
||||
- a token that is already tracked;
|
||||
- an address on its scam list;
|
||||
- a contract that does not answer as an ERC-20 token.
|
||||
- a contract that does not answer as an ERC-20 token;
|
||||
- a token that fakes a known symbol.
|
||||
|
||||
### The token screen
|
||||
|
||||
@@ -602,11 +615,11 @@ Blockscout reports no holder count for a token, the history and the send screen
|
||||
still show it. While "Use Blockscout" is off, no holder count is known.
|
||||
|
||||
Fraud contracts. When the wallet detects a fake token transfer, it adds the
|
||||
token's contract to a list that it keeps. While "Hide transactions from detected
|
||||
fraud contracts" is on, the history hides transfers from the contracts on that
|
||||
list. The send screen never offers those tokens. Turning "Hide fake tokens
|
||||
impersonating a known symbol" off also stops new contracts being added to the
|
||||
list.
|
||||
token's contract to a list. A network switch empties the list. While "Hide
|
||||
transactions from detected fraud contracts" is on, the history hides transfers
|
||||
from the contracts on that list. The send screen never offers those tokens.
|
||||
Turning "Hide fake tokens impersonating a known symbol" off also stops new
|
||||
contracts being added to the list.
|
||||
|
||||
Dust transactions. Scammers send tiny amounts of ETH from an address that
|
||||
resembles one you have dealt with, so that the similar address lands in your
|
||||
@@ -616,11 +629,10 @@ threshold starts at 100,000 gwei, which is 0.0001 ETH. A threshold of 0 hides
|
||||
nothing.
|
||||
|
||||
Known scam addresses. The wallet ships a list of addresses known for fraud,
|
||||
including phishing addresses and wallet drainers. A wallet drainer is a contract
|
||||
that empties a wallet once given permission. Sending to a listed address raises
|
||||
a warning on the confirmation screen, and a listed address cannot be tracked as
|
||||
a token. The list holds only addresses involved in fraud; it is not a sanctions
|
||||
list.
|
||||
including phishing addresses and wallet drainers. Sending to a listed address
|
||||
raises a warning on the confirmation screen, and a listed address cannot be
|
||||
tracked as a token. The list holds only addresses involved in fraud; it is not a
|
||||
sanctions list.
|
||||
|
||||
Addresses and hashes are shown in full, because address poisoning relies on
|
||||
shortened ones. The only shortened address is the label of a token with no known
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Turn a verified dist/ into the two distributable archives.
|
||||
//
|
||||
// Invoked by script/package, which runs `make build` first so that dist/ has
|
||||
// already been checked against the build's own receipt (see the Build Receipts
|
||||
// already been checked against the build's own receipt (see the Builds
|
||||
// section of README.md). This program does not build anything and does not
|
||||
// write into dist/: it reads the emitted tree and writes release/.
|
||||
//
|
||||
|
||||
@@ -60,12 +60,12 @@ main() {
|
||||
|
||||
echo "Running the Firefox e2e suite..."
|
||||
# --shm-size=1g: Firefox needs more than the default 64MB /dev/shm.
|
||||
# --network none: the suite stubs nothing, so this is what keeps the
|
||||
# run offline and deterministic. The extension swallows its own
|
||||
# fetch failures, so the popup flows work unchanged; see the
|
||||
# network note in README.md. Weaker than the Chrome suite's
|
||||
# fixture interception, and honestly so — it proves no request
|
||||
# escaped, but it cannot report which ones were attempted.
|
||||
# --network none: the container has no network, and the suite reaches
|
||||
# only the test page and stub node on loopback (README.md, Browser
|
||||
# tests). The extension swallows its own fetch failures, so the popup
|
||||
# flows work unchanged. Weaker than the Chrome suite's fixture
|
||||
# interception, and honestly so — it proves no request escaped, but it
|
||||
# cannot report which ones were attempted.
|
||||
# HOME=/tmp: the image's root home is not a reliable place for the
|
||||
# browser profile.
|
||||
#
|
||||
|
||||
@@ -18,11 +18,11 @@
|
||||
// updateState(fn) read fresh, apply fn to that fresh record, write it
|
||||
// back — all holding the lock every write of the stored
|
||||
// record takes, so no other write lands in between, by
|
||||
// the background or by any page (README, "Stored state
|
||||
// and its version"). The read is one storage round trip
|
||||
// ahead of the write rather than a page lifetime ahead of
|
||||
// it (which is what made the popup's saveState() need a
|
||||
// per-field merge against a baseline at all).
|
||||
// the background or by any page (README, "Stored data").
|
||||
// The read is one storage round trip ahead of the write
|
||||
// rather than a page lifetime ahead of it (which is what
|
||||
// made the popup's saveState() need a per-field merge
|
||||
// against a baseline at all).
|
||||
//
|
||||
// A handler that must both read and write therefore does its network work
|
||||
// against a snapshot it owns, and applies the RESULT inside updateState().
|
||||
@@ -72,7 +72,7 @@ async function updateStateOnce(mutate) {
|
||||
// src/shared/browserApi.js) is held from the read to the write: two
|
||||
// background turns, or a turn and a page's save, never interleave
|
||||
// (https://git.eeqj.de/sneak/AutistMask/issues/641). Every page's save waits
|
||||
// while it is held (README, "Stored state and its version").
|
||||
// while it is held (README, "Stored data").
|
||||
//
|
||||
// `mutate` must also not call updateState() itself, directly or through
|
||||
// anything it awaits: the inner turn waits for the lock the outer one holds,
|
||||
|
||||
@@ -319,12 +319,12 @@ function showTxApproval(details) {
|
||||
);
|
||||
}
|
||||
// A swap the decoder read no amount for, such as one whose V4 swap
|
||||
// action could not be read or a V4 exact-out swap. The wait and error
|
||||
// screens say the amount could not be decoded, with no currency after
|
||||
// it, rather than show the transaction's ETH value as the amount. A
|
||||
// swap paid in native ETH keeps that value: it is the ETH the swap
|
||||
// pays (for an exact-out swap, the most it pays), not a figure that
|
||||
// had to be read from the calldata.
|
||||
// action could not be read or a V4 exact-out swap. The wait, success
|
||||
// and error screens say the amount could not be decoded, with no
|
||||
// currency after it, rather than show the transaction's ETH value as
|
||||
// the amount. A swap paid in native ETH keeps that value: it is the
|
||||
// ETH the swap pays (for an exact-out swap, the most it pays), not a
|
||||
// figure that had to be read from the calldata.
|
||||
const tokenIn = decoded.details.find((d) => d.label === "Token In");
|
||||
if (
|
||||
tokenIn &&
|
||||
|
||||
@@ -83,10 +83,11 @@ function recoveryPathText(wallet) {
|
||||
// rounded number would report "0.0000 ETH" for an address holding real money.
|
||||
// The lines below it carry the amounts, in the same format as Home and
|
||||
// AddressDetail, followed by the USD total when there is one to give — no
|
||||
// total line at all on testnet or before the first price fetch, and no figure
|
||||
// when every holding here is one with no price, since "$0.00" directly under
|
||||
// "This address holds a balance." is a contradiction. A token holding below
|
||||
// 0.000001 does not count, as the lines below leave it out.
|
||||
// total line at all on testnet, before the first price fetch or while no
|
||||
// refresh has read the ETH balance, and no figure when every holding here is
|
||||
// one with no price, since "$0.00" directly under "This address holds a
|
||||
// balance." is a contradiction. A token holding below 0.000001 does not count,
|
||||
// as the lines below leave it out.
|
||||
//
|
||||
// While no refresh has read the ETH balance the address may be empty, so the
|
||||
// sentence says "may hold".
|
||||
|
||||
@@ -272,7 +272,7 @@ function clearFlash() {
|
||||
}
|
||||
|
||||
// The flash line reserves exactly one line, and a message that wrapped would
|
||||
// push the screen below it down (README, No Layout Shift). So #flash-msg never
|
||||
// push the screen below it down (README, Appearance). So #flash-msg never
|
||||
// wraps: text too long for the line is cut with an ellipsis, and the whole
|
||||
// message is also put in the line's title. Write messages to fit, at most 50
|
||||
// characters, so none is cut.
|
||||
@@ -528,9 +528,9 @@ const ADDRESS_MIN_DISPLAY_LEN = 32;
|
||||
|
||||
// Truncate the middle of a string, replacing removed characters with "…".
|
||||
// Safety: refuses to truncate more than 10 characters, which is the maximum
|
||||
// that still prevents address spoofing attacks (see Display Consistency in
|
||||
// README). Callers that need to display less should use a different UI
|
||||
// approach rather than silently making addresses insecure.
|
||||
// that still prevents address spoofing attacks (see Addresses in README).
|
||||
// Callers that need to display less should use a different UI approach rather
|
||||
// than silently making addresses insecure.
|
||||
function truncateMiddle(str, maxLen) {
|
||||
if (str.length <= maxLen) return str;
|
||||
const removed = str.length - maxLen + 1; // +1 for the ellipsis char
|
||||
@@ -633,9 +633,9 @@ function formatAddressHtml(address, ensName, maxLen, title) {
|
||||
return renderAddressHtml(address, { title, ensName, maxLen });
|
||||
}
|
||||
|
||||
// A transaction's time as every screen shows it (README, Display
|
||||
// Consistency): the ISO datetime, in UTC when the UTC Timestamps setting is
|
||||
// on, and the relative age. Views import these two; they keep no copies.
|
||||
// A transaction's time as every screen shows it (README, Amounts): the ISO
|
||||
// datetime, in UTC when the UTC Timestamps setting is on, and the relative age.
|
||||
// Views import these two; they keep no copies.
|
||||
function isoDate(timestamp) {
|
||||
const d = new Date(timestamp * 1000);
|
||||
const pad = (n) => String(n).padStart(2, "0");
|
||||
|
||||
@@ -265,7 +265,7 @@ async function renderSiteLists() {
|
||||
// A network switch, made by the user here or saved by the background once the
|
||||
// user approved a site's request (src/popup/index.js), leaves every screen on
|
||||
// the page showing the previous network. Two functions leave the page as
|
||||
// README's Screen Map describes:
|
||||
// README's Navigation section describes:
|
||||
//
|
||||
// - cutViewStack(), before the switch is saved, so that save keeps the cut for
|
||||
// a popup closed straight after
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// The 4-decimal amount rule from README.md's Display Consistency section, and
|
||||
// The 4-decimal amount rule from README.md's Amounts section, and
|
||||
// the one exception to it, in one place. Three call sites had grown their own
|
||||
// copy of the truncation — the history and balance lists
|
||||
// (`src/shared/transactions.js`), the approval screen's ERC-20 amount line
|
||||
|
||||
@@ -240,10 +240,9 @@ function onStorageChanged(listener) {
|
||||
/**
|
||||
* Run `fn` while holding the browser's lock called `name`
|
||||
* (`navigator.locks`), and settle as `fn` settles. Every page of the extension
|
||||
* and its background share these locks, except a page in a Firefox private
|
||||
* window (README, "Stored state and its version"), so while one of them holds
|
||||
* `name` another asking for it waits, in the order they asked. The lock is let
|
||||
* go when `fn` settles, whether it resolved or rejected.
|
||||
* and its background share these locks, so while one of them holds `name`
|
||||
* another asking for it waits, in the order they asked. The lock is let go when
|
||||
* `fn` settles, whether it resolved or rejected.
|
||||
*
|
||||
* Every write of the stored record holds the lock named after its key,
|
||||
* "autistmask", from its read to its write: saveState() in
|
||||
@@ -266,8 +265,8 @@ function withLock(name, fn) {
|
||||
|
||||
// `storage.session`, the browser's session storage: what is kept there lasts
|
||||
// until the browser closes. It survives the background worker being stopped
|
||||
// and started again, which module-level variables do not (README, Background
|
||||
// scheduling). The background keeps the connections allowed without
|
||||
// and started again, which module-level variables do not (README, The
|
||||
// background worker). The background keeps the connections allowed without
|
||||
// "Remember" there; see src/background/index.js. Firefox has it from version
|
||||
// 115, the minimum manifest/firefox.json declares.
|
||||
//
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
// The floor of the approval screen's amount line.
|
||||
//
|
||||
// Amounts are truncated to four decimal places for scannability (README.md,
|
||||
// Display Consistency). With the token's true scale resolved, that truncation
|
||||
// can still take a real amount below the floor and print it as `0.0000`: one
|
||||
// base unit of an 18-decimal token, or a few hundred of an 8-decimal one. On
|
||||
// the one screen whose job is to state what is being authorized, a nonzero
|
||||
// transfer or allowance then reads as nothing.
|
||||
// Amounts). With the token's true scale resolved, that truncation can still
|
||||
// take a real amount below the floor and print it as `0.0000`: one base unit of
|
||||
// an 18-decimal token, or a few hundred of an 8-decimal one. On the one screen
|
||||
// whose job is to state what is being authorized, a nonzero transfer or
|
||||
// allowance then reads as nothing.
|
||||
//
|
||||
// The invariant asserted here is narrow: a nonzero amount never renders as
|
||||
// zero. The four-decimal rule itself is unchanged, and the string the
|
||||
|
||||
@@ -74,7 +74,7 @@ describe("parsing the dust threshold", () => {
|
||||
});
|
||||
|
||||
describe("the rejection message", () => {
|
||||
// README, Language & Labeling: error messages are full sentences.
|
||||
// README, Wording: error messages are full sentences.
|
||||
test("is a full sentence naming the constraint", () => {
|
||||
expect(DUST_THRESHOLD_MESSAGE).toMatch(/^[A-Z].*\.$/);
|
||||
expect(DUST_THRESHOLD_MESSAGE).toContain("whole number of gwei");
|
||||
@@ -95,9 +95,9 @@ describe("the flash line the message is shown in", () => {
|
||||
// NOT and CANNOT assert that the message fits inside it: jest runs on
|
||||
// the node environment here, with no layout engine, so every rendered
|
||||
// height is zero. An earlier version of this block claimed to pin the
|
||||
// No Layout Shift policy with this regex, and it passed at any message
|
||||
// length, including one that wrapped to two lines and pushed the
|
||||
// settings view down 12px.
|
||||
// reserved space rule in README, Appearance, with this regex, and it
|
||||
// passed at any message length, including one that wrapped to two lines
|
||||
// and pushed the settings view down 12px.
|
||||
//
|
||||
// The line cuts a message too long for it with an ellipsis (see
|
||||
// showFlash() in src/popup/views/helpers.js). The assertions that
|
||||
|
||||
+5
-5
@@ -1280,7 +1280,7 @@ test("the correct password reveals the full phrase, and nothing logs it (#161)",
|
||||
);
|
||||
assert(!promptShown, "the password prompt is still shown after unlock");
|
||||
|
||||
// Full Identifiers Policy: shown whole, and copyable.
|
||||
// README, ShowRecoveryPhrase: shown whole, and copyable.
|
||||
const title = await env.page.getAttribute(
|
||||
"#show-phrase-value",
|
||||
"title",
|
||||
@@ -2255,7 +2255,7 @@ async function waitForFilledFlashLine(page) {
|
||||
}
|
||||
}
|
||||
|
||||
// README, No Layout Shift: the rejection message goes into #flash-msg,
|
||||
// README, Appearance: the rejection message goes into #flash-msg,
|
||||
// whose min-h-[1.25rem] reserves exactly ONE line at text-xs, and which
|
||||
// cuts a message too long for that line with an ellipsis rather than wrap
|
||||
// it. This shows the real message and measures that nothing moves; the
|
||||
@@ -2603,7 +2603,7 @@ function toHexWei(wei) {
|
||||
}
|
||||
|
||||
// A fee in wei as the confirmation screen writes it: truncated to four decimal
|
||||
// places (README.md, Display Consistency). Deliberately a second
|
||||
// places (README.md, Amounts). Deliberately a second
|
||||
// implementation rather than an import of src/shared/amountDisplay.js:
|
||||
// asserting against an independent rendering is stronger than asserting a
|
||||
// function equals itself. The fixture's fees are above 0.0001 ETH, so the
|
||||
@@ -3298,7 +3298,7 @@ async function goToTokenConfirm(env) {
|
||||
amount: TOKEN_AMOUNT,
|
||||
});
|
||||
await waitForEstimate(env.page);
|
||||
// TOKEN_AMOUNT to four decimal places (README.md, Display Consistency).
|
||||
// TOKEN_AMOUNT to four decimal places (README.md, Amounts).
|
||||
const shown = await shownAmount(env.page);
|
||||
assert(
|
||||
shown === "0.2500 " + STUB_TOKEN.symbol,
|
||||
@@ -3453,7 +3453,7 @@ test("a token that lies about decimals() at signing time broadcasts nothing (#30
|
||||
|
||||
// ------------------------- a send Sign & Send refuses moves nothing (#583)
|
||||
//
|
||||
// README, No Layout Shift. Sign & Send refuses a send on the confirmation
|
||||
// README, Appearance. Sign & Send refuses a send on the confirmation
|
||||
// screen when the active network changed since review and when its gas limit
|
||||
// or fee is over its bound, and each refusal's sentence sits in a box that held
|
||||
// its space from the first paint. This drives the total fee refusal, the longer
|
||||
|
||||
@@ -165,9 +165,9 @@ describe("declared icons", () => {
|
||||
});
|
||||
});
|
||||
|
||||
// README, Installing on Firefox: the extension does not run in private windows.
|
||||
// Firefox gives a page in a private window locks of its own, so that page's
|
||||
// save could land between the background's read and its write (README,
|
||||
// "Stored state and its version").
|
||||
// save could land between the background's read and its write.
|
||||
describe("private windows", () => {
|
||||
test("a page in a firefox private window cannot read or write extension storage", () => {
|
||||
expect(readManifest("firefox").incognito).toBe("not_allowed");
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
// browser's own does for the one call the extension makes,
|
||||
// `navigator.locks.request(name, callback)`. Every module a test file loads
|
||||
// shares it, as the extension's background and its pages share the browser's
|
||||
// (README, "Stored state and its version").
|
||||
// (README, "Stored data").
|
||||
//
|
||||
// Run before each test file by `setupFiles` in package.json.
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// A transaction's time is written by isoDate() and timeAgo() in
|
||||
// src/popup/views/helpers.js on every screen that shows one (README, Display
|
||||
// Consistency; https://git.eeqj.de/sneak/AutistMask/issues/168). AddressDetail
|
||||
// and AddressToken used to define their own copies, so a fix to the shared pair
|
||||
// src/popup/views/helpers.js on every screen that shows one (README, Amounts;
|
||||
// https://git.eeqj.de/sneak/AutistMask/issues/168). AddressDetail and
|
||||
// AddressToken used to define their own copies, so a fix to the shared pair
|
||||
// would not have reached them.
|
||||
//
|
||||
// The pair is replaced before the views are loaded, because a view takes it
|
||||
|
||||
Reference in New Issue
Block a user