Ape Curtis Testnet

Contract

0x657c7E3b1D32bc4e757a2648A004D2F50D83d6a0

Overview

APE Balance

Ape Curtis LogoApe Curtis LogoApe Curtis Logo0 APE
Transaction Hash
Method
Block
From
To

There are no matching entries

1 Internal Transaction found.

Latest 1 internal transaction

Parent Transaction Hash Block From To
166961652025-03-23 20:45:5721 days ago1742762757
0x657c7E3b...50D83d6a0
0 APE

Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
CreatorTokenTransferValidator

Compiler Version
v0.8.20+commit.a1b79de6

Optimization Enabled:
Yes with 200 runs

Other Settings:
paris EvmVersion

Contract Source Code (Solidity Standard Json-Input format)

File 1 of 17 : CreatorTokenTransferValidator.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import "./EOARegistry.sol";
import "../interfaces/IOwnable.sol";
import "../interfaces/ICreatorTokenTransferValidator.sol";
import "@openzeppelin/contracts/access/IAccessControl.sol";
import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";

/**
 * @title  CreatorTokenTransferValidator
 * @author Limit Break, Inc.
 * @notice The CreatorTokenTransferValidator contract is designed to provide a customizable and secure transfer 
 *         validation mechanism for NFT collections. This contract allows the owner of an NFT collection to configure 
 *         the transfer security level, operator whitelist, and permitted contract receiver allowlist for each 
 *         collection.
 *
 * @dev    <h4>Features</h4>
 *         - Transfer security levels: Provides different levels of transfer security, 
 *           from open transfers to completely restricted transfers.
 *         - Operator whitelist: Allows the owner of a collection to whitelist specific operator addresses permitted
 *           to execute transfers on behalf of others.
 *         - Permitted contract receiver allowlist: Enables the owner of a collection to allow specific contract 
 *           addresses to receive NFTs when otherwise disabled by security policy.
 *
 * @dev    <h4>Benefits</h4>
 *         - Enhanced security: Allows creators to have more control over their NFT collections, ensuring the safety 
 *           and integrity of their assets.
 *         - Flexibility: Provides collection owners the ability to customize transfer rules as per their requirements.
 *         - Compliance: Facilitates compliance with regulations by enabling creators to restrict transfers based on 
 *           specific criteria.
 *
 * @dev    <h4>Intended Usage</h4>
 *         - The CreatorTokenTransferValidator contract is intended to be used by NFT collection owners to manage and 
 *           enforce transfer policies. This contract is integrated with the following varations of creator token 
 *           NFT contracts to validate transfers according to the defined security policies.
 *
 *           - ERC721-C:   Creator token implenting OpenZeppelin's ERC-721 standard.
 *           - ERC721-AC:  Creator token implenting Azuki's ERC-721A standard.
 *           - ERC721-CW:  Creator token implementing OpenZeppelin's ERC-721 standard with opt-in staking to 
 *                         wrap/upgrade a pre-existing ERC-721 collection.
 *           - ERC721-ACW: Creator token implementing Azuki's ERC721-A standard with opt-in staking to 
 *                         wrap/upgrade a pre-existing ERC-721 collection.
 *           - ERC1155-C:  Creator token implenting OpenZeppelin's ERC-1155 standard.
 *           - ERC1155-CW: Creator token implementing OpenZeppelin's ERC-1155 standard with opt-in staking to 
 *                         wrap/upgrade a pre-existing ERC-1155 collection.
 *
 *          <h4>Transfer Security Levels</h4>
 *          - Level 0 (Zero): No transfer restrictions.
 *            - Caller Constraints: None
 *            - Receiver Constraints: None
 *          - Level 1 (One): Only whitelisted operators can initiate transfers, with over-the-counter (OTC) trading enabled.
 *            - Caller Constraints: OperatorWhitelistEnableOTC
 *            - Receiver Constraints: None
 *          - Level 2 (Two): Only whitelisted operators can initiate transfers, with over-the-counter (OTC) trading disabled.
 *            - Caller Constraints: OperatorWhitelistDisableOTC
 *            - Receiver Constraints: None
 *          - Level 3 (Three): Only whitelisted operators can initiate transfers, with over-the-counter (OTC) trading enabled. Transfers to contracts with code are not allowed.
 *            - Caller Constraints: OperatorWhitelistEnableOTC
 *            - Receiver Constraints: NoCode
 *          - Level 4 (Four): Only whitelisted operators can initiate transfers, with over-the-counter (OTC) trading enabled. Transfers are allowed only to Externally Owned Accounts (EOAs).
 *            - Caller Constraints: OperatorWhitelistEnableOTC
 *            - Receiver Constraints: EOA
 *          - Level 5 (Five): Only whitelisted operators can initiate transfers, with over-the-counter (OTC) trading disabled. Transfers to contracts with code are not allowed.
 *            - Caller Constraints: OperatorWhitelistDisableOTC
 *            - Receiver Constraints: NoCode
 *          - Level 6 (Six): Only whitelisted operators can initiate transfers, with over-the-counter (OTC) trading disabled. Transfers are allowed only to Externally Owned Accounts (EOAs).
 *            - Caller Constraints: OperatorWhitelistDisableOTC
 *            - Receiver Constraints: EOA
 */
