{"language":"Solidity","sources":{"@openzeppelin/contracts/token/ERC20/IERC20.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/IERC20.sol)\n\npragma solidity >=0.4.16;\n\n/**\n * @dev Interface of the ERC-20 standard as defined in the ERC.\n */\ninterface IERC20 {\n    /**\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\n     * another (`to`).\n     *\n     * Note that `value` may be zero.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /**\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n     * a call to {approve}. `value` is the new allowance.\n     */\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n\n    /**\n     * @dev Returns the value of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the value of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transfer(address to, uint256 value) external returns (bool);\n\n    /**\n     * @dev Returns the remaining number of tokens that `spender` will be\n     * allowed to spend on behalf of `owner` through {transferFrom}. This is\n     * zero by default.\n     *\n     * This value changes when {approve} or {transferFrom} are called.\n     */\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    /**\n     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n     * caller's tokens.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * IMPORTANT: Beware that changing an allowance with this method brings the risk\n     * that someone may use both the old and the new allowance by unfortunate\n     * transaction ordering. One possible solution to mitigate this race\n     * condition is to first reduce the spender's allowance to 0 and set the\n     * desired value afterwards:\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address spender, uint256 value) external returns (bool);\n\n    /**\n     * @dev Moves a `value` amount of tokens from `from` to `to` using the\n     * allowance mechanism. `value` is then deducted from the caller's\n     * allowance.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n"},"@openzeppelin/contracts/utils/ReentrancyGuard.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.5.0) (utils/ReentrancyGuard.sol)\n\npragma solidity ^0.8.20;\n\nimport {StorageSlot} from \"./StorageSlot.sol\";\n\n/**\n * @dev Contract module that helps prevent reentrant calls to a function.\n *\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\n * available, which can be applied to functions to make sure there are no nested\n * (reentrant) calls to them.\n *\n * Note that because there is a single `nonReentrant` guard, functions marked as\n * `nonReentrant` may not call one another. This can be worked around by making\n * those functions `private`, and then adding `external` `nonReentrant` entry\n * points to them.\n *\n * TIP: If EIP-1153 (transient storage) is available on the chain you're deploying at,\n * consider using {ReentrancyGuardTransient} instead.\n *\n * TIP: If you would like to learn more about reentrancy and alternative ways\n * to protect against it, check out our blog post\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\n *\n * IMPORTANT: Deprecated. This storage-based reentrancy guard will be removed and replaced\n * by the {ReentrancyGuardTransient} variant in v6.0.\n *\n * @custom:stateless\n */\nabstract contract ReentrancyGuard {\n    using StorageSlot for bytes32;\n\n    // keccak256(abi.encode(uint256(keccak256(\"openzeppelin.storage.ReentrancyGuard\")) - 1)) & ~bytes32(uint256(0xff))\n    bytes32 private constant REENTRANCY_GUARD_STORAGE =\n        0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00;\n\n    // Booleans are more expensive than uint256 or any type that takes up a full\n    // word because each write operation emits an extra SLOAD to first read the\n    // slot's contents, replace the bits taken up by the boolean, and then write\n    // back. This is the compiler's defense against contract upgrades and\n    // pointer aliasing, and it cannot be disabled.\n\n    // The values being non-zero value makes deployment a bit more expensive,\n    // but in exchange the refund on every call to nonReentrant will be lower in\n    // amount. Since refunds are capped to a percentage of the total\n    // transaction's gas, it is best to keep them low in cases like this one, to\n    // increase the likelihood of the full refund coming into effect.\n    uint256 private constant NOT_ENTERED = 1;\n    uint256 private constant ENTERED = 2;\n\n    /**\n     * @dev Unauthorized reentrant call.\n     */\n    error ReentrancyGuardReentrantCall();\n\n    constructor() {\n        _reentrancyGuardStorageSlot().getUint256Slot().value = NOT_ENTERED;\n    }\n\n    /**\n     * @dev Prevents a contract from calling itself, directly or indirectly.\n     * Calling a `nonReentrant` function from another `nonReentrant`\n     * function is not supported. It is possible to prevent this from happening\n     * by making the `nonReentrant` function external, and making it call a\n     * `private` function that does the actual work.\n     */\n    modifier nonReentrant() {\n        _nonReentrantBefore();\n        _;\n        _nonReentrantAfter();\n    }\n\n    /**\n     * @dev A `view` only version of {nonReentrant}. Use to block view functions\n     * from being called, preventing reading from inconsistent contract state.\n     *\n     * CAUTION: This is a \"view\" modifier and does not change the reentrancy\n     * status. Use it only on view functions. For payable or non-payable functions,\n     * use the standard {nonReentrant} modifier instead.\n     */\n    modifier nonReentrantView() {\n        _nonReentrantBeforeView();\n        _;\n    }\n\n    function _nonReentrantBeforeView() private view {\n        if (_reentrancyGuardEntered()) {\n            revert ReentrancyGuardReentrantCall();\n        }\n    }\n\n    function _nonReentrantBefore() private {\n        // On the first call to nonReentrant, _status will be NOT_ENTERED\n        _nonReentrantBeforeView();\n\n        // Any calls to nonReentrant after this point will fail\n        _reentrancyGuardStorageSlot().getUint256Slot().value = ENTERED;\n    }\n\n    function _nonReentrantAfter() private {\n        // By storing the original value once again, a refund is triggered (see\n        // https://eips.ethereum.org/EIPS/eip-2200)\n        _reentrancyGuardStorageSlot().getUint256Slot().value = NOT_ENTERED;\n    }\n\n    /**\n     * @dev Returns true if the reentrancy guard is currently set to \"entered\", which indicates there is a\n     * `nonReentrant` function in the call stack.\n     */\n    function _reentrancyGuardEntered() internal view returns (bool) {\n        return _reentrancyGuardStorageSlot().getUint256Slot().value == ENTERED;\n    }\n\n    function _reentrancyGuardStorageSlot() internal pure virtual returns (bytes32) {\n        return REENTRANCY_GUARD_STORAGE;\n    }\n}\n"},"@openzeppelin/contracts/utils/StorageSlot.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/StorageSlot.sol)\n// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Library for reading and writing primitive types to specific storage slots.\n *\n * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.\n * This library helps with reading and writing to such slots without the need for inline assembly.\n *\n * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.\n *\n * Example usage to set ERC-1967 implementation slot:\n * ```solidity\n * contract ERC1967 {\n *     // Define the slot. Alternatively, use the SlotDerivation library to derive the slot.\n *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\n *\n *     function _getImplementation() internal view returns (address) {\n *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;\n *     }\n *\n *     function _setImplementation(address newImplementation) internal {\n *         require(newImplementation.code.length > 0);\n *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;\n *     }\n * }\n * ```\n *\n * TIP: Consider using this library along with {SlotDerivation}.\n */\nlibrary StorageSlot {\n    struct AddressSlot {\n        address value;\n    }\n\n    struct BooleanSlot {\n        bool value;\n    }\n\n    struct Bytes32Slot {\n        bytes32 value;\n    }\n\n    struct Uint256Slot {\n        uint256 value;\n    }\n\n    struct Int256Slot {\n        int256 value;\n    }\n\n    struct StringSlot {\n        string value;\n    }\n\n    struct BytesSlot {\n        bytes value;\n    }\n\n    /**\n     * @dev Returns an `AddressSlot` with member `value` located at `slot`.\n     */\n    function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {\n        assembly (\"memory-safe\") {\n            r.slot := slot\n        }\n    }\n\n    /**\n     * @dev Returns a `BooleanSlot` with member `value` located at `slot`.\n     */\n    function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {\n        assembly (\"memory-safe\") {\n            r.slot := slot\n        }\n    }\n\n    /**\n     * @dev Returns a `Bytes32Slot` with member `value` located at `slot`.\n     */\n    function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {\n        assembly (\"memory-safe\") {\n            r.slot := slot\n        }\n    }\n\n    /**\n     * @dev Returns a `Uint256Slot` with member `value` located at `slot`.\n     */\n    function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {\n        assembly (\"memory-safe\") {\n            r.slot := slot\n        }\n    }\n\n    /**\n     * @dev Returns a `Int256Slot` with member `value` located at `slot`.\n     */\n    function getInt256Slot(bytes32 slot) internal pure returns (Int256Slot storage r) {\n        assembly (\"memory-safe\") {\n            r.slot := slot\n        }\n    }\n\n    /**\n     * @dev Returns a `StringSlot` with member `value` located at `slot`.\n     */\n    function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {\n        assembly (\"memory-safe\") {\n            r.slot := slot\n        }\n    }\n\n    /**\n     * @dev Returns an `StringSlot` representation of the string storage pointer `store`.\n     */\n    function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {\n        assembly (\"memory-safe\") {\n            r.slot := store.slot\n        }\n    }\n\n    /**\n     * @dev Returns a `BytesSlot` with member `value` located at `slot`.\n     */\n    function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {\n        assembly (\"memory-safe\") {\n            r.slot := slot\n        }\n    }\n\n    /**\n     * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.\n     */\n    function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {\n        assembly (\"memory-safe\") {\n            r.slot := store.slot\n        }\n    }\n}\n"},"contracts/fanbeimao/FanBeiMaoGenesisSale.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\n\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {ReentrancyGuard} from \"@openzeppelin/contracts/utils/ReentrancyGuard.sol\";\n\ninterface IAgentRegistry {\n    function handleOf(address account) external view returns (string memory);\n    function ownerOfHandle(string calldata handle) external view returns (address);\n}\n\ninterface IPancakeRouter02 {\n    function factory() external view returns (address);\n    function addLiquidityETH(\n        address token,\n        uint256 amountTokenDesired,\n        uint256 amountTokenMin,\n        uint256 amountETHMin,\n        address to,\n        uint256 deadline\n    ) external payable returns (uint256 amountToken, uint256 amountETH, uint256 liquidity);\n}\n\ninterface IPancakeFactory {\n    function getPair(address tokenA, address tokenB) external view returns (address pair);\n}\n\n/**\n * 翻倍猫 · 创世销售（Phase 1）\n *\n * 规则：\n *   - 10,000 份：免费 2,000 份（每个 .ai Agent ID 1 份，每份 100,000 枚）\n *     付费 8,000 份（每个 Agent ID 最多 10 份，每份 0.001 BNB，每份 1,000,000 枚）\n *   - 只有免费 2,000 份卖完后，付费才开启；卖不完就等 3 天后退款\n *   - 付费资金：80% 开池 / 10% 前 10 邀请人 / 10% 国库\n *   - 第 10,000 份自动开 PancakeSwap：6.4 BNB + 6.4e9 枚，LP 打黑洞\n *   - 开售 3 天未满 10,000 份：付费份额可退款\n *   - 代币由本合约托管，开池后买家自行 claim；退款成功后不再发币\n *\n * 这个合约只负责创世销售；交易税、每周 Merkle 分红、开池后继续铸造属于 Phase 2。\n */\ncontract FanBeiMaoGenesisSale is ReentrancyGuard {\n    address public constant DEAD = 0x000000000000000000000000000000000000dEaD;\n\n    uint256 public constant PRICE = 0.001 ether;\n    uint256 public constant FREE_TOKENS = 100_000;\n    uint256 public constant PAID_TOKENS = 1_000_000;\n    uint256 public constant POOL_TOKENS = 6_400_000_000;\n    uint256 public constant MAX_PER_AGENT = 10;\n    uint256 public constant POOL_BPS = 8_000;\n    uint256 public constant INVITER_BPS = 1_000;\n    uint256 public constant TREASURY_BPS = 1_000;\n    uint256 public constant REFUND_PERIOD = 3 days;\n\n    IERC20 public immutable token;\n    address payable public immutable treasury;\n    address public immutable agentRegistry;\n    address public immutable router;\n    address public immutable wbnb;\n    uint256 public immutable startAt;\n    uint256 public immutable refundAt;\n    uint256 public immutable freeCap;\n    uint256 public immutable paidCap;\n\n    uint256 public freeSold;\n    uint256 public paidSold;\n    uint256 public totalPaid;\n    uint256 public totalOwed;\n    uint256 public treasuryOwed;\n    bool public poolSeeded;\n    bool public poolPending;\n\n    mapping(bytes32 => bool) public freeClaimedByKey;\n    mapping(bytes32 => uint256) public paidByKey;\n    mapping(address => uint256) public sharesOf;\n    mapping(address => uint256) public tokensOwed;\n    mapping(address => uint256) public paidBy;\n    mapping(address => bool) public refunded;\n    mapping(address => uint256) public invites;\n    address[10] public topInviters;\n    uint256[10] public topCounts;\n\n    event FreeClaimed(address indexed buyer, bytes32 indexed key, uint256 tokens);\n    event SharesBought(address indexed buyer, address indexed referrer, uint256 shares, uint256 paid, uint256 tokens);\n    event InviteCounted(address indexed referrer, address indexed buyer, uint256 count);\n    event PoolSeeded(address indexed pair, uint256 bnbAmount, uint256 tokenAmount, uint256 liquidity);\n    event PoolPending();\n    event InviterPaid(address indexed inviter, uint256 amount);\n    event TreasuryPaid(uint256 amount);\n    event TokensClaimed(address indexed buyer, uint256 amount);\n    event Refunded(address indexed buyer, uint256 amount);\n\n    constructor(\n        address token_,\n        address payable treasury_,\n        address agentRegistry_,\n        address router_,\n        address wbnb_,\n        uint256 startAt_,\n        uint256 freeCap_,\n        uint256 paidCap_\n    ) {\n        require(token_ != address(0), \"token=0\");\n        require(treasury_ != address(0), \"treasury=0\");\n        require(agentRegistry_ != address(0), \"registry=0\");\n        require(router_ != address(0), \"router=0\");\n        require(wbnb_ != address(0), \"wbnb=0\");\n        require(startAt_ > 0, \"start=0\");\n        require(freeCap_ > 0 && paidCap_ > 0, \"cap=0\");\n        require(freeCap_ + paidCap_ <= 10_000, \"cap>10k\");\n\n        token = IERC20(token_);\n        treasury = treasury_;\n        agentRegistry = agentRegistry_;\n        router = router_;\n        wbnb = wbnb_;\n        startAt = startAt_;\n        refundAt = startAt_ + REFUND_PERIOD;\n        freeCap = freeCap_;\n        paidCap = paidCap_;\n    }\n\n    /* ----------------------------- views ----------------------------- */\n\n    function totalShares() public view returns (uint256) {\n        return freeCap + paidCap;\n    }\n\n    function totalSold() public view returns (uint256) {\n        return freeSold + paidSold;\n    }\n\n    function isFreeOpen() public view returns (bool) {\n        return block.timestamp >= startAt && block.timestamp < refundAt && !poolSeeded && freeSold < freeCap;\n    }\n\n    function isPaidOpen() public view returns (bool) {\n        if (block.timestamp < startAt || block.timestamp >= refundAt || poolSeeded || paidSold >= paidCap) return false;\n        return freeSold >= freeCap;\n    }\n\n    function agentKeyOf(address who) external view returns (bytes32) {\n        return _agentKey(who);\n    }\n\n    function topInvitersList() external view returns (address[10] memory, uint256[10] memory) {\n        return (topInviters, topCounts);\n    }\n\n    /* ----------------------------- agent id ----------------------------- */\n\n    function _agentKey(address who) internal view returns (bytes32) {\n        if (agentRegistry == address(0)) {\n            return bytes32(uint256(uint160(who)));\n        }\n        try IAgentRegistry(agentRegistry).handleOf(who) returns (string memory h) {\n            if (bytes(h).length == 0) return bytes32(0);\n            try IAgentRegistry(agentRegistry).ownerOfHandle(h) returns (address owner_) {\n                if (owner_ != who) return bytes32(0);\n                return keccak256(bytes(h));\n            } catch {\n                return bytes32(0);\n            }\n        } catch {\n            return bytes32(0);\n        }\n    }\n\n    /* ----------------------------- mint ----------------------------- */\n\n    function claimFree() external nonReentrant {\n        require(isFreeOpen(), \"free closed\");\n        bytes32 key = _agentKey(msg.sender);\n        require(key != bytes32(0), \"agent id required\");\n        require(!freeClaimedByKey[key], \"free claimed\");\n\n        freeClaimedByKey[key] = true;\n        freeSold += 1;\n        sharesOf[msg.sender] += 1;\n        tokensOwed[msg.sender] += FREE_TOKENS;\n        totalOwed += FREE_TOKENS;\n\n        emit FreeClaimed(msg.sender, key, FREE_TOKENS);\n    }\n\n    function buy(uint256 shares, address referrer) external payable nonReentrant {\n        require(isPaidOpen(), \"paid closed\");\n        require(shares > 0 && shares <= MAX_PER_AGENT, \"shares\");\n        require(paidSold + shares <= paidCap, \"sold out\");\n\n        bytes32 key = _agentKey(msg.sender);\n        require(key != bytes32(0), \"agent id required\");\n        require(paidByKey[key] + shares <= MAX_PER_AGENT, \"quota\");\n\n        uint256 cost = PRICE * shares;\n        require(msg.value == cost, \"bad value\");\n\n        paidByKey[key] += shares;\n        paidSold += shares;\n        sharesOf[msg.sender] += shares;\n        paidBy[msg.sender] += cost;\n        totalPaid += cost;\n\n        uint256 tokens = PAID_TOKENS * shares;\n        tokensOwed[msg.sender] += tokens;\n        totalOwed += tokens;\n\n        if (referrer != address(0) && referrer != msg.sender) {\n            invites[referrer] += 1;\n            _updateTop(referrer);\n            emit InviteCounted(referrer, msg.sender, invites[referrer]);\n        }\n\n        emit SharesBought(msg.sender, referrer, shares, cost, tokens);\n\n        if (freeSold + paidSold >= totalShares()) {\n            /* 开池约需 3.5M gas；买家 gas 不够时不要硬开，留给任何人 openPool() 重试 */\n            if (gasleft() >= 4_500_000) {\n                _openPool();\n            } else {\n                poolPending = true;\n                emit PoolPending();\n            }\n        }\n    }\n\n    /* ----------------------------- top inviters ----------------------------- */\n\n    function _updateTop(address who) internal {\n        uint256 count = invites[who];\n        uint256 idx = type(uint256).max;\n\n        for (uint256 i = 0; i < 10; i++) {\n            if (topInviters[i] == who) {\n                idx = i;\n                break;\n            }\n        }\n\n        if (idx != type(uint256).max) {\n            topCounts[idx] = count;\n            while (idx > 0 && topCounts[idx] > topCounts[idx - 1]) {\n                address ta = topInviters[idx];\n                topInviters[idx] = topInviters[idx - 1];\n                topInviters[idx - 1] = ta;\n                uint256 tc = topCounts[idx];\n                topCounts[idx] = topCounts[idx - 1];\n                topCounts[idx - 1] = tc;\n                idx--;\n            }\n            return;\n        }\n\n        if (count <= topCounts[9]) return;\n\n        topInviters[9] = who;\n        topCounts[9] = count;\n        uint256 j = 9;\n        while (j > 0 && topCounts[j] > topCounts[j - 1]) {\n            address ta = topInviters[j];\n            topInviters[j] = topInviters[j - 1];\n            topInviters[j - 1] = ta;\n            uint256 tc = topCounts[j];\n            topCounts[j] = topCounts[j - 1];\n            topCounts[j - 1] = tc;\n            j--;\n        }\n    }\n\n    /* ----------------------------- pool ----------------------------- */\n\n    function openPool() external nonReentrant {\n        require(freeSold + paidSold >= totalShares(), \"not filled\");\n        require(!poolSeeded, \"seeded\");\n        _openPool();\n        require(poolSeeded, \"pool failed\");\n    }\n\n    function _openPool() internal {\n        if (poolSeeded) return;\n        if (freeSold + paidSold < totalShares()) return;\n        require(token.balanceOf(address(this)) >= POOL_TOKENS + totalOwed, \"token balance\");\n\n        uint256 poolBnb = (totalPaid * POOL_BPS) / 10_000;\n        uint256 inviterBnb = (totalPaid * INVITER_BPS) / 10_000;\n        uint256 treasuryBnb = totalPaid - poolBnb - inviterBnb;\n\n        require(token.approve(router, POOL_TOKENS), \"approve\");\n\n        try IPancakeRouter02(router).addLiquidityETH{value: poolBnb, gas: 4_000_000}(\n            address(token), POOL_TOKENS, 0, 0, DEAD, block.timestamp + 600\n        ) returns (uint256, uint256, uint256 liquidity) {\n            require(liquidity > 0, \"no lp\");\n            poolSeeded = true;\n            poolPending = false;\n\n            address pair = IPancakeFactory(IPancakeRouter02(router).factory()).getPair(address(token), wbnb);\n            emit PoolSeeded(pair, poolBnb, POOL_TOKENS, liquidity);\n\n            _payInviters(inviterBnb);\n            treasuryOwed += treasuryBnb;\n\n            uint256 bal = token.balanceOf(address(this));\n            if (bal > totalOwed) {\n                token.transfer(treasury, bal - totalOwed);\n            }\n        } catch {\n            poolPending = true;\n            emit PoolPending();\n        }\n    }\n\n    function _payInviters(uint256 amount) internal {\n        uint256 total;\n        for (uint256 i = 0; i < 10; i++) total += topCounts[i];\n\n        if (total == 0) {\n            treasuryOwed += amount;\n            return;\n        }\n\n        uint256 paid;\n        for (uint256 i = 0; i < 10; i++) {\n            uint256 count = topCounts[i];\n            if (count == 0) continue;\n            uint256 share = (amount * count) / total;\n            if (share == 0) continue;\n            (bool ok, ) = payable(topInviters[i]).call{value: share}(\"\");\n            if (ok) {\n                paid += share;\n                emit InviterPaid(topInviters[i], share);\n            }\n        }\n        if (amount > paid) treasuryOwed += amount - paid;\n    }\n\n    function withdrawTreasury() external nonReentrant {\n        require(msg.sender == treasury, \"treasury only\");\n        uint256 amount = treasuryOwed;\n        require(amount > 0, \"nothing\");\n        treasuryOwed = 0;\n        (bool ok, ) = treasury.call{value: amount}(\"\");\n        require(ok, \"treasury xfer\");\n        emit TreasuryPaid(amount);\n    }\n\n    /* ----------------------------- claims / refunds ----------------------------- */\n\n    function claimTokens() external nonReentrant {\n        require(poolSeeded, \"not open\");\n        uint256 amount = tokensOwed[msg.sender];\n        require(amount > 0, \"nothing\");\n        tokensOwed[msg.sender] = 0;\n        totalOwed -= amount;\n        require(token.transfer(msg.sender, amount), \"token xfer\");\n        emit TokensClaimed(msg.sender, amount);\n    }\n\n    function refund() external nonReentrant {\n        require(!poolSeeded, \"pool live\");\n        require(freeSold + paidSold < totalShares(), \"filled\");\n        require(block.timestamp >= refundAt, \"too early\");\n\n        uint256 amount = paidBy[msg.sender];\n        require(amount > 0 && !refunded[msg.sender], \"nothing\");\n\n        refunded[msg.sender] = true;\n        paidBy[msg.sender] = 0;\n\n        uint256 owed = tokensOwed[msg.sender];\n        if (owed > 0) {\n            tokensOwed[msg.sender] = 0;\n            totalOwed -= owed;\n        }\n\n        (bool ok, ) = msg.sender.call{value: amount}(\"\");\n        require(ok, \"refund xfer\");\n        emit Refunded(msg.sender, amount);\n    }\n}\n"}},"settings":{"optimizer":{"enabled":true,"runs":200},"evmVersion":"paris","outputSelection":{"*":{"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"],"":["ast"]}}}}