crypttrace 0.26.0__tar.gz → 0.29.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 (54) hide show
  1. {crypttrace-0.26.0/src/crypttrace.egg-info → crypttrace-0.29.0}/PKG-INFO +38 -13
  2. {crypttrace-0.26.0 → crypttrace-0.29.0}/README.md +37 -12
  3. {crypttrace-0.26.0 → crypttrace-0.29.0}/src/crypttrace/__init__.py +1 -1
  4. {crypttrace-0.26.0 → crypttrace-0.29.0}/src/crypttrace/drain.py +20 -0
  5. {crypttrace-0.26.0 → crypttrace-0.29.0}/src/crypttrace/labels/known.json +285 -13
  6. {crypttrace-0.26.0 → crypttrace-0.29.0}/src/crypttrace/labels/labels.py +60 -12
  7. {crypttrace-0.26.0 → crypttrace-0.29.0}/src/crypttrace/render.py +9 -0
  8. {crypttrace-0.26.0 → crypttrace-0.29.0}/src/crypttrace/web/index.html +8 -0
  9. {crypttrace-0.26.0 → crypttrace-0.29.0/src/crypttrace.egg-info}/PKG-INFO +38 -13
  10. {crypttrace-0.26.0 → crypttrace-0.29.0}/LICENSE +0 -0
  11. {crypttrace-0.26.0 → crypttrace-0.29.0}/pyproject.toml +0 -0
  12. {crypttrace-0.26.0 → crypttrace-0.29.0}/setup.cfg +0 -0
  13. {crypttrace-0.26.0 → crypttrace-0.29.0}/src/crypttrace/addresses.py +0 -0
  14. {crypttrace-0.26.0 → crypttrace-0.29.0}/src/crypttrace/analysis.py +0 -0
  15. {crypttrace-0.26.0 → crypttrace-0.29.0}/src/crypttrace/assess.py +0 -0
  16. {crypttrace-0.26.0 → crypttrace-0.29.0}/src/crypttrace/assets.py +0 -0
  17. {crypttrace-0.26.0 → crypttrace-0.29.0}/src/crypttrace/bridges.py +0 -0
  18. {crypttrace-0.26.0 → crypttrace-0.29.0}/src/crypttrace/chains.py +0 -0
  19. {crypttrace-0.26.0 → crypttrace-0.29.0}/src/crypttrace/cli.py +0 -0
  20. {crypttrace-0.26.0 → crypttrace-0.29.0}/src/crypttrace/config.py +0 -0
  21. {crypttrace-0.26.0 → crypttrace-0.29.0}/src/crypttrace/evidence.py +0 -0
  22. {crypttrace-0.26.0 → crypttrace-0.29.0}/src/crypttrace/fetchers/__init__.py +0 -0
  23. {crypttrace-0.26.0 → crypttrace-0.29.0}/src/crypttrace/fetchers/bitcoin.py +0 -0
  24. {crypttrace-0.26.0 → crypttrace-0.29.0}/src/crypttrace/fetchers/etherscan.py +0 -0
  25. {crypttrace-0.26.0 → crypttrace-0.29.0}/src/crypttrace/fetchers/http.py +0 -0
  26. {crypttrace-0.26.0 → crypttrace-0.29.0}/src/crypttrace/fetchers/solana.py +0 -0
  27. {crypttrace-0.26.0 → crypttrace-0.29.0}/src/crypttrace/fetchers/ton.py +0 -0
  28. {crypttrace-0.26.0 → crypttrace-0.29.0}/src/crypttrace/fetchers/tron.py +0 -0
  29. {crypttrace-0.26.0 → crypttrace-0.29.0}/src/crypttrace/freeze.py +0 -0
  30. {crypttrace-0.26.0 → crypttrace-0.29.0}/src/crypttrace/funder.py +0 -0
  31. {crypttrace-0.26.0 → crypttrace-0.29.0}/src/crypttrace/gascluster.py +0 -0
  32. {crypttrace-0.26.0 → crypttrace-0.29.0}/src/crypttrace/investigate.py +0 -0
  33. {crypttrace-0.26.0 → crypttrace-0.29.0}/src/crypttrace/labels/__init__.py +0 -0
  34. {crypttrace-0.26.0 → crypttrace-0.29.0}/src/crypttrace/labels/audit.py +0 -0
  35. {crypttrace-0.26.0 → crypttrace-0.29.0}/src/crypttrace/labels/bulk.py +0 -0
  36. {crypttrace-0.26.0 → crypttrace-0.29.0}/src/crypttrace/labels/names.py +0 -0
  37. {crypttrace-0.26.0 → crypttrace-0.29.0}/src/crypttrace/labels/partial.json +0 -0
  38. {crypttrace-0.26.0 → crypttrace-0.29.0}/src/crypttrace/labels/tonapi.py +0 -0
  39. {crypttrace-0.26.0 → crypttrace-0.29.0}/src/crypttrace/labels/tronscan.py +0 -0
  40. {crypttrace-0.26.0 → crypttrace-0.29.0}/src/crypttrace/offramp.py +0 -0
  41. {crypttrace-0.26.0 → crypttrace-0.29.0}/src/crypttrace/poisoning.py +0 -0
  42. {crypttrace-0.26.0 → crypttrace-0.29.0}/src/crypttrace/prices.py +0 -0
  43. {crypttrace-0.26.0 → crypttrace-0.29.0}/src/crypttrace/report.py +0 -0
  44. {crypttrace-0.26.0 → crypttrace-0.29.0}/src/crypttrace/spam.py +0 -0
  45. {crypttrace-0.26.0 → crypttrace-0.29.0}/src/crypttrace/store.py +0 -0
  46. {crypttrace-0.26.0 → crypttrace-0.29.0}/src/crypttrace/trace.py +0 -0
  47. {crypttrace-0.26.0 → crypttrace-0.29.0}/src/crypttrace/verify.py +0 -0
  48. {crypttrace-0.26.0 → crypttrace-0.29.0}/src/crypttrace/watch.py +0 -0
  49. {crypttrace-0.26.0 → crypttrace-0.29.0}/src/crypttrace/webapp.py +0 -0
  50. {crypttrace-0.26.0 → crypttrace-0.29.0}/src/crypttrace.egg-info/SOURCES.txt +0 -0
  51. {crypttrace-0.26.0 → crypttrace-0.29.0}/src/crypttrace.egg-info/dependency_links.txt +0 -0
  52. {crypttrace-0.26.0 → crypttrace-0.29.0}/src/crypttrace.egg-info/entry_points.txt +0 -0
  53. {crypttrace-0.26.0 → crypttrace-0.29.0}/src/crypttrace.egg-info/requires.txt +0 -0
  54. {crypttrace-0.26.0 → crypttrace-0.29.0}/src/crypttrace.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: crypttrace
