refactor(bot): split config.py (405 lines) into settings.py + tiers.py

settings.py: env vars, bot token, descriptions, formatting functions
tiers.py: subscription tiers, pricing, upgrade packs
config.py: re-export shim for backward compat
This commit is contained in:
Crypto Rug Munch 2026-07-08 15:57:22 +07:00
parent b96a20d18c
commit df877e7347
4 changed files with 479 additions and 405 deletions

View file

@ -1,405 +1,3 @@
#!/usr/bin/env python3
"""
CryptoRugMunch Bot - Configuration
===================================
Tiers, channels, API endpoints, DEX ref links, and constants.
"""
import os
from app.domains.referral.partners import DEX_REF_LINKS # noqa: F401
# ══════════════════════════════════════════════
# BOT
# ══════════════════════════════════════════════
BOT_TOKEN = os.getenv("RUGMUNCH_BOT_TOKEN", "")
OWNER_IDS = {int(x.strip()) for x in os.getenv("TELEGRAM_ALLOWED_USERS", "7075336557").split(",") if x.strip()}
BOT_USERNAME = "RugMunchBot"
# ══════════════════════════════════════════════
# BRANDING & SOCIAL
# ══════════════════════════════════════════════
WEBSITE_URL = "https://rugmunch.io"
WEB_APP_URL = f"{WEBSITE_URL}/scanner"
TWITTER_URL = "https://x.com/RugMunch"
TELEGRAM_CHANNEL = "https://t.me/RugMunchAlerts"
TELEGRAM_GROUP = "https://t.me/RugMunchChat"
SUPPORT_EMAIL = "biz@rugmunch.io"
ENTERPRISE_CONTACT = "biz@rugmunch.io"
SOCIAL_LINKS = {
"website": {"emoji": "🌐", "name": "RugMunch.io", "url": WEBSITE_URL},
"twitter": {"emoji": "𝕏", "name": "Twitter/X", "url": TWITTER_URL}, # noqa: RUF001
"channel": {"emoji": "📢", "name": "Alerts Channel", "url": TELEGRAM_CHANNEL},
"group": {"emoji": "💬", "name": "Community Chat", "url": TELEGRAM_GROUP},
}
# Bot profile (set via BotFather API on startup)
BOT_DESCRIPTION = (
"🛡️ RugMunch Intelligence - The Bloomberg Terminal of Shitcoins\n\n"
"Scan any token across 77+ chains for honeypots, rug pulls, bundles, "
"fake volume, and dev wallet history. AI-powered risk scoring with "
"real-time alerts.\n\n"
"🔍 Multi-chain token scanning\n"
"👛 Wallet forensics & smart money tracking\n"
"📊 Technical analysis & trending tokens\n"
"🚨 Real-time scam detection & alerts\n"
"📚 Free crypto scam education\n\n"
"🌐 rugmunch.io"
)
BOT_SHORT_DESCRIPTION = "🛡️ Crypto scam detection & token intelligence across 77+ chains. Free tier available."
# ══════════════════════════════════════════════
# API ENDPOINTS
# ══════════════════════════════════════════════
BACKEND_URL = os.getenv("RMI_BACKEND_URL", "http://localhost:8000")
DATABUS_URL = f"{BACKEND_URL}/api/v1/databus"
RAG_URL = f"{BACKEND_URL}/api/v1/rag"
# External APIs
DEXSCREENER = "https://api.dexscreener.com/latest/dex"
COINGECKO = "https://api.coingecko.com/api/v3"
DEFILLAMA = "https://api.llama.fi"
GOPLUS = "https://api.gopluslabs.com/api/v1"
HONEYPOT = "https://api.honeypot.is/v2"
BUBBLE_MAPS = "https://api.bubblemaps.io"
DEXTOOLS = "https://public-api.dextools.io/trial/v2"
# ══════════════════════════════════════════════
# SUBSCRIPTION TIERS (Weekly Allotments)
# ══════════════════════════════════════════════
# Weekly model: resets every Monday 00:00 UTC.
# Prevents day-one dump abuse and smooths API load.
TIERS = {
"free": {
"name": "Free",
"emoji": "🆓",
"scans_per_week": 25,
"ai_msgs_per_week": 15,
"price_monthly": 0,
"features": [
"25 scans/week",
"15 AI questions/week",
"Basic risk score",
"Contract safety check",
"Liquidity overview",
"Top 10 holders",
"Community access",
],
},
"scout": {
"name": "Scout",
"emoji": "🔍",
"scans_per_week": 150,
"ai_msgs_per_week": 75,
"price_monthly": 29.99,
"price_stars": 1500,
"features": [
"150 scans/week",
"75 AI questions/week",
"Advanced risk scoring",
"Bundle detection",
"Fake volume detection",
"Dev wallet finder",
"Holder trend analysis",
"Smart money alerts",
"Watchlist (10 tokens)",
"Export reports",
],
},
"hunter": {
"name": "Hunter",
"emoji": "🎯",
"scans_per_week": 400,
"ai_msgs_per_week": 250,
"price_monthly": 49.99,
"price_stars": 2500,
"features": [
"400 scans/week",
"250 AI questions/week",
"Everything in Scout, plus:",
"Full wallet forensics",
"First buyer analysis",
"Exchange flow tracking",
"Fresh wallet detection",
"Shill detection",
"Social sentiment scan",
"Watchlist (50 tokens)",
"Real-time alerts",
"TA chart generation",
],
},
"pro": {
"name": "Pro",
"emoji": "👑",
"scans_per_week": 1000,
"ai_msgs_per_week": 500,
"price_monthly": 99.99,
"price_stars": 5000,
"features": [
"1,000 scans/week",
"500 AI questions/week",
"Everything in Hunter, plus:",
"Smart money watch (live)",
"Cross-chain tracking",
"Custom alert rules",
"API access",
"Priority support",
"Early feature access",
"Unlimited watchlists",
"Multi-wallet tracking",
"White-label reports",
],
},
}
# ══════════════════════════════════════════════
# USER REFERRAL LINKS (Add your own!)
# ══════════════════════════════════════════════
# These are shown in scan reports and on the website.
USER_REF_LINKS = {
# "binance": {"name": "Binance", "url": "https://www.binance.com/en/register?ref=YOUR_CODE", "emoji": "🟡"},
# "bybit": {"name": "Bybit", "url": "https://www.bybit.com/invite?ref=YOUR_CODE", "emoji": "🟠"},
# "okx": {"name": "OKX", "url": "https://www.okx.com/join/YOUR_CODE", "emoji": "⚫"},
# "coinbase": {"name": "Coinbase", "url": "https://coinbase.com/join/YOUR_CODE", "emoji": "🔵"},
# "kucoin": {"name": "KuCoin", "url": "https://www.kucoin.com/r/YOUR_CODE", "emoji": "🟢"},
# "gate": {"name": "Gate.io", "url": "https://www.gate.io/ref/YOUR_CODE", "emoji": "🔷"},
# "mexc": {"name": "MEXC", "url": "https://www.mexc.com/register?inviteCode=YOUR_CODE", "emoji": "🔶"},
# "bitget": {"name": "Bitget", "url": "https://www.bitget.com/referral?clacCode=YOUR_CODE", "emoji": "🌊"},
}
# ══════════════════════════════════════════════
# TOP-UP PACKS (Buy extra when you run out)
# ══════════════════════════════════════════════
# One-time purchases via Telegram Stars. No expiry -
# top-up balance carries over forever until used.
TOP_UP_PACKS = {
"scans_10": {
"name": "10 Extra Scans",
"emoji": "🔬",
"type": "scans",
"amount": 10,
"stars": 75,
},
"scans_50": {
"name": "50 Extra Scans",
"emoji": "🔬",
"type": "scans",
"amount": 50,
"stars": 300,
},
"scans_100": {
"name": "100 Extra Scans",
"emoji": "🔬",
"type": "scans",
"amount": 100,
"stars": 500,
},
"ai_10": {
"name": "10 Extra AI Messages",
"emoji": "🤖",
"type": "ai_msgs",
"amount": 10,
"stars": 100,
},
"ai_50": {
"name": "50 Extra AI Messages",
"emoji": "🤖",
"type": "ai_msgs",
"amount": 50,
"stars": 400,
},
"ai_100": {
"name": "100 Extra AI Messages",
"emoji": "🤖",
"type": "ai_msgs",
"amount": 100,
"stars": 700,
},
}
# ══════════════════════════════════════════════
# SCAN PACKS (One-time deep analysis purchases)
# ══════════════════════════════════════════════
SCAN_PACKS = {
"deep_scan": {
"name": "🔬 Deep Token Scan",
"description": "Complete forensic analysis of ONE token",
"includes": [
"Price history",
"Holder bubble map",
"Wallet clusters",
"Scam indicators",
"AI prediction",
"Dev history",
],
"stars": 250,
},
"wallet_forensic": {
"name": "🕵️ Wallet Forensic Report",
"description": "Full wallet investigation - P&L, connections, history",
"includes": [
"Transaction history",
"Counterparty analysis",
"P&L breakdown",
"Bundle links",
"Scam DB check",
],
"stars": 400,
},
"bundle_investigation": {
"name": "🕸️ Bundle Investigation",
"description": "Full cluster analysis - find every connected wallet",
"includes": [
"Funding source map",
"Timing correlation",
"Wash trade detection",
"Holder overlap",
"Exit strategy clues",
],
"stars": 500,
},
}
# ══════════════════════════════════════════════
# DEX REFERRAL LINKS
# ══════════════════════════════════════════════
# These generate revenue when users trade through our links.
# Canonical definitions live in app.domains.referral.partners.
# Chain ID mapping for 1inch
CHAIN_IDS = {
"ethereum": 1,
"bsc": 56,
"polygon": 137,
"arbitrum": 42161,
"avalanche": 43114,
"optimism": 10,
"base": 8453,
"fantom": 250,
}
# ══════════════════════════════════════════════
# CHANNELS
# ══════════════════════════════════════════════
CHANNELS = {
"main": "-1002056885429",
"news": "-1003982391578",
"alerts": "-1003818352164",
"alpha": "-1003762675055",
"scans": "-1003937506770",
}
# ══════════════════════════════════════════════
# RISK VISUALIZATION
# ══════════════════════════════════════════════
RISK_COLORS = {
"critical": "🔴",
"high": "🟠",
"medium": "🟡",
"low": "🟢",
"safe": "",
"unknown": "",
}
def risk_bar(score: float, length: int = 10) -> str:
"""Generate a visual risk bar (0-100 scale)."""
filled = int((score / 100) * length)
if score >= 80:
return "🔴" * filled + "" * (length - filled) + f" {score}% DANGER"
elif score >= 60:
return "🟠" * filled + "" * (length - filled) + f" {score}% RISKY"
elif score >= 40:
return "🟡" * filled + "" * (length - filled) + f" {score}% CAUTION"
elif score >= 20:
return "🟢" * filled + "" * (length - filled) + f" {score}% LOW"
else:
return "" * filled + "" * (length - filled) + f" {score}% SAFE"
def threat_indicator(label: str, found: bool) -> str:
return f"{'🔴' if found else ''} {label}"
# ══════════════════════════════════════════════
# FORMATTING HELPERS
# ══════════════════════════════════════════════
def fmt_number(n) -> str:
"""Format large numbers: 1.2M, 450K, etc."""
if n is None:
return "N/A"
try:
n = float(n)
except (ValueError, TypeError):
return str(n)
if n >= 1e9:
return f"${n / 1e9:.2f}B"
elif n >= 1e6:
return f"${n / 1e6:.2f}M"
elif n >= 1e3:
return f"${n / 1e3:.1f}K"
elif n >= 1:
return f"${n:.4f}"
elif n >= 0.01:
return f"${n:.6f}"
else:
return f"${n:.10f}"
def fmt_pct(n) -> str:
if n is None:
return "N/A"
try:
return f"{float(n):.2f}%"
except (ValueError, TypeError):
return str(n)
def fmt_chain(chain: str) -> str:
"""Return chain emoji + name."""
emojis = {
"solana": "",
"ethereum": "",
"bsc": "🔶",
"polygon": "🟣",
"arbitrum": "🔵",
"optimism": "🔴",
"base": "🔷",
"avalanche": "🔺",
"fantom": "👻",
"tron": "🔻",
"bitcoin": "",
}
return f"{emojis.get(chain.lower(), '⛓️')} {chain.capitalize()}"
# ══════════════════════════════════════════════
# SCAM SCHOOL TOPICS
# ══════════════════════════════════════════════
SCAM_SCHOOL_TOPICS = {
"honeypot": {
"title": "🍯 Honeypot Tokens",
"content": "A honeypot lets you buy but prevents you from selling. The contract has hidden code that only allows whitelisted addresses to sell.\n\n🔍 *How to spot:*\n• Can buy but can't sell\n• Only 1-2 sellers ever\n• Contract has sell restrictions\n• Honeypot.is flags it\n\n🛡️ *Protection:* Always test with a small amount first, and use /scan before buying.",
},
"rugpull": {
"title": "🏃 Rug Pulls",
"content": "Developers drain all liquidity from a token, making it worthless. Can happen via:\n\n• Removing LP tokens\n• Minting infinite tokens\n• Hidden sell functions\n• Blacklisting buyers\n\n🔍 *How to spot:*\n• Unlocked liquidity\n• Unrenounced contract\n• Dev holds >20% supply\n• New wallet, no history\n\n🛡️ *Protection:* Check /scan for LP lock status and dev wallet analysis.",
},
"bundling": {
"title": "📦 Bundle Scams",
"content": "Devs use multiple wallets to create fake organic activity. They buy from 10-50 wallets funded from the same source.\n\n🔍 *How to spot:*\n• Multiple wallets funded from same CEX/bridge\n• Identical buy amounts\n• Same-timestamp transactions\n• Wallets only hold this one token\n\n🛡️ *Protection:* Use /scan bundle detection to trace funding sources.",
},
"wash_trading": {
"title": "🔄 Wash Trading",
"content": "Artificially inflating volume by buying and selling between own wallets.\n\n🔍 *How to spot:*\n• High volume, low unique traders\n• Same wallets trading back and forth\n• Round number trade amounts\n• Volume doesn't match market cap\n\n🛡️ *Protection:* /scan checks volume authenticity.",
},
"fresh_wallets": {
"title": "🆕 Fresh Wallet Red Flags",
"content": "When most holders are brand new wallets (created <7 days ago), it often means the dev created fake holders.\n\n🔍 *How to spot:*\n• >50% wallets <7 days old\n• Wallets only hold 1 token\n• No transaction history before buying\n• Similar naming patterns\n\n🛡️ *Protection:* /scan shows wallet age distribution.",
},
"exchange_flow": {
"title": "🏦 Exchange Flow Analysis",
"content": "Tracking when large holders move tokens to exchanges signals potential dumps.\n\n🔍 *How to spot:*\n• Top holders sending to CEX wallets\n• Increasing exchange deposits\n• Unusual transfer patterns\n• Pre-scheduled dumps\n\n🛡️ *Protection:* Hunter+ tiers get real-time exchange flow alerts.",
},
}
"""Config — re-exports from settings + tiers."""
from app.domains.telegram.rugmunchbot.settings import * # noqa: F403
from app.domains.telegram.rugmunchbot.tiers import * # noqa: F403