contract CreatorTokenTransferValidator is EOARegistry, ICreatorTokenTransferValidator {
    using EnumerableSet for EnumerableSet.AddressSet;

    error CreatorTokenTransferValidator__AddressAlreadyAllowed();
    error CreatorTokenTransferValidator__AddressNotAllowed();
    error CreatorTokenTransferValidator__AllowlistDoesNotExist();
    error CreatorTokenTransferValidator__AllowlistOwnershipCannotBeTransferredToZeroAddress();
    error CreatorTokenTransferValidator__CallerDoesNotOwnAllowlist();
    error CreatorTokenTransferValidator__CallerMustBeWhitelistedOperator();
    error CreatorTokenTransferValidator__CallerMustHaveElevatedPermissionsForSpecifiedNFT();
    error CreatorTokenTransferValidator__ReceiverMustNotHaveDeployedCode();
    error CreatorTokenTransferValidator__ReceiverProofOfEOASignatureUnverified();
    
    bytes32 private constant DEFAULT_ACCESS_CONTROL_ADMIN_ROLE = 0x00;
    TransferSecurityLevels public constant DEFAULT_TRANSFER_SECURITY_LEVEL = TransferSecurityLevels.Zero;

    uint120 private lastOperatorWhitelistId;
    uint120 private lastPermittedContractReceiverAllowlistId;

    mapping (TransferSecurityLevels => TransferSecurityPolicy) public transferSecurityPolicies;
    mapping (address => CollectionSecurityPolicy) private collectionSecurityPolicies;
    mapping (uint120 => address) public operatorWhitelistOwners;
    mapping (uint120 => address) public permittedContractReceiverAllowlistOwners;
    mapping (uint120 => EnumerableSet.AddressSet) private operatorWhitelists;
    mapping (uint120 => EnumerableSet.AddressSet) private permittedContractReceiverAllowlists;

    constructor(address defaultOwner) EOARegistry() {
        transferSecurityPolicies[TransferSecurityLevels.Zero] = TransferSecurityPolicy({
            callerConstraints: CallerConstraints.None,
            receiverConstraints: ReceiverConstraints.None
        });

        transferSecurityPolicies[TransferSecurityLevels.One] = TransferSecurityPolicy({
            callerConstraints: CallerConstraints.OperatorWhitelistEnableOTC,
            receiverConstraints: ReceiverConstraints.None
        });

        transferSecurityPolicies[TransferSecurityLevels.Two] = TransferSecurityPolicy({
            callerConstraints: CallerConstraints.OperatorWhitelistDisableOTC,
            receiverConstraints: ReceiverConstraints.None
        });

        transferSecurityPolicies[TransferSecurityLevels.Three] = TransferSecurityPolicy({
            callerConstraints: CallerConstraints.OperatorWhitelistEnableOTC,
            receiverConstraints: ReceiverConstraints.NoCode
        });

        transferSecurityPolicies[TransferSecurityLevels.Four] = TransferSecurityPolicy({
            callerConstraints: CallerConstraints.OperatorWhitelistEnableOTC,
            receiverConstraints: ReceiverConstraints.EOA
        });

        transferSecurityPolicies[TransferSecurityLevels.Five] = TransferSecurityPolicy({
            callerConstraints: CallerConstraints.OperatorWhitelistDisableOTC,
            receiverConstraints: ReceiverConstraints.NoCode
        });

        transferSecurityPolicies[TransferSecurityLevels.Six] = TransferSecurityPolicy({
            callerConstraints: CallerConstraints.OperatorWhitelistDisableOTC,
            receiverConstraints: ReceiverConstraints.EOA
        });

        uint120 id = ++lastOperatorWhitelistId;

        operatorWhitelistOwners[id] = defaultOwner;

        emit CreatedAllowlist(AllowlistTypes.Operators, id, "DEFAULT OPERATOR WHITELIST");
        emit ReassignedAllowlistOwnership(AllowlistTypes.Operators, id, defaultOwner);
    }

    /**
     * @notice Apply the collection transfer policy to a transfer operation of a creator token.
     *
     * @dev Throws when the receiver has deployed code but is not in the permitted contract receiver allowlist,
     *      if the ReceiverConstraints is set to NoCode.
     * @dev Throws when the receiver has never verified a signature to prove they are an EOA and the receiver
     *      is not in the permitted contract receiver allowlist, if the ReceiverConstraints is set to EOA.
     * @dev Throws when `msg.sender` is not a whitelisted operator, if CallerConstraints is OperatorWhitelistDisableOTC.
     * @dev Throws when `msg.sender` is neither a whitelisted operator nor the 'from' addresses,
     *      if CallerConstraints is OperatorWhitelistEnableOTC.
     *
     * @dev <h4>Postconditions:</h4>
     *      1. Transfer is allowed or denied based on the applied transfer policy.
     *
     * @param caller The address initiating the transfer.
     * @param from   The address of the token owner.
     * @param to     The address of the token receiver.
     */
    function applyCollectionTransferPolicy(address caller, address from, address to) external view override {
        address collection = _msgSender();
        CollectionSecurityPolicy memory collectionSecurityPolicy = collectionSecurityPolicies[collection];
        TransferSecurityPolicy memory transferSecurityPolicy = 
            transferSecurityPolicies[collectionSecurityPolicy.transferSecurityLevel];
        
        if (transferSecurityPolicy.receiverConstraints == ReceiverConstraints.NoCode) {
            if (to.code.length > 0) {
                if (!isContractReceiverPermitted(collectionSecurityPolicy.permittedContractReceiversId, to)) {
                    revert CreatorTokenTransferValidator__ReceiverMustNotHaveDeployedCode();
                }
            }
        } else if (transferSecurityPolicy.receiverConstraints == ReceiverConstraints.EOA) {
            if (!isVerifiedEOA(to)) {
                if (!isContractReceiverPermitted(collectionSecurityPolicy.permittedContractReceiversId, to)) {
                    revert CreatorTokenTransferValidator__ReceiverProofOfEOASignatureUnverified();
                }
            }
        }

        if (transferSecurityPolicy.callerConstraints != CallerConstraints.None) {
            if(operatorWhitelists[collectionSecurityPolicy.operatorWhitelistId].length() > 0) {
                if (!isOperatorWhitelisted(collectionSecurityPolicy.operatorWhitelistId, caller)) {
                    if (transferSecurityPolicy.callerConstraints == CallerConstraints.OperatorWhitelistEnableOTC) {
                        if (caller != from) {
                            revert CreatorTokenTransferValidator__CallerMustBeWhitelistedOperator();
                        }
                    } else {
                        revert CreatorTokenTransferValidator__CallerMustBeWhitelistedOperator();
                    }
                }
            }
        }
    }

    /**
     * @notice Create a new operator whitelist.
     *
     * @dev <h4>Postconditions:</h4>
     *      1. A new operator whitelist with the specified name is created.
     *      2. The caller is set as the owner of the new operator whitelist.
     *      3. A `CreatedAllowlist` event is emitted.
     *      4. A `ReassignedAllowlistOwnership` event is emitted.
     *
     * @param name The name of the new operator whitelist.
     * @return     The id of the new operator whitelist.
     */
    function createOperatorWhitelist(string calldata name) external override returns (uint120) {
        uint120 id = ++lastOperatorWhitelistId;

        operatorWhitelistOwners[id] = _msgSender();

        emit CreatedAllowlist(AllowlistTypes.Operators, id, name);
        emit ReassignedAllowlistOwnership(AllowlistTypes.Operators, id, _msgSender());

        return id;
    }

    /**
     * @notice Create a new permitted contract receiver allowlist.
     * 
     * @dev <h4>Postconditions:</h4>
     *      1. A new permitted contract receiver allowlist with the specified name is created.
     *      2. The caller is set as the owner of the new permitted contract receiver allowlist.
     *      3. A `CreatedAllowlist` event is emitted.
     *      4. A `ReassignedAllowlistOwnership` event is emitted.
     *
     * @param name The name of the new permitted contract receiver allowlist.
     * @return     The id of the new permitted contract receiver allowlist.
     */
    function createPermittedContractReceiverAllowlist(string calldata name) external override returns (uint120) {
        uint120 id = ++lastPermittedContractReceiverAllowlistId;

        permittedContractReceiverAllowlistOwners[id] = _msgSender();

        emit CreatedAllowlist(AllowlistTypes.PermittedContractReceivers, id, name);
        emit ReassignedAllowlistOwnership(AllowlistTypes.PermittedContractReceivers, id, _msgSender());

        return id;
    }

    /**
     * @notice Transfer ownership of an operator whitelist to a new owner.
     *
     * @dev Throws when the new owner is the zero address.
     * @dev Throws when the caller does not own the specified operator whitelist.
     *
     * @dev <h4>Postconditions:</h4>
     *      1. The operator whitelist ownership is transferred to the new owner.
     *      2. A `ReassignedAllowlistOwnership` event is emitted.
     *
     * @param id       The id of the operator whitelist.
     * @param newOwner The address of the new owner.
     */
    function reassignOwnershipOfOperatorWhitelist(uint120 id, address newOwner) external override {
        if(newOwner == address(0)) {
            revert CreatorTokenTransferValidator__AllowlistOwnershipCannotBeTransferredToZeroAddress();
        }

        _reassignOwnershipOfOperatorWhitelist(id, newOwner);
    }

    /**
     * @notice Transfer ownership of a permitted contract receiver allowlist to a new owner.
     *
     * @dev Throws when the new owner is the zero address.
     * @dev Throws when the caller does not own the specified permitted contract receiver allowlist.
     *
     * @dev <h4>Postconditions:</h4>
     *      1. The permitted contract receiver allowlist ownership is transferred to the new owner.
     *      2. A `ReassignedAllowlistOwnership` event is emitted.
     *
     * @param id       The id of the permitted contract receiver allowlist.
     * @param newOwner The address of the new owner.
     */
    function reassignOwnershipOfPermittedContractReceiverAllowlist(uint120 id, address newOwner) external override {
        if(newOwner == address(0)) {
            revert CreatorTokenTransferValidator__AllowlistOwnershipCannotBeTransferredToZeroAddress();
        }

        _reassignOwnershipOfPermittedContractReceiverAllowlist(id, newOwner);
    }

    /**
     * @notice Renounce the ownership of an operator whitelist, rendering the whitelist immutable.
     *
     * @dev Throws when the caller does not own the specified operator whitelist.
     *
     * @dev <h4>Postconditions:</h4>
     *      1. The ownership of the specified operator whitelist is renounced.
     *      2. A `ReassignedAllowlistOwnership` event is emitted.
     *
     * @param id The id of the operator whitelist.
     */
    function renounceOwnershipOfOperatorWhitelist(uint120 id) external override {
        _reassignOwnershipOfOperatorWhitelist(id, address(0));
    }

    /**
     * @notice Renounce the ownership of a permitted contract receiver allowlist, rendering the allowlist immutable.
     *
     * @dev Throws when the caller does not own the specified permitted contract receiver allowlist.
     *
     * @dev <h4>Postconditions:</h4>
     *      1. The ownership of the specified permitted contract receiver allowlist is renounced.
     *      2. A `ReassignedAllowlistOwnership` event is emitted.
     *
     * @param id The id of the permitted contract receiver allowlist.
     */
    function renounceOwnershipOfPermittedContractReceiverAllowlist(uint120 id) external override {
        _reassignOwnershipOfPermittedContractReceiverAllowlist(id, address(0));
    }

    /**
     * @notice Set the transfer security level of a collection.
     *
     * @dev Throws when the caller is neither collection contract, nor the owner or admin of the specified collection.
     *
     * @dev <h4>Postconditions:</h4>
     *      1. The transfer security level of the specified collection is set to the new value.
     *      2. A `SetTransferSecurityLevel` event is emitted.
     *
     * @param collection The address of the collection.
     * @param level      The new transfer security level to apply.
     */
    function setTransferSecurityLevelOfCollection(
        address collection, 
        TransferSecurityLevels level) external override {
        _requireCallerIsNFTOrContractOwnerOrAdmin(collection);
        collectionSecurityPolicies[collection].transferSecurityLevel = level;
        emit SetTransferSecurityLevel(collection, level);
    }

    /**
     * @notice Set the operator whitelist of a collection.
     * 
     * @dev Throws when the caller is neither collection contract, nor the owner or admin of the specified collection.
     * @dev Throws when the specified operator whitelist id does not exist.
     *
     * @dev <h4>Postconditions:</h4>
     *      1. The operator whitelist of the specified collection is set to the new value.
     *      2. A `SetAllowlist` event is emitted.
     *
     * @param collection The address of the collection.
     * @param id         The id of the operator whitelist.
     */
    function setOperatorWhitelistOfCollection(address collection, uint120 id) external override {
        _requireCallerIsNFTOrContractOwnerOrAdmin(collection);

        if (id > lastOperatorWhitelistId) {
            revert CreatorTokenTransferValidator__AllowlistDoesNotExist();
        }

        collectionSecurityPolicies[collection].operatorWhitelistId = id;
        emit SetAllowlist(AllowlistTypes.Operators, collection, id);
    }

    /**
     * @notice Set the permitted contract receiver allowlist of a collection.
     *
     * @dev Throws when the caller does not own the specified collection.
     * @dev Throws when the specified permitted contract receiver allowlist id does not exist.
     *
     * @dev <h4>Postconditions:</h4>
     *      1. The permitted contract receiver allowlist of the specified collection is set to the new value.
     *      2. A `PermittedContractReceiverAllowlistSet` event is emitted.
     *
     * @param collection The address of the collection.
     * @param id         The id of the permitted contract receiver allowlist.
     */
    function setPermittedContractReceiverAllowlistOfCollection(address collection, uint120 id) external override {
        _requireCallerIsNFTOrContractOwnerOrAdmin(collection);

        if (id > lastPermittedContractReceiverAllowlistId) {
            revert CreatorTokenTransferValidator__AllowlistDoesNotExist();
        }

        collectionSecurityPolicies[collection].permittedContractReceiversId = id;
        emit SetAllowlist(AllowlistTypes.PermittedContractReceivers, collection, id);
    }

    /**
     * @notice Add an operator to an operator whitelist.
     *
     * @dev Throws when the caller does not own the specified operator whitelist.
     * @dev Throws when the operator address is already allowed.
     *
     * @dev <h4>Postconditions:</h4>
     *      1. The operator is added to the specified operator whitelist.
     *      2. An `AddedToAllowlist` event is emitted.
     *
     * @param id       The id of the operator whitelist.
     * @param operator The address of the operator to add.
     */
    function addOperatorToWhitelist(uint120 id, address operator) external override {
        _requireCallerOwnsOperatorWhitelist(id);

        if (!operatorWhitelists[id].add(operator)) {
            revert CreatorTokenTransferValidator__AddressAlreadyAllowed();
        }

        emit AddedToAllowlist(AllowlistTypes.Operators, id, operator);
    }

    /**
     * @notice Add a contract address to a permitted contract receiver allowlist.
     *
     * @dev Throws when the caller does not own the specified permitted contract receiver allowlist.
     * @dev Throws when the contract address is already allowed.
     *
     * @dev <h4>Postconditions:</h4>
     *      1. The contract address is added to the specified permitted contract receiver allowlist.
     *      2. An `AddedToAllowlist` event is emitted.
     *
     * @param id              The id of the permitted contract receiver allowlist.
     * @param receiver The address of the contract to add.
     */
    function addPermittedContractReceiverToAllowlist(uint120 id, address receiver) external override {
        _requireCallerOwnsPermittedContractReceiverAllowlist(id);

        if (!permittedContractReceiverAllowlists[id].add(receiver)) {
            revert CreatorTokenTransferValidator__AddressAlreadyAllowed();
        }

        emit AddedToAllowlist(AllowlistTypes.PermittedContractReceivers, id, receiver);
    }

    /**
     * @notice Remove an operator from an operator whitelist.
     *
     * @dev Throws when the caller does not own the specified operator whitelist.
     * @dev Throws when the operator is not in the specified operator whitelist.
     *
     * @dev <h4>Postconditions:</h4>
     *      1. The operator is removed from the specified operator whitelist.
     *      2. A `RemovedFromAllowlist` event is emitted.
     *
     * @param id       The id of the operator whitelist.
     * @param operator The address of the operator to remove.
     */
    function removeOperatorFromWhitelist(uint120 id, address operator) external override {
        _requireCallerOwnsOperatorWhitelist(id);

        if (!operatorWhitelists[id].remove(operator)) {
            revert CreatorTokenTransferValidator__AddressNotAllowed();
        }

        emit RemovedFromAllowlist(AllowlistTypes.Operators, id, operator);
    }

    /**
     * @notice Remove a contract address from a permitted contract receiver allowlist.
     * 
     * @dev Throws when the caller does not own the specified permitted contract receiver allowlist.
     * @dev Throws when the contract address is not in the specified permitted contract receiver allowlist.
     *
     * @dev <h4>Postconditions:</h4>
     *      1. The contract address is removed from the specified permitted contract receiver allowlist.
     *      2. A `RemovedFromAllowlist` event is emitted.
     *
     * @param id       The id of the permitted contract receiver allowlist.
     * @param receiver The address of the contract to remove.
     */
    function removePermittedContractReceiverFromAllowlist(uint120 id, address receiver) external override {
        _requireCallerOwnsPermittedContractReceiverAllowlist(id);

        if (!permittedContractReceiverAllowlists[id].remove(receiver)) {
            revert CreatorTokenTransferValidator__AddressNotAllowed();
        }

        emit RemovedFromAllowlist(AllowlistTypes.PermittedContractReceivers, id, receiver);
    }

    /**
     * @notice Get the security policy of the specified collection.
     * @param collection The address of the collection.
     * @return           The security policy of the specified collection, which includes:
     *                   Transfer security level, operator whitelist id, permitted contract receiver allowlist id
     */
    function getCollectionSecurityPolicy(address collection) 
        external view override returns (CollectionSecurityPolicy memory) {
        return collectionSecurityPolicies[collection];
    }

    /**
     * @notice Get the whitelisted operators in an operator whitelist.
     * @param id The id of the operator whitelist.
     * @return   An array of whitelisted operator addresses.
     */
    function getWhitelistedOperators(uint120 id) external view override returns (address[] memory) {
        return operatorWhitelists[id].values();
    }

    /**
     * @notice Get the permitted contract receivers in a permitted contract receiver allowlist.
     * @param id The id of the permitted contract receiver allowlist.
     * @return   An array of contract addresses is the permitted contract receiver allowlist.
     */
    function getPermittedContractReceivers(uint120 id) external view override returns (address[] memory) {
        return permittedContractReceiverAllowlists[id].values();
    }

    /**
     * @notice Check if an operator is in a specified operator whitelist.
     * @param id       The id of the operator whitelist.
     * @param operator The address of the operator to check.
     * @return         True if the operator is in the specified operator whitelist, false otherwise.
     */
    function isOperatorWhitelisted(uint120 id, address operator) public view override returns (bool) {
        return operatorWhitelists[id].contains(operator);
    }

    /**
     * @notice Check if a contract address is in a specified permitted contract receiver allowlist.
     * @param id       The id of the permitted contract receiver allowlist.
     * @param receiver The address of the contract to check.
     * @return         True if the contract address is in the specified permitted contract receiver allowlist, 
     *                 false otherwise.
     */
    function isContractReceiverPermitted(uint120 id, address receiver) public view override returns (bool) {
        return permittedContractReceiverAllowlists[id].contains(receiver);
    }

    /// @notice ERC-165 Interface Support
    function supportsInterface(bytes4 interfaceId) public view virtual override(EOARegistry, IERC165) returns (bool) {
        return
            interfaceId == type(ITransferValidator).interfaceId ||
            interfaceId == type(ITransferSecurityRegistry).interfaceId ||
            interfaceId == type(ICreatorTokenTransferValidator).interfaceId ||
            super.supportsInterface(interfaceId);
    }

    function _requireCallerIsNFTOrContractOwnerOrAdmin(address tokenAddress) internal view {
        bool callerHasPermissions = false;
        if(tokenAddress.code.length > 0) {
            callerHasPermissions = _msgSender() == tokenAddress;
            if(!callerHasPermissions) {

                try IOwnable(tokenAddress).owner() returns (address contractOwner) {
                    callerHasPermissions = _msgSender() == contractOwner;
                } catch {}

                if(!callerHasPermissions) {
                    try IAccessControl(tokenAddress).hasRole(DEFAULT_ACCESS_CONTROL_ADMIN_ROLE, _msgSender()) 
                        returns (bool callerIsContractAdmin) {
                        callerHasPermissions = callerIsContractAdmin;
                    } catch {}
                }
            }
        }

        if(!callerHasPermissions) {
            revert CreatorTokenTransferValidator__CallerMustHaveElevatedPermissionsForSpecifiedNFT();
        }
    }

    function _reassignOwnershipOfOperatorWhitelist(uint120 id, address newOwner) private {
        _requireCallerOwnsOperatorWhitelist(id);
        operatorWhitelistOwners[id] = newOwner;
        emit ReassignedAllowlistOwnership(AllowlistTypes.Operators, id, newOwner);
    }

    function _reassignOwnershipOfPermittedContractReceiverAllowlist(uint120 id, address newOwner) private {
        _requireCallerOwnsPermittedContractReceiverAllowlist(id);
        permittedContractReceiverAllowlistOwners[id] = newOwner;
        emit ReassignedAllowlistOwnership(AllowlistTypes.PermittedContractReceivers, id, newOwner);
    }

    function _requireCallerOwnsOperatorWhitelist(uint120 id) private view {
        if (_msgSender() != operatorWhitelistOwners[id]) {
            revert CreatorTokenTransferValidator__CallerDoesNotOwnAllowlist();
        }
    }

    function _requireCallerOwnsPermittedContractReceiverAllowlist(uint120 id) private view {
        if (_msgSender() != permittedContractReceiverAllowlistOwners[id]) {
            revert CreatorTokenTransferValidator__CallerDoesNotOwnAllowlist();
        }
    }
}

