- Private keys and seed phrases never enter the app.
- Login uses a short-lived one-time nonce and Nimiq signed-message verification.
- Sessions are signed and stored in an httpOnly cookie.
- Run IDs are bound to the authenticated wallet and consumed once.
- Seeds are generated by the server and are not sent to the client as authoritative scores.
- Replay timing, event order, event values, and puzzle solutions are validated server-side.
- Practice scores remain local and are not accepted by ranked endpoints.
- Reward requests require a verified daily score and are unique per wallet/day.
- Scores are calculated from server-replayed events. Ranked submission bodies do not contain an authoritative score field.
- Each run is consumed before replay evaluation, preventing a valid event trace from being replayed after submission.
- Per-IP request limiting protects authentication, run creation, and replay submission endpoints. Responses include
Retry-Afterwhen limited. - Unhandled API failures are logged as structured events and return a generic error response.
Production requirements:
- Set a strong
SESSION_SECRETandDAILY_SECRET. - Configure durable Postgres with
DATABASE_URL. - Production startup rejects SQLite fallback when
DATABASE_URLis missing. - Set
WEB_ORIGINto the deployed frontend origin. - Configure a funded payout worker before enabling on-chain reward settlement.