3
- Version: 0.26.0
3
+ Version: 0.29.0
4
4
  Summary: OSINT toolkit for crypto investigations: trace stolen funds across Ethereum, Bitcoin, Tron, Solana and TON
5
5
  Author: bobslayerX
6
6
  License-Expression: MIT
@@ -546,17 +546,32 @@ with the reason.
546
546
  ### Labels
547
547
 
548
548
  Ships a curated seed set (major exchanges, Tornado Cash, bridges, notable
549
- hacks). `update-labels` pulls authoritative public lists — currently the OFAC
550
- SDN sanctioned-address list — and merges them into the local DB in
551
- `~/.crypttrace/`. The curated seed wins on conflicts, so richer names survive.
552
- Add sources in `labels/labels.py` → `SOURCES`.
549
+ hacks). `update-labels` pulls public lists and merges them into the local DB
550
+ in `~/.crypttrace/`:
551
+
552
+ - **ScamSniffer's phishing blacklist** — about 2,500 EVM addresses of
553
+ phishing sites and wallet drainers, kept by a security team whose lists
554
+ wallets such as Rabby and Phantom use. Updated daily, published with a
555
+ 7-day delay. Labelled `scam`.
556
+ - **The OFAC SDN list** — sanctioned addresses. Labelled `sanctioned`; it wins
557
+ where both lists name an address.
558
+
559
+ Each download replaces that list's previous copy, so an address taken off a
560
+ list loses its label too. The lists are fetched on your machine rather than
561
+ shipped with crypttrace (ScamSniffer's is GPL-licensed, and both change
562
+ daily); run `update-labels` now and then. The curated seed wins on conflicts,
563
+ so richer names survive. Add sources in `labels/labels.py` → `SOURCES`.
564
+
565
+ With the phishing list in place, `check` also names any payment the wallet
566
+ made to a listed address. A fake site or a signed token approval takes money
567
+ in a single transfer, so there is no burst for the drain check to find.
553
568
 
554
569
  On Bitcoin, Tron and Solana the labels cover the reserve wallets of Binance,
555
- OKX and HTX, plus Bybit's older 2022 list — each taken from the address list the
556
- exchange publishes itself for proof-of-reserves; on TON and the EVM chains
557
- (Ethereum, BNB Chain, Arbitrum, Polygon, Base, Optimism), Binance's reserve
558
- wallets. MEXC's reserve wallets are covered on every one of these chains, from
559
- the "verified wallets" table of its monthly Hacken proof-of-reserves audit.
570
+ OKX and HTX — each taken from the address list the exchange publishes itself
571
+ for proof-of-reserves; on TON and the EVM chains (Ethereum, BNB Chain,
572
+ Arbitrum, Polygon, Base, Optimism), Binance's reserve wallets. Bybit's (274)
573
+ and MEXC's reserve wallets are covered on every one of these chains, from the
574
+ "verified wallets" table of their monthly Hacken proof-of-reserves audits.
560
575
  That is what lets `offramp` flag deposit addresses on those chains. Funds sent to an exchange not on that
