b7b1487175
Polymarket geoblocks order placement by IP and Railway ran the worker in a US region — fine for the paper bot (reads only) but a dead end for going live. Fly arn (Sweden, unrestricted, ~25ms from the CLOB's eu-west-2 primaries) passes: geocheck VERDICT TRADABLE, pm geoblock blocked:false. - host/geocheck.py: 3-probe geo-gate verdict (ipinfo, pm /api/geoblock, unauth CLOB order POST); --idle keeps a test machine up - host/start.sh: geocheck at boot (GEOCHECK_ONLY=1 = probe-and-idle test mode, no second book-writer); warns loudly if a region is blocked - fly.toml/fly.Dockerfile: wwf-copybot, single machine, http_service :8080 for the Alchemy push webhook (now wh_blf4qjjvfdbqs9mc -> fly.dev domain) - deploy_bot.sh: railway redeploy -> flyctl apps restart + banner wait Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
86 lines
3.2 KiB
Python
86 lines
3.2 KiB
Python
#!/usr/bin/env python3
|
|
"""Can this box place Polymarket orders? (IP geo-gate probe, no keys needed)
|
|
|
|
Polymarket geoblocks TRADING by IP (reads are open everywhere): an order POST
|
|
from a restricted country gets 403 "Trading restricted in your region" before
|
|
auth is even checked, so an unauthenticated dummy order cleanly separates
|
|
geo-blocked (403 geo message) from allowed (400/401 auth/validation error).
|
|
Restricted list is long and includes surprises — US, UK, France, Germany,
|
|
Brazil (so no Fly gru!), Netherlands, Singapore, Australia:
|
|
https://docs.polymarket.com/developers/CLOB/geoblock
|
|
|
|
Probes, in order:
|
|
1. ipinfo.io — where does the internet think this box is
|
|
2. polymarket geoblock — Polymarket's own verdict for this IP
|
|
3. clob POST /order — the gate that actually matters
|
|
|
|
Usage:
|
|
python3 host/geocheck.py # print verdict, exit 0 = tradable
|
|
python3 host/geocheck.py --idle # then sleep forever (test deploys:
|
|
# keeps the machine up for fly ssh)
|
|
"""
|
|
import json
|
|
import ssl
|
|
import sys
|
|
import time
|
|
import urllib.request
|
|
|
|
CLOB = "https://clob.polymarket.com"
|
|
# macOS framework Pythons often ship without CA certs (same workaround as the
|
|
# rest of the repo); the verdict is informational, so unverified is acceptable
|
|
_CTX = [None, ssl._create_unverified_context()]
|
|
|
|
|
|
def get(url, method="GET", data=None):
|
|
req = urllib.request.Request(url, method=method, data=data,
|
|
headers={"User-Agent": "Mozilla/5.0",
|
|
"Content-Type": "application/json"})
|
|
err = None
|
|
for ctx in _CTX:
|
|
try:
|
|
r = urllib.request.urlopen(req, timeout=20, context=ctx)
|
|
return r.status, r.read().decode(errors="replace")[:300]
|
|
except urllib.error.HTTPError as e:
|
|
return e.code, e.read().decode(errors="replace")[:300]
|
|
except Exception as e:
|
|
err = e
|
|
return None, str(err)
|
|
|
|
|
|
def main():
|
|
ok = True
|
|
|
|
st, body = get("https://ipinfo.io/json")
|
|
import re
|
|
loc = dict(re.findall(r'"(country|city|org)":\s*"([^"]*)"', body or ""))
|
|
if loc:
|
|
print(f"[geo] ip location : {loc.get('country')} {loc.get('city')} ({loc.get('org')})")
|
|
else:
|
|
print(f"[geo] ip location : lookup failed ({st} {(body or '')[:80]})")
|
|
|
|
st, body = get("https://polymarket.com/api/geoblock")
|
|
print(f"[geo] pm geoblock : {st} {body[:160]}")
|
|
|
|
st, body = get(f"{CLOB}/order", method="POST", data=b"{}")
|
|
geo_blocked = (st == 403 and "restricted" in body.lower())
|
|
print(f"[geo] clob order : {st} {body[:160]}")
|
|
|
|
if geo_blocked:
|
|
ok = False
|
|
print("[geo] VERDICT: BLOCKED — this box cannot place Polymarket orders")
|
|
elif st is None:
|
|
ok = False
|
|
print("[geo] VERDICT: UNKNOWN — clob unreachable from this box")
|
|
else:
|
|
print("[geo] VERDICT: TRADABLE — order endpoint reachable past the geo-gate")
|
|
|
|
if "--idle" in sys.argv:
|
|
print("[geo] --idle: sleeping so the machine stays up for inspection…", flush=True)
|
|
while True:
|
|
time.sleep(3600)
|
|
sys.exit(0 if ok else 1)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|