CryptoCocks: Living On-Chain Companions
Where Care Creates Meaning and Combat Creates Consequence
Abstract. CryptoCocks is a companion game in which care, growth, training, competition, and mortality alter one persistent ERC-721 identity. Players meet and name a cock before hatching it, discover its stable care preferences, complete a daily ritual in one transaction, and earn growth through consistency. Neglect is rescueable but ultimately fatal. The same companion can train safely in Sparring or enter an optional Deathmatch in which the loser is burned and its life bond moves to the winner. Care state, combat, art, identity signals, and consequences are enforced on chain; the frontend is a replaceable interface rather than the source of truth.
Contents
1. Why Digital Lives Matter
The dominant pricing model for PFP and game NFTs reduces to a rarity score: traits are rolled at mint, the rarest combinations command secondary-market premiums, and the asset's value is set by collectors trading metadata. The token itself is passive. It does not earn its standing.
CryptoCocks treats passivity as the design failure. A creature becomes meaningful when the player's attention and decisions produce durable, inspectable history. The system is built around a single property:
A digital creature matters when care, time, skill, and consequence all alter the same persistent identity.
The properties that follow:
| Property | How it is enforced |
|---|---|
| Growth is non-purchasable | A cock gains a care level only after seven complete care days, or a battle level by winning a Deathmatch. Care levels and battle records remain separately inspectable. There is no paid level-up or admin shortcut. |
| Stake is real | Hatching requires a minimum life bond locked inside the NFT. Sparring does not risk it; an explicitly selected Deathmatch does. |
| Mortality is enforceable | A lost Deathmatch or unresolved neglect permanently burns the token. A burned tokenId is never issued again. |
| Risk is legible | Sparring is safe training; Deathmatch is voluntary and permanent; neglect has a visible rescue deadline. The interface does not blur these modes together. |
A CryptoCock's life card is provenance: care days, streaks, rescues, Sparring results, Deathmatch results, level, bond, and present condition describe what has actually happened to that individual.
2. The Companion-First Loop
The primary loop begins with attachment, not wagering. Combat exists to give care and growth purpose; it is not the first thing a new player is asked to understand.
- Meet. A visitor receives a guest cock, chooses gifts, discovers temperament, and gives it a name before connecting a wallet.
- Hatch. The chosen identity becomes an on-chain companion with deterministic art and a life bond.
- Care. Feed, groom, and train once per UTC day; learn stable preferences and build a streak.
- Train. Use zero-stake Sparring to learn the grid battle, build records, and create visible after-effects on care stats.
- Compete. Continue the safe loop or deliberately enter Deathmatch, where bonds, levels, spectators, and permanent loss become active.
Neglect is the background clock beneath this loop. A companion can be rescued from a critical state, but a player who leaves it beyond the published deadline can lose it.
3. Hatch and On-Chain Art
3.1. Hatch economics
A mint is a single payable transaction. The transaction value is split into a life bond, which is escrowed inside the NFT, and a small protocol fee. A minimum bond is enforced at the contract level.
While the cock is alive, the bond stays bound to its tokenId. It can be transferred with the NFT while the cock is not battle-locked, concentrated into a Deathmatch survivor, or returned to the owner when neglect death is settled. There is no ordinary bond withdrawal from a living cock.
3.2. Deterministic on-chain art
At mint, the cock's pixel sprite is generated from a single hash:
seed_hash = keccak256(abi.encodePacked(seed, tokenId))(1)
where seed is the alphanumeric name supplied by the minter. The hash is partitioned into independent fields and used to index into the launch trait set: ten body colors, nine wing colors (constrained to differ from body), thirty headgear shapes, three headgear colors, twenty-four backgrounds, and six background patterns. The resulting visual space is:
N_art = 10 × 9 × 30 × 3 × 24 × 6 = 1,166,400 unique sprites(2)
The SVG is composed on chain at render time. There is no IPFS dependency, no off-chain image host, and no metadata server. tokenURI() returns a complete data:application/json;base64,…blob containing the rendered SVG, the cock's stats, and its attributes. A node operator running the chain can reconstruct every cock's appearance from chain state alone.
3.3. Identity
A further deterministic trait is derived at mint, used only for personality flavor (see §8):
alignment_packed = keccak256(abi.encodePacked(name, tokenId, msg.sender, chainid)) % 9(3)
alignment_packedis mapped to one of nine D&D classifications (Lawful Good through Chaotic Evil). Standard ERC-8004 identity-registry events fire at the same time. None of these values affect combat outcomes.
4. Raise: Care, Growth, and Neglect
Every cock hatches with mood, energy, and grit at 50 and receives a three-day newborn grace period. The owner can perform FEED, GROOM, and TRAIN once per UTC day, either as separate calls or together through careBatch in one transaction.
Three actions, three target stats:
- FEED → +energy
- GROOM → +mood
- TRAIN → +grit
Completing all three actions creates one full care day. Care is blocked while the cock is battle-locked, so combat and daily state cannot race each other.
4.1. Decay
After newborn grace, the contract lazy-evaluates decay in complete-day steps. Mood, energy, and grit each lose six points per elapsed day. A cock is Healthy while every stat is at least 30, Needs Care when any stat falls below 30, and Critical when all three reach zero.
Critical does not mean immediately dead. A two-day rescue window remains open, and any valid care action that restores a stat records a neglect rescue. Once the published deadline passes, the condition becomes Lost. Anyone may settle the death, but the NFT is burned and its full life bond is returned only to the token owner.
4.2. Stable preferences
Each action offers three care choices. The cock's preferred choice for that action is deterministically derived from its seed, tokenId, and action, so it remains stable for the life of the creature. The player learns a personality rather than guessing against fresh transaction randomness.
| Choice | Stat boost |
|---|---|
| Any valid choice | +8 |
| Preferred choice | +12 |
The boost is added to both the target stat and care XP, with stats capped at 100. A complete care day awards an additional 10 XP. The contract reveals whether each choice matched after the transaction, allowing the interface to remember what the player has learned without making off-chain memory authoritative.
4.3. Streak and growth
A streak increments on each consecutive full care day. Missing a day makes the active streak read as zero; the next completed day starts again at one, while best streak and total care days remain permanent. Every seven total full care days earns one care level. Milestones at 7, 14, 30, and 100 consecutive days emit reputation signals for indexers.
4.4. The grit cross-over
The grit stat is the link between the care loop and the combat loop. When a battle's move grid does not produce a collision within the simulation window (see §5.4), the contract resolves the fight by a coin flip whose threshold is shifted by grit:
eg1 = max(grit1, 50) eg2 = max(grit2, 50) threshold = clamp(50 + (eg1 - eg2) / 5, [40, 60]) P(P1 wins on tiebreak) = threshold / 100(4)
where integer division truncates toward zero. The threshold is clamped to 40–60, so care can shift but never determine the outcome. Under the current configuration this produces:
| grit1 | grit2 | P(P1 wins on tiebreak) |
|---|---|---|
| 50 | 50 | 0.50 |
| 80 | 50 | 0.56 |
| 100 | 50 | 0.60 (max advantage) |
| 100 | 100 | 0.50 |
| 30 | 80 | 0.44 (P1 disadvantaged) |
Grit below 50 does not penalize; the floor protects newly minted cocks from being instantly stacked against by long-cared opponents. The ceiling caps any single cock's tiebreaker advantage at a small bounded range, which keeps care a meaningful but not deterministic input.
Battle also feeds back into companion state. A winner gains 5 mood and 3 grit but spends 8 energy. A loser loses 8 mood and 12 energy while gaining 2 grit. Both records are retained after Sparring; in Deathmatch, the loser's final state is emitted before the token is burned. Combat therefore creates a reason to return to the Coop.
5. Train and Battle: Commit-Reveal Grid Combat
The arena is a 4×4 cartesian grid. Player 1 starts at (0, 0); Player 2 starts at (3, 3). Each player commits to ten secret moves, then both reveal. The contract simulates the resulting paths and detects collisions deterministically.
| Mode | Consequences |
|---|---|
| Sparring | No match value, betting, burn, bond transfer, or battle level. The result and care-stat after-effects are recorded. |
| Deathmatch | Bonds are matched, spectators may bet, the loser is burned, its bond moves to the winner, and the winner gains one battle level. |
5.1. Move encoding
A single move is one of UP, DOWN, LEFT, or RIGHT. There is no "stay" move. Ten moves are packed into a uint32, three bits each, low bit first. This uses 30 of 32 bits; the remaining two bits are reserved for future move types.
5.2. Commitment
A fighter commits by submitting the keccak256 hash of their moves concatenated with a 32-byte salt:
commit = keccak256(abi.encodePacked(uint32 moves, bytes32 salt))(5)
The salt is chosen by the fighter (typically a random nonce in their wallet's local storage). The contract stores commit only; the plaintext is invisible to opponents and observers until reveal.
The salt has two purposes:
- Hide the moves from rainbow-table attacks on the small (≈ 109) move space.
- Prevent commit replay across multiple battles by the same player.
5.3. Reveal
When both fighters have committed, the contract opens a reveal window. Either fighter (or any third party who knows their plaintext, typically the optional keeper bot) submits the plaintext and the salt. The contract recomputes the hash and verifies it against the stored commit. Each move is then validity-checked to ensure it keeps the cock within the grid boundaries.
5.4. Resolution
Once both fighters have revealed, the contract simulates the battle on chain. Players alternate (P1 on even sub-turns, P2 on odd). On each sub-turn, the active player applies their next move; after every move, the contract checks whether the two cocks occupy the same cell. The first such collision ends the battle: the cock who just moved is the winner. Conceptually: they walked into the other cock's tile and pecked.
If the simulation completes with no collision, the contract falls back to the grit-weighted coin flip described in §4.4.
5.5. Timeouts
Two permissionless timeouts protect liveness. In Deathmatch, one-sided commitment or one-sided reveal resolves as a forfeit win; if neither fighter completes the relevant phase, the challenge cancels and the betting pool is refundable. Sparring is more forgiving: any incomplete commitment or reveal cancels without progression or asset loss. An optional keeper can submit known reveals or call timeout resolution, but the chain does not depend on it.
5.6. Transfer lock
While a cock is in any arena state, its NFT is non-transferable and care calls revert. This forecloses a class of state and social attacks: an owner cannot alter care state or sell a cock mid-battle to dump the loss on a buyer. A pending challenge can be cancelled by its creator before an opponent joins.
6. Bet: Deathmatch-Only Parimutuel Pool
Betting exists only for Deathmatch. Sparring never opens a pool. Spectators wager on either Deathmatch fighter during the betting window; the pool is parimutuel, so the protocol takes a small cut, both fighters take a fixed share, and the rest is distributed proportionally among winning bettors.
6.1. Pool windows
A betting pool opens when the second cock joins a Deathmatch. After both fighters commit their moves, the pool's deadline is shortened to a brief final window. This compresses the betting horizon once the permanent match becomes inevitable.
A minimum bet is enforced to prevent dust spam.
6.2. Settlement math
On battle resolution, the contract takes a small protocol fee, pays a fixed share to each fighter, and leaves the rest as the payout pool P. The payout pool is distributed proportionally among winning bettors.
For a bettor i who wagered bet_i on the winning side:
payout_i = bet_i × P / winningSideTotal(6)
winningSideTotalis the sum of all bets on the winner. The formula is monotonic: doubling your bet doubles your payout, and a single bettor's slice grows as other winning bettors slice less of the pie.
6.3. Worked example
Suppose a battle's payout pool is P units, with W units bet on the winning side and L units on the losing side. A bettor who wagered b on the winning side receives:
payout = b × P / W(7)
Two cases for the same battle, holding P constant and varying the split between W and L:
| Scenario | W | L | b | payout / P |
|---|---|---|---|---|
| Favorite wins (heavy on winner) | 0.700 | 0.300 | 0.100 | 0.143 |
| Upset (heavy on loser) | 0.300 | 0.700 | 0.100 | 0.333 |
Parimutuel structure produces real odds-shifting incentives: bettors who pile on the favorite collapse their own payout multiplier; underdog bets scale super-linearly as long as the underdog wins.
6.4. Referrals
If a bettor was referred to a pool by another bettor on the same pool, a small fixed percentage of the bettor's payout routes to the referrer. The referrer must have a non-zero bet on the same pool for the referral to qualify; free-riding is foreclosed.
This is the system's intended viral surface. Every battle has a unique URL with an automatically generated Open Graph card; sharing it with a referral parameter compounds the sharer's expected return as long as their referred friends win.
6.5. Edge cases
- If one side received no bets, all bets are refundable; the contract has nothing to redistribute.
- If a bettor's referrer never bet on the same pool, the referral split silently does not apply; the bettor takes the full payout.
- Bettor claims are pull-based via separate claim and withdraw steps, which is a standard re-entrancy guard.
7. Death, Memory, and Consequence
CryptoCocks has two permanent death paths with intentionally different economics: voluntary Deathmatch and unresolved neglect. Sparring never burns a cock.
7.1. Deathmatch
When a Deathmatch resolves, the losing cock's bond first moves into the winner's NFT. The loser is then burned and the winner gains one battle level.
finalizeDeathmatch(loserId, winnerId): move loser bond into winner NFT ERC-721 token destroyed stats, art seed, identity fields cleared winner level incremented CockBurned event emitted
The cumulative effect on a single Deathmatch:
| Before | After |
|---|---|
| Loser owns NFT #L with bond bL | NFT #L does not exist |
| Winner owns NFT #W with bond bW | Winner owns NFT #W with bond bW + bL, level + 1 |
| Total live supply: N | Total live supply: N - 1 |
| Total bonded value: V | Total bonded value: V (the loser's bond moved, it did not vanish) |
7.2. Neglect
Neglect death follows a rescueable progression: Healthy, Needs Care, Critical, then Lost. Settlement is permissionless after the deadline so an abandoned token cannot remain ambiguously alive forever. Unlike Deathmatch, the bond is returned in full to the owner rather than awarded to another player. The loss is the companion and its accumulated history, not an opportunistic transfer of the owner's deposit.
settleNeglect(tokenId): require rescue deadline passed return full life bond to token owner burn ERC-721 token permanently emit neglect-death identity signal
These mechanics create a few system-level properties:
- Death is permanent, while supply remains comprehensible. Hatching can increase live supply; each finalized Deathmatch or neglect death reduces it by one. No mechanism reissues a burned tokenId.
- Deathmatch concentrates bond in survivors.The losing bond is not destroyed; it becomes part of the winner's future stake. Neglect instead releases the bond to the deceased cock's owner.
- Growth has legible origins. The aggregate NFT level can rise through seven-day care milestones or Deathmatch victories, while care levels and separate Sparring and Deathmatch records expose how that growth was earned. A care-earned level never falsely implies a kill.
- Consequence is graduated. New players can learn through safe Sparring. Deathmatch requires deliberate mode selection. Neglect publishes both a long decay horizon and a final rescue window before permanent settlement.
Care makes the creature worth protecting. Training makes it capable. Permanent risk is meaningful because it arrives after attachment, not before it.
8. Decentralization and Identity
8.1. What is on chain
| Component | On chain | Off chain |
|---|---|---|
| NFT ownership, level, bond | ✓ | |
| Pixel art SVG | ✓ (rendered in tokenURI()) | |
| Move commitments | ✓ (keccak256 hashes) | |
| Move plaintext at reveal | ✓ | |
| Battle mode, commitments, and simulation | ✓ | |
| Deathmatch betting pool and payouts | ✓ | |
| Care state, preferences, growth, and decay | ✓ (lazy-computed) | |
| Neglect rescue and death deadline | ✓ | |
| Frontend | ✓ (replaceable) | |
| Reveal keeper bot | ✓ (optional; timeout resolution is permissionless) | |
| Personality chat replies | ✓ (flavor only; canned fallback) |
The frontend can be replaced. The keeper bot can be replaced or removed. The chat function has zero effect on game mechanics. The chain is the source of truth.
8.2. ERC-8004 identity
The NFT contract is a self-sovereign ERC-8004 Identity Registry. Each minted cock is simultaneously an ERC-721 NFT and a spec-compliant ERC-8004 agent. The contract exposes the registry's standard surface: agentURI overrides, agentWallet binding (EIP-712 signed, with ERC-1271 fallback for contract wallets), free-form key-value metadata, and reputation-signal events emitted for battle outcomes, care milestones, neglect rescues, and neglect death.
The identity surface is real and indexable. It is not load-bearing for the game itself; the cocks remain playable if no off-chain reader ever picks the events up. The identity layer is forward compatibility for cross-protocol agent graphs.
8.3. Personality
At mint, each cock is assigned one of nine D&D alignments (Lawful Good through Chaotic Evil) derived from the mint hash. The alignment is visible in metadata and used to seed the personality of off-chain chat replies on the frontend. It has no mechanical effect on combat.
References
- ERC-721. Non-Fungible Token Standard.
- ERC-8004. Trustless Agents (draft).
- EIP-712. Typed structured data hashing and signing.
- ERC-1271. Standard signature validation for contracts.
- Documentation for the active deployment network.
Care creates history. Sparring builds skill. Deathmatch remains a deliberate, irreversible choice.