File 2 of 17 : ICreatorTokenTransferValidator.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import "./IEOARegistry.sol";
import "./ITransferSecurityRegistry.sol";
import "./ITransferValidator.sol";

interface ICreatorTokenTransferValidator is ITransferSecurityRegistry, ITransferValidator, IEOARegistry {}

File 3 of 17 : IEOARegistry.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import "@openzeppelin/contracts/utils/introspection/IERC165.sol";

interface IEOARegistry is IERC165 {
    function isVerifiedEOA(address account) external view returns (bool);
}

File 4 of 17 : IOwnable.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

interface IOwnable {
    function owner() external view returns (address);
}

File 5 of 17 : ITransferSecurityRegistry.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import "../utils/TransferPolicy.sol";

interface ITransferSecurityRegistry {
    event AddedToAllowlist(AllowlistTypes indexed kind, uint256 indexed id, address indexed account);
    event CreatedAllowlist(AllowlistTypes indexed kind, uint256 indexed id, string indexed name);
    event ReassignedAllowlistOwnership(AllowlistTypes indexed kind, uint256 indexed id, address indexed newOwner);
    event RemovedFromAllowlist(AllowlistTypes indexed kind, uint256 indexed id, address indexed account);
    event SetAllowlist(AllowlistTypes indexed kind, address indexed collection, uint120 indexed id);
    event SetTransferSecurityLevel(address indexed collection, TransferSecurityLevels level);

    function createOperatorWhitelist(string calldata name) external returns (uint120);
    function createPermittedContractReceiverAllowlist(string calldata name) external returns (uint120);
    function reassignOwnershipOfOperatorWhitelist(uint120 id, address newOwner) external;
    function reassignOwnershipOfPermittedContractReceiverAllowlist(uint120 id, address newOwner) external;
    function renounceOwnershipOfOperatorWhitelist(uint120 id) external;
    function renounceOwnershipOfPermittedContractReceiverAllowlist(uint120 id) external;
    function setTransferSecurityLevelOfCollection(address collection, TransferSecurityLevels level) external;
    function setOperatorWhitelistOfCollection(address collection, uint120 id) external;
    function setPermittedContractReceiverAllowlistOfCollection(address collection, uint120 id) external;
    function addOperatorToWhitelist(uint120 id, address operator) external;
    function addPermittedContractReceiverToAllowlist(uint120 id, address receiver) external;
    function removeOperatorFromWhitelist(uint120 id, address operator) external;
    function removePermittedContractReceiverFromAllowlist(uint120 id, address receiver) external;
    function getCollectionSecurityPolicy(address collection) external view returns (CollectionSecurityPolicy memory);
    function getWhitelistedOperators(uint120 id) external view returns (address[] memory);
    function getPermittedContractReceivers(uint120 id) external view returns (address[] memory);
    function isOperatorWhitelisted(uint120 id, address operator) external view returns (bool);
    function isContractReceiverPermitted(uint120 id, address receiver) external view returns (bool);
}

File 6 of 17 : ITransferValidator.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import "../utils/TransferPolicy.sol";

interface ITransferValidator {
    function applyCollectionTransferPolicy(address caller, address from, address to) external view;
}

File 7 of 17 : EOARegistry.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.4;

import "../interfaces/IEOARegistry.sol";
import "@openzeppelin/contracts/utils/Context.sol";
import "@openzeppelin/contracts/utils/introspection/ERC165.sol";
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";


error CallerDidNotSignTheMessage();
error SignatureAlreadyVerified();

/**
 * @title EOARegistry
 * @author Limit Break, Inc.
 * @notice A registry that may be used globally by any smart contract that limits contract interactions to verified EOA addresses only.
 * @dev Take care and carefully consider whether or not to use this. Restricting operations to EOA only accounts can break Defi composability, 
 * so if Defi composability is an objective, this is not a good option.  Be advised that in the future, EOA accounts might not be a thing
 * but this is yet to be determined.  See https://eips.ethereum.org/EIPS/eip-4337 for more information.
 */
contract EOARegistry is Context, ERC165, IEOARegistry {

    /// @dev A pre-cached signed message hash used for gas-efficient signature recovery
    bytes32 immutable private signedMessageHash;

    /// @dev The plain text message to sign for signature verification
    string constant public MESSAGE_TO_SIGN = "EOA";

    /// @dev Mapping of accounts that to signature verification status
    mapping (address => bool) private eoaSignatureVerified;

    /// @dev Emitted whenever a user verifies that they are an EOA by submitting their signature.
    event VerifiedEOASignature(address indexed account);

    constructor() {
        signedMessageHash = ECDSA.toEthSignedMessageHash(bytes(MESSAGE_TO_SIGN));
    }

    /// @notice Allows a user to verify an ECDSA signature to definitively prove they are an EOA account.
    ///
    /// Throws when the caller has already verified their signature.
    /// Throws when the caller did not sign the message.
    ///
    /// Postconditions:
    /// ---------------
    /// The verified signature mapping has been updated to `true` for the caller.
    function verifySignature(bytes calldata signature) external {
        if(eoaSignatureVerified[_msgSender()]) {
            revert SignatureAlreadyVerified();
        }

        if(_msgSender() != ECDSA.recover(signedMessageHash, signature)) {
            revert CallerDidNotSignTheMessage();
        }

        eoaSignatureVerified[_msgSender()] = true;

        emit VerifiedEOASignature(_msgSender());
    }

    /// @notice Allows a user to verify an ECDSA signature to definitively prove they are an EOA account.
    /// This version is passed the v, r, s components of the signature, and is slightly more gas efficient than
    /// calculating the v, r, s components on-chain.
    ///
    /// Throws when the caller has already verified their signature.
    /// Throws when the caller did not sign the message.
    ///
    /// Postconditions:
    /// ---------------
    /// The verified signature mapping has been updated to `true` for the caller.
    function verifySignatureVRS(uint8 v, bytes32 r, bytes32 s) external {
        if(eoaSignatureVerified[msg.sender]) {
            revert SignatureAlreadyVerified();
        }

        if(msg.sender != ECDSA.recover(signedMessageHash, v, r, s)) {
            revert CallerDidNotSignTheMessage();
        }

        eoaSignatureVerified[msg.sender] = true;

        emit VerifiedEOASignature(msg.sender);
    }

    /// @notice Returns true if the specified account has verified a signature on this registry, false otherwise.
    function isVerifiedEOA(address account) public view override returns (bool) {
        return eoaSignatureVerified[account];
    }

    /// @dev ERC-165 interface support
    function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
        return
            interfaceId == type(IEOARegistry).interfaceId ||
            super.supportsInterface(interfaceId);
    }
}

File 8 of 17 : TransferPolicy.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

enum AllowlistTypes {
    Operators,
    PermittedContractReceivers
}

enum ReceiverConstraints {
    None,
    NoCode,
    EOA
}

