{"sources":{"Riftera.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.26;\n\n/// @title Riftera — Rifters (BNB Chain)\n/// @notice 1,111 fantasy hero NFTs in two parallel lanes, both gated by the\n///         Binance Agent ID (.ai) NFT registry:\n///         - FREE lane: IDs 1..444, 0 BNB, max 3 per wallet, Common only.\n///         - PAID lane: IDs 1001..1667, exactly 0.001 BNB each, max 5 per wallet,\n///           the only lane that can reveal Rare / Legendary Rifters.\n///         Rarity lives in the pre-generated metadata (paid IDs are pre-shuffled:\n///         467 Common / 167 Rare / 33 Legendary), revealed at mint.\n///         Metadata layout under baseURI: free/<id>.json and paid/<id>.json.\ncontract Riftera {\n    string public constant name = \"Riftera Rifters\";\n    string public constant symbol = \"RIFT\";\n    uint256 public constant MAX_SUPPLY = 1111;\n    uint256 public constant FREE_SUPPLY = 444;\n    uint256 public constant PAID_SUPPLY = 667;\n    uint256 public constant PAID_ID_BASE = 1000;\n    uint256 public constant PAID_PRICE = 0.001 ether;\n    uint256 public constant MAX_FREE_PER_WALLET = 3;\n    uint256 public constant MAX_PAID_PER_WALLET = 5;\n\n    /// Binance Agent ID (.ai) registry — constructor arg.\n    /// Mainnet: 0x60B9262456dE011F7d15a54CdD8c48bAaa8B022F\n    IAgentIdRegistry public immutable agentId;\n\n    address public owner;\n    string public baseURI;\n    bool public mintOpen;\n    uint256 public freeMinted;\n    uint256 public paidMinted;\n\n    mapping(address => uint256) public freeCountOf;\n    mapping(address => uint256) public paidCountOf;\n    mapping(uint256 => address) private _owners;\n    mapping(address => uint256) private _balances;\n    mapping(uint256 => address) private _tokenApprovals;\n    mapping(address => mapping(address => bool)) private _operatorApprovals;\n\n    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);\n    event Approval(address indexed tokenOwner, address indexed approved, uint256 indexed tokenId);\n    event ApprovalForAll(address indexed tokenOwner, address indexed operator, bool approved);\n    event MintOpenChanged(bool open);\n    event BaseURIChanged(string newBaseURI);\n    event FreeMint(address indexed minter, uint256 indexed tokenId);\n    event PaidMint(address indexed minter, uint256 indexed tokenId);\n\n    modifier onlyOwner() {\n        require(msg.sender == owner, \"Not owner\");\n        _;\n    }\n\n    constructor(address agentId_, string memory baseURI_) {\n        require(agentId_ != address(0), \"Zero registry\");\n        agentId = IAgentIdRegistry(agentId_);\n        owner = msg.sender;\n        baseURI = baseURI_;\n    }\n\n    // ---------- ERC-165 ----------\n    function supportsInterface(bytes4 interfaceId) public pure returns (bool) {\n        return interfaceId == 0x01ffc9a7 // ERC165\n            || interfaceId == 0x80ac58cd // ERC721\n            || interfaceId == 0x5b5e139f; // ERC721Metadata\n    }\n\n    // ---------- Views ----------\n    function totalMinted() public view returns (uint256) {\n        return freeMinted + paidMinted;\n    }\n\n    function balanceOf(address account) public view returns (uint256) {\n        require(account != address(0), \"Zero address\");\n        return _balances[account];\n    }\n\n    function ownerOf(uint256 tokenId) public view returns (address) {\n        address a = _owners[tokenId];\n        require(a != address(0), \"Nonexistent token\");\n        return a;\n    }\n\n    function isPaidId(uint256 tokenId) public pure returns (bool) {\n        return tokenId > PAID_ID_BASE;\n    }\n\n    function tokenURI(uint256 tokenId) public view returns (string memory) {\n        require(_owners[tokenId] != address(0), \"Nonexistent token\");\n        string memory lane = isPaidId(tokenId) ? \"paid/\" : \"free/\";\n        return string(abi.encodePacked(baseURI, lane, _toString(tokenId), \".json\"));\n    }\n\n    function getApproved(uint256 tokenId) public view returns (address) {\n        require(_owners[tokenId] != address(0), \"Nonexistent token\");\n        return _tokenApprovals[tokenId];\n    }\n\n    function isApprovedForAll(address account, address operator) public view returns (bool) {\n        return _operatorApprovals[account][operator];\n    }\n\n    function hasAgentId(address account) public view returns (bool) {\n        return agentId.balanceOf(account) > 0;\n    }\n\n    // ---------- Mint ----------\n    function mintFree() external {\n        require(mintOpen, \"Mint closed\");\n        require(hasAgentId(msg.sender), \"Needs Binance Agent ID\");\n        require(freeMinted < FREE_SUPPLY, \"Free lane sold out\");\n        require(freeCountOf[msg.sender] < MAX_FREE_PER_WALLET, \"Free limit 3 per wallet\");\n        freeMinted++;\n        freeCountOf[msg.sender]++;\n        uint256 tokenId = freeMinted; // 1..444\n        _mint(msg.sender, tokenId);\n        emit FreeMint(msg.sender, tokenId);\n    }\n\n    function mintPaid() external payable {\n        require(mintOpen, \"Mint closed\");\n        require(hasAgentId(msg.sender), \"Needs Binance Agent ID\");\n        require(msg.value == PAID_PRICE, \"Pay exact 0.001 BNB\");\n        require(paidMinted < PAID_SUPPLY, \"Paid lane sold out\");\n        require(paidCountOf[msg.sender] < MAX_PAID_PER_WALLET, \"Paid limit 5 per wallet\");\n        paidMinted++;\n        paidCountOf[msg.sender]++;\n        uint256 tokenId = PAID_ID_BASE + paidMinted; // 1001..1667\n        _mint(msg.sender, tokenId);\n        emit PaidMint(msg.sender, tokenId);\n    }\n\n    function _mint(address to, uint256 tokenId) internal {\n        _owners[tokenId] = to;\n        _balances[to]++;\n        emit Transfer(address(0), to, tokenId);\n    }\n\n    // ---------- Transfers ----------\n    function approve(address approved, uint256 tokenId) external {\n        address tokenOwner = ownerOf(tokenId);\n        require(msg.sender == tokenOwner || _operatorApprovals[tokenOwner][msg.sender], \"Not authorized\");\n        _tokenApprovals[tokenId] = approved;\n        emit Approval(tokenOwner, approved, 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 transferFrom(address from, address to, uint256 tokenId) public {\n        require(_isApprovedOrOwner(msg.sender, tokenId), \"Not authorized\");\n        _transfer(from, to, tokenId);\n    }\n\n    function safeTransferFrom(address from, address to, uint256 tokenId) external {\n        transferFrom(from, to, tokenId);\n        require(_checkOnERC721Received(from, to, tokenId, \"\"), \"Receiver rejected\");\n    }\n\n    function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) external {\n        transferFrom(from, to, tokenId);\n        require(_checkOnERC721Received(from, to, tokenId, data), \"Receiver rejected\");\n    }\n\n    // ---------- Owner ----------\n    function setMintOpen(bool open_) external onlyOwner {\n        mintOpen = open_;\n        emit MintOpenChanged(open_);\n    }\n\n    function setBaseURI(string memory newBaseURI) external onlyOwner {\n        baseURI = newBaseURI;\n        emit BaseURIChanged(newBaseURI);\n    }\n\n    function withdraw() external onlyOwner {\n        uint256 amount = address(this).balance;\n        require(amount > 0, \"Nothing to withdraw\");\n        (bool ok, ) = payable(owner).call{value: amount}(\"\");\n        require(ok, \"Withdraw failed\");\n    }\n\n    function transferOwnership(address newOwner) external onlyOwner {\n        require(newOwner != address(0), \"Zero address\");\n        owner = newOwner;\n    }\n\n    // ---------- Internals ----------\n    function _isApprovedOrOwner(address spender, uint256 tokenId) internal view returns (bool) {\n        address tokenOwner = ownerOf(tokenId);\n        return spender == tokenOwner\n            || _tokenApprovals[tokenId] == spender\n            || _operatorApprovals[tokenOwner][spender];\n    }\n\n    function _transfer(address from, address to, uint256 tokenId) internal {\n        require(ownerOf(tokenId) == from, \"From not owner\");\n        require(to != address(0), \"Zero address\");\n        delete _tokenApprovals[tokenId];\n        _balances[from]--;\n        _balances[to]++;\n        _owners[tokenId] = to;\n        emit Transfer(from, to, tokenId);\n    }\n\n    function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory data) private returns (bool) {\n        if (to.code.length == 0) return true;\n        try IERC721Receiver(to).onERC721Received(msg.sender, from, tokenId, data) returns (bytes4 retval) {\n            return retval == IERC721Receiver.onERC721Received.selector;\n        } catch {\n            return false;\n        }\n    }\n\n    function _toString(uint256 value) internal 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\ninterface IAgentIdRegistry {\n    function balanceOf(address account) external view returns (uint256);\n}\n\ninterface IERC721Receiver {\n    function onERC721Received(address operator, address from, uint256 tokenId, bytes calldata data) external returns (bytes4);\n}\n"}},"abi":[{"type":"constructor","inputs":[{"name":"agentId_","type":"address","internalType":"address"},{"name":"baseURI_","type":"string","internalType":"string"}],"stateMutability":"nonpayable"},{"name":"Approval","type":"event","inputs":[{"name":"tokenOwner","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":"tokenOwner","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":"BaseURIChanged","type":"event","inputs":[{"name":"newBaseURI","type":"string","indexed":false,"internalType":"string"}],"anonymous":false},{"name":"FreeMint","type":"event","inputs":[{"name":"minter","type":"address","indexed":true,"internalType":"address"},{"name":"tokenId","type":"uint256","indexed":true,"internalType":"uint256"}],"anonymous":false},{"name":"MintOpenChanged","type":"event","inputs":[{"name":"open","type":"bool","indexed":false,"internalType":"bool"}],"anonymous":false},{"name":"PaidMint","type":"event","inputs":[{"name":"minter","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":"FREE_SUPPLY","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"MAX_FREE_PER_WALLET","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"MAX_PAID_PER_WALLET","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":"PAID_ID_BASE","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"PAID_PRICE","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"PAID_SUPPLY","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"agentId","type":"function","inputs":[],"outputs":[{"name":"","type":"address","internalType":"contract IAgentIdRegistry"}],"stateMutability":"view"},{"name":"approve","type":"function","inputs":[{"name":"approved","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":"baseURI","type":"function","inputs":[],"outputs":[{"name":"","type":"string","internalType":"string"}],"stateMutability":"view"},{"name":"freeCountOf","type":"function","inputs":[{"name":"","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"freeMinted","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"getApproved","type":"function","inputs":[{"name":"tokenId","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"name":"hasAgentId","type":"function","inputs":[{"name":"account","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"name":"isApprovedForAll","type":"function","inputs":[{"name":"account","type":"address","internalType":"address"},{"name":"operator","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"name":"isPaidId","type":"function","inputs":[{"name":"tokenId","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"pure"},{"name":"mintFree","type":"function","inputs":[],"outputs":[],"stateMutability":"nonpayable"},{"name":"mintOpen","type":"function","inputs":[],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"name":"mintPaid","type":"function","inputs":[],"outputs":[],"stateMutability":"payable"},{"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":"paidCountOf","type":"function","inputs":[{"name":"","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"paidMinted","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"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":"setBaseURI","type":"function","inputs":[{"name":"newBaseURI","type":"string","internalType":"string"}],"outputs":[],"stateMutability":"nonpayable"},{"name":"setMintOpen","type":"function","inputs":[{"name":"open_","type":"bool","internalType":"bool"}],"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":"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":"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":"transferOwnership","type":"function","inputs":[{"name":"newOwner","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"name":"withdraw","type":"function","inputs":[],"outputs":[],"stateMutability":"nonpayable"}],"matchId":"59196430","creationMatch":"exact_match","runtimeMatch":"exact_match","verifiedAt":"2026-11-13T04:42:36Z","match":"exact_match","chainId":"56","address":"0x36fE923C449F6163a601058626dEf6c83a8f23AE"}