On the confirm-tx screen, asynchronously check the recipient address
via Blockscout API. If the address has never sent or received any
transactions, display a prominent red warning banner.
Closes#82
A single transaction (e.g. a DEX swap) can produce multiple ERC-20
token transfers. The transaction merger was keyed by tx hash alone,
so only the last token transfer survived. This meant the address-token
view's contract-address filter often matched nothing.
Use a composite key (hash + contract address) so all token transfers
are preserved. Also remove the bare normal-tx entry when it gets
replaced by token transfers to avoid duplicates.
Closes#72
- Map known DEX methods (execute, swap, multicall, etc.) to "Swap"
label instead of raw method name like "Execute"
- Remove unused displayData variable in transactionDetail.js
Addresses review feedback on PR #10.
- Preserve contract call metadata (direction, label, method) when token
transfers merge with normal txs in fetchRecentTransactions
- Handle 'contract' direction in counterparty display for home and
address detail list views
- Add decoded calldata display to transaction detail view, fetching
raw input from Blockscout and using decodeCalldata from approval.js
- Show 'Unknown contract call' with raw hex for unrecognized calldata
- Export decodeCalldata from approval.js for reuse
- Display full-precision amount (no 4-decimal truncation) in the
transaction detail view, with native quantity (wei/base units) below
- Both amount and native quantity are click-copyable
- Show wallet/address title above from/to when the address is ours
- Update README Display Consistency to document the exception
Contract interactions (approve, swap, etc.) now display the method
name and token symbol instead of the meaningless 0 ETH value.
Blockscout provides the method name and whether the target is a
contract — parseTx uses these plus TOKEN_BY_ADDRESS to produce
labels like "Approve USDT" or "Swap LINK".
Added directionLabel field to parsed transactions so renderers
don't need to know about the sent/received/contract distinction.
Also: clicking a transaction on the home screen now opens the
transaction detail view instead of navigating to the address
detail view.
The dust filter was hiding contract interactions (approve, transfer,
etc.) because they have 0 ETH value, which falls below the dust
threshold. Contract calls with 0 ETH are normal — only plain ETH
transfers should be checked against the dust threshold.
Also captures is_contract and method from Blockscout's transaction
response for future use in transaction display.
Delete src/shared/tokens.js and migrate all consumers to
src/shared/tokenList.js which has 511 tokens (vs ~150) sourced
from CoinGecko with on-chain verified decimals.
- prices.js: getTopTokenPrices now from tokenList
- transactions.js: KNOWN_SYMBOLS now from tokenList (3.4x more
symbols for spoof detection)
- send.js: KNOWN_SYMBOLS for token dropdown filtering
- approval.js: uses pre-built TOKEN_BY_ADDRESS map instead of
constructing its own from TOKENS array
- addToken.js: uses getTopTokens(25) for quick-pick buttons
(only top 25 shown, not all 511)
When sending an ERC-20 token, Blockscout returns the same tx hash
from both the /transactions endpoint (as a 0 ETH contract call) and
the /token-transfers endpoint (as the actual token transfer with
amount and symbol). The old dedup logic kept the 0 ETH version and
skipped the token transfer.
Now token transfers replace normal transactions with the same hash,
since the token transfer has the real amount, symbol, and contract
address.
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.
Address poisoning attacks also use real native ETH dust transfers
(e.g. 1 gwei) from look-alike addresses. Token-level filters cannot
catch these. Add a configurable dust threshold (default 100,000 gwei
/ 0.0001 ETH) that hides transactions below the threshold from
history. The threshold is editable in Settings and the filter can be
disabled entirely. Document the specific attack tx in the README.
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.
- Transaction values now use exactly 4 decimal places (was 6),
matching balance display everywhere else
- Transaction detail view shows "2026-02-25 15:04:23 (23 days ago)"
instead of just the ISO date
- Added Display Consistency policy to README
Blockscout v2 API rejects the `limit` query parameter on
/transactions and /token-transfers endpoints (returns 422).
Remove it and slice results client-side instead.
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