Files
wownerogue/src/.env.example
T
jwinterm b291bd3c13 docs: document optional fallback daemons in the env examples
Records the fallback list as an OPTION rather than an expectation, with the
caveat that matters here: a fallback only helps if it can fail independently.
A second daemon in the same office shares the outage that takes the first one
down. A node reachable over a separate path — a home node across the mesh, or a
public/community node — is what actually adds availability.

Also records the split the operator identified: free/credits instances only need
the daemon for block height, so a remote node is a reasonable fallback there.
Instances taking payments should prefer daemons they control, because block
height feeds match fairness and entropy. Either way each endpoint still has to
pass the chain-identity check, so a remote node cannot serve another chain.
2026-07-26 08:00:00 -04:00

623 lines
30 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# =============================================================================
# Wownerogue Server Configuration
# =============================================================================
# Copy this file to .env and customize for your environment.
# The server validates these settings at startup. Production fails closed on missing secrets,
# ambiguous payout flags, simulated blocks, or missing wallet/daemon RPC endpoints.
#
# This is a generic MIT self-hosting template. The named operator is solely responsible for the
# deployment and its legal/financial obligations; Such Software does not operate or endorse it.
# Do not set OPERATED_PRODUCT_PROFILE. That opt-in identifier is reserved for the two exact
# Such Software operated templates in .env.mainnet.example and .env.stagenet.example.
#
# QUICK START CONFIGURATIONS:
# ---------------------------
# 1. FREE MODE (no payments, just play):
# PAYMENTS_ENABLED=false
#
# 2. PAID MODE (1 WOW per game, 2x payout on win):
# PAYMENTS_ENABLED=true
# PAYMENT_MODES=direct
# + Configure wallet RPC and database
#
# 3. CREDITS MODE (buy bundles, play multiple games):
# PAYMENTS_ENABLED=true
# PAYMENT_MODES=credits
# + Configure wallet RPC and database
#
# 4. BOTH MODES (let users choose):
# PAYMENTS_ENABLED=true
# PAYMENT_MODES=direct,credits
# =============================================================================
# UNDERSTANDING ATOMIC UNITS
# =============================================================================
# Wownero (like Monero) uses "atomic units" - the smallest indivisible unit.
#
# 1 WOW = 100,000,000,000 atomic units (10^11, or 100 billion)
#
# Examples:
# 1 WOW = 100000000000
# 0.5 WOW = 50000000000
# 0.1 WOW = 10000000000
# 5 WOW = 500000000000
# 10 WOW = 1000000000000
#
# Why? Floating point math is imprecise. Atomic units ensure exact calculations.
# =============================================================================
# SECTION 1: BASIC SERVER SETTINGS
# =============================================================================
# Server port (default: 3000)
PORT=3000
# Environment: production | development | debug
# - production: minimal logging, real blockchain
# - development: verbose logging, can use simulated blocks
# - debug: maximum logging, debug hotkeys enabled
NODE_ENV=production
# External renderer downloads are disabled by default. When true, pinned Pixi/Three
# bundles may be loaded from jsDelivr; vendored, self-hosted assets are preferred.
RENDERER_CDN_ENABLED=false
# Network selection (only matters for Monero - Wownero only has mainnet)
MONERO_NETWORK=mainnet
# Optional: Display "Hosted by" link in footer (leave empty to hide)
# Example: https://yoursite.com or https://github.com/yourname
# HOSTED_BY=https://example.com
# HOSTED_BY_NAME=Example Host
# =============================================================================
# SECTION 2: DATABASE (PostgreSQL) - REQUIRED
# =============================================================================
# The game stores user sessions, payment history, and credits in PostgreSQL.
# You must create the database and user first (see README).
DB_HOST=localhost
DB_PORT=5432
DB_NAME=wownerogue
DB_USER=wownerogue
DB_PASSWORD=your_secure_password_here
# =============================================================================
# SECTION 3: GAME DIFFICULTY
# =============================================================================
# Controls dungeon size, monster behavior, and effective house edge.
#
# Preset | Dungeon | Monster Speed | Player Win Rate | Best For
# ------------|----------|---------------|-----------------|------------------
# easy | 30x15 | Slow | ~70% | Free play, demos
# normal | 45x22 | Medium | ~45% | Balanced gameplay
# hard | 55x28 | Fast | ~35% | Challenge mode
# casino | 70x35 | Fast | ~30% | Paid modes (default)
#
# If unset, defaults to 'casino' for paid modes, 'normal' for free mode.
# DIFFICULTY_PRESET=casino
# Fine-tune individual difficulty parameters (override preset defaults).
# Only set these if you want to deviate from the chosen preset.
#
# Dungeon layout:
# DUNGEON_WIDTH=70 # Map width in tiles
# DUNGEON_HEIGHT=35 # Map height in tiles
# DUNGEON_DUG_PERCENTAGE=0.10 # % of map that's open space (lower = tighter)
# DUNGEON_ROOM_WIDTH_MIN=3 # Room width range (min)
# DUNGEON_ROOM_WIDTH_MAX=4 # Room width range (max)
# DUNGEON_ROOM_HEIGHT_MIN=3 # Room height range (min)
# DUNGEON_ROOM_HEIGHT_MAX=4 # Room height range (max)
# DUNGEON_CORRIDOR_MIN=6 # Corridor length range (min)
# DUNGEON_CORRIDOR_MAX=15 # Corridor length range (max)
#
# Monster behavior:
# MONSTER_SPEED=1.0 # Moves per player move (1.0 = same speed, 0.5 = half)
# MONSTER_CHASE=0.97 # Chase probability 0.0-1.0 (rest is random wander)
# MONSTER_VISION=22 # Vision range in tiles
# MONSTER_DISTANCE=0.30 # Starting distance ratio 0.0-1.0 (lower = closer)
#
# Treasure placement:
# TREASURE_ROOM_POSITION=0.20 # Room position ratio 0.0-1.0 (lower = earlier room)
# TREASURE_EXIT_DISTANCE=0.85 # Distance from exit ratio 0.0-1.0 (higher = farther)
# =============================================================================
# SECTION 4: PAYMENT SYSTEM OVERVIEW
# =============================================================================
#
# PAYMENTS_ENABLED is the master switch:
# false = FREE mode, anyone can play, no crypto involved
# true = Paid mode, requires wallet RPC configuration
#
# PAYMENT_MODES determines HOW users pay (when payments enabled):
#
# ┌─────────────────────────────────────────────────────────────────────────┐
# │ MODE: direct │
# ├─────────────────────────────────────────────────────────────────────────┤
# │ • User pays X WOW per game │
# │ • If they WIN (escape dungeon): get PAYOUT_ESCAPE × X back (e.g., 2x) │
# │ • If they WIN with treasure: get PAYOUT_TREASURE × X back (e.g., 3x) │
# │ • If they LOSE (die): house keeps the payment │
# │ │
# │ Example: Pay 1 WOW, win = get 2 WOW. Die = lose 1 WOW. │
# └─────────────────────────────────────────────────────────────────────────┘
#
# ┌─────────────────────────────────────────────────────────────────────────┐
# │ MODE: credits │
# ├─────────────────────────────────────────────────────────────────────────┤
# │ • User buys a PACKAGE of credits upfront (e.g., 10 credits for 5 WOW) │
# │ • Each game costs 1 credit (or CREDITS_PER_GAME) │
# │ • Packages can include bonus credits (bulk discount) │
# │ • Payouts are optional - credits are usually just for playing │
# │ │
# │ Example: Buy 10 credits for 5 WOW = 0.5 WOW/game (50% discount!) │
# └─────────────────────────────────────────────────────────────────────────┘
#
# ┌─────────────────────────────────────────────────────────────────────────┐
# │ MODE: direct,credits (both enabled) │
# ├─────────────────────────────────────────────────────────────────────────┤
# │ • Users can choose which mode to use │
# │ • If PREFER_CREDITS_FIRST=true, credits are auto-used when available │
# │ • Good for giving users flexibility │
# └─────────────────────────────────────────────────────────────────────────┘
# Master switch: Set to false for completely free play (no wallet needed)
PAYMENTS_ENABLED=true
# FREE_PLAY_ENABLED: offer FREE play as a CHOICE even when payments are on. Free games
# are recorded as game_mode=FREE and appear on the Pleb leaderboard (NOT the Hall of
# Champions, which is for paid games). Always effectively on when PAYMENTS_ENABLED=false.
#
# DEPLOYMENT PATTERNS
# • Mainnet prestige: free-to-play + sell service credits/entry, with NO PAYOUTS.
# No-payout design is not a legal conclusion; an independent operator needs its own review.
# PAYMENTS_ENABLED=true FREE_PLAY_ENABLED=true PAYOUTS_ENABLED=false
# DIRECT_PAYOUTS_ENABLED=false CREDITS_PAYOUTS_ENABLED=false
# DIRECT_REQUIRES_ADDRESS=false CREDITS_REQUIRES_ADDRESS=false (no payout = no address)
# • Test/stagenet: test mechanics can exercise payouts only with conspicuous no-real-value copy.
# Never accept or represent mainnet funds under a test-only profile.
# PAYMENTS_ENABLED=true PAYOUTS_ENABLED=true *_PAYOUTS_ENABLED=true
FREE_PLAY_ENABLED=true
# Which payment modes to enable (comma-separated)
PAYMENT_MODES=direct,credits
# =============================================================================
# SECTION 5: DIRECT MODE CONFIGURATION
# =============================================================================
# Only relevant if PAYMENT_MODES includes "direct"
# Enable/disable direct payments
DIRECT_PAYMENT_ENABLED=true
# Price per game in atomic units (100000000000 = 1 WOW)
DIRECT_GAME_PRICE=100000000000
# Must user provide a payout address before playing?
# true = User must set address first (ensures they can receive winnings)
# false = User can play without address (but can't receive payouts!)
DIRECT_REQUIRES_ADDRESS=false
# Allow guest play without any address? (Usually false for paid modes)
DIRECT_ALLOW_GUEST_PLAY=false
# Payout multipliers for direct mode wins:
# If user pays 1 WOW and ESCAPE multiplier is 2.0, they get 2 WOW on escape.
DIRECT_PAYOUTS_ENABLED=false
DIRECT_PAYOUT_ESCAPE=2.0 # Escape dungeon = 2x payment
DIRECT_PAYOUT_TREASURE=3.0 # Escape WITH treasure = 3x payment
# =============================================================================
# SECTION 6: CREDITS MODE CONFIGURATION
# =============================================================================
# Only relevant if PAYMENT_MODES includes "credits"
# Enable/disable credits system
CREDITS_ENABLED=true
# How many credits does one game cost?
CREDITS_PER_GAME=1
# Must user provide address for credits mode?
CREDITS_REQUIRES_ADDRESS=false
# When both modes enabled:
ALLOW_MIXED_MODE=true # Show both options to user
PREFER_CREDITS_FIRST=true # Auto-deduct credits if user has them
# Credits payouts (usually DISABLED so purchases grant service play, not prize eligibility)
CREDITS_PAYOUTS_ENABLED=false
CREDITS_PAYOUT_BASE=50000000000 # Base amount for credit wins
CREDITS_PAYOUT_ESCAPE=2.0 # Same as direct mode
CREDITS_PAYOUT_TREASURE=3.0 # Same as direct mode
# Optional credit-payout bounds. The global PAYOUT_MAX_PER_GAME below is always
# the outer safety cap, even when this mode-specific maximum is larger.
# CREDITS_PAYOUT_MIN=10000000000
# CREDITS_PAYOUT_MAX=10000000000000
# Credit packages - JSON array of available bundles
# Fields:
# id - Unique identifier (shown in UI)
# credits - Number of game credits included
# price - Cost in atomic units (as STRING to avoid JS number precision issues)
# bonus - Extra free credits (0 for no bonus)
#
# Default packages (small discounts to encourage bulk purchase):
# small: 10 credits for 9 WOW (~10% discount vs 1 WOW/game direct)
# medium: 20 credits for 17 WOW (~15% discount)
# large: 50 credits for 40 WOW (~20% discount)
#
# Tip: Format JSON with newlines for readability, then minify for .env:
# [
# {"id":"small", "credits":10, "price":"900000000000", "bonus":0},
# {"id":"medium", "credits":20, "price":"1700000000000", "bonus":0},
# {"id":"large", "credits":50, "price":"4000000000000", "bonus":0}
# ]
#
CREDITS_PACKAGES='[{"id":"small","credits":10,"price":"900000000000","bonus":0},{"id":"medium","credits":20,"price":"1700000000000","bonus":0},{"id":"large","credits":50,"price":"4000000000000","bonus":0}]'
# Credit packages can bundle cosmetic/render pack grants and a premium tier via
# a "grants" field. Example:
# CREDITS_PACKAGES='[{"id":"supporter_25","credits":20,"bonus":5,"price":"1000000000000","grants":{"packs":["generated-skins","kenney-3d-characters"],"premiumLevel":"supporter"}}]'
# Standalone products (no game entry or credits required). Each product may grant packs,
# a premium tier, and/or funded race tickets. Crypto-match tickets must declare an atomic
# value exactly equal to MATCH_ENTRY_FEE_ATOMIC, and the product price must cover every ticket.
# COSMETIC_PRODUCTS='[{"id":"pack_3d","label":"3D Character Pack","price":"250000000000","grants":{"packs":["kenney-3d-characters"]}}]'
# COSMETIC_PRODUCTS='[{"id":"race_2","label":"Two race entries","price":"10000000000","grants":{"race_entries":2,"race_entry_value_atomic":"5000000000"}}]'
# =============================================================================
# SECTION 6b: EARLY ENTRY
# =============================================================================
# Early entry lets players start a game immediately without waiting for the
# next block. Risk: if a new block arrives before they escape, the game ends.
#
# Disabled by default for direct (paid-per-game) mode since players paid for
# a full block window. Useful for free and credits modes.
# Master toggle
EARLY_ENTRY_ENABLED=true
# Allow early entry in free mode?
EARLY_ENTRY_FREE_MODE=true
# Allow early entry in credits mode?
EARLY_ENTRY_CREDITS_MODE=true
# =============================================================================
# SECTION 7: PAYOUT SETTINGS
# =============================================================================
# Controls how winnings are sent back to players.
# Payouts are batched for efficiency and to reduce transaction fees.
# Master payout switch. The Such-operated mainnet product sells credits for leaderboard prestige
# without crypto winnings. Its separate XMR stagenet test product uses 2x/3x test-coin payouts.
# This switch suppresses payout creation, block/batch dispatch, and retry workers.
PAYOUTS_ENABLED=false
# Production mainnet payouts are additionally fail-closed. Only set this true after legal review,
# bankroll/risk review, and a real wallet-RPC integration test. It is not needed on stagenet.
ALLOW_MAINNET_PAYOUTS=false
# Minimum payout amount (atomic units). Prevents dust transactions.
# 10000000000 = 0.1 WOW
PAYOUT_MIN_AMOUNT=10000000000
# Maximum payout per single game (safety limit)
# 10000000000000 = 100 WOW
PAYOUT_MAX_PER_GAME=10000000000000
# How often to process payout queue (seconds). 300 = every 5 minutes.
PAYOUT_BATCH_INTERVAL=300
# Confirmed incoming outputs must reach at least this many chain confirmations before granting
# a game, credits, cosmetics, or race tickets.
PAYMENT_CONFIRMATIONS=1
# Retry failed payouts this many times before marking as permanently failed.
# Failed payouts are logged with error details. Check logs or query:
# SELECT * FROM payouts WHERE status = 'failed';
# To retry a permanently failed payout, reset it with:
# UPDATE payouts SET status = 'pending', retry_count = 0 WHERE id = <id>;
PAYOUT_MAX_RETRIES=3
# Max payouts to send in one batch (wallet RPC can timeout on large batches)
MAX_PAYOUT_BATCH_SIZE=50
# How often to retry failed/stuck payouts (milliseconds). Default: 300000 (5 min)
# PAYOUT_RETRY_INTERVAL_MS=300000
# =============================================================================
# SECTION 8: ANTI-ABUSE LIMITS
# =============================================================================
# Protect against bots and abuse
MAX_GAMES_PER_HOUR=60 # Max games one user can play per hour
MAX_PAYOUTS_PER_DAY=100 # Max payout transactions per user per day
MAX_CREDIT_PURCHASE_PER_DAY=100000000000000 # Max credit purchase (1000 WOW)
GAME_COOLDOWN_SECONDS=5 # Minimum seconds between games
# =============================================================================
# SECTION 9: WALLET RPC - REQUIRED FOR PAID MODES
# =============================================================================
# The wallet RPC handles:
# 1. Generating unique payment addresses for each user
# 2. Checking for incoming payments
# 3. Sending payouts to winners
#
# You must run wownero-wallet-rpc (or monero-wallet-rpc) separately:
#
# wownero-wallet-rpc \
# --wallet-file /path/to/wallet \
# --password-file /path/to/root-readable-wallet-password \
# --rpc-bind-ip 127.0.0.1 \
# --rpc-bind-port 34570 \
# --rpc-login user:strong-random-rpc-password
#
# Production requires rpc-login even on loopback. The application deliberately proves that an
# unauthenticated request receives a Digest challenge; configured credentials do not make an
# unauthenticated wallet daemon safe. Never combine rpc-login with --disable-rpc-login, and never
# expose wallet RPC beyond the local host.
#
# The wallet must be synced with a daemon to see incoming transactions.
PRIMARY_WALLET_ENDPOINT=http://127.0.0.1:34570
# Required together in production:
# WALLET_RPC_USER=wownerogue
# WALLET_RPC_PASSWORD=replace-with-a-distinct-strong-rpc-password
# =============================================================================
# SECTION 10: BLOCKCHAIN DAEMON RPC
# =============================================================================
# Used to get current block height for game synchronization.
# This is the daemon (wownerod/monerod), NOT the wallet.
#
# The game syncs to block timing - each block triggers game state checks.
PRIMARY_RPC_ENDPOINT=http://127.0.0.1:34568
FALLBACK_RPC_ENDPOINT=http://127.0.0.1:34568
# OPTIONAL: additional daemons, comma or whitespace separated, in PREFERENCE ORDER.
# PRIMARY/FALLBACK above are appended to this list and the whole thing is deduplicated —
# note that the two defaults are the SAME host, so out of the box there is exactly one node
# and no redundancy at all.
#
# A fallback only helps if it can fail independently. A second daemon in the same rack (or the
# same office) shares the outage that takes the first one down, so it buys nothing; a node
# reachable over a separate path — a home node across the mesh, or a public/community node — is
# what actually adds availability.
#
# Every endpoint must still pass the chain-identity check before it may answer, so listing a
# remote node cannot silently serve a different chain's data. For FREE / CREDITS instances the
# daemon is only supplying block height, so a remote node is a reasonable fallback. For instances
# taking PAYMENTS, prefer daemons you control: block height feeds match fairness and entropy, and
# an untrusted node is an untrusted input to those.
#
# RPC_ENDPOINTS=http://127.0.0.1:34568,http://10.42.1.40:34568
#
# How long to stay on a backup before re-testing the preferred node (ms, minimum 1000).
# RPC_PREFERRED_RETRY_MS=60000
#
# When NO endpoint answers, the server does not guess: entries are refused with a clear message
# and nothing is charged. There is intentionally no wallet failover — two wallet-rpc processes
# over one wallet file can spend the same outputs — so a wallet outage declines paid intake while
# credits and free play keep working.
# How often to poll for new blocks (milliseconds)
RPC_POLL_INTERVAL=2000
# =============================================================================
# SECTION 11: ADMIN API
# =============================================================================
# Secure endpoints for refunds, credit adjustments, and user management.
# Generate a strong random key and keep it secret!
# Required in production. Generate with: openssl rand -hex 32
# ADMIN_API_KEY=your-64-character-hex-key-here
# Public operator and paid-play disclosure controls. Production paid instances fail startup
# until these are explicitly set to truthful, non-placeholder values.
# Independent deployments must identify their own operator. Such Software operates only
# play.wowne.ro and monerogue.app; it does not endorse or accept responsibility for self-hosts.
# OPERATOR_NAME=Responsible operator name
# OPERATOR_CONTACT_URL=mailto:support@example.com
# OPERATOR_CONTACT_LABEL=Support
# LEGAL_POLICY_VERSION=2026-07-22-v1
# TERMS_EFFECTIVE_DATE=2026-07-22
# MINIMUM_AGE=18
# PAID_ACKNOWLEDGEMENT_REQUIRED=true
# Leave unset for third-party/self-hosted deployments. Official templates set one reviewed value:
# OPERATED_PRODUCT_PROFILE=such-play-wow-prestige | such-monerogue-stagenet
# Optional plain-language location restriction notice supplied after legal review:
# RESTRICTED_LOCATIONS_NOTICE=
# Use in requests:
# curl -H "X-Admin-Key: your-key" http://localhost:3000/api/admin/...
# Allowed origins for admin API CORS (comma-separated, only needed for cross-origin)
# Same-origin requests are always allowed. Leave unset if admin panel is on same host.
# ALLOWED_ORIGINS=https://admin.example.com
# Set to 'true' ONLY when running behind a trusted reverse proxy (Nginx/Caddy). When
# true, the real client IP is read from the X-Forwarded-For header for rate limiting and
# req.ip. Leave unset/false for direct exposure, otherwise clients could spoof their IP.
# TRUST_PROXY=true
# TRUST_PROXY_HOPS=1 # NPM directly in front of Node
# Anti-instant-death grace (ms) before a block-timeout can end a game. This is NOT a
# fairness floor — random block timing is the core mechanic. It only prevents the
# degenerate case where a block lands the instant a game starts (before the dungeon
# renders / before the first move is possible). Default 2000 (2s); set 0 to disable.
# GAME_START_GRACE_MS=2000
# =============================================================================
# SECTION 13: ADMIN ALERTS (Resend)
# =============================================================================
# Email alerts for low wallet balance and critical issues.
# Sign up at https://resend.com to get an API key.
# Resend API key
# RESEND_API_KEY=re_xxxxxxxxxxxxx
# Admin email to receive alerts
# ADMIN_EMAIL=admin@example.com
# From address for alert emails (must be verified in Resend)
# Default: alerts@monerogue.app
# ALERT_FROM_EMAIL=noreply@yourdomain.com
# -------------------------
# BALANCE THRESHOLDS
# -------------------------
# Two-tier alert system for wallet balance monitoring:
#
# BALANCE_WARN: Sends email alert when balance drops below this level
# You should top up the wallet soon.
#
# BALANCE_CRITICAL: Sends email AND HALTS NEW GAMES when balance drops below
# Users will see a modal: "Sorry, the house balance is too low..."
# Games resume automatically when balance is restored above this threshold.
#
# All values in atomic units:
# WOW: 1 WOW = 100000000000 (10^11)
# XMR: 1 XMR = 1000000000000 (10^12)
# Warning threshold - sends email alert (default: 0.1 WOW/XMR)
BALANCE_WARN=100000000000
# Critical threshold - halts new games (default: 0.01 WOW/XMR)
BALANCE_CRITICAL=10000000000
# Scan recently expired invoices for transfers that mined after the 30-minute watcher stopped.
# Valid receipts create manual-review records only; they never auto-grant stale entries/products.
LATE_PAYMENT_RECONCILE_HOURS=72
LATE_PAYMENT_RECONCILE_BATCH=100
# Legacy alias (superseded by BALANCE_WARN, kept for backwards compatibility)
# LOW_BALANCE_THRESHOLD=100000000000
# -------------------------
# OTHER ALERT SETTINGS
# -------------------------
# Alert when pending/failed payouts exceed this count
HIGH_PENDING_THRESHOLD=10
# Alert when payout processing or refund requested/processing remains nonterminal this long.
# These alerts never retry a transfer. Default: 900000 (15 minutes).
FINANCIAL_REVIEW_STALE_MS=900000
# Alert cooldown in milliseconds (avoid spam)
# Default: 3600000 (1 hour)
ALERT_COOLDOWN_MS=3600000
# =============================================================================
# SECTION 13b: OPTIONAL MAINNET FINANCIAL-EVENT EXPORT
# =============================================================================
# Confirmed payments and final refunds are snapshotted to a durable outbox. Configure both values
# only for a reviewed MAINNET accounting sink that honors Idempotency-Key. Test-network rows are
# suppressed locally and must never be exported. Keep the bearer token in the protected runtime
# environment; never commit it.
# FINANCIAL_EVENT_SINK_URL=https://ledger.operator.example/v1/events
# FINANCIAL_EVENT_SINK_TOKEN=CHANGE_ME_STRONG_ACCOUNTING_SINK_TOKEN
FINANCIAL_EVENT_ACCOUNT_REF=wowngeon:receipts
# FINANCIAL_EVENT_POLL_MS=60000
# FINANCIAL_EVENT_BATCH_SIZE=20
# FINANCIAL_EVENT_MAX_ATTEMPTS=8
# =============================================================================
# SECTION 14: SMIRK WALLET INTEGRATION
# =============================================================================
# Smirk is a browser extension wallet for Wownero/Monero.
# https://smirk.network
#
# Enable this for Wownero mainnet. Disable for Monero stagenet
# (Smirk doesn't support stagenet addresses).
# Enable Smirk wallet connection button (default: true)
# Set to false for Monero stagenet deployments
SMIRK_ENABLED=true
# =============================================================================
# SECTION 14b: BLOCK EXPLORER
# =============================================================================
# URL prefix for linking transaction hashes to a block explorer.
# Include the trailing slash. TX hash will be appended directly.
# Leave unset to disable clickable TX links in transaction history.
#
# Wownero: https://explore.wowne.ro/tx/
# Monero: https://xmrchain.net/tx/
EXPLORER_TX_URL=https://explore.wowne.ro/tx/
# =============================================================================
# SECTION 15: DEVELOPMENT/DEBUG OPTIONS
# =============================================================================
# These are for testing only. Don't use in production with real money!
# Block source: daemon (real blockchain) | simulated (fake blocks for testing)
# Paid modes always use daemon unless FORCE_SIMULATED_BLOCKS=true
BLOCK_SOURCE=daemon
# Force simulated blocks even in paid mode (DANGEROUS - for testing only!)
# FORCE_SIMULATED_BLOCKS=false
# =============================================================================
# LEGACY OPTIONS (deprecated - use PAYMENT_MODES instead)
# =============================================================================
# GAME_MODE: FREE | PAID_SINGLE | PAID_CREDITS
# Kept for backward compatibility. New setups should use PAYMENT_MODES.
# GAME_MODE=
CRYPTO_TYPE=WOW
# =============================================================================
# Tavern & Multiplayer modes (optional)
# =============================================================================
# Tavern: a walkable social room (chat, avatars, spectator camera).
TAVERN_ENABLED=true
# Server-tick / snapshot broadcast cadence in ms (default 100 = 10 Hz)
# TAVERN_TICK_MS=100
# =============================================================================
# Match mode (multiplayer races)
# =============================================================================
# Enable real-time multiplayer races. Solo/Tavern are unaffected.
MATCH_ENABLED=true
# Max players per match, also bounded by the selected ruleset (built-ins max at 8).
MATCH_MAX_PLAYERS=4
# Server tick interval in ms (default 250 = 4 Hz).
# MATCH_TICK_MS=250
# Server-selected match ruleset. Clients cannot choose this value.
# Built-ins: race, last-alive, score-attack, coop-escape. Default: race.
MATCH_RULESET_ID=race
# Paid matches freeze entrants at H, target H+2, and activate at target+1 by default.
# Production requires explicit safe integers from 2 through 100 for both settings.
MATCH_PAID_ENTROPY_DELAY_BLOCKS=2
MATCH_PAID_ENTROPY_CONFIRMATIONS=2
# Minimum race duration in ms before the next block can end it (default 20s).
# MATCH_MIN_DURATION_MS=20000
# Hard ceiling in ms after which a race is force-ended (default 4m).
# MATCH_HARD_CEILING_MS=240000
# Credits cost for prestige-only races (default 1).
# MATCH_CREDITS_COST=1
# Crypto race house fee percent. Production crypto matches require an explicit value from
# 0 (inclusive) through 100 (exclusive).
MATCH_HOUSE_FEE_PERCENT=5
# Required crypto-race per-player entry fee in atomic units when payout matches are enabled.
MATCH_ENTRY_FEE_ATOMIC=5000000000
# Crypto admission requires all three explicit gates plus a worst-case winner cap. Co-op has no
# winner-takes-pot split contract and is therefore rejected for crypto matches.
MATCH_CRYPTO_RACE_ENABLED=false
MATCH_PAYOUTS_ENABLED=false
MATCH_PAYOUT_MAX=50000000000