Documentation · v1

How Gacha Royale works, precisely.

This document specifies the complete mechanics and economics of Gacha Royale: what a spin does, where every lamport goes, what the game returns to players in expectation, and why none of it requires trusting the operator. Everything below is a property of the on-chain program, not of this website — each claim comes with the means to check it.

devnetprogram 5f1F3YFDnJsYqbcju31Mv2yNYtA3RnGidSMX2YggbavRreturn to player 84.405% · published
01

Abstract

Gacha Royale is a game of chance on Solana with one deliberate property: nothing about it is private except the operator's infrastructure. A spin costs 0.3 SOL and wins a seat on a shared 100-seat board with probability exactly ½, decided by a verifiable random function (ORAO VRF) rather than by anything we run. Seats earn a share of every subsequent spin. When the board is full, each new winner takes over one seat chosen at random; the outgoing player is paid automatically — their escrowed exit plus everything the seat accrued.

Three claims distinguish the design, and each is a theorem about the program rather than a promise from a team. First, the odds are exact: a 50/50 whose outcome anyone can recompute from public data (§05). Second, the economics are total: every parameter is a compile-time constant, and the aggregate return to players — 84.405% of all SOL wagered — is published along with the operator's complement of 15.595% (§04). Third, the program cannot become insolvent: what it may owe is capped by what it holds, checked on every spin (§06).

Denomination note. All figures in this document are stated at mainnet denomination (0.3 SOL per spin). The current devnet deployment runs at exactly one-tenth denomination (0.03 SOL per spin); every ratio — odds, return to player, fee split, solvency margins — is preserved to the lamport.
02

The lifecycle of a spin

A spin is not one event but three, and the separation is what makes the game verifiable end to end.

1 · Request

Your wallet sends request_spin. The program collects 0.3 SOL, derives a unique seed from the request account, your public key, and a nonce, and asks ORAO's verifiable random function for the bytes that will decide the outcome. The request joins a strict first-in, first-out queue: no spin can be settled out of order, reordered by the operator, or skipped.

2 · Randomness

ORAO's oracle network fulfills the request by writing 64 bytes of randomness — and the cryptographic proof that they were generated correctly — to an account derived from your seed. Neither we nor you can influence the value; both of us can check it.

3 · Settlement

Anyone — our keepers, you, a stranger — may settle the queue head once its randomness is fulfilled. The outcome is one line of arithmetic: interpret the first eight bytes as an unsigned integer, little-endian; even wins, odd doesn't.

outcome = u64::from_le_bytes(randomness[0..8]) % 2 // 0 → seat, 1 → no seat

Settlement takes exactly one of three paths:

  • No seat. The spin's 0.3 SOL is distributed to seated players and the treasury (§03), and the queue advances.
  • Seat, board not full. You occupy the lowest open position and your exit payout is escrowed the same instant (§03).
  • Seat, board full. A second draw from the same randomness selects one of the 100 seats uniformly; you take it over, and the outgoing player's payout is transferred in the same transaction. Their rotation ends; yours begins.

If ORAO fails to respond within 300 seconds, anyone may expire the request and the player reclaims the full 0.3 SOL. A queued spin therefore has exactly two futures: settled by the rules, or refunded in full.

03

Where every lamport goes

The program moves money along fixed rails. There are no discretionary flows, and the rails are compile-time constants — changing any of them is a source-code change that produces a different, publicly visible program.

EventMovementAmount
Spin without a seatto the pool (funds drip and exits)0.210 SOL
to the treasury (operator)0.090 SOL
Spin that wins a seatto the pool0.300 SOL
escrowed at once for that seat's exit0.357 SOL
Every settled spinreleased as drip, split equally across occupied seats0.0765 SOL
Seat takeoverto the outgoing player (escrow, net of 1% fee)0.35343 SOL
takeover fee to the treasury0.00357 SOL

