"""v3ext.py (A1.18): Swap + Mint/Burn logs from first-2h end to 12 h (or chain head) for mc5-band pools. Writes /root/fwa1/v3/v3ext.db.
Paid dRPC key read in code only. Chunks of <=120k blocks per call, 20 calls a batch."""
import json, sqlite3, time, urllib.request, pickle
src = open("/root/fwa1/v3pull.py").read().split("\n")
K = json.load(open("/opt/common/drpc_paid.json"))["robinhood"]
exec(next(l for l in src if l.startswith("U =")))
T_SWAP = "0xc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67"
T_MINT = "0x7a53080ba414158be7ec69b987b5fb7d07dee101fe85488f0853ae16239d0bde"
T_BURN = "0x0c396cd989a39f4459b5fa1aed6a9a8dcdbc45908acfd67e028cd568da98982c"
SPB = 0.101283; W2 = int(2 * 3600 / SPB); W12 = int(12 * 3600 / SPB); CH = 50000
def post(body):
    for i in range(6):
        try:
            rq = urllib.request.Request(U, json.dumps(body).encode(), {"Content-Type": "application/json", "User-Agent": "Mozilla/5.0"})
            return json.load(urllib.request.urlopen(rq, timeout=120))
        except Exception as e:
            err = e; time.sleep(2 * (i + 1))
    raise err
head = int(post({"jsonrpc": "2.0", "id": 1, "method": "eth_blockNumber", "params": []})["result"], 16)
P, W = pickle.load(open("/root/fwa1/v3/an.pkl", "rb"))
M = sqlite3.connect("file:/root/fwa1/v3/v3a1.db?mode=ro", uri=True)
cb = dict(M.execute("SELECT pool, cb FROM meta").fetchall())
pools = [p["pool"] for p in P if p["feats"][300]["mc"] and p["feats"][300]["mc"] >= 1e5]
D = sqlite3.connect("/root/fwa1/v3/v3ext.db", timeout=120)
D.execute("CREATE TABLE IF NOT EXISTS sw(pool TEXT, b INT, li INT, tx TEXT, snd TEXT, rcp TEXT, a0 TEXT, a1 TEXT, sq TEXT, PRIMARY KEY(pool, b, li))")
D.execute("CREATE TABLE IF NOT EXISTS lp(pool TEXT, b INT, li INT, kind TEXT, data TEXT, PRIMARY KEY(pool, b, li))")
D.execute("CREATE TABLE IF NOT EXISTS done(pool TEXT, fb INT, PRIMARY KEY(pool, fb))")
done = {tuple(r) for r in D.execute("SELECT pool, fb FROM done")}
jobs = []
for p in pools:
    a, z = cb[p] + W2 + 1, min(cb[p] + W12, head)
    for f in range(a, z + 1, CH):
        if (p, f) not in done: jobs.append((p, f, min(f + CH - 1, z)))
print("pools", len(pools), "jobs", len(jobs), "head", head, flush=True)
for i in range(0, len(jobs), 20):
    grp = jobs[i:i + 20]
    body = [{"jsonrpc": "2.0", "id": k, "method": "eth_getLogs", "params": [{"address": p, "fromBlock": hex(f), "toBlock": hex(t), "topics": [[T_SWAP, T_MINT, T_BURN]]}]} for k, (p, f, t) in enumerate(grp)]
    res = post(body); res = res if isinstance(res, list) else []
    for r in res:
        p, f, t = grp[r["id"]]
        if "result" not in r: print("err", p, str(r.get("error"))[:100], flush=True); continue
        for l in r["result"]:
            b, li = int(l["blockNumber"], 16), int(l["logIndex"], 16)
            if l["topics"][0] == T_SWAP:
                D.execute("INSERT OR IGNORE INTO sw VALUES(?,?,?,?,?,?,?,?,?)", (p, b, li, l["transactionHash"], "0x" + l["topics"][1][26:], "0x" + l["topics"][2][26:], l["data"][2:66], l["data"][66:130], l["data"][130:194]))
            else:
                D.execute("INSERT OR IGNORE INTO lp VALUES(?,?,?,?,?)", (p, b, li, "m" if l["topics"][0] == T_MINT else "b", l["data"]))
        D.execute("INSERT OR IGNORE INTO done VALUES(?,?)", (p, f))
    D.commit(); time.sleep(0.3)
    if (i // 20) % 10 == 0: print(i, flush=True)
print("done", D.execute("SELECT COUNT(*) FROM sw").fetchone(), D.execute("SELECT kind, COUNT(*) FROM lp GROUP BY kind").fetchall(), flush=True)