enum CallerConstraints {
    None,
    OperatorWhitelistEnableOTC,
    OperatorWhitelistDisableOTC
}

enum StakerConstraints {
    None,
    CallerIsTxOrigin,
    EOA
}

enum TransferSecurityLevels {
    Zero,
    One,
    Two,
    Three,
    Four,
    Five,
    Six
}

struct TransferSecurityPolicy {
    CallerConstraints callerConstraints;
    ReceiverConstraints receiverConstraints;
}

struct CollectionSecurityPolicy {
    TransferSecurityLevels transferSecurityLevel;
    uint120 operatorWhitelistId;
    uint120 permittedContractReceiversId;
}

File 9 of 17 : IAccessControl.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)

pragma solidity ^0.8.0;

/**
 * @dev External interface of AccessControl declared to support ERC165 detection.
 */
interface IAccessControl {
    /**
     * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
     *
     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
     * {RoleAdminChanged} not being emitted signaling this.
     *
     * _Available since v3.1._
     */
    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);

    /**
     * @dev Emitted when `account` is granted `role`.
     *
     * `sender` is the account that originated the contract call, an admin role
     * bearer except when using {AccessControl-_setupRole}.
     */
    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Emitted when `account` is revoked `role`.
     *
     * `sender` is the account that originated the contract call:
     *   - if using `revokeRole`, it is the admin role bearer
     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
     */
    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) external view returns (bool);

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {AccessControl-_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) external view returns (bytes32);

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function grantRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function revokeRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been granted `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `account`.
     */
    function renounceRole(bytes32 role, address account) external;
}

File 10 of 17 : Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol)

pragma solidity ^0.8.0;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}

File 11 of 17 : ECDSA.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/ECDSA.sol)

pragma solidity ^0.8.0;

import "../Strings.sol";

/**
 * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
 *
 * These functions can be used to verify that a message was signed by the holder
 * of the private keys of a given address.
 */
library ECDSA {
    enum RecoverError {
        NoError,
        InvalidSignature,
        InvalidSignatureLength,
        InvalidSignatureS,
        InvalidSignatureV // Deprecated in v4.8
    }

    function _throwError(RecoverError error) private pure {
        if (error == RecoverError.NoError) {
            return; // no error: do nothing
        } else if (error == RecoverError.InvalidSignature) {
            revert("ECDSA: invalid signature");
        } else if (error == RecoverError.InvalidSignatureLength) {
            revert("ECDSA: invalid signature length");
        } else if (error == RecoverError.InvalidSignatureS) {
            revert("ECDSA: invalid signature 's' value");
        }
    }

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature` or error string. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {toEthSignedMessageHash} on it.
     *
     * Documentation for signature generation:
     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
     *
     * _Available since v4.3._
     */
    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
        if (signature.length == 65) {
            bytes32 r;
            bytes32 s;
            uint8 v;
            // ecrecover takes the signature parameters, and the only way to get them
            // currently is to use assembly.
            /// @solidity memory-safe-assembly
            assembly {
                r := mload(add(signature, 0x20))
                s := mload(add(signature, 0x40))
                v := byte(0, mload(add(signature, 0x60)))
            }
            return tryRecover(hash, v, r, s);
        } else {
            return (address(0), RecoverError.InvalidSignatureLength);
        }
    }

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature`. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {toEthSignedMessageHash} on it.
     */
    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, signature);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
     *
     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
     *
     * _Available since v4.3._
     */
    function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError) {
        bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
        uint8 v = uint8((uint256(vs) >> 255) + 27);
        return tryRecover(hash, v, r, s);
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
     *
     * _Available since v4.2._
     */
    function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, r, vs);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,
     * `r` and `s` signature fields separately.
     *
     * _Available since v4.3._
     */
    function tryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address, RecoverError) {
        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
        // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
        // signatures from current libraries generate a unique signature with an s-value in the lower half order.
        //
        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
        // these malleable signatures as well.
        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
            return (address(0), RecoverError.InvalidSignatureS);
        }

        // If the signature is valid (and not malleable), return the signer address
        address signer = ecrecover(hash, v, r, s);
        if (signer == address(0)) {
            return (address(0), RecoverError.InvalidSignature);
        }

        return (signer, RecoverError.NoError);
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `v`,
     * `r` and `s` signature fields separately.
     */
    function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Returns an Ethereum Signed Message, created from a `hash`. This
     * produces hash corresponding to the one signed with the
     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
     * JSON-RPC method as part of EIP-191.
     *
     * See {recover}.
     */
    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 message) {
        // 32 is the length in bytes of hash,
        // enforced by the type signature above
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, "\x19Ethereum Signed Message:\n32")
            mstore(0x1c, hash)
            message := keccak256(0x00, 0x3c)
        }
    }

    /**
     * @dev Returns an Ethereum Signed Message, created from `s`. This
     * produces hash corresponding to the one signed with the
     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
     * JSON-RPC method as part of EIP-191.
     *
     * See {recover}.
     */
    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s));
    }

    /**
     * @dev Returns an Ethereum Signed Typed Data, created from a
     * `domainSeparator` and a `structHash`. This produces hash corresponding
     * to the one signed with the
     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
     * JSON-RPC method as part of EIP-712.
     *
     * See {recover}.
     */
    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 data) {
        /// @solidity memory-safe-assembly
        assembly {
            let ptr := mload(0x40)
            mstore(ptr, "\x19\x01")
            mstore(add(ptr, 0x02), domainSeparator)
            mstore(add(ptr, 0x22), structHash)
            data := keccak256(ptr, 0x42)
        }
    }

    /**
     * @dev Returns an Ethereum Signed Data with intended validator, created from a
     * `validator` and `data` according to the version 0 of EIP-191.
     *
     * See {recover}.
     */
    function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked("\x19\x00", validator, data));
    }
}

File 12 of 17 : ERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)

pragma solidity ^0.8.0;

import "./IERC165.sol";

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
 * for the additional interface id that will be supported. For example:
 *
 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```
 *
 * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
 */
abstract contract ERC165 is IERC165 {
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}

File 13 of 17 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

File 14 of 17 : Math.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)

pragma solidity ^0.8.0;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    enum Rounding {
        Down, // Toward negative infinity
        Up, // Toward infinity
        Zero // Toward zero
    }

    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a > b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow.
        return (a & b) + (a ^ b) / 2;
    }

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds up instead
     * of rounding down.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a == 0 ? 0 : (a - 1) / b + 1;
    }

    /**
     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
     * with further edits by Uniswap Labs also under MIT license.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
        unchecked {
            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
            // variables such that product = prod1 * 2^256 + prod0.
            uint256 prod0; // Least significant 256 bits of the product
            uint256 prod1; // Most significant 256 bits of the product
            assembly {
                let mm := mulmod(x, y, not(0))
                prod0 := mul(x, y)
                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
            }

            // Handle non-overflow cases, 256 by 256 division.
            if (prod1 == 0) {
                // Solidity will revert if denominator == 0, unlike the div opcode on its own.
                // The surrounding unchecked block does not change this fact.
                // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
                return prod0 / denominator;
            }

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            require(denominator > prod1, "Math: mulDiv overflow");

            ///////////////////////////////////////////////
            // 512 by 256 division.
            ///////////////////////////////////////////////

            // Make division exact by subtracting the remainder from [prod1 prod0].
            uint256 remainder;
            assembly {
                // Compute remainder using mulmod.
                remainder := mulmod(x, y, denominator)

                // Subtract 256 bit number from 512 bit number.
                prod1 := sub(prod1, gt(remainder, prod0))
                prod0 := sub(prod0, remainder)
            }

            // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
            // See https://cs.stackexchange.com/q/138556/92363.

            // Does not overflow because the denominator cannot be zero at this stage in the function.
            uint256 twos = denominator & (~denominator + 1);
            assembly {
                // Divide denominator by twos.
                denominator := div(denominator, twos)

                // Divide [prod1 prod0] by twos.
                prod0 := div(prod0, twos)

                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                twos := add(div(sub(0, twos), twos), 1)
            }

            // Shift in bits from prod1 into prod0.
            prod0 |= prod1 * twos;

            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
            // four bits. That is, denominator * inv = 1 mod 2^4.
            uint256 inverse = (3 * denominator) ^ 2;

            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
            // in modular arithmetic, doubling the correct bits in each step.
            inverse *= 2 - denominator * inverse; // inverse mod 2^8
            inverse *= 2 - denominator * inverse; // inverse mod 2^16
            inverse *= 2 - denominator * inverse; // inverse mod 2^32
            inverse *= 2 - denominator * inverse; // inverse mod 2^64
            inverse *= 2 - denominator * inverse; // inverse mod 2^128
            inverse *= 2 - denominator * inverse; // inverse mod 2^256

            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
            // is no longer required.
            result = prod0 * inverse;
            return result;
        }
    }

    /**
     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
        uint256 result = mulDiv(x, y, denominator);
        if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
            result += 1;
        }
        return result;
    }

    /**
     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
     *
     * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
     */
    function sqrt(uint256 a) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
        //
        // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
        //
        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
        //
        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
        uint256 result = 1 << (log2(a) >> 1);

        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
        // into the expected uint128 result.
        unchecked {
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            return min(result, a / result);
        }
    }

    /**
     * @notice Calculates sqrt(a), following the selected rounding direction.
     */
    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = sqrt(a);
            return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 2, rounded down, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 128;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 64;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 32;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 16;
            }
            if (value >> 8 > 0) {
                value >>= 8;
                result += 8;
            }
            if (value >> 4 > 0) {
                value >>= 4;
                result += 4;
            }
            if (value >> 2 > 0) {
                value >>= 2;
                result += 2;
            }
            if (value >> 1 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log2(value);
            return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 10, rounded down, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >= 10 ** 64) {
                value /= 10 ** 64;
                result += 64;
            }
            if (value >= 10 ** 32) {
                value /= 10 ** 32;
                result += 32;
            }
            if (value >= 10 ** 16) {
                value /= 10 ** 16;
                result += 16;
            }
            if (value >= 10 ** 8) {
                value /= 10 ** 8;
                result += 8;
            }
            if (value >= 10 ** 4) {
                value /= 10 ** 4;
                result += 4;
            }
            if (value >= 10 ** 2) {
                value /= 10 ** 2;
                result += 2;
            }
            if (value >= 10 ** 1) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log10(value);
            return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 256, rounded down, of a positive value.
     * Returns 0 if given 0.
     *
     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
     */
    function log256(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 16;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 8;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 4;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 2;
            }
            if (value >> 8 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 256, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log256(value);
            return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
        }
    }
}

File 15 of 17 : SignedMath.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol)

pragma solidity ^0.8.0;

/**
 * @dev Standard signed math utilities missing in the Solidity language.
 */
library SignedMath {
    /**
     * @dev Returns the largest of two signed numbers.
     */
    function max(int256 a, int256 b) internal pure returns (int256) {
        return a > b ? a : b;
    }

    /**
     * @dev Returns the smallest of two signed numbers.
     */
    function min(int256 a, int256 b) internal pure returns (int256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two signed numbers without overflow.
     * The result is rounded towards zero.
     */
    function average(int256 a, int256 b) internal pure returns (int256) {
        // Formula from the book "Hacker's Delight"
        int256 x = (a & b) + ((a ^ b) >> 1);
        return x + (int256(uint256(x) >> 255) & (a ^ b));
    }

    /**
     * @dev Returns the absolute unsigned value of a signed value.
     */
    function abs(int256 n) internal pure returns (uint256) {
        unchecked {
            // must be unchecked in order to support `n = type(int256).min`
            return uint256(n >= 0 ? n : -n);
        }
    }
}

File 16 of 17 : Strings.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol)