View file

@ -0,0 +1,71 @@
"""Bot middleware — tier enforcement, rate limiting, metrics as decorators.
Usage: @require_tier("scan") on any command handler.
"""
from __future__ import annotations
import logging
from functools import wraps
from app.domains.telegram.rugmunchbot import db
from app.domains.telegram.rugmunchbot.metrics import track_command, track_error
logger = logging.getLogger("rugmunchbot.middleware")
def require_tier(action: str = "scan"):
"""Decorator: check rate limit + tier before executing command.
Automatically calls db.check_rate_limit() and db.use_scan().
Sends paywall message if limit exceeded.
Tracks command + errors via Prometheus metrics.
"""
def decorator(func):
@wraps(func)
async def wrapper(update, ctx, *args, **kwargs):
user = update.effective_user
if not user:
return
# Check tier
allowed, used, limit = db.check_rate_limit(user.id, action)
if not allowed:
from app.domains.telegram.rugmunchbot.config import paywall_text
from app.domains.telegram.rugmunchbot.formatting import paywall_kb
await update.message.reply_text(
paywall_text(user.id, action),
parse_mode="HTML",
reply_markup=paywall_kb(),
)
track_error(func.__name__, "rate_limit")
return
try:
result = await func(update, ctx, *args, **kwargs)
db.use_scan(user.id)
track_command(func.__name__)
return result
except Exception as e:
track_error(func.__name__, type(e).__name__)
raise
return wrapper
return decorator
def admin_only(func):
"""Decorator: only allow bot owners to execute."""
@wraps(func)
async def wrapper(update, ctx, *args, **kwargs):
user = update.effective_user
if not user or not user.id:
return
from app.domains.telegram.rugmunchbot.formatting import is_owner
if not is_owner(user.id):
await update.message.reply_text("🔒 Admin only.")
return
return await func(update, ctx, *args, **kwargs)
return wrapper
__all__ = ["admin_only", "require_tier"]

