#!/usr/bin/env python3
"""tmt_first_swap.py — cold-walk TMT's pool: find pool id via Initialize,
then enumerate Swap events to name the first swap (tx, block, delta).
eip155:4663. Read-only eth_getLogs/eth_call."""
import json, sys, time, urllib.request

sys.path.insert(0, "/workspace/tools")
from eth_call import keccak256, eth_call

RPCS = ["https://rpc.mainnet.chain.robinhood.com", "https://rpc.ordofi.network"]
H = {"Content-Type": "application/json", "User-Agent": "ARION-firstswap/1.0"}
TMT = "0x974e13c26a2143d6161a08fb00ac842063a99ba3".lower()
PM = "0x8366a39cc670b4001a1121b8f6a443a643e40951"
DEPLOY = 73_456_520

INIT_TOPIC = "0x" + keccak256(b"Initialize(bytes32,address,address,uint24,int24,address,uint160,int24)").hex()
SWAP_TOPIC = "0x" + keccak256(b"Swap(bytes32,address,int128,int128,uint160,uint128,int24,uint24)").hex()
TMT_TOPIC = "0x" + TMT[2:].rjust(64, "0")

_i = 0
def rpc(method, params, budget=25):
    global _i
    body = json.dumps({"jsonrpc": "2.0", "id": 1, "method": method, "params": params}).encode()
    t0, delay, last = time.time(), 0.4, None
    while True:
        url = RPCS[_i % len(RPCS)]; _i += 1
        try:
            d = json.load(urllib.request.urlopen(urllib.request.Request(url, data=body, headers=H), timeout=30))
            if "result" in d:
                time.sleep(0.08)
                return d["result"]
            last = d.get("error")
            msg = json.dumps(last).lower()
            if "exceeds" in msg or "limit" in msg or "range" in msg:
                raise RangeTooBig(msg[:120])
            if time.time() - t0 > budget:
                raise RuntimeError(f"budget: {last}")
            time.sleep(delay); delay = min(delay * 1.7, 2.5)
        except RangeTooBig:
            raise
        except Exception as e:
            last = e
            if time.time() - t0 > budget:
                raise RuntimeError(f"budget: {last}")
            time.sleep(delay); delay = min(delay * 1.7, 2.5)

class RangeTooBig(Exception):
    pass

def getlogs(addr, a, b, topics):
    try:
        return rpc("eth_getLogs", [{"address": addr, "fromBlock": hex(a),
                   "toBlock": hex(b), "topics": topics}])
    except RangeTooBig:
        m = (a + b) // 2
        return getlogs(addr, a, m, topics) + getlogs(addr, m + 1, b, topics)

head = int(rpc("eth_blockNumber", []), 16)
print("head", head, flush=True)
print("INIT_TOPIC", INIT_TOPIC)
print("SWAP_TOPIC", SWAP_TOPIC)

# 1. pool id via Initialize where TMT is currency0 or currency1
inits = []
for slot in (2, 3):  # topic2=currency0, topic3=currency1 (topic1=poolId)
    topics = [INIT_TOPIC, None, None, None]
    topics[slot] = TMT_TOPIC
    inits += getlogs(PM, DEPLOY, head, topics)
seen = set()
for lg in inits:
    k = lg["transactionHash"] + lg["logIndex"]
    if k in seen:
        continue
    seen.add(k)
    pid = lg["topics"][1]
    c0 = "0x" + lg["topics"][2][-40:]
    c1 = "0x" + lg["topics"][3][-40:]
    # data: fee uint24, tickSpacing int24, hooks addr, sqrtPriceX96, tick
    d = lg["data"][2:]
    fee = int(d[0:64], 16)
    ts_ = int(d[64:128], 16)
    hooks = "0x" + d[128:192][-40:]
    print("INIT blk", int(lg["blockNumber"], 16), "tx", lg["transactionHash"])
    print("  poolId", pid)
    print("  c0", c0, "c1", c1, "fee", fee, "tickSpacing", ts_, "hooks", hooks)

    # 2. swaps for this pool from its init block
    a = int(lg["blockNumber"], 16)
    swaps = getlogs(PM, a, head, [SWAP_TOPIC, pid])
    print("  swaps:", len(swaps))
    for s in swaps[:6]:
        dd = s["data"][2:]
        am0 = int(dd[0:64], 16); am1 = int(dd[64:128], 16)
        if am0 >= 1 << 127: am0 -= 1 << 128
        if am1 >= 1 << 127: am1 -= 1 << 128
        tick = int(dd[256:320], 16)
        if tick >= 1 << 23: tick -= 1 << 24
        fee24 = int(dd[320:384], 16)
        print("   SWAP blk", int(s["blockNumber"], 16), "tx", s["transactionHash"],
              "sender", "0x" + s["topics"][2][-40:],
              "am0", am0, "am1", am1, "tick", tick, "fee", fee24)
