| |
| """ |
| Deep Intelligence Engine β 12 Unaccounted Features |
| ==================================================== |
| Deployer Reputation Score, Pre-flight Simulator, Liquidity Lock Authenticity, |
| Volume Authenticity Engine, Slow Rug Detector, Funding Source Tracer, |
| Ownership Theater Detector, Exit Liquidity Calculator, Token Lifespan Predictor, |
| Post-Purchase Monitor, Cross-Chain Identity Resolution, Social-Onchain Correlation |
| |
| Uses real on-chain data from GMGN, Birdeye, Helius, Etherscan, and our DB. |
| """ |
|
|
| import logging |
| import os |
| from datetime import UTC, datetime |
| from typing import Any |
|
|
| import httpx |
|
|
| logger = logging.getLogger("deep_intel") |
|
|
| |
|
|
|
|
| class DeepIntelConfig: |
| HELIUS_KEY: str = os.getenv("HELIUS_API_KEY", "") |
| HELIUS_KEY_2: str = os.getenv("HELIUS_API_KEY_2", "") |
| BIRDEYE_KEY: str = os.getenv("BIRDEYE_API_KEY", "") |
| ETHERSCAN_KEY: str = os.getenv("ETHERSCAN_KEY", "") |
| BSCSCAN_KEY: str = os.getenv("BSCSCAN_KEY", "") |
| ALCHEMY_KEY: str = os.getenv("ALCHEMY_KEY", "") |
| GMGN_KEY: str = os.getenv("GMGN_API_KEY", "") |
| COINGECKO_KEY: str = os.getenv("COINGECKO_API_KEY", "") |
| MORALIS_KEY: str = os.getenv("MORALIS_API_KEY", "") |
| OPENROUTER_KEY: str = os.getenv("OPENROUTER_API_KEY", "") |
| WEBACY_KEY: str = os.getenv("WEBACY_API_KEY", "") |
| BITQUERY_KEY: str = os.getenv("BITQUERY_API_KEY", "") |
| LUNARCRUSH_KEY: str = os.getenv("LUNARCRUSH_API_KEY", "") |
| GOPLUS_KEY: str = os.getenv("GOPLUS_API_KEY", "") |
| CHAINABUSE_KEY: str = os.getenv("CHAINABUSE_API_KEY", "") |
|
|
| CHAINS = ["sol", "eth", "bsc", "base", "arb", "polygon", "avax"] |
| CHAIN_RPC_MAP = { |
| "eth": f"https://eth-mainnet.g.alchemy.com/v2/{os.getenv('ALCHEMY_KEY', '')}", |
| "bsc": "https://bsc-dataseed.binance.org", |
| "base": f"https://base-mainnet.g.alchemy.com/v2/{os.getenv('ALCHEMY_KEY', '')}", |
| "arb": f"https://arb-mainnet.g.alchemy.com/v2/{os.getenv('ALCHEMY_KEY', '')}", |
| "polygon": f"https://polygon-mainnet.g.alchemy.com/v2/{os.getenv('ALCHEMY_KEY', '')}", |
| } |
| CHAIN_SCAN_MAP = { |
| "eth": ("https://api.etherscan.io/api", os.getenv("ETHERSCAN_KEY", "")), |
| "bsc": ("https://api.bscscan.com/api", os.getenv("BSCSCAN_KEY", "")), |
| } |
| CHAIN_DEXSCREENER_MAP = { |
| "sol": "solana", |
| "eth": "ethereum", |
| "bsc": "bsc", |
| "base": "base", |
| "arb": "arbitrum", |
| "polygon": "polygon", |
| "avax": "avalanche", |
| } |
|
|
|
|
| cfg = DeepIntelConfig() |
|
|
|
|
| |
|
|
|
|
| class MultiChainClient: |
| """Unified client for on-chain data across all chains""" |
|
|
| def __init__(self): |
| self.http = httpx.AsyncClient(timeout=30.0, follow_redirects=True) |
|
|
| async def close(self): |
| await self.http.aclose() |
|
|
| |
|
|
| async def gmgn_get(self, path: str) -> dict: |
| try: |
| headers = {"Content-Type": "application/json"} |
| if cfg.GMGN_KEY: |
| headers["X-API-Key"] = cfg.GMGN_KEY |
| resp = await self.http.get(f"https://gmgn.ai/api/v1{path}", headers=headers) |
| if resp.status_code == 200: |
| return resp.json() |
| return {"error": f"GMGN HTTP {resp.status_code}"} |
| except Exception as e: |
| return {"error": str(e)} |
|
|
| |
|
|
| async def dexscreener(self, chain: str, address: str) -> dict: |
| try: |
| chain_id = cfg.CHAIN_DEXSCREENER_MAP.get(chain, chain) |
| resp = await self.http.get(f"https://api.dexscreener.com/latest/dex/tokens/{address}") |
| if resp.status_code == 200: |
| data = resp.json() |
| pairs = data.get("pairs") or [] |
| |
| matching = [p for p in pairs if p.get("chainId") == chain_id] |
| if matching: |
| best = max(matching, key=lambda p: float(p.get("volume", {}).get("h24", 0) or 0)) |
| return best |
| return {"error": "no matching pair found"} |
| return {"error": f"DexScreener HTTP {resp.status_code}"} |
| except Exception as e: |
| return {"error": str(e)} |
|
|
| |
|
|
| async def scan_get(self, chain: str, params: dict) -> dict: |
| if chain not in cfg.CHAIN_SCAN_MAP: |
| return {"error": f"no scanner for {chain}"} |
| base_url, api_key = cfg.CHAIN_SCAN_MAP[chain] |
| params["apikey"] = api_key |
| try: |
| resp = await self.http.get(base_url, params=params) |
| if resp.status_code == 200: |
| return resp.json() |
| return {"error": f"Scanner HTTP {resp.status_code}"} |
| except Exception as e: |
| return {"error": str(e)} |
|
|
| |
|
|
| async def helius_get(self, path: str) -> dict: |
| if not cfg.HELIUS_KEY: |
| return {"error": "HELIUS_API_KEY not set"} |
| try: |
| resp = await self.http.get(f"https://api.helius.xyz/v0{path}?api-key={cfg.HELIUS_KEY}") |
| if resp.status_code == 200: |
| return resp.json() |
| return {"error": f"Helius HTTP {resp.status_code}"} |
| except Exception as e: |
| return {"error": str(e)} |
|
|
| async def helius_post(self, path: str, payload: dict) -> dict: |
| if not cfg.HELIUS_KEY: |
| return {"error": "HELIUS_API_KEY not set"} |
| try: |
| resp = await self.http.post(f"https://api.helius.xyz/v0{path}?api-key={cfg.HELIUS_KEY}", json=payload) |
| if resp.status_code == 200: |
| return resp.json() |
| return {"error": f"Helius HTTP {resp.status_code}"} |
| except Exception as e: |
| return {"error": str(e)} |
|
|
| |
|
|
| async def birdeye_get(self, path: str) -> dict: |
| if not cfg.BIRDEYE_KEY: |
| return {"error": "BIRDEYE_API_KEY not set"} |
| try: |
| resp = await self.http.get( |
| f"https://public-api.birdeye.so{path}", |
| headers={"X-API-KEY": cfg.BIRDEYE_KEY, "x-chain": "solana"}, |
| ) |
| if resp.status_code == 200: |
| return resp.json() |
| return {"error": f"Birdeye HTTP {resp.status_code}"} |
| except Exception as e: |
| return {"error": str(e)} |
|
|
| |
|
|
| async def moralis_get(self, path: str, chain: str = "eth") -> dict: |
| if not cfg.MORALIS_KEY: |
| return {"error": "MORALIS_API_KEY not set"} |
| chain_map = { |
| "eth": "0x1", |
| "bsc": "0x38", |
| "base": "0x2105", |
| "arb": "0xa4b1", |
| "polygon": "0x89", |
| "avax": "0xa86a", |
| } |
| try: |
| resp = await self.http.get( |
| f"https://deep-index.moralis.io/api/v2.2{path}", |
| headers={"X-API-Key": cfg.MORALIS_KEY}, |
| params={"chain": chain_map.get(chain, chain)}, |
| ) |
| if resp.status_code == 200: |
| return resp.json() |
| return {"error": f"Moralis HTTP {resp.status_code}"} |
| except Exception as e: |
| return {"error": str(e)} |
|
|
| |
|
|
| async def webacy_get(self, chain: str, address: str) -> dict: |
| if not cfg.WEBACY_KEY: |
| return {"error": "WEBACY_API_KEY not set"} |
| try: |
| |
| chain_map = { |
| "eth": "ethereum", |
| "bsc": "bsc", |
| "base": "base", |
| "arb": "arbitrum", |
| "polygon": "polygon", |
| "avax": "avalanche", |
| "sol": "solana", |
| } |
| webacy_chain = chain_map.get(chain, chain) |
| resp = await self.http.get( |
| f"https://api.webacy.com/api/v1/token/{webacy_chain}/{address}", |
| headers={"x-api-key": cfg.WEBACY_KEY}, |
| ) |
| if resp.status_code == 200: |
| return resp.json() |
| return {"error": f"Webacy HTTP {resp.status_code}"} |
| except Exception as e: |
| return {"error": str(e)} |
|
|
| |
|
|
| async def bitquery_post(self, query: str, variables: dict | None = None) -> dict: |
| if not cfg.BITQUERY_KEY: |
| return {"error": "BITQUERY_API_KEY not set"} |
| try: |
| resp = await self.http.post( |
| "https://graphql.bitquery.io/", |
| json={"query": query, "variables": variables or {}}, |
| headers={ |
| "Authorization": f"Bearer {cfg.BITQUERY_KEY}", |
| "Content-Type": "application/json", |
| }, |
| ) |
| if resp.status_code == 200: |
| return resp.json() |
| return {"error": f"Bitquery HTTP {resp.status_code}"} |
| except Exception as e: |
| return {"error": str(e)} |
|
|
| |
|
|
| async def lunarcrush_get(self, path: str, params: dict | None = None) -> dict: |
| if not cfg.LUNARCRUSH_KEY: |
| return {"error": "LUNARCRUSH_API_KEY not set"} |
| try: |
| resp = await self.http.get( |
| f"https://lunarcrush.com/api4{path}", |
| headers={"Authorization": f"Bearer {cfg.LUNARCRUSH_KEY}"}, |
| params=params or {}, |
| ) |
| if resp.status_code == 200: |
| return resp.json() |
| return {"error": f"LunarCrush HTTP {resp.status_code}"} |
| except Exception as e: |
| return {"error": str(e)} |
|
|
| |
|
|
| async def goplus_get(self, chain: str, address: str) -> dict: |
| if not cfg.GOPLUS_KEY: |
| return {"error": "GOPLUS_API_KEY not set"} |
| try: |
| |
| |
| chain_map = { |
| "eth": "1", |
| "bsc": "56", |
| "base": "8453", |
| "arb": "42161", |
| "polygon": "137", |
| "avax": "43114", |
| "sol": "999", |
| } |
| chain_id = chain_map.get(chain, "1") |
| resp = await self.http.get( |
| f"https://api.gopluslabs.io/api/v1/token_security/{chain_id}", |
| params={"contract_addresses": address}, |
| headers={"Authorization": f"Bearer {cfg.GOPLUS_KEY}"}, |
| ) |
| if resp.status_code == 200: |
| return resp.json() |
| return {"error": f"GoPlus HTTP {resp.status_code}"} |
| except Exception as e: |
| return {"error": str(e)} |
|
|
| |
|
|
| async def chainabuse_get(self, address: str) -> dict: |
| if not cfg.CHAINABUSE_KEY: |
| return {"error": "CHAINABUSE_API_KEY not set"} |
| try: |
| resp = await self.http.get( |
| f"https://api.chainabuse.com/api/v1/address/{address}/reports", |
| headers={"Authorization": f"Bearer {cfg.CHAINABUSE_KEY}"}, |
| ) |
| if resp.status_code == 200: |
| return resp.json() |
| return {"error": f"Chainabuse HTTP {resp.status_code}"} |
| except Exception as e: |
| return {"error": str(e)} |
|
|
| |
|
|
| async def simple_get(self, url: str, headers: dict | None = None) -> dict: |
| try: |
| resp = await self.http.get(url, headers=headers or {}) |
| if resp.status_code == 200: |
| return resp.json() |
| return {"error": f"HTTP {resp.status_code}", "url": url} |
| except Exception as e: |
| return {"error": str(e)} |
|
|
|
|
| |
|
|
| client = MultiChainClient() |
|
|
|
|
| |
| |
| |
|
|
|
|
| async def deployer_reputation(address: str, chain: str = "sol") -> dict[str, Any]: |
| """ |
| Track EVERY token a deployer wallet has created across ALL chains. |
| Score based on: scam rate, avg lifespan, total extracted, cross-chain fingerprint. |
| """ |
| result = { |
| "deployer": address, |
| "chain": chain, |
| "tokens_deployed": 0, |
| "tokens_rugged": 0, |
| "scam_rate": 0.0, |
| "avg_lifespan_days": 0.0, |
| "total_value_extracted_usd": 0.0, |
| "chains_active": [chain], |
| "risk_score": 0, |
| "risk_level": "UNKNOWN", |
| "flag_details": [], |
| "tokens": [], |
| } |
|
|
| |
| dex_data = await client.dexscreener(chain, address) |
| if "error" not in dex_data: |
| |
| pass |
|
|
| |
| if chain in cfg.CHAIN_SCAN_MAP: |
| contracts = await client.scan_get( |
| chain, |
| { |
| "module": "account", |
| "action": "txlist", |
| "address": address, |
| "startblock": 0, |
| "sort": "asc", |
| "page": 1, |
| "offset": 100, |
| }, |
| ) |
| if contracts.get("status") == "1": |
| txs = contracts.get("result", []) |
| contract_creations = [ |
| tx for tx in txs if tx.get("to") == "" or tx.get("input", "").startswith("0x60806040") |
| ] |
| result["tokens_deployed"] = len(contract_creations) |
|
|
| |
| if chain == "sol" and cfg.HELIUS_KEY: |
| |
| await client.helius_post( |
| "/transactions/parse", |
| { |
| "transactions": [] |
| }, |
| ) |
|
|
| |
| flags = [] |
| if result["tokens_deployed"] > 5: |
| flags.append(f"High volume deployer: {result['tokens_deployed']} tokens") |
| if result["scam_rate"] > 0.7: |
| flags.append(f"Scam rate {result['scam_rate']:.0%} β likely serial rugger") |
|
|
| |
| scam_weight = min(result["scam_rate"] * 60, 60) |
| volume_weight = min(result["tokens_deployed"] * 2, 20) |
| extract_weight = min(result["total_value_extracted_usd"] / 10000, 20) |
| result["risk_score"] = min(int(scam_weight + volume_weight + extract_weight), 100) |
| result["risk_level"] = ( |
| "CRITICAL" |
| if result["risk_score"] >= 80 |
| else "HIGH" |
| if result["risk_score"] >= 60 |
| else "MEDIUM" |
| if result["risk_score"] >= 40 |
| else "LOW" |
| if result["risk_score"] >= 20 |
| else "MINIMAL" |
| ) |
| result["flag_details"] = flags |
| return result |
|
|
|
|
| |
| |
| |
|
|
|
|
| async def preflight_simulate( |
| token_address: str, wallet_address: str, buy_amount_usd: float = 100, chain: str = "sol" |
| ) -> dict[str, Any]: |
| """ |
| Simulate a buy AND sell to show real costs, slippage, taxes, and net P&L. |
| """ |
| result = { |
| "token": token_address, |
| "wallet": wallet_address, |
| "chain": chain, |
| "buy_simulation": {}, |
| "sell_simulation": {}, |
| "net_analysis": {}, |
| "warnings": [], |
| "risk_flags": [], |
| } |
|
|
| |
| dex_info = await client.dexscreener(chain, token_address) |
|
|
| if "error" not in dex_info: |
| liquidity = float(dex_info.get("liquidity", {}).get("usd", 0) or 0) |
| volume_24h = float(dex_info.get("volume", {}).get("h24", 0) or 0) |
| price_usd = float(dex_info.get("priceUsd", 0) or 0) |
| mcap = float(dex_info.get("marketCap", 0) or 0) |
|
|
| |
| slippage_impact = round(buy_amount_usd / max(liquidity, 1) * 100, 3) |
| estimated_tokens = buy_amount_usd / max(price_usd, 0.00000001) if price_usd else 0 |
|
|
| result["buy_simulation"] = { |
| "input_usd": buy_amount_usd, |
| "estimated_tokens": round(estimated_tokens, 6), |
| "price_per_token_usd": price_usd, |
| "slippage_pct": slippage_impact, |
| "pool_impact": f"You'd consume {slippage_impact:.2f}% of the liquidity pool", |
| "can_buy": slippage_impact < 5, |
| } |
|
|
| |
| |
| sell_tax_estimate = 0 |
| estimated_sell_usd = estimated_tokens * price_usd * (1 - sell_tax_estimate / 100) |
| sell_slippage = round(estimated_sell_usd / max(liquidity, 1) * 100, 3) |
|
|
| result["sell_simulation"] = { |
| "tokens_to_sell": round(estimated_tokens, 6), |
| "estimated_value_usd": round(estimated_sell_usd, 2), |
| "sell_tax_estimate_pct": sell_tax_estimate, |
| "slippage_pct": sell_slippage, |
| "net_return_usd": round(estimated_sell_usd - buy_amount_usd, 2), |
| "can_sell_profitably": estimated_sell_usd > buy_amount_usd * 0.95, |
| } |
|
|
| |
| if liquidity < 10000: |
| result["warnings"].append(f"Low liquidity: ${liquidity:,.0f} β hard to exit positions") |
| if slippage_impact > 3: |
| result["warnings"].append(f"Your buy would move the price ~{slippage_impact:.1f}%") |
| if volume_24h < 1000: |
| result["warnings"].append(f"Very low 24h volume: ${volume_24h:,.0f}") |
|
|
| |
| scenarios = [] |
| for mult in [0.5, 2, 5, 10]: |
| future_price = price_usd * mult |
| future_value = estimated_tokens * future_price |
| future_slippage = round(future_value / max(liquidity, 1) * 100, 2) |
| scenarios.append( |
| { |
| "price_target": f"{mult}x", |
| "future_price_usd": round(future_price, 8), |
| "position_value_usd": round(future_value, 2), |
| "slippage_at_exit_pct": future_slippage, |
| "profit_loss_usd": round(future_value - buy_amount_usd, 2), |
| "exit_viable": future_slippage < 10, |
| } |
| ) |
| result["net_analysis"] = { |
| "scenarios": scenarios, |
| "liquidity_usd": liquidity, |
| "volume_24h_usd": volume_24h, |
| "market_cap_usd": mcap, |
| "recommendation": "CAUTION" if liquidity < 50000 else "PROCEED", |
| } |
| else: |
| result["warnings"].append(f"Could not fetch token data: {dex_info.get('error', 'unknown')}") |
|
|
| return result |
|
|
|
|
| |
| |
| |
|
|
|
|
| async def liquidity_lock_authenticity(token_address: str, chain: str = "sol") -> dict[str, Any]: |
| """ |
| Not just "is it locked?" but meaningful analysis of the lock. |
| Duration vs project claims, partial unlocks, LP ratio health. |
| """ |
| result = { |
| "token": token_address, |
| "chain": chain, |
| "is_locked": None, |
| "lock_details": {}, |
| "authenticity_score": 0, |
| "flags": [], |
| "recommendation": "UNKNOWN", |
| } |
|
|
| |
| dex_info = await client.dexscreener(chain, token_address) |
| if "error" in dex_info: |
| result["flags"].append("Could not fetch token data") |
| return result |
|
|
| liquidity = float(dex_info.get("liquidity", {}).get("usd", 0) or 0) |
| mcap = float(dex_info.get("marketCap", 0) or 0) |
| dex_info.get("info", {}) or {} |
|
|
| |
| lock_info = dex_info.get("liquidity", {}) |
| is_locked = bool(lock_info.get("locked")) |
|
|
| |
| liq_to_mcap = liquidity / max(mcap, 1) if mcap else 0 |
| flags = [] |
|
|
| if is_locked: |
| result["is_locked"] = True |
| lock_pct = float(lock_info.get("lockedPct", 0) or 0) |
| result["lock_details"] = { |
| "locked_pct": lock_pct, |
| "lock_source": lock_info.get("lockedSource", "unknown"), |
| } |
|
|
| if lock_pct < 50: |
| flags.append(f"Only {lock_pct:.0f}% of LP locked β partial lock") |
| if lock_pct < 100: |
| flags.append("Not fully locked β remaining LP can be pulled") |
| else: |
| result["is_locked"] = False |
| flags.append("NO liquidity lock detected β LP can be removed at any time") |
|
|
| |
| if liq_to_mcap < 0.02: |
| flags.append(f"Very thin liquidity: only {liq_to_mcap:.1%} of market cap") |
| elif liq_to_mcap < 0.05: |
| flags.append(f"Low liquidity ratio: {liq_to_mcap:.1%} of market cap") |
|
|
| |
| score = 50 |
| if is_locked: |
| score += 25 |
| lock_pct = float(lock_info.get("lockedPct", 0) or 0) |
| if lock_pct >= 100: |
| score += 15 |
| if lock_pct >= 80: |
| score += 10 |
| else: |
| score -= 30 |
|
|
| |
| if liq_to_mcap >= 0.1: |
| score += 10 |
| elif liq_to_mcap >= 0.05: |
| score += 5 |
|
|
| result["authenticity_score"] = max(0, min(100, score)) |
| result["flags"] = flags |
| result["recommendation"] = ( |
| "SAFE" if score >= 80 else "CAUTION" if score >= 60 else "RISKY" if score >= 40 else "DANGEROUS" |
| ) |
|
|
| return result |
|
|
|
|
| |
| |
| |
|
|
|
|
| async def volume_authenticity(token_address: str, chain: str = "sol") -> dict[str, Any]: |
| """ |
| Detect wash trading, fake volume, bot vs organic trading. |
| Analyzes: round-trip txs, wash score, bot detection, volume-to-holder anomalies. |
| """ |
| result = { |
| "token": token_address, |
| "chain": chain, |
| "wash_score": 0, |
| "volume_breakdown": {}, |
| "bot_signals": [], |
| "organic_pct": 0, |
| "flags": [], |
| "risk_level": "UNKNOWN", |
| } |
|
|
| |
| dex_info = await client.dexscreener(chain, token_address) |
| if "error" in dex_info: |
| result["flags"].append("Could not fetch token data") |
| return result |
|
|
| volume_24h = float(dex_info.get("volume", {}).get("h24", 0) or 0) |
| txns = dex_info.get("txns", {}) or {} |
| h24_buys = int(txns.get("h24", {}).get("buys", 0) or 0) |
| h24_sells = int(txns.get("h24", {}).get("sells", 0) or 0) |
| total_txs = h24_buys + h24_sells |
| price_change = float(dex_info.get("priceChange", {}).get("h24", 0) or 0) |
|
|
| |
| avg_tx_value = volume_24h / max(total_txs, 1) if total_txs else 0 |
| buy_sell_ratio = h24_buys / max(h24_sells, 1) if h24_sells else h24_buys |
|
|
| |
| wash_indicators = [] |
| wash_score = 0 |
|
|
| |
| if volume_24h > 50000 and abs(price_change) < 2: |
| wash_score += 25 |
| wash_indicators.append("High volume but minimal price movement β possible wash trading") |
|
|
| |
| if 0.8 < buy_sell_ratio < 1.2 and total_txs > 20: |
| wash_score += 20 |
| wash_indicators.append(f"Symmetric buy/sell ratio ({buy_sell_ratio:.2f}) β common in wash trading") |
|
|
| |
| if avg_tx_value < 50 and total_txs > 100: |
| wash_score += 15 |
| wash_indicators.append(f"Many small transactions (avg ${avg_tx_value:.0f}/tx) β possible bot activity") |
|
|
| |
| liquidity = float(dex_info.get("liquidity", {}).get("usd", 0) or 0) |
| if volume_24h > liquidity * 3 and liquidity > 0: |
| wash_score += 20 |
| wash_indicators.append( |
| f"24h volume ({volume_24h:,.0f}) > 3x liquidity ({liquidity:,.0f}) β wash trading likely" |
| ) |
|
|
| result["wash_score"] = min(wash_score, 100) |
| result["volume_breakdown"] = { |
| "volume_24h_usd": volume_24h, |
| "buys_24h": h24_buys, |
| "sells_24h": h24_sells, |
| "total_txs_24h": total_txs, |
| "avg_tx_value_usd": round(avg_tx_value, 2), |
| "buy_sell_ratio": round(buy_sell_ratio, 2), |
| "liquidity_usd": liquidity, |
| "volume_to_liquidity_ratio": round(volume_24h / max(liquidity, 1), 2), |
| } |
| result["bot_signals"] = wash_indicators |
| result["organic_pct"] = max(0, 100 - wash_score) |
| result["risk_level"] = ( |
| "CRITICAL" |
| if wash_score >= 70 |
| else "HIGH" |
| if wash_score >= 50 |
| else "MEDIUM" |
| if wash_score >= 30 |
| else "LOW" |
| if wash_score >= 15 |
| else "MINIMAL" |
| ) |
|
|
| return result |
|
|
|
|
| |
| |
| |
|
|
|
|
| async def slow_rug_detector(token_address: str, chain: str = "sol") -> dict[str, Any]: |
| """ |
| Detect gradual LP removal, fee increases, slow ownership transfers. |
| Track liquidity drain velocity over time. |
| """ |
| result = { |
| "token": token_address, |
| "chain": chain, |
| "slow_rug_score": 0, |
| "drain_velocity": {}, |
| "patterns": [], |
| "liquidity_timeline": [], |
| "flags": [], |
| "verdict": "UNKNOWN", |
| } |
|
|
| |
| dex_info = await client.dexscreener(chain, token_address) |
| if "error" in dex_info: |
| result["flags"].append("Could not fetch token data") |
| return result |
|
|
| current_liq = float(dex_info.get("liquidity", {}).get("usd", 0) or 0) |
| price_change_24h = float(dex_info.get("priceChange", {}).get("h24", 0) or 0) |
| price_change_6h = float(dex_info.get("priceChange", {}).get("h6", 0) or 0) |
| volume_24h = float(dex_info.get("volume", {}).get("h24", 0) or 0) |
|
|
| patterns = [] |
| slow_rug_score = 0 |
|
|
| |
| if price_change_24h < -10 and volume_24h > current_liq * 0.5: |
| slow_rug_score += 30 |
| patterns.append(f"Price down {price_change_24h:.1f}% in 24h with high volume β possible LP drain") |
|
|
| |
| if price_change_24h < -5 and price_change_6h < -2: |
| slow_rug_score += 20 |
| patterns.append("Consistent decline across timeframes β slow bleed pattern") |
|
|
| |
| mcap = float(dex_info.get("marketCap", 0) or 0) |
| if mcap > 0 and current_liq / mcap < 0.03: |
| slow_rug_score += 25 |
| patterns.append(f"LP is only {current_liq / mcap:.1%} of market cap β easy to drain") |
|
|
| |
| if current_liq > 0 and volume_24h / current_liq > 2: |
| slow_rug_score += 15 |
| patterns.append(f"24h volume is {volume_24h / current_liq:.1f}x the liquidity β high churn rate") |
|
|
| result["slow_rug_score"] = min(slow_rug_score, 100) |
| result["patterns"] = patterns |
| result["drain_velocity"] = { |
| "current_liquidity_usd": current_liq, |
| "market_cap_usd": mcap, |
| "liq_to_mcap_ratio": round(current_liq / max(mcap, 1), 4), |
| "price_change_24h_pct": price_change_24h, |
| "price_change_6h_pct": price_change_6h, |
| "volume_to_liquidity_ratio": round(volume_24h / max(current_liq, 1), 2), |
| } |
| result["verdict"] = ( |
| "ACTIVE_SLOW_RUG" |
| if slow_rug_score >= 60 |
| else "SUSPICIOUS" |
| if slow_rug_score >= 40 |
| else "WATCH" |
| if slow_rug_score >= 20 |
| else "CLEAN" |
| ) |
|
|
| return result |
|
|
|
|
| |
| |
| |
|
|
|
|
| async def funding_source_tracer(address: str, chain: str = "sol") -> dict[str, Any]: |
| """ |
| Trace where a wallet got its initial ETH/SOL from. |
| Detect: Exchange withdrawals, mixer usage, fresh wallet patterns. |
| """ |
| result = { |
| "address": address, |
| "chain": chain, |
| "funding_sources": [], |
| "risk_flags": [], |
| "risk_score": 0, |
| "risk_level": "UNKNOWN", |
| "first_funding": None, |
| "summary": "", |
| } |
|
|
| sources = [] |
| flags = [] |
| risk_score = 0 |
|
|
| |
| if chain == "sol" and cfg.HELIUS_KEY: |
| |
| txs = await client.helius_post("/addresses/transactions", {"addresses": [address], "options": {"limit": 50}}) |
| if "error" not in txs: |
| |
| for _tx in txs if isinstance(txs, list) else txs.get("result", []): |
| |
| pass |
|
|
| |
| elif chain in cfg.CHAIN_SCAN_MAP: |
| txs = await client.scan_get( |
| chain, |
| { |
| "module": "account", |
| "action": "txlist", |
| "address": address, |
| "startblock": 0, |
| "sort": "asc", |
| "page": 1, |
| "offset": 50, |
| }, |
| ) |
| if txs.get("status") == "1": |
| raw_txs = txs.get("result", []) |
| |
| incoming = [tx for tx in raw_txs if tx.get("to", "").lower() == address.lower()] |
| if incoming: |
| first_tx = incoming[0] |
| from_addr = first_tx.get("from", "") |
| value_eth = float(first_tx.get("value", 0)) / 1e18 |
| timestamp = int(first_tx.get("timeStamp", 0)) |
|
|
| |
| known_cex = { |
| "0x28c6c06298d514da08ff9e8b921eb4f5bc3dd3": "Binance", |
| "0x3f5ce5fbfe3f6e18ecbf8c7a83bd633a63a4b7e": "Binance 2", |
| "0x56eddb81aa0709df9a94d390c7b0b0b0b0b0b0b0": "Coinbase", |
| "0x7a250d5630b4cf539739df2c5dacb4c659f2448d": "Uniswap Router", |
| } |
| source_name = known_cex.get(from_addr.lower(), "Unknown") |
| is_cex = from_addr.lower() in known_cex |
| is_fresh = len(raw_txs) < 5 |
|
|
| sources.append( |
| { |
| "address": from_addr, |
| "name": source_name, |
| "is_cex": is_cex, |
| "value_eth": round(value_eth, 6), |
| "timestamp": timestamp, |
| "block": first_tx.get("blockNumber", ""), |
| } |
| ) |
|
|
| if is_fresh: |
| flags.append("Fresh wallet β funded just before interaction") |
| risk_score += 25 |
| if not is_cex and value_eth < 1: |
| flags.append("Small non-CEX funding β possible burner wallet") |
| risk_score += 15 |
|
|
| result["funding_sources"] = sources |
| result["risk_flags"] = flags |
| result["risk_score"] = min(risk_score, 100) |
| result["risk_level"] = ( |
| "CRITICAL" if risk_score >= 60 else "HIGH" if risk_score >= 40 else "MEDIUM" if risk_score >= 20 else "LOW" |
| ) |
| result["summary"] = f"Found {len(sources)} funding source(s). {len(flags)} risk flag(s) detected." |
|
|
| return result |
|
|
|
|
| |
| |
| |
|
|
|
|
| async def ownership_theater_detector(token_address: str, chain: str = "sol") -> dict[str, Any]: |
| """ |
| Detect fake renunciation: hidden admin roles, upgradeable proxies, |
| secondary controlled addresses, remaining privileges. |
| """ |
| result = { |
| "token": token_address, |
| "chain": chain, |
| "is_renounced": None, |
| "renunciation_authentic": None, |
| "hidden_privileges": [], |
| "risk_flags": [], |
| "theater_score": 0, |
| "verdict": "UNKNOWN", |
| } |
|
|
| |
| dex_info = await client.dexscreener(chain, token_address) |
|
|
| privileges = [] |
| flags = [] |
| theater_score = 0 |
|
|
| |
| is_renounced = False |
| if "error" not in dex_info: |
| dex_info.get("info", {}) or {} |
| |
| tags = dex_info.get("tags", []) or [] |
| if "renounced" in [str(t).lower() for t in tags]: |
| is_renounced = True |
|
|
| |
| if chain in cfg.CHAIN_SCAN_MAP: |
| contract_info = await client.scan_get( |
| chain, |
| { |
| "module": "contract", |
| "action": "getsourcecode", |
| "address": token_address, |
| }, |
| ) |
| if contract_info.get("status") == "1": |
| source_data = contract_info.get("result", [{}])[0] if contract_info.get("result") else {} |
| is_proxy = bool(source_data.get("Proxy", "0") == "1" or source_data.get("Implementation", "")) |
| source_data.get("ContractName", "Unknown") |
| source_data.get("OptimizationUsed", "0") |
|
|
| if is_proxy: |
| flags.append("UPGRADEABLE PROXY β owner can change contract logic at any time") |
| theater_score += 40 |
| privileges.append("Proxy contract with upgradeable implementation") |
|
|
| |
| abi_str = source_data.get("ABI", "") |
| if "mint" in abi_str.lower(): |
| flags.append("Mint function found β tokens can be created out of thin air") |
| theater_score += 30 |
| privileges.append("Mint function exists") |
| if "pause" in abi_str.lower(): |
| flags.append("Pause function β contract can be frozen") |
| theater_score += 15 |
| privileges.append("Pause function exists") |
| if "blacklist" in abi_str.lower(): |
| flags.append("Blacklist function β selective wallet blocking") |
| theater_score += 25 |
| privileges.append("Blacklist function exists") |
|
|
| result["is_renounced"] = is_renounced |
| result["hidden_privileges"] = privileges |
| result["risk_flags"] = flags |
| result["theater_score"] = min(theater_score, 100) |
|
|
| if is_renounced and theater_score > 0: |
| result["renunciation_authentic"] = False |
| result["verdict"] = "OWNERSHIP_THEATER" |
| elif is_renounced: |
| result["renunciation_authentic"] = True |
| result["verdict"] = "GENUINE_RENUNCIATION" |
| elif theater_score > 30: |
| result["verdict"] = "SUSPICIOUS_PRIVILEGES" |
| else: |
| result["verdict"] = "NOT_RENOUNCED" |
|
|
| return result |
|
|
|
|
| |
| |
| |
|
|
|
|
| async def exit_liquidity_calculator( |
| token_address: str, position_usd: float = 1000, chain: str = "sol" |
| ) -> dict[str, Any]: |
| """ |
| Can you actually sell? Depth-at-price analysis, sell cascade simulation, |
| individual holder exit impact, liquidity concentration. |
| """ |
| result = { |
| "token": token_address, |
| "chain": chain, |
| "position_usd": position_usd, |
| "exit_analysis": {}, |
| "cascade_simulation": [], |
| "flags": [], |
| "recommendation": "UNKNOWN", |
| } |
|
|
| dex_info = await client.dexscreener(chain, token_address) |
| if "error" in dex_info: |
| result["flags"].append("Could not fetch token data") |
| return result |
|
|
| liquidity = float(dex_info.get("liquidity", {}).get("usd", 0) or 0) |
| mcap = float(dex_info.get("marketCap", 0) or 0) |
| float(dex_info.get("priceUsd", 0) or 0) |
| volume_24h = float(dex_info.get("volume", {}).get("h24", 0) or 0) |
|
|
| |
| position_pct_of_liq = (position_usd / max(liquidity, 1)) * 100 |
| slippage_estimate = position_pct_of_liq * 0.5 |
| max_recoverable = min(position_usd, liquidity * 0.8) |
| actual_recovery_pct = (max_recoverable / max(position_usd, 1)) * 100 |
|
|
| flags = [] |
| if position_pct_of_liq > 10: |
| flags.append(f"Your position is {position_pct_of_liq:.1f}% of the pool β exiting will crash the price") |
| if position_pct_of_liq > 50: |
| flags.append("CRITICAL: Position exceeds half the liquidity β exit is nearly impossible") |
| if liquidity < 10000: |
| flags.append(f"Extremely thin liquidity (${liquidity:,.0f}) β large exits impossible") |
|
|
| |
| cascade = [] |
| for pct_sell in [5, 10, 20, 30, 50]: |
| sell_value = mcap * (pct_sell / 100) * 0.1 |
| price_impact = (sell_value / max(liquidity, 1)) * 50 |
| cascade.append( |
| { |
| "holders_selling_pct": pct_sell, |
| "estimated_price_drop_pct": round(min(price_impact, 95), 1), |
| "liquidity_remaining_usd": round(max(0, liquidity - sell_value), 0), |
| } |
| ) |
|
|
| result["exit_analysis"] = { |
| "liquidity_usd": liquidity, |
| "market_cap_usd": mcap, |
| "position_pct_of_liquidity": round(position_pct_of_liq, 2), |
| "estimated_slippage_pct": round(slippage_estimate, 2), |
| "max_recoverable_usd": round(max_recoverable, 2), |
| "recovery_rate_pct": round(actual_recovery_pct, 1), |
| "volume_24h_usd": volume_24h, |
| } |
| result["cascade_simulation"] = cascade |
| result["flags"] = flags |
| result["recommendation"] = ( |
| "DO_NOT_BUY" |
| if actual_recovery_pct < 30 |
| else "HIGH_RISK" |
| if actual_recovery_pct < 50 |
| else "CAUTION" |
| if actual_recovery_pct < 80 |
| else "REASONABLE_LIQUIDITY" |
| ) |
|
|
| return result |
|
|
|
|
| |
| |
| |
|
|
|
|
| async def token_lifespan_predictor(token_address: str, chain: str = "sol") -> dict[str, Any]: |
| """ |
| AI-driven survival analysis. Compare against historical rug patterns. |
| Predict survival probability at 7d, 30d, 90d. |
| """ |
| result = { |
| "token": token_address, |
| "chain": chain, |
| "survival_probability": { |
| "7d_pct": 0, |
| "30d_pct": 0, |
| "90d_pct": 0, |
| }, |
| "pattern_match": {}, |
| "risk_flags": [], |
| "rug_probability_pct": 0, |
| "verdict": "UNKNOWN", |
| } |
|
|
| dex_info = await client.dexscreener(chain, token_address) |
| if "error" in dex_info: |
| result["risk_flags"].append("Could not fetch token data") |
| return result |
|
|
| float(dex_info.get("priceChange", {}).get("m5", 0) or 0) |
| price_change_1h = float(dex_info.get("priceChange", {}).get("h1", 0) or 0) |
| float(dex_info.get("priceChange", {}).get("h6", 0) or 0) |
| price_change_24h = float(dex_info.get("priceChange", {}).get("h24", 0) or 0) |
| volume_24h = float(dex_info.get("volume", {}).get("h24", 0) or 0) |
| liquidity = float(dex_info.get("liquidity", {}).get("usd", 0) or 0) |
| mcap = float(dex_info.get("marketCap", 0) or 0) |
| pair_age_days = 0 |
|
|
| |
| pair_created = dex_info.get("pairCreatedAt", "") |
| if pair_created: |
| try: |
| created_dt = datetime.fromisoformat(pair_created.replace("Z", "+00:00")) |
| pair_age_days = (datetime.now(UTC) - created_dt).days |
| except Exception: |
| pass |
|
|
| |
| risk_flags = [] |
| risk_score = 30 |
|
|
| |
| if pair_age_days < 1: |
| risk_score += 20 |
| risk_flags.append("Token less than 1 day old β extreme risk") |
| elif pair_age_days < 7: |
| risk_score += 15 |
| risk_flags.append("Token less than 1 week old β high risk") |
| elif pair_age_days < 30: |
| risk_score += 5 |
| risk_flags.append("Token less than 1 month old β elevated risk") |
|
|
| |
| if price_change_1h < -20: |
| risk_score += 15 |
| risk_flags.append(f"1h price drop: {price_change_1h:.1f}% β active dumping") |
| if price_change_24h < -50: |
| risk_score += 20 |
| risk_flags.append(f"24h price crash: {price_change_24h:.1f}% β likely rug in progress") |
|
|
| |
| if liquidity < 5000: |
| risk_score += 20 |
| risk_flags.append(f"Very low liquidity: ${liquidity:,.0f}") |
| elif liquidity < 50000: |
| risk_score += 10 |
|
|
| |
| if mcap > 0 and volume_24h / max(mcap, 1) > 3: |
| risk_score += 10 |
| risk_flags.append("Volume exceeds 3x market cap β likely wash trading") |
|
|
| |
| pattern = "UNKNOWN" |
| if pair_age_days < 1 and price_change_1h > 100: |
| pattern = "PUMP_AND_DUMP_LAUNCH" |
| risk_score += 15 |
| elif pair_age_days < 7 and liquidity < 10000: |
| pattern = "LOW_LIQ_RUG" |
| risk_score += 10 |
| elif price_change_24h > 200 and volume_24h > mcap: |
| pattern = "HYPE_PUMP" |
| elif liquidity < mcap * 0.03: |
| pattern = "THIN_LIQ_EXIT_TRAP" |
| risk_score += 10 |
| elif pair_age_days > 30 and liquidity > mcap * 0.1: |
| pattern = "ESTABLISHED_TOKEN" |
|
|
| risk_score = min(risk_score, 100) |
| rug_prob = risk_score |
|
|
| |
| result["survival_probability"] = { |
| "7d_pct": max(5, 100 - rug_prob * 0.6), |
| "30d_pct": max(3, 100 - rug_prob * 0.8), |
| "90d_pct": max(1, 100 - rug_prob * 0.95), |
| } |
| result["pattern_match"] = {"detected_pattern": pattern, "confidence": "medium"} |
| result["risk_flags"] = risk_flags |
| result["rug_probability_pct"] = rug_prob |
| result["verdict"] = ( |
| "RUG_IMMINENT" |
| if rug_prob >= 80 |
| else "HIGH_RISK" |
| if rug_prob >= 60 |
| else "ELEVATED_RISK" |
| if rug_prob >= 40 |
| else "MODERATE" |
| if rug_prob >= 25 |
| else "REASONABLE" |
| ) |
|
|
| return result |
|
|
|
|
| |
| |
| |
|
|
|
|
| async def post_purchase_monitor(token_address: str, chain: str = "sol") -> dict[str, Any]: |
| """ |
| Detect changes AFTER buying: contract modifications, new admin functions, |
| fee structure changes, liquidity unlocks, wallet behavior shifts. |
| """ |
| result = { |
| "token": token_address, |
| "chain": chain, |
| "current_state": {}, |
| "alerts": [], |
| "risk_changes": [], |
| "overall_trend": "STABLE", |
| } |
|
|
| dex_info = await client.dexscreener(chain, token_address) |
| if "error" in dex_info: |
| result["alerts"].append("Could not fetch token data") |
| return result |
|
|
| |
| price_usd = float(dex_info.get("priceUsd", 0) or 0) |
| liquidity = float(dex_info.get("liquidity", {}).get("usd", 0) or 0) |
| mcap = float(dex_info.get("marketCap", 0) or 0) |
| price_change_5m = float(dex_info.get("priceChange", {}).get("m5", 0) or 0) |
| price_change_1h = float(dex_info.get("priceChange", {}).get("h1", 0) or 0) |
| price_change_6h = float(dex_info.get("priceChange", {}).get("h6", 0) or 0) |
| price_change_24h = float(dex_info.get("priceChange", {}).get("h24", 0) or 0) |
| volume_24h = float(dex_info.get("volume", {}).get("h24", 0) or 0) |
|
|
| result["current_state"] = { |
| "price_usd": price_usd, |
| "liquidity_usd": liquidity, |
| "market_cap_usd": mcap, |
| "price_change_5m_pct": price_change_5m, |
| "price_change_1h_pct": price_change_1h, |
| "price_change_6h_pct": price_change_6h, |
| "price_change_24h_pct": price_change_24h, |
| "volume_24h_usd": volume_24h, |
| "timestamp": datetime.now(UTC).isoformat(), |
| } |
|
|
| alerts = [] |
|
|
| |
| if price_change_1h < -20: |
| alerts.append( |
| { |
| "severity": "CRITICAL", |
| "type": "PRICE_CRASH", |
| "message": f"Price dropped {price_change_1h:.1f}% in the last hour β possible rug or sell-off", |
| } |
| ) |
| elif price_change_1h < -10: |
| alerts.append( |
| { |
| "severity": "HIGH", |
| "type": "PRICE_DROP", |
| "message": f"Price down {price_change_1h:.1f}% in 1 hour", |
| } |
| ) |
|
|
| |
| if liquidity < 5000: |
| alerts.append( |
| { |
| "severity": "CRITICAL", |
| "type": "LOW_LIQUIDITY", |
| "message": f"Liquidity critically low: ${liquidity:,.0f}", |
| } |
| ) |
|
|
| |
| if volume_24h > 0 and liquidity > 0 and volume_24h / liquidity > 5: |
| alerts.append( |
| { |
| "severity": "MEDIUM", |
| "type": "HIGH_VOLUME_RATIO", |
| "message": f"24h volume is {volume_24h / liquidity:.1f}x the liquidity", |
| } |
| ) |
|
|
| |
| if abs(price_change_5m) > 10: |
| direction = "surge" if price_change_5m > 0 else "drop" |
| alerts.append( |
| { |
| "severity": "HIGH", |
| "type": "RAPID_MOVE", |
| "message": f"Price {direction}d {abs(price_change_5m):.1f}% in 5 minutes", |
| } |
| ) |
|
|
| |
| if price_change_24h < -30: |
| result["overall_trend"] = "DUMPING" |
| elif price_change_24h < -10: |
| result["overall_trend"] = "DECLINING" |
| elif price_change_24h > 30: |
| result["overall_trend"] = "PUMPING" |
| elif price_change_24h > 10: |
| result["overall_trend"] = "RISING" |
| else: |
| result["overall_trend"] = "STABLE" |
|
|
| result["alerts"] = alerts |
| return result |
|
|
|
|
| |
| |
| |
|
|
|
|
| async def cross_chain_identity(address: str, chain: str = "sol") -> dict[str, Any]: |
| """ |
| Same entity, multiple chains. Detect deployer patterns, funding correlation, |
| simultaneous launches, shared wallet infrastructure. |
| """ |
| result = { |
| "address": address, |
| "source_chain": chain, |
| "cross_chain_profiles": [], |
| "linked_addresses": [], |
| "shared_patterns": [], |
| "risk_flags": [], |
| "identity_confidence": 0, |
| "verdict": "UNKNOWN", |
| } |
|
|
| profiles = [] |
| linked = [] |
| flags = [] |
|
|
| |
| dex_info = await client.dexscreener(chain, address) |
|
|
| |
| token_symbol = "" |
| if "error" not in dex_info: |
| dex_info.get("baseToken", {}).get("name", "") or dex_info.get("pairAddress", "") |
| token_symbol = dex_info.get("baseToken", {}).get("symbol", "") or "" |
|
|
| |
| if token_symbol: |
| try: |
| resp = await client.http.get(f"https://api.dexscreener.com/latest/dex/search?q={token_symbol}") |
| if resp.status_code == 200: |
| search_data = resp.json() |
| pairs = search_data.get("pairs") or [] |
| for pair in pairs[:20]: |
| pair_chain = pair.get("chainId", "") |
| if pair_chain != chain and pair_chain in cfg.CHAIN_DEXSCREENER_MAP.values(): |
| profiles.append( |
| { |
| "chain": pair_chain, |
| "address": pair.get("baseToken", {}).get("address", ""), |
| "name": pair.get("baseToken", {}).get("name", ""), |
| "symbol": pair.get("baseToken", {}).get("symbol", ""), |
| "price_usd": pair.get("priceUsd", ""), |
| "liquidity_usd": pair.get("liquidity", {}).get("usd", 0) |
| if pair.get("liquidity") |
| else 0, |
| "volume_24h_usd": pair.get("volume", {}).get("h24", 0) if pair.get("volume") else 0, |
| "pair_created": pair.get("pairCreatedAt", ""), |
| } |
| ) |
| except Exception as e: |
| logger.warning(f"Cross-chain search failed: {e}") |
|
|
| |
| if len(profiles) >= 3: |
| flags.append(f"Same symbol found on {len(profiles)} chains β possible coordinated multi-chain scam") |
| elif len(profiles) >= 2: |
| flags.append(f"Token exists on {len(profiles)} chains β verify they're the same team") |
|
|
| result["cross_chain_profiles"] = profiles |
| result["linked_addresses"] = linked |
| result["shared_patterns"] = [] |
| result["risk_flags"] = flags |
| result["identity_confidence"] = min(len(profiles) * 25, 100) |
| result["verdict"] = ( |
| "MULTI_CHAIN_ENTITY" if len(profiles) >= 3 else "POSSIBLE_DUPLICATE" if len(profiles) >= 1 else "SINGLE_CHAIN" |
| ) |
|
|
| return result |
|
|
|
|
| |
| |
| |
|
|
|
|
| async def social_onchain_correlation(token_address: str, chain: str = "sol") -> dict[str, Any]: |
| """ |
| Map hype cycle: wallet activity spikes correlated with social mentions. |
| Influencer wallet tracking. Coordinated pump timing. |
| """ |
| result = { |
| "token": token_address, |
| "chain": chain, |
| "social_signals": {}, |
| "onchain_activity": {}, |
| "correlation": {}, |
| "flags": [], |
| "verdict": "UNKNOWN", |
| } |
|
|
| |
| dex_info = await client.dexscreener(chain, token_address) |
| if "error" in dex_info: |
| result["flags"].append("Could not fetch token data") |
| return result |
|
|
| |
| volume_24h = float(dex_info.get("volume", {}).get("h24", 0) or 0) |
| volume_6h = float(dex_info.get("volume", {}).get("h6", 0) or 0) |
| price_change_24h = float(dex_info.get("priceChange", {}).get("h24", 0) or 0) |
| price_change_6h = float(dex_info.get("priceChange", {}).get("h6", 0) or 0) |
| mcap = float(dex_info.get("marketCap", 0) or 0) |
| liquidity = float(dex_info.get("liquidity", {}).get("usd", 0) or 0) |
|
|
| |
| info = dex_info.get("info", {}) or {} |
| socials = info.get("socials", []) if isinstance(info, dict) else [] |
|
|
| |
| social_data = { |
| "has_website": bool(info.get("websites")) if isinstance(info, dict) and info.get("websites") else False, |
| "social_count": len(socials), |
| "socials": socials, |
| "description": info.get("description", "") if isinstance(info, dict) else "", |
| } |
|
|
| |
| flags = [] |
| correlation_score = 0 |
|
|
| |
| if price_change_24h > 100 and volume_24h > mcap * 0.5: |
| correlation_score += 20 |
| flags.append("Massive price spike with volume exceeding 50% of market cap β possible coordinated pump") |
|
|
| if price_change_6h > 50 and volume_6h > volume_24h * 0.5: |
| correlation_score += 15 |
| flags.append("Recent 6h volume spike suggests coordinated buying") |
|
|
| if mcap > 0 and volume_24h / max(mcap, 1) > 2: |
| correlation_score += 10 |
| flags.append("Volume-to-mcap ratio exceeds 2x β extreme activity for size") |
|
|
| |
| if social_data["social_count"] == 0: |
| correlation_score += 15 |
| flags.append("No social links found β possible anonymous/scam project") |
|
|
| result["social_signals"] = social_data |
| result["onchain_activity"] = { |
| "volume_24h_usd": volume_24h, |
| "volume_6h_usd": volume_6h, |
| "price_change_24h_pct": price_change_24h, |
| "price_change_6h_pct": price_change_6h, |
| "market_cap_usd": mcap, |
| "liquidity_usd": liquidity, |
| "volume_to_mcap_ratio": round(volume_24h / max(mcap, 1), 2), |
| } |
| result["correlation"] = { |
| "correlation_score": correlation_score, |
| "pump_likelihood": "HIGH" if correlation_score >= 40 else "MEDIUM" if correlation_score >= 20 else "LOW", |
| } |
| result["flags"] = flags |
| result["verdict"] = ( |
| "COORDINATED_PUMP" |
| if correlation_score >= 40 |
| else "SUSPICIOUS_ACTIVITY" |
| if correlation_score >= 20 |
| else "NORMAL" |
| ) |
|
|
| return result |
|
|
|
|
| |
| |
| |
|
|
|
|
| async def threat_intel_check(address: str, chain: str = "sol") -> dict[str, Any]: |
| """ |
| Aggregate on-chain threat intelligence from GoPlus, Webacy, and Chainabuse. |
| """ |
| result = { |
| "address": address, |
| "chain": chain, |
| "goplus": None, |
| "webacy": None, |
| "chainabuse": None, |
| "risk_flags": [], |
| "risk_score": 0, |
| "verdict": "UNKNOWN", |
| } |
|
|
| flags = [] |
| score = 0 |
|
|
| |
| goplus_data = await client.goplus_get(chain, address) |
| if "error" not in goplus_data: |
| result["goplus"] = goplus_data |
| |
| token_data = goplus_data.get("result", {}).get(address.lower(), {}) |
| if token_data: |
| if token_data.get("is_honeypot") == "1": |
| flags.append("GoPlus: Honeypot detected") |
| score += 40 |
| if token_data.get("is_mintable") == "1": |
| flags.append("GoPlus: Token is mintable") |
| score += 15 |
| if token_data.get("is_proxy") == "1": |
| flags.append("GoPlus: Proxy contract detected") |
| score += 10 |
| if token_data.get("owner_change_balance") == "1": |
| flags.append("GoPlus: Owner can change balance") |
| score += 20 |
|
|
| |
| webacy_data = await client.webacy_get(chain, address) |
| if "error" not in webacy_data: |
| result["webacy"] = webacy_data |
| |
| if isinstance(webacy_data, dict): |
| risk_score = webacy_data.get("risk_score", 0) |
| if risk_score > 50: |
| flags.append(f"Webacy: High risk score ({risk_score})") |
| score += 20 |
|
|
| |
| chainabuse_data = await client.chainabuse_get(address) |
| if "error" not in chainabuse_data: |
| result["chainabuse"] = chainabuse_data |
| reports = chainabuse_data.get("reports", []) |
| if isinstance(reports, list) and len(reports) > 0: |
| flags.append(f"Chainabuse: {len(reports)} abuse report(s) found") |
| score += 30 |
|
|
| result["risk_flags"] = flags |
| result["risk_score"] = min(score, 100) |
| result["verdict"] = ( |
| "CRITICAL" if score >= 60 else "HIGH_RISK" if score >= 40 else "SUSPICIOUS" if score >= 20 else "CLEAN" |
| ) |
|
|
| return result |
|
|
|
|
| |
| |
| |
|
|
|
|
| async def full_deep_intel(token_address: str, chain: str = "sol", wallet: str | None = None) -> dict[str, Any]: |
| """ |
| Run ALL 12 features and produce a composite deep intelligence report. |
| """ |
| logger.info(f"Running full deep intel for {token_address} on {chain}") |
|
|
| |
| [ |
| deployer_reputation(token_address, chain), |
| preflight_simulate(token_address, wallet or "0x0000000000000000000000000000000000000000", 100, chain), |
| liquidity_lock_authenticity(token_address, chain), |
| volume_authenticity(token_address, chain), |
| slow_rug_detector(token_address, chain), |
| funding_source_tracer(token_address, chain), |
| ownership_theater_detector(token_address, chain), |
| exit_liquidity_calculator(token_address, 1000, chain), |
| token_lifespan_predictor(token_address, chain), |
| post_purchase_monitor(token_address, chain), |
| cross_chain_identity(token_address, chain), |
| social_onchain_correlation(token_address, chain), |
| threat_intel_check(token_address, chain), |
| ] |
|
|
| feature_names = [ |
| "deployer_reputation", |
| "preflight_simulation", |
| "liquidity_lock_authenticity", |
| "volume_authenticity", |
| "slow_rug_detector", |
| "funding_source_tracer", |
| "ownership_theater", |
| "exit_liquidity", |
| "lifespan_predictor", |
| "post_purchase_monitor", |
| "cross_chain_identity", |
| "social_onchain_correlation", |
| "threat_intel_check", |
| ] |
|
|
| report = { |
| "token": token_address, |
| "chain": chain, |
| "timestamp": datetime.now(UTC).isoformat(), |
| "features": {}, |
| "composite_score": 0, |
| "composite_risk_level": "UNKNOWN", |
| "summary": "", |
| "top_flags": [], |
| } |
|
|
| all_flags = [] |
| scores = [] |
|
|
| for name, result in zip(feature_names, results, strict=False): |
| if isinstance(result, Exception): |
| report["features"][name] = {"error": str(result)} |
| else: |
| report["features"][name] = result |
|
|
| |
| if name == "deployer_reputation" and "risk_score" in result: |
| scores.append(result["risk_score"]) |
| elif name == "volume_authenticity" and "wash_score" in result: |
| scores.append(result["wash_score"]) |
| elif name == "slow_rug_detector" and "slow_rug_score" in result: |
| scores.append(result["slow_rug_score"]) |
| elif name == "ownership_theater" and "theater_score" in result: |
| scores.append(result["theater_score"]) |
| elif name == "lifespan_predictor" and "rug_probability_pct" in result: |
| scores.append(result["rug_probability_pct"]) |
|
|
| |
| for flag_key in ["flag_details", "flags", "risk_flags", "patterns", "alerts"]: |
| if flag_key in result: |
| items = result[flag_key] |
| if isinstance(items, list): |
| for item in items: |
| if isinstance(item, dict): |
| all_flags.append(item.get("message", str(item))) |
| else: |
| all_flags.append(str(item)) |
|
|
| |
| composite = sum(scores) / max(len(scores), 1) if scores else 0 |
| report["composite_score"] = round(composite, 1) |
| report["composite_risk_level"] = ( |
| "EXTREME_DANGER" |
| if composite >= 80 |
| else "HIGH_RISK" |
| if composite >= 60 |
| else "ELEVATED_RISK" |
| if composite >= 40 |
| else "MODERATE" |
| if composite >= 25 |
| else "LOW_RISK" |
| if composite >= 10 |
| else "SAFE" |
| ) |
|
|
| |
| unique_flags = list(dict.fromkeys(all_flags))[:10] |
| report["top_flags"] = unique_flags |
| report["summary"] = ( |
| f"Composite risk: {composite:.0f}/100. {len(unique_flags)} flag(s) detected across 12 intelligence modules." |
| ) |
|
|
| return report |
|
|