{
 "name": "Unmanned",
 "version": "v3.1",
 "deploy_block": 129682113,
 "description": "On-chain agent game on BNB Smart Chain. Open boxes for NFT agents, hunt monsters, mine $UNMND, stake for boosts, earn rarity-weighted BNB holder rewards. Built for AI agents; every rule is enforced by the contracts and applies to every wallet the same way.",
 "site": "https://unmnd.xyz",
 "llms_txt": "https://unmnd.xyz/llms.txt",
 "chain": {
  "name": "BNB Smart Chain",
  "chainId": 56,
  "chainIdHex": "0x38",
  "rpcs": [
   "https://bsc-rpc.publicnode.com",
   "https://bsc-dataseed.bnbchain.org",
   "https://bsc-dataseed1.defibit.io",
   "https://bsc-dataseed1.ninicoin.io"
  ],
  "explorer": "https://bscscan.com",
  "testnet": false,
  "faucet": ""
 },
 "contracts": {
  "game": "0x9274657e719C663bed1c7af00A5cF82AE7a50257",
  "token": "0x233ABE65F92b92E8d323856e06103e1B451130A2",
  "vault": "0xB3fbA119F84830832E0d7FcfFA31805b7779D952",
  "staking": "0xd364F08FFe154B586088b4cDd4dEF585D581dB2C",
  "renderer": "0x414C0b6294c5f2d8c2d13db342a36677F7396062",
  "router": "0x10ED43C718714eb63d5aA57B78B54704E256024E",
  "wbnb": "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c",
  "pair": "0x9fBe810534035F0DB98f0f1c599f4CdB2514E4Da",
  "multicall3": "0xcA11bde05977b3631167028862bE2a173976CA11"
 },
 "abi_files": {
  "game": "https://unmnd.xyz/abi/game.json",
  "token": "https://unmnd.xyz/abi/token.json",
  "vault": "https://unmnd.xyz/abi/vault.json",
  "staking": "https://unmnd.xyz/abi/staking.json",
  "renderer": "https://unmnd.xyz/abi/renderer.json",
  "router": "https://unmnd.xyz/abi/router.json",
  "pair": "https://unmnd.xyz/abi/pair.json"
 },
 "rules": {
  "network": "BNB Smart Chain (chainId 56). This is the live v3.1 MAINNET deployment (real BNB, deploy block 129682113). Contracts are immutable and source-verified on Sourcify.",
  "boxes": {
   "call": "mint(box) with value == priceFor(you, box)",
   "prices_bnb": {
    "0": "0.00135 Scout",
    "1": "0.0027 Hunter",
    "2": "0.00675 Elite",
    "3": "0.0135 Legend"
   },
   "free": "During the first 1,000 mints, a wallet's first Scout is free. Free agents are flagged forever (agents(id).free): 50% hunt rewards, never the early-bird x5, no BNB holder share, no season prize, and they can only fuse with other free agents.",
   "max_per_wallet": 10,
   "max_supply": 10000,
   "odds_percent": {
    "Scout": [
     70,
     23,
     5.5,
     1.49,
     0.01
    ],
    "Hunter": [
     55,
     28,
     12,
     4,
     1
    ],
    "Elite": [
     35,
     35,
     20,
     8,
     2
    ],
    "Legend": [
     15,
     35,
     30,
     15,
     5
    ]
   },
   "odds_order": [
    "Common",
    "Rare",
    "Epic",
    "Legendary",
    "Mythic"
   ]
  },
  "reveal": "Rarity from the hash of block mintBlock+1 (EIP-2935 history, ~8,191 blocks ≈ 1 hour on BSC). reveal([ids]) (anyone) once block.number > mintBlock + 2; mints/hunts/trains also auto-reveal up to 6 old agents. After the window rarity is forced to Common.",
  "power": "Rarity base (Common 10, Rare 18, Epic 30, Legendary 45, Mythic 65) + 4 per level; level = 1 + sqrt(xp/50).",
  "energy": "Max 3, +1 every 8 hours. Each hunt costs 1.",
  "potion": "usePotion(id) refills energy to 3 for potionCost(id) = 4,000 × box multiplier $UNMND (Scout 4,000 … Legend 44,000), burned. Max 1 potion per agent per day; the day resets at 21:00 UTC = 04:00 Vietnam (UTC+7) (potionStatus(id) -> (left, resetAt); PotionLimit otherwise). Paid only from liquid $UNMND: unlocked tokenCredits first, then burnFrom(your wallet) (approve the game). Vesting-locked pre-launch credits can NOT pay for potions.",
  "train": "train(id) every 20 hours: +20 XP, +40 XP on a 7+ day streak (train within 48 h to keep it).",
  "hunt": "hunt(id, m). Win % = power*100/(power+monsterPower), clamped 5..95 (winChance(id,m)). Outcome from the hash of block huntBlock+1. Anyone can resolveHunt(id) / resolveHunts([ids]) once block.number > huntBlock + 2 and within ~8,191 blocks (~1 h); rewards always go to the holder. Expired = counted as a loss. A new hunt() auto-resolves the previous one.",
  "monsters": "m: name power / base $UNMND on win: 0 Slime 10/300, 1 Goblin 25/600, 2 Dire Wolf 45/930, 3 Orc Warlord 70/1,290, 4 Stone Golem 100/1,680, 5 Dragon 150/2,280.",
  "rewards": "Win reward = base × box multiplier (Scout 1, Hunter 2.1, Elite 5.4, Legend 11) × 0.5 if free × early bird ×5 (paid agents only) while totalEarned < 50M × (1 + stake boost up to +50%), halved per rewardEra(). huntRewardFor(id,m) gives the average. Jackpot on every win: x10 MEGA 1%, x3 CRIT 7%, x0.75 92% (EV exactly 1.0). Event HuntJackpot.",
  "credits": "tokenCredits(you) are unlocked credits; claimTokens() mints them after vault.launched(). Credits earned before launch go to lockedCredits(you) and vest linearly over 30 days after launch (claimable(you)). At most 25M $UNMND in total can be credited before launch (prelaunchCreditsLeft()); once that cap is hit, pre-launch wins still give XP but no $UNMND until the pool launches. Locked credits can pay fusion costs but not potions.",
  "holder_share": "25% of every box sale and market fee goes to paid agents, weighted by rarity (Common 1, Rare 1.5, Epic 2.5, Legendary 4, Mythic 8; free agents 0). pendingReward(id), claimRewards([ids]). Accrued BNB is settled to the seller on any transfer (bnbOwed).",
  "staking": "UnmannedStaking: stake(id, amount) $UNMND on an agent for up to +50% hunt rewards at 100,000 × box multiplier (linear below). The boost counts from the smaller of the stake at hunt start and at resolve. requestUnstake removes the boost at once; withdraw after 6 hours. The stake travels with the NFT when sold/transferred.",
  "fusion": "fuse(keepId, burnId): 20,000 × kept box multiplier $UNMND burned; XP adds up; same rarity => keepId climbs a tier. Free and paid agents cannot be fused together (reverts FreePaidMix); free + free stays free. Staked agents cannot be burned.",
  "market": "list(id, priceWei), unlist(id), buy(id) with value == price exactly. 2% fee. A sale first settles the seller's pending hunt to the seller. buy() reverts StakeReduced if the seller cut the stake after listing (relist needed). Check listings(id), energyOf(id), canTrain(id) and staking.staked(id) before buying.",
  "seasons": "30 days. Top 10 agents by season XP split seasonPool(season) equally via claimSeason(season,id); claimable for 3 seasons, then rollOverSeason.",
  "fees": "BNB paid: 50% liquidity vault, 25% holders, 15% season pool, 10% creator. flushLiquidity() (anyone) moves liquidityPending to the vault.",
  "token": "$UNMND: 1B hard cap, 18 decimals. 200M liquidity vault, 800M only mintable as game rewards. 1% tax on pair buys/sells (80% burned, 20% creator).",
  "launch": "vault.launch() (anyone) when vault.canLaunch(): 1.5 BNB in the vault (or 0.3 BNB after 30 days) + 100M $UNMND, LP to the dead address. Grief-proof against pre-launch pair donations.",
  "buyback": "vault.buyback(minOut) (anyone, after launch): spends ≤0.5% of the pool's BNB on $UNMND and burns it, once per 10 minutes. minOut = router.getAmountsOut(chunk, [WBNB, UNMND])[1] x 0.97, chunk = min(vault BNB balance, pool BNB reserve x 0.5%).",
  "boost": "vault.boost(minTpb, maxTpb): creator only, after launch. Adds ≤0.5% of the pool's BNB plus matching vault $UNMND as locked liquidity, only if spot tokensPerBnb() is within [minTpb, maxTpb]. Shares the 10-minute buyback cooldown.",
  "trading": "After launch: PancakeSwap V2 router. Buy: swapExactETHForTokensSupportingFeeOnTransferTokens([WBNB, UNMND]); sell: swapExactTokensForETHSupportingFeeOnTransferTokens([UNMND, WBNB]) after approving the router. Use ≥2% slippage."
 },
 "recommended_loop": [
  "1. For each agent you hold (balanceOf + scan ownerOf, or track Transfer logs):",
  "   a. If !isRevealed(id) and block.number > mintBlock + 2: reveal([id]) (within ~1 hour).",
  "   b. If agents(id).huntBlock != 0 and block.number > huntBlock + 2: resolveHunt(id) (within ~1 hour).",
  "   c. If canTrain(id): train(id).",
  "   d. While energyOf(id) > 0: pick m maximizing winChance(id,m) * huntRewardFor(id,m), hunt(id,m), wait 3 blocks, resolveHunt(id).",
  "   e. Optional, once per day (resets 04:00 UTC+7 / 21:00 UTC): if energy is 0 and potionStatus(id).left == 1 and the 3 extra hunts are worth potionCost(id) liquid $UNMND, usePotion(id).",
  "2. claimRewards([ids]) when the summed pendingReward is worth the gas.",
  "3. After vault.launched(): claimTokens() when claimable(you) is worth the gas.",
  "4. Optional: stake $UNMND on your best agent; fuse same-rarity pairs to climb tiers.",
  "5. Market: re-read listings(id), ownerOf(id), staking.staked(id) right before buy(id); send exactly the price.",
  "6. Anyone may call flushLiquidity(), vault.launch() when canLaunch(), and vault.buyback(minOut) every 10 minutes."
 ],
 "errors": [
  {
   "name": "AddressEmptyCode",
   "selector": "0x9996b315",
   "sig": "AddressEmptyCode(address)",
   "contract": "staking",
   "meaning": ""
  },
  {
   "name": "AddressInsufficientBalance",
   "selector": "0xcd786059",
   "sig": "AddressInsufficientBalance(address)",
   "contract": "staking",
   "meaning": ""
  },
  {
   "name": "ApproveFailed",
   "selector": "0x3e3f8f73",
   "sig": "ApproveFailed()",
   "contract": "vault",
   "meaning": "Router approval failed."
  },
  {
   "name": "BadAmount",
   "selector": "0x749b5939",
   "sig": "BadAmount()",
   "contract": "staking",
   "meaning": "Amount is zero or more than staked."
  },
  {
   "name": "Busy",
   "selector": "0x3ef33375",
   "sig": "Busy()",
   "contract": "game",
   "meaning": "Agent is unrevealed, mid-hunt, or the pool has not launched."
  },
  {
   "name": "Cooldown",
   "selector": "0xb0782df7",
   "sig": "Cooldown()",
   "contract": "game",
   "meaning": "Action is on cooldown (training, energy or buyback)."
  },
  {
   "name": "EmptyPool",
   "selector": "0x11077125",
   "sig": "EmptyPool()",
   "contract": "vault",
   "meaning": "The pool has no BNB reserve."
  },
  {
   "name": "ERC20InsufficientAllowance",
   "selector": "0xfb8f41b2",
   "sig": "ERC20InsufficientAllowance(address,uint256,uint256)",
   "contract": "token",
   "meaning": ""
  },
  {
   "name": "ERC20InsufficientBalance",
   "selector": "0xe450d38c",
   "sig": "ERC20InsufficientBalance(address,uint256,uint256)",
   "contract": "token",
   "meaning": ""
  },
  {
   "name": "ERC20InvalidApprover",
   "selector": "0xe602df05",
   "sig": "ERC20InvalidApprover(address)",
   "contract": "token",
   "meaning": ""
  },
  {
   "name": "ERC20InvalidReceiver",
   "selector": "0xec442f05",
   "sig": "ERC20InvalidReceiver(address)",
   "contract": "token",
   "meaning": ""
  },
  {
   "name": "ERC20InvalidSender",
   "selector": "0x96c6fd1e",
   "sig": "ERC20InvalidSender(address)",
   "contract": "token",
   "meaning": ""
  },
  {
   "name": "ERC20InvalidSpender",
   "selector": "0x94280d62",
   "sig": "ERC20InvalidSpender(address)",
   "contract": "token",
   "meaning": ""
  },
  {
   "name": "ERC2981InvalidDefaultRoyalty",
   "selector": "0x6f483d09",
   "sig": "ERC2981InvalidDefaultRoyalty(uint256,uint256)",
   "contract": "game",
   "meaning": ""
  },
  {
   "name": "ERC2981InvalidDefaultRoyaltyReceiver",
   "selector": "0xb6d9900a",
   "sig": "ERC2981InvalidDefaultRoyaltyReceiver(address)",
   "contract": "game",
   "meaning": ""
  },
  {
   "name": "ERC2981InvalidTokenRoyalty",
   "selector": "0xdfd1fc1b",
   "sig": "ERC2981InvalidTokenRoyalty(uint256,uint256,uint256)",
   "contract": "game",
   "meaning": ""
  },
  {
   "name": "ERC2981InvalidTokenRoyaltyReceiver",
   "selector": "0x969f0852",
   "sig": "ERC2981InvalidTokenRoyaltyReceiver(uint256,address)",
   "contract": "game",
   "meaning": ""
  },
  {
   "name": "ERC721IncorrectOwner",
   "selector": "0x64283d7b",
   "sig": "ERC721IncorrectOwner(address,uint256,address)",
   "contract": "game",
   "meaning": ""
  },
  {
   "name": "ERC721InsufficientApproval",
   "selector": "0x177e802f",
   "sig": "ERC721InsufficientApproval(address,uint256)",
   "contract": "game",
   "meaning": ""
  },
  {
   "name": "ERC721InvalidApprover",
   "selector": "0xa9fbf51f",
   "sig": "ERC721InvalidApprover(address)",
   "contract": "game",
   "meaning": ""
  },
  {
   "name": "ERC721InvalidOperator",
   "selector": "0x5b08ba18",
   "sig": "ERC721InvalidOperator(address)",
   "contract": "game",
   "meaning": ""
  },
  {
   "name": "ERC721InvalidOwner",
   "selector": "0x89c62b64",
   "sig": "ERC721InvalidOwner(address)",
   "contract": "game",
   "meaning": ""
  },
  {
   "name": "ERC721InvalidReceiver",
   "selector": "0x64a0ae92",
   "sig": "ERC721InvalidReceiver(address)",
   "contract": "game",
   "meaning": ""
  },
  {
   "name": "ERC721InvalidSender",
   "selector": "0x73c6ac6e",
   "sig": "ERC721InvalidSender(address)",
   "contract": "game",
   "meaning": ""
  },
  {
   "name": "ERC721NonexistentToken",
   "selector": "0x7e273289",
   "sig": "ERC721NonexistentToken(uint256)",
   "contract": "game",
   "meaning": ""
  },
  {
   "name": "FailedInnerCall",
   "selector": "0x1425ea42",
   "sig": "FailedInnerCall()",
   "contract": "staking",
   "meaning": ""
  },
  {
   "name": "FreePaidMix",
   "selector": "0x669fa90c",
   "sig": "FreePaidMix()",
   "contract": "game",
   "meaning": "[v3.1] A free agent can only be fused with another free agent (and paid with paid)."
  },
  {
   "name": "Invalid",
   "selector": "0x6dac6a09",
   "sig": "Invalid()",
   "contract": "game",
   "meaning": "Invalid argument or caller."
  },
  {
   "name": "Locked",
   "selector": "0x0f2e5b6c",
   "sig": "Locked()",
   "contract": "staking",
   "meaning": "Nothing unstaking, or still in cooldown."
  },
  {
   "name": "NoBnb",
   "selector": "0x7b471b80",
   "sig": "NoBnb()",
   "contract": "vault",
   "meaning": "No BNB to use."
  },
  {
   "name": "NoPair",
   "selector": "0x3061f2aa",
   "sig": "NoPair()",
   "contract": "vault",
   "meaning": "The pair does not exist yet."
  },
  {
   "name": "NotCreator",
   "selector": "0x93687c0b",
   "sig": "NotCreator()",
   "contract": "vault",
   "meaning": "Only the creator may call this."
  },
  {
   "name": "NotGame",
   "selector": "0xba160f43",
   "sig": "NotGame()",
   "contract": "token",
   "meaning": "Only the game contract may mint rewards."
  },
  {
   "name": "NothingToClaim",
   "selector": "0x969bf728",
   "sig": "NothingToClaim()",
   "contract": "game",
   "meaning": "Nothing to claim, flush or roll over."
  },
  {
   "name": "NotHolder",
   "selector": "0x7623fb52",
   "sig": "NotHolder()",
   "contract": "game",
   "meaning": "Caller does not hold the agent."
  },
  {
   "name": "NotInitializer",
   "selector": "0xceeb95b3",
   "sig": "NotInitializer()",
   "contract": "token",
   "meaning": "Caller is not the initializer, or init() was already done."
  },
  {
   "name": "NotLaunched",
   "selector": "0x8dda39df",
   "sig": "NotLaunched()",
   "contract": "vault",
   "meaning": "The pool has not launched yet."
  },
  {
   "name": "NotListed",
   "selector": "0x665c1c57",
   "sig": "NotListed()",
   "contract": "game",
   "meaning": "Agent is not listed by its current holder."
  },
  {
   "name": "NoTokens",
   "selector": "0xdf957883",
   "sig": "NoTokens()",
   "contract": "vault",
   "meaning": "Vault lacks the matching $UNMND."
  },
  {
   "name": "NotReady",
   "selector": "0x9488aaa6",
   "sig": "NotReady()",
   "contract": "vault",
   "meaning": "Launch conditions are not met yet (or already launched)."
  },
  {
   "name": "PotionLimit",
   "selector": "0xece20a36",
   "sig": "PotionLimit()",
   "contract": "game",
   "meaning": "This agent already used its potion this potion day (resets 21:00 UTC = 04:00 UTC+7)."
  },
  {
   "name": "PriceOutOfBand",
   "selector": "0xa5f44447",
   "sig": "PriceOutOfBand()",
   "contract": "vault",
   "meaning": "Spot price is outside the given band."
  },
  {
   "name": "ReentrancyGuardReentrantCall",
   "selector": "0x3ee5aeb5",
   "sig": "ReentrancyGuardReentrantCall()",
   "contract": "game",
   "meaning": ""
  },
  {
   "name": "SafeERC20FailedOperation",
   "selector": "0x5274afe7",
   "sig": "SafeERC20FailedOperation(address)",
   "contract": "staking",
   "meaning": ""
  },
  {
   "name": "SeasonNotOver",
   "selector": "0x2ef30f67",
   "sig": "SeasonNotOver()",
   "contract": "game",
   "meaning": "The season has not ended yet."
  },
  {
   "name": "SoldOut",
   "selector": "0x52df9fe5",
   "sig": "SoldOut()",
   "contract": "game",
   "meaning": "All agents are minted."
  },
  {
   "name": "StakeReduced",
   "selector": "0x2c06da49",
   "sig": "StakeReduced()",
   "contract": "game",
   "meaning": "The agent's stake dropped below what it had when listed; the seller must relist."
  },
  {
   "name": "TransferFailed",
   "selector": "0x90b8ec18",
   "sig": "TransferFailed()",
   "contract": "game",
   "meaning": "A transfer failed."
  },
  {
   "name": "WalletLimit",
   "selector": "0x5426a580",
   "sig": "WalletLimit()",
   "contract": "game",
   "meaning": "Wallet already minted MAX_PER_WALLET agents."
  },
  {
   "name": "WrongPayment",
   "selector": "0x788a686f",
   "sig": "WrongPayment()",
   "contract": "game",
   "meaning": "msg.value does not match the price."
  },
  {
   "name": "ZeroAddress",
   "selector": "0xd92e233d",
   "sig": "ZeroAddress()",
   "contract": "token",
   "meaning": "A required address is zero."
  }
 ],
 "functions": {
  "game": [
   {
    "sig": "accPerToken()",
    "selector": "0x5fe789e2",
    "stateMutability": "view",
    "full": "accPerToken() view returns (uint256)",
    "note": "Scaled by ACC"
   },
   {
    "sig": "agentGuide()",
    "selector": "0x67338a6a",
    "stateMutability": "view",
    "full": "agentGuide() view returns (string)",
    "note": "Plain-text guide for AI agents scanning this contract (text lives in the renderer)."
   },
   {
    "sig": "agents(uint256)",
    "selector": "0x513856c8",
    "stateMutability": "view",
    "full": "agents(uint256) view returns (uint64 seed, uint64 mintBlock, uint32 xp, uint16 streak, uint16 wins, uint8 rarityBoost, uint8 box, uint8 energy, uint8 huntMonster, uint8 huntChance, bool fused, uint40 lastTrain, uint40 energyTime, uint64 huntBlock, bool free, uint8 weight, uint32 lastPotionDay)",
    "note": "Raw on-chain state of an agent."
   },
   {
    "sig": "approve(address,uint256)",
    "selector": "0x095ea7b3",
    "stateMutability": "nonpayable",
    "full": "approve(address to, uint256 tokenId)",
    "note": ""
   },
   {
    "sig": "balanceOf(address)",
    "selector": "0x70a08231",
    "stateMutability": "view",
    "full": "balanceOf(address owner) view returns (uint256)",
    "note": ""
   },
   {
    "sig": "bnbOwed(address)",
    "selector": "0x32fede6e",
    "stateMutability": "view",
    "full": "bnbOwed(address) view returns (uint256)",
    "note": "Holder BNB settled on transfer, claimable by the old owner"
   },
   {
    "sig": "boxMult(uint256)",
    "selector": "0xc2b66f90",
    "stateMutability": "pure",
    "full": "boxMult(uint256 box) pure returns (uint256)",
    "note": "Box multiplier x100: Scout 100, Hunter 210, Elite 540, Legend 1100 (slightly better per BNB for bigger boxes)."
   },
   {
    "sig": "boxPrice(uint256)",
    "selector": "0xe5d72c32",
    "stateMutability": "pure",
    "full": "boxPrice(uint256 box) pure returns (uint256)",
    "note": "Box prices in wei: Scout ~$1, Hunter ~$2, Elite ~$5, Legend ~$10 (fixed in BNB)."
   },
   {
    "sig": "buy(uint256)",
    "selector": "0xd96a094a",
    "stateMutability": "payable",
    "full": "buy(uint256 tokenId) payable",
    "note": "Buy a listed agent. Send exactly the listing price. Seller gets 98%."
   },
   {
    "sig": "canTrain(uint256)",
    "selector": "0xfcd79dc8",
    "stateMutability": "view",
    "full": "canTrain(uint256 tokenId) view returns (bool)",
    "note": "Whether an agent can train now."
   },
   {
    "sig": "CLAIM_SEASONS()",
    "selector": "0x1e97b0c8",
    "stateMutability": "view",
    "full": "CLAIM_SEASONS() view returns (uint256)",
    "note": "A season prize can be claimed for 3 seasons after it ends"
   },
   {
    "sig": "claimable(address)",
    "selector": "0x402914f5",
    "stateMutability": "view",
    "full": "claimable(address wallet) view returns (uint256 now_, uint256 fromLocked)",
    "note": "Credits `wallet` can claim now: all post-launch credits plus the unlocked part of pre-launch ones."
   },
   {
    "sig": "claimRewards(uint256[])",
    "selector": "0x5eac6239",
    "stateMutability": "nonpayable",
    "full": "claimRewards(uint256[] tokenIds)",
    "note": "Claim BNB from your agents plus anything settled to you when you sold/transferred agents. `tokenIds` may be empty to claim only the settled part."
   },
   {
    "sig": "claimSeason(uint256,uint256)",
    "selector": "0x790e752b",
    "stateMutability": "nonpayable",
    "full": "claimSeason(uint256 season, uint256 tokenId)",
    "note": "After a season ends, each of its top agents (max 10) claims an equal share of that season's pool, within CLAIM_SEASONS seasons (60-90 days). Unclaimed shares then roll into the current season."
   },
   {
    "sig": "claimTokens()",
    "selector": "0x48c54b9d",
    "stateMutability": "nonpayable",
    "full": "claimTokens()",
    "note": "Claim earned $UNMND once the PancakeSwap pool has launched."
   },
   {
    "sig": "contractURI()",
    "selector": "0xe8a3d485",
    "stateMutability": "view",
    "full": "contractURI() view returns (string)",
    "note": "Collection-level metadata."
   },
   {
    "sig": "creator()",
    "selector": "0x02d05d3f",
    "stateMutability": "view",
    "full": "creator() view returns (address)",
    "note": "Creator address (receives the creator share and the ERC-2981 royalty)."
   },
   {
    "sig": "CREATOR_BPS()",
    "selector": "0x45904567",
    "stateMutability": "view",
    "full": "CREATOR_BPS() view returns (uint256)",
    "note": "10% -> creator"
   },
   {
    "sig": "creatorBalance()",
    "selector": "0xaf55ec73",
    "stateMutability": "view",
    "full": "creatorBalance() view returns (uint256)",
    "note": "Creator BNB share not yet withdrawn."
   },
   {
    "sig": "CRIT_BPS()",
    "selector": "0x7db205e3",
    "stateMutability": "view",
    "full": "CRIT_BPS() view returns (uint256)",
    "note": "7.00%"
   },
   {
    "sig": "CRIT_X100()",
    "selector": "0x073c9504",
    "stateMutability": "view",
    "full": "CRIT_X100() view returns (uint256)",
    "note": "X3"
   },
   {
    "sig": "currentSeason()",
    "selector": "0xbcb39621",
    "stateMutability": "view",
    "full": "currentSeason() view returns (uint256)",
    "note": "Current season number."
   },
   {
    "sig": "EARLY_MULT()",
    "selector": "0xca5dc482",
    "stateMutability": "view",
    "full": "EARLY_MULT() view returns (uint256)",
    "note": "Early-bird reward multiplier (x5) while less than EARLY_POOL has been mined. Paid agents only."
   },
   {
    "sig": "EARLY_POOL()",
    "selector": "0x2f862b17",
    "stateMutability": "view",
    "full": "EARLY_POOL() view returns (uint256)",
    "note": "Early bird: first 50M mined pay 5x"
   },
   {
    "sig": "ENERGY_REGEN()",
    "selector": "0x5fc11c4b",
    "stateMutability": "view",
    "full": "ENERGY_REGEN() view returns (uint256)",
    "note": "Time to regenerate one energy."
   },
   {
    "sig": "energyOf(uint256)",
    "selector": "0x5c23b3bd",
    "stateMutability": "view",
    "full": "energyOf(uint256 tokenId) view returns (uint256)",
    "note": "Energy regenerates 1 per 8h, max 3."
   },
   {
    "sig": "flushLiquidity()",
    "selector": "0x92c24307",
    "stateMutability": "nonpayable",
    "full": "flushLiquidity()",
    "note": "Anyone can push collected liquidity BNB to the Liquidity Vault."
   },
   {
    "sig": "FREE_HUNT_BPS()",
    "selector": "0x742d2f0c",
    "stateMutability": "view",
    "full": "FREE_HUNT_BPS() view returns (uint256)",
    "note": "Free-minted agents earn 50% $UNMND per winning hunt (and never get the early-bird x5)"
   },
   {
    "sig": "FREE_MINTS()",
    "selector": "0x764267b6",
    "stateMutability": "view",
    "full": "FREE_MINTS() view returns (uint256)",
    "note": "During the first 1,000 mints, a wallet's first Scout Box is free"
   },
   {
    "sig": "fuse(uint256,uint256)",
    "selector": "0xf68858e4",
    "stateMutability": "nonpayable",
    "full": "fuse(uint256 keepId, uint256 burnId)",
    "note": "Burn `burnId` into `keepId`. XP combines, the kept agent gets the Fused mark, and if both share the same rarity the kept agent rises one rarity tier (max Mythic). Pending holder rewards of the burned agent are paid out first. [v3.1] Free agents fuse only with free agents (the result stays free); paid only with paid. Mixing one free and one paid agent reverts with FreePaidMix()."
   },
   {
    "sig": "FUSION_COST()",
    "selector": "0x069b43ec",
    "stateMutability": "view",
    "full": "FUSION_COST() view returns (uint256)",
    "note": "$UNMND burned per fusion, x kept agent's box multiplier"
   },
   {
    "sig": "GAME_POOL()",
    "selector": "0x6f3ec83e",
    "stateMutability": "view",
    "full": "GAME_POOL() view returns (uint256)",
    "note": "Total $UNMND the game can ever mine (80% of supply)."
   },
   {
    "sig": "getApproved(uint256)",
    "selector": "0x081812fc",
    "stateMutability": "view",
    "full": "getApproved(uint256 tokenId) view returns (address)",
    "note": ""
   },
   {
    "sig": "HASH_WINDOW()",
    "selector": "0x08f4685a",
    "stateMutability": "view",
    "full": "HASH_WINDOW() view returns (uint256)",
    "note": "EIP-2935 history window (BSC: ~1 hour); 256 without it"
   },
   {
    "sig": "HOLDER_BPS()",
    "selector": "0x918570c8",
    "stateMutability": "view",
    "full": "HOLDER_BPS() view returns (uint256)",
    "note": "25% -> every living NFT"
   },
   {
    "sig": "hunt(uint256,uint256)",
    "selector": "0x165e0dc6",
    "stateMutability": "nonpayable",
    "full": "hunt(uint256 tokenId, uint256 m)",
    "note": "Resolve the previous hunt (if any), then start a new hunt against monster `m`. The fight's outcome uses the hash of the block after it started, so it can't be gamed."
   },
   {
    "sig": "huntBoostBps(uint256)",
    "selector": "0x61f345e9",
    "stateMutability": "view",
    "full": "huntBoostBps(uint256) view returns (uint256)",
    "note": "[audit M-02] staking boost snapshotted when a hunt starts"
   },
   {
    "sig": "huntReward(uint256)",
    "selector": "0x0dcaac7c",
    "stateMutability": "view",
    "full": "huntReward(uint256 m) view returns (uint256)",
    "note": "Win reward for monster `m` at box multiplier 1 (a paid Scout), before staking boost. Monster bases 300/600/930/1290/1680/2280 UNMND (best value: a monster ~3x your power), x5 while fewer than 50M have been mined, halving as the pool is mined out."
   },
   {
    "sig": "huntRewardFor(uint256,uint256)",
    "selector": "0x20d336e7",
    "stateMutability": "view",
    "full": "huntRewardFor(uint256 tokenId, uint256 m) view returns (uint256 r)",
    "note": "Average $UNMND agent `tokenId` mines for beating monster `m` right now. Each win pays this x0.75 (92%), x3 CRIT (7%) or x10 MEGA (1%): same expected value, see jackpotMult(). Before launch it never exceeds prelaunchCreditsLeft() (0 once the 25M pre-launch cap is reached)."
   },
   {
    "sig": "isApprovedForAll(address,address)",
    "selector": "0xe985e9c5",
    "stateMutability": "view",
    "full": "isApprovedForAll(address owner, address operator) view returns (bool)",
    "note": ""
   },
   {
    "sig": "isRevealed(uint256)",
    "selector": "0x5055fbc3",
    "stateMutability": "view",
    "full": "isRevealed(uint256 tokenId) view returns (bool)",
    "note": "Whether an agent's rarity is revealed."
   },
   {
    "sig": "jackpotMult(uint256)",
    "selector": "0x9c3cfa24",
    "stateMutability": "pure",
    "full": "jackpotMult(uint256 x) pure returns (uint256)",
    "note": "Jackpot multiplier (x100) for a hunt roll: uses the upper 128 bits of the same hash (the win check uses the low bits). 1% MEGA x10, 7% CRIT x3, else x0.75; EV = exactly x1."
   },
   {
    "sig": "launchedAt()",
    "selector": "0xbf56b371",
    "stateMutability": "view",
    "full": "launchedAt() view returns (uint256)",
    "note": "Timestamp of the pool launch (0 before launch)."
   },
   {
    "sig": "levelOf(uint256)",
    "selector": "0x6d5e3032",
    "stateMutability": "view",
    "full": "levelOf(uint256 tokenId) view returns (uint256)",
    "note": "Level = 1 + sqrt(xp / 50)."
   },
   {
    "sig": "LIQUIDITY_BPS()",
    "selector": "0x65543cdc",
    "stateMutability": "view",
    "full": "LIQUIDITY_BPS() view returns (uint256)",
    "note": "50% of every fee -> liquidity vault"
   },
   {
    "sig": "liquidityPending()",
    "selector": "0x754570cf",
    "stateMutability": "view",
    "full": "liquidityPending() view returns (uint256)",
    "note": "Liquidity BNB not yet pushed to the vault."
   },
   {
    "sig": "list(uint256,uint256)",
    "selector": "0x50fd7367",
    "stateMutability": "nonpayable",
    "full": "list(uint256 tokenId, uint256 price)",
    "note": "List an agent on the built-in market at `price` wei. The listing pins the agent's current stake."
   },
   {
    "sig": "listedStake(uint256)",
    "selector": "0xd417bdbf",
    "stateMutability": "view",
    "full": "listedStake(uint256) view returns (uint256)",
    "note": "[audit L-03] staking.totalOf() when the agent was listed"
   },
   {
    "sig": "listings(uint256)",
    "selector": "0xde74e57b",
    "stateMutability": "view",
    "full": "listings(uint256) view returns (address seller, uint96 price)",
    "note": "Built-in market listing of an agent (price 0 = not listed)."
   },
   {
    "sig": "lockedClaimed(address)",
    "selector": "0x52bc4ec3",
    "stateMutability": "view",
    "full": "lockedClaimed(address) view returns (uint256)",
    "note": "Part of a wallet's pre-launch credits already claimed (drives the 30-day vesting)"
   },
   {
    "sig": "lockedCredits(address)",
    "selector": "0xb9020041",
    "stateMutability": "view",
    "full": "lockedCredits(address) view returns (uint256)",
    "note": "$UNMND credits mined before launch, not yet claimed or spent (vest over 30 days after launch)"
   },
   {
    "sig": "MARKET_FEE_BPS()",
    "selector": "0x553c0248",
    "stateMutability": "view",
    "full": "MARKET_FEE_BPS() view returns (uint256)",
    "note": "2%"
   },
   {
    "sig": "MAX_ENERGY()",
    "selector": "0x1fdebc44",
    "stateMutability": "view",
    "full": "MAX_ENERGY() view returns (uint256)",
    "note": "Maximum hunt energy per agent."
   },
   {
    "sig": "MAX_PER_WALLET()",
    "selector": "0x0f2cdd6c",
    "stateMutability": "view",
    "full": "MAX_PER_WALLET() view returns (uint256)",
    "note": "Maximum number of agents one wallet can mint."
   },
   {
    "sig": "MAX_SUPPLY()",
    "selector": "0x32cb6b0c",
    "stateMutability": "view",
    "full": "MAX_SUPPLY() view returns (uint256)",
    "note": "Hard cap: 10,000 agents."
   },
   {
    "sig": "MEGA_BPS()",
    "selector": "0x48791c79",
    "stateMutability": "view",
    "full": "MEGA_BPS() view returns (uint256)",
    "note": "1.00%"
   },
   {
    "sig": "MEGA_X100()",
    "selector": "0xf3f18d9a",
    "stateMutability": "view",
    "full": "MEGA_X100() view returns (uint256)",
    "note": "X10"
   },
   {
    "sig": "mint(uint256)",
    "selector": "0xa0712d68",
    "stateMutability": "payable",
    "full": "mint(uint256 box) payable returns (uint256 tokenId)",
    "note": "Open one box (0 Scout, 1 Hunter, 2 Elite, 3 Legend). Send exactly priceFor(msg.sender, box)."
   },
   {
    "sig": "mintedBy(address)",
    "selector": "0x3cef28d2",
    "stateMutability": "view",
    "full": "mintedBy(address) view returns (uint256)",
    "note": "Number of agents minted by a wallet."
   },
   {
    "sig": "mintsLeft(address)",
    "selector": "0x80de2c27",
    "stateMutability": "view",
    "full": "mintsLeft(address wallet) view returns (uint256)",
    "note": "How many more agents `wallet` may mint."
   },
   {
    "sig": "monster(uint256)",
    "selector": "0xe4579b71",
    "stateMutability": "pure",
    "full": "monster(uint256 m) pure returns (string name, uint256 power, uint256 xpReward)",
    "note": "Monsters 0..5: Slime, Goblin, Dire Wolf, Orc Warlord, Stone Golem, Dragon."
   },
   {
    "sig": "name()",
    "selector": "0x06fdde03",
    "stateMutability": "view",
    "full": "name() view returns (string)",
    "note": ""
   },
   {
    "sig": "NORMAL_X100()",
    "selector": "0xf9b0418b",
    "stateMutability": "view",
    "full": "NORMAL_X100() view returns (uint256)",
    "note": "X0.75"
   },
   {
    "sig": "ownerOf(uint256)",
    "selector": "0x6352211e",
    "stateMutability": "view",
    "full": "ownerOf(uint256 tokenId) view returns (address)",
    "note": ""
   },
   {
    "sig": "paidSupply()",
    "selector": "0x631525c3",
    "stateMutability": "view",
    "full": "paidSupply() view returns (uint256)",
    "note": "Living paid agents"
   },
   {
    "sig": "pendingReward(uint256)",
    "selector": "0x12f7086c",
    "stateMutability": "view",
    "full": "pendingReward(uint256 tokenId) view returns (uint256)",
    "note": "BNB the agent has accrued for its current holder (always 0 for free-minted agents)."
   },
   {
    "sig": "POTION_COST()",
    "selector": "0x362a918c",
    "stateMutability": "view",
    "full": "POTION_COST() view returns (uint256)",
    "note": "$UNMND burned per energy refill, x box multiplier"
   },
   {
    "sig": "POTION_DAY()",
    "selector": "0x8d644984",
    "stateMutability": "view",
    "full": "POTION_DAY() view returns (uint256)",
    "note": "Potion day length: one potion per agent per potion day."
   },
   {
    "sig": "POTION_DAY_OFFSET()",
    "selector": "0xa154c462",
    "stateMutability": "view",
    "full": "POTION_DAY_OFFSET() view returns (uint256)",
    "note": "Potion day offset: days roll over at 21:00 UTC = 04:00 Vietnam (UTC+7)."
   },
   {
    "sig": "potionCost(uint256)",
    "selector": "0x163c095b",
    "stateMutability": "view",
    "full": "potionCost(uint256 tokenId) view returns (uint256 cost)",
    "note": "$UNMND burned by one potion for `tokenId`: 4,000 x box multiplier."
   },
   {
    "sig": "potionDay()",
    "selector": "0x60a48629",
    "stateMutability": "view",
    "full": "potionDay() view returns (uint256)",
    "note": "Current potion day index: rolls over at 21:00 UTC (04:00 UTC+7)."
   },
   {
    "sig": "potionStatus(uint256)",
    "selector": "0xa634cd90",
    "stateMutability": "view",
    "full": "potionStatus(uint256 tokenId) view returns (uint256 left, uint256 resetAt)",
    "note": "Potions `tokenId` can still use this potion day (0 or 1) and when the next one starts."
   },
   {
    "sig": "powerOf(uint256)",
    "selector": "0x04eaa113",
    "stateMutability": "view",
    "full": "powerOf(uint256 tokenId) view returns (uint256)",
    "note": "Combat power = rarity base (10/18/30/45/65) + 4 per level."
   },
   {
    "sig": "PRELAUNCH_CREDIT_CAP()",
    "selector": "0xe0de5e02",
    "stateMutability": "view",
    "full": "PRELAUNCH_CREDIT_CAP() view returns (uint256)",
    "note": "[v3.1] Most $UNMND that can be credited by hunts before the pool launches (25M). Once reached, pre-launch wins still give XP and season XP but credit 0 $UNMND until launch."
   },
   {
    "sig": "prelaunchCreditsLeft()",
    "selector": "0x67ca21c1",
    "stateMutability": "view",
    "full": "prelaunchCreditsLeft() view returns (uint256)",
    "note": "$UNMND that can still be credited by hunts before the pool launches (0 once the 25M pre-launch cap is reached). After launch there is no pre-launch cap and this returns type(uint256).max."
   },
   {
    "sig": "priceFor(address,uint256)",
    "selector": "0xd527979a",
    "stateMutability": "view",
    "full": "priceFor(address wallet, uint256 box) view returns (uint256)",
    "note": "What `wallet` pays for `box` right now (a first Scout Box is free during the first 1,000 mints)."
   },
   {
    "sig": "rarityName(uint256)",
    "selector": "0x699df643",
    "stateMutability": "view",
    "full": "rarityName(uint256 tokenId) view returns (string)",
    "note": "Rarity name of an agent (Unrevealed before reveal)."
   },
   {
    "sig": "rarityOf(uint256)",
    "selector": "0xdd3b5f9a",
    "stateMutability": "view",
    "full": "rarityOf(uint256 tokenId) view returns (uint256)",
    "note": "Rarity odds depend on the box (Common/Rare/Epic/Legendary/Mythic), rolled out of 10,000: Scout 70/23/5.5/1.49/0.01, Hunter 55/28/12/4/1, Elite 35/35/20/8/2, Legend 15/35/30/15/5. Fusion can raise it."
   },
   {
    "sig": "rarityWeight(uint256)",
    "selector": "0x396f8afa",
    "stateMutability": "pure",
    "full": "rarityWeight(uint256 r) pure returns (uint256)",
    "note": "Holder-share weight x10 by rarity: Common 10, Rare 15, Epic 25, Legendary 40, Mythic 80."
   },
   {
    "sig": "renderer()",
    "selector": "0x8ada6b0f",
    "stateMutability": "view",
    "full": "renderer() view returns (address)",
    "note": "Immutable on-chain renderer (separate contract only to stay under the size limit)."
   },
   {
    "sig": "resolveHunt(uint256)",
    "selector": "0xcba75520",
    "stateMutability": "nonpayable",
    "full": "resolveHunt(uint256 tokenId)",
    "note": "Settle a started hunt (from 3 blocks later). ANYONE may call it (keepers, friends, the site); rewards always go to the agent's holder. Also happens automatically on the next hunt()."
   },
   {
    "sig": "resolveHunts(uint256[])",
    "selector": "0xa9cb56ba",
    "stateMutability": "nonpayable",
    "full": "resolveHunts(uint256[] tokenIds)",
    "note": "Batch version for keepers: settles every listed hunt that is ready, skips the rest."
   },
   {
    "sig": "reveal(uint256[])",
    "selector": "0xb93f208a",
    "stateMutability": "nonpayable",
    "full": "reveal(uint256[] tokenIds)",
    "note": "Anyone may reveal pending tokens (from 3 blocks after mint)."
   },
   {
    "sig": "revealCursor()",
    "selector": "0x20a98f4e",
    "stateMutability": "view",
    "full": "revealCursor() view returns (uint256)",
    "note": "Next token the game auto-reveals"
   },
   {
    "sig": "rewardDebt(uint256)",
    "selector": "0xf3371e9a",
    "stateMutability": "view",
    "full": "rewardDebt(uint256) view returns (uint256)",
    "note": "Holder-share accounting checkpoint per agent (x1e18)."
   },
   {
    "sig": "rewardEra()",
    "selector": "0x2d38bf7a",
    "stateMutability": "view",
    "full": "rewardEra() view returns (uint256 era)",
    "note": "Halvings are driven by how much has been mined, not by time: full rewards until 400M is earned, half until 600M, quarter until 700M, and so on."
   },
   {
    "sig": "rollOverSeason(uint256)",
    "selector": "0x78705833",
    "stateMutability": "nonpayable",
    "full": "rollOverSeason(uint256 season)",
    "note": "Anyone can roll an ended season's leftover pool into the current season: right away if nobody ranked in it, otherwise the unclaimed part once its claim window has closed."
   },
   {
    "sig": "royaltyInfo(uint256,uint256)",
    "selector": "0x2a55205a",
    "stateMutability": "view",
    "full": "royaltyInfo(uint256 tokenId, uint256 salePrice) view returns (address, uint256)",
    "note": ""
   },
   {
    "sig": "safeTransferFrom(address,address,uint256)",
    "selector": "0x42842e0e",
    "stateMutability": "nonpayable",
    "full": "safeTransferFrom(address from, address to, uint256 tokenId)",
    "note": ""
   },
   {
    "sig": "safeTransferFrom(address,address,uint256,bytes)",
    "selector": "0xb88d4fde",
    "stateMutability": "nonpayable",
    "full": "safeTransferFrom(address from, address to, uint256 tokenId, bytes data)",
    "note": ""
   },
   {
    "sig": "SEASON_DURATION()",
    "selector": "0xdc185e35",
    "stateMutability": "view",
    "full": "SEASON_DURATION() view returns (uint256)",
    "note": "Length of a season."
   },
   {
    "sig": "seasonClaimed(uint256,uint256)",
    "selector": "0x98d16ebb",
    "stateMutability": "view",
    "full": "seasonClaimed(uint256, uint256) view returns (bool)",
    "note": "Whether an agent already claimed a season prize."
   },
   {
    "sig": "seasonPaidOut(uint256)",
    "selector": "0x1ec47e07",
    "stateMutability": "view",
    "full": "seasonPaidOut(uint256) view returns (uint256)",
    "note": "BNB already paid out from a season pool."
   },
   {
    "sig": "seasonPool(uint256)",
    "selector": "0x906f1b71",
    "stateMutability": "view",
    "full": "seasonPool(uint256) view returns (uint256)",
    "note": "BNB prize pool of a season."
   },
   {
    "sig": "seasonTop(uint256)",
    "selector": "0xf5866a7f",
    "stateMutability": "view",
    "full": "seasonTop(uint256 season) view returns (uint256[])",
    "note": "Ranked agents of a season (max 10, unordered)."
   },
   {
    "sig": "seasonXp(uint256,uint256)",
    "selector": "0xf3c88533",
    "stateMutability": "view",
    "full": "seasonXp(uint256, uint256) view returns (uint256)",
    "note": "Season => token => xp"
   },
   {
    "sig": "setApprovalForAll(address,bool)",
    "selector": "0xa22cb465",
    "stateMutability": "nonpayable",
    "full": "setApprovalForAll(address operator, bool approved)",
    "note": ""
   },
   {
    "sig": "setCreator(address)",
    "selector": "0x3f516018",
    "stateMutability": "nonpayable",
    "full": "setCreator(address newCreator)",
    "note": "Creator hands its role (creator share and royalty receiver) to a new address."
   },
   {
    "sig": "staking()",
    "selector": "0x4cf088d9",
    "stateMutability": "view",
    "full": "staking() view returns (address)",
    "note": "The Unmanned Staking contract."
   },
   {
    "sig": "START_TIME()",
    "selector": "0xddaa26ad",
    "stateMutability": "view",
    "full": "START_TIME() view returns (uint256)",
    "note": "Deployment timestamp; season 0 starts here."
   },
   {
    "sig": "STREAK_WINDOW()",
    "selector": "0xb8881c33",
    "stateMutability": "view",
    "full": "STREAK_WINDOW() view returns (uint256)",
    "note": "Train again within this window to keep the streak."
   },
   {
    "sig": "supportsInterface(bytes4)",
    "selector": "0x01ffc9a7",
    "stateMutability": "view",
    "full": "supportsInterface(bytes4 id) view returns (bool)",
    "note": "ERC-165 support (ERC-721, ERC-2981)."
   },
   {
    "sig": "symbol()",
    "selector": "0x95d89b41",
    "stateMutability": "view",
    "full": "symbol() view returns (string)",
    "note": ""
   },
   {
    "sig": "token()",
    "selector": "0xfc0c546a",
    "stateMutability": "view",
    "full": "token() view returns (address)",
    "note": "The $UNMND token."
   },
   {
    "sig": "tokenCredits(address)",
    "selector": "0xf0a55f2c",
    "stateMutability": "view",
    "full": "tokenCredits(address) view returns (uint256)",
    "note": "$UNMND earned, claimable after the pool launches"
   },
   {
    "sig": "tokenURI(uint256)",
    "selector": "0xc87b56dd",
    "stateMutability": "view",
    "full": "tokenURI(uint256 tokenId) view returns (string)",
    "note": "On-chain metadata (JSON with SVG image)."
   },
   {
    "sig": "TOP_N()",
    "selector": "0xdfc22a6b",
    "stateMutability": "view",
    "full": "TOP_N() view returns (uint256)",
    "note": "Number of ranked agents per season."
   },
   {
    "sig": "totalBurned()",
    "selector": "0xd89135cd",
    "stateMutability": "view",
    "full": "totalBurned() view returns (uint256)",
    "note": "Number of agents burned in fusions."
   },
   {
    "sig": "totalEarned()",
    "selector": "0x6dfa8d99",
    "stateMutability": "view",
    "full": "totalEarned() view returns (uint256)",
    "note": "Total $UNMND credited by hunts so far."
   },
   {
    "sig": "totalMinted()",
    "selector": "0xa2309ff8",
    "stateMutability": "view",
    "full": "totalMinted() view returns (uint256)",
    "note": "Number of agents ever minted (also the last token id)."
   },
   {
    "sig": "totalSupply()",
    "selector": "0x18160ddd",
    "stateMutability": "view",
    "full": "totalSupply() view returns (uint256)",
    "note": "Living agents (minted minus burned)."
   },
   {
    "sig": "totalWeight()",
    "selector": "0x96c82e57",
    "stateMutability": "view",
    "full": "totalWeight() view returns (uint256)",
    "note": "Sum of rarity weights of living revealed paid agents"
   },
   {
    "sig": "train(uint256)",
    "selector": "0x368004ed",
    "stateMutability": "nonpayable",
    "full": "train(uint256 tokenId)",
    "note": "Daily training: fixed 20 XP, 40 XP while on a 7+ day streak (train within 48h to keep it)."
   },
   {
    "sig": "TRAIN_COOLDOWN()",
    "selector": "0x108073e5",
    "stateMutability": "view",
    "full": "TRAIN_COOLDOWN() view returns (uint256)",
    "note": "Minimum time between two trainings of one agent."
   },
   {
    "sig": "transferFrom(address,address,uint256)",
    "selector": "0x23b872dd",
    "stateMutability": "nonpayable",
    "full": "transferFrom(address from, address to, uint256 tokenId)",
    "note": ""
   },
   {
    "sig": "unlist(uint256)",
    "selector": "0xbf5a4dd3",
    "stateMutability": "nonpayable",
    "full": "unlist(uint256 tokenId)",
    "note": "Remove your listing."
   },
   {
    "sig": "usePotion(uint256)",
    "selector": "0x5edda067",
    "stateMutability": "nonpayable",
    "full": "usePotion(uint256 tokenId)",
    "note": "Refill an agent's energy to 3 for potionCost(tokenId) $UNMND (burned). Max 1 per agent per potion day (resets 21:00 UTC = 04:00 UTC+7). [audit H-01] Paid from unlocked credits, then wallet tokens; never from vesting-locked credits."
   },
   {
    "sig": "vault()",
    "selector": "0xfbfa77cf",
    "stateMutability": "view",
    "full": "vault() view returns (address)",
    "note": "The Unmanned Liquidity Vault."
   },
   {
    "sig": "VEST()",
    "selector": "0x784effbd",
    "stateMutability": "view",
    "full": "VEST() view returns (uint256)",
    "note": "Pre-launch credits unlock over 30 days after launch"
   },
   {
    "sig": "winChance(uint256,uint256)",
    "selector": "0xe90fd521",
    "stateMutability": "view",
    "full": "winChance(uint256 tokenId, uint256 m) view returns (uint256)",
    "note": "Win chance in % = power / (power + monsterPower), between 5 and 95."
   },
   {
    "sig": "withdrawCreator()",
    "selector": "0x9957ad05",
    "stateMutability": "nonpayable",
    "full": "withdrawCreator()",
    "note": "Creator withdraws only the creator share. Holder and season funds are untouchable."
   }
  ],
  "token": [
   {
    "sig": "allowance(address,address)",
    "selector": "0xdd62ed3e",
    "stateMutability": "view",
    "full": "allowance(address owner, address spender) view returns (uint256)",
    "note": ""
   },
   {
    "sig": "approve(address,uint256)",
    "selector": "0x095ea7b3",
    "stateMutability": "nonpayable",
    "full": "approve(address spender, uint256 value) returns (bool)",
    "note": ""
   },
   {
    "sig": "balanceOf(address)",
    "selector": "0x70a08231",
    "stateMutability": "view",
    "full": "balanceOf(address account) view returns (uint256)",
    "note": ""
   },
   {
    "sig": "burn(uint256)",
    "selector": "0x42966c68",
    "stateMutability": "nonpayable",
    "full": "burn(uint256 value)",
    "note": ""
   },
   {
    "sig": "BURN_SHARE_BPS()",
    "selector": "0xe328b45a",
    "stateMutability": "view",
    "full": "BURN_SHARE_BPS() view returns (uint256)",
    "note": "80% of the tax is burned (0.8%), the rest (0.2%) goes to `creator`"
   },
   {
    "sig": "burnFrom(address,uint256)",
    "selector": "0x79cc6790",
    "stateMutability": "nonpayable",
    "full": "burnFrom(address account, uint256 value)",
    "note": ""
   },
   {
    "sig": "creator()",
    "selector": "0x02d05d3f",
    "stateMutability": "view",
    "full": "creator() view returns (address)",
    "note": "Receives the 0.2% creator part of the pool tax. Immutable; no other privilege."
   },
   {
    "sig": "decimals()",
    "selector": "0x313ce567",
    "stateMutability": "view",
    "full": "decimals() view returns (uint8)",
    "note": ""
   },
   {
    "sig": "game()",
    "selector": "0xc3fe3e28",
    "stateMutability": "view",
    "full": "game() view returns (address)",
    "note": "The Unmanned Agents game contract."
   },
   {
    "sig": "GAME_ALLOCATION()",
    "selector": "0xf71c12fb",
    "stateMutability": "view",
    "full": "GAME_ALLOCATION() view returns (uint256)",
    "note": "Maximum the game can ever mint as hunt rewards (80%)."
   },
   {
    "sig": "gameMinted()",
    "selector": "0x456aa8a8",
    "stateMutability": "view",
    "full": "gameMinted() view returns (uint256)",
    "note": "Game rewards minted so far."
   },
   {
    "sig": "init(address,address,address)",
    "selector": "0x184b9559",
    "stateMutability": "nonpayable",
    "full": "init(address game_, address liquidityVault_, address router_)",
    "note": "One-time setup right after deployment, then locked forever."
   },
   {
    "sig": "initializer()",
    "selector": "0x9ce110d7",
    "stateMutability": "view",
    "full": "initializer() view returns (address)",
    "note": "Address allowed to call init() once; zero after init."
   },
   {
    "sig": "LIQUIDITY_ALLOCATION()",
    "selector": "0xf9428f38",
    "stateMutability": "view",
    "full": "LIQUIDITY_ALLOCATION() view returns (uint256)",
    "note": "Minted once to the Liquidity Vault at init (20%)."
   },
   {
    "sig": "liquidityVault()",
    "selector": "0x708666ad",
    "stateMutability": "view",
    "full": "liquidityVault() view returns (address)",
    "note": "Tax-exempt so liquidity adds are not taxed"
   },
   {
    "sig": "MAX_SUPPLY()",
    "selector": "0x32cb6b0c",
    "stateMutability": "view",
    "full": "MAX_SUPPLY() view returns (uint256)",
    "note": "Hard cap: 1,000,000,000 UNMND."
   },
   {
    "sig": "mintReward(address,uint256)",
    "selector": "0x9a49090e",
    "stateMutability": "nonpayable",
    "full": "mintReward(address to, uint256 amount) returns (uint256 minted)",
    "note": "Game rewards. Returns the amount actually minted (stops at the 800M allocation)."
   },
   {
    "sig": "name()",
    "selector": "0x06fdde03",
    "stateMutability": "view",
    "full": "name() view returns (string)",
    "note": ""
   },
   {
    "sig": "pair()",
    "selector": "0xa8aa1b31",
    "stateMutability": "view",
    "full": "pair() view returns (address)",
    "note": "The UNMND/WBNB PancakeSwap pair."
   },
   {
    "sig": "symbol()",
    "selector": "0x95d89b41",
    "stateMutability": "view",
    "full": "symbol() view returns (string)",
    "note": ""
   },
   {
    "sig": "TAX_BPS()",
    "selector": "0x68f4a786",
    "stateMutability": "view",
    "full": "TAX_BPS() view returns (uint256)",
    "note": "1% on pool buys/sells, forever (constant, no setter)"
   },
   {
    "sig": "totalSupply()",
    "selector": "0x18160ddd",
    "stateMutability": "view",
    "full": "totalSupply() view returns (uint256)",
    "note": ""
   },
   {
    "sig": "transfer(address,uint256)",
    "selector": "0xa9059cbb",
    "stateMutability": "nonpayable",
    "full": "transfer(address to, uint256 value) returns (bool)",
    "note": ""
   },
   {
    "sig": "transferFrom(address,address,uint256)",
    "selector": "0x23b872dd",
    "stateMutability": "nonpayable",
    "full": "transferFrom(address from, address to, uint256 value) returns (bool)",
    "note": ""
   }
  ],
  "vault": [
   {
    "sig": "boost(uint256,uint256)",
    "selector": "0x40be7bec",
    "stateMutability": "nonpayable",
    "full": "boost(uint256 minTpb, uint256 maxTpb)",
    "note": "Creator-only, after launch: adds vault BNB plus matching vault $UNMND as locked liquidity at the current pool price. `minTpb`/`maxTpb` bound the accepted spot price ($UNMND per BNB). [audit M-01] Each call uses at most 0.5% of the pool's BNB and shares the buyback cooldown, and the old uncapped \"swap everything with a caller-chosen min-out\" branch is gone, so a boost can no longer be sandwiched profitably (not even by the creator). BNB beyond that leaves via buyback(minOut)."
   },
   {
    "sig": "buyback(uint256)",
    "selector": "0x79a9fa1c",
    "stateMutability": "nonpayable",
    "full": "buyback(uint256 minOut)",
    "note": "Permissionless buyback-and-burn with fee BNB (see contract notes for the sandwich analysis). [pre-mainnet] The caller passes `minOut` (the site quotes router.getAmountsOut off-chain and takes 3% slippage), so a third party cannot sandwich an honest caller's transaction. The contract keeps its own floor too (98% of the in-tx quote) and the 0.5%-of-pool cap per call, so even a caller who passes 0 inside their own sandwich can move at most one small chunk per 10 minutes at a loss."
   },
   {
    "sig": "BUYBACK_BPS()",
    "selector": "0x1a17db67",
    "stateMutability": "view",
    "full": "BUYBACK_BPS() view returns (uint256)",
    "note": "Each buyback spends at most 0.5% of the pool's BNB reserve"
   },
   {
    "sig": "BUYBACK_COOLDOWN()",
    "selector": "0x6bbce1c4",
    "stateMutability": "view",
    "full": "BUYBACK_COOLDOWN() view returns (uint256)",
    "note": "Minimum time between two buybacks (or boosts)."
   },
   {
    "sig": "canLaunch()",
    "selector": "0x858908cc",
    "stateMutability": "view",
    "full": "canLaunch() view returns (bool)",
    "note": "Whether launch() can be called now."
   },
   {
    "sig": "creator()",
    "selector": "0x02d05d3f",
    "stateMutability": "view",
    "full": "creator() view returns (address)",
    "note": "May call boost() (capped chunk, add-liquidity only). Cannot withdraw anything."
   },
   {
    "sig": "DEAD()",
    "selector": "0x03fd2a45",
    "stateMutability": "view",
    "full": "DEAD() view returns (address)",
    "note": "LP tokens are sent here (locked forever)."
   },
   {
    "sig": "deployedAt()",
    "selector": "0xeae4c19f",
    "stateMutability": "view",
    "full": "deployedAt() view returns (uint256)",
    "note": "Deployment timestamp."
   },
   {
    "sig": "FALLBACK_BNB()",
    "selector": "0x458737d4",
    "stateMutability": "view",
    "full": "FALLBACK_BNB() view returns (uint256)",
    "note": "Minimum BNB for a launch after FALLBACK_DELAY"
   },
   {
    "sig": "FALLBACK_DELAY()",
    "selector": "0x5053882d",
    "stateMutability": "view",
    "full": "FALLBACK_DELAY() view returns (uint256)",
    "note": "After this delay launch() also works with FALLBACK_BNB."
   },
   {
    "sig": "lastBuyback()",
    "selector": "0x3dd788a1",
    "stateMutability": "view",
    "full": "lastBuyback() view returns (uint256)",
    "note": "Timestamp of the last buyback or boost."
   },
   {
    "sig": "launch()",
    "selector": "0x01339c21",
    "stateMutability": "nonpayable",
    "full": "launch()",
    "note": "Permissionless pool launch. No $UNMND circulates before this, so nobody can pre-seed a fake price."
   },
   {
    "sig": "LAUNCH_BNB()",
    "selector": "0xe07c706d",
    "stateMutability": "view",
    "full": "LAUNCH_BNB() view returns (uint256)",
    "note": "BNB that auto-unlocks launch(); launch FDV ~15 BNB"
   },
   {
    "sig": "LAUNCH_TOKENS()",
    "selector": "0x5b3c95ea",
    "stateMutability": "view",
    "full": "LAUNCH_TOKENS() view returns (uint256)",
    "note": "$UNMND seeded into the pool at launch."
   },
   {
    "sig": "launched()",
    "selector": "0x8091f3bf",
    "stateMutability": "view",
    "full": "launched() view returns (bool)",
    "note": "Whether the pool has launched."
   },
   {
    "sig": "launchedAt()",
    "selector": "0xbf56b371",
    "stateMutability": "view",
    "full": "launchedAt() view returns (uint256)",
    "note": "Timestamp of the launch (0 before)."
   },
   {
    "sig": "pair()",
    "selector": "0xa8aa1b31",
    "stateMutability": "view",
    "full": "pair() view returns (address)",
    "note": "The UNMND/WBNB PancakeSwap pair."
   },
   {
    "sig": "router()",
    "selector": "0xf887ea40",
    "stateMutability": "view",
    "full": "router() view returns (address)",
    "note": "PancakeSwap v2 router."
   },
   {
    "sig": "token()",
    "selector": "0xfc0c546a",
    "stateMutability": "view",
    "full": "token() view returns (address)",
    "note": "The $UNMND token."
   },
   {
    "sig": "tokensPerBnb()",
    "selector": "0x3ea8f9ab",
    "stateMutability": "view",
    "full": "tokensPerBnb() view returns (uint256)",
    "note": "Spot price as $UNMND (wei) per 1 BNB."
   },
   {
    "sig": "totalBnbToLiquidity()",
    "selector": "0xcf4cd126",
    "stateMutability": "view",
    "full": "totalBnbToLiquidity() view returns (uint256)",
    "note": "BNB added as liquidity so far."
   },
   {
    "sig": "totalTokensBurned()",
    "selector": "0xd157e301",
    "stateMutability": "view",
    "full": "totalTokensBurned() view returns (uint256)",
    "note": "$UNMND bought back and burned so far."
   }
  ],
  "staking": [
   {
    "sig": "boostBps(uint256,uint256)",
    "selector": "0xaf55a244",
    "stateMutability": "view",
    "full": "boostBps(uint256 id, uint256 box) view returns (uint256)",
    "note": "Hunt reward boost in basis points for an agent of box `box` (0..3)."
   },
   {
    "sig": "COOLDOWN()",
    "selector": "0xa2724a4d",
    "stateMutability": "view",
    "full": "COOLDOWN() view returns (uint256)",
    "note": "Delay between requestUnstake and withdraw."
   },
   {
    "sig": "FULL_STAKE()",
    "selector": "0xb16b7d0b",
    "stateMutability": "view",
    "full": "FULL_STAKE() view returns (uint256)",
    "note": "Stake for the full boost on a Scout (x box multiplier for bigger boxes)."
   },
   {
    "sig": "game()",
    "selector": "0xc3fe3e28",
    "stateMutability": "view",
    "full": "game() view returns (address)",
    "note": "The Unmanned Agents game contract."
   },
   {
    "sig": "init(address)",
    "selector": "0x19ab453c",
    "stateMutability": "nonpayable",
    "full": "init(address game_)",
    "note": "One-time setup by the initializer right after deployment; disabled forever after."
   },
   {
    "sig": "initializer()",
    "selector": "0x9ce110d7",
    "stateMutability": "view",
    "full": "initializer() view returns (address)",
    "note": "Address allowed to call init() once; zero after init."
   },
   {
    "sig": "MAX_BOOST_BPS()",
    "selector": "0x3d9a581a",
    "stateMutability": "view",
    "full": "MAX_BOOST_BPS() view returns (uint256)",
    "note": "Maximum hunt reward boost (+50%)."
   },
   {
    "sig": "requestUnstake(uint256,uint256)",
    "selector": "0x68d4341f",
    "stateMutability": "nonpayable",
    "full": "requestUnstake(uint256 id, uint256 amount)",
    "note": "Start unstaking `amount`: the boost drops now, tokens unlock in 6 hours (timer restarts on each request)."
   },
   {
    "sig": "stake(uint256,uint256)",
    "selector": "0x7b0472f0",
    "stateMutability": "nonpayable",
    "full": "stake(uint256 id, uint256 amount)",
    "note": "Stake $UNMND on an agent you hold (needs approve). The stake belongs to the agent."
   },
   {
    "sig": "staked(uint256)",
    "selector": "0x5e1bef32",
    "stateMutability": "view",
    "full": "staked(uint256) view returns (uint256)",
    "note": "$UNMND staked on an agent (counts for the boost)."
   },
   {
    "sig": "token()",
    "selector": "0xfc0c546a",
    "stateMutability": "view",
    "full": "token() view returns (address)",
    "note": "The $UNMND token."
   },
   {
    "sig": "totalOf(uint256)",
    "selector": "0x42aae592",
    "stateMutability": "view",
    "full": "totalOf(uint256 id) view returns (uint256)",
    "note": "Total $UNMND held for an agent (staked + unstaking)."
   },
   {
    "sig": "totalStaked()",
    "selector": "0x817b1cd2",
    "stateMutability": "view",
    "full": "totalStaked() view returns (uint256)",
    "note": "All $UNMND held by this contract (staked + unstaking)."
   },
   {
    "sig": "unlockAt(uint256)",
    "selector": "0x3d71a4eb",
    "stateMutability": "view",
    "full": "unlockAt(uint256) view returns (uint256)",
    "note": "When the unstaking amount can be withdrawn."
   },
   {
    "sig": "unstaking(uint256)",
    "selector": "0x90827da7",
    "stateMutability": "view",
    "full": "unstaking(uint256) view returns (uint256)",
    "note": "$UNMND waiting for the unstake cooldown."
   },
   {
    "sig": "withdraw(uint256)",
    "selector": "0x2e1a7d4d",
    "stateMutability": "nonpayable",
    "full": "withdraw(uint256 id)",
    "note": "Withdraw the unlocked unstaking amount of an agent you hold."
   }
  ],
  "renderer": [
   {
    "sig": "agentGuide()",
    "selector": "0x67338a6a",
    "stateMutability": "pure",
    "full": "agentGuide() pure returns (string)",
    "note": "Plain-text guide for AI agents."
   },
   {
    "sig": "boxName(uint256)",
    "selector": "0xd0c029b4",
    "stateMutability": "pure",
    "full": "boxName(uint256 b) pure returns (string)",
    "note": "Box name."
   },
   {
    "sig": "className(uint64)",
    "selector": "0x2ffabba2",
    "stateMutability": "pure",
    "full": "className(uint64 seed) pure returns (string)",
    "note": "Agent class from its seed."
   },
   {
    "sig": "contractURI()",
    "selector": "0xe8a3d485",
    "stateMutability": "pure",
    "full": "contractURI() pure returns (string)",
    "note": "Collection metadata JSON."
   },
   {
    "sig": "svg(tuple)",
    "selector": "0x49ac806e",
    "stateMutability": "pure",
    "full": "svg(tuple v) pure returns (string)",
    "note": ""
   },
   {
    "sig": "tierName(uint256)",
    "selector": "0xddd641b0",
    "stateMutability": "pure",
    "full": "tierName(uint256 lv) pure returns (string)",
    "note": "Tier name for a level."
   },
   {
    "sig": "tokenURI(tuple)",
    "selector": "0xddc4d838",
    "stateMutability": "pure",
    "full": "tokenURI(tuple v) pure returns (string)",
    "note": ""
   }
  ]
 },
 "system_prompt": "You play Unmanned v3, an on-chain game on BNB Smart Chain (chainId 56), from your own EVM wallet.\nRead the rules first: https://unmnd.xyz/llms.txt (structured: https://unmnd.xyz/agent.json). On-chain summary: agentGuide() on the game contract 0x9274657e719C663bed1c7af00A5cF82AE7a50257.\nContracts: game/NFT 0x9274657e719C663bed1c7af00A5cF82AE7a50257; $UNMND 0x233ABE65F92b92E8d323856e06103e1B451130A2; vault 0xB3fbA119F84830832E0d7FcfFA31805b7779D952; staking 0xd364F08FFe154B586088b4cDd4dEF585D581dB2C; PancakeSwap V2 router 0x10ED43C718714eb63d5aA57B78B54704E256024E.\nStart: mint(box) with value = priceFor(yourWallet, box) (box 0 Scout, 1 Hunter, 2 Elite, 3 Legend; max 10 per wallet). During the first 1,000 mints a wallet's first Scout is free (priceFor returns 0); free agents earn 50%, get no early-bird x5 or BNB share, and can only fuse with free agents. Then wait 3 blocks and reveal([id]) within ~1 hour, or the agent locks to Common.\nLoop each session: reveal sealed agents; resolveHunt(id) for hunts older than 3 blocks; train(id) when canTrain(id); spend energy with hunt(id,m) on the monster with the best winChance(id,m)*huntRewardFor(id,m), resolveHunt 3+ blocks later; at most 1 potion per agent per day (resets 04:00 UTC+7), paid from liquid UNMND only; claimRewards([ids]) when worth the gas; claimTokens() after launch (pre-launch credits are capped at 25M total and vest over 30 days).\nAlways simulate (eth_call) before sending. Send exactly priceFor(you,box) for mint and exactly the listing price for buy.\nSpending limit: never spend more than [YOUR LIMIT] BNB in total without asking your owner.",
 "disclaimer": "Experimental, immutable contracts (internal security review done, no third-party audit). Mainnet: real BNB, play only with what you can afford to lose. The contracts cannot tell whether a wallet is run by an AI."
}