#!/usr/bin/env python3
"""Check Ben's memecoin book against his exit ladder. No API key needed."""
import urllib.request, json, time, sys

LADDER = {
 # name: (contract, baseline_mcap_at_ladder_set, chain)
 'UTYA':      ('EQBaCgUwOoc6gHCNln_oJzb0mVs79YG7wYoavh-o1ItaneLA', 47_450_161, 'ton'),
 'TROLL':     ('5UUH9RTDiSpq6HKS6bp4NdU9PNJpXRXuiw6ShBTBhgH2',      57_032_477, 'solana'),
 'WOJAK':     ('0x8De39B057CC6522230AB19C0205080a8663331Ef',        21_614_732, 'ethereum'),
 'CUPSEY':    ('6NwarBvDkXhByqVp2Qkq5i9XbtA2B3Bwe8SWGu9vpump',      14_928_241, 'solana'),
 'CHONKETHA': ('HcfnJxLov6tY8i1dq9uYRRZKCvxADPpovcfkyXzdpump',       7_945_682, 'solana'),
 'CHERRY':    ('EQBKRSNRkeP1-2jcg5T_f__0s5Hj-vrbfNLMQy8dnZs7xd_p',   2_158_834, 'ton'),
 'LAYOOO':    ('9sfCHMLWSVy6MD6zr7pR1gD3qbT7C6K1E3dMf2ZBpump',       1_120_912, 'solana'),
 'JOTCHUA':   ('BcHEaaTCvycPwwsJ9yQTXdHP9X2gCLkznDbZ8VySpump',       3_430_880, 'solana'),
}
TIERS = [(3,'RECOVER COST'),(5,'SELL 25%'),(10,'SELL 25%'),(20,'SELL 25%')]

def get(u):
    try:
        return json.loads(urllib.request.urlopen(
            urllib.request.Request(u, headers={'User-Agent':'Mozilla/5.0'}), timeout=25).read())
    except Exception:
        return {}

def live(addr):
    d = get(f'https://api.dexscreener.com/latest/dex/tokens/{addr}')
    ps = [p for p in (d.get('pairs') or []) if ((p.get('volume') or {}).get('h24') or 0) > 200]
    if not ps: return None
    ps.sort(key=lambda p: -((p.get('liquidity') or {}).get('usd') or 0))
    p = ps[0]
    return dict(mc=p.get('marketCap') or 0,
                liq=sum((x.get('liquidity') or {}).get('usd') or 0 for x in ps),
                v24=sum((x.get('volume') or {}).get('h24') or 0 for x in ps),
                pc=p.get('priceChange') or {})

print(f"BEN'S EXIT LADDER — checked {time.strftime('%Y-%m-%d %H:%M UTC', time.gmtime())}\n")
print(f"{'coin':11}{'mcap now':>13}{'vs baseline':>13}{'next tier':>13}{'need':>9}{'v/liq':>7}{'24h':>8}")
hits = []
for name,(addr,base,chain) in LADDER.items():
    d = live(addr)
    if not d:
        print(f"  {name:9}  -- no live pair (check for a migration/new contract) --"); continue
    mult = d['mc']/base
    nxt = next(((m,l) for m,l in TIERS if mult < m), None)
    if nxt is None:
        hits.append((name,'ALL TIERS PASSED',mult)); label,need = 'ALL PASSED','-'
    else:
        label = f"{nxt[0]}x {nxt[1]}"; need = f"{nxt[0]/mult:.2f}x"
    for m,l in TIERS:
        if mult >= m: hits.append((name, f'{m}x {l}', mult))
    vl = d['v24']/d['liq'] if d['liq'] else 0
    print(f"  {name:9}{d['mc']:>13,.0f}{mult:>12.2f}x{label:>13}{need:>9}{vl:>7.2f}{d['pc'].get('h24',0):>8}")
    time.sleep(0.3)

print()
if hits:
    print("*** TIERS TRIGGERED — ACTION DUE ***")
    seen=set()
    for n,l,m in hits:
        if (n,l) in seen: continue
        seen.add((n,l)); print(f"  {n}: {l}  (now {m:.2f}x baseline)")
else:
    print("No tier hit. Nothing to sell.")
print("\nAlso apply the trailing rule manually: -50% from any local high exits the remainder.")
print("TON leg review date: 22 Sep 2026 (end of Durov's stated 'this summer').")
