Skip to content
99ersstudio
All work
Web Tools/Live

Wallet Risk Scanner

Self-hosted wallet sanctions tracer across six chains. Tether blacklist + OFAC + multi-hop. PDF reports.

6
chains
199
tests
4
hop depth

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

  1. 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.
  2. 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.
  3. 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.
  4. 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.
  5. 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

PythonStreamlitSQLitePlotlyreportlabDocker

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