{"sources":{"TurfWar.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.26;\n\n/// @notice Minimal view of the Binance Agent ID registry (SPACE ID based).\ninterface IAgentIdRegistry {\n    function balanceOf(address owner) external view returns (uint256);\n}\n\n/// @notice Minimal PancakeSwap V2 router surface used at finalize time.\ninterface IPancakeRouter {\n    function addLiquidityETH(\n        address token,\n        uint256 amountTokenDesired,\n        uint256 amountTokenMin,\n        uint256 amountETHMin,\n        address to,\n        uint256 deadline\n    ) external payable returns (uint256 amountToken, uint256 amountETH, uint256 liquidity);\n}\n\n/// @title Turf War (TURF) — Bitcoin vs AI\n/// @notice A 50x50 faction canvas on BSC that only Agent ID wallets can play.\n///         Two factions — Bitcoin (states 1-4) and AI (states 5-8) — fight\n///         over 2,500 cells in a single 6-hour war. One contract holds\n///         everything: the ERC-20 token, registration, the war, and the\n///         final distribution. No admin functions, no taxes, no re-mint.\n///\n///         Timeline (anchored to the immutable `warStart`):\n///         - Registration: from deploy until warEnd; pick a faction once,\n///           it can never be changed. Joining the smaller faction grants a\n///           permanent +1 free-cell credit (underdog bonus).\n///         - War: warStart .. warStart+6h. First 600s = Land Rush (empty\n///           cells half price). Last 1800s = Final Assault (flips cheap);\n///           the assault window extends to 2700s if 500 agents registered.\n///         - finalize(): anyone, after warEnd. Score per faction = its cell\n///           count, plus a 5% bonus when its largest 4-connected region has\n///           >= 25 cells. Winner = higher score; tie -> more cells; still\n///           tied -> Bitcoin wins (faction 1, the first faction).\n///           BNB splits 70% liquidity / 30% treasury; painter pool is\n///           125M TURF (+12.5M taken from the treasury share if 300 agents\n///           registered), split by final cells with winner cells weighted\n///           3 and loser cells weighted 2. Top flipper gets 1M TURF.\ncontract TurfWar {\n    // ---------------- ERC-20 ----------------\n    string public constant name = \"Turf War\";\n    string public constant symbol = \"TURF\";\n    uint8 public constant decimals = 18;\n    uint256 public totalSupply;\n    mapping(address => uint256) public balanceOf;\n    mapping(address => mapping(address => uint256)) public allowance;\n\n    event Transfer(address indexed from, address indexed to, uint256 value);\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n\n    // ---------------- Setup ----------------\n    IAgentIdRegistry public immutable registry;\n    address public immutable treasury;\n    IPancakeRouter public immutable router;\n\n    uint256 public immutable warStart;\n    uint256 public immutable warEnd; // warStart + 6h\n\n    address public constant BURN = 0x000000000000000000000000000000000000dEaD;\n\n    // ---------------- War constants ----------------\n    uint256 public constant SIDE = 50;\n    uint256 public constant CELLS = 2500; // 50 x 50\n    uint256 public constant WAR_LEN = 21600; // 6 hours\n    uint256 public constant RUSH_LEN = 600; // first 10 minutes\n    uint256 public constant ASSAULT_LEN = 1800; // last 30 minutes\n    uint256 public constant ASSAULT_LEN_500 = 2700; // extended assault at 500 registrations\n    uint256 public constant MAX_PAINTS = 20; // per agent, free + paid\n    uint256 public constant BASE_FREE = 3; // free cells for every registered agent\n\n    uint256 public constant PRICE_RUSH = 0.0005 ether; // empty cell during Land Rush\n    uint256 public constant PRICE_EMPTY = 0.001 ether; // empty / own cell\n    uint256 public constant PRICE_FLIP = 0.0015 ether; // enemy cell\n    uint256 public constant PRICE_FLIP_ASSAULT = 0.001 ether; // enemy cell in Final Assault\n\n    // Faction palettes (rgb24). State id = palette index + 1 (BTC) or + 5 (AI).\n    uint32 public constant BTC0 = 0xF7931A;\n    uint32 public constant BTC1 = 0xFFB74D;\n    uint32 public constant BTC2 = 0xE65100;\n    uint32 public constant BTC3 = 0xFFD54F;\n    uint32 public constant AI0 = 0x7C4DFF;\n    uint32 public constant AI1 = 0x00E5FF;\n    uint32 public constant AI2 = 0x651FFF;\n    uint32 public constant AI3 = 0x18FFFF;\n\n    // ---------------- Token distribution ----------------\n    uint256 public constant TOTAL_TOKENS = 250_000_000 * 1e18;\n    uint256 public constant PAINTER_POOL = 125_000_000 * 1e18; // 50%\n    uint256 public constant LP_TOKENS = 100_000_000 * 1e18; // 40%\n    uint256 public constant TREASURY_TOKENS = 25_000_000 * 1e18; // 10%\n    uint256 public constant MILESTONE300_BONUS = 12_500_000 * 1e18; // added to painter pool at 300 registrations\n    uint256 public constant TOP_FLIPPER_PRIZE = 1_000_000 * 1e18; // paid out of the treasury share\n\n    // ---------------- State ----------------\n    uint8[2500] private _cellState; // packed automatically: 32 cells per slot\n    address[2500] private _cellOwner;\n\n    mapping(address => bool) public registered;\n    mapping(address => uint8) public factionOf; // 1 = Bitcoin, 2 = AI\n    mapping(address => address) public referrerOf;\n    mapping(address => bool) public underdogBonus;\n    mapping(address => uint256) public recruitCredits;\n    mapping(address => uint256) public freeUsed;\n    mapping(address => bool) private _recruitDone;\n    mapping(address => uint256) public cellsOf; // cells currently owned\n    mapping(address => uint256) public flipsOf; // enemy cells flipped\n    mapping(address => uint256) public paintCount; // total paints (cap accounting)\n    mapping(address => bool) public claimed;\n\n    uint256 public totalRegistered;\n    uint256 public registeredBTC;\n    uint256 public registeredAI;\n    uint256 public cellsBTC;\n    uint256 public cellsAI;\n    uint256 public totalPaints;\n    uint256 public totalRaised;\n\n    address public topFlipper;\n    uint256 public topFlips;\n\n    bool public finalized;\n    uint8 public winner; // 0 until finalized, then 1 or 2\n    uint256 public tokensPerWeight; // painterPool * 1e18 / totalWeightUnits\n    uint256 public painterPoolFinal;\n    uint256 public lpBnbAmount;\n    uint256 public treasuryBnbAmount;\n\n    event Registered(address indexed agent, uint8 faction, address referrer, bool underdog);\n    event Painted(address indexed agent, uint256 indexed cell, uint32 rgb, bool wasFlip);\n    event Finalized(uint8 winner, uint256 scoreBTC, uint256 scoreAI, uint256 tokensPerWeight, uint256 lpBnb, uint256 treasuryBnb);\n    event Claimed(address indexed agent, uint256 amount);\n\n    bool private _locked;\n    modifier nonReentrant() {\n        require(!_locked, \"reentrant\");\n        _locked = true;\n        _;\n        _locked = false;\n    }\n\n    constructor(address agentIdRegistry, address treasury_, address router_, uint256 warStart_) {\n        require(agentIdRegistry != address(0), \"registry 0\");\n        require(treasury_ != address(0), \"treasury 0\");\n        require(router_ != address(0), \"router 0\");\n        require(warStart_ > block.timestamp, \"warStart past\");\n        registry = IAgentIdRegistry(agentIdRegistry);\n        treasury = treasury_; // eksplisit: deploy lewat proxy CREATE2, jangan pakai msg.sender\n        router = IPancakeRouter(router_);\n        warStart = warStart_;\n        warEnd = warStart_ + WAR_LEN;\n        totalSupply = TOTAL_TOKENS;\n        balanceOf[address(this)] = totalSupply;\n        emit Transfer(address(0), address(this), totalSupply);\n    }\n\n    // ---------------- ERC-20 functions ----------------\n    function transfer(address to, uint256 value) external returns (bool) {\n        _transfer(msg.sender, to, value);\n        return true;\n    }\n\n    function approve(address spender, uint256 value) external returns (bool) {\n        allowance[msg.sender][spender] = value;\n        emit Approval(msg.sender, spender, value);\n        return true;\n    }\n\n    function transferFrom(address from, address to, uint256 value) external returns (bool) {\n        uint256 allowed = allowance[from][msg.sender];\n        require(allowed >= value, \"allowance\");\n        if (allowed != type(uint256).max) {\n            allowance[from][msg.sender] = allowed - value;\n        }\n        _transfer(from, to, value);\n        return true;\n    }\n\n    function _transfer(address from, address to, uint256 value) internal {\n        require(to != address(0), \"to 0\");\n        require(balanceOf[from] >= value, \"balance\");\n        balanceOf[from] -= value;\n        balanceOf[to] += value;\n        emit Transfer(from, to, value);\n    }\n\n    // ---------------- Agent ID gate ----------------\n    function isAgent(address wallet) public view returns (bool) {\n        try registry.balanceOf(wallet) returns (uint256 n) {\n            return n > 0;\n        } catch {\n            return false;\n        }\n    }\n\n    // ---------------- Time helpers ----------------\n    function _assaultLen() internal view returns (uint256) {\n        return totalRegistered >= 500 ? ASSAULT_LEN_500 : ASSAULT_LEN;\n    }\n\n    function _isRush() internal view returns (bool) {\n        return block.timestamp < warStart + RUSH_LEN;\n    }\n\n    function _isAssault() internal view returns (bool) {\n        return block.timestamp >= warEnd - _assaultLen();\n    }\n\n    function _phase() internal view returns (uint256) {\n        if (finalized) return 3;\n        uint256 t = block.timestamp;\n        if (t < warStart) return 0; // waitlist\n        if (t < warEnd) return 1; // war\n        return 2; // ended, not finalized\n    }\n\n    // ---------------- Free credits ----------------\n    /// @notice Total free-cell entitlement of an agent (before subtracting\n    ///         what it already used): 3 base + 1 underdog + 1 once 100\n    ///         agents registered + recruit credits earned.\n    function freeEntitlement(address agent) public view returns (uint256) {\n        uint256 total = BASE_FREE;\n        if (underdogBonus[agent]) total += 1;\n        if (totalRegistered >= 100) total += 1;\n        total += recruitCredits[agent];\n        return total;\n    }\n\n    /// @notice Free cells the agent can still use right now.\n    function freeAllowanceOf(address agent) public view returns (uint256) {\n        uint256 total = freeEntitlement(agent);\n        uint256 used = freeUsed[agent];\n        return total > used ? total - used : 0;\n    }\n\n    // ---------------- Registration ----------------\n    /// @notice Join a faction. Open from deploy until warEnd; Agent ID\n    ///         required; one registration per wallet, faction is final.\n    ///         Registering into the currently smaller faction grants the\n    ///         permanent underdog bonus (+1 free cell).\n    function register(uint8 faction, address referrer) external {\n        require(block.timestamp < warEnd, \"registration closed\");\n        require(isAgent(msg.sender), \"no Agent ID\");\n        require(!registered[msg.sender], \"already registered\");\n        require(faction == 1 || faction == 2, \"invalid faction\");\n        require(referrer != msg.sender, \"referrer is self\");\n\n        bool underdog;\n        if (faction == 1) {\n            underdog = registeredBTC < registeredAI;\n            registeredBTC += 1;\n        } else {\n            underdog = registeredAI < registeredBTC;\n            registeredAI += 1;\n        }\n        registered[msg.sender] = true;\n        factionOf[msg.sender] = faction;\n        referrerOf[msg.sender] = referrer;\n        underdogBonus[msg.sender] = underdog;\n        totalRegistered += 1;\n        emit Registered(msg.sender, faction, referrer, underdog);\n    }\n\n    // ---------------- Painting ----------------\n    function _factionOfState(uint8 s) internal pure returns (uint8) {\n        if (s == 0) return 0;\n        return s <= 4 ? 1 : 2;\n    }\n\n    /// @notice Map an rgb24 to the caller's faction state id; reverts when\n    ///         the color is not in the caller's faction palette.\n    function _stateFor(uint8 faction, uint32 rgb) internal pure returns (uint8) {\n        if (faction == 1) {\n            if (rgb == BTC0) return 1;\n            if (rgb == BTC1) return 2;\n            if (rgb == BTC2) return 3;\n            if (rgb == BTC3) return 4;\n        } else {\n            if (rgb == AI0) return 5;\n            if (rgb == AI1) return 6;\n            if (rgb == AI2) return 7;\n            if (rgb == AI3) return 8;\n        }\n        revert(\"not your faction color\");\n    }\n\n    function _priceFor(uint8 state, uint8 myFaction) internal view returns (uint256 price, bool isFlip) {\n        uint8 f = _factionOfState(state);\n        if (f != 0 && f != myFaction) {\n            return (_isAssault() ? PRICE_FLIP_ASSAULT : PRICE_FLIP, true);\n        }\n        return (_isRush() ? PRICE_RUSH : PRICE_EMPTY, false);\n    }\n\n    /// @notice Paint cells. Each element of `packed` encodes one cell as\n    ///         cellIndex * 16777216 + rgb24 (cellIndex 0..2499, row-major).\n    ///         The rgb must belong to the caller's faction palette. Free\n    ///         credits are consumed first; paid cells are charged by cell\n    ///         state and time (see constants). Excess BNB is refunded in\n    ///         the same transaction. Max 20 paints per agent for the war.\n    function paint(uint256[] calldata packed) external payable nonReentrant {\n        uint256 t = block.timestamp;\n        require(t >= warStart, \"war not started\");\n        require(t < warEnd, \"war ended\");\n        require(registered[msg.sender], \"not registered\");\n        require(packed.length > 0, \"empty batch\");\n        require(paintCount[msg.sender] + packed.length <= MAX_PAINTS, \"paint cap\");\n\n        uint8 myFaction = factionOf[msg.sender];\n\n        // Recruit bonus: the first-ever paint of a referred agent grants\n        // +1 free credit to the agent and +1 to its referrer (once).\n        if (paintCount[msg.sender] == 0 && !_recruitDone[msg.sender]) {\n            _recruitDone[msg.sender] = true;\n            address ref = referrerOf[msg.sender];\n            if (ref != address(0)) {\n                recruitCredits[msg.sender] += 1;\n                recruitCredits[ref] += 1;\n            }\n        }\n\n        uint256 allowanceNow = freeEntitlement(msg.sender);\n        uint256 due = 0;\n\n        for (uint256 i = 0; i < packed.length; i++) {\n            uint256 cell = packed[i] / 16777216;\n            uint32 rgb = uint32(packed[i] % 16777216);\n            require(cell < CELLS, \"invalid cell\");\n            uint8 newState = _stateFor(myFaction, rgb);\n            uint8 oldState = _cellState[cell];\n            address oldOwner = _cellOwner[cell];\n            (uint256 price, bool isFlip) = _priceFor(oldState, myFaction);\n\n            if (freeUsed[msg.sender] < allowanceNow) {\n                freeUsed[msg.sender] += 1;\n            } else {\n                due += price;\n            }\n\n            if (oldOwner != msg.sender) {\n                if (oldOwner != address(0)) {\n                    cellsOf[oldOwner] -= 1;\n                    if (_factionOfState(oldState) == 1) cellsBTC -= 1;\n                    else cellsAI -= 1;\n                }\n                cellsOf[msg.sender] += 1;\n                if (myFaction == 1) cellsBTC += 1;\n                else cellsAI += 1;\n            }\n            _cellState[cell] = newState;\n            _cellOwner[cell] = msg.sender;\n\n            if (isFlip) {\n                flipsOf[msg.sender] += 1;\n                if (flipsOf[msg.sender] > topFlips) {\n                    topFlips = flipsOf[msg.sender];\n                    topFlipper = msg.sender;\n                }\n            }\n            emit Painted(msg.sender, cell, rgb, isFlip);\n        }\n\n        paintCount[msg.sender] += packed.length;\n        totalPaints += packed.length;\n        require(msg.value >= due, \"insufficient payment\");\n        totalRaised += due;\n        uint256 refund = msg.value - due;\n        if (refund > 0) {\n            (bool ok, ) = msg.sender.call{value: refund}(\"\");\n            require(ok, \"refund failed\");\n        }\n    }\n\n    // ---------------- Reads ----------------\n    function getCells(uint256 from, uint256 to) external view returns (uint8[] memory states) {\n        require(from <= to && to <= CELLS, \"range\");\n        states = new uint8[](to - from);\n        for (uint256 i = from; i < to; i++) {\n            states[i - from] = _cellState[i];\n        }\n    }\n\n    function cellOwnerOf(uint256 cell) external view returns (address) {\n        require(cell < CELLS, \"invalid cell\");\n        return _cellOwner[cell];\n    }\n\n    function status()\n        external\n        view\n        returns (\n            uint256 phase,\n            uint256 start,\n            uint256 end,\n            uint256 registeredTotal,\n            uint256 regBTC,\n            uint256 regAI,\n            uint256 cellsBtc,\n            uint256 cellsAi,\n            uint256 paints,\n            uint256 priceEmptyNow,\n            uint256 priceFlipNow,\n            bool isFinalAssault,\n            uint8 winnerOut\n        )\n    {\n        phase = _phase();\n        start = warStart;\n        end = warEnd;\n        registeredTotal = totalRegistered;\n        regBTC = registeredBTC;\n        regAI = registeredAI;\n        cellsBtc = cellsBTC;\n        cellsAi = cellsAI;\n        paints = totalPaints;\n        if (phase == 1) {\n            priceEmptyNow = _isRush() ? PRICE_RUSH : PRICE_EMPTY;\n            priceFlipNow = _isAssault() ? PRICE_FLIP_ASSAULT : PRICE_FLIP;\n        }\n        isFinalAssault = _isAssault();\n        winnerOut = winner;\n    }\n\n    // ---------------- Finalize & claim ----------------\n    /// @notice Largest 4-connected same-faction region per faction (BFS over\n    ///         an in-memory copy of the grid) and the resulting scores.\n    function _scores() internal view returns (uint256 scoreBTC, uint256 scoreAI, uint256 largestBTC, uint256 largestAI) {\n        uint8[2500] memory grid;\n        for (uint256 i = 0; i < CELLS; i++) grid[i] = _cellState[i];\n        bool[2500] memory visited;\n        uint256[2500] memory stack;\n        for (uint256 start = 0; start < CELLS; start++) {\n            uint8 s = grid[start];\n            if (s == 0 || visited[start]) continue;\n            uint8 f = _factionOfState(s);\n            uint256 size = 0;\n            uint256 sp = 0;\n            stack[sp++] = start;\n            visited[start] = true;\n            while (sp > 0) {\n                uint256 cur = stack[--sp];\n                size += 1;\n                uint256 x = cur % SIDE;\n                uint256 y = cur / SIDE;\n                if (x > 0) {\n                    uint256 n = cur - 1;\n                    if (!visited[n] && grid[n] != 0 && _factionOfState(grid[n]) == f) { visited[n] = true; stack[sp++] = n; }\n                }\n                if (x < SIDE - 1) {\n                    uint256 n = cur + 1;\n                    if (!visited[n] && grid[n] != 0 && _factionOfState(grid[n]) == f) { visited[n] = true; stack[sp++] = n; }\n                }\n                if (y > 0) {\n                    uint256 n = cur - SIDE;\n                    if (!visited[n] && grid[n] != 0 && _factionOfState(grid[n]) == f) { visited[n] = true; stack[sp++] = n; }\n                }\n                if (y < SIDE - 1) {\n                    uint256 n = cur + SIDE;\n                    if (!visited[n] && grid[n] != 0 && _factionOfState(grid[n]) == f) { visited[n] = true; stack[sp++] = n; }\n                }\n            }\n            if (f == 1) { if (size > largestBTC) largestBTC = size; }\n            else { if (size > largestAI) largestAI = size; }\n        }\n        scoreBTC = cellsBTC + (largestBTC >= 25 ? (cellsBTC * 5) / 100 : 0);\n        scoreAI = cellsAI + (largestAI >= 25 ? (cellsAI * 5) / 100 : 0);\n    }\n\n    /// @notice Close the war: compute the winner, seed the PancakeSwap V2\n    ///         pool with 70% of the BNB and 40% of the tokens (LP burned),\n    ///         send 30% of the BNB to the treasury, pay the top-flipper\n    ///         prize out of the treasury token share, send the rest of the\n    ///         treasury token share to the treasury, and open claims.\n    ///         Callable by anyone after warEnd, once, if anyone painted.\n    function finalize() external nonReentrant {\n        require(!finalized, \"finalized\");\n        require(block.timestamp >= warEnd, \"war running\");\n        require(totalPaints > 0, \"no paints\");\n        finalized = true;\n\n        (uint256 scoreBTC, uint256 scoreAI, , ) = _scores();\n        uint8 w;\n        if (scoreBTC != scoreAI) w = scoreBTC > scoreAI ? 1 : 2;\n        else if (cellsBTC != cellsAI) w = cellsBTC > cellsAI ? 1 : 2;\n        else w = 1; // full tie -> Bitcoin wins (documented house rule)\n        winner = w;\n\n        // Painter pool: 125M, +12.5M taken from the treasury share when the\n        // 300-registration milestone was reached.\n        uint256 pool = PAINTER_POOL;\n        uint256 milestoneBonus = 0;\n        if (totalRegistered >= 300) {\n            milestoneBonus = MILESTONE300_BONUS;\n            pool += milestoneBonus;\n        }\n        painterPoolFinal = pool;\n\n        uint256 weightWinner = w == 1 ? cellsBTC : cellsAI;\n        uint256 weightLoser = w == 1 ? cellsAI : cellsBTC;\n        uint256 totalWeightUnits = weightWinner * 3 + weightLoser * 2;\n        tokensPerWeight = (pool * 1e18) / totalWeightUnits;\n\n        // Token splits out of the treasury share, in priority order:\n        // top-flipper prize first, then the milestone bonus (stays in the\n        // contract inside the painter pool), treasury receives the rest.\n        uint256 topPrize = topFlips > 0 ? TOP_FLIPPER_PRIZE : 0;\n        uint256 treasuryTokens = TREASURY_TOKENS - topPrize - milestoneBonus;\n        if (topPrize > 0) _transfer(address(this), topFlipper, topPrize);\n        if (treasuryTokens > 0) _transfer(address(this), treasury, treasuryTokens);\n\n        // BNB splits: 70% liquidity / 30% treasury.\n        uint256 bnb = address(this).balance;\n        lpBnbAmount = (bnb * 70) / 100;\n        treasuryBnbAmount = bnb - lpBnbAmount;\n\n        allowance[address(this)][address(router)] = LP_TOKENS;\n        emit Approval(address(this), address(router), LP_TOKENS);\n        router.addLiquidityETH{value: lpBnbAmount}(\n            address(this),\n            LP_TOKENS,\n            0,\n            0,\n            BURN,\n            block.timestamp + 3600\n        );\n\n        if (treasuryBnbAmount > 0) {\n            (bool ok, ) = treasury.call{value: treasuryBnbAmount}(\"\");\n            require(ok, \"treasury bnb failed\");\n        }\n        emit Finalized(w, scoreBTC, scoreAI, tokensPerWeight, lpBnbAmount, treasuryBnbAmount);\n    }\n\n    /// @notice Painters claim from the painter pool: final cells owned x\n    ///         faction weight (3 winner / 2 loser) x tokensPerWeight.\n    ///         One claim per agent.\n    function claim() external nonReentrant {\n        require(finalized, \"not finalized\");\n        require(!claimed[msg.sender], \"claimed\");\n        uint256 n = cellsOf[msg.sender];\n        require(n > 0, \"no cells\");\n        claimed[msg.sender] = true;\n        uint256 weight = factionOf[msg.sender] == winner ? 3 : 2;\n        uint256 amount = (n * weight * tokensPerWeight) / 1e18;\n        _transfer(address(this), msg.sender, amount);\n        emit Claimed(msg.sender, amount);\n    }\n}\n"}},"abi":[{"type":"constructor","inputs":[{"name":"agentIdRegistry","type":"address","internalType":"address"},{"name":"treasury_","type":"address","internalType":"address"},{"name":"router_","type":"address","internalType":"address"},{"name":"warStart_","type":"uint256","internalType":"uint256"}],"stateMutability":"nonpayable"},{"name":"Approval","type":"event","inputs":[{"name":"owner","type":"address","indexed":true,"internalType":"address"},{"name":"spender","type":"address","indexed":true,"internalType":"address"},{"name":"value","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"name":"Claimed","type":"event","inputs":[{"name":"agent","type":"address","indexed":true,"internalType":"address"},{"name":"amount","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"name":"Finalized","type":"event","inputs":[{"name":"winner","type":"uint8","indexed":false,"internalType":"uint8"},{"name":"scoreBTC","type":"uint256","indexed":false,"internalType":"uint256"},{"name":"scoreAI","type":"uint256","indexed":false,"internalType":"uint256"},{"name":"tokensPerWeight","type":"uint256","indexed":false,"internalType":"uint256"},{"name":"lpBnb","type":"uint256","indexed":false,"internalType":"uint256"},{"name":"treasuryBnb","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"name":"Painted","type":"event","inputs":[{"name":"agent","type":"address","indexed":true,"internalType":"address"},{"name":"cell","type":"uint256","indexed":true,"internalType":"uint256"},{"name":"rgb","type":"uint32","indexed":false,"internalType":"uint32"},{"name":"wasFlip","type":"bool","indexed":false,"internalType":"bool"}],"anonymous":false},{"name":"Registered","type":"event","inputs":[{"name":"agent","type":"address","indexed":true,"internalType":"address"},{"name":"faction","type":"uint8","indexed":false,"internalType":"uint8"},{"name":"referrer","type":"address","indexed":false,"internalType":"address"},{"name":"underdog","type":"bool","indexed":false,"internalType":"bool"}],"anonymous":false},{"name":"Transfer","type":"event","inputs":[{"name":"from","type":"address","indexed":true,"internalType":"address"},{"name":"to","type":"address","indexed":true,"internalType":"address"},{"name":"value","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"name":"AI0","type":"function","inputs":[],"outputs":[{"name":"","type":"uint32","internalType":"uint32"}],"stateMutability":"view"},{"name":"AI1","type":"function","inputs":[],"outputs":[{"name":"","type":"uint32","internalType":"uint32"}],"stateMutability":"view"},{"name":"AI2","type":"function","inputs":[],"outputs":[{"name":"","type":"uint32","internalType":"uint32"}],"stateMutability":"view"},{"name":"AI3","type":"function","inputs":[],"outputs":[{"name":"","type":"uint32","internalType":"uint32"}],"stateMutability":"view"},{"name":"ASSAULT_LEN","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"ASSAULT_LEN_500","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"BASE_FREE","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"BTC0","type":"function","inputs":[],"outputs":[{"name":"","type":"uint32","internalType":"uint32"}],"stateMutability":"view"},{"name":"BTC1","type":"function","inputs":[],"outputs":[{"name":"","type":"uint32","internalType":"uint32"}],"stateMutability":"view"},{"name":"BTC2","type":"function","inputs":[],"outputs":[{"name":"","type":"uint32","internalType":"uint32"}],"stateMutability":"view"},{"name":"BTC3","type":"function","inputs":[],"outputs":[{"name":"","type":"uint32","internalType":"uint32"}],"stateMutability":"view"},{"name":"BURN","type":"function","inputs":[],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"name":"CELLS","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"LP_TOKENS","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"MAX_PAINTS","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"MILESTONE300_BONUS","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"PAINTER_POOL","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"PRICE_EMPTY","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"PRICE_FLIP","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"PRICE_FLIP_ASSAULT","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"PRICE_RUSH","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"RUSH_LEN","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"SIDE","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"TOP_FLIPPER_PRIZE","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"TOTAL_TOKENS","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"TREASURY_TOKENS","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"WAR_LEN","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"allowance","type":"function","inputs":[{"name":"","type":"address","internalType":"address"},{"name":"","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"approve","type":"function","inputs":[{"name":"spender","type":"address","internalType":"address"},{"name":"value","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"nonpayable"},{"name":"balanceOf","type":"function","inputs":[{"name":"","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"cellOwnerOf","type":"function","inputs":[{"name":"cell","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"name":"cellsAI","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"cellsBTC","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"cellsOf","type":"function","inputs":[{"name":"","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"claim","type":"function","inputs":[],"outputs":[],"stateMutability":"nonpayable"},{"name":"claimed","type":"function","inputs":[{"name":"","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"name":"decimals","type":"function","inputs":[],"outputs":[{"name":"","type":"uint8","internalType":"uint8"}],"stateMutability":"view"},{"name":"factionOf","type":"function","inputs":[{"name":"","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"uint8","internalType":"uint8"}],"stateMutability":"view"},{"name":"finalize","type":"function","inputs":[],"outputs":[],"stateMutability":"nonpayable"},{"name":"finalized","type":"function","inputs":[],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"name":"flipsOf","type":"function","inputs":[{"name":"","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"freeAllowanceOf","type":"function","inputs":[{"name":"agent","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"freeEntitlement","type":"function","inputs":[{"name":"agent","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"freeUsed","type":"function","inputs":[{"name":"","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"getCells","type":"function","inputs":[{"name":"from","type":"uint256","internalType":"uint256"},{"name":"to","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"states","type":"uint8[]","internalType":"uint8[]"}],"stateMutability":"view"},{"name":"isAgent","type":"function","inputs":[{"name":"wallet","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"name":"lpBnbAmount","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"name","type":"function","inputs":[],"outputs":[{"name":"","type":"string","internalType":"string"}],"stateMutability":"view"},{"name":"paint","type":"function","inputs":[{"name":"packed","type":"uint256[]","internalType":"uint256[]"}],"outputs":[],"stateMutability":"payable"},{"name":"paintCount","type":"function","inputs":[{"name":"","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"painterPoolFinal","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"recruitCredits","type":"function","inputs":[{"name":"","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"referrerOf","type":"function","inputs":[{"name":"","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"name":"register","type":"function","inputs":[{"name":"faction","type":"uint8","internalType":"uint8"},{"name":"referrer","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"name":"registered","type":"function","inputs":[{"name":"","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"name":"registeredAI","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"registeredBTC","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"registry","type":"function","inputs":[],"outputs":[{"name":"","type":"address","internalType":"contract IAgentIdRegistry"}],"stateMutability":"view"},{"name":"router","type":"function","inputs":[],"outputs":[{"name":"","type":"address","internalType":"contract IPancakeRouter"}],"stateMutability":"view"},{"name":"status","type":"function","inputs":[],"outputs":[{"name":"phase","type":"uint256","internalType":"uint256"},{"name":"start","type":"uint256","internalType":"uint256"},{"name":"end","type":"uint256","internalType":"uint256"},{"name":"registeredTotal","type":"uint256","internalType":"uint256"},{"name":"regBTC","type":"uint256","internalType":"uint256"},{"name":"regAI","type":"uint256","internalType":"uint256"},{"name":"cellsBtc","type":"uint256","internalType":"uint256"},{"name":"cellsAi","type":"uint256","internalType":"uint256"},{"name":"paints","type":"uint256","internalType":"uint256"},{"name":"priceEmptyNow","type":"uint256","internalType":"uint256"},{"name":"priceFlipNow","type":"uint256","internalType":"uint256"},{"name":"isFinalAssault","type":"bool","internalType":"bool"},{"name":"winnerOut","type":"uint8","internalType":"uint8"}],"stateMutability":"view"},{"name":"symbol","type":"function","inputs":[],"outputs":[{"name":"","type":"string","internalType":"string"}],"stateMutability":"view"},{"name":"tokensPerWeight","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"topFlipper","type":"function","inputs":[],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"name":"topFlips","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"totalPaints","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"totalRaised","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"totalRegistered","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"totalSupply","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"transfer","type":"function","inputs":[{"name":"to","type":"address","internalType":"address"},{"name":"value","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"nonpayable"},{"name":"transferFrom","type":"function","inputs":[{"name":"from","type":"address","internalType":"address"},{"name":"to","type":"address","internalType":"address"},{"name":"value","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"nonpayable"},{"name":"treasury","type":"function","inputs":[],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"name":"treasuryBnbAmount","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"underdogBonus","type":"function","inputs":[{"name":"","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"name":"warEnd","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"warStart","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"winner","type":"function","inputs":[],"outputs":[{"name":"","type":"uint8","internalType":"uint8"}],"stateMutability":"view"}],"matchId":"59081725","creationMatch":"exact_match","runtimeMatch":"exact_match","verifiedAt":"2026-11-11T02:45:23Z","match":"exact_match","chainId":"56","address":"0x4EC884302B486dCb3E7fb6B2741aE9E5A5d7771A"}