{"sources":{"src/SeatworkMint.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.24;\n\nimport {SeatworkArt} from \"./SeatworkArt.sol\";\n\ninterface IAgentRegistry {\n    function ownerOf(uint256 tokenId) external view returns (address);\n}\n\ninterface IERC721Receiver {\n    function onERC721Received(address operator, address from, uint256 tokenId, bytes calldata data)\n        external\n        returns (bytes4);\n}\n\n/// @title SeatworkMint\n/// @notice A pixel collection that is mined, not bought. Work is the gate; money only shortens\n///         the work for a single mint.\n/// @dev Design rules, all enforced here:\n///      - Fixed supply. No owner mint, no burn, no upgrade path.\n///      - Difficulty rises with supply: `startBits + totalMinted / bitsStep`.\n///      - A mint is valid when keccak256(wallet, tokenId, nonce) has at least `difficulty - cut`\n///        leading zero bits. The nonce is bound to the wallet and the tokenId, so a solved nonce\n///        cannot be reused by anyone else or for another token.\n///      - Tiers 1-3 reduce the work for that one mint and forward a fee to the treasury. They\n///        never buy a token: the free tier is available forever, at full difficulty.\n///      - Each .ai Agent ID may mint `PER_AGENT_QUOTA` tokens, free or paid alike.\n///      - The difficulty each token was mined at is stored, because that is the rarity of this\n///        collection: proof of work, not a dice roll.\n///      - ERC721 standard surface (balanceOf, ownerOf, transfers, approvals, tokenURI) so the\n///        collection is readable by any wallet or marketplace. The art is drawn by SeatworkArt\n///        inside the contract: no IPFS, no metadata server, nothing to take offline.\ncontract SeatworkMint {\n    IAgentRegistry public immutable registry;\n    address public owner;\n    address public treasury;\n\n    uint256 public constant MAX_SUPPLY = 5000;\n\n    /// @dev Phase one: the first 1,500 cells (30% of supply). Cheap enough to feel fair.\n    uint256 public constant START_BITS = 18;\n    uint256 public constant PHASE1_STEP = 200;\n\n    /// @dev Phase two: from 1,500 on, the floor jumps 3 bits and climbs to 32 at the last cell.\n    uint256 public constant PHASE2_START = 1500;\n    uint256 public constant PHASE2_BASE_BITS = 28;\n    uint256 public constant PHASE2_STEP = 700;\n\n    /// @dev Bits at or above which a cell counts as a heavy mine (1.5x airdrop weight).\n    uint256 public constant HEAVY_BITS = 30;\n    uint256 public constant EARLY_CLASS = 500;\n    uint256 public constant PER_AGENT_QUOTA = 3;\n\n    uint256 public constant TIER1_FEE = 0.0002 ether;\n    uint256 public constant TIER2_FEE = 0.00067 ether;\n    uint256 public constant TIER3_FEE = 0.00134 ether;\n\n    uint256 public totalMinted;\n\n    /// @notice Timestamp the mine opens. Before it, mint reverts with NotStarted.\n    /// @dev Adjustable only while the mine is still closed, so it can be postponed before launch\n    ///      and can never be used to freeze a collection that is already mining.\n    uint256 public mintStart;\n\n    string public constant name = \"Seatwork Cells\";\n    string public constant symbol = \"CELL\";\n\n    /// @notice Difficulty each token was mined at.\n    mapping(uint256 => uint8) public minedBits;\n    /// @notice Agent ID that minted each token.\n    mapping(uint256 => uint256) public minterAgentId;\n    /// @notice How many tokens each Agent ID has minted.\n    mapping(uint256 => uint256) public mintedByAgent;\n\n    /// @notice How many cells each address brought in through its referral link.\n    mapping(address => uint256) public referrals;\n\n    mapping(uint256 => address) private _owners;\n    mapping(address => uint256) private _balances;\n    mapping(uint256 => address) private _tokenApprovals;\n\n    // ERC721Enumerable bookkeeping\n    mapping(address => uint256[]) private _ownedTokens;\n    mapping(uint256 => uint256) private _ownedTokensIndex;\n    uint256[] private _allTokens;\n    mapping(uint256 => uint256) private _allTokensIndex;\n    mapping(address => mapping(address => bool)) private _operatorApprovals;\n\n    event Mined(uint256 indexed tokenId, address indexed minter, uint256 indexed agentId, uint8 bits, uint8 tier);\n    event TreasurySet(address treasury);\n    event MintStartSet(uint256 mintStart);\n    event Referred(address indexed referrer, address indexed referee, uint256 indexed tokenId);\n    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);\n    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);\n    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\n\n    error OnlyOwner();\n    error ZeroAddress();\n    error SoldOut();\n    error QuotaReached();\n    error NotAgentHolder();\n    error WrongPayment();\n    error BadTier();\n    error WeakNonce();\n    error TreasuryForwardFailed();\n    error NotStarted();\n    error UnknownToken();\n    error NotAuthorized();\n    error BadRecipient();\n\n    bytes4 private constant ERC721_RECEIVED = 0x150b7a02;\n\n    modifier onlyOwner() {\n        if (msg.sender != owner) revert OnlyOwner();\n        _;\n    }\n\n    constructor(address registry_, address treasury_, uint256 mintStart_) {\n        if (registry_ == address(0) || treasury_ == address(0)) revert ZeroAddress();\n        registry = IAgentRegistry(registry_);\n        treasury = treasury_;\n        mintStart = mintStart_;\n        owner = msg.sender;\n    }\n\n    /// @notice Move the opening time. Only possible while the mine is closed.\n    function setMintStart(uint256 mintStart_) external onlyOwner {\n        if (block.timestamp >= mintStart) revert NotStarted();\n        mintStart = mintStart_;\n        emit MintStartSet(mintStart_);\n    }\n\n    function setTreasury(address treasury_) external onlyOwner {\n        if (treasury_ == address(0)) revert ZeroAddress();\n        treasury = treasury_;\n        emit TreasurySet(treasury_);\n    }\n\n    /// @notice Bits of work a mint needs right now, before any tier cut.\n    /// @dev Two phases. The first 1,500 cells climb 18 -> 25. From 1,500 the floor jumps to 28 and\n    ///      climbs to 32 at the last cell, so the free tier turns into hours while a paid tier still\n    ///      finishes in minutes.\n    function difficulty() public view returns (uint8) {\n        if (totalMinted < PHASE2_START) {\n            return uint8(START_BITS + totalMinted / PHASE1_STEP);\n        }\n        return uint8(PHASE2_BASE_BITS + (totalMinted - PHASE2_START) / PHASE2_STEP);\n    }\n\n    /// @notice Fee and work cut for a tier. Tier 0 is free and cuts nothing.\n    function tier(uint8 t) public pure returns (uint256 fee, uint8 cut) {\n        if (t == 0) return (0, 0);\n        if (t == 1) return (TIER1_FEE, 2);\n        if (t == 2) return (TIER2_FEE, 4);\n        if (t == 3) return (TIER3_FEE, 6);\n        revert BadTier();\n    }\n\n    /// @notice Airdrop weight in basis points of a common token: 10000 = 1x.\n    ///         Early class doubles it, heavy mining adds 50%.\n    function airdropWeight(uint256 tokenId) public view returns (uint256) {\n        if (tokenId == 0 || tokenId > totalMinted) return 0;\n        uint256 weight = 10_000;\n        if (tokenId <= EARLY_CLASS) weight = 20_000;\n        if (minedBits[tokenId] >= HEAVY_BITS) weight = (weight * 15) / 10;\n        return weight;\n    }\n\n    /// @notice Mine the next token. `nonce` is the work you did, `tier` optionally shortens it.\n    function mint(uint256 agentId, uint256 nonce, uint8 tierIndex, address referrer) external payable returns (uint256 tokenId) {\n        if (block.timestamp < mintStart) revert NotStarted();\n        if (totalMinted >= MAX_SUPPLY) revert SoldOut();\n        if (mintedByAgent[agentId] >= PER_AGENT_QUOTA) revert QuotaReached();\n        if (_registryOwnerOf(agentId) != msg.sender) revert NotAgentHolder();\n\n        (uint256 fee, uint8 cut) = tier(tierIndex);\n        if (msg.value != fee) revert WrongPayment();\n\n        tokenId = totalMinted + 1;\n        uint8 required = difficulty();\n        uint8 effective = required > cut ? required - cut : 1;\n        if (!_hasWork(msg.sender, tokenId, nonce, effective)) revert WeakNonce();\n\n        if (referrer != address(0) && referrer != msg.sender) {\n            referrals[referrer] += 1;\n            emit Referred(referrer, msg.sender, tokenId);\n        }\n\n        minedBits[tokenId] = required;\n        minterAgentId[tokenId] = agentId;\n        mintedByAgent[agentId] += 1;\n        totalMinted = tokenId;\n\n        _owners[tokenId] = msg.sender;\n        _balances[msg.sender] += 1;\n        _addTokenToOwnerEnumeration(msg.sender, tokenId);\n        _addTokenToAllEnumeration(tokenId);\n\n        emit Transfer(address(0), msg.sender, tokenId);\n        emit Mined(tokenId, msg.sender, agentId, required, tierIndex);\n\n        if (fee > 0) {\n            (bool ok,) = treasury.call{value: fee}(\"\");\n            if (!ok) revert TreasuryForwardFailed();\n        }\n    }\n\n    /// @notice Number of leading zero bits in the work hash for this wallet and token.\n    function workBits(address minter, uint256 tokenId, uint256 nonce) public pure returns (uint8 bits) {\n        bytes32 h = keccak256(abi.encode(minter, tokenId, nonce));\n        for (uint256 i = 0; i < 32; i++) {\n            uint8 b = uint8(h[i]);\n            if (b == 0) {\n                bits += 8;\n                continue;\n            }\n            bits += uint8(_leadingZeros(b));\n            break;\n        }\n    }\n\n    /* ------------------------------- ERC721 surface ------------------------------ */\n\n    function totalSupply() external view returns (uint256) {\n        return totalMinted;\n    }\n\n    function balanceOf(address account) public view returns (uint256) {\n        if (account == address(0)) revert ZeroAddress();\n        return _balances[account];\n    }\n\n    function ownerOf(uint256 tokenId) public view returns (address) {\n        address holder = _owners[tokenId];\n        if (holder == address(0)) revert UnknownToken();\n        return holder;\n    }\n\n    function approve(address to, uint256 tokenId) external {\n        address holder = ownerOf(tokenId);\n        if (msg.sender != holder && !isApprovedForAll(holder, msg.sender)) revert NotAuthorized();\n        _tokenApprovals[tokenId] = to;\n        emit Approval(holder, to, tokenId);\n    }\n\n    function getApproved(uint256 tokenId) external view returns (address) {\n        if (_owners[tokenId] == address(0)) revert UnknownToken();\n        return _tokenApprovals[tokenId];\n    }\n\n    function setApprovalForAll(address operator, bool approved) external {\n        _operatorApprovals[msg.sender][operator] = approved;\n        emit ApprovalForAll(msg.sender, operator, approved);\n    }\n\n    function isApprovedForAll(address holder, address operator) public view returns (bool) {\n        return _operatorApprovals[holder][operator];\n    }\n\n    function transferFrom(address from, address to, uint256 tokenId) public {\n        if (to == address(0)) revert ZeroAddress();\n        address holder = ownerOf(tokenId);\n        if (holder != from) revert NotAuthorized();\n        if (msg.sender != holder && _tokenApprovals[tokenId] != msg.sender && !isApprovedForAll(holder, msg.sender)) {\n            revert NotAuthorized();\n        }\n\n        delete _tokenApprovals[tokenId];\n        _removeTokenFromOwnerEnumeration(from, tokenId);\n        _balances[from] -= 1;\n        _balances[to] += 1;\n        _owners[tokenId] = to;\n        _addTokenToOwnerEnumeration(to, tokenId);\n\n        emit Transfer(from, to, tokenId);\n    }\n\n    function safeTransferFrom(address from, address to, uint256 tokenId) external {\n        safeTransferFrom(from, to, tokenId, \"\");\n    }\n\n    function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public {\n        transferFrom(from, to, tokenId);\n        if (to.code.length != 0) {\n            bytes4 ret = IERC721Receiver(to).onERC721Received(msg.sender, from, tokenId, data);\n            if (ret != ERC721_RECEIVED) revert BadRecipient();\n        }\n    }\n\n    function supportsInterface(bytes4 interfaceId) external pure returns (bool) {\n        return interfaceId == 0x01ffc9a7 // ERC165\n            || interfaceId == 0x80ac58cd // ERC721\n            || interfaceId == 0x5b5e139f // ERC721Metadata\n            || interfaceId == 0x780e9d63; // ERC721Enumerable\n    }\n\n    /// @notice The art, generated from the tokenId inside the contract.\n    function tokenURI(uint256 tokenId) external view returns (string memory) {\n        if (_owners[tokenId] == address(0)) revert UnknownToken();\n        return SeatworkArt.tokenURI(tokenId, minedBits[tokenId]);\n    }\n\n    /* ------------------------------ enumerable views ----------------------------- */\n\n    /// @notice Token held by `holder` at `index`. Lets a wallet or this site list what you own.\n    function tokenOfOwnerByIndex(address holder, uint256 index) external view returns (uint256) {\n        if (index >= _balances[holder]) revert UnknownToken();\n        return _ownedTokens[holder][index];\n    }\n\n    /// @notice Token at `index` in mint order.\n    function tokenByIndex(uint256 index) external view returns (uint256) {\n        if (index >= _allTokens.length) revert UnknownToken();\n        return _allTokens[index];\n    }\n\n    /* --------------------------------- internals -------------------------------- */\n\n    function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private {\n        _ownedTokensIndex[tokenId] = _ownedTokens[to].length;\n        _ownedTokens[to].push(tokenId);\n    }\n\n    function _addTokenToAllEnumeration(uint256 tokenId) private {\n        _allTokensIndex[tokenId] = _allTokens.length;\n        _allTokens.push(tokenId);\n    }\n\n    function _removeTokenFromOwnerEnumeration(address from, uint256 tokenId) private {\n        uint256 lastIndex = _ownedTokens[from].length - 1;\n        uint256 lastToken = _ownedTokens[from][lastIndex];\n        uint256 index = _ownedTokensIndex[tokenId];\n        if (index != lastIndex) {\n            _ownedTokens[from][index] = lastToken;\n            _ownedTokensIndex[lastToken] = index;\n        }\n        _ownedTokens[from].pop();\n        delete _ownedTokensIndex[tokenId];\n    }\n\n    function _hasWork(address minter, uint256 tokenId, uint256 nonce, uint8 target) private pure returns (bool) {\n        return workBits(minter, tokenId, nonce) >= target;\n    }\n\n    function _leadingZeros(uint8 b) private pure returns (uint256 n) {\n        while (b != 0) {\n            n++;\n            b >>= 1;\n        }\n        return 8 - n;\n    }\n\n    /// @dev Manual staticcall: a broken registry reads as \"not a holder\", never as a raw revert.\n    function _registryOwnerOf(uint256 agentId) private view returns (address) {\n        (bool ok, bytes memory data) = address(registry).staticcall(abi.encodeWithSignature(\"ownerOf(uint256)\", agentId));\n        if (!ok || data.length < 32) return address(0);\n        uint256 raw = abi.decode(data, (uint256));\n        if (raw > type(uint160).max) return address(0);\n        return address(uint160(raw));\n    }\n}\n"},"src/SeatworkArt.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.24;\n\n/// @title SeatworkCellsArt\n/// @notice Draws a Seatwork cell from its tokenId, inside the contract.\n/// @dev Everything here is pure: the same tokenId always produces the same SVG, on any machine,\n///      with no metadata server, no IPFS pin and nothing that can be swapped after mint.\n///      The sprite is 16x16 with a mirrored left half, so every cell is symmetrical, and the\n///      pixels come from keccak256(\"seatwork:\" + tokenId). Colour depends on the class:\n///      opening cells (first 500) get a lime helmet, cells mined at 22 bits or more get amber.\nlibrary SeatworkArt {\n    uint256 private constant W = 16;\n    /// @dev Upper bound for one SVG document, with slack for the word-wise append.\n    uint256 private constant CAP = 24_576;\n    uint256 private constant HALF = 8;\n\n    /// @dev 16 rows of 8 columns: H helmet, F face, E eye, B body, L legs, . empty.\n    string private constant MASK =\n        \"....HH.....HHHH...HHHHHH..HHHHHH..FFFFF...FEFFF...FFFFF....BBB..\"\n        \"..BBBBB..BBBBBBB.BBBBBBB..BBBBB...LL.LL...LL.LL...LL.LL..LLL.LLL\";\n\n    string private constant BASE64 = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\";\n\n    /// @notice The sprite seed for a token.\n    function seed(uint256 tokenId) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"seatworkcells:\", _toString(tokenId)));\n    }\n\n    struct Traits {\n        uint8 helmetStyle;\n        uint8 faceStyle;\n        uint8 bodyStyle;\n        uint8 tool;\n        uint8 boots;\n        uint8 belt;\n        uint8 arms;\n        uint8 bg;\n        uint8 eye;\n    }\n\n    /// @notice Full SVG document for one cell.\n    /// @dev Mirrors site/art.js line for line: every trait comes from one byte of the seed, so the\n    ///      browser and the chain draw the same sprite. Measured unique across all 5,000 ids.\n    ///      The document is written into one pre-sized buffer instead of being rebuilt with\n    ///      string.concat at every rect: concatenating in a loop copies the whole string on each\n    ///      pass, which made tokenURI quadratic and cost up to 50M gas for a single token.\n    function svg(uint256 tokenId, uint8 bits) internal pure returns (string memory) {\n        bytes32 h = seed(tokenId);\n        string[5] memory pal = _palette(tokenId, bits);\n        Traits memory t = _traits(h);\n\n        uint8[8][16] memory g = _baseGrid();\n        _style(g, t);\n        _speckle(g, h);\n\n        bytes memory buf = new bytes(CAP);\n        uint256 at = _put(buf, 0,\n            \"<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' width='512' height='512' \"\n            \"shape-rendering='crispEdges'><rect width='16' height='16' fill='\");\n        at = _put(buf, at, pal[3]);\n        at = _put(buf, at, \"'/>\");\n        at = _plate(buf, at, t.bg);\n        at = _pixels(buf, at, g, pal);\n        at = _put(buf, at, \"</svg>\");\n\n        assembly {\n            mstore(buf, at)\n        }\n        return string(buf);\n    }\n\n    function _traits(bytes32 h) private pure returns (Traits memory t) {\n        t.helmetStyle = uint8(h[0]) % 3;\n        t.faceStyle = uint8(h[1]) % 3;\n        t.bodyStyle = uint8(h[2]) % 4;\n        t.tool = uint8(h[3]) % 4;\n        t.boots = uint8(h[4]) % 2;\n        t.belt = uint8(h[5]) % 2;\n        t.arms = uint8(h[6]) % 2;\n        t.bg = uint8(h[7]) % 3;\n        t.eye = uint8(h[9]) % 2;\n    }\n\n    function _baseGrid() private pure returns (uint8[8][16] memory g) {\n        bytes memory mask = bytes(MASK);\n        for (uint256 y = 0; y < 16; y++) {\n            for (uint256 x = 0; x < HALF; x++) {\n                bytes1 ch = mask[y * HALF + x];\n                uint8 idx = 255;\n                if (ch == \"H\") idx = 2;\n                else if (ch == \"F\") idx = 3;\n                else if (ch == \"E\") idx = 0;\n                else if (ch == \"B\") idx = 1;\n                else if (ch == \"L\") idx = 1;\n                g[y][x] = idx;\n            }\n        }\n    }\n\n    function _style(uint8[8][16] memory g, Traits memory t) private pure {\n        if (t.helmetStyle == 1) { g[0][4] = 255; g[0][5] = 255; }\n        if (t.helmetStyle == 2) { g[3][1] = 2; g[3][6] = 2; }\n\n        if (t.faceStyle == 1) { g[5][5] = 0; g[5][6] = 0; }\n        if (t.faceStyle == 2) { g[6][3] = 1; g[6][4] = 1; g[6][5] = 1; }\n        if (t.eye == 1) { g[5][3] = 0; }\n\n        if (t.bodyStyle == 1) { for (uint256 ys = 8; ys <= 11; ys++) g[ys][4] = 2; }\n        if (t.bodyStyle == 2) { g[9][1] = 2; g[9][2] = 2; g[10][1] = 2; g[10][2] = 2; }\n        if (t.bodyStyle == 3) { g[8][2] = 2; g[9][3] = 2; g[10][4] = 2; }\n\n        if (t.belt == 1) { g[11][2] = 0; g[11][3] = 0; g[11][4] = 0; g[11][5] = 0; }\n        if (t.arms == 1) { g[9][0] = 1; g[10][0] = 1; }\n        if (t.boots == 1) { g[15][2] = 0; g[15][5] = 0; }\n\n        if (t.tool == 1) { g[7][0] = 2; g[8][0] = 2; }\n        if (t.tool == 2) { g[10][0] = 4; g[11][0] = 4; }\n        if (t.tool == 3) { g[11][0] = 3; g[11][1] = 3; }\n    }\n\n    function _speckle(uint8[8][16] memory g, bytes32 h) private pure {\n        for (uint256 i = 0; i < 24; i++) {\n            uint256 ry = 7 + (uint8(h[(8 + i) % 32]) % 5);\n            uint256 rx = uint8(h[(16 + i) % 32]) % HALF;\n            if (g[ry][rx] != 255 && uint8(h[(24 + i) % 32]) % 2 == 0) {\n                g[ry][rx] = 1 + (uint8(h[(28 + i) % 32]) % 3);\n            }\n        }\n    }\n\n    function _plate(bytes memory buf, uint256 at, uint8 bg) private pure returns (uint256) {\n        if (bg == 1) {\n            for (uint256 ty = 0; ty < 16; ty += 2) {\n                for (uint256 tx = 0; tx < 16; tx += 2) {\n                    at = _put(buf, at, \"<rect x='\");\n                    at = _put(buf, at, _toString(tx));\n                    at = _put(buf, at, \"' y='\");\n                    at = _put(buf, at, _toString(ty));\n                    at = _put(buf, at, \"' width='1' height='1' fill='#e2ddcd'/>\");\n                }\n            }\n        } else if (bg == 2) {\n            at = _put(buf, at, \"<rect x='0' y='14' width='16' height='2' fill='#e8e3d4'/>\");\n        }\n        return at;\n    }\n\n    function _pixels(bytes memory buf, uint256 at, uint8[8][16] memory g, string[5] memory pal)\n        private\n        pure\n        returns (uint256)\n    {\n        for (uint256 y = 0; y < 16; y++) {\n            for (uint256 x = 0; x < HALF; x++) {\n                uint8 idx = g[y][x];\n                if (idx == 255) continue;\n                at = _put(buf, at, \"<rect x='\");\n                at = _put(buf, at, _toString(x));\n                at = _put(buf, at, \"' y='\");\n                at = _put(buf, at, _toString(y));\n                at = _put(buf, at, \"' width='1' height='1' fill='\");\n                at = _put(buf, at, pal[idx]);\n                at = _put(buf, at, \"'/>\");\n                uint256 mirror = W - 1 - x;\n                if (mirror != x) {\n                    at = _put(buf, at, \"<rect x='\");\n                    at = _put(buf, at, _toString(mirror));\n                    at = _put(buf, at, \"' y='\");\n                    at = _put(buf, at, _toString(y));\n                    at = _put(buf, at, \"' width='1' height='1' fill='\");\n                    at = _put(buf, at, pal[idx]);\n                    at = _put(buf, at, \"'/>\");\n                }\n            }\n        }\n        return at;\n    }\n\n    /// @dev Append `part` at `at` inside a pre-allocated buffer. Word-wise copy by assembly:\n    ///      the tail word may write past the string length, which is why the buffer keeps slack.\n    function _put(bytes memory buf, uint256 at, string memory part) private pure returns (uint256) {\n        bytes memory src = bytes(part);\n        uint256 len = src.length;\n        if (len == 0) return at;\n        assembly {\n            let s := add(src, 32)\n            let d := add(add(buf, 32), at)\n            for { let i := 0 } lt(i, len) { i := add(i, 32) } { mstore(add(d, i), mload(add(s, i))) }\n        }\n        return at + len;\n    }\n\n    /// @notice ERC721 metadata, base64 JSON with the SVG inlined as a data URI.\n    function tokenURI(uint256 tokenId, uint8 bits) internal pure returns (string memory) {\n        string memory image = _escapeHash(svg(tokenId, bits));\n        string memory class = tokenId <= 500 ? \"Opening class\" : (bits >= 22 ? \"Heavy mine\" : \"Common\");\n\n        string memory json = string.concat(\n            '{\"name\":\"Seatwork Cells #', _pad(_toString(tokenId), 4),\n            '\",\"description\":\"A Seatwork Cells pixel cell mined on BNB Smart Chain. Rarity is the work: this cell was ',\n            \"found at \", _toString(bits), \" bits of leading zeros, \", class,\n            '. The sprite is generated from the tokenId inside the contract, so it cannot be changed or taken offline.\",',\n            '\"image\":\"data:image/svg+xml;utf8,', image, '\",',\n            '\"attributes\":[{\"trait_type\":\"Bits at mint\",\"value\":', _toString(bits), \"},\",\n            '{\"trait_type\":\"Class\",\"value\":\"', class, '\"}',\n            \"]}\"\n        );\n\n        return string.concat(\"data:application/json;base64,\", _base64(bytes(json)));\n    }\n\n    function _palette(uint256 tokenId, uint8 bits) private pure returns (string[5] memory pal) {\n        if (tokenId <= 500) {\n            pal = [\"#12211c\", \"#2f5d46\", \"#a7c957\", \"#f0ebdd\", \"#e2c15a\"];\n        } else if (bits >= 22) {\n            pal = [\"#12211c\", \"#3b3324\", \"#c9922f\", \"#f0ebdd\", \"#ffd166\"];\n        } else {\n            pal = [\"#12211c\", \"#2f5d46\", \"#7fa653\", \"#f0ebdd\", \"#d8a13a\"];\n        }\n    }\n\n    /// @dev '#' must be percent-encoded inside a data URI.\n    function _escapeHash(string memory input) private pure returns (string memory) {\n        bytes memory b = bytes(input);\n        uint256 count;\n        for (uint256 i = 0; i < b.length; i++) if (b[i] == \"#\") count++;\n        if (count == 0) return input;\n\n        bytes memory out = new bytes(b.length + count * 2);\n        uint256 j;\n        for (uint256 i = 0; i < b.length; i++) {\n            if (b[i] == \"#\") { out[j] = \"%\"; out[j + 1] = \"2\"; out[j + 2] = \"3\"; j += 3; }\n            else { out[j] = b[i]; j++; }\n        }\n        return string(out);\n    }\n\n    function _pad(string memory s, uint256 width) private pure returns (string memory) {\n        bytes memory b = bytes(s);\n        if (b.length >= width) return s;\n        bytes memory out = new bytes(width);\n        uint256 pad = width - b.length;\n        for (uint256 i = 0; i < pad; i++) out[i] = \"0\";\n        for (uint256 i2 = 0; i2 < b.length; i2++) out[pad + i2] = b[i2];\n        return string(out);\n    }\n\n    function _toString(uint256 value) private pure returns (string memory) {\n        if (value == 0) return \"0\";\n        uint256 temp = value;\n        uint256 digits;\n        while (temp != 0) { digits++; temp /= 10; }\n        bytes memory buffer = new bytes(digits);\n        while (value != 0) {\n            digits--;\n            buffer[digits] = bytes1(uint8(48 + (value % 10)));\n            value /= 10;\n        }\n        return string(buffer);\n    }\n\n    function _base64(bytes memory data) private pure returns (string memory) {\n        if (data.length == 0) return \"\";\n        bytes memory table = bytes(BASE64);\n        uint256 len = 4 * ((data.length + 2) / 3);\n        bytes memory out = new bytes(len);\n        uint256 i;\n        uint256 j;\n        for (; i + 3 <= data.length; i += 3) {\n            uint256 n = (uint256(uint8(data[i])) << 16) | (uint256(uint8(data[i + 1])) << 8) | uint256(uint8(data[i + 2]));\n            out[j++] = table[(n >> 18) & 63];\n            out[j++] = table[(n >> 12) & 63];\n            out[j++] = table[(n >> 6) & 63];\n            out[j++] = table[n & 63];\n        }\n        if (data.length - i == 1) {\n            uint256 n = uint256(uint8(data[i])) << 16;\n            out[j++] = table[(n >> 18) & 63];\n            out[j++] = table[(n >> 12) & 63];\n            out[j++] = \"=\";\n            out[j++] = \"=\";\n        } else if (data.length - i == 2) {\n            uint256 n = (uint256(uint8(data[i])) << 16) | (uint256(uint8(data[i + 1])) << 8);\n            out[j++] = table[(n >> 18) & 63];\n            out[j++] = table[(n >> 12) & 63];\n            out[j++] = table[(n >> 6) & 63];\n            out[j++] = \"=\";\n        }\n        return string(out);\n    }\n}\n"}},"abi":[{"type":"constructor","inputs":[{"name":"registry_","type":"address","internalType":"address"},{"name":"treasury_","type":"address","internalType":"address"},{"name":"mintStart_","type":"uint256","internalType":"uint256"}],"stateMutability":"nonpayable"},{"name":"BadRecipient","type":"error","inputs":[]},{"name":"BadTier","type":"error","inputs":[]},{"name":"NotAgentHolder","type":"error","inputs":[]},{"name":"NotAuthorized","type":"error","inputs":[]},{"name":"NotStarted","type":"error","inputs":[]},{"name":"OnlyOwner","type":"error","inputs":[]},{"name":"QuotaReached","type":"error","inputs":[]},{"name":"SoldOut","type":"error","inputs":[]},{"name":"TreasuryForwardFailed","type":"error","inputs":[]},{"name":"UnknownToken","type":"error","inputs":[]},{"name":"WeakNonce","type":"error","inputs":[]},{"name":"WrongPayment","type":"error","inputs":[]},{"name":"ZeroAddress","type":"error","inputs":[]},{"name":"Approval","type":"event","inputs":[{"name":"owner","type":"address","indexed":true,"internalType":"address"},{"name":"approved","type":"address","indexed":true,"internalType":"address"},{"name":"tokenId","type":"uint256","indexed":true,"internalType":"uint256"}],"anonymous":false},{"name":"ApprovalForAll","type":"event","inputs":[{"name":"owner","type":"address","indexed":true,"internalType":"address"},{"name":"operator","type":"address","indexed":true,"internalType":"address"},{"name":"approved","type":"bool","indexed":false,"internalType":"bool"}],"anonymous":false},{"name":"Mined","type":"event","inputs":[{"name":"tokenId","type":"uint256","indexed":true,"internalType":"uint256"},{"name":"minter","type":"address","indexed":true,"internalType":"address"},{"name":"agentId","type":"uint256","indexed":true,"internalType":"uint256"},{"name":"bits","type":"uint8","indexed":false,"internalType":"uint8"},{"name":"tier","type":"uint8","indexed":false,"internalType":"uint8"}],"anonymous":false},{"name":"MintStartSet","type":"event","inputs":[{"name":"mintStart","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"name":"Referred","type":"event","inputs":[{"name":"referrer","type":"address","indexed":true,"internalType":"address"},{"name":"referee","type":"address","indexed":true,"internalType":"address"},{"name":"tokenId","type":"uint256","indexed":true,"internalType":"uint256"}],"anonymous":false},{"name":"Transfer","type":"event","inputs":[{"name":"from","type":"address","indexed":true,"internalType":"address"},{"name":"to","type":"address","indexed":true,"internalType":"address"},{"name":"tokenId","type":"uint256","indexed":true,"internalType":"uint256"}],"anonymous":false},{"name":"TreasurySet","type":"event","inputs":[{"name":"treasury","type":"address","indexed":false,"internalType":"address"}],"anonymous":false},{"name":"EARLY_CLASS","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"HEAVY_BITS","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"MAX_SUPPLY","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"PER_AGENT_QUOTA","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"PHASE1_STEP","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"PHASE2_BASE_BITS","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"PHASE2_START","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"PHASE2_STEP","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"START_BITS","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"TIER1_FEE","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"TIER2_FEE","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"TIER3_FEE","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"airdropWeight","type":"function","inputs":[{"name":"tokenId","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"approve","type":"function","inputs":[{"name":"to","type":"address","internalType":"address"},{"name":"tokenId","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"name":"balanceOf","type":"function","inputs":[{"name":"account","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"difficulty","type":"function","inputs":[],"outputs":[{"name":"","type":"uint8","internalType":"uint8"}],"stateMutability":"view"},{"name":"getApproved","type":"function","inputs":[{"name":"tokenId","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"name":"isApprovedForAll","type":"function","inputs":[{"name":"holder","type":"address","internalType":"address"},{"name":"operator","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"name":"minedBits","type":"function","inputs":[{"name":"","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"uint8","internalType":"uint8"}],"stateMutability":"view"},{"name":"mint","type":"function","inputs":[{"name":"agentId","type":"uint256","internalType":"uint256"},{"name":"nonce","type":"uint256","internalType":"uint256"},{"name":"tierIndex","type":"uint8","internalType":"uint8"},{"name":"referrer","type":"address","internalType":"address"}],"outputs":[{"name":"tokenId","type":"uint256","internalType":"uint256"}],"stateMutability":"payable"},{"name":"mintStart","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"mintedByAgent","type":"function","inputs":[{"name":"","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"minterAgentId","type":"function","inputs":[{"name":"","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"name","type":"function","inputs":[],"outputs":[{"name":"","type":"string","internalType":"string"}],"stateMutability":"view"},{"name":"owner","type":"function","inputs":[],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"name":"ownerOf","type":"function","inputs":[{"name":"tokenId","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"name":"referrals","type":"function","inputs":[{"name":"","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"registry","type":"function","inputs":[],"outputs":[{"name":"","type":"address","internalType":"contract IAgentRegistry"}],"stateMutability":"view"},{"name":"safeTransferFrom","type":"function","inputs":[{"name":"from","type":"address","internalType":"address"},{"name":"to","type":"address","internalType":"address"},{"name":"tokenId","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"name":"safeTransferFrom","type":"function","inputs":[{"name":"from","type":"address","internalType":"address"},{"name":"to","type":"address","internalType":"address"},{"name":"tokenId","type":"uint256","internalType":"uint256"},{"name":"data","type":"bytes","internalType":"bytes"}],"outputs":[],"stateMutability":"nonpayable"},{"name":"setApprovalForAll","type":"function","inputs":[{"name":"operator","type":"address","internalType":"address"},{"name":"approved","type":"bool","internalType":"bool"}],"outputs":[],"stateMutability":"nonpayable"},{"name":"setMintStart","type":"function","inputs":[{"name":"mintStart_","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"name":"setTreasury","type":"function","inputs":[{"name":"treasury_","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"name":"supportsInterface","type":"function","inputs":[{"name":"interfaceId","type":"bytes4","internalType":"bytes4"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"pure"},{"name":"symbol","type":"function","inputs":[],"outputs":[{"name":"","type":"string","internalType":"string"}],"stateMutability":"view"},{"name":"tier","type":"function","inputs":[{"name":"t","type":"uint8","internalType":"uint8"}],"outputs":[{"name":"fee","type":"uint256","internalType":"uint256"},{"name":"cut","type":"uint8","internalType":"uint8"}],"stateMutability":"pure"},{"name":"tokenByIndex","type":"function","inputs":[{"name":"index","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"tokenOfOwnerByIndex","type":"function","inputs":[{"name":"holder","type":"address","internalType":"address"},{"name":"index","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"tokenURI","type":"function","inputs":[{"name":"tokenId","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"string","internalType":"string"}],"stateMutability":"view"},{"name":"totalMinted","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":"transferFrom","type":"function","inputs":[{"name":"from","type":"address","internalType":"address"},{"name":"to","type":"address","internalType":"address"},{"name":"tokenId","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"name":"treasury","type":"function","inputs":[],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"name":"workBits","type":"function","inputs":[{"name":"minter","type":"address","internalType":"address"},{"name":"tokenId","type":"uint256","internalType":"uint256"},{"name":"nonce","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"bits","type":"uint8","internalType":"uint8"}],"stateMutability":"pure"}],"matchId":"57810774","creationMatch":"exact_match","runtimeMatch":"exact_match","verifiedAt":"2026-10-31T09:55:24Z","match":"exact_match","chainId":"56","address":"0xEff3c54bB66B970Ef6e2e5f28A09802Fbfe8221F"}