#!/usr/bin/env python3
"""PROPOSED, read-only. Not deployed. Ben 5 Oct 2026.

family_check.py <token>  ->  launch family + honeypot probe, in a few seconds, from the public RPC.

Why: in 46k Robinhood Chain launches (15 Sep to 4 Oct 2026) two hook code families made most coins that hit
a sellable $2M within 6 hours. Both are operations, not organic runners:
  CAMPAIGN_WETH  hook code 5059 bytes, md5 7adb2ec7 (WETH quote, fee 3000). 64 launches, ~3/day.
                 99.6 to 99.9% of swaps go through one private router per coin. Wallets that bought through normal
                 routers never sold through them (PANDAKEY: 61 buys, 0 sells in 24 h). Treat as UNSELLABLE.
  BUNDLE_ETH     hook code 341 bytes, md5 6de2bb44 (native ETH, fee 2500 or 0, start ~$2.4k).
                 140 launches, ~7/day. Launch tx itself buys through ~40 wallets (~$27k in 2 s). Public trading
                 works (outside sells exist). From a 30 s entry: median 2.5x, top quarter 4.9x, peak ~14 min.
Price Predict's `pad` reads the hook of the mint_to pool, which for CAMPAIGN_WETH has no hook, so its model
cannot see this family today. Check every pool of the token instead.
"""
import json, sys, hashlib, urllib.request, collections

RPC = 'https://rpc.mainnet.chain.robinhood.com'
UA = 'Mozilla/5.0 (Macintosh) Chrome/128'
PM = '0x8366a39cc670b4001a1121b8f6a443a643e40951'
INIT = '0xdd466e674ea557f56295e2d0218a125ea4b4f0f6f3307b95f85e6110838d6438'
SWAP = '0x40e9cecb9f5f1f1c5b9c97dec2917b7ee92e57ba5563708daca94dd84ad7112f'
# public routers seen across many pools (2 Oct 2026 sample: 0x8876 traded 95 pools in 5 min)
PUBLIC_ROUTERS = {'0x8876789976decbfcbbbe364623c63652db8c0904', '0x6aa80dbbed9ae5ab45fbf61f9644fada3b29326e',
                  '0x8f10b468b06c6fd214b65f87778827f7d113f996', '0x204faca1764b154221e35c0d20abb3c525710498',
                  '0x36dc95f1f088e11c0066dc19173f745655002bc2', '0x65050a9b7e5075a2ba5ced7b1b64ee66262c40dc',
                  '0xec9aa0a6c2372131a0502aba6188269ab52cacb5', '0x0005ea38eb0a69d1253508ebdbdb9ea8cb26b5ef'}
FAMILIES = {'5059_7adb2ec7': 'CAMPAIGN_WETH', '341_6de2bb44': 'BUNDLE_ETH'}

def rpc(m, p, tries=6):
    import time
    for i in range(tries):
        try:
            r = json.loads(urllib.request.urlopen(urllib.request.Request(RPC, json.dumps(dict(jsonrpc='2.0', id=1, method=m, params=p)).encode(),
                                                                         {'Content-Type': 'application/json', 'User-Agent': UA}), timeout=30).read())
        except Exception as e:                 # 429 / timeouts: back off, never hammer the public RPC
            if i == tries - 1: raise
            time.sleep(4 * (i + 1)); continue
        if 'error' in r: raise RuntimeError(r['error'])
        return r['result']

def s128(h):
    v = int(h, 16); return v - (1 << 256) if v >> 255 else v

def pools_of(token, from_block):
    tpad = '0x' + '0' * 24 + token[2:].lower()
    out = []
    for pos in (2, 3):   # token as currency0 (topic2) or currency1 (topic3)
        topics = [INIT, None, None, None]; topics[pos] = tpad
        for lg in rpc('eth_getLogs', [{'address': PM, 'topics': topics[:pos + 1], 'fromBlock': hex(from_block), 'toBlock': 'latest'}]):
            w = lg['data'][2:]; ws = [w[i:i + 64] for i in range(0, len(w), 64)]
            out.append(dict(pool=lg['topics'][1], c0='0x' + lg['topics'][2][-40:], c1='0x' + lg['topics'][3][-40:],
                            fee=int(ws[0], 16), hook='0x' + ws[2][-40:], block=int(lg['blockNumber'], 16)))
    return out

def code_family(addr):
    if int(addr, 16) == 0: return 'none'
    c = rpc('eth_getCode', [addr, 'latest'])
    return '%d_%s' % (len(c) // 2 - 1, hashlib.md5(c.encode()).hexdigest()[:8])   # same fingerprint as the study

def sell_probe(pool, token_is_c0, from_block):
    """count buys/sells per router; honeypot suspect = public routers buy but never sell"""
    head = int(rpc('eth_blockNumber', []), 16); logs = []; b = from_block; step = 8000
    while b <= min(head, from_block + 72_000) and len(logs) < 3000:      # first ~2 h of the pool, max 3000 swaps
        try:
            logs += rpc('eth_getLogs', [{'address': PM, 'topics': [SWAP, pool], 'fromBlock': hex(b), 'toBlock': hex(b + step - 1)}]); b += step
        except RuntimeError as e:
            if 'exceeds' in str(e) and step > 250: step //= 4; continue
            raise
    by = collections.defaultdict(lambda: [0, 0])
    for lg in logs:
        d = lg['data'][2:]; a0, a1 = s128(d[:64]), s128(d[64:128])
        quote_to_user = (a1 if token_is_c0 else a0) > 0          # v4 amounts are user side: >0 user received
        by['0x' + lg['topics'][2][-40:]][1 if quote_to_user else 0] += 1
    pub_b = sum(v[0] for r, v in by.items() if r in PUBLIC_ROUTERS); pub_s = sum(v[1] for r, v in by.items() if r in PUBLIC_ROUTERS)
    top = max(by.items(), key=lambda kv: sum(kv[1]))[0] if by else None
    share = sum(by[top]) / max(1, len(logs)) if top else 0
    return dict(swaps=len(logs), public_buys=pub_b, public_sells=pub_s, top_router=top, top_router_share=round(share, 3),
                honeypot_suspect=pub_b >= 10 and pub_s == 0)

if __name__ == '__main__':
    tok = sys.argv[1].lower()
    head = int(rpc('eth_blockNumber', []), 16)
    ps = pools_of(tok, max(0, head - 3_000_000))          # ~3.5 days back; widen for older tokens
    res = []
    for p in ps:
        fam = code_family(p['hook'])
        r = dict(p, hook_family=fam, family=FAMILIES.get(fam, 'organic/unknown'))
        r.update(sell_probe(p['pool'], p['c0'] == tok, p['block']))
        res.append(r)
    verdict = 'AVOID: campaign family, outsiders cannot sell via normal apps' if any(r['family'] == 'CAMPAIGN_WETH' or r['honeypot_suspect'] for r in res) \
        else 'FAST FLIP ONLY: bundled launch' if any(r['family'] == 'BUNDLE_ETH' for r in res) else 'no known operation family'
    print(json.dumps(dict(token=tok, verdict=verdict, pools=res), indent=1))