561
576
  list still show as `unknown`. Every label records where it came from — see
562
577
  `crypttrace labels audit`.
@@ -712,15 +727,17 @@ src/crypttrace/
712
727
  webapp.py # Flask backend for the web UI
713
728
  web/index.html # single-page frontend (interactive graph)
714
729
  selftest.py # offline end-to-end checks, run by CI
730
+ tools/refresh_por.py # maintainer: refresh exchange reserve-wallet labels
715
731
  cases/ # worked investigations with their data
716
732
  ```
717
733
 
718
734
  ## Roadmap
719
735
 
720
736
  - More exchanges on Bitcoin, Tron, Solana (now: Binance, OKX, HTX, Bybit, MEXC),
721
- TON and the EVM chains (now: Binance, MEXC),
722
- and refreshing these lists as the exchanges republish them
723
- - More label sources: Chainabuse, CryptoScamDB, exchange deposit-address sets
737
+ TON and the EVM chains (now: Binance, HTX, Bybit, MEXC)
738
+ - More label sources: Chainabuse (needs an API key), more exchange
739
+ deposit-address sets (OKX's is in). CryptoScamDB is gone (its API has been
740
+ down since 2023); ScamSniffer's list took its place.
724
741
 
725
742
  ## Contributing
726
743
 
@@ -731,6 +748,14 @@ a `source` a reader can check and a `source_kind` (`self-published`,
731
748
  `crypttrace labels audit` and `python selftest.py` before opening a PR.
732
749
  Accuracy matters more than volume — a wrong label is worse than no label.
733
750
 
751
+ Exchanges republish their reserve-wallet lists (Binance continuously, HTX and
752
+ MEXC monthly). `python tools/refresh_por.py binance htx` shows what changed
753
+ since the labels were taken; `--write` adds the newly listed wallets and marks
754
+ the ones no longer listed as possibly retired (their labels stay: old funds
755
+ still lead there). For MEXC, download the latest Hacken audit PDF from
756
+ mexc.com/proof-of-reserve/audit-report and pass it with `--mexc FILE`; for
757
+ Bybit, the one from bybit.com/en/app/user/audit-report with `--bybit FILE`.
758
+
734
759
  ## Licence
735
760
 
736
761
  MIT — see [LICENSE](LICENSE).
@@ -512,17 +512,32 @@ with the reason.
512
512
  ### Labels
513
513
 
514
514
  Ships a curated seed set (major exchanges, Tornado Cash, bridges, notable
515
- hacks). `update-labels` pulls authoritative public lists — currently the OFAC
516
- SDN sanctioned-address list — and merges them into the local DB in
517
- `~/.crypttrace/`. The curated seed wins on conflicts, so richer names survive.
518
- Add sources in `labels/labels.py` → `SOURCES`.
515
+ hacks). `update-labels` pulls public lists and merges them into the local DB
516
+ in `~/.crypttrace/`:
517
+
518
+ - **ScamSniffer's phishing blacklist** — about 2,500 EVM addresses of
519
+ phishing sites and wallet drainers, kept by a security team whose lists
520
+ wallets such as Rabby and Phantom use. Updated daily, published with a
521
+ 7-day delay. Labelled `scam`.
522
+ - **The OFAC SDN list** — sanctioned addresses. Labelled `sanctioned`; it wins
523
+ where both lists name an address.
524
+
525
+ Each download replaces that list's previous copy, so an address taken off a
526
+ list loses its label too. The lists are fetched on your machine rather than
527
+ shipped with crypttrace (ScamSniffer's is GPL-licensed, and both change
528
+ daily); run `update-labels` now and then. The curated seed wins on conflicts,
529
+ so richer names survive. Add sources in `labels/labels.py` → `SOURCES`.
530
+
531
+ With the phishing list in place, `check` also names any payment the wallet
532
+ made to a listed address. A fake site or a signed token approval takes money
533
+ in a single transfer, so there is no burst for the drain check to find.
519
534
 
520
535
  On Bitcoin, Tron and Solana the labels cover the reserve wallets of Binance,
521
- OKX and HTX, plus Bybit's older 2022 list — each taken from the address list the
522
- exchange publishes itself for proof-of-reserves; on TON and the EVM chains
523
- (Ethereum, BNB Chain, Arbitrum, Polygon, Base, Optimism), Binance's reserve
524
- wallets. MEXC's reserve wallets are covered on every one of these chains, from
525
- the "verified wallets" table of its monthly Hacken proof-of-reserves audit.
536
+ OKX and HTX — each taken from the address list the exchange publishes itself
537
+ for proof-of-reserves; on TON and the EVM chains (Ethereum, BNB Chain,
538
+ Arbitrum, Polygon, Base, Optimism), Binance's reserve wallets. Bybit's (274)
539
+ and MEXC's reserve wallets are covered on every one of these chains, from the
540
+ "verified wallets" table of their monthly Hacken proof-of-reserves audits.
526
541
  That is what lets `offramp` flag deposit addresses on those chains. Funds sent to an exchange not on that
527
542
  list still show as `unknown`. Every label records where it came from — see
528
543
  `crypttrace labels audit`.
@@ -678,15 +693,17 @@ src/crypttrace/
678
693
  webapp.py # Flask backend for the web UI
679
694
  web/index.html # single-page frontend (interactive graph)
680
695
  selftest.py # offline end-to-end checks, run by CI
696
+ tools/refresh_por.py # maintainer: refresh exchange reserve-wallet labels
681
697
  cases/ # worked investigations with their data
682
698
  ```
