mirror of
https://github.com/Such-Software/wownerogue.git
synced 2026-10-20 07:38:34 +02:00
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.
623 lines
30 KiB
Bash
623 lines
30 KiB
Bash
# =============================================================================
|
||
# 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
|