crypttrace 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. crypttrace-0.2.0/LICENSE +21 -0
  2. crypttrace-0.2.0/PKG-INFO +503 -0
  3. crypttrace-0.2.0/README.md +469 -0
  4. crypttrace-0.2.0/pyproject.toml +55 -0
  5. crypttrace-0.2.0/setup.cfg +4 -0
  6. crypttrace-0.2.0/src/crypttrace/__init__.py +2 -0
  7. crypttrace-0.2.0/src/crypttrace/addresses.py +132 -0
  8. crypttrace-0.2.0/src/crypttrace/analysis.py +222 -0
  9. crypttrace-0.2.0/src/crypttrace/assess.py +273 -0
  10. crypttrace-0.2.0/src/crypttrace/assets.py +68 -0
  11. crypttrace-0.2.0/src/crypttrace/bridges.py +90 -0
  12. crypttrace-0.2.0/src/crypttrace/chains.py +254 -0
  13. crypttrace-0.2.0/src/crypttrace/cli.py +795 -0
  14. crypttrace-0.2.0/src/crypttrace/config.py +27 -0
  15. crypttrace-0.2.0/src/crypttrace/fetchers/__init__.py +0 -0
  16. crypttrace-0.2.0/src/crypttrace/fetchers/bitcoin.py +186 -0
  17. crypttrace-0.2.0/src/crypttrace/fetchers/etherscan.py +114 -0
  18. crypttrace-0.2.0/src/crypttrace/fetchers/http.py +139 -0
  19. crypttrace-0.2.0/src/crypttrace/fetchers/solana.py +97 -0
  20. crypttrace-0.2.0/src/crypttrace/fetchers/tron.py +128 -0
  21. crypttrace-0.2.0/src/crypttrace/funder.py +76 -0
  22. crypttrace-0.2.0/src/crypttrace/investigate.py +204 -0
  23. crypttrace-0.2.0/src/crypttrace/labels/__init__.py +0 -0
  24. crypttrace-0.2.0/src/crypttrace/labels/audit.py +102 -0
  25. crypttrace-0.2.0/src/crypttrace/labels/known.json +148 -0
  26. crypttrace-0.2.0/src/crypttrace/labels/labels.py +199 -0
  27. crypttrace-0.2.0/src/crypttrace/labels/partial.json +15 -0
  28. crypttrace-0.2.0/src/crypttrace/offramp.py +58 -0
  29. crypttrace-0.2.0/src/crypttrace/prices.py +90 -0
  30. crypttrace-0.2.0/src/crypttrace/render.py +241 -0
  31. crypttrace-0.2.0/src/crypttrace/report.py +175 -0
  32. crypttrace-0.2.0/src/crypttrace/store.py +215 -0
  33. crypttrace-0.2.0/src/crypttrace/trace.py +165 -0
  34. crypttrace-0.2.0/src/crypttrace/verify.py +153 -0
  35. crypttrace-0.2.0/src/crypttrace/watch.py +138 -0
  36. crypttrace-0.2.0/src/crypttrace/web/index.html +660 -0
  37. crypttrace-0.2.0/src/crypttrace/webapp.py +292 -0
  38. crypttrace-0.2.0/src/crypttrace.egg-info/PKG-INFO +503 -0
  39. crypttrace-0.2.0/src/crypttrace.egg-info/SOURCES.txt +41 -0
  40. crypttrace-0.2.0/src/crypttrace.egg-info/dependency_links.txt +1 -0
  41. crypttrace-0.2.0/src/crypttrace.egg-info/entry_points.txt +2 -0
  42. crypttrace-0.2.0/src/crypttrace.egg-info/requires.txt +6 -0
  43. crypttrace-0.2.0/src/crypttrace.egg-info/top_level.txt +1 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 samsepiol09
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,503 @@
1
+ Metadata-Version: 2.4
2
+ Name: crypttrace
3
+ Version: 0.2.0
4
+ Summary: OSINT toolkit for crypto investigations: trace stolen funds across Ethereum, Bitcoin, Tron and Solana
5
+ Author: bobslayerX
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/bobslayerX/crypttrace
8
+ Project-URL: Issues, https://github.com/bobslayerX/crypttrace/issues
9
+ Project-URL: Changelog, https://github.com/bobslayerX/crypttrace/blob/main/CHANGELOG.md
10
+ Keywords: osint,blockchain,forensics,cryptocurrency,bitcoin,ethereum,tron,solana,investigation
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Environment :: Console
13
+ Classifier: Environment :: Web Environment
14
+ Classifier: Intended Audience :: Information Technology
15
+ Classifier: Intended Audience :: Legal Industry
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.9
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Topic :: Security
24
+ Classifier: Topic :: Utilities
25
+ Requires-Python: >=3.9
26
+ Description-Content-Type: text/markdown
27
+ License-File: LICENSE
28
+ Requires-Dist: typer>=0.12
29
+ Requires-Dist: rich>=13.0
30
+ Requires-Dist: requests>=2.31
31
+ Provides-Extra: web
32
+ Requires-Dist: flask>=3.0; extra == "web"
33
+ Dynamic: license-file
34
+
35
+ # crypttrace
36
+
37
+ [![selftest](https://github.com/bobslayerX/crypttrace/actions/workflows/selftest.yml/badge.svg)](https://github.com/bobslayerX/crypttrace/actions/workflows/selftest.yml)
38
+ [![PyPI](https://img.shields.io/pypi/v/crypttrace)](https://pypi.org/project/crypttrace/)
39
+ [![Python](https://img.shields.io/pypi/pyversions/crypttrace)](https://pypi.org/project/crypttrace/)
40
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue)](LICENSE)
41
+
42
+ Open-source OSINT toolkit for crypto investigations. Give it a suspicious
43
+ address; it pulls the public on-chain history, labels known entities (exchanges,
44
+ mixers, sanctioned wallets), scores risk, and maps where the funds moved —
45
+ across Ethereum, Bitcoin, Tron, Solana and more.
46
+
47
+ Built for the investigation that actually happens: *someone's crypto was stolen,
48
+ here's the wallet — where did the money go, and where can it still be stopped?*
49
+
50
+ Works as a terminal tool **and** as a local web app with an interactive
51
+ fund-flow graph.
52
+
53
+ ![crypttrace tracing the AFX Trade exploit](https://raw.githubusercontent.com/bobslayerX/crypttrace/main/assets/graph-outflow.png)
54
+
55
+ *Real case: the AFX Trade exploiter (July 2026, $24.15M). crypttrace follows the
56
+ stolen ETH out of the attacker's wallet — 12,467 ETH (~$23.3M) to a holding
57
+ address, then split across three wallets and split again. Classic layering,
58
+ mapped in seconds.*
59
+
60
+ ---
61
+
62
+ ## Install
63
+
64
+ ```bash
65
+ pipx install "crypttrace[web]" # or: pip install "crypttrace[web]"
66
+ ```
67
+
68
+ `[web]` also installs Flask for the web UI; leave it off for the terminal tool
69
+ alone. Python 3.9 or newer. To work on the code instead:
70
+
71
+ ```bash
72
+ git clone https://github.com/bobslayerX/crypttrace
73
+ cd crypttrace
74
+ pip install -e ".[web]"
75
+ python selftest.py # offline checks, no API keys needed
76
+ ```
77
+
78
+ ### API keys — what's actually required
79
+
80
+ | | Needed? | How to get it |
81
+ |---|---|---|
82
+ | **EVM chains** (Ethereum, BSC, Polygon, Arbitrum, Optimism, Base) | **Required** | Free key at [etherscan.io/myapikey](https://etherscan.io/myapikey). One v2 key covers all EVM chains. |
83
+ | **Bitcoin, Tron, Solana** | **Not required** | Work out of the box via public endpoints. |
84
+
85
+ ```bash
86
+ export ETHERSCAN_API_KEY=xxxx # required for EVM chains only
87
+ ```
88
+
89
+ On Windows (PowerShell):
90
+
91
+ ```powershell
92
+ $env:ETHERSCAN_API_KEY = "xxxx" # this window only
93
+ [Environment]::SetEnvironmentVariable("ETHERSCAN_API_KEY", "xxxx", "User") # permanently
94
+ ```
95
+
96
+ **About the keyless chains:** Bitcoin, Tron and Solana work with no signup at
97
+ all, but their free public endpoints are **rate-limited**. crypttrace handles
98
+ this for you — it caches every response, spaces requests out, and retries with
99
+ backoff when a limit is hit. For deep traces you can raise the ceiling with your
100
+ own credentials (all optional):
101
+
102
+ ```bash
103
+ export TRONGRID_API_KEY=xxxx # optional: higher TronGrid quota
104
+ export CRYPTTRACE_SOLANA_RPC=https://… # optional: your own (faster) Solana RPC
105
+ ```
106
+
107
+ (In PowerShell: `$env:TRONGRID_API_KEY = "xxxx"` and so on.)
108
+
109
+ ## Supported chains
110
+
111
+ | Chain | `--chain` | Data source | Model |
112
+ |---|---|---|---|
113
+ | Ethereum, BSC, Polygon, Arbitrum, Optimism, Base | `eth` `bsc` `polygon` `arbitrum` `optimism` `base` | Etherscan v2 | account |
114
+ | Bitcoin | `btc` | mempool.space | UTXO |
115
+ | Tron (TRX + USDT-TRC20) | `tron` | TronGrid | account |
116
+ | Solana (SOL + SPL) | `sol` | public JSON-RPC | account |
117
+
118
+ Every network is normalized to the same transfer shape, so `profile`, `trace`,
119
+ `funder`, `report` and the web graph behave identically everywhere. Bitcoin
120
+ additionally unlocks `cluster`. Tron matters for everyday victim cases — most
121
+ romance / "pig butchering" scams move USDT-TRC20 because fees are near zero.
122
+
123
+ ---
124
+
125
+ ## Web UI
126
+
127
+ ```bash
128
+ crypttrace serve # then open http://127.0.0.1:8000
129
+ ```
130
+
131
+ Paste an address, pick a chain and direction, and get an interactive fund-flow
132
+ graph: nodes coloured by what they are, arrows showing where value went, click a
133
+ node for its full profile, click a transfer line to open it on the block
134
+ explorer. A side panel shows the profile, first-funder chain and off-ramp check.
135
+ Everything runs on your machine — nothing is uploaded anywhere.
136
+
137
+ This exists so non-technical victims can use the tool at all: a form and a
138
+ picture, instead of command-line flags.
139
+
140
+ **Both directions of the same investigation.** Forward — where the stolen money
141
+ went:
142
+
143
+ ![Tracing stolen funds forward](https://raw.githubusercontent.com/bobslayerX/crypttrace/main/assets/graph-outflow.png)
144
+
145
+ Backward — how that wallet was funded in the first place, which is how you tie
146
+ an anonymous wallet to something identifiable:
147
+
148
+ ![Tracing a wallet's funding backward](https://raw.githubusercontent.com/bobslayerX/crypttrace/main/assets/graph-inflow.png)
149
+
150
+ ## If your crypto was stolen — start here
151
+
152
+ ```bash
153
+ crypttrace investigate 0xADDRESS_THE_FUNDS_WENT_TO
154
+ ```
155
+
156
+ One command. It follows the money, works out where it ended up, saves a case
157
+ file you can send to an exchange or attach to a police report, and then explains
158
+ **in plain language what to do next** — which exchange to contact, where to file,
159
+ how to keep watching the money, and how to avoid the "recovery services" that
160
+ target victims a second time.
161
+
162
+ It is also honest with you: most stolen crypto is not recovered, and what
163
+ matters is speed and whether the funds touch a regulated exchange. The tool
164
+ gives you evidence and timing — it cannot move funds or name a person by itself.
165
+
166
+ ## Commands
167
+
168
+ ```bash
169
+ # The one-command investigation (recommended starting point)
170
+ crypttrace investigate 0xADDRESS --chain eth
171
+
172
+ # What is this address? (local label DB, works offline)
173
+ crypttrace label 0x28c6c06298d514db089934071355e5743bf21d60
174
+
175
+ # Balance, activity window, risk, top counterparties — on any chain
176
+ crypttrace profile 0xADDRESS --chain eth
177
+ crypttrace profile bc1qADDRESS --chain btc
178
+
179
+ # Follow the money, hop by hop, as a coloured tree
180
+ crypttrace trace 0xADDRESS --depth 4 --branching 3
181
+
182
+ # Trace backwards instead: where did this wallet's funds come FROM?
183
+ crypttrace trace 0xADDRESS --direction in
184
+
185
+ # Trace a token rather than the native coin (most thefts are stablecoins)
186
+ crypttrace trace 0xADDRESS --asset usdt --depth 4
187
+
188
+ # Token holdings, valued in USD
189
+ crypttrace tokens 0xADDRESS
190
+
191
+ # Who bootstrapped this wallet's first gas? Follow it toward a KYC point
192
+ crypttrace funder 0xADDRESS --hops 6
193
+
194
+ # Is this an exchange deposit address (i.e. the cash-out point)?
195
+ crypttrace offramp 0xADDRESS
196
+
197
+ # Bitcoin only: find other wallets owned by the same person
198
+ crypttrace cluster bc1qADDRESS
199
+
200
+ # Who fed this wallet? In a mass theft, that's the victim list → CSV
201
+ crypttrace victims bc1qADDRESS --chain btc --depth 1 -o victims.csv
202
+
203
+ # When did the money move? Spots automated sweeps vs ordinary use
204
+ crypttrace timeline bc1qADDRESS --chain btc
205
+
206
+ # Follow funds across bridges into other chains
207
+ crypttrace crosschain 0xADDRESS --window 48
208
+
209
+ # Watch addresses; alert loudly the moment funds head for an exchange
210
+ crypttrace watch add 0xADDRESS --note "my stolen ETH"
211
+ crypttrace watch run --interval 300 # or --once for cron / Task Scheduler
212
+
213
+ # Full investigation report to disk (Markdown + JSON)
214
+ crypttrace report 0xADDRESS --depth 3
215
+
216
+ # Refresh label lists (OFAC sanctions, …)
217
+ crypttrace update-labels
218
+
219
+ # Launch the web UI / list chains
220
+ crypttrace serve
221
+ crypttrace chains
222
+ ```
223
+
224
+ Example trace output:
225
+
226
+ ```
227
+ 🔴 0x098B716B…3E2f96 [Ronin Bridge Exploiter (Lazarus)]
228
+ ├── ──33568.15 ETH (1 tx) ≈$63.8M──▶ 🔴 0x35fb6f6d…26d4b1 [OFAC SDN (sanctioned)]
229
+ │ └── ↳ trail ends here (identifiable entity — subpoena / off-chain)
230
+ └── ──25127.51 ETH (1 tx) ≈$47.7M──▶ ⚪ 0xf7b31119…5cf1be
231
+ └── ──4100.00 ETH (41 tx) ≈$7.8M──▶ 🟣 Tornado Cash: 0.1 ETH
232
+ └── ↳ trail ends here (identifiable entity — subpoena / off-chain)
233
+ ```
234
+
235
+ Legend: 🟢 exchange · 🟣 mixer · 🔴 sanctioned/scam · 🌉 bridge · ⚪ unknown
236
+
237
+ ---
238
+
239
+ ## Capabilities in depth
240
+
241
+ ### Tracing (forward and backward)
242
+
243
+ `trace` follows the largest transfers recursively and stops at identifiable
244
+ entities — that's the OSINT handoff point. `--direction out` (default) answers
245
+ "where did the money go"; `--direction in` answers "where did this wallet's
246
+ money come from", which is how you vet a suspicious address or find a victim's
247
+ source of funds.
248
+
249
+ ### Watch & alerts — catching the cash-out
250
+
251
+ The only window to freeze stolen funds is the moment they reach an exchange
252
+ deposit. Victims can't monitor a chain 24/7. `watch` keeps a list of addresses,
253
+ detects new activity and raises a **loud HIGH alert** the instant funds move
254
+ toward an exchange (directly, or to a detected deposit address); quieter notices
255
+ for other movement. It only alerts on activity *after* an address is added, and
256
+ never double-alerts.
257
+
258
+ ```bash
259
+ crypttrace watch add 0xADDRESS --note "victim funds"
260
+ crypttrace watch list
261
+ crypttrace watch run --interval 300 # continuous
262
+ crypttrace watch run --once # single check, for scheduled tasks
263
+ ```
264
+
265
+ Optional Telegram alerts: set `CRYPTTRACE_TG_TOKEN` and `CRYPTTRACE_TG_CHAT`,
266
+ then pass `--telegram`.
267
+
268
+ ### Off-ramp detection
269
+
270
+ Laundered funds reaching an exchange land on a per-user *deposit address* —
271
+ there are millions, so none appear in any label list. `offramp` spots them by
272
+ behaviour: an address forwarding most of its outgoing value to a labelled
273
+ exchange is almost certainly a deposit address, i.e. the cash-out point where
274
+ that exchange holds the depositor's KYC. `trace` applies the same heuristic
275
+ automatically, turning an anonymous intermediary into "→ Binance deposit (KYC
276
+ point)".
277
+
278
+ ### First-funder (deanonymization)
279
+
280
+ `funder` follows a wallet's funding link backward: whoever sent its first gas,
281
+ then whoever funded that funder. A fresh laundering wallet must be bootstrapped
282
+ from somewhere, and the chain frequently terminates at an exchange withdrawal —
283
+ an identification point. A core primitive for tying "unrelated" wallets to one
284
+ controller. (Uses external transactions; wallets first funded by an internal
285
+ contract call need internal-tx data — a planned extension.)
286
+
287
+ ### Victim lists and timing analysis
288
+
289
+ Two things a graph shows but can't hand you as evidence.
290
+
291
+ `victims` walks the money backwards from a consolidation wallet and lists every
292
+ address that fed it — amounts, transaction counts, first/last seen, explorer
293
+ links — and writes it to **CSV**. After a mass drain that list *is* the set of
294
+ victims, in the form an exchange's compliance team or a police report can
295
+ actually use.
296
+
297
+ `timeline` answers *when*. It buckets activity into a histogram and finds the
298
+ tightest window containing most of the transfers. This separates a theft from
299
+ ordinary wallet use: hundreds of transfers inside minutes is an automated tool
300
+ spending keys it already holds, whereas a real owner's activity is spread over
301
+ months. The tool says so in plain language rather than leaving you to eyeball it.
302
+
303
+ ```
304
+ crypttrace victims bc1qADDRESS --chain btc --depth 2 -o victims.csv
305
+ crypttrace timeline bc1qADDRESS --chain btc --buckets 24
306
+ ```
307
+
308
+ ![The victim list for one branch of the Coldcard sweep in the web UI](https://raw.githubusercontent.com/bobslayerX/crypttrace/main/assets/web-victims.jpg)
309
+
310
+ A worked example — 1,169 swept addresses, 1,082.58 BTC, with the commands to
311
+ reproduce it — is in [`cases/coldcard-2026`](cases/coldcard-2026).
312
+
313
+ **Dust is filtered by default.** Addresses that become publicly known get spammed
314
+ with tiny transfers, which otherwise bury the transactions that matter and can
315
+ flip the timing verdict entirely. Each chain has a dust threshold; override with
316
+ `--min-value`, or keep everything with `--include-dust`. Bitcoin history is
317
+ paged rather than read one page deep, so an old sweep isn't hidden behind recent
318
+ spam.
319
+
320
+ ### Bitcoin clustering (common-input-ownership)
321
+
322
+ Bitcoin's UTXO model enables the strongest clustering heuristic in blockchain
323
+ forensics: if several addresses sign the inputs of one transaction, one party
324
+ almost certainly controls all of them. `cluster` surfaces those co-signers,
325
+ turning a single address into a set of wallets belonging to the same owner. A
326
+ strong lead, not proof.
327
+
328
+ ### Cross-chain tracing (bridges)
329
+
330
+ When funds cross a bridge the trail ends at the bridge contract and reappears on
331
+ another chain, with no free deterministic link between the two. `crosschain`
332
+ uses a behavioural heuristic that catches many real cases: launderers frequently
333
+ bridge to the *same address* they control on the destination chain, so after a
334
+ transfer into a known bridge the tool searches every other supported chain for
335
+ an inbound transfer to that address of a similar amount (bridges take a fee)
336
+ within a time window. Matches are reported with amount and delay — a strong
337
+ **lead, not proof**. Recognised bridges: Wormhole, the canonical Optimism /
338
+ Arbitrum / Base bridges, Across, Synapse and Celer cBridge (extend the
339
+ `"bridge"` entries in `labels/known.json`).
340
+
341
+ ### Assets & USD values
342
+
343
+ The tracer follows the chain's native coin by default. `--asset` switches to a
344
+ token — most thefts and scams move stablecoins, so this is usually what you
345
+ want:
346
+
347
+ ```bash
348
+ crypttrace trace 0xADDRESS --asset usdt # USDT on Ethereum
349
+ crypttrace trace TADDRESS --chain tron --asset usdt # USDT-TRC20 on Tron
350
+ crypttrace tokens TADDRESS --chain tron
351
+ ```
352
+
353
+ Token contracts differ per chain, so the registry is chain-aware: `usdt` on Tron
354
+ resolves to `TR7NHqje…jLj6t`, on Ethereum to `0xdac17f95…31ec7`. Known symbols
355
+ are `usdt`, `usdc`, `dai`, `weth`, `wbtc` on EVM and `usdt`, `usdc` on
356
+ Tron/Solana; you can also pass any contract address directly.
357
+
358
+ Matching is by **exact contract**, which matters: attackers routinely airdrop
359
+ fake tokens named "USDT" to poison wallets, and those are ignored rather than
360
+ traced. Native coins and tokens are also kept strictly separate — summing TRX
361
+ with USDT would be meaningless.
362
+
363
+ Amounts carry approximate USD values (stablecoins pinned to $1, others priced
364
+ via CoinGecko). If pricing is unavailable, USD shows as `—` rather than a guess.
365
+
366
+ ### Labels
367
+
368
+ Ships a curated seed set (major exchanges, Tornado Cash, bridges, notable
369
+ hacks). `update-labels` pulls authoritative public lists — currently the OFAC
370
+ SDN sanctioned-address list — and merges them into the local DB in
371
+ `~/.crypttrace/`. The curated seed wins on conflicts, so richer names survive.
372
+ Add sources in `labels/labels.py` → `SOURCES`.
373
+
374
+ Bitcoin, Tron and Solana coverage is currently Binance only: its reserve
375
+ wallets, taken from the address list Binance publishes itself for
376
+ proof-of-reserves. So `offramp` can flag Binance deposit addresses on those
377
+ chains, but funds sent to other exchanges there will still show as `unknown`.
378
+ Every label records where it came from — see `crypttrace labels audit`.
379
+
380
+ ### Reports
381
+
382
+ `report` runs the full analysis and writes to `~/crypttrace-reports/` (override
383
+ with `--out`): a readable Markdown report (assessment, summary, key findings,
384
+ counterparties, the full fund-flow trace, methodology note) plus a `.json` with
385
+ the raw structured data.
386
+
387
+ ### Self-verification
388
+
389
+ A forensics tool that quietly miscounts is worse than no tool: the output looks
390
+ authoritative and ends up in reports. `verify` re-derives the totals from what
391
+ the tool parsed and compares them against the figures the chain index reports
392
+ independently.
393
+
394
+ ```
395
+ crypttrace verify bc1qADDRESS --chain btc
396
+ ```
397
+
398
+ It reports one of:
399
+
400
+ | Status | Meaning |
401
+ |---|---|
402
+ | **verified** | Gross totals match the chain independently. |
403
+ | **consistent** | Balance reconciles, but this chain publishes no independent gross totals, so attribution is only partly checked. |
404
+ | **partial** | Only part of the address's history was read — totals are a floor, not the whole picture. |
405
+ | **mismatch** | Computed totals disagree with the chain. Don't rely on the output until it's explained. |
406
+
407
+ `victims` runs this automatically, because that list is the output most likely
408
+ to be quoted as evidence; the web UI shows the same status as a badge.
409
+
410
+ This exists because the tool *did* once miscount — attributing a whole
411
+ multi-input Bitcoin transaction to its first input address, crediting one
412
+ wallet with 89 BTC it never handled. That was caught by hand against a block
413
+ explorer; the check now catches it automatically.
414
+
415
+ ### Caching & rate limits
416
+
417
+ Every API response is cached in SQLite under `~/.crypttrace/`, so re-running a
418
+ trace — or revisiting an address within one trace — costs no requests. Non-EVM
419
+ fetchers additionally throttle per host and retry with exponential backoff on
420
+ HTTP 429, so free endpoints degrade gracefully instead of erroring out.
421
+
422
+ ---
423
+
424
+ ## Honest limitations
425
+
426
+ Read this before relying on the tool — and before promising anything to a
427
+ victim.
428
+
429
+ - **Pseudonymity.** You see that funds landed on `0xABC`, not who owns it. The
430
+ tool brings a trail to a *point of identification* (usually an exchange with
431
+ KYC). The name comes from a legal request to that exchange, not from the chain.
432
+ - **Mixers break the trail.** Tornado Cash and privacy pools sever the on-chain
433
+ link. Anything past them is heuristic and not guaranteed.
434
+ - **Heuristics are leads, not proof.** Off-ramp detection, cross-chain matching
435
+ and Bitcoin clustering are strong signals that can coincide by chance. Verify
436
+ before acting on them.
437
+ - **Labels are only as good as the database.** Unlabelled ≠ innocent.
438
+ - **Recovery depends on others.** crypttrace can tell you *when* and *where* to
439
+ act; freezing funds depends on exchanges and law enforcement responding.
440
+
441
+ ## Layout
442
+
443
+ ```
444
+ src/crypttrace/
445
+ cli.py # Typer CLI — every command
446
+ chains.py # unified multi-chain adapter (one transfer shape for all)
447
+ config.py # chains, keys, paths
448
+ fetchers/
449
+ etherscan.py # EVM (Etherscan v2) + SQLite cache
450
+ bitcoin.py # Bitcoin UTXO (mempool.space) + clustering
451
+ tron.py # Tron / TRC20 (TronGrid) + base58 conversion
452
+ solana.py # Solana JSON-RPC
453
+ http.py # shared cache, throttling, 429 backoff
454
+ labels/
455
+ known.json # curated label DB, one source per claim
456
+ partial.json # addresses known only in truncated form
457
+ labels.py # lookup, risk scoring, source imports
458
+ audit.py # checksum + provenance audit of the label DB
459
+ addresses.py # per-chain address validation (checksums)
460
+ store.py # local SQLite store of every transfer read
461
+ trace.py # fund-flow tree + graph builder
462
+ investigate.py # one-command victim workflow
463
+ analysis.py # victim lists, timeline, burst detection
464
+ assess.py # reasoned assessment with evidence and confidence
465
+ verify.py # reconcile computed totals against the chain
466
+ funder.py # first-funder heuristic
467
+ offramp.py # exchange-deposit detection
468
+ bridges.py # cross-chain matching
469
+ watch.py # watchlist + alerts
470
+ report.py # Markdown + JSON reports
471
+ prices.py # USD valuation
472
+ render.py # rich terminal rendering
473
+ webapp.py # Flask backend for the web UI
474
+ web/index.html # single-page frontend (interactive graph)
475
+ selftest.py # offline end-to-end checks, run by CI
476
+ cases/ # worked investigations with their data
477
+ ```
478
+
479
+ ## Roadmap
480
+
481
+ - Exchange/service labels for Bitcoin, Tron and Solana
482
+ - `report --pdf` for exchange and law-enforcement filings
483
+ - Internal transactions (completes `funder` and contract-mediated transfers)
484
+ - Per-mint filtering for Solana SPL tokens
485
+ - More label sources: Chainabuse, CryptoScamDB, exchange deposit-address sets
486
+ - Spam/dust token filtering in `tokens`
487
+ - Entity clustering on EVM via the gas-funding heuristic
488
+
489
+ ## Contributing
490
+
491
+ Label data is the highest-leverage contribution: exchange wallets, known scam
492
+ and drainer addresses, bridges. Add them to `labels/known.json` with a `chain`,
493
+ a `source` a reader can check and a `source_kind` (`self-published`,
494
+ `official-list`, `explorer-tag`, `research`, `community`), then run
495
+ `crypttrace labels audit` and `python selftest.py` before opening a PR.
496
+ Accuracy matters more than volume — a wrong label is worse than no label.
497
+
498
+ ## Licence
499
+
500
+ MIT — see [LICENSE](LICENSE).
501
+
502
+ *Use responsibly. This is an investigative aid, not evidence of wrongdoing, and
503
+ not a substitute for law enforcement.*