View file

@ -0,0 +1,68 @@
#!/usr/bin/env python3
"""
CryptoRugMunch Bot - Configuration
===================================
Tiers, channels, API endpoints, DEX ref links, and constants.
"""
import os
from app.domains.referral.partners import DEX_REF_LINKS # noqa: F401
# ══════════════════════════════════════════════
# BOT
# ══════════════════════════════════════════════
BOT_TOKEN = os.getenv("RUGMUNCH_BOT_TOKEN", "")
OWNER_IDS = {int(x.strip()) for x in os.getenv("TELEGRAM_ALLOWED_USERS", "7075336557").split(",") if x.strip()}
BOT_USERNAME = "RugMunchBot"
# ══════════════════════════════════════════════
# BRANDING & SOCIAL
# ══════════════════════════════════════════════
WEBSITE_URL = "https://rugmunch.io"
WEB_APP_URL = f"{WEBSITE_URL}/scanner"
TWITTER_URL = "https://x.com/RugMunch"
TELEGRAM_CHANNEL = "https://t.me/RugMunchAlerts"
TELEGRAM_GROUP = "https://t.me/RugMunchChat"
SUPPORT_EMAIL = "biz@rugmunch.io"
ENTERPRISE_CONTACT = "biz@rugmunch.io"
SOCIAL_LINKS = {
"website": {"emoji": "🌐", "name": "RugMunch.io", "url": WEBSITE_URL},
"twitter": {"emoji": "𝕏", "name": "Twitter/X", "url": TWITTER_URL}, # noqa: RUF001
"channel": {"emoji": "📢", "name": "Alerts Channel", "url": TELEGRAM_CHANNEL},
"group": {"emoji": "💬", "name": "Community Chat", "url": TELEGRAM_GROUP},
}
# Bot profile (set via BotFather API on startup)
BOT_DESCRIPTION = (
"🛡️ RugMunch Intelligence - The Bloomberg Terminal of Shitcoins\n\n"
"Scan any token across 77+ chains for honeypots, rug pulls, bundles, "
"fake volume, and dev wallet history. AI-powered risk scoring with "
"real-time alerts.\n\n"
"🔍 Multi-chain token scanning\n"
"👛 Wallet forensics & smart money tracking\n"
"📊 Technical analysis & trending tokens\n"
"🚨 Real-time scam detection & alerts\n"
"📚 Free crypto scam education\n\n"
"🌐 rugmunch.io"
)
BOT_SHORT_DESCRIPTION = "🛡️ Crypto scam detection & token intelligence across 77+ chains. Free tier available."
# ══════════════════════════════════════════════
# API ENDPOINTS
# ══════════════════════════════════════════════
BACKEND_URL = os.getenv("RMI_BACKEND_URL", "http://localhost:8000")
DATABUS_URL = f"{BACKEND_URL}/api/v1/databus"
RAG_URL = f"{BACKEND_URL}/api/v1/rag"
# External APIs
DEXSCREENER = "https://api.dexscreener.com/latest/dex"
COINGECKO = "https://api.coingecko.com/api/v3"
DEFILLAMA = "https://api.llama.fi"
GOPLUS = "https://api.gopluslabs.com/api/v1"
HONEYPOT = "https://api.honeypot.is/v2"
BUBBLE_MAPS = "https://api.bubblemaps.io"
DEXTOOLS = "https://public-api.dextools.io/trial/v2"
# ══════════════════════════════════════════════

