English · Français
Map the blockchain. Turn raw on-chain transactions into an interactive fund-flow graph — for OSINT investigators, journalists, and students learning how blockchains work.
Paste an address → chainmap fetches its transactions from the Etherscan v2 API and draws a directed address → address graph, expanded breadth-first to a depth you choose. Then it layers investigator tooling on top: filters, edge bundling, contract-call decoding, cycle detection, sink/faucet hubs, and per-node risk scoring.
- Fully client-side — no backend, no build step, no telemetry.
- Your API key and data stay in your browser. The only site ever contacted is
api.etherscan.io, enforced by a strict Content-Security-Policy. - English + French, fully localized.
- 321 unit/integration tests on the DOM-free core.
- Quick start
- Features
- Learn how blockchains work
- Architecture
- Privacy, security & ethics
- Development & tests
- Supported chains
Zero install — it's native ES modules.
git clone https://github.com/gl0bal01/chainmap.git && cd chainmap
python3 -m http.server 8000
# open http://localhost:8000/No API key? Click Demo mode — it loads a bundled sample investigation so you can explore every feature immediately.
Live scans: get a free key at https://etherscan.io → API Keys, paste it in the UI, pick a chain, paste an address, Start. One key works across all supported chains (Etherscan v2 is a unified multichain endpoint).
- BFS expansion — recurse from a root address to any depth, with a per-address sample size, a hard safety cap, and a Stop that truly aborts in-flight requests.
- Three tx families — normal, internal, and ERC-20/721/1155 token transfers, each a colored edge.
- Calldata decoding — 4-byte selectors → human method names + named decoded args and
a plain-language
► Summaryline, so atransfer()'s real recipient (hidden in calldata) is surfaced. - Noise reduction — amount/date/zero-value/spam filters, and edge bundling (collapse many A→B transfers into one weighted arrow).
- Investigation overlays — round-trip (cycle) detection, sink/faucet hubs (with reversible Hide faucets / Hide sinks toggles), peel-chain detection (highlights forwarding chains where value hops through throwaway addresses), color-by-age, known-address labels, mixer/bridge/sanctioned tagging (🌀/🌉/⛔ badges), and an explainable per-node risk score.
- Per-edge risk flags — unlimited/blanket approvals, a hidden real recipient, and mixer/bridge/sanctioned counterparties are called out in the edge details panel and escalated on the graph in two visual tiers: danger (mixer/bridge/sanctioned, red ⚠) vs informational (approvals/hidden-recipient, amber ⓘ). Signals, not verdicts — always corroborate before you conclude.
- Chain detector — paste any address; it tells you the chain family (or non-EVM) by format. Then click Detect chain to probe ~12 popular chains for on-chain activity and auto-select the one where the address is most active, showing where else it's active.
- Exports — PNG, PDF, and CSV (with a sampling caveat baked in, plus decoded method, real recipient, decoded amount, and risk-flag columns per edge). Save/load workspaces.
- Keyboard navigation — Ctrl/Cmd+Arrow jumps selection to the nearest node in that direction. Ctrl/Cmd+K command palette — search nodes by address / alias / known-label / category and transactions by hash / method (hybrid substring + fuzzy ranking); picking a result focuses + selects it and auto-reveals it if hidden by a filter/hub-hide.
- Honest by design — big-integer amounts (never floating point), failed txs dropped, and sampling surfaced everywhere. The sampling caveat applies to every feature above: overlays, flags, and hub/peel-chain detection only ever see the sampled graph, never full on-chain history.
chainmap doubles as a hands-on course. Every blockchain concept — accounts, the three transaction families, base units & decimals, calldata, token standards, BFS graphs, sampling, failed txs, multichain, and investigation heuristics — maps to something you can see and do in the tool, with 8 guided labs.
📚 Full curriculum + labs → docs/LEARN.md · en français → docs/LEARN.fr.md
Native ES modules, no bundler. The design principle: graphStore is the single
source of truth. Every mutation goes through it; it emits events; the render layer mirrors
it into vis-network DataSets by subscribing. Filters/overlays are a display projection
(vis DataViews) over that mirror, so the store always holds the full graph for CSV/detail
even when the view is filtered.
BFS scan ──► graphStore (truth) ──emits events──► render/network ──► vis DataViews ──► canvas
▲ │ ▲
etherscanClient ui.js / main.js (composition root) filters · bundling · overlays
▲
rateLimiter
The correctness-critical core is DOM-free and unit-tested in Node (format,
etherscanClient, graphStore, scanner, display, roundTrips, riskScore, …). The
DOM/vis layer (render/*, ui.js) is thin. See INTERFACES.md for the
frozen module contracts.
- Nothing leaves your browser except calls to
api.etherscan.io— no backend, proxy, analytics, or third-party beacons. Verify it in DevTools → Network. - Vendored libraries (
vis-network,jsPDF) — no CDN — pinned with Subresource Integrity. A strict CSP limitsscript-srcto'self'andconnect-srcto the Etherscan API. - No untrusted string reaches
innerHTML— aliases and API token symbols are rendered as DOM text nodes; the analysis is XSS-inert by construction. - OSINT ethics: the graph is a sample, not proof. Public-chain data is pseudonymous, not anonymous, and not always what it seems (spoofed token names, dust attacks, exchange omnibus wallets). Label your limits; corroborate before you conclude.
Tests are dev-only (they never run in production and aren't needed to use the app).
bun install # dev deps only (happy-dom, playwright-core)
bun test # 321 unit + integration testsbun test covers the DOM-free modules (amount math, dedup keys, BFS guards, failed-tx
filtering, cycle detection, ABI decode, risk scoring, en/fr key parity, …) plus a happy-dom
integration test that drives the real main.js against a stubbed vis/fetch. CI runs the
suite and a vendor-integrity check (SRI + SHA-256) on every push.
All 64 Etherscan v2 chains (Ethereum, L2s like Base/Arbitrum/Optimism/Linea/Blast, sidechains like BNB/Polygon/Gnosis/Avalanche, Sonic, and ~30 testnets). One API key works across all — Etherscan v2 is a unified multichain endpoint. Each chain carries its native currency symbol (so native txs show BNB/POL/AVAX/S/… not "ETH" everywhere). Add one = a single entry in src/config.js ({id, name, explorer, native}, validated against Etherscan v2's chainlist).
- Blockchain address-format patterns for the chain detector are adapted from gl0bal01's
discord-osint-assistant. - Graph rendering by vis-network;
- PDF export by jsPDF.
- OiY for the idea ;)