683
699
 
684
700
  ## Roadmap
685
701
 
686
702
  - More exchanges on Bitcoin, Tron, Solana (now: Binance, OKX, HTX, Bybit, MEXC),
687
- TON and the EVM chains (now: Binance, MEXC),
688
- and refreshing these lists as the exchanges republish them
689
- - More label sources: Chainabuse, CryptoScamDB, exchange deposit-address sets
703
+ TON and the EVM chains (now: Binance, HTX, Bybit, MEXC)
704
+ - More label sources: Chainabuse (needs an API key), more exchange
705
+ deposit-address sets (OKX's is in). CryptoScamDB is gone (its API has been
706
+ down since 2023); ScamSniffer's list took its place.
690
707
 
691
708
  ## Contributing
692
709
 
@@ -697,6 +714,14 @@ a `source` a reader can check and a `source_kind` (`self-published`,
697
714
  `crypttrace labels audit` and `python selftest.py` before opening a PR.
698
715
  Accuracy matters more than volume — a wrong label is worse than no label.
699
716
 
717
+ Exchanges republish their reserve-wallet lists (Binance continuously, HTX and
718
+ MEXC monthly). `python tools/refresh_por.py binance htx` shows what changed
719
+ since the labels were taken; `--write` adds the newly listed wallets and marks
720
+ the ones no longer listed as possibly retired (their labels stay: old funds
721
+ still lead there). For MEXC, download the latest Hacken audit PDF from
722
+ mexc.com/proof-of-reserve/audit-report and pass it with `--mexc FILE`; for
723
+ Bybit, the one from bybit.com/en/app/user/audit-report with `--bybit FILE`.
724
+
700
725
  ## Licence
701
726
 
702
727
  MIT — see [LICENSE](LICENSE).
@@ -1,2 +1,2 @@
1
1
  """crypttrace — OSINT crypto investigation CLI."""
2
- __version__ = "0.26.0"
2
+ __version__ = "0.29.0"
@@ -72,6 +72,25 @@ def _amounts(rows: List[dict]) -> Dict[str, float]:
72
72
  return dict(tot)
73
73
 
74
74
 
75
+ def _flagged(out: List[dict]) -> List[dict]:
76
+ """Payments to an address on a phishing or sanctions list, per address.
77
+
78
+ A phishing site or a signed token approval usually takes money in one
79
+ transfer, so there is no burst to find; the destination's label is the tell."""
80
+ by: Dict[str, dict] = {}
81
+ for r in out:
82
+ kind = labels.type_of(r["to"])
83
+ if kind not in ("scam", "sanctioned"):
84
+ continue
85
+ f = by.setdefault(r["to"], {"address": r["to"], "label": labels.label_of(r["to"]), "type": kind,
86
+ "amounts": defaultdict(float), "first": r["timestamp"], "txs": set()})
87
+ f["amounts"][r.get("symbol") or "?"] += r.get("value") or 0
88
+ f["first"] = min(f["first"], r["timestamp"])
89
+ f["txs"].add(r.get("hash"))
90
+ return [{**f, "amounts": dict(f["amounts"]), "txs": len(f["txs"])}
91
+ for f in sorted(by.values(), key=lambda f: f["first"])]
92
+
93
+
75
94
  def check(address: str, chain: str, limit: int = 1000) -> Dict:
76
95
  """Verdict on one wallet: drained (and how), suspicious, or no drain found."""
77
96
  me = chains.norm_addr(address, chain)
@@ -86,6 +105,7 @@ def check(address: str, chain: str, limit: int = 1000) -> Dict:
86
105
  if not out:
87
106
  res["reasons"].append("this wallet has sent nothing in the history read")
88
107
  return res
108
+ res["flagged"] = _flagged(out)
89
109
 
90
110
  burst = _best_burst(out, chains.symbol(chain))
91
111
  dest, win = burst["to"], burst["rows"]