The exact smart contract that holds your prize pools, on chain. Every instruction. Every signer role. Every byte.
Every Turf Monster contest you enter is escrowed by a small program that lives on Solana — a public, immutable blockchain. The prize pool isn't sitting in a Turf Monster bank account. It's locked in an on-chain account that only the contract itself can move, following rules anyone can read.
You sign your own entry. Your USDC moves from your wallet to a contest account in one transaction. When the contest settles, the contract pays winners directly from that account to their wallets — we can't touch the money in between.
Below: the exact bytes that ship on chain, every instruction the contract exposes, and who is allowed to call each one.
close-buffer runs.
Solana charges rent on every byte in the ProgramData account, regardless of what's in it. The ELF section layout decides what those bytes are.
.text is the BPF bytecode that actually runs on chain. Most of it is Anchor's auto-generated account-validation code, not the business logic itself.
Each handler's handle_X function plus the Anchor-generated try_accounts validator. The validators dwarf the business logic. Measured per-instruction from a debug-info rebuild.
anchor_lang account-info helpers, ErrorCode formatters, AccountSerialize / Deserialize machinery, Bumps-struct support.
core::* and alloc::* monomorphizations: slice indexing, format machinery, Vec growth. Pulled in by msg!() and Vec usage.
The embedded IDL JSON plus the 6 Idl* instruction handlers (IdlCreateAccount, IdlResize, IdlClose, IdlWrite, IdlSetAuthority, IdlSetBuffer). Lets Solscan and `anchor idl fetch` decode the program without our source.
solana_program::* invoke helpers, system-program builders, classic SPL Token instruction builders, Pack/Unpack codecs, ATA helpers. Every USDC and USDT transfer routes through these — they're not optional, they're literally how SPL tokens move on Solana.
spl_token_2022 + spl_transfer_hook + spl_token_group + spl_elgamal instruction builders. The contract doesn't use any Token-2022 mints, but Anchor 0.32.1 pulls these in unconditionally — known framework bug. ~0.06 SOL of permanent rent wasted; resolved automatically when we upgrade to Anchor 0.33+.
VaultState/UserAccount/Contest/ContestEntry/EntryTokenAccount/Season/AcceptedCurrency serializers plus the 39 VaultError variants (codes 6000–6038).
The 8-byte-discriminator switch generated by #[program] that routes each TX to one of the 18 handlers.
borsh deserializers, panic_fmt / begin_panic for require!() failures, compiler_builtins for soft-float multiplication, sha256 for mint_entry_token's source_ref hashing.
These are the instructions you (the contestant) sign directly. Your wallet's signature is the only thing that authorizes them — no operator can call them on your behalf.
enter_contest
user signs
Pay your entry fee from your own wallet's USDC (or USDT) ATA, in one signed transaction. Your stats counter ticks up.
Replaces v0.15.1's `enter_contest_direct`. You sign an SPL transfer from your ATA to the contest's per-currency operator-revenue ATA. The instruction creates the ContestEntry PDA, awards seeds from the current Season, and increments your UserAccount.entries counter.
enter_contest_with_token
user signs
Consume one of your unused free-entry tokens to enter a contest at no cash cost.
You sign as the token owner. The instruction marks the EntryTokenAccount as consumed and creates a ContestEntry with currency_idx = u8::MAX (token-funded). No SPL transfer occurs — the operator covers the prize-pool side.
set_username
user signs
Change your on-chain display name. Validated against a reserved-prefix list (admin, system, turf, ...) and required to be printable ASCII, 3+ characters.
Phantom users sign in the browser. Custodial / managed-wallet users sign via the server-held encrypted keypair. Admin alone cannot rename someone — wallet consent is required.
create_user_account
permissionless
First-touch onboarding. Creates your on-chain UserAccount PDA — the stats record that tracks your seeds, entries, wins, and total payouts.
Permissionless and idempotent: anyone can pay the rent to create another wallet's UserAccount. Turf Monster's server bot (Alex) does this for every new signup via an after_commit job.
create_contest
1-of-3 + creator
Open a new contest, funded with a USDC prize pool that you (the creator) transfer from your ATA at creation time.
Dual-signer: a vault signer pays the SOL rent for the new Contest PDA and per-contest prize-pool ATA; the creator signs the USDC transfer that funds the prizes. Stores the per-currency entry-fee schedule the contest will honor.
Four signer roles. Each instruction is bound to exactly one role — the contract refuses to execute when the wrong key signs.
Solana rent formula:
(data_len + 128) × 6960 lamports
— this is the rent-exempt minimum (2 years × lamports-per-byte-year × 2× exemption threshold).
Subsequent upgrades through the Squad multisig need only the float portion — a new buffer is written, the program is upgraded in place, then the old buffer is closed. Net cost per upgrade: roughly zero, modulo TX fees and the brief float for the new buffer.
We sent a confirmation link to (your current address). Click the link in that email to confirm changing your email to . Your email won't change until you do — the link expires in 30 minutes.
Try again in .
Your 6 picks are saved — sign in to submit your lineup.
We emailed a one-tap sign-in link. Check your email and Click the Magic Link to continue.
We just resent a one-tap sign-in link. Check your email and Click the Magic Link to continue.
Entry purchases are paused while we upgrade checkout. Your picks are saved.
You must be 18+ to enter skill-based contests in OH. Enter your date of birth — we only ask once.
We use your date of birth only to confirm eligibility. Skill-based contest age limits: 18+ most states; 19+ AL/NE; 21+ IA/MA/VA.
Your active wallet changed from to .
Pick how you'd like to fund your entry. More options are on the way.
USDC balance:
Entry tokens:
Drop an image or click to upload
PNG or JPG
For your security we didn't co-sign this transaction — it didn't match the entry we prepared, so nothing was submitted and your funds are safe. Please close this and try entering again. If it keeps happening, contact support.