#!/usr/bin/env python3 """dcheck.py (FW Analyst 2, 6 Oct 2026): pre-buy SAFETY check for one Doppler coin (hook 0x4e3468951d49f2eea976ed0d6e75ffcb44a9a544). eth_call only, public RPC, about 8 calls, under 5 s. usage: python3 dcheck.py [--sell-amount-tokens N] Prints one JSON line. verdict OK only if: pool status 2 (liquidity locked forever, exit reverts), launch fee schedule finished, fee now (LP + hook end fee) <= 2%, and another wallet sold in this pool in the last ~33 min (sell proven on chain). Not covered: token-contract transfer blocks (Doppler DERC20 is standard; check code size 0 vs known) and price impact.""" import sys, json, time, urllib.request from Crypto.Hash import keccak as _k U = "https://rpc.mainnet.chain.robinhood.com" HOOK = "0x4e3468951d49f2eea976ed0d6e75ffcb44a9a544"; PM = "0x8366a39cc670b4001a1121b8f6a443a643e40951" def kk(b): h = _k.new(digest_bits=256); h.update(b); return h.digest() def sel(sig): return "0x" + kk(sig.encode()).hex()[:8] def rpc(m, p): for i in range(6): try: q = urllib.request.Request(U, json.dumps({"jsonrpc": "2.0", "id": 1, "method": m, "params": p}).encode(), {"content-type": "application/json", "User-Agent": "Mozilla/5.0"}) return json.load(urllib.request.urlopen(q, timeout=20)) except Exception as e: time.sleep(1 + i); err = e raise err def call(to, data, frm=None): o = {"to": to, "data": data} if frm: o["from"] = frm return rpc("eth_call", [o, "latest"]) a32 = lambda a: a[2:].lower().rjust(64, "0") u32 = lambda v: hex(v & ((1 << 256) - 1))[2:].rjust(64, "0") def words(h): h = h[2:]; return [h[i:i + 64] for i in range(0, len(h), 64)] tok = sys.argv[1].lower() amt = int(float(sys.argv[sys.argv.index("--sell-amount-tokens") + 1]) * 1e18) if "--sell-amount-tokens" in sys.argv else 10 ** 21 out = {"token": tok, "t_bkk": time.strftime("%H:%M:%S", time.gmtime(time.time() + 7 * 3600))} st = call(HOOK, "0x1bab58f5" + a32(tok)).get("result", "0x") if not st or int(st, 16) == 0: print(json.dumps(dict(out, verdict="NO", why="not a Doppler hook 0x4e34 asset"))); sys.exit() w = words(st) numeraire = "0x" + w[0][24:]; dhook = "0x" + w[2][24:]; status = int(w[4], 16) c0, c1 = "0x" + w[5][24:], "0x" + w[6][24:]; fee = int(w[7], 16); spc = int(w[8], 16) - (1 << 256 if int(w[8], 16) >> 255 else 0) key = a32(c0) + a32(c1) + u32(fee) + u32(spc) + a32(HOOK) pid = "0x" + kk(bytes.fromhex(key)).hex() out.update(pool=pid, numeraire=numeraire, status=status, extra_hook=dhook) ex = call(HOOK, "0x5ec5db32" + a32(tok), frm="0xeb7c034704ef8dcd2d32324c1545f62fb4ad0862") out["exit_blocked"] = "error" in ex # status 2 + revert = liquidity can never be removed s0 = call(PM, "0x1e2eaeaf" + kk(bytes.fromhex(pid[2:] + "6".rjust(64, "0"))).hex()) v = int(s0["result"], 16); out["lp_fee_pct"] = ((v >> 208) & 0xFFFFFF) / 1e4 hook_fee_now = 0.0; sched_done = True if int(dhook, 16): fs = call(dhook, sel("getFeeSchedule(bytes32)") + pid[2:]) if fs.get("result"): f = [int(x, 16) for x in words(fs["result"])] start, f0, f1, last, length = f[:5] age = time.time() - start sched_done = age > length + 3 hook_fee_now = (f1 if sched_done else max(f1, f0 - (f0 - f1) * max(age, 0) / max(length, 1))) / 1e4 out.update(fee_start_pct=f0 / 1e4, fee_end_pct=f1 / 1e4, fee_len_s=length, launch_age_s=round(age), hook_fee_now_pct=round(hook_fee_now, 2)) # sell proof: real sells by other wallets in this pool in the last ~33 min (the on-chain quoter 0x3881e5246e81e1bf731a9fc1856268d381bb9bd7 is curve math only and does not run hooks) SWAP = "0x40e9cecb9f5f1f1c5b9c97dec2917b7ee92e57ba5563708daca94dd84ad7112f" head = int(rpc("eth_blockNumber", [])["result"], 16) lg = rpc("eth_getLogs", [{"address": PM, "topics": [SWAP, pid], "fromBlock": hex(head - int(__import__("os").environ.get("SELLWIN", "20000"))), "toBlock": hex(head)}]).get("result") or [] sells = 0; buys = 0; skip = {HOOK, dhook} for l in lg: snd = "0x" + l["topics"][2][26:] if snd in skip: continue d = l["data"][2:]; a0 = int(d[:64], 16); a0 -= (1 << 256) if a0 >> 255 else 0; a1 = int(d[64:128], 16); a1 -= (1 << 256) if a1 >> 255 else 0 amt_asset = a0 if tok == c0 else a1 if amt_asset < 0: sells += 1 elif amt_asset > 0: buys += 1 out.update(swaps_33min=len(lg), outside_buys_33min=buys, outside_sells_33min=sells) out["sell_ok"] = True if sells > 0 else None # None = not proven yet (no recent sells), not a fail fee_now = out["lp_fee_pct"] + hook_fee_now out["fee_now_pct"] = round(fee_now, 2) ok = status == 2 and out["exit_blocked"] and sched_done and fee_now <= 2.0 and out.get("sell_ok") is True why = [x for x, bad in (("launch fee still high", not sched_done), ("fee over 2%", fee_now > 2.0), ("no recent sell by another wallet (sell not proven)", out.get("sell_ok") is not True), ("liquidity not locked", not (status == 2 and out["exit_blocked"]))) if bad] print(json.dumps(dict(out, verdict="OK" if ok else "WAIT" if why == ["launch fee still high"] else "NO", why=why)))