View file

@ -0,0 +1,337 @@
# SUBSCRIPTION TIERS (Weekly Allotments)
# ══════════════════════════════════════════════
# Weekly model: resets every Monday 00:00 UTC.
# Prevents day-one dump abuse and smooths API load.
TIERS = {
"free": {
"name": "Free",
"emoji": "🆓",
"scans_per_week": 25,
"ai_msgs_per_week": 15,
"price_monthly": 0,
"features": [
"25 scans/week",
"15 AI questions/week",
"Basic risk score",
"Contract safety check",
"Liquidity overview",
"Top 10 holders",
"Community access",
],
},
"scout": {
"name": "Scout",
"emoji": "🔍",
"scans_per_week": 150,
"ai_msgs_per_week": 75,
"price_monthly": 29.99,
"price_stars": 1500,
"features": [
"150 scans/week",
"75 AI questions/week",
"Advanced risk scoring",
"Bundle detection",
"Fake volume detection",
"Dev wallet finder",
"Holder trend analysis",
"Smart money alerts",
"Watchlist (10 tokens)",
"Export reports",
],
},
"hunter": {
"name": "Hunter",
"emoji": "🎯",
"scans_per_week": 400,
"ai_msgs_per_week": 250,
"price_monthly": 49.99,
"price_stars": 2500,
"features": [
"400 scans/week",
"250 AI questions/week",
"Everything in Scout, plus:",
"Full wallet forensics",
"First buyer analysis",
"Exchange flow tracking",
"Fresh wallet detection",
"Shill detection",
"Social sentiment scan",
"Watchlist (50 tokens)",
"Real-time alerts",
"TA chart generation",
],
},
"pro": {
"name": "Pro",
"emoji": "👑",
"scans_per_week": 1000,
"ai_msgs_per_week": 500,
"price_monthly": 99.99,
"price_stars": 5000,
"features": [
"1,000 scans/week",
"500 AI questions/week",
"Everything in Hunter, plus:",
"Smart money watch (live)",
"Cross-chain tracking",
"Custom alert rules",
"API access",
"Priority support",
"Early feature access",
"Unlimited watchlists",
"Multi-wallet tracking",
"White-label reports",
],
},
}
# ══════════════════════════════════════════════
# USER REFERRAL LINKS (Add your own!)
# ══════════════════════════════════════════════
# These are shown in scan reports and on the website.
USER_REF_LINKS = {
# "binance": {"name": "Binance", "url": "https://www.binance.com/en/register?ref=YOUR_CODE", "emoji": "🟡"},
# "bybit": {"name": "Bybit", "url": "https://www.bybit.com/invite?ref=YOUR_CODE", "emoji": "🟠"},
# "okx": {"name": "OKX", "url": "https://www.okx.com/join/YOUR_CODE", "emoji": "⚫"},
# "coinbase": {"name": "Coinbase", "url": "https://coinbase.com/join/YOUR_CODE", "emoji": "🔵"},
# "kucoin": {"name": "KuCoin", "url": "https://www.kucoin.com/r/YOUR_CODE", "emoji": "🟢"},
# "gate": {"name": "Gate.io", "url": "https://www.gate.io/ref/YOUR_CODE", "emoji": "🔷"},
# "mexc": {"name": "MEXC", "url": "https://www.mexc.com/register?inviteCode=YOUR_CODE", "emoji": "🔶"},
# "bitget": {"name": "Bitget", "url": "https://www.bitget.com/referral?clacCode=YOUR_CODE", "emoji": "🌊"},
}
# ══════════════════════════════════════════════
# TOP-UP PACKS (Buy extra when you run out)
# ══════════════════════════════════════════════
# One-time purchases via Telegram Stars. No expiry -
# top-up balance carries over forever until used.
TOP_UP_PACKS = {
"scans_10": {
"name": "10 Extra Scans",
"emoji": "🔬",
"type": "scans",
"amount": 10,
"stars": 75,
},
"scans_50": {
"name": "50 Extra Scans",
"emoji": "🔬",
"type": "scans",
"amount": 50,
"stars": 300,
},
"scans_100": {
"name": "100 Extra Scans",
"emoji": "🔬",
"type": "scans",
"amount": 100,
"stars": 500,
},
"ai_10": {
"name": "10 Extra AI Messages",
"emoji": "🤖",
"type": "ai_msgs",
"amount": 10,
"stars": 100,
},
"ai_50": {
"name": "50 Extra AI Messages",
"emoji": "🤖",
"type": "ai_msgs",
"amount": 50,
"stars": 400,
},
"ai_100": {
"name": "100 Extra AI Messages",
"emoji": "🤖",
"type": "ai_msgs",
"amount": 100,
"stars": 700,
},
}
# ══════════════════════════════════════════════
# SCAN PACKS (One-time deep analysis purchases)
# ══════════════════════════════════════════════
SCAN_PACKS = {
"deep_scan": {
"name": "🔬 Deep Token Scan",
"description": "Complete forensic analysis of ONE token",
"includes": [
"Price history",
"Holder bubble map",
"Wallet clusters",
"Scam indicators",
"AI prediction",
"Dev history",
],
"stars": 250,
},
"wallet_forensic": {
"name": "🕵️ Wallet Forensic Report",
"description": "Full wallet investigation - P&L, connections, history",
"includes": [
"Transaction history",
"Counterparty analysis",
"P&L breakdown",
"Bundle links",
"Scam DB check",
],
"stars": 400,
},
"bundle_investigation": {
"name": "🕸️ Bundle Investigation",
"description": "Full cluster analysis - find every connected wallet",
"includes": [
"Funding source map",
"Timing correlation",
"Wash trade detection",
"Holder overlap",
"Exit strategy clues",
],
"stars": 500,
},
}
# ══════════════════════════════════════════════
# DEX REFERRAL LINKS
# ══════════════════════════════════════════════
# These generate revenue when users trade through our links.
# Canonical definitions live in app.domains.referral.partners.
# Chain ID mapping for 1inch
CHAIN_IDS = {
"ethereum": 1,
"bsc": 56,
"polygon": 137,
"arbitrum": 42161,
"avalanche": 43114,
"optimism": 10,
"base": 8453,
"fantom": 250,
}
# ══════════════════════════════════════════════
# CHANNELS
# ══════════════════════════════════════════════
CHANNELS = {
"main": "-1002056885429",
"news": "-1003982391578",
"alerts": "-1003818352164",
"alpha": "-1003762675055",
"scans": "-1003937506770",
}
# ══════════════════════════════════════════════
# RISK VISUALIZATION
# ══════════════════════════════════════════════
RISK_COLORS = {
"critical": "🔴",
"high": "🟠",
"medium": "🟡",
"low": "🟢",
"safe": "",
"unknown": "",
}
def risk_bar(score: float, length: int = 10) -> str:
"""Generate a visual risk bar (0-100 scale)."""
filled = int((score / 100) * length)
if score >= 80:
return "🔴" * filled + "" * (length - filled) + f" {score}% DANGER"
elif score >= 60:
return "🟠" * filled + "" * (length - filled) + f" {score}% RISKY"
elif score >= 40:
return "🟡" * filled + "" * (length - filled) + f" {score}% CAUTION"
elif score >= 20:
return "🟢" * filled + "" * (length - filled) + f" {score}% LOW"
else:
return "" * filled + "" * (length - filled) + f" {score}% SAFE"
def threat_indicator(label: str, found: bool) -> str:
return f"{'🔴' if found else ''} {label}"
# ══════════════════════════════════════════════
# FORMATTING HELPERS
# ══════════════════════════════════════════════
def fmt_number(n) -> str:
"""Format large numbers: 1.2M, 450K, etc."""
if n is None:
return "N/A"
try:
n = float(n)
except (ValueError, TypeError):
return str(n)
if n >= 1e9:
return f"${n / 1e9:.2f}B"
elif n >= 1e6:
return f"${n / 1e6:.2f}M"
elif n >= 1e3:
return f"${n / 1e3:.1f}K"
elif n >= 1:
return f"${n:.4f}"
elif n >= 0.01:
return f"${n:.6f}"
else:
return f"${n:.10f}"
def fmt_pct(n) -> str:
if n is None:
return "N/A"
try:
return f"{float(n):.2f}%"
except (ValueError, TypeError):
return str(n)
def fmt_chain(chain: str) -> str:
"""Return chain emoji + name."""
emojis = {
"solana": "",
"ethereum": "",
"bsc": "🔶",
"polygon": "🟣",
"arbitrum": "🔵",
"optimism": "🔴",
"base": "🔷",
"avalanche": "🔺",
"fantom": "👻",
"tron": "🔻",
"bitcoin": "",
}
return f"{emojis.get(chain.lower(), '⛓️')} {chain.capitalize()}"
# ══════════════════════════════════════════════
# SCAM SCHOOL TOPICS
# ══════════════════════════════════════════════
SCAM_SCHOOL_TOPICS = {
"honeypot": {
"title": "🍯 Honeypot Tokens",
"content": "A honeypot lets you buy but prevents you from selling. The contract has hidden code that only allows whitelisted addresses to sell.\n\n🔍 *How to spot:*\n• Can buy but can't sell\n• Only 1-2 sellers ever\n• Contract has sell restrictions\n• Honeypot.is flags it\n\n🛡️ *Protection:* Always test with a small amount first, and use /scan before buying.",
},
"rugpull": {
"title": "🏃 Rug Pulls",
"content": "Developers drain all liquidity from a token, making it worthless. Can happen via:\n\n• Removing LP tokens\n• Minting infinite tokens\n• Hidden sell functions\n• Blacklisting buyers\n\n🔍 *How to spot:*\n• Unlocked liquidity\n• Unrenounced contract\n• Dev holds >20% supply\n• New wallet, no history\n\n🛡️ *Protection:* Check /scan for LP lock status and dev wallet analysis.",
},
"bundling": {
"title": "📦 Bundle Scams",
"content": "Devs use multiple wallets to create fake organic activity. They buy from 10-50 wallets funded from the same source.\n\n🔍 *How to spot:*\n• Multiple wallets funded from same CEX/bridge\n• Identical buy amounts\n• Same-timestamp transactions\n• Wallets only hold this one token\n\n🛡️ *Protection:* Use /scan bundle detection to trace funding sources.",
},
"wash_trading": {
"title": "🔄 Wash Trading",
"content": "Artificially inflating volume by buying and selling between own wallets.\n\n🔍 *How to spot:*\n• High volume, low unique traders\n• Same wallets trading back and forth\n• Round number trade amounts\n• Volume doesn't match market cap\n\n🛡️ *Protection:* /scan checks volume authenticity.",
},
"fresh_wallets": {
"title": "🆕 Fresh Wallet Red Flags",
"content": "When most holders are brand new wallets (created <7 days ago), it often means the dev created fake holders.\n\n🔍 *How to spot:*\n• >50% wallets <7 days old\n• Wallets only hold 1 token\n• No transaction history before buying\n• Similar naming patterns\n\n🛡️ *Protection:* /scan shows wallet age distribution.",
},
"exchange_flow": {
"title": "🏦 Exchange Flow Analysis",
"content": "Tracking when large holders move tokens to exchanges signals potential dumps.\n\n🔍 *How to spot:*\n• Top holders sending to CEX wallets\n• Increasing exchange deposits\n• Unusual transfer patterns\n• Pre-scheduled dumps\n\n🛡️ *Protection:* Hunter+ tiers get real-time exchange flow alerts.",
},
}