merge: chore/cleanup-remove-bloat-and-secrets into main
This commit is contained in:
commit
bde2f3a97d
1173 changed files with 437609 additions and 0 deletions
156
app/routers/honeypot_map.py
Normal file
156
app/routers/honeypot_map.py
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
#!/usr/bin/env python3
|
||||
"""#14 — Honeypot Network Map. Maps all known honeypot contracts, clusters by deployer,
|
||||
fund flows. Interactive graph showing the honeypot factory network."""
|
||||
|
||||
import os
|
||||
|
||||
import httpx
|
||||
from fastapi import APIRouter, HTTPException, Query
|
||||
from pydantic import BaseModel
|
||||
|
||||
router = APIRouter(prefix="/api/v1/honeypot-map", tags=["honeypot-map"])
|
||||
|
||||
BACKEND = os.environ.get("BACKEND_URL", "http://localhost:8000")
|
||||
|
||||
|
||||
class HoneypotNode(BaseModel):
|
||||
id: str
|
||||
label: str
|
||||
type: str = "contract" # contract, deployer, funder, victim
|
||||
chain: str
|
||||
total_victims: int = 0
|
||||
total_stolen_usd: float = 0
|
||||
risk_score: int = 0
|
||||
|
||||
|
||||
class HoneypotEdge(BaseModel):
|
||||
source: str
|
||||
target: str
|
||||
relationship: str # deployed, funded_by, stole_from
|
||||
amount_usd: float = 0
|
||||
|
||||
|
||||
@router.get("/deployer/{deployer_address}")
|
||||
async def get_honeypot_deployer(deployer_address: str, chain: str = Query("ethereum")):
|
||||
"""Map all honeypot contracts deployed by a single address."""
|
||||
nodes: list[dict] = []
|
||||
edges: list[dict] = []
|
||||
|
||||
# Deployer node
|
||||
deployer_id = deployer_address[:16]
|
||||
nodes.append(
|
||||
{
|
||||
"id": deployer_id,
|
||||
"label": f"Deployer {deployer_address[:10]}",
|
||||
"type": "deployer",
|
||||
"chain": chain,
|
||||
}
|
||||
)
|
||||
|
||||
# Find all contracts deployed
|
||||
try:
|
||||
async with httpx.AsyncClient(timeout=15) as client:
|
||||
resp = await client.get(
|
||||
f"{BACKEND}/api/v1/eth-labels/search", params={"address": deployer_address, "type": "deployer"}
|
||||
)
|
||||
if resp.status_code == 200:
|
||||
data = resp.json()
|
||||
for entry in data.get("labels", []):
|
||||
is_honeypot = any(w in (entry.get("label", "") or "").lower() for w in ["honeypot", "scam", "rug"])
|
||||
contract_id = entry.get("contract_address", "")[:16]
|
||||
if contract_id:
|
||||
nodes.append(
|
||||
{
|
||||
"id": contract_id,
|
||||
"label": entry.get("name", contract_id),
|
||||
"type": "honeypot" if is_honeypot else "contract",
|
||||
"chain": entry.get("chain", chain),
|
||||
"risk_score": 80 if is_honeypot else 30,
|
||||
}
|
||||
)
|
||||
edges.append(
|
||||
{
|
||||
"source": deployer_id,
|
||||
"target": contract_id,
|
||||
"relationship": "deployed",
|
||||
}
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return {"nodes": nodes, "edges": edges, "total_contracts": len([n for n in nodes if n["type"] != "deployer"])}
|
||||
|
||||
|
||||
@router.get("/network")
|
||||
async def get_honeypot_network(
|
||||
chain: str = Query("ethereum"),
|
||||
limit: int = Query(50, le=100),
|
||||
min_risk: int = Query(50, le=100),
|
||||
):
|
||||
"""Get the current honeypot network map for a chain. Clusters by deployer groups."""
|
||||
nodes: list[dict] = []
|
||||
edges: list[dict] = []
|
||||
seen_deployers: set[str] = set()
|
||||
|
||||
try:
|
||||
async with httpx.AsyncClient(timeout=15) as client:
|
||||
resp = await client.get(
|
||||
f"{BACKEND}/api/v1/eth-labels/search", params={"q": "honeypot", "type": "deployer", "limit": limit}
|
||||
)
|
||||
if resp.status_code == 200:
|
||||
entries = resp.json().get("labels", [])
|
||||
for entry in entries[:limit]:
|
||||
deployer = entry.get("address", "")
|
||||
if deployer and deployer not in seen_deployers:
|
||||
seen_deployers.add(deployer)
|
||||
dep_id = deployer[:16]
|
||||
nodes.append(
|
||||
{
|
||||
"id": dep_id,
|
||||
"label": f"Deployer {deployer[:10]}",
|
||||
"type": "deployer",
|
||||
"chain": entry.get("chain", chain),
|
||||
"risk_score": entry.get("risk_score", 70),
|
||||
}
|
||||
)
|
||||
|
||||
# Get their contracts
|
||||
for contract in entry.get("contracts", [])[:5]:
|
||||
c_id = contract.get("address", "")[:16]
|
||||
if c_id:
|
||||
nodes.append(
|
||||
{
|
||||
"id": c_id,
|
||||
"label": contract.get("name", c_id),
|
||||
"type": "contract",
|
||||
"chain": entry.get("chain", chain),
|
||||
"risk_score": 75,
|
||||
}
|
||||
)
|
||||
edges.append(
|
||||
{
|
||||
"source": dep_id,
|
||||
"target": c_id,
|
||||
"relationship": "deployed",
|
||||
}
|
||||
)
|
||||
except Exception as e:
|
||||
raise HTTPException(502, f"Labels service unavailable: {e}")
|
||||
|
||||
return {
|
||||
"chain": chain,
|
||||
"nodes": nodes,
|
||||
"edges": edges,
|
||||
"total_deployers": len(seen_deployers),
|
||||
"total_contracts": len([n for n in nodes if n["type"] == "contract"]),
|
||||
}
|
||||
|
||||
|
||||
@router.get("/stats")
|
||||
async def get_honeypot_stats():
|
||||
"""Global honeypot statistics."""
|
||||
return {
|
||||
"description": "Honeypot contract network intelligence from eth-labels + SENTINEL + Real-CATS",
|
||||
"data_sources": ["eth-labels (115K addresses)", "Real-CATS (153K tokens)", "SENTINEL scanner"],
|
||||
"chains_supported": ["ethereum", "bsc", "polygon", "arbitrum", "base", "avalanche", "optimism"],
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue