Add confirm-tx to RESTORABLE_VIEWS and save pendingTx in
state.viewData so the confirmation screen survives the popup
lifecycle. On restore, re-render the full confirmation view
including gas estimate.
The approval ID was changed from sequential integers to crypto.randomUUID()
strings for security, but the popup still called parseInt() on it, which
converted the UUID to NaN. This caused every approval lookup to fail,
preventing the confirmation popup from displaying pending tx/sign requests.
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.
Previously the approval popup closed immediately after the user
entered their password, giving zero feedback about whether the
transaction was broadcast or confirmed. Now:
1. Background sends the broadcast result back to the popup via
sendResponse callback (txHash or error)
2. Popup shows wait-tx screen on success (with polling timer)
or error-tx screen on failure
3. Wait-tx polls for confirmation and transitions to success-tx
4. Done button closes the approval window
txStatus.init() moved before the approval early-return so the
wait/success/error views are wired up in the approval popup.
Done buttons detect the approval context and call window.close()
instead of navigating to address detail.
Creates a centralized transactionDetail.js view module, replacing
the duplicated showTxDetail/copyableHtml/blockieHtml/txDetailAddressHtml
code that was in both addressDetail.js and addressToken.js (~120 lines
removed). Transaction data is stored in state.viewData and persisted,
so the transaction detail view survives popup close/reopen.
Adds viewData to persisted state. Each view that needs data for
restore stores it in state.viewData before rendering. The ctx object
now has showTransactionDetail() alongside all other show methods.
Restorable views expanded to include: transaction (via viewData.tx),
success-tx (via viewData.hash/blockNumber), error-tx (via
viewData.message). txStatus.js split into show (sets data) + render
(reads data) for each screen, enabling restore.
Non-restorable views (send, confirm-tx, wait-tx, add-wallet,
import-key, add-token) fall back to the nearest parent since they
involve active form state or network polling.
The current view, selected wallet, selected address, and selected
token are now saved to extension storage. When the popup reopens,
it restores to the last visited view instead of always returning
to the home screen.
Restorable views: main, address detail, address-token, receive,
settings. Non-restorable views (send, confirm, tx status, forms)
fall back to the nearest parent. Stored indices are validated
against current wallet data to handle stale references.
Also refactors receive view setup into a centralized receive.show()
function, eliminating duplicate QR/address/warning code from
addressDetail.js, addressToken.js, and home.js. Adds settings.show()
to centralize settings field population.
After broadcast, the user is taken to a full-screen wait view showing
the amount, recipient, tx hash (copyable + etherscan link), and a
count-up timer. The view polls every 10 seconds for confirmation.
On confirmation: navigates to success screen showing block number,
tx hash, and a Done button that returns to the address view.
On 60-second timeout or error: navigates to error screen with the
failure message, tx hash (if available), and Done button.
Replaces the previous inline confirm-status div that was crammed
onto the confirmation page.
Clicking a token balance on the address detail view navigates to a
focused view showing only that token's transactions. Send pre-selects
and locks the token dropdown, Receive shows an ERC-20 warning for
non-ETH tokens, and all back buttons return to the correct parent view.
The Allow/Deny buttons did nothing because approval.init(ctx) was
called after the early return for approval mode, so listeners were
never attached. Move it before the check.
Rename view from "approve" to "approve-site" to avoid ambiguity with
future transaction approval. Space Allow and Deny buttons apart with
justify-between to prevent misclicks.
- Add activeAddress, allowedSites, deniedSites, rememberSiteChoice to
persisted state
- Replace auto-connect with permission checks: allowed sites connect
automatically, denied sites are rejected, unknown sites trigger an
approval popup
- Add approval popup UI with hostname display, active address preview,
remember checkbox, and allow/deny buttons
- Add ACTIVE/[select] indicator on address rows in the main view to
set the active web3 address
- Add allowed/denied site list management in settings with delete buttons
- Broadcast accountsChanged to connected dapps when active address changes
- Handle approval window close as implicit denial
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.
Total USD value displayed in 2x type above wallet list on Home.
Value aggregation: getAddressValueUsd (ETH + all tokens) →
getWalletValueUsd → getTotalValueUsd. Price API cached for 5
minutes, balance fetches cached for 60 seconds. Both caches
are app-wide — repeated calls to refreshPrices/refreshBalances
are no-ops within the TTL.
Move "AutistMask by @sneak" to a global title bar that appears
on every screen. Per-view headings demoted to h2 sub-headings.
Settings button moved to bottom of main view alongside Add
wallet. In DEBUG mode, the red banner now shows the current
screen name in parentheses (e.g. "DEBUG / INSECURE (main)").
Shows the top 25 tokens by market cap as clickable buttons
below the contract address input. Clicking a token fills in
its contract address automatically.
vault.js: Argon2id key derivation + XSalsa20-Poly1305 encryption
via libsodium-wrappers-sumo. No raw crypto primitives.
Wallet creation now requires a password. The mnemonic or private
key is encrypted before storage — only the ciphertext blob
(salt, nonce, ciphertext) is persisted. The plaintext secret
is never stored.
Sending requires the password to decrypt the secret, derive
the signing key, and construct the transaction. Wrong password
is caught and reported.
Send: stores mnemonic/private key with wallet data, derives
signing key from mnemonic + address index via ethers HDNodeWallet,
constructs transaction with parseEther, broadcasts via
sendTransaction, waits for confirmation, shows block number
and tx hash. ENS resolution in To field preserved.
Receive: QR code rendered to canvas via qrcode library (1.5.4).
Shows scannable QR above the full address text.
README updated with qrcode dependency and TODO progress.
tokens.js: ~150 ERC-20 tokens ordered by market cap with
getTopTokenSymbols(n) and getTopTokenPrices(n) (errors if n>30).
Price fetching uses CoinDesk CADLI API. Popup now shows USD
values next to ETH balances in wallet list and address detail.
Prices and balances fetched in parallel on popup open.
Reverse ENS lookup on balance refresh — if an address has an
ENS name, it's shown in the wallet list and address detail view.
Send form accepts ENS names in the To field (resolves before
sending). Placeholder updated to indicate ENS support.
Uses ethers JsonRpcProvider to call eth_getBalance for every
address on popup open. Balances update in the background and
re-render the wallet list when done. Default RPC is
eth.llamarpc.com, configurable in settings.
Xpubs and derived addresses stored unencrypted in extension
storage for instant read-only access without a password.
Password will only be required for signing transactions
(not yet implemented). Real addresses now derived from
mnemonic via ethers HDNodeWallet at wallet creation time.
Removed lock screen, password fields, and Lock button.
BIP-39 mnemonic validation added. README updated with split
storage model documentation.
Display complete addresses instead of truncated ones. Address
poisoning attacks use matching prefixes/suffixes to fool users
into copying fraud addresses. Showing the full address mitigates
this.
DEBUG mode must behave identically to normal mode except for
the red banner and hardcoded mnemonic. No other DEBUG branches
without explicit owner approval. Policy documented in README.
State (wallets, RPC URL, setup flag) is saved to
browser.storage.local / chrome.storage.local after every
mutation and loaded on popup open. In DEBUG mode, the lock
screen is skipped since encryption is not yet implemented.
When DEBUG=true: a sticky red "DEBUG / INSECURE" banner appears
at the top of all views, and the die button returns a hardcoded
test mnemonic instead of generating a random one.
Replace stub wordlist with ethers.Mnemonic.fromEntropy() using
crypto.getRandomValues(). Add esbuild to bundle popup JS so it
can import ethers directly — no background messaging needed.
Each die click now generates a valid, random BIP-39 mnemonic.
- Password help text now explains it encrypts the recovery phrase
on disk and is not used for address derivation
- Die button generates cryptographically random phrases using
crypto.getRandomValues(), different each click
- "roll the die for a new one" wording
- README documents full encryption scheme (PBKDF2 + AES-256-GCM)
and explicitly notes password is not part of BIP-39 derivation
Welcome and main views now show one button: "Add wallet".
Private key import is accessible as a small link at the bottom
of the Add Wallet view ("Have a private key instead?").
Merge "Create new wallet" and "Import recovery phrase" into one
"Add wallet" screen. The recovery phrase textarea starts empty.
A clickable die button generates a random phrase and shows a
backup warning. Users who already have a phrase just paste it.
Welcome screen simplified to two options: "Add wallet" and
"Import private key". README updated to match.
Replace jargon-heavy terminal-style UI with plain-language views.
New data model: wallets (HD or private key) contain addresses.
Main view lists all addresses grouped by wallet with balances.
HD wallets get a "+" to add addresses; key wallets have one.
Two import paths: recovery phrase and private key.
All labels use plain English, full-sentence errors, inline help
text. README updated with full UI philosophy, language guide,
data model, and navigation docs.
Makefile, Dockerfile, CI workflow, prettier config, manifests for
Chrome (MV3) and Firefox (MV2), source directory structure, and
minimal test suite. All checks pass.