#!/usr/bin/env python3 """READ-ONLY: canonical pDAI mint-adapter prerequisites at saved block 27,824,343. This new script was not run against an RPC when the evidence card was built. Its accompanying output is an explicitly archived subset, not a new result. Python 3 standard library only. No keys, approvals, signatures, simulations, transactions, broadcasts, or state overrides. Only eth_chainId and eth_call. An archive-capable PulseChain RPC is needed to reproduce the saved state. """ import argparse import datetime import json import re import sys import urllib.request PIN = 27824343 EXPECTED_CHAIN_ID = 369 PDAI = "0x6b175474e89094c44da98b954eedeac495271d0f" DAI_JOIN = "0x9759a6ac90977b93b58547b4a71c78317f391a28" VAT = "0x35d1b3f3d7966a1dfe207aa4514c12a259a0492b" ALLOWED_METHODS = {"eth_chainId", "eth_call"} def address(value): if not re.fullmatch(r"0x[0-9a-fA-F]{40}", value): raise argparse.ArgumentTypeError("Expected a full 0x-prefixed address") return value.lower() def requests(holder=None): rows = [{"label": "chain_id", "method": "eth_chainId", "params": []}] specs = [ ("Vat.live()", VAT, "0x957aa58c"), ("DaiJoin.live()", DAI_JOIN, "0x957aa58c"), ("DAI.wards(DaiJoin)", PDAI, "0xbf353dbb" + DAI_JOIN[2:].zfill(64)), ] if holder: specs.append(("Vat.dai(holder) [rad = 10^-45 DAI]", VAT, "0x6c25b346" + holder[2:].zfill(64))) rows.extend({"label": label, "method": "eth_call", "params": [{"to": target, "data": data}, hex(PIN)]} for label, target, data in specs) return rows def rpc(url, method, params, timeout): if method not in ALLOWED_METHODS: raise ValueError("This tool only permits chain ID and getter reads") body = json.dumps({"jsonrpc": "2.0", "id": 1, "method": method, "params": params}).encode() req = urllib.request.Request(url, data=body, headers={"Content-Type": "application/json", "User-Agent": "pSTABLES-readonly-check/1.0"}) with urllib.request.urlopen(req, timeout=timeout) as response: return json.load(response) def main(): parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("--rpc", default="https://rpc.pulsechain.com") parser.add_argument("--holder", type=address, help="Optionally read this holder's internal Vat DAI (raw rad units)") parser.add_argument("--timeout", type=int, default=30) parser.add_argument("--print-requests", action="store_true", help="Print the exact requests without any network connection") args = parser.parse_args() planned = requests(args.holder) if args.print_requests: print(json.dumps({"offline": True, "block": PIN, "requests": planned}, indent=2)) return 0 if args.timeout <= 0: parser.error("--timeout must be positive") chain = rpc(args.rpc, "eth_chainId", [], args.timeout) try: chain_id = int(chain.get("result", ""), 16) except (TypeError, ValueError): raise RuntimeError("Chain ID read failed: " + json.dumps(chain)) if chain_id != EXPECTED_CHAIN_ID: raise RuntimeError("Expected PulseChain chain ID 369, got " + str(chain_id)) output = { "evidence_type": "NEW getter run, produced when this script is executed", "generated_utc": datetime.datetime.now(datetime.timezone.utc).isoformat(), "chain_id": chain_id, "block": PIN, "read_only": True, "simulation_or_broadcast": False, "scope": "Mint-adapter prerequisites only; no DaiJoin.exit execution test", "reads": [{"label": "chain_id", "response": chain}], } failed = False for row in planned[1:]: try: response = rpc(args.rpc, row["method"], row["params"], args.timeout) except Exception as error: response = {"transport_error": str(error)} entry = {"label": row["label"], "request": { "jsonrpc": "2.0", "id": 1, "method": row["method"], "params": row["params"]}, "response": response} result = response.get("result") if isinstance(result, str) and re.fullmatch(r"0x[0-9a-fA-F]{64}", result): entry["decoded_uint256"] = str(int(result, 16)) else: failed = True entry["decode_error"] = "Expected a complete 32-byte uint256 result" output["reads"].append(entry) output["all_getters_decoded"] = not failed print(json.dumps(output, indent=2)) return 1 if failed else 0 if __name__ == "__main__": try: sys.exit(main()) except (OSError, RuntimeError, ValueError) as error: print(json.dumps({"error": str(error), "read_only": True}), file=sys.stderr) sys.exit(1)