Skip to content
DevnetTest network: tokens have no real value.What this means

Fairness & security

Smart contract

Stakes on OHKO are held by ohko_escrow, an Anchor program on Solana devnet. It escrows both stakes, pays the winner, splits fees into its vaults, burns $OHKO, runs sit-and-go tournaments and pays season prizes. The game server cannot move escrowed funds except through the rules below, and every match can be refunded even if OHKO disappears.

Addresses

  • Escrow programDaKW9RdxAKPd8WDcXuG7j7hU8cccPXg7tzc795mXxh9S
  • $OHKO mintBkhwZUpyJWSNks93vpJJGvgfVjPwaSeFokGc2k9xcCjw
  • Mock USDC mint23Wz74M4x3RFXJYdtT5UMTLL3jjxBQNizqYQ1bFME3wW
  • Treasury vaultCZUVbMxMB4otqwfMKiFNpKe74gQobnAymhjkkh1Lc83x
  • Buyback vault7ZVgdCGhLaHgKeoezX2ynCPE1tKLJrNHhbYC5Gtp9wJN
  • Season vault21YaCJEeW1TLnVJca3CeZnPZhy5ZjzJZPXkAxmeVnNQ3
  • Admin4YpmgCxJ1jfMN1qboWWtCRdanxYusyASuv551cC3fiVH
  • Referee9JUj5WyT9dwKdC5dNYtLxrByKy8ZbadHmCtb1bRamC7V
  • KeeperHdfLmkoKNQpnsZbHD3x52Y3qQcQ68F3sY92SfvAYq4E4

The program's IDL ships with the OHKO SDK (packages/sdk), which also contains typed instruction builders, account decoders and an exact copy of the fee math.

Accounts

All accounts are program-derived addresses (PDAs):

AccountSeedsHolds
Config["config"]Admin, referee and keeper keys, pause flag, rake per currency, fee split, discount tiers, stake limits per currency, deadlines, prize splits, the allowed mints and vaults
PlayerProfile["profile", wallet]The wallet, its referrer (set once) and when it was set, match statistics
Match["match", id]Creator, opponent, currency, stake, format, seed_commitment, state, deadlines, join slot and slot hash, rake applied, snapshotted referrers, result and battle_log_hash. SOL stakes are its lamports
Match escrow["escrow", match]USDC or $OHKO stakes, in a token account owned by the match PDA
Tournament["tournament", id]Size, entry, currency, format, seats, bracket results, prize split and seed commitment. SOL entries are its lamports
Tournament escrow["tournament_escrow", tournament]USDC or $OHKO entries
Vault["vault", 0 / 1 / 2]Treasury, buyback and season vaults (SOL as lamports, tokens in token accounts the vault owns)
Season["season", id]A published season payout: Merkle root, totals and which entries were paid

Match states are Open (created, waiting for the opponent), Active (both stakes in), then closed by settlement, a draw, a cancel or a refund. Closed match accounts are deleted and their rent returns to the creator.

Instructions

InstructionWhoWhat it does
initialize_configUpgrade authorityCreates the config and the three vaults once
update_configAdminReplaces economy parameters and the referee/keeper keys within the hard caps
set_pausedAdminPauses new matches, joins and tournaments; never blocks settlement or refunds
transfer_adminAdminStarts a two-step admin handover
accept_adminPending adminCompletes the handover
init_player_profilePlayerCreates the player's profile
set_referrerPlayerRegisters a referrer once; never the player itself
create_matchCreatorDeposits the creator's stake with the server's seed commitment, optionally locked to one opponent
join_matchOpponentDeposits the opponent's stake, records the slot hash and makes the match Active
cancel_matchCreatorRefunds an Open match before anyone joins
settle_matchRefereePays the winner, splits the fee into the vaults, pays referrers, burns $OHKO rake, records battle_log_hash
settle_drawRefereeRefunds both players in full
refund_expiredAnyoneRefunds an Open match after its join deadline, or both players of an Active match after its settle deadline
create_tournamentRefereeOpens a sit-and-go table with a committed master seed
join_tournamentPlayerTakes a seat and deposits the entry; the last seat starts the tournament
report_tournament_matchRefereeRecords the winner of one bracket match with its log hash
payout_tournamentAnyonePays the podium of a completed bracket and the fees
refund_tournamentAnyoneRefunds every seat of a table that did not fill or missed its settle deadline
withdraw_treasuryAdminWithdraws revenue from the treasury vault
withdraw_buybackKeeperReleases SOL or USDC from the buyback vault for a swap (never $OHKO)
burn_from_vaultKeeperBurns $OHKO held by the buyback vault
publish_seasonAdminPublishes a season's Merkle root and totals (the vault must already hold them)
distribute_seasonAdminPays published season entries in batches, each proven against the root and paid once

