{"sources":{"PoeNft.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.20;\n\n/// @title POE — Proof of Epoch (v2)\n/// @notice Commemorative ERC721 issued by the AGCE sale contract: one per\n///         paid launch share, AND one free-edition proof per free claim\n///         (v2 change — v1 free claims received AGCE only, which starved\n///         this contract of discovery traffic: the metadata pointers live\n///         here, so the free path now touches this contract too).\n///         Paid proofs carry a tier set at mint by the holder's cumulative\n///         paid shares: Tier I for 1–4, Tier II for 5–9, Tier III for 10.\n///         Free-edition proofs are tier 0: they never count toward the\n///         paid tiers and are never upgraded by later paid shares.\n///         All editions share one approved artwork template (framed\n///         plate, three epoch rings, centered crown, satellite dot, tier\n///         bars at the bottom) and differ only in accent color and bar\n///         count: neutral grey, no bars (free), silver #8b98a8 (I), teal\n///         #35d0ba (II), gold #e3a82b (III). tokenURI is a fully on-chain\n///         data:application/json;base64 document whose image is an inline\n///         SVG rendered by the contract.\ncontract PoeNft {\n    string public constant name = \"Proof of Epoch\";\n    string public constant symbol = \"POE\";\n    string public constant EXTERNAL_URL = \"https://agce.pages.dev\";\n\n    address public owner;\n    address public minter;\n    uint256 public nextId = 1;\n\n    mapping(uint256 => address) internal _owners;\n    mapping(uint256 => uint256) public tierOf;\n    mapping(address => uint256) public balanceOf;\n    mapping(uint256 => address) public getApproved;\n    mapping(address => mapping(address => bool)) public isApprovedForAll;\n\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    constructor() {\n        owner = msg.sender;\n    }\n\n    modifier onlyOwner() {\n        require(msg.sender == owner, \"not owner\");\n        _;\n    }\n\n    /// @notice Set the sale contract allowed to mint. One-time setup.\n    function setMinter(address minter_) external onlyOwner {\n        require(minter_ != address(0), \"zero address\");\n        minter = minter_;\n    }\n\n    /// @notice Tier for a cumulative paid-share count: 1–4 -> I, 5–9 -> II,\n    ///         10 -> III. (Proofs are minted from the paid path only.)\n    function tierFor(uint256 paidCumulative) public pure returns (uint256) {\n        if (paidCumulative >= 10) return 3;\n        if (paidCumulative >= 5) return 2;\n        return 1;\n    }\n\n    /// @notice Mint one proof to `to`, tiered by the holder's cumulative\n    ///         paid shares at this moment (`paidCumulative`).\n    function mintTo(address to, uint256 paidCumulative) external returns (uint256 id) {\n        require(msg.sender == minter, \"not minter\");\n        require(to != address(0), \"zero to\");\n        id = nextId++;\n        _owners[id] = to;\n        tierOf[id] = tierFor(paidCumulative);\n        balanceOf[to] += 1;\n        emit Transfer(address(0), to, id);\n    }\n\n    /// @notice Mint one free-edition proof (tier 0) to `to`. Issued by the\n    ///         sale contract with each free claim; carries no paid tier\n    ///         and is unaffected by the holder's paid shares, past or\n    ///         future.\n    function mintFreeTo(address to) external returns (uint256 id) {\n        require(msg.sender == minter, \"not minter\");\n        require(to != address(0), \"zero to\");\n        id = nextId++;\n        _owners[id] = to;\n        tierOf[id] = 0;\n        balanceOf[to] += 1;\n        emit Transfer(address(0), to, id);\n    }\n\n    function ownerOf(uint256 id) public view returns (address) {\n        address o = _owners[id];\n        require(o != address(0), \"nonexistent token\");\n        return o;\n    }\n\n    function approve(address approved, uint256 id) external {\n        address o = ownerOf(id);\n        require(msg.sender == o || isApprovedForAll[o][msg.sender], \"not authorized\");\n        getApproved[id] = approved;\n        emit Approval(o, approved, id);\n    }\n\n    function setApprovalForAll(address operator, bool approved) external {\n        isApprovedForAll[msg.sender][operator] = approved;\n        emit ApprovalForAll(msg.sender, operator, approved);\n    }\n\n    function transferFrom(address from, address to, uint256 id) public {\n        require(ownerOf(id) == from, \"wrong owner\");\n        require(\n            msg.sender == from || msg.sender == getApproved[id] || isApprovedForAll[from][msg.sender],\n            \"not authorized\"\n        );\n        require(to != address(0), \"zero to\");\n        getApproved[id] = address(0);\n        balanceOf[from] -= 1;\n        balanceOf[to] += 1;\n        _owners[id] = to;\n        emit Transfer(from, to, id);\n    }\n\n    function safeTransferFrom(address from, address to, uint256 id) external {\n        safeTransferFrom(from, to, id, \"\");\n    }\n\n    function safeTransferFrom(address from, address to, uint256 id, bytes memory data) public {\n        transferFrom(from, to, id);\n        if (to.code.length > 0) {\n            require(\n                IERC721Receiver(to).onERC721Received(msg.sender, from, id, data) ==\n                    IERC721Receiver.onERC721Received.selector,\n                \"receiver rejected\"\n            );\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    }\n\n    function tokenURI(uint256 id) public view returns (string memory) {\n        require(_owners[id] != address(0), \"nonexistent token\");\n        uint256 tier = tierOf[id];\n        string memory svg = _svg(tier);\n        string memory desc;\n        string memory attrs;\n        if (tier == 0) {\n            desc = \"Proof of Epoch (POE) - free-claim edition of the commemorative proof of the AGCE (AGC Epoch) community launch, issued with each free claim. Neutral grey, no tier bars; paid editions are tiered by the holder cumulative paid shares: I for 1-4, II for 5-9, III for 10. AGC official X: @Agentic_coin.\";\n            attrs = '[{\"trait_type\":\"Tier\",\"value\":\"Free\"},{\"trait_type\":\"Source\",\"value\":\"Free Claim\"}]';\n        } else {\n            desc = \"Proof of Epoch (POE) - commemorative proof issued with each paid share of the AGCE (AGC Epoch) community launch. Tier is set at mint by the holder cumulative paid shares: I for 1-4, II for 5-9, III for 10. AGC official X: @Agentic_coin.\";\n            attrs = string(abi.encodePacked('[{\"trait_type\":\"Tier\",\"value\":\"', _roman(tier), '\"}]'));\n        }\n        string memory json = string(\n            abi.encodePacked(\n                '{\"name\":\"Proof of Epoch #',\n                _toString(id),\n                '\",\"description\":\"',\n                desc,\n                '\",\"image\":\"data:image/svg+xml;base64,',\n                _b64(bytes(svg)),\n                '\",\"external_url\":\"',\n                EXTERNAL_URL,\n                '\",\"attributes\":',\n                attrs,\n                '}'\n            )\n        );\n        return string(abi.encodePacked(\"data:application/json;base64,\", _b64(bytes(json))));\n    }\n\n    function _roman(uint256 tier) internal pure returns (string memory) {\n        if (tier == 3) return \"III\";\n        if (tier == 2) return \"II\";\n        return \"I\";\n    }\n\n    /// @dev The approved artwork (icons/poe-tier{1,2,3}.svg + free edition):\n    ///      one shared template — framed plate, three epoch rings, centered\n    ///      crown, satellite dot — with the edition accent color (free\n    ///      edition neutral grey #a3a3a3 with NO tier bars, I silver\n    ///      #8b98a8, II teal #35d0ba, III gold #e3a82b) and 0/1/2/3 tier bars\n    ///      at the bottom. The master files' role/aria-label attributes are\n    ///      dropped here; geometry and colors are unchanged.\n    function _svg(uint256 tier) internal pure returns (string memory) {\n        string memory c = tier == 3 ? \"#e3a82b\" : tier == 2 ? \"#35d0ba\" : tier == 1 ? \"#8b98a8\" : \"#a3a3a3\";\n        string memory bars;\n        if (tier == 3) {\n            bars = string(\n                abi.encodePacked(\n                    \"<rect x='216' y='404' width='18' height='54' rx='4' fill='\", c, \"'/>\",\n                    \"<rect x='247' y='404' width='18' height='54' rx='4' fill='\", c, \"'/>\",\n                    \"<rect x='278' y='404' width='18' height='54' rx='4' fill='\", c, \"'/>\"\n                )\n            );\n        } else if (tier == 2) {\n            bars = string(\n                abi.encodePacked(\n                    \"<rect x='231.5' y='404' width='18' height='54' rx='4' fill='\", c, \"'/>\",\n                    \"<rect x='262.5' y='404' width='18' height='54' rx='4' fill='\", c, \"'/>\"\n                )\n            );\n        } else if (tier == 1) {\n            bars = string(\n                abi.encodePacked(\"<rect x='247' y='404' width='18' height='54' rx='4' fill='\", c, \"'/>\")\n            );\n        }\n        // tier 0 (free edition): bars stays empty — no tier bars.\n        return string(\n            abi.encodePacked(\n                \"<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512' width='512' height='512'>\",\n                \"<rect width='512' height='512' fill='#0a0e13'/>\",\n                \"<rect x='18' y='18' width='476' height='476' fill='#11161d' stroke='\", c, \"' stroke-width='6'/>\",\n                \"<circle cx='256' cy='228' r='148' fill='none' stroke='\", c, \"' stroke-width='10'/>\",\n                \"<circle cx='256' cy='228' r='118' fill='none' stroke='\", c, \"' stroke-width='4'/>\",\n                \"<circle cx='256' cy='228' r='104' fill='none' stroke='\", c, \"' stroke-width='4' stroke-dasharray='8 11' opacity='0.7'/>\",\n                \"<path d='M168 280 L184 172 L226 220 L256 144 L286 220 L328 172 L344 280 Z' fill='\", c, \"'/>\",\n                \"<rect x='168' y='294' width='176' height='18' rx='9' fill='\", c, \"'/>\",\n                \"<circle cx='360' cy='124' r='11' fill='#e8ecf1'/>\",\n                bars,\n                \"</svg>\"\n            )\n        );\n    }\n\n    function _toString(uint256 v) internal pure returns (string memory) {\n        if (v == 0) return \"0\";\n        uint256 digits;\n        uint256 t = v;\n        while (t > 0) { digits++; t /= 10; }\n        bytes memory b = new bytes(digits);\n        while (v > 0) {\n            b[--digits] = bytes1(uint8(48 + (v % 10)));\n            v /= 10;\n        }\n        return string(b);\n    }\n\n    /// @dev Standard base64 encoding (OpenZeppelin-style assembly implementation).\n    function _b64(bytes memory data) internal pure returns (string memory) {\n        if (data.length == 0) return \"\";\n        string memory table = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\";\n        uint256 encodedLen = 4 * ((data.length + 2) / 3);\n        string memory result = new string(encodedLen + 32);\n        assembly {\n            let tablePtr := add(table, 1)\n            let resultPtr := add(result, 32)\n            for {\n                let dataPtr := data\n                let endPtr := add(dataPtr, mload(data))\n            } lt(dataPtr, endPtr) {} {\n                dataPtr := add(dataPtr, 3)\n                let input := mload(dataPtr)\n                mstore8(resultPtr, mload(add(tablePtr, and(shr(18, input), 0x3F))))\n                resultPtr := add(resultPtr, 1)\n                mstore8(resultPtr, mload(add(tablePtr, and(shr(12, input), 0x3F))))\n                resultPtr := add(resultPtr, 1)\n                mstore8(resultPtr, mload(add(tablePtr, and(shr(6, input), 0x3F))))\n                resultPtr := add(resultPtr, 1)\n                mstore8(resultPtr, mload(add(tablePtr, and(input, 0x3F))))\n                resultPtr := add(resultPtr, 1)\n            }\n            switch mod(mload(data), 3)\n            case 1 {\n                mstore8(sub(resultPtr, 1), 0x3d)\n                mstore8(sub(resultPtr, 2), 0x3d)\n            }\n            case 2 {\n                mstore8(sub(resultPtr, 1), 0x3d)\n            }\n            mstore(result, encodedLen)\n        }\n        return result;\n    }\n}\n\ninterface IERC721Receiver {\n    function onERC721Received(address operator, address from, uint256 tokenId, bytes calldata data)\n        external\n        returns (bytes4);\n}\n"}},"abi":[{"type":"constructor","inputs":[],"stateMutability":"nonpayable"},{"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":"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":"EXTERNAL_URL","type":"function","inputs":[],"outputs":[{"name":"","type":"string","internalType":"string"}],"stateMutability":"view"},{"name":"approve","type":"function","inputs":[{"name":"approved","type":"address","internalType":"address"},{"name":"id","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"name":"balanceOf","type":"function","inputs":[{"name":"","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"getApproved","type":"function","inputs":[{"name":"","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"name":"isApprovedForAll","type":"function","inputs":[{"name":"","type":"address","internalType":"address"},{"name":"","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"name":"mintFreeTo","type":"function","inputs":[{"name":"to","type":"address","internalType":"address"}],"outputs":[{"name":"id","type":"uint256","internalType":"uint256"}],"stateMutability":"nonpayable"},{"name":"mintTo","type":"function","inputs":[{"name":"to","type":"address","internalType":"address"},{"name":"paidCumulative","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"id","type":"uint256","internalType":"uint256"}],"stateMutability":"nonpayable"},{"name":"minter","type":"function","inputs":[],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"name":"name","type":"function","inputs":[],"outputs":[{"name":"","type":"string","internalType":"string"}],"stateMutability":"view"},{"name":"nextId","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"owner","type":"function","inputs":[],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"name":"ownerOf","type":"function","inputs":[{"name":"id","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"name":"safeTransferFrom","type":"function","inputs":[{"name":"from","type":"address","internalType":"address"},{"name":"to","type":"address","internalType":"address"},{"name":"id","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":"id","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":"setMinter","type":"function","inputs":[{"name":"minter_","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":"tierFor","type":"function","inputs":[{"name":"paidCumulative","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"pure"},{"name":"tierOf","type":"function","inputs":[{"name":"","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"tokenURI","type":"function","inputs":[{"name":"id","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"string","internalType":"string"}],"stateMutability":"view"},{"name":"transferFrom","type":"function","inputs":[{"name":"from","type":"address","internalType":"address"},{"name":"to","type":"address","internalType":"address"},{"name":"id","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"}],"matchId":"58503397","creationMatch":"exact_match","runtimeMatch":"exact_match","verifiedAt":"2026-11-05T13:41:40Z","match":"exact_match","chainId":"56","address":"0xD2001b3EF8Fb923aF515628E717f6AC1BC4a36e1"}