{"sources":{"PeaFunPods.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.20;\n\n/// @title Pea Fun — Pods (POD)\n/// @notice Pea Fun is a 30-day pea-garden game on BNB Smart Chain for\n///         Binance Agent ID holders. Every rule of the game is\n///         readable in this contract:\n///         - There are exactly 10,000 pods (ERC-721, numbered 1 to\n///           10,000, freely transferable): 5,000 are FREE and 5,000\n///           cost a flat 0.001 BNB each, in two separate pools.\n///         - Minting starts when the dev wallet calls `openGate()` —\n///           exactly once, never reversible. FREE pods can be claimed\n///           only during the first 24 hours after that moment; PAID\n///           pods stay on sale until the 5,000-pod paid pool is sold\n///           out, with no time limit.\n///         - Free pods: 1 per wallet, and only for wallets holding a\n///           Binance Agent ID. Paid pods: up to 9 more per wallet. A\n///           wallet can mint at most 10 pods in total (the free pod\n///           counts toward the cap). Minting follows the wallet, not\n///           the token balance, so it cannot be rented.\n///         - Every PAID pod mints an instant bonus of exactly 1,000\n///           PEA to the buyer, inside the purchase transaction\n///           itself, from a published 5,000,000 PEA bonus reserve\n///           (5,000 paid pods x 1,000), tracked by the token's\n///           `bonusMinted` counter. Free pods receive no such bonus.\n///         - REFERRALS: a free claim may name a referrer (a wallet\n///           that already holds at least 1 pod and is not the\n///           claimer). The referrer instantly receives +250 PEA from\n///           the published 5,000,000 PEA referral reserve, and from\n///           then on receives +5% of every harvest the referred\n///           wallet ever makes — minted ON TOP from the same\n///           reserve, so the harvester always keeps 100% of their\n///           own harvest. One referrer per wallet, set once at the\n///           free claim, never changeable. Referral rewards stop\n///           when the reserve is empty; harvesting never stops.\n///         - STREAKS: harvesting on back-to-back days (UTC) grows a\n///           wallet's streak. Reaching 7, 14 and 30 days pays\n///           +250, +500 and +1,500 PEA from the published 7,500,000\n///           PEA streak reserve. Missing a day restarts the streak.\n///         - Sale proceeds are forwarded to the dev wallet (the\n///           project owner's Agentic wallet) at the moment of\n///           purchase; overpayments are refunded in the same\n///           transaction.\n///         - Every pod produces 500 PEA per day into its buffer,\n///           accruing per second from the moment it is minted. The\n///           buffer pauses once 500 PEA are waiting (1 full day)\n///           until the pod is picked, and production stops forever\n///           30 days after THAT POD was minted: every pod has its\n///           own full 30-day run, whenever it was claimed or bought.\n///           PEA still waiting in a buffer stays pickable after its\n///           run, and travels with the pod when the pod changes\n///           owner.\n///         - Picking (harvesting) costs a flat fee of exactly\n///           0.0001 BNB per pod, forwarded to the dev wallet. PEA\n///           exists only once picked or paid out as one of the\n///           published bonuses above: there is no pre-mine and the\n///           dev wallet cannot mint PEA or pods for itself outside\n///           the same public rules as everyone else.\n///         - The dev wallet's only powers are calling `openGate()`\n///           once and setting the metadata base URI before the gate\n///           opens. It cannot pause anything, change any number, or\n///           move anyone's pod or PEA.\n///         - No price, return, pool, or listing is promised by this\n///           contract.\n\ninterface IAgentIdRegistry {\n    function balanceOf(address owner) external view returns (uint256);\n}\n\ninterface IPeaToken {\n    function mintProduction(address to, uint256 amount) external;\n    function mintStreak(address to, uint256 amount) external;\n    function mintReferral(address to, uint256 amount) external;\n    function mintBonus(address to, uint256 amount) external;\n}\n\ninterface IERC721Receiver {\n    function onERC721Received(\n        address operator,\n        address from,\n        uint256 tokenId,\n        bytes calldata data\n    ) external returns (bytes4);\n}\n\ncontract PeaFunPods {\n    // --- ERC-721 metadata ---\n    string public constant name = \"Pea Fun Pod\";\n    string public constant symbol = \"POD\";\n\n    // --- Gate parameters ---\n    uint256 public constant FREE_PODS_TOTAL = 5_000;\n    uint256 public constant PAID_PODS_TOTAL = 5_000;\n    uint256 public constant TOTAL_PODS = FREE_PODS_TOTAL + PAID_PODS_TOTAL;\n    uint256 public constant MAX_PODS_PER_WALLET = 10;\n    uint256 public constant POD_PRICE = 0.001 ether;\n    uint256 public constant FREE_WINDOW_DURATION = 24 hours;\n    uint256 public constant SEASON_DURATION = 30 days; // per pod, from its mint\n\n    // --- Production parameters ---\n    uint256 public constant RATE_PER_DAY = 500 * 10 ** 18; // per pod\n    uint256 public constant BUFFER_CAP = 500 * 10 ** 18; // per pod\n    uint256 public constant PICK_FEE = 0.0001 ether; // per pod\n\n    // --- Paid-pod instant bonus ---\n    uint256 public constant BONUS_PER_POD = 1_000 * 10 ** 18;\n\n    // --- Referral parameters ---\n    uint256 public constant REFERRAL_INSTANT = 250 * 10 ** 18;\n    uint256 public constant REFERRAL_HARVEST_PERCENT = 5; // % of every harvest\n\n    // --- Streak parameters ---\n    uint256 public constant STREAK_BONUS_7 = 250 * 10 ** 18;\n    uint256 public constant STREAK_BONUS_14 = 500 * 10 ** 18;\n    uint256 public constant STREAK_BONUS_30 = 1_500 * 10 ** 18;\n\n    IAgentIdRegistry public immutable registry;\n    IPeaToken public immutable peaToken;\n    address public immutable devWallet;\n    string private _baseURI;\n\n    /// @notice When the gate opened. Zero until the dev wallet opens\n    ///         it; can be set exactly once.\n    uint256 public gateStart;\n    uint256 public totalPodsMinted;\n    uint256 public freePodsClaimed;\n    uint256 public paidPodsSold;\n    mapping(address => uint256) public podsMintedBy;\n    mapping(address => bool) public freeClaimedBy;\n\n    // --- Referral state ---\n    /// @notice The wallet that referred `who`, set once at their\n    ///         free claim. Zero if they were never referred.\n    mapping(address => address) public referredBy;\n\n    // --- Streak state (per wallet) ---\n    mapping(address => uint256) public lastHarvestDay; // UTC day index\n    mapping(address => uint256) private _streakCount;\n\n    // --- Production state (per pod) ---\n    /// @notice Timestamp up to which a pod's production has been\n    ///         settled by a pick. Production accrues from here to\n    ///         the earlier of now and the pod's own season end,\n    ///         capped at BUFFER_CAP.\n    mapping(uint256 => uint256) public lastSettled;\n    /// @notice When this pod was minted. Its personal 30-day run\n    ///         ends at mintedAt + SEASON_DURATION.\n    mapping(uint256 => uint256) public mintedAt;\n\n    // --- ERC-721 state ---\n    mapping(uint256 => address) private _owners;\n    mapping(address => uint256) public balanceOf;\n    mapping(uint256 => address) public getApproved;\n    mapping(address => mapping(address => bool)) public isApprovedForAll;\n    mapping(address => uint256[]) private _podsOf;\n    mapping(uint256 => uint256) private _podIndex; // tokenId -> index in owner's list\n\n    event Transfer(\n        address indexed from,\n        address indexed to,\n        uint256 indexed tokenId\n    );\n    event Approval(\n        address indexed owner,\n        address indexed approved,\n        uint256 indexed tokenId\n    );\n    event ApprovalForAll(\n        address indexed owner,\n        address indexed operator,\n        bool approved\n    );\n    event GateOpened(uint256 indexed startTime);\n    event FreePodClaimed(address indexed claimer, uint256 indexed tokenId);\n    event ReferralSet(address indexed claimer, address indexed referrer);\n    event ReferralInstantPaid(\n        address indexed referrer,\n        address indexed claimer,\n        uint256 amount\n    );\n    event PodsBought(\n        address indexed buyer,\n        uint256 count,\n        uint256 firstTokenId,\n        uint256 costWei,\n        uint256 bonusPeaWei\n    );\n    event Harvested(address indexed owner, uint256 pods, uint256 amount);\n    event ReferralSharePaid(\n        address indexed referrer,\n        address indexed harvester,\n        uint256 amount\n    );\n    event StreakBonusPaid(\n        address indexed owner,\n        uint256 streakDays,\n        uint256 amount\n    );\n\n    /// @param registry_ The SPACE ID Agent ID registry whose\n    ///        balanceOf decides who may mint. Locked forever.\n    /// @param peaToken_ The PEA token this contract mints on harvest\n    ///        and as the published bonuses. Locked forever.\n    /// @param devWallet_ The project owner's Agentic wallet: receives\n    ///        sale proceeds and pick fees; its only powers are\n    ///        `openGate()` (once) and `setBaseURI` (pre-launch).\n    /// @param baseURI_ Metadata base URI; tokenURI(id) = base + id + \".json\".\n    constructor(\n        address registry_,\n        address peaToken_,\n        address devWallet_,\n        string memory baseURI_\n    ) {\n        require(registry_ != address(0), \"Zero registry\");\n        require(peaToken_ != address(0), \"Zero token\");\n        require(devWallet_ != address(0), \"Zero dev wallet\");\n        registry = IAgentIdRegistry(registry_);\n        peaToken = IPeaToken(peaToken_);\n        devWallet = devWallet_;\n        _baseURI = baseURI_;\n    }\n\n    // --- Views ---\n    function freePodsRemaining() public view returns (uint256) {\n        return FREE_PODS_TOTAL - freePodsClaimed;\n    }\n\n    function paidPodsRemaining() public view returns (uint256) {\n        return PAID_PODS_TOTAL - paidPodsSold;\n    }\n\n    /// @notice When free claims close (or closed). Zero until the\n    ///         gate opens.\n    function freeWindowClosesAt() public view returns (uint256) {\n        return gateStart == 0 ? 0 : gateStart + FREE_WINDOW_DURATION;\n    }\n\n    /// @notice True while free pods can still be claimed: the first\n    ///         24 hours after the gate opened.\n    function freeWindowOpen() public view returns (bool) {\n        return\n            gateStart != 0 &&\n            block.timestamp < gateStart + FREE_WINDOW_DURATION;\n    }\n\n    /// @notice True while paid pods can still be bought: from the\n    ///         moment the gate opens until the paid pool sells out.\n    ///         There is no time limit on paid sales.\n    function paidSalesOpen() public view returns (bool) {\n        return gateStart != 0 && paidPodsRemaining() > 0;\n    }\n\n    /// @notice True while any minting lane (free or paid) is open.\n    function windowOpen() public view returns (bool) {\n        return freeWindowOpen() || paidSalesOpen();\n    }\n\n    /// @notice When this pod's own 30-day run ends and its\n    ///         production stops forever. Zero for unminted pods.\n    function podSeasonEndsAt(uint256 tokenId) public view returns (uint256) {\n        return mintedAt[tokenId] == 0\n            ? 0\n            : mintedAt[tokenId] + SEASON_DURATION;\n    }\n\n    /// @notice IDs of the pods `who` currently owns.\n    function podsOf(address who) public view returns (uint256[] memory) {\n        return _podsOf[who];\n    }\n\n    /// @notice The current harvest streak of a wallet, in days.\n    function currentStreak(address who) public view returns (uint256) {\n        return _streakCount[who];\n    }\n\n    /// @notice How much PEA is waiting in a pod's buffer right now:\n    ///         production per second since the last pick, paused at\n    ///         the 500 PEA cap, and frozen at the season end.\n    function pendingOf(uint256 tokenId) public view returns (uint256) {\n        if (_owners[tokenId] == address(0)) return 0;\n        return _pending(tokenId);\n    }\n\n    function _pending(uint256 tokenId) internal view returns (uint256) {\n        uint256 start = lastSettled[tokenId];\n        uint256 end = block.timestamp;\n        uint256 seasonEnd = mintedAt[tokenId] + SEASON_DURATION;\n        if (end > seasonEnd) end = seasonEnd;\n        if (end <= start) return 0;\n        uint256 raw = ((end - start) * RATE_PER_DAY) / 1 days;\n        return raw > BUFFER_CAP ? BUFFER_CAP : raw;\n    }\n\n    function ownerOf(uint256 tokenId) public view returns (address) {\n        address owner = _owners[tokenId];\n        require(owner != address(0), \"Nonexistent token\");\n        return owner;\n    }\n\n    function tokenOfOwnerByIndex(address owner, uint256 index)\n        public\n        view\n        returns (uint256)\n    {\n        require(index < _podsOf[owner].length, \"Index out of bounds\");\n        return _podsOf[owner][index];\n    }\n\n    function tokenURI(uint256 tokenId) public view returns (string memory) {\n        require(_owners[tokenId] != address(0), \"Nonexistent token\");\n        return string(abi.encodePacked(_baseURI, _toString(tokenId), \".json\"));\n    }\n\n    function supportsInterface(bytes4 interfaceId)\n        public\n        pure\n        returns (bool)\n    {\n        return\n            interfaceId == 0x80ac58cd || // ERC721\n            interfaceId == 0x5b5e139f || // ERC721Metadata\n            interfaceId == 0x01ffc9a7; // ERC165\n    }\n\n    // --- Dev controls (complete list — there are no others) ---\n    /// @notice Open the gate, exactly once, at this block's\n    ///         timestamp. Irreversible. Free claims run for 24 hours\n    ///         from this moment; paid sales run until sold out.\n    function openGate() external {\n        require(msg.sender == devWallet, \"Only dev wallet\");\n        require(gateStart == 0, \"Already opened\");\n        gateStart = block.timestamp;\n        emit GateOpened(block.timestamp);\n    }\n\n    /// @notice Set the metadata base URI. Only the dev wallet, and\n    ///         only before the gate opens; locked forever after.\n    function setBaseURI(string calldata baseURI_) external {\n        require(msg.sender == devWallet, \"Only dev wallet\");\n        require(gateStart == 0, \"Locked after launch\");\n        _baseURI = baseURI_;\n    }\n\n    // --- Minting ---\n    function _requireAgentId(address who) internal view {\n        require(registry.balanceOf(who) > 0, \"Binance Agent ID required\");\n    }\n\n    function _requireFreeWindow() internal view {\n        require(freeWindowOpen(), \"Free window is not open\");\n    }\n\n    function _requireOpened() internal view {\n        require(gateStart != 0, \"Gate is not open\");\n    }\n\n    function _mintPod(address to) internal returns (uint256 tokenId) {\n        tokenId = totalPodsMinted + 1;\n        totalPodsMinted = tokenId;\n        podsMintedBy[to] += 1;\n        mintedAt[tokenId] = block.timestamp;\n        lastSettled[tokenId] = block.timestamp;\n        _owners[tokenId] = to;\n        balanceOf[to] += 1;\n        _podIndex[tokenId] = _podsOf[to].length;\n        _podsOf[to].push(tokenId);\n        emit Transfer(address(0), to, tokenId);\n    }\n\n    /// @notice Claim this wallet's one free pod. Requires a Binance\n    ///         Agent ID, the 24-hour free window, and remaining free\n    ///         quota. An optional referrer may be named: a wallet\n    ///         that already holds at least 1 pod and is not the\n    ///         claimer. A valid referrer instantly receives +250 PEA\n    ///         from the referral reserve and +5% of every future\n    ///         harvest of this wallet (minted on top). Free pods\n    ///         receive no paid-pod bonus.\n    function claimFree(address referrer) external {\n        _requireFreeWindow();\n        _requireAgentId(msg.sender);\n        require(!freeClaimedBy[msg.sender], \"Free pod already claimed\");\n        require(freePodsClaimed < FREE_PODS_TOTAL, \"Free pods gone\");\n        require(\n            podsMintedBy[msg.sender] < MAX_PODS_PER_WALLET,\n            \"Per-wallet cap\"\n        );\n        freeClaimedBy[msg.sender] = true;\n        freePodsClaimed += 1;\n        uint256 tokenId = _mintPod(msg.sender);\n        emit FreePodClaimed(msg.sender, tokenId);\n        if (\n            referrer != address(0) &&\n            referrer != msg.sender &&\n            balanceOf[referrer] > 0 &&\n            referredBy[msg.sender] == address(0)\n        ) {\n            referredBy[msg.sender] = referrer;\n            emit ReferralSet(msg.sender, referrer);\n            try peaToken.mintReferral(referrer, REFERRAL_INSTANT) {\n                emit ReferralInstantPaid(\n                    referrer,\n                    msg.sender,\n                    REFERRAL_INSTANT\n                );\n            } catch {\n                // Referral reserve exhausted: the claim still stands.\n            }\n        }\n    }\n\n    /// @notice Buy `count` pods at a flat 0.001 BNB each. Pods arrive\n    ///         immediately, and so does the bonus: exactly 1,000 PEA\n    ///         per pod, minted to the buyer inside this same\n    ///         transaction, from the published 5,000,000 PEA bonus\n    ///         reserve. Proceeds are forwarded to the dev wallet and\n    ///         any overpayment refunded in the same transaction.\n    ///         Requires a Binance Agent ID and that the gate has\n    ///         opened; paid sales have no time limit and end only\n    ///         when the paid pool sells out.\n    function buyPods(uint256 count) external payable {\n        require(count > 0, \"Zero pods\");\n        _requireOpened();\n        _requireAgentId(msg.sender);\n        require(paidPodsSold + count <= PAID_PODS_TOTAL, \"Paid pods gone\");\n        require(\n            podsMintedBy[msg.sender] + count <= MAX_PODS_PER_WALLET,\n            \"Per-wallet cap\"\n        );\n        uint256 cost = count * POD_PRICE;\n        require(msg.value >= cost, \"Insufficient payment\");\n        uint256 bonus = count * BONUS_PER_POD;\n        paidPodsSold += count;\n        uint256 firstId = totalPodsMinted + 1;\n        for (uint256 i = 0; i < count; i++) {\n            _mintPod(msg.sender);\n        }\n        peaToken.mintBonus(msg.sender, bonus);\n        emit PodsBought(msg.sender, count, firstId, cost, bonus);\n        (bool sent, ) = devWallet.call{value: cost}(\"\");\n        require(sent, \"Proceeds transfer failed\");\n        uint256 excess = msg.value - cost;\n        if (excess > 0) {\n            (bool refunded, ) = msg.sender.call{value: excess}(\"\");\n            require(refunded, \"Refund failed\");\n        }\n    }\n\n    // --- Harvesting ---\n    /// @notice Pick (harvest) the listed pods in one transaction:\n    ///         pay exactly 0.0001 BNB per listed pod and receive all\n    ///         PEA waiting in their buffers. The caller must own\n    ///         every listed pod. Picking updates the caller's\n    ///         harvest streak, pays the caller's referrer (if any)\n    ///         +5% of the picked amount minted on top, and restarts\n    ///         production from this moment (still inside each pod's\n    ///         own 30-day run).\n    function harvest(uint256[] calldata tokenIds) external payable {\n        require(tokenIds.length > 0, \"No pods\");\n        require(\n            msg.value == PICK_FEE * tokenIds.length,\n            \"Exact pick fee required\"\n        );\n        uint256 total = 0;\n        for (uint256 i = 0; i < tokenIds.length; i++) {\n            require(_owners[tokenIds[i]] == msg.sender, \"Not pod owner\");\n            uint256 amount = _pending(tokenIds[i]);\n            if (amount > 0) {\n                lastSettled[tokenIds[i]] = block.timestamp;\n                total += amount;\n            }\n        }\n        require(total > 0, \"Nothing to pick\");\n        peaToken.mintProduction(msg.sender, total);\n        emit Harvested(msg.sender, tokenIds.length, total);\n        address ref = referredBy[msg.sender];\n        if (ref != address(0)) {\n            uint256 share = (total * REFERRAL_HARVEST_PERCENT) / 100;\n            if (share > 0) {\n                try peaToken.mintReferral(ref, share) {\n                    emit ReferralSharePaid(ref, msg.sender, share);\n                } catch {\n                    // Referral reserve exhausted: the harvest stands.\n                }\n            }\n        }\n        _updateStreak(msg.sender);\n        (bool sent, ) = devWallet.call{value: msg.value}(\"\");\n        require(sent, \"Fee transfer failed\");\n    }\n\n    /// @notice Advance a wallet's harvest streak after a harvest:\n    ///         a harvest on the next UTC day grows the streak, a\n    ///         harvest after a missed day restarts it at 1, and\n    ///         extra harvests on the same day change nothing.\n    ///         Milestones at 7 / 14 / 30 days pay their bonuses\n    ///         from the streak reserve, once per streak run.\n    function _updateStreak(address who) internal {\n        uint256 today = block.timestamp / 1 days;\n        if (lastHarvestDay[who] == today) return;\n        if (lastHarvestDay[who] == today - 1) {\n            _streakCount[who] += 1;\n        } else {\n            _streakCount[who] = 1;\n        }\n        lastHarvestDay[who] = today;\n        uint256 s = _streakCount[who];\n        uint256 bonus = 0;\n        if (s == 7) bonus = STREAK_BONUS_7;\n        else if (s == 14) bonus = STREAK_BONUS_14;\n        else if (s == 30) bonus = STREAK_BONUS_30;\n        if (bonus > 0) {\n            try peaToken.mintStreak(who, bonus) {\n                emit StreakBonusPaid(who, s, bonus);\n            } catch {\n                // Streak reserve exhausted: the streak still counts.\n            }\n        }\n    }\n\n    // --- ERC-721 functions ---\n    function approve(address to, uint256 tokenId) external {\n        address owner = ownerOf(tokenId);\n        require(\n            msg.sender == owner || isApprovedForAll[owner][msg.sender],\n            \"Not owner or operator\"\n        );\n        getApproved[tokenId] = to;\n        emit Approval(owner, to, tokenId);\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(\n        address from,\n        address to,\n        uint256 tokenId\n    ) external {\n        _transferFrom(from, to, tokenId, msg.sender);\n    }\n\n    function safeTransferFrom(\n        address from,\n        address to,\n        uint256 tokenId\n    ) external {\n        _transferFrom(from, to, tokenId, msg.sender);\n        _checkReceiver(from, to, tokenId, \"\");\n    }\n\n    function safeTransferFrom(\n        address from,\n        address to,\n        uint256 tokenId,\n        bytes calldata data\n    ) external {\n        _transferFrom(from, to, tokenId, msg.sender);\n        _checkReceiver(from, to, tokenId, data);\n    }\n\n    function _transferFrom(\n        address from,\n        address to,\n        uint256 tokenId,\n        address caller\n    ) internal {\n        address owner = ownerOf(tokenId);\n        require(owner == from, \"From is not owner\");\n        require(to != address(0), \"Transfer to zero address\");\n        require(\n            caller == owner ||\n                getApproved[tokenId] == caller ||\n                isApprovedForAll[owner][caller],\n            \"Not authorized\"\n        );\n        getApproved[tokenId] = address(0);\n        emit Approval(owner, address(0), tokenId);\n        balanceOf[from] -= 1;\n        balanceOf[to] += 1;\n        _owners[tokenId] = to;\n        // The pod's uncollected buffer (lastSettled) is untouched:\n        // it travels with the pod to its new owner.\n        _removeFromOwnerList(from, tokenId);\n        _podIndex[tokenId] = _podsOf[to].length;\n        _podsOf[to].push(tokenId);\n        emit Transfer(from, to, tokenId);\n    }\n\n    function _removeFromOwnerList(address owner, uint256 tokenId) internal {\n        uint256 index = _podIndex[tokenId];\n        uint256 lastIndex = _podsOf[owner].length - 1;\n        if (index != lastIndex) {\n            uint256 movedId = _podsOf[owner][lastIndex];\n            _podsOf[owner][index] = movedId;\n            _podIndex[movedId] = index;\n        }\n        _podsOf[owner].pop();\n    }\n\n    function _checkReceiver(\n        address from,\n        address to,\n        uint256 tokenId,\n        bytes memory data\n    ) internal {\n        if (to.code.length > 0) {\n            bytes4 retval = IERC721Receiver(to).onERC721Received(\n                msg.sender,\n                from,\n                tokenId,\n                data\n            );\n            require(\n                retval == IERC721Receiver.onERC721Received.selector,\n                \"Receiver rejected\"\n            );\n        }\n    }\n\n    // --- Helpers ---\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) {\n            digits++;\n            temp /= 10;\n        }\n        bytes memory buffer = new bytes(digits);\n        while (value != 0) {\n            digits -= 1;\n            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n            value /= 10;\n        }\n        return string(buffer);\n    }\n}\n"}},"abi":[{"type":"constructor","inputs":[{"name":"registry_","type":"address","internalType":"address"},{"name":"peaToken_","type":"address","internalType":"address"},{"name":"devWallet_","type":"address","internalType":"address"},{"name":"baseURI_","type":"string","internalType":"string"}],"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":"FreePodClaimed","type":"event","inputs":[{"name":"claimer","type":"address","indexed":true,"internalType":"address"},{"name":"tokenId","type":"uint256","indexed":true,"internalType":"uint256"}],"anonymous":false},{"name":"GateOpened","type":"event","inputs":[{"name":"startTime","type":"uint256","indexed":true,"internalType":"uint256"}],"anonymous":false},{"name":"Harvested","type":"event","inputs":[{"name":"owner","type":"address","indexed":true,"internalType":"address"},{"name":"pods","type":"uint256","indexed":false,"internalType":"uint256"},{"name":"amount","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"name":"PodsBought","type":"event","inputs":[{"name":"buyer","type":"address","indexed":true,"internalType":"address"},{"name":"count","type":"uint256","indexed":false,"internalType":"uint256"},{"name":"firstTokenId","type":"uint256","indexed":false,"internalType":"uint256"},{"name":"costWei","type":"uint256","indexed":false,"internalType":"uint256"},{"name":"bonusPeaWei","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"name":"ReferralInstantPaid","type":"event","inputs":[{"name":"referrer","type":"address","indexed":true,"internalType":"address"},{"name":"claimer","type":"address","indexed":true,"internalType":"address"},{"name":"amount","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"name":"ReferralSet","type":"event","inputs":[{"name":"claimer","type":"address","indexed":true,"internalType":"address"},{"name":"referrer","type":"address","indexed":true,"internalType":"address"}],"anonymous":false},{"name":"ReferralSharePaid","type":"event","inputs":[{"name":"referrer","type":"address","indexed":true,"internalType":"address"},{"name":"harvester","type":"address","indexed":true,"internalType":"address"},{"name":"amount","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"name":"StreakBonusPaid","type":"event","inputs":[{"name":"owner","type":"address","indexed":true,"internalType":"address"},{"name":"streakDays","type":"uint256","indexed":false,"internalType":"uint256"},{"name":"amount","type":"uint256","indexed":false,"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":"BONUS_PER_POD","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"BUFFER_CAP","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"FREE_PODS_TOTAL","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"FREE_WINDOW_DURATION","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"MAX_PODS_PER_WALLET","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"PAID_PODS_TOTAL","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"PICK_FEE","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"POD_PRICE","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"RATE_PER_DAY","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"REFERRAL_HARVEST_PERCENT","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"REFERRAL_INSTANT","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"SEASON_DURATION","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"STREAK_BONUS_14","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"STREAK_BONUS_30","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"STREAK_BONUS_7","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"TOTAL_PODS","type":"function","inputs":[],"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":"","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"buyPods","type":"function","inputs":[{"name":"count","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"payable"},{"name":"claimFree","type":"function","inputs":[{"name":"referrer","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"name":"currentStreak","type":"function","inputs":[{"name":"who","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"devWallet","type":"function","inputs":[],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"name":"freeClaimedBy","type":"function","inputs":[{"name":"","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"name":"freePodsClaimed","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"freePodsRemaining","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"freeWindowClosesAt","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"freeWindowOpen","type":"function","inputs":[],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"name":"gateStart","type":"function","inputs":[],"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":"harvest","type":"function","inputs":[{"name":"tokenIds","type":"uint256[]","internalType":"uint256[]"}],"outputs":[],"stateMutability":"payable"},{"name":"isApprovedForAll","type":"function","inputs":[{"name":"","type":"address","internalType":"address"},{"name":"","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"name":"lastHarvestDay","type":"function","inputs":[{"name":"","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"lastSettled","type":"function","inputs":[{"name":"","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"mintedAt","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":"openGate","type":"function","inputs":[],"outputs":[],"stateMutability":"nonpayable"},{"name":"ownerOf","type":"function","inputs":[{"name":"tokenId","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"name":"paidPodsRemaining","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"paidPodsSold","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"paidSalesOpen","type":"function","inputs":[],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"name":"peaToken","type":"function","inputs":[],"outputs":[{"name":"","type":"address","internalType":"contract IPeaToken"}],"stateMutability":"view"},{"name":"pendingOf","type":"function","inputs":[{"name":"tokenId","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"podSeasonEndsAt","type":"function","inputs":[{"name":"tokenId","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"podsMintedBy","type":"function","inputs":[{"name":"","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"podsOf","type":"function","inputs":[{"name":"who","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"uint256[]","internalType":"uint256[]"}],"stateMutability":"view"},{"name":"referredBy","type":"function","inputs":[{"name":"","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"name":"registry","type":"function","inputs":[],"outputs":[{"name":"","type":"address","internalType":"contract IAgentIdRegistry"}],"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":"baseURI_","type":"string","internalType":"string"}],"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":"tokenOfOwnerByIndex","type":"function","inputs":[{"name":"owner","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":"totalPodsMinted","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":"windowOpen","type":"function","inputs":[],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"}],"matchId":"58612608","creationMatch":"exact_match","runtimeMatch":"exact_match","verifiedAt":"2026-11-06T09:52:46Z","match":"exact_match","chainId":"56","address":"0x25F3EFb465685692EF3DdC47Ed040baF216B5D38"}