{"sources":{"src/WorldyggMarket.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\n\nimport {IERC721} from \"@openzeppelin/contracts/token/ERC721/IERC721.sol\";\nimport {Ownable} from \"@openzeppelin/contracts/access/Ownable.sol\";\nimport {ReentrancyGuard} from \"@openzeppelin/contracts/utils/ReentrancyGuard.sol\";\n\n/// NFT market for Worldygg Trees, Yggdrasil and partner collections, paid in BNB.\n/// Listings stay in the seller's wallet until sold (the market only needs approval); offers hold their BNB here.\n/// A listing fills only while its seller still holds the token, the market is approved for it and it has not expired.\n/// The fee (feeBps of the collection) comes out of the seller's price.\ncontract WorldyggMarket is Ownable, ReentrancyGuard {\n    uint256 public constant MIN_PRICE = 0.001 ether;\n    uint256 public constant MAX_BATCH = 100;\n    uint256 public constant MAX_FEE_BPS = 1000;\n    /// gas forwarded with a BNB payout; a wallet that refuses it gets the amount in `pending`\n    uint256 private constant PAY_GAS = 50_000;\n\n    struct Listing {\n        address collection;\n        uint256 tokenId;\n        address seller;\n        uint256 price;\n        uint64 expiry;\n    }\n\n    struct Bid {\n        address bidder;\n        address collection;\n        uint256 tokenId; // ignored when anyToken\n        bool anyToken;\n        bool active;\n        uint64 expiry;\n        uint256 price;\n    }\n\n    address public feeRecipient;\n    mapping(address => bool) public supported;\n    mapping(address => uint256) public feeBps;\n    /// payouts a wallet refused, claimable with withdraw()\n    mapping(address => uint256) public pending;\n\n    Listing[] private _listings;\n    /// position + 1 in _listings of each (collection, tokenId)\n    mapping(bytes32 => uint256) private _pos;\n    Bid[] private _bids;\n\n    /// sale history, kept on-chain so sites and agents can read last sales and volume without an indexer\n    struct Sale {\n        address collection;\n        uint64 time;\n        address seller;\n        address buyer;\n        uint256 tokenId;\n        uint256 price;\n    }\n\n    Sale[] private _sales;\n    mapping(address => uint256[]) private _salesOf;\n    mapping(bytes32 => uint256) public lastSalePrice;\n    /// total BNB traded per collection\n    mapping(address => uint256) public volume;\n\n    event CollectionSet(address indexed collection, bool supported, uint256 feeBps);\n    event Listed(address indexed collection, uint256 indexed tokenId, address indexed seller, uint256 price, uint64 expiry);\n    event ListingCancelled(address indexed collection, uint256 indexed tokenId);\n    event Sold(address indexed collection, uint256 indexed tokenId, address seller, address buyer, uint256 price, uint256 bidId);\n    event BidPlaced(uint256 indexed bidId, address indexed bidder, address indexed collection, uint256 tokenId, bool anyToken, uint256 price, uint64 expiry);\n    event BidCancelled(uint256 indexed bidId);\n\n    constructor(address feeRecipient_, address initialOwner) Ownable(initialOwner) {\n        require(feeRecipient_ != address(0), \"No fee recipient\");\n        feeRecipient = feeRecipient_;\n    }\n\n    // ---------------------------------------------------------------- admin\n\n    function setCollection(address collection, bool on, uint256 bps) external onlyOwner {\n        require(bps <= MAX_FEE_BPS, \"Fee too high\");\n        supported[collection] = on;\n        feeBps[collection] = bps;\n        emit CollectionSet(collection, on, bps);\n    }\n\n    function setFeeRecipient(address r) external onlyOwner {\n        require(r != address(0), \"No fee recipient\");\n        feeRecipient = r;\n    }\n\n    // ---------------------------------------------------------------- listings\n\n    /// Lists a token for `price` wei for 1, 7, 30 or 90 days. Approve the market for the token first.\n    function list(address collection, uint256 tokenId, uint256 price, uint256 durationDays) external {\n        require(supported[collection], \"Unsupported collection\");\n        require(price >= MIN_PRICE, \"Price too low\");\n        IERC721 nft = IERC721(collection);\n        require(nft.ownerOf(tokenId) == msg.sender, \"Not owner\");\n        require(_approved(nft, msg.sender, tokenId), \"Approve market first\");\n        uint64 expiry = uint64(block.timestamp + _duration(durationDays));\n\n        bytes32 k = _key(collection, tokenId);\n        Listing memory l = Listing(collection, tokenId, msg.sender, price, expiry);\n        uint256 p = _pos[k];\n        if (p == 0) {\n            _listings.push(l);\n            _pos[k] = _listings.length;\n        } else {\n            _listings[p - 1] = l;\n        }\n        emit Listed(collection, tokenId, msg.sender, price, expiry);\n    }\n\n    /// Removes a listing; its seller or the token's current holder may do it.\n    function cancelListing(address collection, uint256 tokenId) external {\n        uint256 p = _pos[_key(collection, tokenId)];\n        require(p != 0, \"Not listed\");\n        Listing storage l = _listings[p - 1];\n        require(msg.sender == l.seller || _ownerOf(collection, tokenId) == msg.sender, \"Not seller\");\n        _removeListing(collection, tokenId);\n        emit ListingCancelled(collection, tokenId);\n    }\n\n    /// Buys a listed token; send the listed price exactly.\n    function buy(address collection, uint256 tokenId) external payable nonReentrant {\n        uint256 p = _pos[_key(collection, tokenId)];\n        require(p != 0, \"Not listed\");\n        Listing memory l = _listings[p - 1];\n        require(_fillable(l), \"Listing not fillable\");\n        require(msg.value == l.price, \"Wrong price\");\n        require(msg.sender != l.seller, \"Own listing\");\n        _sell(l.collection, l.tokenId, l.seller, msg.sender, l.price, type(uint256).max);\n    }\n\n    /// Buys up to 100 tokens, each only if still listed and fillable at <= its max price; the rest of the BNB is\n    /// refunded. Returns how many were bought.\n    function buyMany(address[] calldata collections, uint256[] calldata tokenIds, uint256[] calldata maxPrices)\n        external\n        payable\n        nonReentrant\n        returns (uint256 bought)\n    {\n        uint256 n = tokenIds.length;\n        require(n > 0 && n <= MAX_BATCH && collections.length == n && maxPrices.length == n, \"Bad batch\");\n        uint256 spent;\n        for (uint256 i; i < n; ++i) {\n            uint256 p = _pos[_key(collections[i], tokenIds[i])];\n            if (p == 0) continue;\n            Listing memory l = _listings[p - 1];\n            if (l.price > maxPrices[i] || spent + l.price > msg.value || l.seller == msg.sender || !_fillable(l)) continue;\n            spent += l.price;\n            _sell(l.collection, l.tokenId, l.seller, msg.sender, l.price, type(uint256).max);\n            ++bought;\n        }\n        if (msg.value > spent) _pay(msg.sender, msg.value - spent);\n    }\n\n    // ---------------------------------------------------------------- offers\n\n    /// Places an offer of msg.value for one token, or for any token of the collection when `anyToken`.\n    function bid(address collection, uint256 tokenId, bool anyToken, uint256 durationDays)\n        external\n        payable\n        returns (uint256 bidId)\n    {\n        require(supported[collection], \"Unsupported collection\");\n        require(msg.value >= MIN_PRICE, \"Price too low\");\n        bidId = _placeBid(collection, anyToken ? 0 : tokenId, anyToken, msg.value, _duration(durationDays));\n    }\n\n    /// Places `count` any-token offers on a collection, msg.value / count each.\n    function bidMany(address collection, uint256 count, uint256 durationDays) external payable returns (uint256 firstBidId) {\n        require(supported[collection], \"Unsupported collection\");\n        require(count > 0 && count <= MAX_BATCH, \"Bad count\");\n        require(msg.value % count == 0, \"Uneven value\");\n        uint256 each = msg.value / count;\n        require(each >= MIN_PRICE, \"Price too low\");\n        uint256 d = _duration(durationDays);\n        firstBidId = _bids.length;\n        for (uint256 i; i < count; ++i) _placeBid(collection, 0, true, each, d);\n    }\n\n    /// Sells `tokenId` into an open offer. Approve the market for the token first.\n    function acceptBid(uint256 bidId, uint256 tokenId) external nonReentrant {\n        require(bidId < _bids.length, \"No bid\");\n        Bid storage b = _bids[bidId];\n        require(b.active && b.expiry > block.timestamp, \"Bid not open\");\n        require(b.anyToken || b.tokenId == tokenId, \"Wrong token\");\n        require(supported[b.collection], \"Unsupported collection\");\n        require(IERC721(b.collection).ownerOf(tokenId) == msg.sender, \"Not owner\");\n        require(b.bidder != msg.sender, \"Own bid\");\n        b.active = false;\n        _sell(b.collection, tokenId, msg.sender, b.bidder, b.price, bidId);\n    }\n\n    /// Returns an offer's BNB to its bidder, also for expired offers.\n    function cancelBid(uint256 bidId) public nonReentrant {\n        require(bidId < _bids.length, \"No bid\");\n        Bid storage b = _bids[bidId];\n        require(b.bidder == msg.sender, \"Not bidder\");\n        require(b.active, \"Bid closed\");\n        b.active = false;\n        emit BidCancelled(bidId);\n        _pay(msg.sender, b.price);\n    }\n\n    function cancelBids(uint256[] calldata bidIds) external {\n        for (uint256 i; i < bidIds.length; ++i) cancelBid(bidIds[i]);\n    }\n\n    /// Claims payouts the wallet refused earlier.\n    function withdraw() external nonReentrant {\n        uint256 amt = pending[msg.sender];\n        require(amt > 0, \"Nothing pending\");\n        pending[msg.sender] = 0;\n        (bool ok,) = payable(msg.sender).call{value: amt}(\"\");\n        require(ok, \"Withdraw failed\");\n    }\n\n    // ---------------------------------------------------------------- views\n\n    function listing(address collection, uint256 tokenId) external view returns (Listing memory l, bool fillable) {\n        uint256 p = _pos[_key(collection, tokenId)];\n        if (p == 0) return (l, false);\n        l = _listings[p - 1];\n        fillable = _fillable(l);\n    }\n\n    function listingCount() external view returns (uint256) {\n        return _listings.length;\n    }\n\n    function listingsPage(uint256 offset, uint256 limit) external view returns (Listing[] memory page, bool[] memory fillable) {\n        uint256 n = _listings.length;\n        uint256 end = offset + limit > n ? n : offset + limit;\n        uint256 len = end > offset ? end - offset : 0;\n        page = new Listing[](len);\n        fillable = new bool[](len);\n        for (uint256 i; i < len; ++i) {\n            page[i] = _listings[offset + i];\n            fillable[i] = _fillable(page[i]);\n        }\n    }\n\n    function bidOf(uint256 bidId) external view returns (Bid memory b, bool open) {\n        require(bidId < _bids.length, \"No bid\");\n        b = _bids[bidId];\n        open = b.active && b.expiry > block.timestamp;\n    }\n\n    function bidCount() external view returns (uint256) {\n        return _bids.length;\n    }\n\n    function saleCount(address collection) external view returns (uint256) {\n        return _salesOf[collection].length;\n    }\n\n    /// The latest `limit` sales of a collection, newest first, skipping the newest `offset`.\n    function recentSales(address collection, uint256 offset, uint256 limit) external view returns (Sale[] memory page) {\n        uint256[] storage ids = _salesOf[collection];\n        uint256 n = ids.length;\n        uint256 len = offset >= n ? 0 : (n - offset < limit ? n - offset : limit);\n        page = new Sale[](len);\n        for (uint256 i; i < len; ++i) page[i] = _sales[ids[n - 1 - offset - i]];\n    }\n\n    /// Last sale price of a token (0 if never sold here).\n    function lastSale(address collection, uint256 tokenId) external view returns (uint256) {\n        return lastSalePrice[_key(collection, tokenId)];\n    }\n\n    function bidsPage(uint256 offset, uint256 limit) external view returns (uint256[] memory ids, Bid[] memory page) {\n        uint256 n = _bids.length;\n        uint256 end = offset + limit > n ? n : offset + limit;\n        uint256 len = end > offset ? end - offset : 0;\n        ids = new uint256[](len);\n        page = new Bid[](len);\n        for (uint256 i; i < len; ++i) {\n            ids[i] = offset + i;\n            page[i] = _bids[offset + i];\n        }\n    }\n\n    // ---------------------------------------------------------------- internals\n\n    function _sell(address collection, uint256 tokenId, address seller, address buyer, uint256 price, uint256 bidId) private {\n        if (_pos[_key(collection, tokenId)] != 0) _removeListing(collection, tokenId);\n        IERC721(collection).transferFrom(seller, buyer, tokenId);\n        uint256 fee = price * feeBps[collection] / 10_000;\n        if (fee > 0) _pay(feeRecipient, fee);\n        _pay(seller, price - fee);\n        _salesOf[collection].push(_sales.length);\n        _sales.push(Sale(collection, uint64(block.timestamp), seller, buyer, tokenId, price));\n        lastSalePrice[_key(collection, tokenId)] = price;\n        volume[collection] += price;\n        emit Sold(collection, tokenId, seller, buyer, price, bidId);\n    }\n\n    function _placeBid(address collection, uint256 tokenId, bool anyToken, uint256 price, uint256 duration)\n        private\n        returns (uint256 bidId)\n    {\n        bidId = _bids.length;\n        uint64 expiry = uint64(block.timestamp + duration);\n        _bids.push(Bid(msg.sender, collection, tokenId, anyToken, true, expiry, price));\n        emit BidPlaced(bidId, msg.sender, collection, tokenId, anyToken, price, expiry);\n    }\n\n    function _removeListing(address collection, uint256 tokenId) private {\n        bytes32 k = _key(collection, tokenId);\n        uint256 i = _pos[k] - 1;\n        uint256 last = _listings.length - 1;\n        if (i != last) {\n            Listing memory m = _listings[last];\n            _listings[i] = m;\n            _pos[_key(m.collection, m.tokenId)] = i + 1;\n        }\n        _listings.pop();\n        delete _pos[k];\n    }\n\n    function _fillable(Listing memory l) private view returns (bool) {\n        if (l.expiry <= block.timestamp || !supported[l.collection]) return false;\n        if (_ownerOf(l.collection, l.tokenId) != l.seller) return false;\n        return _approved(IERC721(l.collection), l.seller, l.tokenId);\n    }\n\n    /// ownerOf that returns address(0) for burned (e.g. merged) tokens instead of reverting\n    function _ownerOf(address collection, uint256 tokenId) private view returns (address) {\n        try IERC721(collection).ownerOf(tokenId) returns (address o) {\n            return o;\n        } catch {\n            return address(0);\n        }\n    }\n\n    function _approved(IERC721 nft, address holder, uint256 tokenId) private view returns (bool) {\n        return nft.isApprovedForAll(holder, address(this)) || nft.getApproved(tokenId) == address(this);\n    }\n\n    function _pay(address to, uint256 amt) private {\n        (bool ok,) = payable(to).call{value: amt, gas: PAY_GAS}(\"\");\n        if (!ok) pending[to] += amt;\n    }\n\n    function _duration(uint256 d) private pure returns (uint256) {\n        require(d == 1 || d == 7 || d == 30 || d == 90, \"Duration 1/7/30/90 days\");\n        return d * 1 days;\n    }\n\n    function _key(address collection, uint256 tokenId) private pure returns (bytes32) {\n        return keccak256(abi.encode(collection, tokenId));\n    }\n}\n"},"lib/openzeppelin-contracts/contracts/token/ERC721/IERC721.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC721/IERC721.sol)\n\npragma solidity >=0.6.2;\n\nimport {IERC165} from \"../../utils/introspection/IERC165.sol\";\n\n/**\n * @dev Required interface of an ERC-721 compliant contract.\n */\ninterface IERC721 is IERC165 {\n    /**\n     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);\n\n    /**\n     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.\n     */\n    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);\n\n    /**\n     * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.\n     */\n    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\n\n    /**\n     * @dev Returns the number of tokens in ``owner``'s account.\n     */\n    function balanceOf(address owner) external view returns (uint256 balance);\n\n    /**\n     * @dev Returns the owner of the `tokenId` token.\n     *\n     * Requirements:\n     *\n     * - `tokenId` must exist.\n     */\n    function ownerOf(uint256 tokenId) external view returns (address owner);\n\n    /**\n     * @dev Safely transfers `tokenId` token from `from` to `to`.\n     *\n     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `tokenId` token must exist and be owned by `from`.\n     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon\n     *   a safe transfer.\n     *\n     * Emits a {Transfer} event.\n     */\n    function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;\n\n    /**\n     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients\n     * are aware of the ERC-721 protocol to prevent tokens from being forever locked.\n     *\n     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `tokenId` token must exist and be owned by `from`.\n     * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or\n     *   {setApprovalForAll}.\n     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon\n     *   a safe transfer.\n     *\n     * Emits a {Transfer} event.\n     */\n    function safeTransferFrom(address from, address to, uint256 tokenId) external;\n\n    /**\n     * @dev Transfers `tokenId` token from `from` to `to`.\n     *\n     * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC-721\n     * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must\n     * understand this adds an external call which potentially creates a reentrancy vulnerability.\n     *\n     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `tokenId` token must be owned by `from`.\n     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(address from, address to, uint256 tokenId) external;\n\n    /**\n     * @dev Gives permission to `to` to transfer `tokenId` token to another account.\n     * The approval is cleared when the token is transferred.\n     *\n     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.\n     *\n     * Requirements:\n     *\n     * - The caller must own the token or be an approved operator.\n     * - `tokenId` must exist.\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address to, uint256 tokenId) external;\n\n    /**\n     * @dev Approve or remove `operator` as an operator for the caller.\n     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.\n     *\n     * Requirements:\n     *\n     * - The `operator` cannot be the address zero.\n     *\n     * Emits an {ApprovalForAll} event.\n     */\n    function setApprovalForAll(address operator, bool approved) external;\n\n    /**\n     * @dev Returns the account approved for `tokenId` token.\n     *\n     * Requirements:\n     *\n     * - `tokenId` must exist.\n     */\n    function getApproved(uint256 tokenId) external view returns (address operator);\n\n    /**\n     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.\n     *\n     * See {setApprovalForAll}\n     */\n    function isApprovedForAll(address owner, address operator) external view returns (bool);\n}\n"},"lib/openzeppelin-contracts/contracts/access/Ownable.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)\n\npragma solidity ^0.8.20;\n\nimport {Context} from \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * The initial owner is set to the address provided by the deployer. This can\n * later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n    address private _owner;\n\n    /**\n     * @dev The caller account is not authorized to perform an operation.\n     */\n    error OwnableUnauthorizedAccount(address account);\n\n    /**\n     * @dev The owner is not a valid owner account. (eg. `address(0)`)\n     */\n    error OwnableInvalidOwner(address owner);\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.\n     */\n    constructor(address initialOwner) {\n        if (initialOwner == address(0)) {\n            revert OwnableInvalidOwner(address(0));\n        }\n        _transferOwnership(initialOwner);\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        _checkOwner();\n        _;\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        if (owner() != _msgSender()) {\n            revert OwnableUnauthorizedAccount(_msgSender());\n        }\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby disabling any functionality that is only available to the owner.\n     */\n    function renounceOwnership() public virtual onlyOwner {\n        _transferOwnership(address(0));\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Can only be called by the current owner.\n     */\n    function transferOwnership(address newOwner) public virtual onlyOwner {\n        if (newOwner == address(0)) {\n            revert OwnableInvalidOwner(address(0));\n        }\n        _transferOwnership(newOwner);\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Internal function without access restriction.\n     */\n    function _transferOwnership(address newOwner) internal virtual {\n        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n"},"lib/openzeppelin-contracts/contracts/utils/ReentrancyGuard.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/ReentrancyGuard.sol)\n\npragma solidity ^0.8.20;\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 */\nabstract contract ReentrancyGuard {\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    uint256 private _status;\n\n    /**\n     * @dev Unauthorized reentrant call.\n     */\n    error ReentrancyGuardReentrantCall();\n\n    constructor() {\n        _status = 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    function _nonReentrantBefore() private {\n        // On the first call to nonReentrant, _status will be NOT_ENTERED\n        if (_status == ENTERED) {\n            revert ReentrancyGuardReentrantCall();\n        }\n\n        // Any calls to nonReentrant after this point will fail\n        _status = 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        _status = 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 _status == ENTERED;\n    }\n}\n"},"lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.4.0) (utils/introspection/IERC165.sol)\n\npragma solidity >=0.4.16;\n\n/**\n * @dev Interface of the ERC-165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[ERC].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n    /**\n     * @dev Returns true if this contract implements the interface defined by\n     * `interfaceId`. See the corresponding\n     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]\n     * to learn more about how these ids are created.\n     *\n     * This function call must use less than 30 000 gas.\n     */\n    function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n"},"lib/openzeppelin-contracts/contracts/utils/Context.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n    function _msgSender() internal view virtual returns (address) {\n        return msg.sender;\n    }\n\n    function _msgData() internal view virtual returns (bytes calldata) {\n        return msg.data;\n    }\n\n    function _contextSuffixLength() internal view virtual returns (uint256) {\n        return 0;\n    }\n}\n"}},"matchId":"56847134","creationMatch":"exact_match","runtimeMatch":"exact_match","verifiedAt":"2026-10-24T13:09:24Z","match":"exact_match","chainId":"56","address":"0xB81324e14319712De43E560111452b73834cd72A"}