A verifiable, sink-driven token economy for on-chain gladiator combat on Solana.
Version 1.0 — July 2026 Author: Lisman Razvan (SECFORIT SRL)
SOL&Sandals is a turn-based gladiator combat game deployed on the Solana blockchain. It combines a deterministic, seedable client-side combat engine with three Anchor programs that govern asset ownership, a capped token economy, trustless PvP wagering, and an escrowed NFT marketplace. The GOLD token — the game’s sole unit of account — follows a 50-million-unit hard cap with halving-style emission eras, a suite of deflationary sinks (arena entry fees, exponential forge upgrades, cosmetic renames, and marketplace fees split 50/50 between burn and treasury), and staking-based reward bonuses gated by lockup periods and elite-tier appearance bonds. Every economic constant is implemented identically in Rust (on-chain) and TypeScript (client-side), covered by unit tests on both sides. This document describes the full technical architecture, the token economy design from first principles, the combat engine mathematics, and the trust model under which the system operates.
Blockchain games face a structural economic problem: every in-game action that creates tokens is a faucet, and without proportional sinks, supply grows monotonically. A token with unbounded supply and zero marginal demand converges to zero value. Most web3 games address this with deferred promises (future land sales, governance tokens, staking emissions that print more tokens). SOL&Sandals inverts the model: the sinks are not future work — they are the core loop. Every time a player fights above tier 0, forges gear, renames their gladiator, or trades on the marketplace, a measurable fraction of GOLD is permanently destroyed or locked.
GameConfig exposes total_minted,
total_burned, and total_staked on-chain so
anyone can audit the real float.| Layer | Technology |
|---|---|
| Blockchain | Solana (Agave 3.0.x, devnet) |
| Smart contracts | Anchor 0.32.1 (Rust) |
| BPF toolchain | Solana platform-tools v1.52 (rustc 1.89) |
| Frontend | React 18, TypeScript, Vite 5 |
| Wallet integration | @solana/wallet-adapter (Phantom, Solflare) |
| NFT standard | Metaplex Token Metadata |
| Token standard | SPL Token (0 decimals) |
| Testing | Mocha (Anchor), Vitest (frontend), cargo test (unit) |
The system is divided into four layers:
┌──────────────────────────────────────────────────────┐
│ React UI (Vite) │
│ ┌─────────────┐ ┌──────────────┐ ┌─────────────┐ │
│ │ Game Engine │ │ Wallet Layer │ │ State/Store │ │
│ │ (pure TS) │ │ (adapters) │ │ (local) │ │
│ └──────┬──────┘ └──────┬───────┘ └─────────────┘ │
└─────────┼────────────────┼───────────────────────────┘
│ │
▼ ▼
┌──────────────────────────────────────────────────────┐
│ Solana Devnet │
│ ┌────────────┐ ┌───────────┐ ┌───────────────────┐ │
│ │ arena-core │ │arena-wager│ │ marketplace │ │
│ │ GOLD mint │ │ PvP escrow│ │ NFT escrow (GOLD) │ │
│ │ profiles │ │ settle │ │ list/buy/cancel │ │
│ │ forge/rename│ │ timeout │ │ 5% fee burn/treas│ │
│ │ staking │ │ │ │ │ │
│ └────────────┘ └───────────┘ └───────────────────┘ │
│ ┌────────────────────────────────────────────────┐ │
│ │ Metaplex Token Metadata (NFTs) │ │
│ └────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────┘
| Program | ID |
|---|---|
| arena-core | Ghp3KCDNnzhUDF4VMGbZwnb7AtzX1yBzRW5tRAZ6YXmt |
| arena-wager | 2Z8gJ1nB64qkkR6CLnygGj4muj6YN1cN6WSWYw76nqJ6 |
| marketplace | iRxYaR4KPcrxeBmqzrR45jWT5n4YzeEWjbWFfqHyvw1 |
The three programs are loosely coupled — they share no direct CPI calls. They interact only through the shared GOLD SPL token. This means each program can be upgraded, redeployed, or replaced independently without breaking the others, as long as the GOLD mint and treasury account addresses remain stable.
The combat engine is 100% pure TypeScript with zero dependencies. It
runs client-side in milliseconds, is fully deterministic (seeded PRNG),
and is covered by 34 unit tests. The engine lives in
app/src/game/ across seven modules: combat.ts,
ai.ts, items.ts, progression.ts,
rng.ts, types.ts, opponents.ts,
and fight.ts.
| Stat | Role |
|---|---|
| Strength | Raw melee damage multiplier. Each point adds 0.8 damage to successful hits (scaled by morale). |
| Attack | Hit probability. The primary factor in the hit formula (2× attack). |
| Defense | Damage reduction. Soaks 60% of the stat value from each hit; doubled effectiveness while blocking. |
| Vitality | Hit points. HP = 40 + vitality × 6. Also boosts rest healing. |
| Charisma | Powers taunting (a contest against the opponent’s charisma) and casting (bolt damage = charisma × 1.2). Also resists enemy taunts. |
| Agility | Crit chance (+1% per point on top of 5% base) and dodge chance (1.5× multiplier in the evade score). |
Players choose one action per turn. The AI opponent chooses simultaneously via its personality-driven weight system.
The core action. Hit probability is a ratio contest:
hitChance = (atk×2 + agi) × moraleMult(A) / [(atk×2 + agi) × moraleMult(A) + (def×0.5 + agi×1.5) × moraleMult(D)]
Brace until next turn. Damages taken are reduced to 35%. Restores 5 morale. The block stance lapses automatically when the blocker’s next turn begins. The AI notices blocking and shifts toward taunts and casts (which partially or fully ignore armor).
Spend 3 focus (built at +1/turn, capped at 3) to hurl an arcane bolt.
Ignores armor entirely — defense does not reduce cast damage. Blocking
still helps (damage reduced to 60% instead of 35%). Damage formula:
roll(4,8) + charisma × 1.2. Erodes 6 morale. Casting
without enough focus causes a fizzle: the caster loses 5 morale from the
crowd’s jeers.
The signature mechanic. A charisma contest:
power = charisma(A) × 2 + roll(0,10)
resist = charisma(D) + roll(0,10)
min(30, 8 + (power - resist) × 0.8) morale. Attacker gains
4.Recover roll(6,10) + vitality/4 HP and 10 morale.
However, the resting fighter is exposed: incoming
damage until their next turn is increased (the block multiplier of 0.35
does not apply, and the rest action does not set
blocking = true — the fighter takes full damage).
Morale ranges from 0 to 100 and is the combat differentiator. Below 50 (the “shaken” threshold), attack and defense are penalized by a linear multiplier from 1.0 down to 0.6 at 0 morale. At 0 morale, a fighter may flee (35% per taunt received). Morale is damaged by being hit, being taunted, and fizzling a cast. It is restored by blocking, resting, dodging an attack, and successfully taunting. This creates a second dimension of combat: you can win by depleting HP, or by breaking your opponent’s nerve.
Five personality archetypes govern opponent decision-making via weighted random action selection:
| Personality | Attack | Block | Cast | Taunt | Rest |
|---|---|---|---|---|---|
| Aggressive | 6 | 1 | 2 | 1 | 0.5 |
| Defensive | 3 | 4 | 1 | 1 | 1.5 |
| Trickster | 3 | 1 | 3 | 4 | 1 |
| Berserker | 8 | 0.2 | 0.5 | 1 | 0.2 |
| Showman | 3 | 1 | 2 | 5 | 1 |
These weights are dynamically modified by the fight state: - Low HP (<35%) doubles block weight and adds +3 to rest (except berserkers, who never rest). - Enemy morale ≤25: +4 to taunt weight (smell blood). - Enemy blocking: attack weight halved, +2 to taunt (chip morale instead of swinging into a shield). - Enemy HP <20%: +6 to attack, rest weight set to 0.1 (finish them). - Cast weight drops to 0.1 when focus < 3 (can’t cast yet).
Combat uses the mulberry32 algorithm, a fast 32-bit PRNG:
a = a + 0x6D2B79F5
t = imul(a ^ (a >>> 15), 1 | a)
t = t + imul(t ^ (t >>> 7), 61 | t)
return ((t ^ (t >>> 14)) >>> 0) / 4294967296
Every fight is seeded. Given the same seed and action sequence, the fight replays identically. This is the foundation for on-chain fight verification: the seed can be committed before the fight, and the action sequence submitted afterward for a verifier contract to replay and confirm the outcome. Chance values are clamped to [0.02, 0.95] so nothing is probabilistically certain.
Ten opponents, tier 0 through 9, each with unique stats, equipment, personality, taunt lines, and flavor text:
| Tier | Name | Personality | Notable |
|---|---|---|---|
| 0 | Fyodor the Unfortunate | defensive | Tutorial opponent. Rusty gladius, cloth tunic. |
| 1 | Livia the Alley Cat | trickster | High agility (9), spear, sandals. |
| 2 | Brutus the Wall | defensive | Defense 11, tower shield, chainmail. |
| 3 | Cassia the Flame | showman | Charisma 12. The crowd favorite. |
| 4 | Ragnar the Red | berserker | Strength 13, vitality 12. Never rests. |
| 5 | Seneca the Serpent | trickster | Attack 12, agility 12, falx. |
| 6 | Octavia the Iron Rose | aggressive | Plate armor, champion helm. Elite tier (bond required). |
| 7 | Maximus the Mountain | aggressive | Strength 16, vitality 16, titan cleaver. |
| 8 | Nyx the Whisper | trickster | Charisma 15, agility 16, dreadlord cuirass. |
| 9 | Imperator Sol | showman | All stats 12–18, full legendary gear. Undefeated in 100 bouts. |
The GOLD token (SPL, 0 decimals, mint authority held by the
arena-core PDA) is the sole medium of exchange, unit of
account, and store of value within SOL&Sandals. Its supply policy is
designed to transition from inflationary bootstrapping to deflationary
maturity.
| Parameter | Value |
|---|---|
| Hard cap | 50,000,000 GOLD (lifetime) |
| Halving interval | Every 10,000,000 GOLD minted |
| Emission era | total_minted / 10,000,000 |
| Era scaling | base >> era (integer halving) |
| Registration stipend | 150 GOLD (era-scaled) |
| Win reward | (25 + 12×tier) GOLD (era-scaled) |
| Loss reward | 5 GOLD (era-scaled) |
| Daily cap | 600 GOLD per gladiator per slot-day |
| Slots per day | 216,000 (~24h at 400ms slots) |
The cap is on cumulative minted
(total_minted), not on circulating supply. Burns do not
reopen emission room — once minted, that unit counts against the cap
forever. This prevents the classic “burn and re-mint” dilution
attack.
Emission is demand-driven, not clock-driven. The faster the game grows, the sooner rewards halve. Early players are compensated for bootstrapping the economy; late-era players rely on the sink/velocity economy rather than issuance.
Every sink splits its payment by
TREASURY_SHARE_BPS = 5000: 50% burned, 50% routed
to the treasury PDA (burn takes the rounding remainder).
| Sink | Cost | Location |
|---|---|---|
| Arena entry fee | 2 × tier GOLD per fight | arena-core::record_fight |
| Forge upgrade | 100 × 2^gear_tier GOLD | arena-core::forge_upgrade |
| Rename | 25 GOLD | arena-core::rename_gladiator |
| Marketplace fee | 5% of sale price | marketplace::buy_item |
| Staking lockup | Variable (not destroyed, removed from float) | arena-core::stake_gold |
| Tier | Fee | Net on win (era 0) | Net on loss (era 0) |
|---|---|---|---|
| 0 | 0 | +25 | +5 |
| 1 | 2 | +35 | +3 |
| 3 | 6 | +49 | −1 |
| 5 | 10 | +73 | −5 |
| 7 | 14 | +97 | −9 |
| 9 | 18 | +121 | −13 |
Above tier 2, a loss is a net GOLD loss. This makes reckless farming of high tiers self-defeating.
| Tier | Cost to upgrade | Cumulative cost | Bonus |
|---|---|---|---|
| 0 → 1 | 100 | 100 | +2% |
| 2 → 3 | 400 | 700 | +6% |
| 4 → 5 | 1,600 | 3,100 | +10% |
| 6 → 7 | 6,400 | 12,700 | +14% |
| 8 → 9 | 25,600 | 51,100 | +18% |
| 9 → 10 | 51,200 | 102,300 | +20% |
The full forge ladder costs 102,300 GOLD — approximately 170 days of capped daily income — and the total bonus it unlocks (+20%) generates far less GOLD over a player’s lifetime than the sink cost. Forge is a net-negative GOLD flow: it exists to give late-game players something to burn toward, not to print more tokens.
Staking locks GOLD in a program vault, removing it from the circulating float. It serves two purposes:
The combined forge + stake bonus is capped at +40%. Bonuses multiply the base reward after era scaling but before the daily cap. The daily cap is always enforced — bonuses increase how fast you reach the cap, not the cap itself.
Staked GOLD is subject to a minimum lock period
(MIN_STAKE_LOCK_SLOTS = 300 on devnet, ~2 minutes; designed
for days on mainnet). Each new stake refreshes the lock timer.
The treasury PDA accumulates 50% of every sink payment. It is a program-owned token account with no direct withdrawal instruction in the current deployment — spend governance is deferred to Phase 3 (see §8). Planned uses: DEX liquidity seeding, tournament prize pools (recycled, not minted), buy-and-burn operations. The treasury also serves as an on-chain verifiable sink accumulator: anyone can read its balance and confirm the total GOLD drained from circulation.
At any point, the effective circulating supply is:
float = total_minted - total_burned - treasury_balance - total_staked
All four values are readable from GameConfig and the
treasury/stake vault token accounts. The economic claim is not that GOLD
is scarce, but that its float is transparent and its supply-side drivers
are fully constrained.
The central hub. Owns the GOLD mint authority (a PDA), manages gladiator identity, and records PvE fight results.
Accounts: - GameConfig — singleton PDA
at ["config"]. Stores authority, gold_mint, aggregate
counters. - GladiatorProfile — one PDA per NFT at
["gladiator", nft_mint]. Stores level, XP, W/L, rating,
cooldown, gear tier, daily emission tracking. -
StakeAccount — one PDA per owner at
["stake", owner]. Tracks staked amount and lock expiry.
Instructions: - initialize — creates
GameConfig, GOLD mint (PDA authority), treasury, stake vault. One-time.
- register_gladiator(name) — creates profile, mints
era-scaled stipend. Requires holding the NFT. -
record_fight(tier, won) — charges entry fee (burned +
treasury), verifies cooldown, checks bond, awards XP/rating, mints GOLD
(era-scaled, boosted by forge/stake, clamped by daily cap and supply
cap). Emits FightRecorded event. -
forge_upgrade — burns 100 × 2^tier GOLD,
increments gear tier. Emits GoldSunk. -
rename_gladiator(new_name) — burns 25 GOLD, updates name.
Emits GoldSunk. - stake_gold(amount) —
transfers GOLD to stake vault, records amount and lock. Emits
GoldStaked. - unstake_gold(amount) — returns
GOLD from vault after lock expires. Emits GoldUnstaked.
Trustless PvP betting. State machine: Open → Active → Settled/Canceled/Refunded.
Instructions: -
create_match(match_id, stake) — challenger escrows stake
into a match PDA vault. Any SPL mint accepted (client enforces GOLD).
Match is Open. - join_match — opponent matches
the stake. Match becomes Active. Clock restarts for
timeout. - settle_cooperative(winner) — both players
co-sign. Winner receives the pot (2× stake). Match is
Settled. - settle_by_arbiter(winner) — the
designated arbiter (a pubkey set at match creation, e.g., a game server
key) signs. Fallback for when a loser refuses to co-sign. -
cancel_match — creator reclaims stake from an
Open match nobody joined. - timeout_refund —
anyone can trigger a refund of both stakes after
SETTLE_TIMEOUT_SLOTS (9000 slots, ~1h on devnet). Funds can
never be permanently locked.
Security properties: - The vault authority is the match PDA — only the program can move escrowed funds. - Settle paths are gated by signature checks (cooperative: both players; arbiter: the designated key). - The timeout path is permissionless after the slot threshold: no signature is required from either player. This is the ultimate escape hatch.
Escrowed NFT listings priced in GOLD. One listing per NFT mint.
Instructions: - init_market — one-time
setup pinning the payment mint, treasury, and authority. -
list_item(price) — seller escrows the NFT into a listing
PDA vault. - buy_item — buyer pays the seller (price −
fee), burns half the fee, routes half to treasury, receives the NFT.
Listing and vault are closed; rent returns to the seller. Emits
ItemSold. - cancel_listing — seller reclaims
the NFT, closes the listing and vault.
Fee structure: 5% of sale price. Split 50/50 between burn and treasury (2.5% each). For a 100 GOLD sale: seller receives 95, 3 GOLD burned, 2 GOLD to treasury.
| Screen | Description |
|---|---|
| Home | Wallet connect, gladiator summary, quick actions |
| Character Creation | Name, 15 stat points allocation, SVG appearance (skin/hair/warpaint) |
| Ladder | 10 opponents with stats preview, fight initiation |
| Fight | Turn-by-turn animated combat, action buttons, combat log, HP/morale bars, SVG fighters |
| Stats | Level, XP, stat allocation, equipment view |
| Shop | 22 items across 5 slots, buy/sell, level-gated |
| Forge | GOLD-burning gear upgrades with cost preview |
| PvP | Create/join wager matches, simulate fight, settle |
| Marketplace | NFT listings (list/buy/cancel), GOLD-denominated |
| Leaderboard | On-chain ranking by Elo rating from
getProgramAccounts |
The gladiator is rendered as an inline SVG with customizable
appearance (skin tone, hair style, hair color, warpaint) set at
character creation. Equipment changes the rendered character: each item
carries a hue value that tints the corresponding body part
(weapon in hand, shield on arm, armor on torso, helmet on head, boots on
feet). This creates visible progression — a fresh gladiator in a cloth
tunic looks fundamentally different from a tier-10 champion in Dreadlord
Cuirass wielding a Titan Cleaver.
record_fight is self-reported by the
NFT holder’s wallet. The program trusts the caller’s
won: bool and tier parameters. This is
acceptable for a devnet demo where GOLD has no real-world value. The
following mitigations bound the damage of forged wins:
| Mitigation | Mechanism |
|---|---|
| Slot cooldown | 150 slots (~60s) between fights per gladiator |
| Entry fees | Claims above tier 0 cost real GOLD first |
| Daily cap | Max 600 GOLD/day/gladiator, regardless of wins |
| Supply cap | 50M lifetime; mass-farming accelerates halving, gutting margins |
| Elite bonds | Tiers 6–9 require locked capital |
| Public audit | total_minted, total_burned,
total_staked on-chain |
The combat engine is already deterministic and seedable. The production verification path is:
Commit-reveal: Before a fight, the player commits to a seed hash on-chain. After the fight, they submit the (seed, action_sequence). An on-chain verifier replays the engine, confirms the outcome, and only then mints rewards.
Signed oracle: A game server (the same key that
serves as arbiter in PvP wagers) signs fight results. The
program verifies the signature against a known oracle pubkey.
Both approaches are compatible with the current engine without modification. The daily cap, entry fees, and bonds remain valuable as defense-in-depth even with verified fights.
update_price instruction
exists.GameConfig,
GladiatorProfile, and Market accounts changed
layout with the economy update. Existing devnet deployments need a fresh
deploy or a migrate_* reallocation instruction (not
implemented; documented in ECONOMY_DESIGN.md).The economic claim is narrow and defensible: given organic demand for the game, GOLD can hold value, whereas an unbounded-faucet token provably cannot. The mechanisms:
Utility demand. GOLD is required for: arena entry above tier 0, forge upgrades, elite bonds, renames, marketplace purchases, and PvP stakes. A player who wants to progress must acquire GOLD — either by playing or by buying from other players.
Burn deflation. Every sink destroys ≥50% of what it collects. Once emission eras advance, net supply growth can turn negative while activity is high. Marketplace burn scales with trade volume, which grows with player count.
Lockup constrains float. Bonds + staking remove a structural fraction of supply. Progression forces lockup — to farm the best arenas, you must first lock GOLD.
Hard cap enables pricing. 50M lifetime units, verifiable on-chain. A market can price a capped asset; it cannot price an unbounded one.
Honest assumptions. This holds only if (a) the game retains players — token design cannot rescue a game nobody plays; (b) fight verification becomes trust-minimized; (c) real liquidity exists (Phase 3). The system is designed to be compatible with value accrual, not to guarantee it.
| Era | Minted range | Faucet scale | Registration | Win (tier 0) |
|---|---|---|---|---|
| 0 | 0 – 10M | 100% | 150 | 25 |
| 1 | 10M – 20M | 50% | 75 | 12 |
| 2 | 20M – 30M | 25% | 37 | 6 |
| 3 | 30M – 40M | 12.5% | 18 | 3 |
| 4 | 40M – 50M | 6.25% | 9 | 1 |
| 5+ | ≥50M | 0% | 0 | 0 |
At era 5 the cap is reached and all emission stops. Fights still grant XP and rating — GOLD emission simply ends. The economy thereafter runs entirely on velocity: existing GOLD circulates through wagers, marketplace trades, entry fees, and forge upgrades.
Maximum faucet: 600 GOLD/day (hard cap). Maximum sink (theoretical): 18 GOLD/fight × 5 fights/day (cooldown-bounded) = 90 GOLD/day in entry fees. Forge at tier 9→10: 51,200 GOLD (one-time, ~85 days of capped income). Net daily: At the cap, even a 100%-win-rate tier-9 farmer (implausible without verification) nets at most 600 − 90 = 510 GOLD/day — but the forge curve ahead of them will consume it all. A realistic mid-tier player (tier 5, mixed W/L) nets 50–150 GOLD/day after entry fees.
The sink/faucet balance is not perfectly symmetric at launch — that would make the game unplayable. It is designed so that early eras are net-inflationary (bootstrapping) and late eras are net-deflationary (maturity), with the crossover determined by actual player activity rather than a calendar date.
SOL&Sandals is not a token with a game attached. It is a game whose economic design makes the token necessary, scarce, and auditable. The combat engine is fast, deterministic, and fully testable. The on-chain programs are minimal — three contracts, one token, no oracles, no dependencies between programs. The sinks are the core loop: every time a player fights, forges, renames, or trades, GOLD leaves circulation. The emission schedule is capped and decaying. The treasury exists but cannot print.
The system makes no promises about price. It makes a verifiable promise about supply. The rest depends on whether people want to fight in the arena.
| Constant | Value | Location |
|---|---|---|
MAX_GOLD_SUPPLY |
50,000,000 | arena-core, progression.ts |
HALVING_INTERVAL |
10,000,000 minted | arena-core, progression.ts |
STARTING_GOLD |
150 (era-scaled) | arena-core, progression.ts |
BASE_WIN_GOLD |
25 + 12·tier | arena-core, progression.ts |
LOSS_GOLD |
5 | arena-core, progression.ts |
BASE_WIN_XP |
40 + 20·tier | arena-core, progression.ts |
LOSS_XP |
15 | arena-core, progression.ts |
FIGHT_COOLDOWN_SLOTS |
150 | arena-core |
MAX_TIER |
9 | arena-core |
ENTRY_FEE_PER_TIER |
2 | arena-core, progression.ts |
DAILY_GOLD_CAP |
600 | arena-core, progression.ts |
SLOTS_PER_DAY |
216,000 | arena-core |
TREASURY_SHARE_BPS |
5,000 (50%) | arena-core, progression.ts |
FORGE_BASE_COST |
100 | arena-core, progression.ts |
MAX_GEAR_TIER |
10 | arena-core, progression.ts |
GEAR_BONUS_PCT_PER_TIER |
2% | arena-core, progression.ts |
MAX_GEAR_BONUS_PCT |
20% | arena-core, progression.ts |
STAKE_BONUS_DIVISOR |
50 GOLD per +1% | arena-core, progression.ts |
MAX_STAKE_BONUS_PCT |
20% | arena-core, progression.ts |
TIER_BOND_FREE_TIERS |
6 | arena-core |
TIER_BOND_STEP |
50 GOLD | arena-core |
MIN_STAKE_LOCK_SLOTS |
300 | arena-core |
RENAME_COST |
25 | arena-core, progression.ts |
MARKET_FEE_BPS |
500 (5%) | marketplace, progression.ts |
SETTLE_TIMEOUT_SLOTS |
9,000 | arena-wager |
FOCUS_COST |
3 | combat.ts |
MAX_MORALE |
100 | combat.ts |
SHAKEN_THRESHOLD |
50 | combat.ts |
FLEE_CHANCE_AT_ZERO |
0.35 | combat.ts |
POINTS_PER_LEVEL |
3 | progression.ts |
CREATION_POINTS |
15 | progression.ts |
BASE_STAT |
5 | progression.ts |
BASE_HP |
40 | progression.ts |
HP_PER_VITALITY |
6 | progression.ts |
Level n requires 50 × n × (n−1) total XP: -
Level 1: 0 XP - Level 2: 100 XP - Level 3: 300 XP - Level 5: 1,000 XP -
Level 10: 4,500 XP - Level 20: 19,000 XP - Level 50: 122,500 XP (max
level)
Repository: github.com/navzar97/gladiator-arena License: MIT