""" Entity Labeler - Advanced Wallet Labeling Module ================================================ Exposes: • Exchange/Protocol detection (Uniswap, Aave, Binance, etc.) • Whale detection (high-value wallets) • Contract type detection (fungible, non-fungible, proxy, library) • Risk scoring (low/medium/high/critical) • Smart contract verification status • Token metadata (name, symbol, decimals) """ import logging from datetime import datetime from typing import Any from pydantic import BaseModel from app.entity_clustering import EntityClusteringEngine logger = logging.getLogger(__name__) # ─── KNOWN ENTITIES DATABASE ────────────────────────────────────────────── # Exchange contracts (major CEX/DEX) EXCHANGES = { "binance": ["0x" + "0" * 39 + "2a", "0x" + "0" * 39 + "3b"], # Placeholder - actual addresses "coinbase": ["0x" + "0" * 39 + "4c"], "uniswap": ["0x7a250d5630b4cf139281983dce37532e7d5c9196"], "sushiswap": ["0xc0a47dfe034b400b26bc65c9f1b2c5ac5b5d7373"], "curve": ["0x90e80ecf27b8b9f3a6c5b6694c44515f5b6f5d45"], "chainlink": ["0x514910771af9ca656af840dff83e8264ecf986ca"], } # Protocol contracts (DeFi protocols) PROTOCOLS = { "aave": { "address": "0x7d2768de32b0b8013e039f31fbacf67128c9c3d8", "token": "0x37d819f03d3261550b4e75c5e5c5c5c5c5c5c5c5", # placeholder "type": "lending", }, "compound": { "address": "0x3fdf4e696732ad248fbfc9d846c252d66b4d945c", "type": "lending", }, "uniswap_v3": { "address": "0x1f98431c8ad98523631ae4a59f267346ea31f988", "type": "amm", }, } # Token categories TOKEN_TYPES = { "stablecoin": ["usdc", "usdt", "dai", "busd", "ampt"], "memecoin": ["pepe", "shib", "doge", "floki"], "governance": ["snapshot", "governance", "vote"], "yield": ["aave", "comp", "yearn"], } # ─── DETECTION FUNCTIONS ────────────────────────────────────────────────── def detect_exchange(address: str, name: str = "", symbol: str = "") -> str | None: """Detect if address belongs to a known exchange/protocol.""" address_lower = address.lower() # Check exchange contracts for exchange, contracts in EXCHANGES.items(): if any(contract.lower() in address_lower for contract in contracts): return exchange # Check name/symbol matching name_lower = (name + " " + symbol).lower() for exchange in EXCHANGES: if exchange.lower() in name_lower: return exchange return None def detect_protocol(address: str, name: str = "", symbol: str = "") -> str | None: """Detect if address is a DeFi protocol.""" # Check protocol contracts for protocol, info in PROTOCOLS.items(): if info["address"].lower() in address.lower(): return protocol # Check name/symbol name_lower = (name + " " + symbol).lower() for protocol in PROTOCOLS: if protocol.lower() in name_lower: return protocol return None def detect_token_type(symbol: str, name: str = "") -> list[str]: """Detect token type(s) based on name/symbol.""" symbol_lower = symbol.lower() name_lower = name.lower() types = [] for token_type, keywords in TOKEN_TYPES.items(): if any(kw in symbol_lower or kw in name_lower for kw in keywords): types.append(token_type) return types def detect_whale(address: str, balance_eth: float = 0, balance_usd: float = 0) -> dict[str, Any] | None: """Detect if address is a whale (high-value wallet).""" whale_thresholds = { "super_whale": 10000, # $10M+ USD "high_whale": 1000, # $1M+ USD "medium_whale": 100, # $100k+ USD } for level, threshold_usd in whale_thresholds.items(): if balance_usd >= threshold_usd: return { "is_whale": True, "level": level, "balance_usd": balance_usd, "balance_eth": balance_eth, "rank": "whale", } return None def detect_high_risk(address: str, tx_count: int = 0, age_days: int = 0) -> dict[str, Any]: """Detect high-risk wallet characteristics.""" risk_factors = [] risk_score = 0 # Low age with high activity = suspicious if age_days < 30 and tx_count > 100: risk_factors.append("new_wallet_high_activity") risk_score += 2 # High transaction count (potential bot/spam) if tx_count > 1000: risk_factors.append("high_frequency") risk_score += 1 # Zero balance but active (potential scam) if tx_count > 50: risk_factors.append("活跃但余额为零") risk_score += 1 return { "is_high_risk": risk_score >= 2, "risk_score": risk_score, "risk_factors": risk_factors, "risk_level": "low" if risk_score == 0 else ("medium" if risk_score <= 2 else "high"), } def analyze_contract_type(bytecode: str, source_code: str | None = None) -> dict[str, Any]: """Analyze contract type from bytecode.""" result = { "is_contract": True, "contract_type": "unknown", "is_verified": source_code is not None, "is_proxy": False, "proxy_type": None, "has_own_code": False, } # Check for proxy patterns if "0x360894a1" in bytecode: # delegate call to result["is_proxy"] = True result["proxy_type"] = "delegate" elif "0xc5318c17" in bytecode: # implementation storage result["is_proxy"] = True result["proxy_type"] = "transparent" elif "0x70ca07de" in bytecode: # upgradeTo result["is_proxy"] = True result["proxy_type"] = "upgradeable" # Check for specific contract types if "transferFrom" in (source_code or ""): result["contract_type"] = "erc20" elif "tokenURI" in (source_code or "") or "safeMint" in (source_code or ""): result["contract_type"] = "erc721" elif "vote" in (source_code or ""): result["contract_type"] = "governance" return result # ─── ENTITY LABELER ENGINE ──────────────────────────────────────────────── class EntityLabeler: """Main entity labeler engine.""" def __init__(self, clustering_engine: EntityClusteringEngine | None = None): self.clustering = clustering_engine or EntityClusteringEngine() self.labels: dict[str, dict[str, Any]] = {} self.risk_scores: dict[str, float] = {} def label_address( self, address: str, chain: str = "ethereum", name: str = "", symbol: str = "", balance_eth: float = 0, balance_usd: float = 0, tx_count: int = 0, age_days: int = 0, bytecode: str = "", source_code: str | None = None, ) -> dict[str, Any]: """Comprehensive labeling of an address.""" label = { "address": address, "chain": chain, "labels": [], "labels_detail": [], "risk": {"score": 0, "level": "low", "factors": []}, "whale": None, "exchange": None, "protocol": None, "token_type": [], "contract": {}, "verified_at": datetime.utcnow().isoformat(), } # Detect exchange exchange = detect_exchange(address, name, symbol) if exchange: label["exchange"] = exchange label["labels"].append(f"exchange:{exchange}") label["labels_detail"].append({"type": "exchange", "name": exchange}) label["risk"]["score"] += 1 # Detect protocol protocol = detect_protocol(address, name, symbol) if protocol: label["protocol"] = protocol label["labels"].append(f"protocol:{protocol}") label["labels_detail"].append({"type": "protocol", "name": protocol}) # Detect whale whale = detect_whale(address, balance_eth, balance_usd) if whale: label["whale"] = whale label["labels"].append(f"whale:{whale['level']}") label["labels_detail"].append({"type": "whale", "level": whale["level"]}) label["risk"]["score"] += 1 # Whales need monitoring # Detect token type token_types = detect_token_type(symbol, name) if token_types: label["token_type"] = token_types label["labels"].extend([f"token_type:{tt}" for tt in token_types]) # Detect risk factors risk = detect_high_risk(address, tx_count, age_days) label["risk"]["score"] += risk["risk_score"] label["risk"]["factors"] = risk["risk_factors"] # Adjust risk level label["risk"]["level"] = risk["risk_level"] # Analyze contract if bytecode: contract_info = analyze_contract_type(bytecode, source_code) label["contract"] = contract_info if contract_info["contract_type"] != "unknown": label["labels"].append(f"contract:{contract_info['contract_type']}") # Store label self.labels[address] = label # Update risk score self.risk_scores[address] = min(label["risk"]["score"], 10) return label def batch_label_addresses( self, addresses: list[dict[str, Any]], ) -> dict[str, dict[str, Any]]: """Label multiple addresses at once.""" results = {} for addr_info in addresses: address = addr_info.get("address", "") result = self.label_address( address=address, chain=addr_info.get("chain", "ethereum"), name=addr_info.get("name", ""), symbol=addr_info.get("symbol", ""), balance_eth=addr_info.get("balance_eth", 0), balance_usd=addr_info.get("balance_usd", 0), tx_count=addr_info.get("tx_count", 0), age_days=addr_info.get("age_days", 0), bytecode=addr_info.get("bytecode", ""), source_code=addr_info.get("source_code"), ) results[address] = result return results def get_label(self, address: str) -> dict[str, Any] | None: """Get label for an address.""" return self.labels.get(address.lower()) def get_risk_score(self, address: str) -> float: """Get risk score for an address.""" return self.risk_scores.get(address.lower(), 0) def get_risk_level(self, address: str) -> str: """Get risk level for an address.""" score = self.get_risk_score(address) if score >= 8: return "critical" elif score >= 5: return "high" elif score >= 2: return "medium" return "low" # ─── MODULE FUNCTIONS ───────────────────────────────────────────────────── _labeler: EntityLabeler | None = None def get_entity_labeler() -> EntityLabeler: """Get the global entity labeler instance.""" global _labeler if _labeler is None: _labeler = EntityLabeler() return _labeler def label_address( address: str, chain: str = "ethereum", name: str = "", symbol: str = "", balance_eth: float = 0, balance_usd: float = 0, tx_count: int = 0, age_days: int = 0, bytecode: str = "", source_code: str | None = None, ) -> dict[str, Any]: """Label an address with comprehensive metadata.""" labeler = get_entity_labeler() return labeler.label_address( address=address, chain=chain, name=name, symbol=symbol, balance_eth=balance_eth, balance_usd=balance_usd, tx_count=tx_count, age_days=age_days, bytecode=bytecode, source_code=source_code, ) def batch_label_addresses(addresses: list[dict[str, Any]]) -> dict[str, dict[str, Any]]: """Label multiple addresses.""" labeler = get_entity_labeler() return labeler.batch_label_addresses(addresses) def get_risk_score(address: str) -> float: """Get risk score for an address.""" labeler = get_entity_labeler() return labeler.get_risk_score(address) def get_risk_level(address: str) -> str: """Get risk level for an address.""" labeler = get_entity_labeler() return labeler.get_risk_level(address) # ─── API RESPONSE MODELS ────────────────────────────────────────────────── class LabelResponse(BaseModel): address: str chain: str = "ethereum" labels: list[str] risk: dict[str, Any] whale: dict[str, Any] | None = None exchange: str | None = None protocol: str | None = None token_type: list[str] = [] contract: dict[str, Any] = {} verified_at: str class RiskResponse(BaseModel): address: str risk_score: float risk_level: str risk_factors: list[str]