The problem
Block explorers like Tronscan and Etherscan are great for looking up a single transaction, but they will not tell you whether the counterparty wallet is on Tether's on-chain blacklist or the OFAC SDN list. The commercial answer (Chainalysis, TRM Labs) is excellent, cloud-only, and priced for institutions. We wanted the same verdict for a wallet — across the chains we actually care about — as a self-hosted box anyone could run in an afternoon.
How we built it
- 01Built a per-chain client registry (`src/chains/`) where every chain — Tron, Ethereum, Polygon, Arbitrum, BSC, Bitcoin — exposes the same minimal interface. Adding a new EVM L2 is roughly thirty lines.
- 02Pulled the Tether on-chain blacklist directly from the USDT contract on each EVM chain plus Tron, and parsed the OFAC SDN XML feed (US Treasury public source) once a day into a local SQLite cache.
- 03Wrote a BFS counterparty tracer that walks 1–4 hops deep with a per-hop fanout cap, scored hop-1 hits at 25 points, hop-2 at 15, hop-3 at 8 — so laundered taint still moves the verdict but does not dominate it.
- 04Wrapped everything in a Streamlit UI organised verdict-first: one giant color-coded banner up top, then collapsible Risk Report, Money Flow (Sankey + network), Wallet Detail, and Fees tabs. One-click reportlab PDF export for compliance hand-off.
- 05Shipped a `scripts/scan_alerts.py` cron entrypoint that diffs against the previous scan, prints new flags as stdout JSON, and lets external mail / Slack / webhook shippers route the result.
Outcome
v1.0.0 tagged. 199 tests, all mocked (no network call required to run the suite — CI-friendly). End-to-end verified against the canonical Tron USDT contract (Tether-blacklist verdict), a Binance hot wallet (CLEAN with deep history), and the Bitcoin genesis address (OFAC + 1-hop). Docker Compose stack runs from a fresh box with one command and reads `ETHERSCAN_API_KEY` from `.env.local` — every other source (Tron, BTC, OFAC, Tether blacklist) works keyless.
Stack
Python 3.14 · Streamlit on port 8502 · SQLite (WAL mode) for cache + tracked-wallet store · plotly for Sankey + network diagrams · reportlab for PDF · Etherscan v2 for EVM tx history · TronGrid free tier for Tron · mempool.space for Bitcoin.
Next up
Native push channel (email / Slack / webhook) so the alerts runner does not require an external shipper. L2 expansion beyond Arbitrum (Optimism, Base) — same ~30-line pattern as BSC.
More case studies
- Web ToolsSEOMAX
Self-hosted SEO intelligence platform. 77 endpoints, DataForSEO-powered, Docker-deployable.
- GamesPoker Platform
Multi-table online poker with real-money-capable risk review, admin tooling, and webhook fan-out.
- Mobile AppsMieter App
German tenant-rights companion. 8-city Mietspiegel, Mietpreischeck, Nebenkostenprüfung, PDF export.