Introduction
KICKAIFM is a fully on-chain competitive football manager where every player in your squad is powered by an AI brain. You build a team of 11 AI agents, train them, set tactics, upgrade your club's infrastructure, and compete in real $KICK-staked matches against other managers.
Unlike traditional football games, no outcomes are scripted. Matches are simulated deterministically server-side using each player's real trained stats, your tactical configuration, and a cryptographic seed — and the result is settled on-chain by the KICKAIFM oracle. Everything from player growth to prize distributions is governed by transparent smart contracts on BASE.
Key Numbers
| Metric | Value |
|---|---|
| Players per squad | 11 |
| Skills per player | 7 (Pace, Shooting, Passing, Dribbling, Defense, Stamina, Decision) |
| Max skill value | 99 |
| Upgrade asset types | 4 (Stadium, Merchandise, Advertising, Facilities) |
| Max upgrade tier | T4 per asset (32 upgrade-points total) |
| Match duration (simulated) | 90 minutes / 5,400 ticks at 1 tick/sec |
| Match fee | 5% of prize pool → protocol treasury |
| $KICK emission model | Protocol emission rate split by each team emission score |
| Move library (bitmask) | 25 individual + team unlockable moves |
Live on BASE
- •Network: BASE
- •Smart contracts: Solidity
- •Token standard: ERC-20
- •Wallet: any EVM wallet (MetaMask, Coinbase Wallet, WalletConnect…)
| Label | Address | Explorer |
|---|---|---|
| KickToken (ERC-20) | 0x88d582BB02b893A2079913b4d7771AB99cf68d73 | To be updated |
| KickProtocol | 0xFb8E30b369D675E1EB41d96aC65C79C99673Fd96 | To be updated |
| KickMatch | 0xB636161b9DAa6D1AAb8d02365714853B29D463C | To be updated |
| KickOracle | 0x1d92FD0114C6836cc2124108348c999ddd7bD06B | To be updated |
| Treasury | 0xaD781b5d1Acf8feEA41A4C6a9Dd8F71c0699aA6e | To be updated |
Architecture
KICKAIFM is split into three repositories that communicate through a strict trust boundary: the BASE smart contracts are the source of truth for all economic and match settlement; the backend runs the AI Agents engines that produce the match simulation and submits results via the oracle; the frontend is a read-mostly interface that never touches raw private keys except through the user's wallet adapter.
Request Flow
User Wallet
│
├─▶ Next.js
│ └─▶ REST API (Express) — JWT auth via wallet signature
│ ├─▶ Prisma DB — read/write player/team state
│ ├─▶ Training Engine — XP calc, move unlocks, injury check
│ └─▶ Oracle Service — signs & submits contract transactions
│
└─▶ Solidity Contracts
├─ trainCollective() — transfer $KICK + ETH, record stats
├─ resolveInjuryCheck() — oracle-only, sets injuryUntil
├─ createMatchChallenge() — escrow half prize pool
├─ acceptMatchChallenge() — escrow opponent half, commit formation
├─ settleMatch() — oracle-only, distribute winnings
└─ claimRewards() — distribute $KICK from emission shareData Layers
| Layer | What lives here |
|---|---|
| Smart contracts | KickToken (ERC-20), KickProtocol (core game), KickMatch (matches) |
| Postgres (Prisma) | Off-chain mirror of on-chain state, match replay ticks, training history, revenue history |
| Redis (planned) | Active WebSocket rooms, live match tick buffer, nonce store |
| Client store (Zustand) | UI state, live match tick stream, squad & finance cache |
Player Brain
Every one of your 11 players is an autonomous AI agent parameterised by a set of persistent on-chain stats. These stats directly influence every decision the match simulation engine makes on behalf of that player — from triggering a shot to winning a tackle. There is no hidden RNG bonus: better stats = higher probability of success.
Skill Attributes
| Skill | Range | What it controls in-match |
|---|---|---|
| Pace | 0–99 | Sprint speed, pressing effectiveness, chase-down tackles |
| Shooting | 0–99 | Shot trigger probability in the box, shot power vs defender |
| Passing | 0–99 | Pass accuracy, key-pass frequency, set-piece quality |
| Dribbling | 0–99 | Retention under pressure, 1v1 success, move execution probability |
| Defense | 0–99 | Tackle success rate, interception chance, block probability |
| Stamina | 0–99 | Rate at which fatigue builds, second-half performance drop |
| Decision | 0–99 | When to shoot vs pass, pressing triggers, position coverage |
Player Roles
Each player has a PlayerRole that describes their behavioural archetype. Roles influence how stats are weighted during match decisions — a Poacher prioritises Shooting while a Playmaker leans on Passing and Decision.
| Role | Primary stats | Behaviour |
|---|---|---|
| Balanced | All equal | Standard weighting; adapts to situation |
| Playmaker | Passing, Decision | Seeks to thread through-balls; holds ball under pressure |
| Destroyer | Defense, Stamina | High press intensity; prioritises disruption over attack |
| Poacher | Shooting, Pace | Makes forward runs; has elevated shot-trigger probability |
| Sweeper | Defense, Decision | Drops into covering position; highest block/interception rate |
| WingBack | Pace, Dribbling | Wide overlapping runs; contributes to both defence and attack |
| TargetMan | Defense, Shooting | Aerial duels; link-up play; holds up ball in box |
| Dribbler | Dribbling, Pace | Carries ball independently; higher chance of beating defender |
Positions
Players are placed on the pitch according to their Position enum, mapped to normalised (x, z) coordinates defined per formation. Their initial coordinates are determined by formation and they drift toward goal or back into shape depending on possession and tactical settings.
| Position | Zone |
|---|---|
| GK | Goalkeeper |
| CB, RB, LB | Defensive line |
| CDM, CM, CAM | Midfield (deep, central, advanced) |
| RM, LM | Wide midfield |
| CF, ST | Attacking line |
XP & Diminishing Returns
Every training session grants XP. Raw XP is converted into skill points using a diminishing- returns formula: the more total XP a player has accumulated, the smaller the increment from each new session. This prevents pay-to-win scenarios where short-term grinding becomes exponentially effective — elite players require sustained investment.
The on-chain training instruction applies a diminishing-returns multiplier to raw XP: the multiplier starts at 1.0 for a fresh player and gradually floors at 10% as total accumulated XP grows. This ensures early gains are fast but elite players require sustained long-term investment — exact thresholds are not published.
Move Library (64-bit Bitmask)
Each player has a move_library: u64 — a 64-position bitmask where each bit represents an unlockable special move. Moves are unlocked automatically by the training engine when a player meets the required skill threshold and session count. Unlocked moves are factored into match simulation to trigger special animations and grant small probability bonuses.
| Category | Moves | Unlock Skill / Min |
|---|---|---|
| Dribble | Rabona, Heel Flick, Elastico, Roulette, Step Over | Dribbling 60–75 |
| Shooting | Fake Shot, Bicycle Kick, Trivela, Chip Shot, Low Driven, First-Time Volley, Knuckleball, Dipping FK | Shooting 55–85 |
| Passing | Corner Inswing | Passing 70 |
| Defensive | Slide Tackle, Standing Block, Interception, Header Clear | Defense 50–65 |
| GK Special | GK Rush, GK Sweeper | Decision 70–75 |
| Team (collective) | Team Press, Quick 1-2, Overlapping Run, Diagonal Ball, Wall Pass Set | Various + collective sessions |
Fatigue & Morale
fatigue accumulates with each training session — intensity × 10 points. Fatigue over a threshold blocks further training. It recovers passively at 5 + (facilities_tier × 3) points per hour. Higher Facilities tier dramatically accelerates recovery.
morale (0–100) is initialised at 80 and influenced by match outcomes and training consistency. High morale results in a slight up-tick to decision-making quality during matches.
Team Brain
Beyond individual skill, a football squad is more than the sum of its parts. KICKAIFM models collective intelligence via the chemistry stat (0–100) and a set of unlockable team behaviours called collective drills. Chemistry is the team's shared neural glue — it amplifies every player's effective stats during match simulation.
Chemistry (0–100)
Chemistry is stored per team on-chain. It is:
| Event | Effect on Chemistry |
|---|---|
| Collective training session | +2 to +12 points (drill type × intensity) |
| Win a match | Small passive boost (off-chain) |
| Player injury during match | Small decrease (off-chain) |
| Maximum cap | 100 |
In match simulation, chemistry acts as a shared team modifier. It is mixed with each defender's defense stat when calculating defensive strength against shots:
During shot resolution, the engine combines the defender's defense stat with the team's chemistry score to produce a composite defensive strength value. Higher chemistry meaningfully raises the bar for attackers to score.
Collective Drills
Running a collective training session costs $KICK plus a small ETH fee, requires the on-chain cooldown window, and currently uses Fitness, Technical, or Chemistry drills. These sessions update selected players or team chemistry and feed the collective move unlock system in the move library bitmask.
| Drill Type | Primary effect | Session result |
|---|---|---|
| Fitness | PACE / STAMINA / DEFENSE style growth | 3 / 4 / 5 selected players by intensity |
| Technical | SHOOTING / PASSING / DRIBBLING / DECISION style growth | 3 / 4 / 5 selected players by intensity |
| Chemistry | Team cohesion | Chemistry gain, no individual stat gain |
Formation Commitment (Commit-Reveal)
When you create or accept a match challenge, you submit a hash of your formation using the match contract address, chain id, match id, wallet address, side flag, formation code, and a 32-byte salt. The actual formation is only revealed after both sides have committed, preventing opponents from counter-picking. The smart contract verifies the hash on-chain when you call revealFormation(matchId, formation, salt).
bytes32 computed = keccak256(
abi.encode(
address(this),
block.chainid,
matchId,
msg.sender,
isChallenger,
formation,
salt
)
);
require(computed == expectedHash, "Invalid formation reveal");Training System
Training is the primary way to grow your squad. Players improve through individual sessions targeting a specific skill, collective squad sessions that raise stats or chemistry, and tactical scenario training that teaches decision patterns. Training spends $KICK and may include a small ETH fee depending on the on-chain action; upgrade payments are the main $KICK burn path.
Individual Training
| Intensity | Cost | $KICK flow | XP Weight | Fatigue+ |
|---|---|---|---|---|
| Soft (1) | 10 $KICK + 0.0002 ETH | Transfer to protocol | 1× | +10 |
| Regular (2) | 20 $KICK + 0.0004 ETH | Transfer to protocol | 2× | +20 |
| Intense (3) | 30 $KICK + 0.0006 ETH | Transfer to protocol | 3× | +30 |
You choose a SkillTarget (one of the 7 skills) and an intensity level. The training engine calculates:
// 1. Base XP = session weight × facilities multiplier const base_xp = BASE_SESSION_XP * session_intensity + (facilities_tier * FACILITIES_XP_BONUS); // 2. Apply diminishing returns const xp_gain = calculate_xp_gain(base_xp, player.total_xp); // 3. Convert XP to skill points (capped at MAX_SKILL = 99) const xp8 = Math.min(Math.floor(xp / 100), 255); player[skillTarget] = Math.min(99, player[skillTarget] + xp8); // 4. Accumulate total XP player.total_xp += xp_gain; // 5. Raise fatigue player.fatigue = Math.min(MAX_FATIGUE, player.fatigue + intensity * 10);
Facilities Bonus
Upgrading your Facilities asset tier gives a multiplicative XP bonus per training session. Higher facilities also reduce injury risk and accelerate fatigue recovery. This makes Facilities the most direct multiplier on player development speed.
| Facilities Tier | XP bonus per session | Fatigue recovery (pts/hr) | Injury risk reduction |
|---|---|---|---|
| T0 (none) | +0 bonus XP | 5 pts/hr | 0% |
| T1 | +1× FACILITIES_XP_BONUS | 8 pts/hr | −15% |
| T2 | +2× | 11 pts/hr | −30% |
| T3 | +3× | 14 pts/hr | −45% |
| T4 (max) | +4× | 17 pts/hr | −60% |
Collective Training
Any owner can run a collective training session once per cooldown window. All 11 players participate; the session raises team.chemistry and contributes toward unlocking team moves in every player's move library.
| Parameter | Value |
|---|---|
| Soft cost | 35 $KICK + 0.0006 ETH |
| Regular cost | 65 $KICK + 0.0012 ETH |
| Intensive cost | 100 $KICK + 0.002 ETH |
| Cooldown | 30 seconds (on-chain enforced) |
| Chemistry cap | 100 |
| Team move sessions requirement | 1–5 sessions depending on the move |
Tactical Scenario Training
Tactical scenarios are built in the Tactics view by placing players and the ball, adding action steps, then training the saved scenario. Scenario training transfers $KICK directly to treasury and can be amplified in one transaction.
| Amplifier | Cost | Effect |
|---|---|---|
| 1× | 10 $KICK | Process the scenario once |
| 5× | 50 $KICK | Reinforce the same pattern five times |
| 10× | 100 $KICK | Strongest reinforcement for the selected scenario |
Injury System
After every individual training session, a pending injury check is flagged on the player account (pending_injury_check = true). The oracle resolves this server-side using a deterministic hash of a server-generated entropy value and the player ID.
Injury probability scales with the player's current fatigue and the session intensity; higher Facilities tier significantly reduces the chance. When an injury triggers, severity is classified as Minor (days), Moderate (up to ~10 days), or Severe (up to ~30 days) — determined deterministically by the oracle. Exact thresholds are internal to the oracle service.
An injured player (injury_until > block.timestamp) cannot be selected for training. They can still appear in match squads but with heavily reduced effective stats in the simulation engine.
Move Unlock Triggers
After every training session the backend runs checkMoveUnlocks() against the updated player snapshot. Any move whose skill threshold and session-count requirements are now met is automatically added to the player's move_library bitmask and persisted to the DB. Move unlocks are shown as real-time notifications in the UI.
Tactics & Player Decisions
The match simulation engine is a deterministic, seed-driven agent loop. Every tick (1 simulated second) each player acts according to their stats and the team's tactical configuration. There is no human intervention mid-match; formations are committed on-chain before the game, while trained tactical scenarios inform the backend AI engine.
Tactical Configuration
| Parameter | Range | Effect |
|---|---|---|
| pressingIntensity | 0–100 | How aggressively defenders close down the ball carrier |
| width | 0–100 | Horizontal spread of attacking runners |
| tempo | 0–100 | Speed of ball carrier movement toward goal; shot trigger modifier |
| defensiveLine | 0–100 | How high defenders position themselves (offside trap risk) |
| attackingMentality | 0–100 | Multiplied into shot trigger probability; higher = more attempts |
Formations
| Formation | Shape | Best for |
|---|---|---|
| F433 | 4-3-3 | Balanced pressing and width; three active forwards |
| F442 | 4-4-2 | Compact midfield block; dual striker threat |
| F352 | 3-5-2 | Wide midfield control; overloads central zones |
| F451 | 4-5-1 | Defensive discipline; counter-attack via lone striker |
| F532 | 5-3-2 | Maximum defensive coverage; disciplined wing-backs |
| F4231 | 4-2-3-1 | Double pivot shield + attacking trident; control-heavy |
Formation positions are mapped as normalised (x, z) coordinate pairs. The engine places all 11 players at their formation positions at kickoff and half-time, then each player drifts toward attack or defence based on possession and tick-level logic.
Tick-Level Decision Loop
Each of the 5,400 ticks runs the following decision pipeline: possession is tracked per-player, defenders close down the ball carrier, tackle and shot checks are resolved using each player's stats combined with the team's tactical configuration, and stamina decays gradually throughout the match. The exact coefficients and thresholds are internal to the simulation engine and not published to prevent exploitation.
How Stats Influence Decisions
| Stat | Decision it influences |
|---|---|
| Shooting | Shot trigger probability and power in the box |
| Defense | Tackle and interception success probability |
| Defense + Chemistry | Combined shot-stop strength against incoming shots |
| Stamina | Player effectiveness late-game; decays over match duration |
| Pace | Ball carrier movement speed and press recovery |
| Decision | GK special move triggers and situational awareness |
Individual vs Team Intelligence
Individual stats determine micro-level outcomes: will this shoulder-barge succeed? Will this shot beat the keeper? Team chemistry and collective drills determine the macro shape: Does the midfield press as a unit? Do wingers time their overlapping runs? A squad of individually mediocre players with 100 chemistry can outperform disjointed superstars.
Match System
Matches are peer-to-peer challenges backed by on-chain $KICK escrow. The full lifecycle — challenge creation, acceptance, simulation, oracle settlement, and prize distribution — is governed by the smart contracts. No third party can alter the outcome.
Full Match Lifecycle
1. CHALLENGE CREATED
Challenger calls createMatchChallenge(prizePool, formationHash)
Minimum full prize pool: 10 $KICK (5 $KICK per side)
└─ Half prize pool locked in contract escrow
└─ formationHash = keccak256(abi.encode(matchContract, chainId, matchId, owner, side, formation, salt))
2. CHALLENGE ACCEPTED
Opponent calls acceptMatchChallenge(matchId, formationHash)
└─ Other half locked in escrow
└─ Match status → InProgress
└─ Backend detects event, queues simulation
3. FORMATIONS REVEALED
Both managers call revealFormation(matchId, formation, salt)
└─ On-chain hash verification
└─ Formation stored in match state
4. SIMULATION (off-chain, backend)
MatchEngine.simulate(homeTeam, awayTeam, seed)
└─ seed derived from both team addresses and a recent block hash
└─ 5,400 ticks computed deterministically by the backend engine
└─ resultHash = cryptographic commitment to (seed, scores, events)
5. SETTLEMENT (oracle → on-chain)
Oracle calls settleMatch(homeScore, awayScore, resultHash)
└─ Match status → Settled
└─ Winner gets prizePool − 5% fee
└─ Draw → each team gets half back
└─ W/D/L records updated on both teams
└─ 5% fee → protocol treasuryPrize Distribution
| Result | Challenger receives | Opponent receives | Protocol fee |
|---|---|---|---|
| Home win (challenger) | prize_pool − 5% | 0 | 5% of prize_pool |
| Away win (opponent) | 0 | prize_pool − 5% | 5% of prize_pool |
| Draw | prize_pool / 2 | prize_pool / 2 | 0 (no fee on draw) |
Live Match Streaming
While the simulation runs server-side, every tick is streamed to connected clients via WebSocket. The frontend's Three.js renderer consumes these ticks in real time, smoothly interpolating 22 player positions and the ball on the 3D pitch. Clients can also request a replay of any past match using the REPLAY_REQUEST message type.
| WS Message | Direction | Payload |
|---|---|---|
| SUBSCRIBE | client → server | { matchId } |
| MATCH_START | server → client | Match metadata, team data |
| TICK | server → client | MatchTick: player positions, ball, events, score |
| EVENT | server → client | MatchEvent: GOAL, CARD, FOUL, etc. |
| MATCH_END | server → client | Final score, resultHash |
| REPLAY_REQUEST | client → server | { matchId, fromTick } |
| REPLAY_CHUNK | server → client | Array of MatchTick[] |
Match Events
| Event Type | Trigger condition |
|---|---|
| KICKOFF | Tick 0 and after each goal |
| HALFTIME | Tick 2,700 (45 min) |
| FULLTIME | Tick 5,400 (90 min) |
| GOAL | Shot succeeds: (shooting/99 × 0.65) > (defense + chem/2)/149 |
| SHOT_SAVED | Shot fails: 40% of near-miss cases |
| SHOT_BLOCKED | Shot fails: 30% of near-miss cases |
| SHOT_WIDE | Shot fails: remaining cases |
| FOUL | Tackle fails: 25% chance × (1 − defense/99) |
| YELLOW_CARD | Foul: additional 30% chance |
| PENALTY | Foul conceded inside penalty box |
| CORNER | Ball crosses goal-line by defending team |
| OFFSIDE | Attacker ahead of last defender (future) |
Finance & $KICK Token
$KICK is the native utility token of KICKAIFM. It is both the currency for all in-game actions and the source of protocol emissions for active teams. The current finance panel tracks wallet balance, live pending rewards, daily emissions, emission score, protocol share, and upgrade ROI.
$KICK Flows
| Action | $KICK direction | Note |
|---|---|---|
| Create team | 1500 $KICK + 0.015 ETH | One-time team creation payment |
| Individual training | 10 / 20 / 30 $KICK + ETH fee | Player skill growth by intensity |
| Collective training | 35 / 65 / 100 $KICK + ETH fee | Squad stat or chemistry training |
| Tactical training | 10 / 50 / 100 $KICK | Direct transfer to treasury for 1x / 5x / 10x scenario training |
| Asset upgrade | 200 / 300 / 400 / 600 $KICK burned + ETH fee | Starts a cooldown, then must be completed |
| Match challenge/accept | Locked in contract escrow | Released on settlement |
| Match win | Escrow → winner wallet | Prize pool minus 5% fee |
| Claim revenue | Minted → your wallet | $KICK minted from protocol mint authority |
| Claim revenue ETH fee | 20% of reward value in ETH → treasury | Quoted before the wallet signs |
Emission Score
Rewards accrue from the protocol emission rate according to your team's emission score. The frontend reads on-chain economy data and shows your score, total protocol score, protocol share, estimated daily emissions, and a smooth live pending counter between chain refreshes.
| Component | How it affects finance |
|---|---|
| Emission score | Your share weight in protocol emissions |
| Upgrade points | Points generated by infrastructure tiers |
| Stat points | Points generated by trained player strength and activity |
| Protocol share | Your score divided by all active team scores |
| Daily emissions | emissionRate × your protocol share × 86,400 seconds |
protocolShare = myEmissionScore / totalEmissionScore dailyEmission = emissionRateWeiPerSecond * protocolShare * 86400 // The UI snaps to on-chain pendingRewards every 2 seconds and interpolates // between refreshes using the computed per-team emission rate.
Infrastructure Upgrades
Stadium, Merch Store, Ad Boards, and Facilities each have four paid tiers after the starting tier. Upgrading burns the listed $KICK amount, sends the listed ETH fee with the transaction, starts an on-chain cooldown, and then requires a separatecompleteUpgrade call once the timer is ready.
| Next tier | $KICK burn | ETH fee | Cooldown |
|---|---|---|---|
| T1 | 200 $KICK | 0.003 ETH | 3 hours |
| T2 | 300 $KICK | 0.005 ETH | 6 hours |
| T3 | 400 $KICK | 0.008 ETH | 12 hours |
| T4 | 600 $KICK | 0.012 ETH | 24 hours |
Claiming Revenue
You claim accrued $KICK by calling claimRewards. Claims require at least1 $KICK pending on-chain. Before signing, the frontend requests a backend quote containing the pending $KICK and ETH fee. If the claim oracle is not configured, the claim button is disabled and rewards continue to accrue.
| $KICK minted to your wallet | 100% of accrued tokens |
| ETH fee deducted | 20% of reward value in ETH → treasury |
| Backend confirmation | Claim transaction hash is posted back for DB sync |
Protocol Revenue Sources
| Source | Rate | Where it goes |
|---|---|---|
| Upgrade ETH fee | 0.003 / 0.005 / 0.008 / 0.012 ETH | Protocol treasury wallet |
| Match settlement fee | 5% of prize pool | Protocol treasury wallet |
| Revenue claim ETH fee | 20% of reward value in ETH | Protocol treasury wallet |
| Team creation payment | 1500 $KICK + 0.015 ETH | Protocol-defined team creation flow |
| Upgrade $KICK burn | Full listed upgrade $KICK cost | Burned (deflationary) |
Emission Score (Upgrade Points)
Upgrade tiers generate upgrade_points that contribute to your team's global emission score. The Finance panel also displays statPoints, so managers can see how much of their score comes from infrastructure versus squad development.
| Tier | Points per asset |
|---|---|
| T0 | 0 |
| T1 | 1 |
| T2 | 2 |
| T3 | 4 |
| T4 | 8 |
Max upgrade points = 4 assets × 8 points = 32 points. Combined with training stat points (max 16), total emission score ceiling is 48 per team.
Smart Contracts
The KICKAIFM Solidity contracts (KickToken, KickProtocol, KickMatch, and KickOracle) are the authoritative layer for economic decisions. They enforce access control, handle token transfers, manage match escrow, and store the canonical state of every team, player, economy account, and match on-chain.
Contract Functions
| Function | Caller | What it does |
|---|---|---|
| initializeProtocol | Admin | Bootstrap protocol state, set emission rate, fee bps, oracle authority |
| createTeam | Player | Transfer KICK + ETH and initialise the team record plus club economy state |
| initPlayer | Team owner | Write each player slot's position and role on-chain after team creation |
| trainIndividual | Team owner | Transfer $KICK + ETH, apply XP, flag injury check |
| trainCollective | Team owner | Transfer $KICK + ETH, raise chemistry, enforce cooldown |
| initializeDefaultRoster | Team owner | Initialise the default 11-player on-chain roster when needed |
| resolveInjuryCheck | Oracle | Set player injuryUntil from oracle-computed days |
| startUpgrade / completeUpgrade | Team owner | Transfer $KICK + ETH, increment tier, emit event |
| claimRewards | Team owner | Distribute accrued $KICK, collect ETH claim fee |
| createMatchChallenge | Team owner | Lock half prize pool in contract escrow, commit formation hash |
| acceptMatchChallenge | Any team owner | Lock other half, change status to InProgress |
| revealFormation | Both owners | Verify hash, store formation on-chain |
| settleMatch | Oracle | Verify result, distribute winnings, update W/D/L records |
| cancelMatchChallenge | Challenger | Refund escrow if match still Open |
| timeoutMatch / claimRevealForfeit | Eligible caller | Resolve expired reveal or stale match states |
| updateProtocol | Admin | Governance: update emission rate, fees, oracle key, treasury |
Contract Storage
| Contract | Key Mapping | Stores |
|---|---|---|
| KickProtocol | teams[ownerAddress] | Name, formation, W/D/L, chemistry, asset tiers, last claim ts |
| KickProtocol | economies[ownerAddress] | Emission score, upgrade points, stat points, pending rewards, reward debt |
| KickProtocol | players[teamOwner][index] | 7 skills, fatigue, morale, XP, move library, injuryUntil |
| KickMatch | matches[matchId] | Status, both team addresses, prize pool, hashes, scores |
| KickToken | ERC-20 standard | Balances, allowances, totalSupply, emission mint accounting |
Token Operations
All token operations use the ERC-20 standard. The KickToken contract grants the KickProtocol contract minter privileges for distributing revenue. Match escrow is held directly by the KickMatch contract — no external key can unilaterally access it.
Oracle Service
The oracle is a privileged backend service. Its signing keypair is stored in a secrets manager and never exposed in code or environment files. It is the only authority permitted to call resolveInjuryCheck and settleMatch on-chain. After the simulation completes, the oracle submits a signed settlement transaction containing the scores and a cryptographic result commitment, then triggers the live match-end event stream to all connected clients.
Custom Error Codes
| Error | Condition |
|---|---|
| InvalidFeeBps | Fee > 10% (1000 bps) |
| NameTooLong | Team name > 32 chars |
| PlayerInjured | injury_until > block.timestamp |
| PlayerTooFatigued | fatigue ≥ MAX_FATIGUE |
| CollectiveCooldown | Too soon since last collective session |
| MaxTierReached | Asset already at T4 |
| NothingToClaim | Pending rewards are below the 1 $KICK claim minimum |
| MatchNotOpen | Challenge status ≠ Open |
| CannotChallengeYourself | Challenger and opponent are same wallet |
| InvalidFormationReveal | Formation hash does not match commitment |
| NotChallengeOwner | Only challenger can cancel |
| NoPendingCheck | resolve_injury_check called without pending flag |
| PrizeTooLow | Prize pool below MIN_PRIZE_POOL |
Security
Security is a first-class concern at every layer of KICKAIFM. The economic model and match system are designed to be fair, transparent, and manipulation-resistant.
Match Integrity
| Threat | Mitigation |
|---|---|
| Knowing opponent formation early | Commit-reveal: formation hashes committed before acceptance; reveals verified on-chain |
| Predicting match outcome | Seed generated from both pubkeys + block hash after both commit; unknowable in advance |
| Oracle manipulation | resultHash submitted on-chain; anyone can re-run simulation with public seed to verify |
| Oracle key compromise | Key stored in Vault/Secrets Manager; on-chain admin can rotate oracle_authority |
Economic Security
| Risk | Mitigation |
|---|---|
| Flash-loan match manipulation | Prize pool locked before simulation begins; no re-entrance possible |
| Inflation attack | Revenue emission is rate-limited; claim ETH fee reduces net APY; governance controls rate |
| Sybil match farming | TEAM_CREATION_FEE burned per team; match fee on every settlement |
| Rug-pull treasury | Treasury is a separate, governed wallet; mint authority is the protocol PDA (deterministic) |
Backend & API Security
| Layer | Controls |
|---|---|
| Authentication | Wallet signature → JWT; all mutating endpoints require valid JWT |
| Authorisation | requireTeamOwner middleware checks DB that wallet matches team.ownerWallet |
| AI engine | Match simulation runs server-side only; clients receive tick stream, never engine code |
| Network | Services run on an isolated internal network; databases are not publicly reachable |
| Secrets | Oracle keypair managed by an external secrets service; never committed to code or config files |
| Input validation | Zod schemas on all API endpoints; Solidity require() on all contract functions |
Verifiability
Settled matches are cryptographically auditable. The on-chain KickMatchcontract stores the result commitment (scores + cryptographic hash of the full event log) signed by the oracle. An independent auditor with access to the simulation engine can reproduce the result from the on-chain seed and team snapshots and confirm it matches the stored commitment — no trust in the oracle is required beyond the key rotation process.