-
Notifications
You must be signed in to change notification settings - Fork 10
SKILL
name: building-xaya-games description: Use when building or deploying a simple on-chain (non-channel) game on the Xaya platform — writing a GSP with libxayagame, running the XayaX Polygon bridge, porting the mover example to a new game or chain, registering Xaya names, or sending moves via the XayaAccounts contract. For real-time 1v1 channel games (off-chain signed states, disputes, relays), use xaya-game-skill instead.
A Xaya game = a GSP (Game State Processor: libxayagame + your C++ rules) that deterministically derives game state from moves stored on a blockchain, fed by the XayaX bridge. Everything below was verified live on Polygon mainnet (2026-06-12). Trust this file over memory — agents reconstructing these facts from memory invent XayaX flags, hedge on addresses, and get RPC semantics wrong.
Full verified file templates (patch, Dockerfile, compose, scripts, real outputs): REFERENCE.md in this skill directory. A complete worked tutorial lives in the Xaya tutorials wiki (Mover Parts 1–3).
| Item | Value |
|---|---|
| XayaAccounts (ERC-721 names + moves) | 0x8C12253F71091b9582908C8a44F78870Ec6F304F |
| WCHI token (ERC-20, 8 decimals) | 0xE79feAAA457ad7899357E8E2065a3267aC9eE601 |
| Registration policy contract | 0x997A8B19d200A453D77c3857E81Af31F680b3663 |
| Name registration fee | flat 1 WCHI (any length 1–10, verified via policy.checkRegistration) |
| Public Polygon RPC (Xaya team) | https://polygon-node.xaya.io |
| Docker images | bridge xaya/xayax (prebuilt, on Docker Hub), build base xaya/libxayagame
|
| Move gas cost | well under $0.01 in POL |
| Namespace for ALL player moves | p |
Turn-based / async / MMO-style → simple on-chain moves (this skill). Real-time 1v1 with per-second interaction → game channels (xaya-game-skill).
-
Pick a game id (e.g.
gr). No on-chain registry — collision is by convention only. Moves arrive wrapped: a player sends{"g":{"gr":{...your move...}}}; your GSP receives only the inner object plus the name (nop/prefix). -
Scaffold from mover (
libxayagame/mover/):logic.cpp/hpp(GameLogic callbacks),moves.cpp/hpp(move parsing),main.cpp(DefaultMain wiring),proto/*.proto(protobuf state+undo — the verified-deterministic serialization; don't rely on JSON key ordering for state).pending.cppoptional — XayaX provides no pending feed. -
Add the chain case in
GetInitialStateInternal:case Chain::POLYGON: height = <recent block ≤ current tip>; hashHex = ""; break;Empty hash = accept any block at that height (verified pattern). Check the live tip first (getblockchaininfoon XayaX, or polygonscan) — a future height breaks sync. The height is your game's genesis; moves before it are invisible. Never change it after launch. -
Handle the version check: XayaX reports version
1000000; libxayagame's default minimum is1010200. Either setconfig.MinXayaVersion = 1000000;in yourmain.cpp(clean, field verified atdefaultmain.hpp:180) or sed-patch the installed header before compiling (see REFERENCE.md — the verified tutorial path). -
Build with the
xaya/libxayagamebase image (libs preinstalled; minutes). Do NOT rebuild the whole libxayagame CMake tree (slow, needs jsonrpccpp/googletest/eth-utils from source). Do NOT use the image's prebuiltmoverd— it's broken upstream (missinglibmover.so). Full Dockerfile in REFERENCE.md. -
Run XayaX + GSP via compose. XayaX
ethconnector takes EXACTLY these flags (verified — do not invent others like--eth_ws_url,--genesis_height,--max_reorg_depth):eth --eth_rpc_url=<RPC> --accounts_contract=<XayaAccounts> --port=8000 --listen_locally=false --zmq_address=tcp://<service-name>:28555 --logtostderr. Fresh XayaX starts near the tip and serves within ~2 minutes; it backfills older blocks on demand. -
GSP flags:
--xaya_rpc_url=http://<xayax-service>:8000 --xaya_rpc_protocol=2 --game_rpc_port=8600 --game_rpc_listen_locally=false --storage_type=sqlite --datadir=/xayagame --enable_pruning=1000 --pending_moves=false. -
Send moves:
XayaAccounts.move('p', name, moveJson, MAX_UINT256, 0, address(0))— nonce MAX_UINT256 skips the check; amount/receiver are for optional WCHI payments. Registration:policy.checkRegistration→WCHI.approve(XayaAccounts, fee)→register('p', name). Verified scripts in REFERENCE.md. -
Verify with the GSP RPC:
getnullstateuntil"state":"up-to-date", send a live move (sub-cent),getcurrentstateshows it. Expected log lines in REFERENCE.md.
| Pitfall | Fix |
|---|---|
Docker auto-assigns 192.168.0.0/20 to new networks when default pools are exhausted — shadows LAN routes, can cut off remote access (happened for real) |
ALWAYS pin the compose network subnet (e.g. 172.16.0.0/24) and check ip route for collisions |
--zmq_address=tcp://localhost:28555 |
Must be the Docker service name — it's the address XayaX advertises; the GSP connects to it from another container |
| Default JSON-RPC protocol 1 | XayaX speaks 2.0 — --xaya_rpc_protocol=2 or startup RPC errors |
waitforchange("") assumed to return immediately |
Wrong: empty/unparseable hash WAITS for the next change or ~5 s internal timeout. Only a valid-but-stale hash returns immediately (libxayagame source) |
| Trusting any player JSON | Invalid moves must be IGNORED (log + continue), never crash — anyone can send any JSON to your game id |
| First move semantics surprise (mover) | A player's first move executes 1 step in its own block — {"d":"k","n":2} ends at (0,2), not (0,2)+1 block delay |
| C++ edits not picked up |
docker compose build --no-cache after source changes if in doubt |
getpendingstate via XayaX |
Returns a "pending moves are not tracked" error; --pending_moves=true is harmless but useless (logs Not subscribing to pending moves) |
- GSP log shows:
Connected to RPC daemon with chain polygon→Detected ZMQ blocks endpoint→Got genesis height from game: <N>→Game did not specify genesis hash, retrieved <hash>→ attach-step batches → done in ~2 min. -
getnullstate→{"chain":"polygon","gameid":"<id>","state":"up-to-date",...}. - Live round-trip: send a real move (costs <$0.01), watch
Processed 1 moves forwardin the log, confirm viagetcurrentstate. Two independently-synced GSPs return byte-identicalgamestate.
Xaya developer documentation — verified on Polygon mainnet. Questions? Xaya Development Discord