pragma solidity ^0.8.0;

import "./math/Math.sol";
import "./math/SignedMath.sol";

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant _SYMBOLS = "0123456789abcdef";
    uint8 private constant _ADDRESS_LENGTH = 20;

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        unchecked {
            uint256 length = Math.log10(value) + 1;
            string memory buffer = new string(length);
            uint256 ptr;
            /// @solidity memory-safe-assembly
            assembly {
                ptr := add(buffer, add(32, length))
            }
            while (true) {
                ptr--;
                /// @solidity memory-safe-assembly
                assembly {
                    mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
                }
                value /= 10;
                if (value == 0) break;
            }
            return buffer;
        }
    }

    /**
     * @dev Converts a `int256` to its ASCII `string` decimal representation.
     */
    function toString(int256 value) internal pure returns (string memory) {
        return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value))));
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        unchecked {
            return toHexString(value, Math.log256(value) + 1);
        }
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
     */
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
        bytes memory buffer = new bytes(2 * length + 2);
        buffer[0] = "0";
        buffer[1] = "x";
        for (uint256 i = 2 * length + 1; i > 1; --i) {
            buffer[i] = _SYMBOLS[value & 0xf];
            value >>= 4;
        }
        require(value == 0, "Strings: hex length insufficient");
        return string(buffer);
    }

    /**
     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
     */
    function toHexString(address addr) internal pure returns (string memory) {
        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
    }

    /**
     * @dev Returns true if the two strings are equal.
     */
    function equal(string memory a, string memory b) internal pure returns (bool) {
        return keccak256(bytes(a)) == keccak256(bytes(b));
    }
}

File 17 of 17 : EnumerableSet.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.

pragma solidity ^0.8.0;

/**
 * @dev Library for managing
 * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
 * types.
 *
 * Sets have the following properties:
 *
 * - Elements are added, removed, and checked for existence in constant time
 * (O(1)).
 * - Elements are enumerated in O(n). No guarantees are made on the ordering.
 *
 * ```solidity
 * contract Example {
 *     // Add the library methods
 *     using EnumerableSet for EnumerableSet.AddressSet;
 *
 *     // Declare a set state variable
 *     EnumerableSet.AddressSet private mySet;
 * }
 * ```
 *
 * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
 * and `uint256` (`UintSet`) are supported.
 *
 * [WARNING]
 * ====
 * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
 * unusable.
 * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
 *
 * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
 * array of EnumerableSet.
 * ====
 */
