diff --git a/HANDOFF.md b/HANDOFF.md index 7760c613..bcda4642 100644 --- a/HANDOFF.md +++ b/HANDOFF.md @@ -40,6 +40,21 @@ The repo is authoritative; project memory has deeper history. Published feed stays at $1,000 to match the paper book. $500 run: +2728% (small banks compound faster — their-bet ceilings bind later). +## Queued next-session work (in value order) + +1. **Exact-res_t migration**: `payouts.resolution_time(cond)` (Etherscan V2, + wired+verified 2026-07-08) gives true resolution timestamps; migrate + trust.py / validate_timing / portfolio.py to consume them instead of + endDate metadata. Alignment-grade change — same care as the 2026-07-08 + audit. Backfill throttled ≤5 req/s (Etherscan free tier). +2. **Empirical fill model**: every copy now logs a `book` snapshot (spread + + 5c depth) to the fills ledger; once a few weeks accumulate, fit slippage + vs stake/depth and replace portfolio.py's flat SLIP haircut; add a depth + gate before real-money sizing. +3. **Funding-cluster tracer port** to Etherscan logs (Alchemy free tier now + caps getLogs at 10 blocks — insider.py's ring detection is degraded + until then). + ## Watch list (the standing question: does Set E hold up?) - **AIcAIc** — held-win only 42%; his edge is sell-timing (most lag-fragile diff --git a/README.md b/README.md index 9bba0ea6..e223abfb 100644 --- a/README.md +++ b/README.md @@ -244,7 +244,7 @@ runner is retired (GitHub throttled `*/5` to ~2h in practice — it copied 1 of |--------|--------------| | [Goldsky Turbo Pipelines](https://docs.goldsky.com/chains/polymarket) | per-fill order events with timestamps for *every* wallet (Polymarket killed subgraphs with the 2026-04-28 v2 migration) — fixes the cache's two blind spots: no entry times, and position-level aggregation hiding scalps. See also [warproxxx/poly_data](https://github.com/warproxxx/poly_data), [Bitquery](https://docs.bitquery.io/docs/examples/polymarket-api/) | | [PolymarketData.co](https://www.polymarketdata.co/) | HISTORICAL order-book snapshots (Aug 2025+) → depth-aware backtest fills. Forward-going depth is now captured in-house: every copy logs `book` {bb, ba, spread, bid5c, ask5c} to the fills ledger (2026-07-08) | -| free Etherscan-V2 (Polygonscan) API key | topic-filtered logs over wide ranges → EXACT `ConditionResolution` timestamps (CLOB/gamma have no true resolution time; `end_date_iso` can be months wrong) + restores the funding-cluster tracer (Alchemy FREE tier caps `eth_getLogs` at 10 blocks as of 2026-07) | +| ~~free Etherscan-V2 key~~ **WIRED 2026-07-08**: `payouts.resolution_time(cond)` returns the exact on-chain `ConditionResolution` timestamp (cached forever in `resolution_times`; key = `etherscan_key` in gitignored config.json, 5 req/s free tier). Verified: the Jul-7 Brewers market truly resolved 2026-07-08 04:51 — cached metadata res_t was 29h wrong. NEXT: migrate trust/validate/portfolio to consume it (alignment-grade change, do carefully), and port the funding-cluster tracer off Alchemy getLogs (free tier caps at 10 blocks) | | Pinnacle closing lines via [SharpAPI](https://sharpapi.io/sportsbooks/pinnacle-odds-api) / [sportsapis.dev](https://sportsapis.dev/historical-odds) / [BettingIsCool](https://api.bettingiscool.com/) (Pinnacle closed its public API 2025-07) | closing-line-value as an independent "was this bet sharp" ground truth; a Pinnacle *suspension* on an ITF/esports match is itself a fixing signal | | [Polysights Insider Finder](https://gizmodo.com/tracking-insider-trading-on-polymarket-is-turning-into-a-business-of-its-own-2000709286) | cross-check for flagged insider wallets | diff --git a/live/payouts.py b/live/payouts.py index c2e989c0..37fdfaf7 100644 --- a/live/payouts.py +++ b/live/payouts.py @@ -204,3 +204,48 @@ def stats(): if __name__ == "__main__": print(stats()) + + +# ---- exact resolution TIME (Etherscan V2 logs; wired 2026-07-08) ------------ +# CLOB/gamma carry NO true resolution moment (end_date_iso can be months off — +# the Jul-7 Brewers game carried 2026-05-05 — and cached res_t is endDate +# metadata, 29h wrong on that market). The only truth is the CTF +# ConditionResolution event. Alchemy's FREE tier caps eth_getLogs at 10 +# blocks (discovered 2026-07-08), so this goes through Etherscan V2 +# (chainid=137, wide-range topic-filtered logs, free `etherscan_key` in the +# gitignored config.json). Cached forever — resolution events are immutable. +# Free-tier limits: 5 req/s, 100k/day — throttle any bulk backfill. +cache.query("CREATE TABLE IF NOT EXISTS resolution_times(cond TEXT PRIMARY KEY, res_ts BIGINT)") + +_CTF = "0x4D97DCd97eC945f40cF65F87097ACe5EA0476045" +_RES_TOPIC = "0xb44d84d3289691f71497564b85d4233648d9dbae8cbdbb4329f301c3a0185894" + + +def resolution_time(cond): + """Exact on-chain resolution timestamp for a condition — None while the + market is unresolved or without an etherscan_key. First caller pays one + Etherscan query; cached forever after.""" + r = cache.query("SELECT res_ts FROM resolution_times WHERE cond=?", [cond]) + if r: + return r[0][0] + key = os.environ.get("ETHERSCAN_KEY") + if not key: + try: + key = json.load(open(os.path.join(HERE, "..", "config.json"))).get("etherscan_key") + except Exception: + key = None + if not key: + return None + url = ("https://api.etherscan.io/v2/api?chainid=137&module=logs&action=getLogs" + f"&address={_CTF}&topic0={_RES_TOPIC}&topic0_1_opr=and&topic1={cond}" + f"&fromBlock=0&toBlock=latest&apikey={key}") + try: + resp = json.load(urllib.request.urlopen(url, timeout=30, context=_SSL)) + res = resp.get("result") or [] + if resp.get("status") == "1" and res: + ts = int(res[0]["timeStamp"], 16) + cache.query("INSERT OR REPLACE INTO resolution_times VALUES (?,?)", [cond, ts]) + return ts + except Exception: + pass + return None