At a full board the per-seat drip is exact: 0.0765 ÷ 100 = 0.000765 SOL per seat per spin. The outgoing player additionally receives every lamport of drip their seat accrued and had not yet claimed — leaving is always a payout, never a forfeiture.

These flows are not merely documented; they are enforced against each other. The program refuses to compile unless the following identities hold:

0.210 + 0.090 == 0.300 // a spin without a seat is fully distributed 0.00357 + 0.35343 == 0.357 // the exit escrow is fully distributed 0.357 − 0.300 + 0.0765 == 0.1335 // equity swing of a winning spin 0.210 − 0.0765 == 0.1335 // equity swing of a non-winning spin (antisymmetric)

The last two lines say something worth pausing on: a winning spin and a non-winning spin move the pool's equity by the same magnitude in opposite directions — the game is a fair-odds martingale over a published house margin, not a curve someone tuned.

04

Expected value, stated plainly

Most games of chance publish their odds reluctantly, if at all. Here the full expectation is short enough to derive by hand, so we do it in front of you. Figures assume the steady state — a full board — which is where the game spends nearly all of its life.

How long a seat lives

Each spin takes over a given seat with probability ½ × 1⁄100 = 0.5%. Seat lifetime is therefore geometric: 200 spins on average, with a median of ln 2 ÷ 0.005 ≈ 139 spins — half of all seats rotate out before their 139th spin, and long tenures are exponentially rare rather than impossible.

What a seat is worth

E[drip] = 200 spins × 0.000765 = 0.153 SOL E[win] = 0.35343 exit + 0.153 drip = 0.50643 SOL (+68.8% of the spin price) floor = 0.35343 exit alone = +17.81% even if the seat earns nothing

The floor deserves emphasis: because the exit is escrowed at the moment a seat is won, the worst possible outcome of a winning spin is +17.81%. Drip can only improve it.

Return to player

RTP = ½ × E[win] / price = 0.5 × 0.50643 / 0.3 = 0.84405

The aggregate return to players is 84.405% of all SOL wagered; the operator retains 15.595%. As a check, compute the house side independently: the treasury collects 0.09 on half of all spins and the 0.00357 takeover fee on the other half — 0.5 × 0.09 + 0.5 × 0.00357 = 0.046785 = 15.595% of 0.3. The same number arrives from opposite directions, which is what it means for an economy to be closed.

Read this before playing. An 84.405% return means that, averaged over all players and all time, each 1 SOL wagered returns 0.84405 SOL. Individual sessions vary enormously — that is the game — but no strategy, timing, or seat choice changes the expectation. Anyone telling you otherwise is selling something.
05

Randomness you can verify

Every claim about odds reduces to one question: where do the deciding bytes come from? Here they come from ORAO's verifiable random function — an oracle network that signs its randomness with a proof — and they are bound to your spin before they exist.

The binding works like this. The seed is derived deterministically from the spin request account, your wallet's public key, and a nonce; the randomness account's address is derived from that seed. By the time ORAO generates the bytes, the spin they will decide is already fixed on-chain — the operator cannot shop for outcomes, and neither can you.

Verification requires no cooperation from us. The repository ships a standalone script that, given any spin — yours or a stranger's — recomputes the seed, fetches the randomness and its proof from chain data, checks the proof against ORAO's public keys, and re-derives the outcome:

python3 scripts/verify_spin.py \ --request <SPIN_REQUEST_PDA> \ --payer <PAYER_PUBKEY> \ --nonce <N>

For the aggregate rather than the individual view, the verification page recomputes the published totals — spins settled, SOL paid out, realized return to player — from raw chain events and reconciles them against an independent RPC read, live, in your browser.

06

Solvency by construction

The catastrophic failure of games like this one is a payout the pool cannot cover. Gacha Royale makes that state unreachable rather than unlikely.

Define the pool's equity as its balance minus everything it could ever owe: every escrowed exit and every lamport of accrued, unclaimed drip. Each settled spin moves equity by exactly ±0.1335 SOL (§03). Before admitting a new spin, the program requires equity to cover the worst case of every pending spin plus the new one:

