Documentation · v1

How Gacha Wars works, precisely.

This document specifies the complete mechanics and economics of Gacha Wars: 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.

live on Solana mainnetprogram 5f1F3YFDnJsYqbcju31Mv2yNYtA3RnGidSMX2YggbavRreturn to player 84.405% · published
01

Abstract

Gacha Wars 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 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 pool is self-funding and players are structurally senior: the game launched with zero operator capital, and whenever player claims exceed pool cash, one hundred percent of the house's fees are permanently redirected to close the gap — the house is paid last, after every player, every time (§06).

Live figures. Every number in this document is the deployed mainnet value: 0.3 SOL per spin, 84.405% return to player, and the fee split below. They are compile-time constants in the on-chain program, not settings — you can read them back from the chain and they will match 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 an on-chain verifiable random function (MagicBlock's ephemeral-vrf) 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

The oracle answers by delivering 32 bytes of randomness together with the proof that they were generated correctly. The proof is an RFC 9381 ECVRF verified by the randomness program itself, on-chain, and the delivery is authenticated: only that program's identity may write an outcome onto your spin, and once written it can never be revised — not by us, not by the oracle. Typical delivery is under a second. 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 the oracle 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 MagicBlock's ephemeral-vrf — an RFC 9381 elliptic-curve VRF whose proof is verified on-chain by the randomness program itself, in the open, before your outcome can exist. The program is open source and independently audited.

The binding works like this. The seed is derived deterministically from the spin request account, your wallet's public key, and a nonce, and it is recorded on-chain the moment you pay — before any randomness exists. The oracle then delivers the bytes back into that exact spin. The operator cannot shop for outcomes, and neither can you.

Two properties make the delivery trustworthy without trusting anyone. First, only the randomness program's own identity may deliver: the game rejects an outcome signed by anything else, so a forged result is not merely detected, it is unconstructible. Second, randomness is write-once — once an outcome is recorded it can never be revised, by us or by the oracle. And a spin whose randomness never arrives is refundable in full by anyone after 300 seconds, so there is no state in which a paid spin simply disappears.

Verification requires no cooperation from us. Every settled spin publishes its randomness in an on-chain event alongside the seed it was bound to, so any observer can replay the whole history — yours or a stranger's — and recompute each outcome with one line of arithmetic:

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

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

Players first, house last

The catastrophic failure of games like this one is a payout the pool cannot cover. Gacha Wars answers it without a single lamport of operator capital: the pool launched empty and funds itself from play, with the house's own fee subordinated to every player claim.

Define the pool's backing gap as everything it owes — every recorded exit and every lamport of accrued, unclaimed drip — minus its cash. Exits only ever come due when the board is full, and filling the board pours roughly two hundred spins of revenue into the pool first, so the gap is an accounting number, not missing payout money. Whenever it is positive, the program permanently redirects one hundred percent of the house's fees into the pool until it closes:

gap > 0 ⟹ every house fee → the pool, forfeited forever

A miss repairs the gap by 0.2235 SOL against 0.1335 of damage per win, so closure is fast in expectation, and the treasury reads zero income for the entire life of any gap — the house is paid only when every player claim is fully cash-backed. Exits themselves pay in the same transaction as the winning spin in every reachable state; in the astronomically remote alternative (odds on the order of 10⁻⁴⁵), the exact amount becomes a numbered claim, first in line ahead of all fees, paid from the very next revenue. Nothing is ever reduced, cancelled, or renegotiated. The invariant suite asserts all of 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, and audits. Both fees are subordinated to players (§06): during any backing gap they are permanently forfeited into the pool instead — so the operator's realized take is provably at or below the published 15.595%, forever.

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 Wars 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%

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