Events

Every state change emits an event, so indexers (OHKO's own fee ledger included) can rebuild the history from transactions alone:

EventEmitted when
ConfigInitializedThe config is created
ConfigUpdatedParameters or keys change
PausedSetThe pause flag changes
AdminTransferStartedAn admin handover starts
AdminTransferredThe new admin accepts
ProfileCreatedA player profile is created
ReferrerSetA player registers a referrer
MatchCreatedThe creator deposits (includes the seed commitment)
MatchJoinedThe opponent deposits (includes the slot hash)
MatchCancelledThe creator cancels
MatchSettledThe referee settles (winner, payout, fee split, log hash)
MatchDrawnA draw refunds both players
MatchRefundedAn expired match is refunded
ReferralPaidA referrer is paid during settlement
ReferralRedirectedA referral too small for an empty wallet stays in the treasury
OhkoBurned$OHKO is burned (table fees, tournaments, buybacks)
VaultWithdrawnThe admin or keeper withdraws from a vault
TournamentCreatedA tournament table opens
TournamentJoinedA player takes a seat
TournamentStartedThe last seat is taken
TournamentMatchReportedA bracket result is recorded
TournamentPaidOutThe podium is paid
TournamentEntryRefundedOne seat is refunded
TournamentRefundedEvery seat of a table has been refunded
SeasonPublishedA season's payout root is published
SeasonPaidA batch of season entries is paid

Security model

  • Checked math everywhere, with 128-bit intermediates for basis-point math. Rounding dust goes to the treasury (or is burned on $OHKO tables).
  • Strict account checks: owners, mints, signers, PDA seeds and account relationships are verified before any handler runs. Payouts can only go to the match's players, the seated players or podium of a tournament, or the configured vaults.
  • Hard caps: the rake is at most 10%, splits sum to 100%, discount tiers can only lower the rake, deadlines stay between one minute and 30 days.
  • Pause never traps funds: it blocks new matches, joins and tournaments, never settlements, cancels or refunds.
  • No minting: the program can burn $OHKO but never mint it.
  • Front-running protection: initialize_config is restricted to the upgrade authority, and a staked match is locked to the paired opponent's wallet.
  • Every program error has its own entry in OHKO's error catalog, with a plain-language explanation (see FAQ & troubleshooting).

The full threat model with every check per instruction is in programs/ohko_escrow/SECURITY.md in the repository.

Trust assumptions

  1. The referee decides results. The program cannot run a battle, so the referee key (held by the game server) reports the winner. It can only pay one of the two players of the match, and only before the settle deadline; every settlement commits a log hash anyone can verify (see Provably fair). A compromised referee could misreport active matches until the key is rotated, but could never pay itself.
  2. The keeper handles buyback funds. It may withdraw SOL and USDC from the buyback vault (30% of fees since the last buyback) to swap them. Every withdrawal and burn is an on-chain event.
  3. The admin sets parameters within the caps and withdraws revenue. Mainnet requires a multisig admin.
  4. The upgrade authority can replace the program. Mainnet requires a multisig or timelock and a verifiable build.
  5. Holder discounts read current balances at create and join. Borrowing $OHKO to qualify costs nothing but lowers that match's fee by at most 1.5 points; it never risks player funds.

Refund guarantees

  • Nobody joined: the creator can cancel at any time, and anyone can refund after the join deadline.
  • The referee never settled: after the settle deadline anyone can call refund_expired, and both players get their full stake back. The OHKO app shows a Claim refund button, and the server's own keeper sends it automatically.
  • A tournament never filled or stalled: after its deadline anyone can call refund_tournament and every seat is refunded.
  • These refunds work while the program is paused and even if OHKO's servers are gone: any Solana client can send them.