Liquimon docs
Everything you need to understand, play, and build on Liquimon — the fully on-chain creature battler powered by a fixed supply of $LMON.
Overview
Liquimon is a monster-battling game that runs entirely in smart contracts. You collect elemental creatures, stake $LMON to fight other trainers head-to-head, and evolve your creatures by winning. There is no central server and no off-chain game state — every creature, battle, and evolution is recorded on-chain.
The defining rule is Battle-Forged Evolution: the only source of evolution XP is a won PvP battle. You cannot buy your way up the ladder; you fight your way up.
How to play
- Get $LMON. The token is the currency for every action in the game.
- Recruit a creature at the Academy by paying $LMON. You receive a creature of a chosen species, with a fixed element and base stats.
- Battle in the Arena. Open or accept a challenge, commit a creature, and stake $LMON. After a short delay anyone can settle the match on-chain.
- Win to take the staked pot and earn XP on your creature.
- Evolve by spending that XP, pushing your creature into a scarcer, stronger form.
The $LMON token
Liquimon (ticker $LMON) is a deliberately plain ERC-20. The full supply is minted once, in the constructor, to the deployer. After that:
- There is no mint function — supply can never increase.
- There is no owner, admin, or pause — no privileged control of any kind.
- There is no upgrade path — the bytecode is final.
| Property | Value |
|---|---|
| name | Liquimon |
| symbol | LMON |
| decimals | 18 |
| totalSupply | 8888 × 10¹⁸ (8,888 LMON) |
| functions | transfer · approve · transferFrom · balanceOf · allowance |
$LMON is used to stake in battles, pay to recruit creatures, and is won by victors. Fees from battles and recruiting accumulate in the Treasury, which recirculates them as rewards. Because supply is fixed, the economy is zero-sum: tokens move, but are never created or destroyed.
Elements & type chart
There are six elemental types. Each is super-effective against two types and resisted by two. The chart is fully symmetric — no element is strictly best.
Rows attack · columns defend · values are damage multipliers.
The contract resolves a matchup with a single function returning one of three multipliers:
| Result | Multiplier | Stored as |
|---|---|---|
| Super-effective | ×2.0 | 200 |
| Neutral | ×1.0 | 100 |
| Resisted | ×0.5 | 50 |
The strength relationships are fixed in TypeChart as a bitmask, so every multiplier is a pure, gas-cheap lookup. A creature's element is set by its species and never changes — not even when it evolves.
Creatures & species
A species is a template registered by the game admin. A creature is an individual instance of a species, owned by a trainer. Stats come entirely from the species, so a creature's power changes only when it evolves into a different species.
Species fields
| Field | Meaning |
|---|---|
| elem | Element id, 0–5 (see type chart) |
| power | Offense used in battle resolution |
| defense | Mitigates incoming effective power (recommended 0–100) |
| speed | Adds a flat initiative edge |
| evolvesTo | Species id this evolves into (0 = final form) |
| evolveXp | XP a creature must spend to evolve |
Creature fields
| Field | Meaning |
|---|---|
| species | Current species id (changes on evolution) |
| owner | Trainer who controls the creature |
| xp | Battle XP earned, spent on evolution |
Creatures are owned game assets and can be handed to another trainer with transferCreature. They are not consumed by battling — the same creature can fight repeatedly, banking XP toward its next form.
Recruiting
The Academy is the on-ramp for new creatures. The admin lists which species are recruitable and at what $LMON price; a price of 0 means a species is unavailable.
// 1. approve the Academy to spend your $LMON
lmon.approve(academy, price);
// 2. recruit — pays $LMON to the Treasury, mints a creature to you
uint256 creatureId = academy.recruit(speciesId);
The payment is routed straight to the Treasury, and the Academy calls the Registry to mint your creature. The Academy must be authorized in the Registry (setAcademy) for minting to succeed.
Battling
Battles happen in the Arena. They are stake-for-stake and zero-sum: both trainers escrow $LMON, and the winner takes the combined pot minus a Treasury fee. No tokens are minted.
The flow
// challenger: commit a creature + escrow stake
// requiredType = 0xFF means any element may accept
lmon.approve(arena, stakeA);
uint256 id = arena.createChallenge(creatureA, stakeA, 0xFF, minStake);
// opponent: match the challenge with their own creature + stake
lmon.approve(arena, stakeB);
arena.acceptChallenge(id, creatureB, stakeB);
// anyone: settle after SETTLE_DELAY blocks (permissionless)
arena.settle(id);
How the winner is decided
Each side's effective power is computed, then both enter a weighted random roll. Advantage tilts the odds — it does not guarantee a win.
eff = eff × 100 ÷ (100 + defense)
eff = eff + speed + 1
P(A wins) = effA ÷ (effA + effB)
Here multiplier is the attacker's type multiplier against the defender, and defense is the defender's defense. Randomness is derived from the settle block's hash (falling back to prevrandao if the block has aged past 256 blocks).
Payout & XP
- The winner receives the full pot minus the fee (default 5%, sent to the Treasury).
- The winning creature gains 100 XP, or 150 XP if it won from a type disadvantage (the "clutch" bonus).
- An unaccepted challenge can be cancelled by its creator at any time, or by anyone after
ACCEPT_TIMEOUTblocks — the stake always returns to the challenger.
Evolution
Evolution is the payoff for winning. Once a creature has banked enough XP, its owner spends that XP to evolve it into the species set by evolvesTo.
// requires creature.xp >= currentSpecies.evolveXp
registry.evolve(creatureId);
- Evolving consumes exactly
evolveXpfrom the creature. - The creature's species changes; its element stays the same.
- Evolution lines can be chains (A → B → C) or convergent (A → C, B → C).
- A species with
evolvesTo = 0is a final form and cannot evolve further.
The Treasury
The Treasury is the $LMON reservoir. Battle fees and recruit fees flow in as ordinary transfers; the admin disburses them for seasonal rewards, tournaments, and airdrops. It never mints — it only recirculates the fixed supply.
| Function | Who | Effect |
|---|---|---|
| fund(amount) | anyone | Pull $LMON in (caller approves first) |
| disburse(to, amount) | admin | Pay $LMON out |
| balance() | view | Current $LMON held |
Contract reference
Five Solidity files: the Liquimon token plus four game contracts. A TypeChart library and an IERC20 interface are shared but are not standalone contracts.
LiquimonRegistry
| Function | Access | Description |
|---|---|---|
| registerSpecies(name, elem, power, defense, speed) | admin | Create a species, returns its id |
| setEvolution(id, evolvesTo, evolveXp) | admin | Wire an evolution edge |
| setAcademy(addr) / setArena(addr) | admin | Authorize the minter / XP awarder |
| mintCreature(to, speciesId) | academy | Mint a creature instance |
| addXp(creatureId, amount) | arena | Award battle XP |
| evolve(creatureId) | owner | Spend XP to evolve |
| transferCreature(creatureId, to) | owner | Hand a creature to another trainer |
| battleStats(creatureId) | view | elem, power, defense, speed, owner |
| ownerOf / xpOf / multiplier / typeName | view | Lookups |
LiquimonAcademy
| Function | Access | Description |
|---|---|---|
| setPrice(species, price) | admin | List / delist a species |
| recruit(species) | anyone | Pay $LMON → Treasury, mint a creature |
LiquimonArena
| Function | Access | Description |
|---|---|---|
| createChallenge(creatureA, stakeA, requiredType, minStake) | anyone | Open a challenge, returns id |
| acceptChallenge(id, creatureB, stakeB) | anyone | Match and lock a challenge |
| settle(id) | anyone | Resolve after the settle delay |
| cancelChallenge(id) | challenger / timeout | Refund an unaccepted challenge |
| setFeeBps(bps) | admin | Adjust the Treasury fee (cap 20%) |
LiquimonTreasury
| Function | Access | Description |
|---|---|---|
| fund(amount) | anyone | Deposit $LMON |
| disburse(to, amount) | admin | Pay rewards out |
| balance() | view | $LMON held |
Deploy & wire
Compile with solc 0.8.26, optimizer on (200 runs), EVM version cancun, viaIR off. Deploy in this order, then wire the authorizations and seed the game.
// 1) deploy (deployer receives all 8,888 LMON)
Liquimon lmon = new Liquimon();
LiquimonRegistry registry = new LiquimonRegistry(admin);
LiquimonTreasury treasury = new LiquimonTreasury(lmon, admin);
LiquimonAcademy academy = new LiquimonAcademy(lmon, registry, treasury, admin);
LiquimonArena arena = new LiquimonArena(lmon, registry, treasury, admin);
// 2) authorize the game contracts in the Registry
registry.setAcademy(academy);
registry.setArena(arena);
// 3) seed species + evolution lines
registry.registerSpecies("Emberling", 0, 40, 10, 30); // id 1
registry.registerSpecies("Embeast", 0, 70, 25, 45); // id 2
registry.setEvolution(1, 2, 100); // Emberling → Embeast for 100 XP
// 4) list starters + fund the Treasury
academy.setPrice(1, 10e18);
lmon.transfer(treasury, 500e18);
Liquimon.sol file imports the four game contracts, but the token itself uses only basic ERC-20 logic — the imports keep the protocol in one place and don't inflate the token's bytecode (~1.4 KB).Parameters
| Parameter | Default | Where | Notes |
|---|---|---|---|
| feeBps | 500 (5%) | Arena | Of the pot, to Treasury. Cap 2000 (20%) |
| XP_PER_WIN | 100 | Arena | +50% on an upset win |
| SETTLE_DELAY | 3 blocks | Arena | Wait before a locked battle settles |
| ACCEPT_TIMEOUT | 7200 blocks | Arena | Before anyone can reclaim a challenge |
| evolveXp | per species | Registry | Set via setEvolution |
| price | per species | Academy | Recruit cost; 0 = unavailable |
Security notes
- Fixed supply. $LMON has no mint, owner, or upgrade path — supply is final at deployment.
- Randomness. Battle resolution uses block-hash /
prevrandaorandomness. This is fine for low-to-mid stakes but is influenceable by block producers at high value. The resolution math is isolated, so a VRF can be dropped in for high-stakes play. - Permissionless settlement. Anyone can settle a locked battle after the delay, so a losing player cannot stall to avoid paying out.
- Reentrancy. Contracts that move $LMON use checks-effects-interactions and a reentrancy guard; the Registry holds no funds.
- Verify before you trust. The contracts are open-source. Read them, confirm deployed addresses, and treat the game as experimental software.
Glossary
| Term | Meaning |
|---|---|
| $LMON | The fixed-supply ERC-20 that powers every action |
| Species | A creature template: element, stats, evolution target |
| Creature | An owned instance of a species, with its own XP |
| XP | Earned only by winning; spent only on evolution |
| Multiplier | Type damage modifier: ×2.0, ×1.0, or ×0.5 |
| Clutch bonus | +50% XP for winning from a type disadvantage |
| Pot | The combined staked $LMON in a battle |
Ready to go deeper? Read the whitepaper for the full design rationale and economic model.