admit(spin) requires equity ≥ 0.1335 × (pending + 1)

If the condition fails, the spin is refused at the door — players see a solvency pause, which is the system working, not failing. The consequence is an invariant, not an aspiration: at every instant, every seat could rotate out and every accrued lamport could be claimed, and the pool would pay all of it. The invariant suite asserts this after every instruction, in every test, under both denominations.

07

Liveness and the limits of our power

A fair game you cannot exit is not fair. The design therefore treats the operator as a convenience, never a dependency, and enumerates exactly what we can and cannot do.

ActionWho can perform it
Settle a fulfilled spinAnyone. Our keepers run for liveness; a stranger's transaction settles identically.
Expire a stalled request (after 300 s) for a full refundAnyone.
Trigger an outgoing player's payoutAnyone — it is part of settlement itself.
Pause the gameThe operator — new spins only. Settlement, payouts, refunds and exits can never be paused, by anyone, including us.
Change the odds, prices, or feesNo one. They are compile-time constants; changing them means deploying visibly different code.

The asymmetry is deliberate: every power that protects players is permissionless, and the one power reserved to the operator can only stop money from coming in — never stop it from going out.

08

Fees and the treasury

The operator's revenue has exactly two sources, both visible in §03: 0.09 SOL from each spin that doesn't win a seat, and the 1% fee (0.00357 SOL) on each exit escrow at takeover. In expectation this totals 15.595% of turnover — the exact complement of the published return to player, because the economy has nowhere else for a lamport to go.

Treasury funds accrue in a program account and are withdrawn to the operations multisig. They fund what you would expect: oracle fees, infrastructure, audits, and the launch float that seeded the pool's solvency margin before the first spin.

09

Eligibility and responsible play

Before a wallet's first spin, the program requires an on-chain attestation: that the player is of legal age in their jurisdiction and accepts the current terms of service (version 1). The interface additionally gates play by jurisdiction. A wallet-level self-exclusion registry is enforced by the program itself — an excluded wallet's spins are refused at the door, by code, not by customer support.

Gacha Royale is entertainment with a known, published cost — not an investment, not an income, and not a puzzle with a winning strategy. The expected cost of play is 15.595% of whatever you wager. Decide what that entertainment is worth to you before your first spin, and play with money whose loss you would genuinely not mind.
10

Every parameter

The complete economic surface of the game. Names are the actual constants in the program source; a build in which any identity of §03 fails does not compile.

ParameterConstantValue
Spin priceSPIN_PRICE0.3 SOL
Win probabilityWIN_MODULUS = 2exactly ½
Board sizeBOARD_SIZE100 seats
Non-winning spin → poolMISS_TO_POOL0.21 SOL
Non-winning spin → treasuryMISS_TO_TREASURY0.09 SOL
Winning spin → poolWIN_TO_POOL0.30 SOL
Exit escrow (gross)EXIT_ESCROW_GROSS0.357 SOL
Takeover fee (1% of escrow)KICK_FEE0.00357 SOL
Exit paid, netEXIT_PAID_NET0.35343 SOL
Drip per spin (all seats)DRIP_PER_SPIN0.0765 SOL
Drip per seat, full board— derived0.000765 SOL
Equity swing per settled spinNET_EQUITY_DELTA±0.1335 SOL
Randomness timeout → refundREQUEST_TIMEOUT_SECS300 s
Launch floatLAUNCH_FLOAT30 SOL
Return to player— derived, §0484.405%
Operator margin— derived, §0415.595%

Devnet deployment: every lamport constant above divided by exactly 10; all ratios unchanged. Program: 5f1F3YFDnJsYqbcju31Mv2yNYtA3RnGidSMX2YggbavR. For the full formal treatment — proofs, event schemas, and the verification guide — read the whitepaper.

Read the whitepaperVerify the numbers liveBack to the site