library EnumerableSet {
    // To implement this library for multiple types with as little code
    // repetition as possible, we write it in terms of a generic Set type with
    // bytes32 values.
    // The Set implementation uses private functions, and user-facing
    // implementations (such as AddressSet) are just wrappers around the
    // underlying Set.
    // This means that we can only create new EnumerableSets for types that fit
    // in bytes32.

    struct Set {
        // Storage of set values
        bytes32[] _values;
        // Position of the value in the `values` array, plus 1 because index 0
        // means a value is not in the set.
        mapping(bytes32 => uint256) _indexes;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function _add(Set storage set, bytes32 value) private returns (bool) {
        if (!_contains(set, value)) {
            set._values.push(value);
            // The value is stored at length-1, but we add 1 to all indexes
            // and use 0 as a sentinel value
            set._indexes[value] = set._values.length;
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function _remove(Set storage set, bytes32 value) private returns (bool) {
        // We read and store the value's index to prevent multiple reads from the same storage slot
        uint256 valueIndex = set._indexes[value];

        if (valueIndex != 0) {
            // Equivalent to contains(set, value)
            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
            // the array, and then remove the last element (sometimes called as 'swap and pop').
            // This modifies the order of the array, as noted in {at}.

            uint256 toDeleteIndex = valueIndex - 1;
            uint256 lastIndex = set._values.length - 1;

            if (lastIndex != toDeleteIndex) {
                bytes32 lastValue = set._values[lastIndex];

                // Move the last value to the index where the value to delete is
                set._values[toDeleteIndex] = lastValue;
                // Update the index for the moved value
                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex
            }

            // Delete the slot where the moved value was stored
            set._values.pop();

            // Delete the index for the deleted slot
            delete set._indexes[value];

            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function _contains(Set storage set, bytes32 value) private view returns (bool) {
        return set._indexes[value] != 0;
    }

    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function _length(Set storage set) private view returns (uint256) {
        return set._values.length;
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function _at(Set storage set, uint256 index) private view returns (bytes32) {
        return set._values[index];
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function _values(Set storage set) private view returns (bytes32[] memory) {
        return set._values;
    }

    // Bytes32Set

    struct Bytes32Set {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _add(set._inner, value);
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _remove(set._inner, value);
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
        return _contains(set._inner, value);
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(Bytes32Set storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
        return _at(set._inner, index);
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
        bytes32[] memory store = _values(set._inner);
        bytes32[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }

    // AddressSet

    struct AddressSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(AddressSet storage set, address value) internal returns (bool) {
        return _add(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(AddressSet storage set, address value) internal returns (bool) {
        return _remove(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(AddressSet storage set, address value) internal view returns (bool) {
        return _contains(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(AddressSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(AddressSet storage set, uint256 index) internal view returns (address) {
        return address(uint160(uint256(_at(set._inner, index))));
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(AddressSet storage set) internal view returns (address[] memory) {
        bytes32[] memory store = _values(set._inner);
        address[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }

    // UintSet

    struct UintSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(UintSet storage set, uint256 value) internal returns (bool) {
        return _add(set._inner, bytes32(value));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(UintSet storage set, uint256 value) internal returns (bool) {
        return _remove(set._inner, bytes32(value));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(UintSet storage set, uint256 value) internal view returns (bool) {
        return _contains(set._inner, bytes32(value));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(UintSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(UintSet storage set, uint256 index) internal view returns (uint256) {
        return uint256(_at(set._inner, index));
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(UintSet storage set) internal view returns (uint256[] memory) {
        bytes32[] memory store = _values(set._inner);
        uint256[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "evmVersion": "paris",
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"defaultOwner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"CallerDidNotSignTheMessage","type":"error"},{"inputs":[],"name":"CreatorTokenTransferValidator__AddressAlreadyAllowed","type":"error"},{"inputs":[],"name":"CreatorTokenTransferValidator__AddressNotAllowed","type":"error"},{"inputs":[],"name":"CreatorTokenTransferValidator__AllowlistDoesNotExist","type":"error"},{"inputs":[],"name":"CreatorTokenTransferValidator__AllowlistOwnershipCannotBeTransferredToZeroAddress","type":"error"},{"inputs":[],"name":"CreatorTokenTransferValidator__CallerDoesNotOwnAllowlist","type":"error"},{"inputs":[],"name":"CreatorTokenTransferValidator__CallerMustBeWhitelistedOperator","type":"error"},{"inputs":[],"name":"CreatorTokenTransferValidator__CallerMustHaveElevatedPermissionsForSpecifiedNFT","type":"error"},{"inputs":[],"name":"CreatorTokenTransferValidator__ReceiverMustNotHaveDeployedCode","type":"error"},{"inputs":[],"name":"CreatorTokenTransferValidator__ReceiverProofOfEOASignatureUnverified","type":"error"},{"inputs":[],"name":"SignatureAlreadyVerified","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"enum AllowlistTypes","name":"kind","type":"uint8"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"AddedToAllowlist","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"enum AllowlistTypes","name":"kind","type":"uint8"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"string","name":"name","type":"string"}],"name":"CreatedAllowlist","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"enum AllowlistTypes","name":"kind","type":"uint8"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"ReassignedAllowlistOwnership","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"enum AllowlistTypes","name":"kind","type":"uint8"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"RemovedFromAllowlist","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"enum AllowlistTypes","name":"kind","type":"uint8"},{"indexed":true,"internalType":"address","name":"collection","type":"address"},{"indexed":true,"internalType":"uint120","name":"id","type":"uint120"}],"name":"SetAllowlist","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"collection","type":"address"},{"indexed":false,"internalType":"enum TransferSecurityLevels","name":"level","type":"uint8"}],"name":"SetTransferSecurityLevel","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"VerifiedEOASignature","type":"event"},{"inputs":[],"name":"DEFAULT_TRANSFER_SECURITY_LEVEL","outputs":[{"internalType":"enum TransferSecurityLevels","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MESSAGE_TO_SIGN","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint120","name":"id","type":"uint120"},{"internalType":"address","name":"operator","type":"address"}],"name":"addOperatorToWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint120","name":"id","type":"uint120"},{"internalType":"address","name":"receiver","type":"address"}],"name":"addPermittedContractReceiverToAllowlist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"caller","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"}],"name":"applyCollectionTransferPolicy","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"name","type":"string"}],"name":"createOperatorWhitelist","outputs":[{"internalType":"uint120","name":"","type":"uint120"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"name","type":"string"}],"name":"createPermittedContractReceiverAllowlist","outputs":[{"internalType":"uint120","name":"","type":"uint120"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"}],"name":"getCollectionSecurityPolicy","outputs":[{"components":[{"internalType":"enum TransferSecurityLevels","name":"transferSecurityLevel","type":"uint8"},{"internalType":"uint120","name":"operatorWhitelistId","type":"uint120"},{"internalType":"uint120","name":"permittedContractReceiversId","type":"uint120"}],"internalType":"struct CollectionSecurityPolicy","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint120","name":"id","type":"uint120"}],"name":"getPermittedContractReceivers","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint120","name":"id","type":"uint120"}],"name":"getWhitelistedOperators","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint120","name":"id","type":"uint120"},{"internalType":"address","name":"receiver","type":"address"}],"name":"isContractReceiverPermitted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint120","name":"id","type":"uint120"},{"internalType":"address","name":"operator","type":"address"}],"name":"isOperatorWhitelisted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"isVerifiedEOA","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint120","name":"","type":"uint120"}],"name":"operatorWhitelistOwners","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint120","name":"","type":"uint120"}],"name":"permittedContractReceiverAllowlistOwners","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint120","name":"id","type":"uint120"},{"internalType":"address","name":"newOwner","type":"address"}],"name":"reassignOwnershipOfOperatorWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint120","name":"id","type":"uint120"},{"internalType":"address","name":"newOwner","type":"address"}],"name":"reassignOwnershipOfPermittedContractReceiverAllowlist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint120","name":"id","type":"uint120"},{"internalType":"address","name":"operator","type":"address"}],"name":"removeOperatorFromWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint120","name":"id","type":"uint120"},{"internalType":"address","name":"receiver","type":"address"}],"name":"removePermittedContractReceiverFromAllowlist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint120","name":"id","type":"uint120"}],"name":"renounceOwnershipOfOperatorWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint120","name":"id","type":"uint120"}],"name":"renounceOwnershipOfPermittedContractReceiverAllowlist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"},{"internalType":"uint120","name":"id","type":"uint120"}],"name":"setOperatorWhitelistOfCollection","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"},{"internalType":"uint120","name":"id","type":"uint120"}],"name":"setPermittedContractReceiverAllowlistOfCollection","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"},{"internalType":"enum TransferSecurityLevels","name":"level","type":"uint8"}],"name":"setTransferSecurityLevelOfCollection","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum TransferSecurityLevels","name":"","type":"uint8"}],"name":"transferSecurityPolicies","outputs":[{"internalType":"enum CallerConstraints","name":"callerConstraints","type":"uint8"},{"internalType":"enum ReceiverConstraints","name":"receiverConstraints","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"verifySignature","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"verifySignatureVRS","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60a06040523480156200001157600080fd5b506040516200251b3803806200251b833981016040819052620000349162000726565b604080518082019091526003815262454f4160e81b602082015262000059906200055e565b608052604080518082019091526000808252602080830182905290805260029081905281517fac33ff75c19e70fe83507db0d683fd3465c996598dc972688b7ace676c89077b80549092839160ff1916906001908490811115620000c157620000c162000758565b021790555060208201518154829061ff001916610100836002811115620000ec57620000ec62000758565b021790555050604080518082019091526001808252600060208301819052919250600291908152602081019190915260400160002081518154829060ff1916600183600281111562000142576200014262000758565b021790555060208201518154829061ff0019166101008360028111156200016d576200016d62000758565b021790555050604080518082019091526002808252600060208084018290529082905281905281517f679795a0195a1b76cdebb7c51d74e058aee92919b8c3389af86ef24535e8a28c8054939450929091839160ff1916906001908490811115620001dc57620001dc62000758565b021790555060208201518154829061ff00191661010083600281111562000207576200020762000758565b021790555050604080518082019091526001808252602082015290506002600060038152602081019190915260400160002081518154829060ff191660018360028111156200025a576200025a62000758565b021790555060208201518154829061ff00191661010083600281111562000285576200028562000758565b02179055505060408051808201909152600180825260026020808401829052600460005281905282517fee60d0579bcffd98e668647d59fec1ff86a7fb340ce572e844f234ae73a6918f8054949550939092849260ff19909216918490811115620002f457620002f462000758565b021790555060208201518154829061ff0019166101008360028111156200031f576200031f62000758565b02179055505060408051808201909152600280825260016020830152909150600060058152602081019190915260400160002081518154829060ff1916600183600281111562000373576200037362000758565b021790555060208201518154829061ff0019166101008360028111156200039e576200039e62000758565b0217905550506040805180820190915260028082526020808301829052600660005281905281517f59dd4b18488d12f51eda69757a0ed42a2010c14b564330cc74a06895e60c077b8054939450929091839160ff19169060019084908111156200040c576200040c62000758565b021790555060208201518154829061ff00191661010083600281111562000437576200043762000758565b021790555050600180546000925082906200045b906001600160781b03166200076e565b82546001600160781b038083166101009490940a848102910219909116179092556000908152600460205260409081902080546001600160a01b0386166001600160a01b031990911617905551909150620004d9907f44454641554c54204f50455241544f522057484954454c4953540000000000008152601a0190565b6040519081900390206001600160781b03821660006040517fae6fa502f14a93bc6996eabc5c1ebc61072d478b73fb03333a34754d31aa146d90600090a46001600160a01b0382166001600160781b03821660006040517f3ba9771b33f74e565d2184fa864cb3777a52a873cca631683d3e5d696b877c5b90600090a4505062000846565b6000620005728251620005a360201b60201c565b8260405160200162000586929190620007d1565b604051602081830303815290604052805190602001209050919050565b60606000620005b2836200063c565b60010190506000816001600160401b03811115620005d457620005d462000830565b6040519080825280601f01601f191660200182016040528015620005ff576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a85049450846200060957509392505050565b6000807a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000831062000686577a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000830492506040015b6d04ee2d6d415b85acef81000000008310620006b3576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc100008310620006d257662386f26fc10000830492506010015b6305f5e1008310620006eb576305f5e100830492506008015b61271083106200070057612710830492506004015b6064831062000713576064830492506002015b600a831062000720576001015b92915050565b6000602082840312156200073957600080fd5b81516001600160a01b03811681146200075157600080fd5b9392505050565b634e487b7160e01b600052602160045260246000fd5b60006001600160781b038281166002600160781b03198101620007a157634e487b7160e01b600052601160045260246000fd5b6001019392505050565b60005b83811015620007c8578181015183820152602001620007ae565b50506000910152565b7f19457468657265756d205369676e6564204d6573736167653a0a0000000000008152600083516200080b81601a850160208801620007ab565b8351908301906200082481601a840160208801620007ab565b01601a01949350505050565b634e487b7160e01b600052604160045260246000fd5b608051611cb26200086960003960008181610c170152610fa80152611cb26000f3fe608060405234801561001057600080fd5b50600436106101c45760003560e01c80637c58813c116100f9578063b6567f2211610097578063da0194c011610071578063da0194c01461047c578063e30cd5e11461048f578063f80af984146104a2578063fec1d643146104b557600080fd5b8063b6567f2214610436578063b955455214610449578063d72dde5e1461046957600080fd5b80639445f530116100d35780639445f530146103c357806399f9a678146103d65780639e814cae146103e9578063a9f138eb1461042357600080fd5b80637c58813c1461035b57806389a9c855146103845780638d744314146103b057600080fd5b8063285fb8c811610166578063372fb54d11610140578063372fb54d146102f75780633fe5df991461030a578063501b7d2e1461031d578063731fb9d81461034857600080fd5b8063285fb8c8146102a257806333f0901b146102b557806334778f6a146102e457600080fd5b806317e94a6c116101a257806317e94a6c1461024757806318fbf6fe146102675780631c33b3281461027a5780632304aa021461028f57600080fd5b806301ffc9a7146101c95780630fac9f76146101f15780631390a2c214610232575b600080fd5b6101dc6101d736600461180e565b6104c8565b60405190151581526020015b60405180910390f35b61021a6101ff366004611854565b6004602052600090815260409020546001600160a01b031681565b6040516001600160a01b0390911681526020016101e8565b610245610240366004611884565b610521565b005b61025a610255366004611854565b6105ad565b6040516101e891906118bb565b610245610275366004611884565b6105d1565b610282600081565b6040516101e89190611932565b61024561029d366004611940565b610606565b6102456102b0366004611975565b6106b3565b6102d760405180604001604052806003815260200162454f4160e81b81525081565b6040516101e891906119c0565b6102456102f2366004611854565b610956565b610245610305366004611884565b610964565b61025a610318366004611854565b6109c7565b61033061032b366004611a50565b6109eb565b6040516001600160781b0390911681526020016101e8565b610245610356366004611884565b610af7565b61021a610369366004611854565b6005602052600090815260409020546001600160a01b031681565b6101dc610392366004611a92565b6001600160a01b031660009081526020819052604090205460ff1690565b6102456103be366004611940565b610b28565b6101dc6103d1366004611884565b610bb8565b6102456103e4366004611aaf565b610be1565b6104156103f7366004611af9565b60026020526000908152604090205460ff8082169161010090041682565b6040516101e8929190611b24565b610245610431366004611854565b610cb4565b610330610444366004611a50565b610cbf565b61045c610457366004611a92565b610da6565b6040516101e89190611b4a565b6101dc610477366004611884565b610e3c565b61024561048a366004611b86565b610e5e565b61024561049d366004611884565b610ee6565b6102456104b0366004611a50565b610f72565b6102456104c3366004611884565b611078565b60006001600160e01b0319821663050bf71960e31b14806104f957506001600160e01b03198216638f1d689960e01b145b8061050c57506001600160e01b03198216155b8061051b575061051b826110db565b92915050565b61052a82611110565b6001600160781b038216600090815260066020526040902061054c908261115b565b61056957604051633e7dfd2360e21b815260040160405180910390fd5b6001600160a01b0381166001600160781b03831660005b6040517f5d23e0e2d8347166058712ba9dceec21d6edd7b466a0d13cb759d730bd56039090600090a45050565b6001600160781b038116600090815260076020526040902060609061051b90611170565b6001600160a01b0381166105f8576040516335c410ff60e21b815260040160405180910390fd5b610602828261117d565b5050565b61060f826111eb565b6001546001600160781b03908116908216111561063f576040516311630a7b60e11b815260040160405180910390fd5b6001600160a01b038216600081815260036020526040812080546fffffffffffffffffffffffffffffff0019166101006001600160781b0386169081029190911790915591905b6040517f6e5a76d990dc6af893e20eb82ea37eac6f22cc50e7c7306275569cdc5421a54390600090a45050565b336000818152600360205260408082208151606081019092528054829060ff1660068111156106e4576106e4611908565b60068111156106f5576106f5611908565b815290546001600160781b03610100820481166020840152600160801b9091041660409091015280519091506000906002908290600681111561073a5761073a611908565b600681111561074b5761074b611908565b81526020810191909152604090810160002081518083019092528054829060ff16600281111561077d5761077d611908565b600281111561078e5761078e611908565b81528154602090910190610100900460ff1660028111156107b1576107b1611908565b60028111156107c2576107c2611908565b90525090506001816020015160028111156107df576107df611908565b03610824576001600160a01b0384163b1561081f57610802826040015185610bb8565b61081f576040516305652c5560e51b815260040160405180910390fd5b61088c565b60028160200151600281111561083c5761083c611908565b0361088c576001600160a01b03841660009081526020819052604090205460ff1661088c5761086f826040015185610bb8565b61088c57604051636719795560e11b815260040160405180910390fd5b6000815160028111156108a1576108a1611908565b1461094e576020808301516001600160781b031660009081526006909152604081206108cc9061131f565b111561094e576108e0826020015187610e3c565b61094e576001815160028111156108f9576108f9611908565b0361093557846001600160a01b0316866001600160a01b03161461093057604051635234102760e01b815260040160405180910390fd5b61094e565b604051635234102760e01b815260040160405180910390fd5b505050505050565b610961816000611329565b50565b61096d8261136d565b6001600160781b038216600090815260076020526040902061098f908261115b565b6109ac57604051633e7dfd2360e21b815260040160405180910390fd5b6001600160a01b0381166001600160781b0383166001610580565b6001600160781b038116600090815260066020526040902060609061051b90611170565b6001805460009182918290610a08906001600160781b0316611bc8565b91906101000a8154816001600160781b0302191690836001600160781b0316021790559050610a343390565b6001600160781b0382166000908152600460205260409081902080546001600160a01b0319166001600160a01b03939093169290921790915551610a7b9085908590611bee565b6040519081900390206001600160781b03821660006040517fae6fa502f14a93bc6996eabc5c1ebc61072d478b73fb03333a34754d31aa146d90600090a4336001600160781b03821660005b6040517f3ba9771b33f74e565d2184fa864cb3777a52a873cca631683d3e5d696b877c5b90600090a49392505050565b6001600160a01b038116610b1e576040516335c410ff60e21b815260040160405180910390fd5b6106028282611329565b610b31826111eb565b6001546001600160781b03600160781b90910481169082161115610b68576040516311630a7b60e11b815260040160405180910390fd5b6001600160a01b038216600081815260036020526040902080546effffffffffffffffffffffffffffff60801b1916600160801b6001600160781b03851690810291909117909155906001610686565b6001600160781b0382166000908152600760205260408120610bda9083611395565b9392505050565b3360009081526020819052604090205460ff1615610c12576040516319d18a2160e31b815260040160405180910390fd5b610c3e7f00000000000000000000000000000000000000000000000000000000000000008484846113b7565b6001600160a01b0316336001600160a01b031614610c6f57604051637640718d60e01b815260040160405180910390fd5b33600081815260208190526040808220805460ff19166001179055517fe7f8d62df5af850daa5d677e9e5c8065b7b549ec99ae61ba0ffaa9f5bf3e2d039190a2505050565b61096181600061117d565b6000806001600f81819054906101000a90046001600160781b0316610ce390611bc8565b91906101000a8154816001600160781b0302191690836001600160781b0316021790559050610d0f3390565b6001600160781b0382166000908152600560205260409081902080546001600160a01b0319166001600160a01b03939093169290921790915551610d569085908590611bee565b6040519081900390206001600160781b03821660016040517fae6fa502f14a93bc6996eabc5c1ebc61072d478b73fb03333a34754d31aa146d90600090a4336001600160781b0382166001610ac7565b60408051606081018252600080825260208201819052918101919091526001600160a01b038216600090815260036020526040908190208151606081019092528054829060ff166006811115610dfe57610dfe611908565b6006811115610e0f57610e0f611908565b815290546001600160781b03610100820481166020840152600160801b9091041660409091015292915050565b6001600160781b0382166000908152600660205260408120610bda9083611395565b610e67826111eb565b6001600160a01b0382166000908152600360205260409020805482919060ff19166001836006811115610e9c57610e9c611908565b0217905550816001600160a01b03167fb39d8f1e6f05413a407e46fc950eb92e9f5b3d65a47c3f0bdc7a2741a6ec0f7d82604051610eda9190611932565b60405180910390a25050565b610eef8261136d565b6001600160781b0382166000908152600760205260409020610f1190826113df565b610f2e57604051637e8490a560e01b815260040160405180910390fd5b6001600160a01b0381166001600160781b03831660015b6040517f611e962a89a9663f9e201204430468ed34f23cd95c1be59b66fa79cefa726b4f90600090a45050565b3360009081526020819052604090205460ff1615610fa3576040516319d18a2160e31b815260040160405180910390fd5b6110037f000000000000000000000000000000000000000000000000000000000000000083838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506113f492505050565b6001600160a01b0316336001600160a01b03161461103457604051637640718d60e01b815260040160405180910390fd5b33600081815260208190526040808220805460ff19166001179055517fe7f8d62df5af850daa5d677e9e5c8065b7b549ec99ae61ba0ffaa9f5bf3e2d039190a25050565b61108182611110565b6001600160781b03821660009081526006602052604090206110a390826113df565b6110c057604051637e8490a560e01b815260040160405180910390fd5b6001600160a01b0381166001600160781b0383166000610f45565b60006001600160e01b031982166389a9c85560e01b148061051b57506301ffc9a760e01b6001600160e01b031983161461051b565b6001600160781b0381166000908152600460205260409020546001600160a01b0316335b6001600160a01b03161461096157604051633e527f3960e01b815260040160405180910390fd5b6000610bda836001600160a01b038416611418565b60606000610bda8361150b565b6111868261136d565b6001600160781b038216600081815260056020526040902080546001600160a01b0319166001600160a01b0384169081179091559060015b6040517f3ba9771b33f74e565d2184fa864cb3777a52a873cca631683d3e5d696b877c5b90600090a45050565b60006001600160a01b0382163b156113015750336001600160a01b038216148061130157816001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015611269575060408051601f3d908101601f1916820190925261126691810190611bfe565b60015b1561127c576001600160a01b0316331490505b80611301576001600160a01b0382166391d148546000336040516001600160e01b031960e085901b16815260048101929092526001600160a01b03166024820152604401602060405180830381865afa9250505080156112f9575060408051601f3d908101601f191682019092526112f691810190611c1b565b60015b156113015790505b8061060257604051637f954ba160e01b815260040160405180910390fd5b600061051b825490565b61133282611110565b6001600160781b038216600081815260046020526040812080546001600160a01b0319166001600160a01b03851690811790915591906111be565b6001600160781b0381166000908152600560205260409020546001600160a01b031633611134565b6001600160a01b03811660009081526001830160205260408120541515610bda565b60008060006113c887878787611567565b915091506113d58161162b565b5095945050505050565b6000610bda836001600160a01b03841661177a565b600080600061140385856117c9565b915091506114108161162b565b509392505050565b6000818152600183016020526040812054801561150157600061143c600183611c3d565b855490915060009061145090600190611c3d565b90508181146114b557600086600001828154811061147057611470611c50565b906000526020600020015490508087600001848154811061149357611493611c50565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806114c6576114c6611c66565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061051b565b600091505061051b565b60608160000180548060200260200160405190810160405280929190818152602001828054801561155b57602002820191906000526020600020905b815481526020019060010190808311611547575b50505050509050919050565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083111561159e5750600090506003611622565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa1580156115f2573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b03811661161b57600060019250925050611622565b9150600090505b94509492505050565b600081600481111561163f5761163f611908565b036116475750565b600181600481111561165b5761165b611908565b036116ad5760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e6174757265000000000000000060448201526064015b60405180910390fd5b60028160048111156116c1576116c1611908565b0361170e5760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e6774680060448201526064016116a4565b600381600481111561172257611722611908565b036109615760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b60648201526084016116a4565b60008181526001830160205260408120546117c15750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561051b565b50600061051b565b60008082516041036117ff5760208301516040840151606085015160001a6117f387828585611567565b94509450505050611807565b506000905060025b9250929050565b60006020828403121561182057600080fd5b81356001600160e01b031981168114610bda57600080fd5b80356001600160781b038116811461184f57600080fd5b919050565b60006020828403121561186657600080fd5b610bda82611838565b6001600160a01b038116811461096157600080fd5b6000806040838503121561189757600080fd5b6118a083611838565b915060208301356118b08161186f565b809150509250929050565b6020808252825182820181905260009190848201906040850190845b818110156118fc5783516001600160a01b0316835292840192918401916001016118d7565b50909695505050505050565b634e487b7160e01b600052602160045260246000fd5b6007811061192e5761192e611908565b9052565b6020810161051b828461191e565b6000806040838503121561195357600080fd5b823561195e8161186f565b915061196c60208401611838565b90509250929050565b60008060006060848603121561198a57600080fd5b83356119958161186f565b925060208401356119a58161186f565b915060408401356119b58161186f565b809150509250925092565b600060208083528351808285015260005b818110156119ed578581018301518582016040015282016119d1565b506000604082860101526040601f19601f8301168501019250505092915050565b60008083601f840112611a2057600080fd5b50813567ffffffffffffffff811115611a3857600080fd5b60208301915083602082850101111561180757600080fd5b60008060208385031215611a6357600080fd5b823567ffffffffffffffff811115611a7a57600080fd5b611a8685828601611a0e565b90969095509350505050565b600060208284031215611aa457600080fd5b8135610bda8161186f565b600080600060608486031215611ac457600080fd5b833560ff81168114611ad557600080fd5b95602085013595506040909401359392505050565b80356007811061184f57600080fd5b600060208284031215611b0b57600080fd5b610bda82611aea565b6003811061096157610961611908565b60408101611b3184611b14565b838252611b3d83611b14565b8260208301529392505050565b6000606082019050611b5d82845161191e565b60208301516001600160781b038082166020850152806040860151166040850152505092915050565b60008060408385031215611b9957600080fd5b8235611ba48161186f565b915061196c60208401611aea565b634e487b7160e01b600052601160045260246000fd5b60006001600160781b03808316818103611be457611be4611bb2565b6001019392505050565b8183823760009101908152919050565b600060208284031215611c1057600080fd5b8151610bda8161186f565b600060208284031215611c2d57600080fd5b81518015158114610bda57600080fd5b8181038181111561051b5761051b611bb2565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052603160045260246000fdfea264697066735822122016ec445fc083785e10ec9116462f125d2772802d3109f7302950a5c0fbd3c55964736f6c634300081400330000000000000000000000009cd54860f52065d988bff06eb9474ac3beeba238

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106101c45760003560e01c80637c58813c116100f9578063b6567f2211610097578063da0194c011610071578063da0194c01461047c578063e30cd5e11461048f578063f80af984146104a2578063fec1d643146104b557600080fd5b8063b6567f2214610436578063b955455214610449578063d72dde5e1461046957600080fd5b80639445f530116100d35780639445f530146103c357806399f9a678146103d65780639e814cae146103e9578063a9f138eb1461042357600080fd5b80637c58813c1461035b57806389a9c855146103845780638d744314146103b057600080fd5b8063285fb8c811610166578063372fb54d11610140578063372fb54d146102f75780633fe5df991461030a578063501b7d2e1461031d578063731fb9d81461034857600080fd5b8063285fb8c8146102a257806333f0901b146102b557806334778f6a146102e457600080fd5b806317e94a6c116101a257806317e94a6c1461024757806318fbf6fe146102675780631c33b3281461027a5780632304aa021461028f57600080fd5b806301ffc9a7146101c95780630fac9f76146101f15780631390a2c214610232575b600080fd5b6101dc6101d736600461180e565b6104c8565b60405190151581526020015b60405180910390f35b61021a6101ff366004611854565b6004602052600090815260409020546001600160a01b031681565b6040516001600160a01b0390911681526020016101e8565b610245610240366004611884565b610521565b005b61025a610255366004611854565b6105ad565b6040516101e891906118bb565b610245610275366004611884565b6105d1565b610282600081565b6040516101e89190611932565b61024561029d366004611940565b610606565b6102456102b0366004611975565b6106b3565b6102d760405180604001604052806003815260200162454f4160e81b81525081565b6040516101e891906119c0565b6102456102f2366004611854565b610956565b610245610305366004611884565b610964565b61025a610318366004611854565b6109c7565b61033061032b366004611a50565b6109eb565b6040516001600160781b0390911681526020016101e8565b610245610356366004611884565b610af7565b61021a610369366004611854565b6005602052600090815260409020546001600160a01b031681565b6101dc610392366004611a92565b6001600160a01b031660009081526020819052604090205460ff1690565b6102456103be366004611940565b610b28565b6101dc6103d1366004611884565b610bb8565b6102456103e4366004611aaf565b610be1565b6104156103f7366004611af9565b60026020526000908152604090205460ff8082169161010090041682565b6040516101e8929190611b24565b610245610431366004611854565b610cb4565b610330610444366004611a50565b610cbf565b61045c610457366004611a92565b610da6565b6040516101e89190611b4a565b6101dc610477366004611884565b610e3c565b61024561048a366004611b86565b610e5e565b61024561049d366004611884565b610ee6565b6102456104b0366004611a50565b610f72565b6102456104c3366004611884565b611078565b60006001600160e01b0319821663050bf71960e31b14806104f957506001600160e01b03198216638f1d689960e01b145b8061050c57506001600160e01b03198216155b8061051b575061051b826110db565b92915050565b61052a82611110565b6001600160781b038216600090815260066020526040902061054c908261115b565b61056957604051633e7dfd2360e21b815260040160405180910390fd5b6001600160a01b0381166001600160781b03831660005b6040517f5d23e0e2d8347166058712ba9dceec21d6edd7b466a0d13cb759d730bd56039090600090a45050565b6001600160781b038116600090815260076020526040902060609061051b90611170565b6001600160a01b0381166105f8576040516335c410ff60e21b815260040160405180910390fd5b610602828261117d565b5050565b61060f826111eb565b6001546001600160781b03908116908216111561063f576040516311630a7b60e11b815260040160405180910390fd5b6001600160a01b038216600081815260036020526040812080546fffffffffffffffffffffffffffffff0019166101006001600160781b0386169081029190911790915591905b6040517f6e5a76d990dc6af893e20eb82ea37eac6f22cc50e7c7306275569cdc5421a54390600090a45050565b336000818152600360205260408082208151606081019092528054829060ff1660068111156106e4576106e4611908565b60068111156106f5576106f5611908565b815290546001600160781b03610100820481166020840152600160801b9091041660409091015280519091506000906002908290600681111561073a5761073a611908565b600681111561074b5761074b611908565b81526020810191909152604090810160002081518083019092528054829060ff16600281111561077d5761077d611908565b600281111561078e5761078e611908565b81528154602090910190610100900460ff1660028111156107b1576107b1611908565b60028111156107c2576107c2611908565b90525090506001816020015160028111156107df576107df611908565b03610824576001600160a01b0384163b1561081f57610802826040015185610bb8565b61081f576040516305652c5560e51b815260040160405180910390fd5b61088c565b60028160200151600281111561083c5761083c611908565b0361088c576001600160a01b03841660009081526020819052604090205460ff1661088c5761086f826040015185610bb8565b61088c57604051636719795560e11b815260040160405180910390fd5b6000815160028111156108a1576108a1611908565b1461094e576020808301516001600160781b031660009081526006909152604081206108cc9061131f565b111561094e576108e0826020015187610e3c565b61094e576001815160028111156108f9576108f9611908565b0361093557846001600160a01b0316866001600160a01b03161461093057604051635234102760e01b815260040160405180910390fd5b61094e565b604051635234102760e01b815260040160405180910390fd5b505050505050565b610961816000611329565b50565b61096d8261136d565b6001600160781b038216600090815260076020526040902061098f908261115b565b6109ac57604051633e7dfd2360e21b815260040160405180910390fd5b6001600160a01b0381166001600160781b0383166001610580565b6001600160781b038116600090815260066020526040902060609061051b90611170565b6001805460009182918290610a08906001600160781b0316611bc8565b91906101000a8154816001600160781b0302191690836001600160781b0316021790559050610a343390565b6001600160781b0382166000908152600460205260409081902080546001600160a01b0319166001600160a01b03939093169290921790915551610a7b9085908590611bee565b6040519081900390206001600160781b03821660006040517fae6fa502f14a93bc6996eabc5c1ebc61072d478b73fb03333a34754d31aa146d90600090a4336001600160781b03821660005b6040517f3ba9771b33f74e565d2184fa864cb3777a52a873cca631683d3e5d696b877c5b90600090a49392505050565b6001600160a01b038116610b1e576040516335c410ff60e21b815260040160405180910390fd5b6106028282611329565b610b31826111eb565b6001546001600160781b03600160781b90910481169082161115610b68576040516311630a7b60e11b815260040160405180910390fd5b6001600160a01b038216600081815260036020526040902080546effffffffffffffffffffffffffffff60801b1916600160801b6001600160781b03851690810291909117909155906001610686565b6001600160781b0382166000908152600760205260408120610bda9083611395565b9392505050565b3360009081526020819052604090205460ff1615610c12576040516319d18a2160e31b815260040160405180910390fd5b610c3e7fd3f5cd7a1487f8f0a2a12cf6e95545173640e44a3a845c5f2c9d00175aab42948484846113b7565b6001600160a01b0316336001600160a01b031614610c6f57604051637640718d60e01b815260040160405180910390fd5b33600081815260208190526040808220805460ff19166001179055517fe7f8d62df5af850daa5d677e9e5c8065b7b549ec99ae61ba0ffaa9f5bf3e2d039190a2505050565b61096181600061117d565b6000806001600f81819054906101000a90046001600160781b0316610ce390611bc8565b91906101000a8154816001600160781b0302191690836001600160781b0316021790559050610d0f3390565b6001600160781b0382166000908152600560205260409081902080546001600160a01b0319166001600160a01b03939093169290921790915551610d569085908590611bee565b6040519081900390206001600160781b03821660016040517fae6fa502f14a93bc6996eabc5c1ebc61072d478b73fb03333a34754d31aa146d90600090a4336001600160781b0382166001610ac7565b60408051606081018252600080825260208201819052918101919091526001600160a01b038216600090815260036020526040908190208151606081019092528054829060ff166006811115610dfe57610dfe611908565b6006811115610e0f57610e0f611908565b815290546001600160781b03610100820481166020840152600160801b9091041660409091015292915050565b6001600160781b0382166000908152600660205260408120610bda9083611395565b610e67826111eb565b6001600160a01b0382166000908152600360205260409020805482919060ff19166001836006811115610e9c57610e9c611908565b0217905550816001600160a01b03167fb39d8f1e6f05413a407e46fc950eb92e9f5b3d65a47c3f0bdc7a2741a6ec0f7d82604051610eda9190611932565b60405180910390a25050565b610eef8261136d565b6001600160781b0382166000908152600760205260409020610f1190826113df565b610f2e57604051637e8490a560e01b815260040160405180910390fd5b6001600160a01b0381166001600160781b03831660015b6040517f611e962a89a9663f9e201204430468ed34f23cd95c1be59b66fa79cefa726b4f90600090a45050565b3360009081526020819052604090205460ff1615610fa3576040516319d18a2160e31b815260040160405180910390fd5b6110037fd3f5cd7a1487f8f0a2a12cf6e95545173640e44a3a845c5f2c9d00175aab429483838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506113f492505050565b6001600160a01b0316336001600160a01b03161461103457604051637640718d60e01b815260040160405180910390fd5b33600081815260208190526040808220805460ff19166001179055517fe7f8d62df5af850daa5d677e9e5c8065b7b549ec99ae61ba0ffaa9f5bf3e2d039190a25050565b61108182611110565b6001600160781b03821660009081526006602052604090206110a390826113df565b6110c057604051637e8490a560e01b815260040160405180910390fd5b6001600160a01b0381166001600160781b0383166000610f45565b60006001600160e01b031982166389a9c85560e01b148061051b57506301ffc9a760e01b6001600160e01b031983161461051b565b6001600160781b0381166000908152600460205260409020546001600160a01b0316335b6001600160a01b03161461096157604051633e527f3960e01b815260040160405180910390fd5b6000610bda836001600160a01b038416611418565b60606000610bda8361150b565b6111868261136d565b6001600160781b038216600081815260056020526040902080546001600160a01b0319166001600160a01b0384169081179091559060015b6040517f3ba9771b33f74e565d2184fa864cb3777a52a873cca631683d3e5d696b877c5b90600090a45050565b60006001600160a01b0382163b156113015750336001600160a01b038216148061130157816001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015611269575060408051601f3d908101601f1916820190925261126691810190611bfe565b60015b1561127c576001600160a01b0316331490505b80611301576001600160a01b0382166391d148546000336040516001600160e01b031960e085901b16815260048101929092526001600160a01b03166024820152604401602060405180830381865afa9250505080156112f9575060408051601f3d908101601f191682019092526112f691810190611c1b565b60015b156113015790505b8061060257604051637f954ba160e01b815260040160405180910390fd5b600061051b825490565b61133282611110565b6001600160781b038216600081815260046020526040812080546001600160a01b0319166001600160a01b03851690811790915591906111be565b6001600160781b0381166000908152600560205260409020546001600160a01b031633611134565b6001600160a01b03811660009081526001830160205260408120541515610bda565b60008060006113c887878787611567565b915091506113d58161162b565b5095945050505050565b6000610bda836001600160a01b03841661177a565b600080600061140385856117c9565b915091506114108161162b565b509392505050565b6000818152600183016020526040812054801561150157600061143c600183611c3d565b855490915060009061145090600190611c3d565b90508181146114b557600086600001828154811061147057611470611c50565b906000526020600020015490508087600001848154811061149357611493611c50565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806114c6576114c6611c66565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061051b565b600091505061051b565b60608160000180548060200260200160405190810160405280929190818152602001828054801561155b57602002820191906000526020600020905b815481526020019060010190808311611547575b50505050509050919050565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083111561159e5750600090506003611622565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa1580156115f2573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b03811661161b57600060019250925050611622565b9150600090505b94509492505050565b600081600481111561163f5761163f611908565b036116475750565b600181600481111561165b5761165b611908565b036116ad5760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e6174757265000000000000000060448201526064015b60405180910390fd5b60028160048111156116c1576116c1611908565b0361170e5760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e6774680060448201526064016116a4565b600381600481111561172257611722611908565b036109615760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b60648201526084016116a4565b60008181526001830160205260408120546117c15750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561051b565b50600061051b565b60008082516041036117ff5760208301516040840151606085015160001a6117f387828585611567565b94509450505050611807565b506000905060025b9250929050565b60006020828403121561182057600080fd5b81356001600160e01b031981168114610bda57600080fd5b80356001600160781b038116811461184f57600080fd5b919050565b60006020828403121561186657600080fd5b610bda82611838565b6001600160a01b038116811461096157600080fd5b6000806040838503121561189757600080fd5b6118a083611838565b915060208301356118b08161186f565b809150509250929050565b6020808252825182820181905260009190848201906040850190845b818110156118fc5783516001600160a01b0316835292840192918401916001016118d7565b50909695505050505050565b634e487b7160e01b600052602160045260246000fd5b6007811061192e5761192e611908565b9052565b6020810161051b828461191e565b6000806040838503121561195357600080fd5b823561195e8161186f565b915061196c60208401611838565b90509250929050565b60008060006060848603121561198a57600080fd5b83356119958161186f565b925060208401356119a58161186f565b915060408401356119b58161186f565b809150509250925092565b600060208083528351808285015260005b818110156119ed578581018301518582016040015282016119d1565b506000604082860101526040601f19601f8301168501019250505092915050565b60008083601f840112611a2057600080fd5b50813567ffffffffffffffff811115611a3857600080fd5b60208301915083602082850101111561180757600080fd5b60008060208385031215611a6357600080fd5b823567ffffffffffffffff811115611a7a57600080fd5b611a8685828601611a0e565b90969095509350505050565b600060208284031215611aa457600080fd5b8135610bda8161186f565b600080600060608486031215611ac457600080fd5b833560ff81168114611ad557600080fd5b95602085013595506040909401359392505050565b80356007811061184f57600080fd5b600060208284031215611b0b57600080fd5b610bda82611aea565b6003811061096157610961611908565b60408101611b3184611b14565b838252611b3d83611b14565b8260208301529392505050565b6000606082019050611b5d82845161191e565b60208301516001600160781b038082166020850152806040860151166040850152505092915050565b60008060408385031215611b9957600080fd5b8235611ba48161186f565b915061196c60208401611aea565b634e487b7160e01b600052601160045260246000fd5b60006001600160781b03808316818103611be457611be4611bb2565b6001019392505050565b8183823760009101908152919050565b600060208284031215611c1057600080fd5b8151610bda8161186f565b600060208284031215611c2d57600080fd5b81518015158114610bda57600080fd5b8181038181111561051b5761051b611bb2565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052603160045260246000fdfea264697066735822122016ec445fc083785e10ec9116462f125d2772802d3109f7302950a5c0fbd3c55964736f6c63430008140033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

0000000000000000000000009cd54860f52065d988bff06eb9474ac3beeba238

-----Decoded View---------------
Arg [0] : defaultOwner (address): 0x9Cd54860f52065D988BfF06eB9474aC3bEeBa238

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 0000000000000000000000009cd54860f52065d988bff06eb9474ac3beeba238


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.