ETH Price: $3,136.13 (-4.92%)
Gas: 4 Gwei

Contract

0x721C00182a990771244d7A71B9FA2ea789A3b433
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Value
Apply List To Co...199861912024-05-31 0:19:5934 days ago1717114799IN
0x721C0018...789A3b433
0 ETH0.0003719810.22807657
Set Transfer Sec...199800062024-05-30 3:33:4735 days ago1717040027IN
0x721C0018...789A3b433
0 ETH0.000413178.05141486
Apply List To Co...193443832024-03-02 2:03:59124 days ago1709345039IN
0x721C0018...789A3b433
0 ETH0.0017281447.44911499
Create List193443742024-03-02 2:02:11124 days ago1709344931IN
0x721C0018...789A3b433
0 ETH0.0024747346.44678863
Set Transfer Sec...193443582024-03-02 1:58:59124 days ago1709344739IN
0x721C0018...789A3b433
0 ETH0.0014897743.48808043
Set Transfer Sec...193435912024-03-01 23:23:59124 days ago1709335439IN
0x721C0018...789A3b433
0 ETH0.0013126641.72890361
Add Accounts To ...193233022024-02-28 3:17:59127 days ago1709090279IN
0x721C0018...789A3b433
0 ETH0.018261146.58836127
Create List193209832024-02-27 19:29:59128 days ago1709062199IN
0x721C0018...789A3b433
0 ETH0.0030912758.04452955
Add Accounts To ...193134842024-02-26 18:20:47129 days ago1708971647IN
0x721C0018...789A3b433
0 ETH0.0053800854.39487944
Add Accounts To ...192356072024-02-15 20:06:59140 days ago1708027619IN
0x721C0018...789A3b433
0 ETH0.0070304971.0689377
Add Accounts To ...192323142024-02-15 9:03:47140 days ago1707987827IN
0x721C0018...789A3b433
0 ETH0.0031820318.88628336
Remove Accounts ...192323022024-02-15 9:01:23140 days ago1707987683IN
0x721C0018...789A3b433
0 ETH0.0007299419.09090573
Add Code Hashes ...192322862024-02-15 8:58:11140 days ago1707987491IN
0x721C0018...789A3b433
0 ETH0.0021320818.3743833
Remove Code Hash...192322802024-02-15 8:56:59140 days ago1707987419IN
0x721C0018...789A3b433
0 ETH0.0007711620.13263202
Add Accounts To ...192322692024-02-15 8:54:47140 days ago1707987287IN
0x721C0018...789A3b433
0 ETH0.0019385619.61298027
Add Accounts To ...192318852024-02-15 7:37:11140 days ago1707982631IN
0x721C0018...789A3b433
0 ETH0.0021151921.39477418
Add Accounts To ...192318332024-02-15 7:26:47140 days ago1707982007IN
0x721C0018...789A3b433
0 ETH0.0026591822.92146383
Remove Code Hash...192316802024-02-15 6:56:11140 days ago1707980171IN
0x721C0018...789A3b433
0 ETH0.0007238818.89341801
Add Accounts To ...192181182024-02-13 9:11:23142 days ago1707815483IN
0x721C0018...789A3b433
0 ETH0.0023666420.39652232
Remove Accounts ...192178832024-02-13 8:23:59142 days ago1707812639IN
0x721C0018...789A3b433
0 ETH0.0007772820.28405224
Add Operator To ...192178752024-02-13 8:22:23142 days ago1707812543IN
0x721C0018...789A3b433
0 ETH0.0024083120.88519563
Add Code Hashes ...192175892024-02-13 7:24:35142 days ago1707809075IN
0x721C0018...789A3b433
0 ETH0.001922919.43345718
Remove Accounts ...192173112024-02-13 6:28:59142 days ago1707805739IN
0x721C0018...789A3b433
0 ETH0.0006566117.14310723
Remove Code Hash...192173082024-02-13 6:28:23142 days ago1707805703IN
0x721C0018...789A3b433
0 ETH0.0006489616.93799922
Add Code Hashes ...192172652024-02-13 6:19:47142 days ago1707805187IN
0x721C0018...789A3b433
0 ETH0.0019680819.89005629
View all transactions

Latest 1 internal transaction

Advanced mode:
Parent Transaction Hash Block From To Value
191435302024-02-02 21:56:47153 days ago1706911007  Contract Creation0 ETH
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
CreatorTokenTransferValidatorV2

Compiler Version
v0.8.19+commit.7dd6d404

Optimization Enabled:
Yes with 1000000 runs

Other Settings:
paris EvmVersion
File 1 of 18 : CreatorTokenTransferValidatorV2.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

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

/**
 * @title  CreatorTokenTransferValidatorV2
 * @author Limit Break, Inc.
 * @notice The CreatorTokenTransferValidatorV2 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, blacklisted accounts and codehashes and whitelisted accounts and codehashes 
 *         for each collection.
 *
 * @dev    <h4>Features</h4>
 *         - Transfer security levels: Provides different levels of transfer security, 
 *           from open transfers to completely restricted transfers.
 *         - Blacklist: Allows the owner of a collection to blacklist specific operator addresses or codehashes
 *           from executing transfers on behalf of others.
 *         - Whitelist: Allows the owner of a collection to whitelist specific operator addresses or codehashes
 *           permitted to execute transfers on behalf of others or send/receive tokens 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 CreatorTokenTransferValidatorV2 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>
 *          - Recommended: Recommended defaults are same as Level 3 (Whitelisting with OTC Enabled).
 *            - Caller Constraints: OperatorWhitelistEnableOTC
 *            - Receiver Constraints: None
 *          - Level 1: No transfer restrictions.
 *            - Caller Constraints: None
 *            - Receiver Constraints: None
 *          - Level 2: Only non-blacklisted operators can initiate transfers, over-the-counter (OTC) trading enabled.
 *            - Caller Constraints: OperatorBlacklistEnableOTC
 *            - Receiver Constraints: None
 *          - Level 3: Only whitelisted accounts can initiate transfers, over-the-counter (OTC) trading enabled.
 *            - Caller Constraints: OperatorWhitelistEnableOTC
 *            - Receiver Constraints: None
 *          - Level 4: Only whitelisted accounts can initiate transfers, over-the-counter (OTC) trading disabled.
 *            - Caller Constraints: OperatorWhitelistDisableOTC
 *            - Receiver Constraints: None
 *          - Level 5: Only whitelisted accounts can initiate transfers, over-the-counter (OTC) trading enabled. 
 *                     Transfers to contracts with code are not allowed, unless present on the whitelist.
 *            - Caller Constraints: OperatorWhitelistEnableOTC
 *            - Receiver Constraints: NoCode
 *          - Level 6: Only whitelisted accounts can initiate transfers, over-the-counter (OTC) trading enabled. 
 *                     Transfers are allowed only to Externally Owned Accounts (EOAs), unless present on the whitelist.
 *            - Caller Constraints: OperatorWhitelistEnableOTC
 *            - Receiver Constraints: EOA
 *          - Level 7: Only whitelisted accounts can initiate transfers, over-the-counter (OTC) trading disabled. 
 *                     Transfers to contracts with code are not allowed, unless present on the whitelist.
 *            - Caller Constraints: OperatorWhitelistDisableOTC
 *            - Receiver Constraints: NoCode
 *          - Level 8: Only whitelisted accounts can initiate transfers, over-the-counter (OTC) trading disabled. 
 *                     Transfers are allowed only to Externally Owned Accounts (EOAs), unless present on the whitelist.
 *            - Caller Constraints: OperatorWhitelistDisableOTC
 *            - Receiver Constraints: EOA
 */
contract CreatorTokenTransferValidatorV2 is EOARegistry, ICreatorTokenTransferValidatorV2 {
    using EnumerableSet for EnumerableSet.AddressSet;
    using EnumerableSet for EnumerableSet.Bytes32Set;

    // Custom Errors
    /// @dev Thrown when an array that cannot be zero length is supplied with zero length.
    error CreatorTokenTransferValidator__ArrayLengthCannotBeZero();

    /// @dev Thrown when attempting to set a list id that does not exist.
    error CreatorTokenTransferValidator__ListDoesNotExist();

    /// @dev Thrown when attempting to transfer the ownership of a list to the zero address.
    error CreatorTokenTransferValidator__ListOwnershipCannotBeTransferredToZeroAddress();

    /// @dev Thrown when attempting to call a function that requires the caller to be the list owner.
    error CreatorTokenTransferValidator__CallerDoesNotOwnList();

    /// @dev Thrown when validating a transfer for a collection using whitelists and the operator is not on the whitelist.
    error CreatorTokenTransferValidator__CallerMustBeWhitelisted();

    /// @dev Thrown when attempting to call a function that requires owner or default admin role for a collection that the caller does not have.
    error CreatorTokenTransferValidator__CallerMustHaveElevatedPermissionsForSpecifiedNFT();

    /// @dev Thrown when validating a transfer for a collection using blacklists and the operator is on the blacklist.
    error CreatorTokenTransferValidator__OperatorIsBlacklisted();

    /// @dev Thrown when validating a transfer for a collection that does not allow receiver to have code and the receiver has code.
    error CreatorTokenTransferValidator__ReceiverMustNotHaveDeployedCode();

    /// @dev Thrown when validating a transfer for a collection that requires receivers be verified EOAs and the receiver is not verified.
    error CreatorTokenTransferValidator__ReceiverProofOfEOASignatureUnverified();

    /// @dev Thrown when attempting to add the zero address to a whitelist or blacklist.
    error CreatorTokenTransferValidator__ZeroAddressNotAllowed();

    /// @dev Thrown when attempting to add the zero code hash to a whitelist or blacklist.
    error CreatorTokenTransferValidator__ZeroCodeHashNotAllowed();

    // Structs
    /**
     * @dev This struct is internally for the storage of account and codehash lists.
     */
    struct List {
        EnumerableSet.AddressSet enumerableAccounts;
        EnumerableSet.Bytes32Set enumerableCodehashes;
        mapping (address => bool) nonEnumerableAccounts;
        mapping (bytes32 => bool) nonEnumerableCodehashes;
    }
    
    // Constants
    /// @dev The default admin role value for contracts that implement access control.
    bytes32 private constant DEFAULT_ACCESS_CONTROL_ADMIN_ROLE = 0x00;
    /// @dev Value representing a zero value code hash.
    bytes32 private constant CODEHASH_ZERO = 0x0000000000000000000000000000000000000000000000000000000000000000;

    /// @notice Keeps track of the most recently created list id.
    uint120 public lastListId;

    /// @notice Mapping of list ids to list owners
    mapping (uint120 => address) public listOwners;

    /// @dev Mapping of collection addresses to their security policy settings
    mapping (address => CollectionSecurityPolicyV2) private collectionSecurityPolicies;

    /// @dev Mapping of list ids to blacklist settings
    mapping (uint120 => List) private blacklists;

    /// @dev Mapping of list ids to whitelist settings
    mapping (uint120 => List) private whitelists;

    constructor(address defaultOwner) EOARegistry() {
        uint120 id = 0;

        listOwners[id] = defaultOwner;

        emit CreatedList(id, "DEFAULT LIST");
        emit ReassignedListOwnership(id, defaultOwner);
    }

    /*************************************************************************/
    /*                               MODIFIERS                               */
    /*************************************************************************/

    /**
     * @dev This modifier restricts a function call to the owner of the list `id`.
     * @dev Throws when the caller is not the list owner.
     */
    modifier onlyListOwner(uint120 id) {
        _requireCallerOwnsList(id);
        _;
    }

    /**
     * @dev This modifier reverts a transaction if the supplied array has a zero length.
     * @dev Throws when the array parameter has a zero length.
     */
    modifier notZero(uint256 value) {
        if (value == 0) {
            revert CreatorTokenTransferValidator__ArrayLengthCannotBeZero();
        }
        _;
    }

    /*************************************************************************/
    /*                          APPLY TRANSFER POLICIES                      */
    /*************************************************************************/

    /**
     * @notice Apply the collection transfer policy to a transfer operation of a creator token.
     *
     * @dev Throws when the receiver has deployed code and isn't whitelisted, if ReceiverConstraints.NoCode is set.
     * @dev Throws when the receiver has never verified a signature to prove they are an EOA and the receiver
     *      isn't whitelisted, if the ReceiverConstraints.EOA is set.
     * @dev Throws when `msg.sender` is blacklisted, if CallerConstraints.OperatorBlacklistEnableOTC is set, unless
     *      `msg.sender` is also the `from` address.
     * @dev Throws when `msg.sender` isn't whitelisted, if CallerConstraints.OperatorWhitelistEnableOTC is set, unless
     *      `msg.sender` is also the `from` address.
     * @dev Throws when neither `msg.sender` nor `from` are whitelisted, if 
     *      CallerConstraints.OperatorWhitelistDisableOTC is set.
     *
     * @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 {
        CollectionSecurityPolicyV2 storage collectionSecurityPolicy = collectionSecurityPolicies[_msgSender()];
        uint120 listId = collectionSecurityPolicy.listId;
        (CallerConstraints callerConstraints, ReceiverConstraints receiverConstraints) = 
            transferSecurityPolicies(collectionSecurityPolicy.transferSecurityLevel);

        List storage whitelist = whitelists[listId];

        if (receiverConstraints == ReceiverConstraints.NoCode) {
            if (_getCodeLengthAsm(to) > 0) {
                if (!whitelist.nonEnumerableAccounts[to]) {
                    if (!whitelist.nonEnumerableCodehashes[_getCodeHashAsm(to)]) {
                        revert CreatorTokenTransferValidator__ReceiverMustNotHaveDeployedCode();
                    }
                }
            }

            
        } else if (receiverConstraints == ReceiverConstraints.EOA) {
            if (!isVerifiedEOA(to)) {
                if (!whitelist.nonEnumerableAccounts[to]) {
                    if (!whitelist.nonEnumerableCodehashes[_getCodeHashAsm(to)]) {
                        revert CreatorTokenTransferValidator__ReceiverProofOfEOASignatureUnverified();
                    }
                }
            }
        }

        if (caller == from) {
            if (callerConstraints != CallerConstraints.OperatorWhitelistDisableOTC) {
                return;
            }
        }

        if (callerConstraints == CallerConstraints.OperatorBlacklistEnableOTC) {
            List storage blacklist = blacklists[listId];
            if (blacklist.nonEnumerableAccounts[caller]) {
                revert CreatorTokenTransferValidator__OperatorIsBlacklisted();
            }

            if (blacklist.nonEnumerableCodehashes[_getCodeHashAsm(caller)]) {
                revert CreatorTokenTransferValidator__OperatorIsBlacklisted();
            }
        } else if (callerConstraints == CallerConstraints.OperatorWhitelistEnableOTC) {
            if (whitelist.nonEnumerableAccounts[caller]) {
                return;
            }

            if (whitelist.nonEnumerableCodehashes[_getCodeHashAsm(caller)]) {
                return;
            }

            revert CreatorTokenTransferValidator__CallerMustBeWhitelisted();
        } else if (callerConstraints == CallerConstraints.OperatorWhitelistDisableOTC) {
            mapping(address => bool) storage accountWhitelist = whitelist.nonEnumerableAccounts;

            if (accountWhitelist[caller]) {
                return;
            }

            if (accountWhitelist[from]) {
                return;
            }

            mapping(bytes32 => bool) storage codehashWhitelist = whitelist.nonEnumerableCodehashes;

            if (codehashWhitelist[_getCodeHashAsm(caller)]) {
                return;
            }

            if (codehashWhitelist[_getCodeHashAsm(from)]) {
                return;
            }

            revert CreatorTokenTransferValidator__CallerMustBeWhitelisted();
        }
    }

    /**
     * @notice Returns the caller and receiver constraints for the specified transfer security level.
     * 
     * @param level The transfer security level to return the caller and receiver constraints for.
     * 
     * @return callerConstraints    The `CallerConstraints` enum value for the level.
     * @return receiverConstraints The `ReceiverConstraints` enum value for the level.
     */
    function transferSecurityPolicies(TransferSecurityLevels level) public pure returns (CallerConstraints callerConstraints, ReceiverConstraints receiverConstraints) {
        if (level == TransferSecurityLevels.Recommended) {
            callerConstraints = CallerConstraints.OperatorWhitelistEnableOTC;
            receiverConstraints = ReceiverConstraints.None;
        } else if (level == TransferSecurityLevels.One) {
            callerConstraints = CallerConstraints.None;
            receiverConstraints = ReceiverConstraints.None;
        } else if (level == TransferSecurityLevels.Two) {
            callerConstraints = CallerConstraints.OperatorBlacklistEnableOTC;
            receiverConstraints = ReceiverConstraints.None;
        } else if (level == TransferSecurityLevels.Three) {
            callerConstraints = CallerConstraints.OperatorWhitelistEnableOTC;
            receiverConstraints = ReceiverConstraints.None;
        } else if (level == TransferSecurityLevels.Four) {
            callerConstraints = CallerConstraints.OperatorWhitelistDisableOTC;
            receiverConstraints = ReceiverConstraints.None;
        } else if (level == TransferSecurityLevels.Five) {
            callerConstraints = CallerConstraints.OperatorWhitelistEnableOTC;
            receiverConstraints = ReceiverConstraints.NoCode;
        } else if (level == TransferSecurityLevels.Six) {
            callerConstraints = CallerConstraints.OperatorWhitelistEnableOTC;
            receiverConstraints = ReceiverConstraints.EOA;
        } else if (level == TransferSecurityLevels.Seven) {
            callerConstraints = CallerConstraints.OperatorWhitelistDisableOTC;
            receiverConstraints = ReceiverConstraints.NoCode;
        } else {
            callerConstraints = CallerConstraints.OperatorWhitelistDisableOTC;
            receiverConstraints = ReceiverConstraints.EOA;
        }
    }

    /*************************************************************************/
    /*                              LIST MANAGEMENT                          */
    /*************************************************************************/

    /**
     * @notice Creates a new list id.  The list id is a handle to allow editing of blacklisted and whitelisted accounts
     *         and codehashes.
     *
     * @dev <h4>Postconditions:</h4>
     *      1. A new list with the specified name is created.
     *      2. The caller is set as the owner of the new list.
     *      3. A `CreatedList` event is emitted.
     *      4. A `ReassignedListOwnership` event is emitted.
     *
     * @param name The name of the new list.
     * @return     The id of the new list.
     */
    function createList(string calldata name) public override returns (uint120) {
        uint120 id = ++lastListId;

        listOwners[id] = _msgSender();

        emit CreatedList(id, name);
        emit ReassignedListOwnership(id, _msgSender());

        return id;
    }

    /**
     * @notice Creates a new list id, and copies all blacklisted and whitelisted accounts and codehashes from the
     *         specified source list.
     *
     * @dev    <h4>Postconditions:</h4>
     *         1. A new list with the specified name is created.
     *         2. The caller is set as the owner of the new list.
     *         3. A `CreatedList` event is emitted.
     *         4. A `ReassignedListOwnership` event is emitted.
     *         5. All blacklisted and whitelisted accounts and codehashes from the specified source list are copied
     *            to the new list.
     *         6. An `AddedAccountToList` event is emitted for each blacklisted and whitelisted account copied.
     *         7. An `AddedCodeHashToList` event is emitted for each blacklisted and whitelisted codehash copied.
     *
     * @param name         The name of the new list.
     * @param sourceListId The id of the source list to copy from.
     * @return             The id of the new list.
     */
    function createListCopy(string calldata name, uint120 sourceListId) external override returns (uint120) {
        uint120 id = ++lastListId;

        unchecked {
            if (sourceListId > id - 1) {
                revert CreatorTokenTransferValidator__ListDoesNotExist();
            }
        }

        listOwners[id] = _msgSender();

        emit CreatedList(id, name);
        emit ReassignedListOwnership(id, _msgSender());

        List storage sourceBlacklist = blacklists[sourceListId];
        List storage sourceWhitelist = whitelists[sourceListId];
        List storage targetBlacklist = blacklists[id];
        List storage targetWhitelist = whitelists[id];

        _copyAddressSet(ListTypes.Blacklist, id, sourceBlacklist, targetBlacklist);
        _copyBytes32Set(ListTypes.Blacklist, id, sourceBlacklist, targetBlacklist);
        _copyAddressSet(ListTypes.Whitelist, id, sourceWhitelist, targetWhitelist);
        _copyBytes32Set(ListTypes.Whitelist, id, sourceWhitelist, targetWhitelist);

        return id;
    }

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

        _reassignOwnershipOfList(id, newOwner);
    }

    /**
     * @notice Renounce the ownership of a list, rendering the list immutable.
     *
     * @dev Throws when the caller does not own the specified list.
     *
     * @dev <h4>Postconditions:</h4>
     *      1. The ownership of the specified list is renounced.
     *      2. A `ReassignedListOwnership` event is emitted.
     *
     * @param id The id of the list.
     */
    function renounceOwnershipOfList(uint120 id) public override {
        _reassignOwnershipOfList(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 Applies the specified list to 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 list id does not exist.
     *
     * @dev <h4>Postconditions:</h4>
     *      1. The list of the specified collection is set to the new value.
     *      2. An `AppliedListToCollection` event is emitted.
     *
     * @param collection The address of the collection.
     * @param id         The id of the operator whitelist.
     */
    function applyListToCollection(address collection, uint120 id) public override {
        _requireCallerIsNFTOrContractOwnerOrAdmin(collection);

        if (id > lastListId) {
            revert CreatorTokenTransferValidator__ListDoesNotExist();
        }

        collectionSecurityPolicies[collection].listId = id;
        emit AppliedListToCollection(collection, id);
    }

    /**
     * @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 getCollectionSecurityPolicyV2(address collection) 
        external view override returns (CollectionSecurityPolicyV2 memory) {
        return collectionSecurityPolicies[collection];
    }

    /**
     * @notice Adds one or more accounts to a blacklist.
     *
     * @dev Throws when the caller does not own the specified list.
     * @dev Throws when the accounts array is empty.
     *
     * @dev <h4>Postconditions:</h4>
     *      1. Accounts not previously in the list are added.
     *      2. An `AddedAccountToList` event is emitted for each account that is newly added to the list.
     *
     * @param id       The id of the list.
     * @param accounts The addresses of the accounts to add.
     */
    function addAccountsToBlacklist(
        uint120 id, 
        address[] calldata accounts
    ) external override 
    onlyListOwner(id) 
    notZero(accounts.length) {
        List storage blacklist = blacklists[id];
        address account;
        for (uint256 i = 0; i < accounts.length;) {
            account = accounts[i];

            if (account == address(0)) {
                revert CreatorTokenTransferValidator__ZeroAddressNotAllowed();
            }

            if (blacklist.enumerableAccounts.add(account)) {
                emit AddedAccountToList(ListTypes.Blacklist, id, account);
                blacklist.nonEnumerableAccounts[account] = true;
            }

            unchecked {
                ++i;
            }
        }
    }

    /**
     * @notice Adds one or more accounts to a whitelist.
     *
     * @dev Throws when the caller does not own the specified list.
     * @dev Throws when the accounts array is empty.
     *
     * @dev <h4>Postconditions:</h4>
     *      1. Accounts not previously in the list are added.
     *      2. An `AddedAccountToList` event is emitted for each account that is newly added to the list.
     *
     * @param id       The id of the list.
     * @param accounts The addresses of the accounts to add.
     */
    function addAccountsToWhitelist(
        uint120 id, 
        address[] calldata accounts
    ) external override 
    onlyListOwner(id) 
    notZero(accounts.length) {
        List storage whitelist = whitelists[id];
        address account;
        for (uint256 i = 0; i < accounts.length;) {
            account = accounts[i];

            if (account == address(0)) {
                revert CreatorTokenTransferValidator__ZeroAddressNotAllowed();
            }

            if (whitelist.enumerableAccounts.add(account)) {
                emit AddedAccountToList(ListTypes.Whitelist, id, account);
                whitelist.nonEnumerableAccounts[account] = true;
            }

            unchecked {
                ++i;
            }
        }
    }

    /**
     * @notice Adds one or more codehashes to a blacklist.
     *
     * @dev Throws when the caller does not own the specified list.
     * @dev Throws when the codehashes array is empty.
     * @dev Throws when a codehash is zero.
     *
     * @dev <h4>Postconditions:</h4>
     *      1. Codehashes not previously in the list are added.
     *      2. An `AddedCodeHashToList` event is emitted for each codehash that is newly added to the list.
     *
     * @param id         The id of the list.
     * @param codehashes The codehashes to add.
     */
    function addCodeHashesToBlacklist(
        uint120 id, 
        bytes32[] calldata codehashes
    ) external override
    onlyListOwner(id) 
    notZero(codehashes.length) {
        List storage blacklist = blacklists[id];
        bytes32 codehash;
        for (uint256 i = 0; i < codehashes.length;) {
            codehash = codehashes[i];

            if (codehash == CODEHASH_ZERO) {
                revert CreatorTokenTransferValidator__ZeroCodeHashNotAllowed();
            }

            if (blacklist.enumerableCodehashes.add(codehash)) {
                emit AddedCodeHashToList(ListTypes.Blacklist, id, codehash);
                blacklist.nonEnumerableCodehashes[codehash] = true;
            }

            unchecked {
                ++i;
            }
        }
    }

    /**
     * @notice Adds one or more codehashes to a whitelist.
     *
     * @dev Throws when the caller does not own the specified list.
     * @dev Throws when the codehashes array is empty.
     * @dev Throws when a codehash is zero.
     *
     * @dev <h4>Postconditions:</h4>
     *      1. Codehashes not previously in the list are added.
     *      2. An `AddedCodeHashToList` event is emitted for each codehash that is newly added to the list.
     *
     * @param id         The id of the list.
     * @param codehashes The codehashes to add.
     */
    function addCodeHashesToWhitelist(
        uint120 id, 
        bytes32[] calldata codehashes
    ) external override 
    onlyListOwner(id) 
    notZero(codehashes.length) {
        List storage whitelist = whitelists[id];
        bytes32 codehash;
        for (uint256 i = 0; i < codehashes.length;) {
            codehash = codehashes[i];

            if (codehash == CODEHASH_ZERO) {
                revert CreatorTokenTransferValidator__ZeroCodeHashNotAllowed();
            }

            if (whitelist.enumerableCodehashes.add(codehash)) {
                emit AddedCodeHashToList(ListTypes.Whitelist, id, codehash);
                whitelist.nonEnumerableCodehashes[codehash] = true;
            }

            unchecked {
                ++i;
            }
        }
    }

    /**
     * @notice Removes one or more accounts from a blacklist.
     *
     * @dev Throws when the caller does not own the specified list.
     * @dev Throws when the accounts array is empty.
     *
     * @dev <h4>Postconditions:</h4>
     *      1. Accounts previously in the list are removed.
     *      2. A `RemovedAccountFromList` event is emitted for each account that is removed from the list.
     *
     * @param id       The id of the list.
     * @param accounts The addresses of the accounts to remove.
     */
    function removeAccountsFromBlacklist(
        uint120 id, 
        address[] calldata accounts
    ) external override 
    onlyListOwner(id) 
    notZero(accounts.length) {
        List storage blacklist = blacklists[id];
        address account;
        for (uint256 i = 0; i < accounts.length;) {
            account = accounts[i];
            if (blacklist.enumerableAccounts.remove(account)) {
                emit RemovedAccountFromList(ListTypes.Blacklist, id, account);
                delete blacklist.nonEnumerableAccounts[account];
            }

            unchecked {
                ++i;
            }
        }
    }

    /**
     * @notice Removes one or more accounts from a whitelist.
     *
     * @dev Throws when the caller does not own the specified list.
     * @dev Throws when the accounts array is empty.
     *
     * @dev <h4>Postconditions:</h4>
     *      1. Accounts previously in the list are removed.
     *      2. A `RemovedAccountFromList` event is emitted for each account that is removed from the list.
     *
     * @param id       The id of the list.
     * @param accounts The addresses of the accounts to remove.
     */
    function removeAccountsFromWhitelist(
        uint120 id, 
        address[] calldata accounts
    ) external override 
    onlyListOwner(id) 
    notZero(accounts.length) {
        List storage whitelist = whitelists[id];
        address account;
        for (uint256 i = 0; i < accounts.length;) {
            account = accounts[i];
            if (whitelist.enumerableAccounts.remove(account)) {
                emit RemovedAccountFromList(ListTypes.Whitelist, id, account);
                delete whitelist.nonEnumerableAccounts[account];
            }

            unchecked {
                ++i;
            }
        }
    }

    /**
     * @notice Removes one or more codehashes from a blacklist.
     *
     * @dev Throws when the caller does not own the specified list.
     * @dev Throws when the codehashes array is empty.
     *
     * @dev <h4>Postconditions:</h4>
     *      1. Codehashes previously in the list are removed.
     *      2. A `RemovedCodeHashFromList` event is emitted for each codehash that is removed from the list.
     *
     * @param id         The id of the list.
     * @param codehashes The codehashes to remove.
     */
    function removeCodeHashesFromBlacklist(
        uint120 id, 
        bytes32[] calldata codehashes
    ) external override
    onlyListOwner(id) 
    notZero(codehashes.length) {
        List storage blacklist = blacklists[id];
        bytes32 codehash;
        for (uint256 i = 0; i < codehashes.length;) {
            codehash = codehashes[i];
            if (blacklist.enumerableCodehashes.remove(codehash)) {
                emit RemovedCodeHashFromList(ListTypes.Blacklist, id, codehash);
                delete blacklist.nonEnumerableCodehashes[codehash];
            }

            unchecked {
                ++i;
            }
        }
    }

    /**
     * @notice Removes one or more codehashes from a whitelist.
     *
     * @dev Throws when the caller does not own the specified list.
     * @dev Throws when the codehashes array is empty.
     *
     * @dev <h4>Postconditions:</h4>
     *      1. Codehashes previously in the list are removed.
     *      2. A `RemovedCodeHashFromList` event is emitted for each codehash that is removed from the list.
     *
     * @param id         The id of the list.
     * @param codehashes The codehashes to remove.
     */
    function removeCodeHashesFromWhitelist(
        uint120 id, 
        bytes32[] calldata codehashes
    ) external override
    onlyListOwner(id) 
    notZero(codehashes.length) {
        List storage whitelist = whitelists[id];
        bytes32 codehash;
        for (uint256 i = 0; i < codehashes.length;) {
            codehash = codehashes[i];
            if (whitelist.enumerableCodehashes.remove(codehash)) {
                emit RemovedCodeHashFromList(ListTypes.Whitelist, id, codehash);
                delete whitelist.nonEnumerableCodehashes[codehash];
            }

            unchecked {
                ++i;
            }
        }
    }

    /**
     * @notice Get blacklisted accounts by list id.
     * @param  id The id of the list.
     * @return An array of blacklisted accounts.
     */
    function getBlacklistedAccounts(uint120 id) public view override returns (address[] memory) {
        return blacklists[id].enumerableAccounts.values();
    }

    /**
     * @notice Get whitelisted accounts by list id.
     * @param  id The id of the list.
     * @return An array of whitelisted accounts.
     */
    function getWhitelistedAccounts(uint120 id) public view override returns (address[] memory) {
        return whitelists[id].enumerableAccounts.values();
    }

    /**
     * @notice Get blacklisted codehashes by list id.
     * @param id The id of the list.
     * @return   An array of blacklisted codehashes.
     */
    function getBlacklistedCodeHashes(uint120 id) public view override returns (bytes32[] memory) {
        return blacklists[id].enumerableCodehashes.values();
    }

    /**
     * @notice Get whitelisted codehashes by list id.
     * @param id The id of the list.
     * @return   An array of whitelisted codehashes.
     */
    function getWhitelistedCodeHashes(uint120 id) public view override returns (bytes32[] memory) {
        return whitelists[id].enumerableCodehashes.values();
    }

    /**
     * @notice Check if an account is blacklisted in a specified list.
     * @param id       The id of the list.
     * @param account  The address of the account to check.
     * @return         True if the account is blacklisted in the specified list, false otherwise.
     */
    function isAccountBlacklisted(uint120 id, address account) public view override returns (bool) {
        return blacklists[id].nonEnumerableAccounts[account];
    }

    /**
     * @notice Check if an account is whitelisted in a specified list.
     * @param id       The id of the list.
     * @param account  The address of the account to check.
     * @return         True if the account is whitelisted in the specified list, false otherwise.
     */
    function isAccountWhitelisted(uint120 id, address account) public view override returns (bool) {
        return whitelists[id].nonEnumerableAccounts[account];
    }

    /**
     * @notice Check if a codehash is blacklisted in a specified list.
     * @param id       The id of the list.
     * @param codehash  The codehash to check.
     * @return         True if the codehash is blacklisted in the specified list, false otherwise.
     */
    function isCodeHashBlacklisted(uint120 id, bytes32 codehash) public view override returns (bool) {
        return codehash == CODEHASH_ZERO ? false : blacklists[id].nonEnumerableCodehashes[codehash];
    }

    /**
     * @notice Check if a codehash is whitelisted in a specified list.
     * @param id       The id of the list.
     * @param codehash  The codehash to check.
     * @return         True if the codehash is whitelisted in the specified list, false otherwise.
     */
    function isCodeHashWhitelisted(uint120 id, bytes32 codehash) public view override returns (bool) {
        return codehash == CODEHASH_ZERO ? false : whitelists[id].nonEnumerableCodehashes[codehash];
    }

    /**
     * @notice Get blacklisted accounts by collection.
     * @param collection The address of the collection.
     * @return           An array of blacklisted accounts.
     */
    function getBlacklistedAccountsByCollection(address collection) external view override returns (address[] memory) {
        return getBlacklistedAccounts(collectionSecurityPolicies[collection].listId);
    }

    /**
     * @notice Get whitelisted accounts by collection.
     * @param collection The address of the collection.
     * @return           An array of whitelisted accounts.
     */
    function getWhitelistedAccountsByCollection(address collection) external view override returns (address[] memory) {
        return getWhitelistedAccounts(collectionSecurityPolicies[collection].listId);
    }

    /**
     * @notice Get blacklisted codehashes by collection.
     * @param collection The address of the collection.
     * @return           An array of blacklisted codehashes.
     */
    function getBlacklistedCodeHashesByCollection(address collection) external view override returns (bytes32[] memory) {
        return getBlacklistedCodeHashes(collectionSecurityPolicies[collection].listId);
    }

    /**
     * @notice Get whitelisted codehashes by collection.
     * @param collection The address of the collection.
     * @return           An array of whitelisted codehashes.
     */
    function getWhitelistedCodeHashesByCollection(address collection) external view override returns (bytes32[] memory) {
        return getWhitelistedCodeHashes(collectionSecurityPolicies[collection].listId);
    }

    /**
     * @notice Check if an account is blacklisted by a specified collection.
     * @param collection The address of the collection.
     * @param account    The address of the account to check.
     * @return           True if the account is blacklisted by the specified collection, false otherwise.
     */
    function isAccountBlacklistedByCollection(address collection, address account) external view override returns (bool) {
        return isAccountBlacklisted(collectionSecurityPolicies[collection].listId, account);
    }

    /**
     * @notice Check if an account is whitelisted by a specified collection.
     * @param collection The address of the collection.
     * @param account    The address of the account to check.
     * @return           True if the account is whitelisted by the specified collection, false otherwise.
     */
    function isAccountWhitelistedByCollection(address collection, address account) external view override returns (bool) {
        return isAccountWhitelisted(collectionSecurityPolicies[collection].listId, account);
    }

    /**
     * @notice Check if a codehash is blacklisted by a specified collection.
     * @param collection The address of the collection.
     * @param codehash   The codehash to check.
     * @return           True if the codehash is blacklisted by the specified collection, false otherwise.
     */
    function isCodeHashBlacklistedByCollection(address collection, bytes32 codehash) external view override returns (bool) {
        return isCodeHashBlacklisted(collectionSecurityPolicies[collection].listId, codehash);
    }

    /**
     * @notice Check if a codehash is whitelisted by a specified collection.
     * @param collection The address of the collection.
     * @param codehash   The codehash to check.
     * @return           True if the codehash is whitelisted by the specified collection, false otherwise.
     */
    function isCodeHashWhitelistedByCollection(address collection, bytes32 codehash) external view override returns (bool) {
        return isCodeHashWhitelisted(collectionSecurityPolicies[collection].listId, codehash);
    }

    /// @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(ITransferSecurityRegistryV2).interfaceId ||
            interfaceId == type(ICreatorTokenTransferValidator).interfaceId ||
            interfaceId == type(ICreatorTokenTransferValidatorV2).interfaceId ||
            super.supportsInterface(interfaceId);
    }

    /*************************************************************************/
    /*                                HELPERS                                */
    /*************************************************************************/

    /**
     * @notice Reverts the transaction if the caller is not the owner or assigned the default
     * @notice admin role of the contract at `tokenAddress`.
     *
     * @dev    Throws when the caller is neither owner nor assigned the default admin role.
     * 
     * @param tokenAddress The contract address of the token to check permissions for.
     */
    function _requireCallerIsNFTOrContractOwnerOrAdmin(address tokenAddress) internal view {
        bool callerHasPermissions = false;
        if(_getCodeLengthAsm(tokenAddress) > 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();
        }
    }

    /**
     * @notice Copies all addresses in `ptrFromList` to `ptrToList`.
     * 
     * @dev    This function will copy all addresses from one list to another list.
     * @dev    Note: If used to copy adddresses to an existing list the current list contents will not be
     * @dev    deleted before copying. New addresses will be appeneded to the end of the list and the
     * @dev    non-enumerable mapping key value will be set to true.
     * 
     * @dev <h4>Postconditions:</h4>
     *      1. Addresses in from list that are not already present in to list are added to the to list.
     *      2. Emits an `AddedAccountToList` event for each address copied to the list.
     * 
     * @param  listType          The type of list addresses are being copied from and to.
     * @param  destinationListId The id of the list being copied to.
     * @param  ptrFromList       The storage pointer for the list being copied from.
     * @param  ptrToList         The storage pointer for the list being copied to.
     */
    function _copyAddressSet(
        ListTypes listType,
        uint120 destinationListId,
        List storage ptrFromList,
        List storage ptrToList
    ) private {
        EnumerableSet.AddressSet storage ptrFromSet = ptrFromList.enumerableAccounts;
        EnumerableSet.AddressSet storage ptrToSet = ptrToList.enumerableAccounts;
        mapping (address => bool) storage ptrToNonEnumerableSet = ptrToList.nonEnumerableAccounts;
        uint256 sourceLength = ptrFromSet.length();
        address account;
        for (uint256 i = 0; i < sourceLength;) {
            account = ptrFromSet.at(i); 
            if (ptrToSet.add(account)) {
                emit AddedAccountToList(listType, destinationListId, account);
                ptrToNonEnumerableSet[account] = true;
            }

            unchecked {
                ++i;
            }
        }
    }

    /**
     * @notice Copies all codehashes in `ptrFromList` to `ptrToList`.
     * 
     * @dev    This function will copy all codehashes from one list to another list.
     * @dev    Note: If used to copy codehashes to an existing list the current list contents will not be
     * @dev    deleted before copying. New codehashes will be appeneded to the end of the list and the
     * @dev    non-enumerable mapping key value will be set to true.
     * 
     * @dev <h4>Postconditions:</h4>
     *      1. Codehashes in from list that are not already present in to list are added to the to list.
     *      2. Emits an `AddedCodeHashToList` event for each codehash copied to the list.
     * 
     * @param  listType          The type of list codehashes are being copied from and to.
     * @param  destinationListId The id of the list being copied to.
     * @param  ptrFromList       The storage pointer for the list being copied from.
     * @param  ptrToList         The storage pointer for the list being copied to.
     */
    function _copyBytes32Set(
        ListTypes listType,
        uint120 destinationListId,
        List storage ptrFromList,
        List storage ptrToList
    ) private {
        EnumerableSet.Bytes32Set storage ptrFromSet = ptrFromList.enumerableCodehashes;
        EnumerableSet.Bytes32Set storage ptrToSet = ptrToList.enumerableCodehashes;
        mapping (bytes32 => bool) storage ptrToNonEnumerableSet = ptrToList.nonEnumerableCodehashes;
        uint256 sourceLength = ptrFromSet.length();
        bytes32 codehash;
        for (uint256 i = 0; i < sourceLength;) {
            codehash = ptrFromSet.at(i);
            if (ptrToSet.add(codehash)) {
                emit AddedCodeHashToList(listType, destinationListId, codehash);
                ptrToNonEnumerableSet[codehash] = true;
            }

            unchecked {
                ++i;
            }
        }
    }

    /**
     * @notice Sets the owner of list `id` to `newOwner`.
     * 
     * @dev    Throws when the caller is not the owner of the list.
     * 
     * @dev    <h4>Postconditions:</h4>
     *         1. The owner of list `id` is set to `newOwner`.
     *         2. Emits a `ReassignedListOwnership` event.
     */
    function _reassignOwnershipOfList(uint120 id, address newOwner) private {
        _requireCallerOwnsList(id);
        listOwners[id] = newOwner;
        emit ReassignedListOwnership(id, newOwner);
    }

    /**
     * @notice Requires the caller to be the owner of list `id`.
     * 
     * @dev    Throws when the caller is not the owner of the list.
     */
    function _requireCallerOwnsList(uint120 id) private view {
        if (_msgSender() != listOwners[id]) {
            revert CreatorTokenTransferValidator__CallerDoesNotOwnList();
        }
    }

    /**
     * @dev Internal function used to efficiently retrieve the code length of `account`.
     * 
     * @param account The address to get the deployed code length for.
     * 
     * @return length The length of deployed code at the address.
     */
    function _getCodeLengthAsm(address account) internal view returns (uint256 length) {
        assembly { length := extcodesize(account) }
    }

    /**
     * @dev Internal function used to efficiently retrieve the codehash of `account`.
     * 
     * @param account The address to get the deployed codehash for.
     * 
     * @return codehash The codehash of the deployed code at the address.
     */
    function _getCodeHashAsm(address account) internal view returns (bytes32 codehash) {
        assembly { codehash := extcodehash(account) }
    }

    /*************************************************************************/
    /*                        BACKWARDS COMPATIBILITY                        */
    /*************************************************************************/

    /**
     * @notice Maps to `createList` in V2.
     */
    function createOperatorWhitelist(string calldata name) external override returns (uint120) {
        return createList(name);
    }

    /**
     * @notice Maps to `reassignOwnershipOfList` in V2.
     */
    function reassignOwnershipOfOperatorWhitelist(uint120 id, address newOwner) external override {
        reassignOwnershipOfList(id, newOwner);
    }

    /**
     * @notice Maps to `renounceOwnershipOfList` in V2.
     */
    function renounceOwnershipOfOperatorWhitelist(uint120 id) external override {
        renounceOwnershipOfList(id);
    }

    /**
     * @notice Maps to `applyListToCollection` in V2.
     */
    function setOperatorWhitelistOfCollection(address collection, uint120 id) external override {
        applyListToCollection(collection, id);
    }

    /**
     * @notice Adds a single account to the specified whitelist.
     * @dev    Throws when the caller does not own the specified list.
     */
    function addOperatorToWhitelist(uint120 id, address operator) external override onlyListOwner(id) {
        List storage whitelist = whitelists[id];
        if (whitelist.enumerableAccounts.add(operator)) {
            emit AddedAccountToList(ListTypes.Whitelist, id, operator);
            whitelist.nonEnumerableAccounts[operator] = true;
        }
    }

    /**
     * @notice Removes a single account from the specified whitelist.
     * @dev    Throws when the caller does not own the specified list.
     */
    function removeOperatorFromWhitelist(uint120 id, address operator) external override onlyListOwner(id) {
        List storage whitelist = whitelists[id];
        if (whitelist.enumerableAccounts.remove(operator)) {
            emit RemovedAccountFromList(ListTypes.Whitelist, id, operator);
            delete whitelist.nonEnumerableAccounts[operator];
        }
    }

    /**
     * @notice Gets the V1 Collection Security Policy information.  
     *         Assigns both operatorWhitelistId and permittedContractReceiversId to the listId.
     */
    function getCollectionSecurityPolicy(address collection) external view override returns (CollectionSecurityPolicy memory) {
        CollectionSecurityPolicyV2 memory collectionSecurityPolicy = collectionSecurityPolicies[collection];

        return CollectionSecurityPolicy({
            transferSecurityLevel: collectionSecurityPolicy.transferSecurityLevel,
            operatorWhitelistId: collectionSecurityPolicy.listId,
            permittedContractReceiversId: collectionSecurityPolicy.listId
        });
    }

    /**
     * @notice Maps to `getWhitelistedAccounts` in V2.
     */
    function getWhitelistedOperators(uint120 id) external view override returns (address[] memory) {
        return getWhitelistedAccounts(id);
    }

    /**
     * @notice Maps to `getWhitelistedAccounts` in V2.
     */
    function getPermittedContractReceivers(uint120 id) external view override returns (address[] memory) {
        return getWhitelistedAccounts(id);
    }

    /**
     * @notice Maps to `isAccountWhitelisted` in V2.
     */
    function isOperatorWhitelisted(uint120 id, address operator) external view override returns (bool) {
        return isAccountWhitelisted(id, operator);
    }

    /**
     * @notice Maps to `isAccountWhitelisted` in V2.
     */
    function isContractReceiverPermitted(uint120 id, address receiver) external view override returns (bool) {
        return isAccountWhitelisted(id, receiver);
    }

    /**
     * @notice NO-OP Because V2 Allows Whitelisted Accounts To Be Contract Receivers Automatically.
     * @return 0
     */
    function createPermittedContractReceiverAllowlist(string calldata /*name*/) external pure override returns (uint120) {
        return 0;
    }

    /**
     * @notice NO-OP Because V2 Allows Whitelisted Accounts To Be Contract Receivers Automatically.
     */
    function reassignOwnershipOfPermittedContractReceiverAllowlist(
        uint120 /*id*/, 
        address /*newOwner*/
    ) external pure override {}

    /**
     * @notice NO-OP Because V2 Allows Whitelisted Accounts To Be Contract Receivers Automatically.
     */
    function renounceOwnershipOfPermittedContractReceiverAllowlist(uint120 /*id*/) external pure override {}

    /**
     * @notice NO-OP Because V2 Allows Whitelisted Accounts To Be Contract Receivers Automatically.
     */
    function setPermittedContractReceiverAllowlistOfCollection(
        address /*collection*/, 
        uint120 /*id*/
    ) external pure override {}

    /**
     * @notice NO-OP Because V2 Allows Whitelisted Accounts To Be Contract Receivers Automatically.
     */
    function addPermittedContractReceiverToAllowlist(uint120 /*id*/, address /*receiver*/) external pure override {}

    /**
     * @notice NO-OP Because V2 Allows Whitelisted Accounts To Be Contract Receivers Automatically.
     */
    function removePermittedContractReceiverFromAllowlist(
        uint120 /*id*/, 
        address /*receiver*/
    ) external pure override {}
}

File 2 of 18 : 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";

/// @dev Thrown when the caller does not match the recovered address for the signature.
error CallerDidNotSignTheMessage();

/// @dev Thrown when the caller has already been verified.
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 3 of 18 : IOwnable.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

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

File 4 of 18 : 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 5 of 18 : ICreatorTokenTransferValidatorV2.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

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

interface ICreatorTokenTransferValidatorV2 is ITransferSecurityRegistryV2, ITransferValidator, IEOARegistry {}

File 6 of 18 : 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 7 of 18 : EnumerableSet.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.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.
 *
 * ```
 * 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;
    }
}

File 8 of 18 : 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 9 of 18 : Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (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;
    }
}

File 10 of 18 : 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 11 of 18 : ECDSA.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.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) {
        // 32 is the length in bytes of hash,
        // enforced by the type signature above
        return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
    }

    /**
     * @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) {
        return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));
    }
}

File 12 of 18 : 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 13 of 18 : 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 14 of 18 : ITransferSecurityRegistryV2.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import "./ITransferSecurityRegistry.sol";

interface ITransferSecurityRegistryV2 is ITransferSecurityRegistry {
    event CreatedList(uint256 indexed id, string name);
    event AppliedListToCollection(address indexed collection, uint120 indexed id);
    event ReassignedListOwnership(uint256 indexed id, address indexed newOwner);
    event AddedAccountToList(ListTypes indexed kind, uint256 indexed id, address indexed account);
    event AddedCodeHashToList(ListTypes indexed kind, uint256 indexed id, bytes32 indexed codehash);
    event RemovedAccountFromList(ListTypes indexed kind, uint256 indexed id, address indexed account);
    event RemovedCodeHashFromList(ListTypes indexed kind, uint256 indexed id, bytes32 indexed codehash);

    function transferSecurityPolicies(TransferSecurityLevels level) external pure returns (CallerConstraints callerConstraints, ReceiverConstraints receiverConstraints);
    function createList(string calldata name) external returns (uint120);
    function createListCopy(string calldata name, uint120 sourceListId) external returns (uint120);
    function reassignOwnershipOfList(uint120 id, address newOwner) external;
    function renounceOwnershipOfList(uint120 id) external;
    function applyListToCollection(address collection, uint120 id) external;
    function getCollectionSecurityPolicyV2(address collection) external view returns (CollectionSecurityPolicyV2 memory);
    function addAccountsToBlacklist(uint120 id, address[] calldata accounts) external;
    function addAccountsToWhitelist(uint120 id, address[] calldata accounts) external;
    function addCodeHashesToBlacklist(uint120 id, bytes32[] calldata codehashes) external;
    function addCodeHashesToWhitelist(uint120 id, bytes32[] calldata codehashes) external;
    function removeAccountsFromBlacklist(uint120 id, address[] calldata accounts) external;
    function removeAccountsFromWhitelist(uint120 id, address[] calldata accounts) external;
    function removeCodeHashesFromBlacklist(uint120 id, bytes32[] calldata codehashes) external;
    function removeCodeHashesFromWhitelist(uint120 id, bytes32[] calldata codehashes) external;
    function getBlacklistedAccounts(uint120 id) external view returns (address[] memory);
    function getWhitelistedAccounts(uint120 id) external view returns (address[] memory);
    function getBlacklistedCodeHashes(uint120 id) external view returns (bytes32[] memory);
    function getWhitelistedCodeHashes(uint120 id) external view returns (bytes32[] memory);
    function isAccountBlacklisted(uint120 id, address account) external view returns (bool);
    function isAccountWhitelisted(uint120 id, address account) external view returns (bool);
    function isCodeHashBlacklisted(uint120 id, bytes32 codehash) external view returns (bool);
    function isCodeHashWhitelisted(uint120 id, bytes32 codehash) external view returns (bool);
    function getBlacklistedAccountsByCollection(address collection) external view returns (address[] memory);
    function getWhitelistedAccountsByCollection(address collection) external view returns (address[] memory);
    function getBlacklistedCodeHashesByCollection(address collection) external view returns (bytes32[] memory);
    function getWhitelistedCodeHashesByCollection(address collection) external view returns (bytes32[] memory);
    function isAccountBlacklistedByCollection(address collection, address account) external view returns (bool);
    function isAccountWhitelistedByCollection(address collection, address account) external view returns (bool);
    function isCodeHashBlacklistedByCollection(address collection, bytes32 codehash) external view returns (bool);
    function isCodeHashWhitelistedByCollection(address collection, bytes32 codehash) external view returns (bool);
}

File 15 of 18 : 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 16 of 18 : Strings.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)

pragma solidity ^0.8.0;

import "./math/Math.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 `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);
    }
}

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

/** 
 * @dev Used in events to indicate the list type that an account or 
 * @dev codehash is being added to or removed from.
 * 
 * @dev Used in Creator Token Standards V2.
 */
enum ListTypes {
    // 0: List type that will block a matching address/codehash that is on the list.
    Blacklist,

    // 1: List type that will block any matching address/codehash that is not on the list.
    Whitelist
}

/** 
 * @dev Used in events to indicate the list type that event relates to.
 * 
 * @dev Used in Creator Token Standards V1.
 */
enum AllowlistTypes {
    // 0: List type that defines the allowed operator addresses.
    Operators,

    // 1: List type that defines the allowed contract receivers.
    PermittedContractReceivers
}

/**
 @dev Defines the constraints that will be applied for receipt of tokens.
 */
enum ReceiverConstraints {
    // 0: Any address may receive tokens.
    None,

    // 1: Address must not have deployed bytecode.
    NoCode,

    // 2: Address must verify a signature with the EOA Registry to prove it is an EOA.
    EOA
}

/**
 * @dev Defines the constraints that will be applied to the transfer caller.
 */
enum CallerConstraints {
    // 0: Any address may transfer tokens.
    None,

    // 1: Addresses and codehashes not on the blacklist may transfer tokens.
    OperatorBlacklistEnableOTC,

    // 2: Addresses and codehashes on the whitelist and the owner of the token may transfer tokens.
    OperatorWhitelistEnableOTC,

    // 3: Addresses and codehashes on the whitelist may transfer tokens.
    OperatorWhitelistDisableOTC
}

/**
 * @dev Defines constraints for staking tokens in token wrapper contracts.
 */
enum StakerConstraints {
    // 0: No constraints applied to staker.
    None,

    // 1: Transaction originator must be the address that will receive the wrapped tokens.
    CallerIsTxOrigin,

    // 2: Address that will receive the wrapped tokens must be a verified EOA.
    EOA
}

/**
 * @dev Used in both Creator Token Standards V1 and V2.
 * @dev Levels may have different transfer restrictions in V1 and V2. Refer to the 
 * @dev Creator Token Transfer Validator implementation for the version being utilized
 * @dev to determine the effect of the selected level.
 */
enum TransferSecurityLevels {
    Recommended,
    One,
    Two,
    Three,
    Four,
    Five,
    Six,
    Seven,
    Eight
}

/**
 * @dev Defines the caller and receiver constraints for a transfer security level.
 * @dev Used in Creator Token Standards V1.
 * 
 * @dev **callerConstraints**: The restrictions applied to the transfer caller.
 * @dev **receiverConstraints**: The restrictions applied to the transfer recipient.
 */
struct TransferSecurityPolicy {
    CallerConstraints callerConstraints;
    ReceiverConstraints receiverConstraints;
}

/**
 * @dev Defines the security policy for a token collection in Creator Token Standards V1.
 * 
 * @dev **transferSecurityLevel**: The transfer security level set for the collection.
 * @dev **operatorWhitelistId**: The list id for the operator whitelist.
 * @dev **permittedContractReceiversId: The list id for the contracts that are allowed to receive tokens.
 */
struct CollectionSecurityPolicy {
    TransferSecurityLevels transferSecurityLevel;
    uint120 operatorWhitelistId;
    uint120 permittedContractReceiversId;
}

/**
 * @dev Defines the security policy for a token collection in Creator Token Standards V2.
 * 
 * @dev **transferSecurityLevel**: The transfer security level set for the collection.
 * @dev **listId**: The list id that contains the blacklist and whitelist to apply to the collection.
 */
struct CollectionSecurityPolicyV2 {
    TransferSecurityLevels transferSecurityLevel;
    uint120 listId;
}

/** 
 * @dev Used internally in the Creator Token Base V2 contract to pack transfer validator configuration.
 * 
 * @dev **isInitialized**: If not initialized by the collection owner or admin the default validator will be used.
 * @dev **version**: The transfer validator version.
 * @dev **transferValidator**: The address of the transfer validator to use for applying collection security settings.
 */
struct TransferValidatorReference {
    bool isInitialized;
    uint16 version;
    address transferValidator;
}

File 18 of 18 : Math.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.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) {
                return prod0 / denominator;
            }

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            require(denominator > prod1);

            ///////////////////////////////////////////////
            // 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 10, 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 * 8) < value ? 1 : 0);
        }
    }
}

Settings
{
  "remappings": [
    "@openzeppelin/=lib/openzeppelin-contracts/",
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "forge-std/=lib/forge-std/src/",
    "murky/=lib/murky/src/",
    "erc721a/=lib/ERC721A/",
    "@rari-capital/solmate/=lib/PermitC/lib/solmate/",
    "ERC721A/=lib/ERC721A/contracts/",
    "PermitC/=lib/PermitC/",
    "erc4626-tests/=lib/PermitC/lib/openzeppelin-contracts/lib/erc4626-tests/",
    "forge-gas-metering/=lib/PermitC/lib/forge-gas-metering/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/",
    "openzeppelin/=lib/PermitC/lib/openzeppelin-contracts/contracts/",
    "solady/=lib/PermitC/lib/forge-gas-metering/lib/solady/",
    "solmate/=lib/PermitC/lib/solmate/src/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 1000000
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "paris",
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"defaultOwner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"CallerDidNotSignTheMessage","type":"error"},{"inputs":[],"name":"CreatorTokenTransferValidator__ArrayLengthCannotBeZero","type":"error"},{"inputs":[],"name":"CreatorTokenTransferValidator__CallerDoesNotOwnList","type":"error"},{"inputs":[],"name":"CreatorTokenTransferValidator__CallerMustBeWhitelisted","type":"error"},{"inputs":[],"name":"CreatorTokenTransferValidator__CallerMustHaveElevatedPermissionsForSpecifiedNFT","type":"error"},{"inputs":[],"name":"CreatorTokenTransferValidator__ListDoesNotExist","type":"error"},{"inputs":[],"name":"CreatorTokenTransferValidator__ListOwnershipCannotBeTransferredToZeroAddress","type":"error"},{"inputs":[],"name":"CreatorTokenTransferValidator__OperatorIsBlacklisted","type":"error"},{"inputs":[],"name":"CreatorTokenTransferValidator__ReceiverMustNotHaveDeployedCode","type":"error"},{"inputs":[],"name":"CreatorTokenTransferValidator__ReceiverProofOfEOASignatureUnverified","type":"error"},{"inputs":[],"name":"CreatorTokenTransferValidator__ZeroAddressNotAllowed","type":"error"},{"inputs":[],"name":"CreatorTokenTransferValidator__ZeroCodeHashNotAllowed","type":"error"},{"inputs":[],"name":"SignatureAlreadyVerified","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"enum ListTypes","name":"kind","type":"uint8"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"AddedAccountToList","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"enum ListTypes","name":"kind","type":"uint8"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"bytes32","name":"codehash","type":"bytes32"}],"name":"AddedCodeHashToList","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":"AddedToAllowlist","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"collection","type":"address"},{"indexed":true,"internalType":"uint120","name":"id","type":"uint120"}],"name":"AppliedListToCollection","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":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"string","name":"name","type":"string"}],"name":"CreatedList","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":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"ReassignedListOwnership","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"enum ListTypes","name":"kind","type":"uint8"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"RemovedAccountFromList","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"enum ListTypes","name":"kind","type":"uint8"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"bytes32","name":"codehash","type":"bytes32"}],"name":"RemovedCodeHashFromList","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":"MESSAGE_TO_SIGN","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint120","name":"id","type":"uint120"},{"internalType":"address[]","name":"accounts","type":"address[]"}],"name":"addAccountsToBlacklist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint120","name":"id","type":"uint120"},{"internalType":"address[]","name":"accounts","type":"address[]"}],"name":"addAccountsToWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint120","name":"id","type":"uint120"},{"internalType":"bytes32[]","name":"codehashes","type":"bytes32[]"}],"name":"addCodeHashesToBlacklist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint120","name":"id","type":"uint120"},{"internalType":"bytes32[]","name":"codehashes","type":"bytes32[]"}],"name":"addCodeHashesToWhitelist","outputs":[],"stateMutability":"nonpayable","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":"","type":"uint120"},{"internalType":"address","name":"","type":"address"}],"name":"addPermittedContractReceiverToAllowlist","outputs":[],"stateMutability":"pure","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":"address","name":"collection","type":"address"},{"internalType":"uint120","name":"id","type":"uint120"}],"name":"applyListToCollection","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"name","type":"string"}],"name":"createList","outputs":[{"internalType":"uint120","name":"","type":"uint120"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"uint120","name":"sourceListId","type":"uint120"}],"name":"createListCopy","outputs":[{"internalType":"uint120","name":"","type":"uint120"}],"stateMutability":"nonpayable","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":"","type":"string"}],"name":"createPermittedContractReceiverAllowlist","outputs":[{"internalType":"uint120","name":"","type":"uint120"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint120","name":"id","type":"uint120"}],"name":"getBlacklistedAccounts","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"}],"name":"getBlacklistedAccountsByCollection","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint120","name":"id","type":"uint120"}],"name":"getBlacklistedCodeHashes","outputs":[{"internalType":"bytes32[]","name":"","type":"bytes32[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"}],"name":"getBlacklistedCodeHashesByCollection","outputs":[{"internalType":"bytes32[]","name":"","type":"bytes32[]"}],"stateMutability":"view","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":"address","name":"collection","type":"address"}],"name":"getCollectionSecurityPolicyV2","outputs":[{"components":[{"internalType":"enum TransferSecurityLevels","name":"transferSecurityLevel","type":"uint8"},{"internalType":"uint120","name":"listId","type":"uint120"}],"internalType":"struct CollectionSecurityPolicyV2","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":"getWhitelistedAccounts","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"}],"name":"getWhitelistedAccountsByCollection","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint120","name":"id","type":"uint120"}],"name":"getWhitelistedCodeHashes","outputs":[{"internalType":"bytes32[]","name":"","type":"bytes32[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"}],"name":"getWhitelistedCodeHashesByCollection","outputs":[{"internalType":"bytes32[]","name":"","type":"bytes32[]"}],"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":"account","type":"address"}],"name":"isAccountBlacklisted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"},{"internalType":"address","name":"account","type":"address"}],"name":"isAccountBlacklistedByCollection","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint120","name":"id","type":"uint120"},{"internalType":"address","name":"account","type":"address"}],"name":"isAccountWhitelisted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"},{"internalType":"address","name":"account","type":"address"}],"name":"isAccountWhitelistedByCollection","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint120","name":"id","type":"uint120"},{"internalType":"bytes32","name":"codehash","type":"bytes32"}],"name":"isCodeHashBlacklisted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"},{"internalType":"bytes32","name":"codehash","type":"bytes32"}],"name":"isCodeHashBlacklistedByCollection","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint120","name":"id","type":"uint120"},{"internalType":"bytes32","name":"codehash","type":"bytes32"}],"name":"isCodeHashWhitelisted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"},{"internalType":"bytes32","name":"codehash","type":"bytes32"}],"name":"isCodeHashWhitelistedByCollection","outputs":[{"internalType":"bool","name":"","type":"bool"}],"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":[],"name":"lastListId","outputs":[{"internalType":"uint120","name":"","type":"uint120"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint120","name":"","type":"uint120"}],"name":"listOwners","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint120","name":"id","type":"uint120"},{"internalType":"address","name":"newOwner","type":"address"}],"name":"reassignOwnershipOfList","outputs":[],"stateMutability":"nonpayable","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":"","type":"uint120"},{"internalType":"address","name":"","type":"address"}],"name":"reassignOwnershipOfPermittedContractReceiverAllowlist","outputs":[],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint120","name":"id","type":"uint120"},{"internalType":"address[]","name":"accounts","type":"address[]"}],"name":"removeAccountsFromBlacklist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint120","name":"id","type":"uint120"},{"internalType":"address[]","name":"accounts","type":"address[]"}],"name":"removeAccountsFromWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint120","name":"id","type":"uint120"},{"internalType":"bytes32[]","name":"codehashes","type":"bytes32[]"}],"name":"removeCodeHashesFromBlacklist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint120","name":"id","type":"uint120"},{"internalType":"bytes32[]","name":"codehashes","type":"bytes32[]"}],"name":"removeCodeHashesFromWhitelist","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":"","type":"uint120"},{"internalType":"address","name":"","type":"address"}],"name":"removePermittedContractReceiverFromAllowlist","outputs":[],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint120","name":"id","type":"uint120"}],"name":"renounceOwnershipOfList","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint120","name":"id","type":"uint120"}],"name":"renounceOwnershipOfOperatorWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint120","name":"","type":"uint120"}],"name":"renounceOwnershipOfPermittedContractReceiverAllowlist","outputs":[],"stateMutability":"pure","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":"","type":"address"},{"internalType":"uint120","name":"","type":"uint120"}],"name":"setPermittedContractReceiverAllowlistOfCollection","outputs":[],"stateMutability":"pure","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":"level","type":"uint8"}],"name":"transferSecurityPolicies","outputs":[{"internalType":"enum CallerConstraints","name":"callerConstraints","type":"uint8"},{"internalType":"enum ReceiverConstraints","name":"receiverConstraints","type":"uint8"}],"stateMutability":"pure","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"}]

60a06040523480156200001157600080fd5b50604051620040d6380380620040d683398101604081905262000034916200030b565b604080518082019091526003815262454f4160e81b6020820152620000599062000143565b608052600080805260026020527fac33ff75c19e70fe83507db0d683fd3465c996598dc972688b7ace676c89077b80546001600160a01b0384166001600160a01b031990911617905560405181907f5cc365f89543268cb9f25c255f7f610e9147e733c589bc2732279575f125be1490620000f4906020808252600c908201526b1111519055531508131254d560a21b604082015260600190565b60405180910390a26040516001600160a01b038316906001600160781b038316907f9b0894203394c3cbb23140db7a23b224d3e18e0366e9f65bd9c8402650e2736790600090a35050620003d8565b60006200015782516200018860201b60201c565b826040516020016200016b92919062000363565b604051602081830303815290604052805190602001209050919050565b60606000620001978362000221565b60010190506000816001600160401b03811115620001b957620001b9620003c2565b6040519080825280601f01601f191660200182016040528015620001e4576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a8504945084620001ee57509392505050565b6000807a184f03e93ff9f4daa797ed6e38ed64bf6a1f01000000000000000083106200026b577a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000830492506040015b6d04ee2d6d415b85acef8100000000831062000298576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc100008310620002b757662386f26fc10000830492506010015b6305f5e1008310620002d0576305f5e100830492506008015b6127108310620002e557612710830492506004015b60648310620002f8576064830492506002015b600a831062000305576001015b92915050565b6000602082840312156200031e57600080fd5b81516001600160a01b03811681146200033657600080fd5b9392505050565b60005b838110156200035a57818101518382015260200162000340565b50506000910152565b7f19457468657265756d205369676e6564204d6573736167653a0a0000000000008152600083516200039d81601a8501602088016200033d565b835190830190620003b681601a8401602088016200033d565b01601a01949350505050565b634e487b7160e01b600052604160045260246000fd5b608051613cdb620003fb60003960008181611b5301526128960152613cdb6000f3fe608060405234801561001057600080fd5b50600436106103835760003560e01c80637f39e7e4116101de578063ae602f441161010f578063d72dde5e116100ad578063e30cd5e11161007c578063e30cd5e1146104e2578063e991dc30146108ef578063f80af98414610902578063fec1d6431461091557600080fd5b8063d72dde5e14610748578063da0194c0146108b6578063de02cbb1146108c9578063def0125b146108dc57600080fd5b8063b8dcc68f116100e9578063b8dcc68f1461085d578063b955455214610870578063bf7bfd7e14610890578063d415f62f146108a357600080fd5b8063ae602f44146107d9578063b6567f2214610834578063b67d8f991461084a57600080fd5b80639445f5301161017c5780639e814cae116101565780639e814cae14610781578063a1cc5cc1146107a2578063a5d56b46146107b5578063a9f138eb146107c857600080fd5b80639445f53014610748578063982d03c01461075b57806399f9a6781461076e57600080fd5b80638b6ee865116101b85780638b6ee865146107015780638d744314146107145780638e28800f146107225780639340a7cc1461073557600080fd5b80637f39e7e41461069557806389631626146106b557806389a9c855146106c857600080fd5b806333f0901b116102b8578063515f7b28116102565780636bfab91d116102305780636bfab91d146106495780637161ac8d1461065c578063731fb9d81461066f5780637bac97de1461068257600080fd5b8063515f7b28146106105780635e17263d14610623578063697108281461063657600080fd5b80633fe5df99116102925780633fe5df99146104cf578063409dc573146105d75780634c9d0b45146105ea578063501b7d2e146105fd57600080fd5b806333f0901b1461057b57806334778f6a146105c4578063372fb54d146104e257600080fd5b806317e94a6c1161032557806323c99262116102ff57806323c9926214610507578063285fb8c8146105425780632c7fe70a146105555780632eb0b98a1461056857600080fd5b806317e94a6c146104cf57806318fbf6fe146104e25780632304aa02146104f457600080fd5b806310b5c6a01161036157806310b5c6a0146104215780631390a2c21461044157806316a17ce01461045457806316f18d74146104af57600080fd5b8063015499301461038857806301ffc9a71461039d578063057497cb146103c5575b600080fd5b61039b6103963660046135dd565b610928565b005b6103b06103ab366004613630565b610ad5565b60405190151581526020015b60405180910390f35b6103b06103d3366004613694565b6effffffffffffffffffffffffffffff8216600090815260056020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845260040190915290205460ff1692915050565b61043461042f3660046136cb565b610c1f565b6040516103bc91906136e6565b61039b61044f366004613694565b610c4b565b6103b0610462366004613694565b6effffffffffffffffffffffffffffff8216600090815260046020818152604080842073ffffffffffffffffffffffffffffffffffffffff86168552909201905290205460ff1692915050565b6104c26104bd366004613740565b610d2c565b6040516103bc919061375d565b6104346104dd3660046136cb565b610d74565b61039b6104f0366004613694565b5050565b61039b610502366004613795565b610d7f565b600154610522906effffffffffffffffffffffffffffff1681565b6040516effffffffffffffffffffffffffffff90911681526020016103bc565b61039b6105503660046137ca565b610d89565b6103b0610563366004613815565b611212565b61039b6105763660046135dd565b61125f565b6105b76040518060400160405280600381526020017f454f41000000000000000000000000000000000000000000000000000000000081525081565b6040516103bc9190613841565b61039b6105d23660046136cb565b6113b2565b61039b6105e53660046135dd565b6113bb565b6104c26105f83660046136cb565b611513565b61052261060b3660046138ef565b611542565b61039b61061e3660046135dd565b61154e565b6103b0610631366004613931565b611672565b61039b6106443660046135dd565b6116b9565b61039b610657366004613694565b61180c565b6104c261066a3660046136cb565b611863565b61039b61067d366004613694565b611892565b6103b061069036600461394d565b61189c565b6106a86106a3366004613740565b6118fd565b6040516103bc91906139ae565b6104346106c33660046136cb565b61198f565b6103b06106d6366004613740565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205460ff1690565b61039b61070f3660046136cb565b6119bb565b61039b6104f0366004613795565b6103b061073036600461394d565b6119c6565b6104c2610743366004613740565b611a27565b6103b0610756366004613694565b611a6f565b610434610769366004613740565b611abc565b61039b61077c3660046139e0565b611b04565b61079461078f366004613a2a565b611c41565b6040516103bc929190613a45565b61039b6107b03660046135dd565b611d75565b61039b6107c33660046135dd565b611f18565b61039b6107d63660046136cb565b50565b61080f6107e73660046136cb565b60026020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016103bc565b6105226108423660046138ef565b600092915050565b6103b0610858366004613815565b612070565b61052261086b3660046138ef565b6120b6565b61088361087e366004613740565b6121fb565b6040516103bc9190613a79565b61039b61089e366004613795565b6122f4565b6103b06108b1366004613931565b6123e3565b61039b6108c4366004613abd565b612422565b6105226108d7366004613ae9565b6124e2565b61039b6108ea3660046135dd565b6126db565b6104346108fd366004613740565b6127ff565b61039b6109103660046138ef565b612847565b61039b610923366004613694565b6129b7565b8261093281612a9a565b81600081900361096e576040517fd13675da00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6effffffffffffffffffffffffffffff8516600090815260046020526040812090805b85811015610acb578686828181106109ab576109ab613b3d565b90506020020160208101906109c09190613740565b915073ffffffffffffffffffffffffffffffffffffffff8216610a0f576040517f64019f1100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610a198383612b1f565b15610ac35773ffffffffffffffffffffffffffffffffffffffff82166effffffffffffffffffffffffffffff891660006040517fda8f3bd170446760f0f965a9b52bf271cb9679b5e0a70059eff2d49425229d1790600090a473ffffffffffffffffffffffffffffffffffffffff82166000908152600484016020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555b600101610991565b5050505050505050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f285fb8c8000000000000000000000000000000000000000000000000000000001480610b6857507fffffffff0000000000000000000000000000000000000000000000000000000082167f8f1d689900000000000000000000000000000000000000000000000000000000145b80610bb457507fffffffff0000000000000000000000000000000000000000000000000000000082167ff3417f1a00000000000000000000000000000000000000000000000000000000145b80610bdf57507fffffffff000000000000000000000000000000000000000000000000000000008216155b80610c0a57507fffffffff000000000000000000000000000000000000000000000000000000008216155b80610c195750610c1982612b41565b92915050565b6effffffffffffffffffffffffffffff81166000908152600460205260409020606090610c1990612bd8565b81610c5581612a9a565b6effffffffffffffffffffffffffffff83166000908152600560205260409020610c7f8184612be5565b15610d265773ffffffffffffffffffffffffffffffffffffffff83166effffffffffffffffffffffffffffff851660016040517f503012490a650739416858609e898957b874d17415a062945179c5735797884090600090a473ffffffffffffffffffffffffffffffffffffffff83166000908152600482016020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690555b50505050565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260036020526040902054606090610c199061010090046effffffffffffffffffffffffffffff16611863565b6060610c198261198f565b6104f082826122f4565b3360009081526003602052604081208054909161010082046effffffffffffffffffffffffffffff16918190610dc19060ff16611c41565b6effffffffffffffffffffffffffffff8516600090815260056020526040902091935091506001826002811115610dfa57610dfa61396b565b03610e8657853b15610e815773ffffffffffffffffffffffffffffffffffffffff8616600090815260048201602052604090205460ff16610e8157853f600090815260058201602052604090205460ff16610e81576040517faca58aa000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610f47565b6002826002811115610e9a57610e9a61396b565b03610f475773ffffffffffffffffffffffffffffffffffffffff861660009081526020819052604090205460ff16610f475773ffffffffffffffffffffffffffffffffffffffff8616600090815260048201602052604090205460ff16610f4757853f600090815260058201602052604090205460ff16610f47576040517fce32f2aa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8673ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff1603610f9d576003836003811115610f8e57610f8e61396b565b14610f9d575050505050505050565b6001836003811115610fb157610fb161396b565b03611089576effffffffffffffffffffffffffffff8416600090815260046020818152604080842073ffffffffffffffffffffffffffffffffffffffff8d1685529283019091529091205460ff1615611036576040517f409e6e1e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b883f600090815260058201602052604090205460ff1615611083576040517f409e6e1e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50610acb565b600283600381111561109d5761109d61396b565b036111335773ffffffffffffffffffffffffffffffffffffffff8816600090815260048201602052604090205460ff16156110dc575050505050505050565b873f600090815260058201602052604090205460ff1615611101575050505050505050565b6040517fef28f90100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60038360038111156111475761114761396b565b03610acb5773ffffffffffffffffffffffffffffffffffffffff8816600090815260048201602081905260409091205460ff161561118a57505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff881660009081526020829052604090205460ff16156111c357505050505050505050565b883f600090815260058301602081905260409091205460ff16156111ed5750505050505050505050565b883f60009081526020829052604090205460ff16156111015750505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff82166000908152600360205260408120546112589061010090046effffffffffffffffffffffffffffff16836123e3565b9392505050565b8261126981612a9a565b8160008190036112a5576040517fd13675da00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6effffffffffffffffffffffffffffff8516600090815260056020526040812090805b85811015610acb578686828181106112e2576112e2613b3d565b90506020020160208101906112f79190613740565b91506113038383612be5565b156113aa5773ffffffffffffffffffffffffffffffffffffffff82166effffffffffffffffffffffffffffff891660016040517f503012490a650739416858609e898957b874d17415a062945179c5735797884090600090a473ffffffffffffffffffffffffffffffffffffffff82166000908152600484016020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690555b6001016112c8565b6107d6816119bb565b826113c581612a9a565b816000819003611401576040517fd13675da00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6effffffffffffffffffffffffffffff8516600090815260056020526040812090805b85811015610acb5786868281811061143e5761143e613b3d565b60200291909101359250829050611481576040517f2bb30b6b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61148e6002840183612c07565b1561150b57816effffffffffffffffffffffffffffff891660016040517fc8615322788d404dfe307db9eef031bc148d1cec5e270a1fd6528a02b445d44590600090a46000828152600584016020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555b600101611424565b6effffffffffffffffffffffffffffff81166000908152600560205260409020606090610c1990600201612bd8565b600061125883836120b6565b8261155881612a9a565b816000819003611594576040517fd13675da00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6effffffffffffffffffffffffffffff8516600090815260056020526040812090805b85811015610acb578686828181106115d1576115d1613b3d565b9050602002013591506115f08284600201612c1390919063ffffffff16565b1561166a57816effffffffffffffffffffffffffffff891660016040517f061d78094976b1d9ae7bb858f141c915b46152756409caadb07482983c2ca30190600090a46000828152600584016020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690555b6001016115b7565b600081156116b0576effffffffffffffffffffffffffffff83166000908152600560208181526040808420868552909201905290205460ff16611258565b50600092915050565b826116c381612a9a565b8160008190036116ff576040517fd13675da00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6effffffffffffffffffffffffffffff8516600090815260046020526040812090805b85811015610acb5786868281811061173c5761173c613b3d565b90506020020160208101906117519190613740565b915061175d8383612be5565b156118045773ffffffffffffffffffffffffffffffffffffffff82166effffffffffffffffffffffffffffff891660006040517f503012490a650739416858609e898957b874d17415a062945179c5735797884090600090a473ffffffffffffffffffffffffffffffffffffffff82166000908152600484016020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690555b600101611722565b73ffffffffffffffffffffffffffffffffffffffff8116611859576040517f1f4ee59800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6104f08282612c1f565b6effffffffffffffffffffffffffffff81166000908152600460205260409020606090610c1990600201612bd8565b6104f0828261180c565b73ffffffffffffffffffffffffffffffffffffffff82811660009081526003602090815260408083205461010090046effffffffffffffffffffffffffffff168352600480835281842094861684529390930190529081205460ff16611258565b604080518082019091526000808252602082015273ffffffffffffffffffffffffffffffffffffffff82166000908152600360205260409081902081518083019092528054829060ff1660088111156119585761195861396b565b60088111156119695761196961396b565b8152905461010090046effffffffffffffffffffffffffffff1660209091015292915050565b6effffffffffffffffffffffffffffff81166000908152600560205260409020606090610c1990612bd8565b6107d6816000612c1f565b73ffffffffffffffffffffffffffffffffffffffff82811660009081526003602090815260408083205461010090046effffffffffffffffffffffffffffff168352600582528083209385168352600490930190529081205460ff16611258565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260036020526040902054606090610c199061010090046effffffffffffffffffffffffffffff16611513565b6effffffffffffffffffffffffffffff8216600090815260056020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845260040190915281205460ff16611258565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260036020526040902054606090610c199061010090046effffffffffffffffffffffffffffff16610c1f565b3360009081526020819052604090205460ff1615611b4e576040517fce8c510800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611b7a7f0000000000000000000000000000000000000000000000000000000000000000848484612cb6565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611bde576040517f7640718d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360008181526020819052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055517fe7f8d62df5af850daa5d677e9e5c8065b7b549ec99ae61ba0ffaa9f5bf3e2d039190a2505050565b60008080836008811115611c5757611c5761396b565b03611c685750600290506000915091565b6001836008811115611c7c57611c7c61396b565b03611c8c57506000905080915091565b6002836008811115611ca057611ca061396b565b03611cb15750600190506000915091565b6003836008811115611cc557611cc561396b565b03611cd65750600290506000915091565b6004836008811115611cea57611cea61396b565b03611cfb5750600390506000915091565b6005836008811115611d0f57611d0f61396b565b03611d205750600290506001915091565b6006836008811115611d3457611d3461396b565b03611d4457506002905080915091565b6007836008811115611d5857611d5861396b565b03611d695750600390506001915091565b50600390506002915091565b82611d7f81612a9a565b816000819003611dbb576040517fd13675da00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6effffffffffffffffffffffffffffff8516600090815260056020526040812090805b85811015610acb57868682818110611df857611df8613b3d565b9050602002016020810190611e0d9190613740565b915073ffffffffffffffffffffffffffffffffffffffff8216611e5c576040517f64019f1100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611e668383612b1f565b15611f105773ffffffffffffffffffffffffffffffffffffffff82166effffffffffffffffffffffffffffff891660016040517fda8f3bd170446760f0f965a9b52bf271cb9679b5e0a70059eff2d49425229d1790600090a473ffffffffffffffffffffffffffffffffffffffff82166000908152600484016020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555b600101611dde565b82611f2281612a9a565b816000819003611f5e576040517fd13675da00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6effffffffffffffffffffffffffffff8516600090815260046020526040812090805b85811015610acb57868682818110611f9b57611f9b613b3d565b60200291909101359250829050611fde576040517f2bb30b6b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611feb6002840183612c07565b1561206857816effffffffffffffffffffffffffffff891660006040517fc8615322788d404dfe307db9eef031bc148d1cec5e270a1fd6528a02b445d44590600090a46000828152600584016020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555b600101611f81565b73ffffffffffffffffffffffffffffffffffffffff82166000908152600360205260408120546112589061010090046effffffffffffffffffffffffffffff1683611672565b60018054600091829182906120db906effffffffffffffffffffffffffffff16613b9b565b91906101000a8154816effffffffffffffffffffffffffffff02191690836effffffffffffffffffffffffffffff160217905590506121173390565b6effffffffffffffffffffffffffffff82166000818152600260205260409081902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff949094169390931790925590517f5cc365f89543268cb9f25c255f7f610e9147e733c589bc2732279575f125be14906121ae9087908790613bc9565b60405180910390a260405133906effffffffffffffffffffffffffffff8316907f9b0894203394c3cbb23140db7a23b224d3e18e0366e9f65bd9c8402650e2736790600090a39392505050565b604080516060810182526000808252602082018190529181019190915273ffffffffffffffffffffffffffffffffffffffff821660009081526003602052604080822081518083019092528054829060ff16600881111561225e5761225e61396b565b600881111561226f5761226f61396b565b8152905461010090046effffffffffffffffffffffffffffff166020909101526040805160608101909152815191925090819060088111156122b3576122b361396b565b815260200182602001516effffffffffffffffffffffffffffff16815260200182602001516effffffffffffffffffffffffffffff16815250915050919050565b6122fd82612cde565b6001546effffffffffffffffffffffffffffff908116908216111561234e576040517ff716872600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff821660008181526003602052604080822080547fffffffffffffffffffffffffffffffff000000000000000000000000000000ff166101006effffffffffffffffffffffffffffff87169081029190911790915590519092917fa66ff5557b7dc1562bb5e83306e15b513a25aa7537369bce38fc29c20847a79191a35050565b600081156116b0576effffffffffffffffffffffffffffff8316600090815260046020908152604080832085845260050190915290205460ff16611258565b61242b82612cde565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260036020526040902080548291907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600183600881111561248b5761248b61396b565b02179055508173ffffffffffffffffffffffffffffffffffffffff167fb39d8f1e6f05413a407e46fc950eb92e9f5b3d65a47c3f0bdc7a2741a6ec0f7d826040516124d69190613c16565b60405180910390a25050565b6001805460009182918290612507906effffffffffffffffffffffffffffff16613b9b565b91906101000a8154816effffffffffffffffffffffffffffff02191690836effffffffffffffffffffffffffffff16021790559050600181036effffffffffffffffffffffffffffff16836effffffffffffffffffffffffffffff16111561259b576040517ff716872600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6effffffffffffffffffffffffffffff81166000818152600260205260409081902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001633179055517f5cc365f89543268cb9f25c255f7f610e9147e733c589bc2732279575f125be14906126159088908890613bc9565b60405180910390a260405133906effffffffffffffffffffffffffffff8316907f9b0894203394c3cbb23140db7a23b224d3e18e0366e9f65bd9c8402650e2736790600090a36effffffffffffffffffffffffffffff8084166000908152600460208181526040808420600580845282862096881686529383528185209390925283209093926126a790868685612eb7565b6126b46000868685612fb8565b6126c16001868584612eb7565b6126ce6001868584612fb8565b5092979650505050505050565b826126e581612a9a565b816000819003612721576040517fd13675da00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6effffffffffffffffffffffffffffff8516600090815260046020526040812090805b85811015610acb5786868281811061275e5761275e613b3d565b90506020020135915061277d8284600201612c1390919063ffffffff16565b156127f757816effffffffffffffffffffffffffffff891660006040517f061d78094976b1d9ae7bb858f141c915b46152756409caadb07482983c2ca30190600090a46000828152600584016020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690555b600101612744565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260036020526040902054606090610c199061010090046effffffffffffffffffffffffffffff1661198f565b3360009081526020819052604090205460ff1615612891576040517fce8c510800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6128f17f000000000000000000000000000000000000000000000000000000000000000083838080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061308692505050565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614612955576040517f7640718d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360008181526020819052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055517fe7f8d62df5af850daa5d677e9e5c8065b7b549ec99ae61ba0ffaa9f5bf3e2d039190a25050565b816129c181612a9a565b6effffffffffffffffffffffffffffff831660009081526005602052604090206129eb8184612b1f565b15610d265773ffffffffffffffffffffffffffffffffffffffff83166effffffffffffffffffffffffffffff851660016040517fda8f3bd170446760f0f965a9b52bf271cb9679b5e0a70059eff2d49425229d1790600090a473ffffffffffffffffffffffffffffffffffffffff83166000908152600482016020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905550505050565b6effffffffffffffffffffffffffffff811660009081526002602052604090205473ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146107d6576040517f4e680cb000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006112588373ffffffffffffffffffffffffffffffffffffffff84166130aa565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f89a9c855000000000000000000000000000000000000000000000000000000001480610c1957507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610c19565b60606000611258836130f9565b60006112588373ffffffffffffffffffffffffffffffffffffffff8416613155565b600061125883836130aa565b60006112588383613155565b612c2882612a9a565b6effffffffffffffffffffffffffffff821660008181526002602052604080822080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff861690811790915590519092917f9b0894203394c3cbb23140db7a23b224d3e18e0366e9f65bd9c8402650e2736791a35050565b6000806000612cc787878787613248565b91509150612cd481613337565b5095945050505050565b6000813b15612e8057503373ffffffffffffffffffffffffffffffffffffffff82161480612e80578173ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015612d8b575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201909252612d8891810190613c24565b60015b15612dab5773ffffffffffffffffffffffffffffffffffffffff16331490505b80612e805773ffffffffffffffffffffffffffffffffffffffff82166391d148546000336040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b168152600481019290925273ffffffffffffffffffffffffffffffffffffffff166024820152604401602060405180830381865afa925050508015612e78575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201909252612e7591810190613c41565b60015b15612e805790505b806104f0576040517f7f954ba100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8181600481016000612ec8846134ef565b90506000805b82811015612fac57612ee086826134f9565b9150612eec8583612b1f565b15612fa4578173ffffffffffffffffffffffffffffffffffffffff16896effffffffffffffffffffffffffffff168b6001811115612f2c57612f2c61396b565b6040517fda8f3bd170446760f0f965a9b52bf271cb9679b5e0a70059eff2d49425229d1790600090a473ffffffffffffffffffffffffffffffffffffffff8216600090815260208590526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555b600101612ece565b50505050505050505050565b6002808301908201600583016000612fcf846134ef565b90506000805b82811015612fac57612fe786826134f9565b9150612ff38583612c07565b1561307e5781896effffffffffffffffffffffffffffff168b600181111561301d5761301d61396b565b6040517fc8615322788d404dfe307db9eef031bc148d1cec5e270a1fd6528a02b445d44590600090a4600082815260208590526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555b600101612fd5565b60008060006130958585613505565b915091506130a281613337565b509392505050565b60008181526001830160205260408120546130f157508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610c19565b506000610c19565b60608160000180548060200260200160405190810160405280929190818152602001828054801561314957602002820191906000526020600020905b815481526020019060010190808311613135575b50505050509050919050565b6000818152600183016020526040812054801561323e576000613179600183613c63565b855490915060009061318d90600190613c63565b90508181146131f25760008660000182815481106131ad576131ad613b3d565b90600052602060002001549050808760000184815481106131d0576131d0613b3d565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061320357613203613c76565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610c19565b6000915050610c19565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083111561327f575060009050600361332e565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa1580156132d3573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff81166133275760006001925092505061332e565b9150600090505b94509492505050565b600081600481111561334b5761334b61396b565b036133535750565b60018160048111156133675761336761396b565b036133d3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f45434453413a20696e76616c6964207369676e6174757265000000000000000060448201526064015b60405180910390fd5b60028160048111156133e7576133e761396b565b0361344e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e6774680060448201526064016133ca565b60038160048111156134625761346261396b565b036107d6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f756500000000000000000000000000000000000000000000000000000000000060648201526084016133ca565b6000610c19825490565b6000611258838361354a565b600080825160410361353b5760208301516040840151606085015160001a61352f87828585613248565b94509450505050613543565b506000905060025b9250929050565b600082600001828154811061356157613561613b3d565b9060005260206000200154905092915050565b80356effffffffffffffffffffffffffffff8116811461359357600080fd5b919050565b60008083601f8401126135aa57600080fd5b50813567ffffffffffffffff8111156135c257600080fd5b6020830191508360208260051b850101111561354357600080fd5b6000806000604084860312156135f257600080fd5b6135fb84613574565b9250602084013567ffffffffffffffff81111561361757600080fd5b61362386828701613598565b9497909650939450505050565b60006020828403121561364257600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461125857600080fd5b73ffffffffffffffffffffffffffffffffffffffff811681146107d657600080fd5b600080604083850312156136a757600080fd5b6136b083613574565b915060208301356136c081613672565b809150509250929050565b6000602082840312156136dd57600080fd5b61125882613574565b6020808252825182820181905260009190848201906040850190845b8181101561373457835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101613702565b50909695505050505050565b60006020828403121561375257600080fd5b813561125881613672565b6020808252825182820181905260009190848201906040850190845b8181101561373457835183529284019291840191600101613779565b600080604083850312156137a857600080fd5b82356137b381613672565b91506137c160208401613574565b90509250929050565b6000806000606084860312156137df57600080fd5b83356137ea81613672565b925060208401356137fa81613672565b9150604084013561380a81613672565b809150509250925092565b6000806040838503121561382857600080fd5b823561383381613672565b946020939093013593505050565b600060208083528351808285015260005b8181101561386e57858101830151858201604001528201613852565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b60008083601f8401126138bf57600080fd5b50813567ffffffffffffffff8111156138d757600080fd5b60208301915083602082850101111561354357600080fd5b6000806020838503121561390257600080fd5b823567ffffffffffffffff81111561391957600080fd5b613925858286016138ad565b90969095509350505050565b6000806040838503121561394457600080fd5b61383383613574565b6000806040838503121561396057600080fd5b82356136b081613672565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600981106139aa576139aa61396b565b9052565b60006040820190506139c182845161399a565b6020928301516effffffffffffffffffffffffffffff16919092015290565b6000806000606084860312156139f557600080fd5b833560ff81168114613a0657600080fd5b95602085013595506040909401359392505050565b80356009811061359357600080fd5b600060208284031215613a3c57600080fd5b61125882613a1b565b6040810160048410613a5957613a5961396b565b83825260038310613a6c57613a6c61396b565b8260208301529392505050565b6000606082019050613a8c82845161399a565b60208301516effffffffffffffffffffffffffffff8082166020850152806040860151166040850152505092915050565b60008060408385031215613ad057600080fd5b8235613adb81613672565b91506137c160208401613a1b565b600080600060408486031215613afe57600080fd5b833567ffffffffffffffff811115613b1557600080fd5b613b21868287016138ad565b9094509250613b34905060208501613574565b90509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006effffffffffffffffffffffffffffff808316818103613bbf57613bbf613b6c565b6001019392505050565b60208152816020820152818360408301376000818301604090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160101919050565b60208101610c19828461399a565b600060208284031215613c3657600080fd5b815161125881613672565b600060208284031215613c5357600080fd5b8151801515811461125857600080fd5b81810381811115610c1957610c19613b6c565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea2646970667358221220b2e22ffac36fef1d4cc736309089b3d0e9c332fda01fd4faf1593371ad9d647a64736f6c6343000813003300000000000000000000000067985b1f8b613b57077bbdb24a5defcdda458317

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106103835760003560e01c80637f39e7e4116101de578063ae602f441161010f578063d72dde5e116100ad578063e30cd5e11161007c578063e30cd5e1146104e2578063e991dc30146108ef578063f80af98414610902578063fec1d6431461091557600080fd5b8063d72dde5e14610748578063da0194c0146108b6578063de02cbb1146108c9578063def0125b146108dc57600080fd5b8063b8dcc68f116100e9578063b8dcc68f1461085d578063b955455214610870578063bf7bfd7e14610890578063d415f62f146108a357600080fd5b8063ae602f44146107d9578063b6567f2214610834578063b67d8f991461084a57600080fd5b80639445f5301161017c5780639e814cae116101565780639e814cae14610781578063a1cc5cc1146107a2578063a5d56b46146107b5578063a9f138eb146107c857600080fd5b80639445f53014610748578063982d03c01461075b57806399f9a6781461076e57600080fd5b80638b6ee865116101b85780638b6ee865146107015780638d744314146107145780638e28800f146107225780639340a7cc1461073557600080fd5b80637f39e7e41461069557806389631626146106b557806389a9c855146106c857600080fd5b806333f0901b116102b8578063515f7b28116102565780636bfab91d116102305780636bfab91d146106495780637161ac8d1461065c578063731fb9d81461066f5780637bac97de1461068257600080fd5b8063515f7b28146106105780635e17263d14610623578063697108281461063657600080fd5b80633fe5df99116102925780633fe5df99146104cf578063409dc573146105d75780634c9d0b45146105ea578063501b7d2e146105fd57600080fd5b806333f0901b1461057b57806334778f6a146105c4578063372fb54d146104e257600080fd5b806317e94a6c1161032557806323c99262116102ff57806323c9926214610507578063285fb8c8146105425780632c7fe70a146105555780632eb0b98a1461056857600080fd5b806317e94a6c146104cf57806318fbf6fe146104e25780632304aa02146104f457600080fd5b806310b5c6a01161036157806310b5c6a0146104215780631390a2c21461044157806316a17ce01461045457806316f18d74146104af57600080fd5b8063015499301461038857806301ffc9a71461039d578063057497cb146103c5575b600080fd5b61039b6103963660046135dd565b610928565b005b6103b06103ab366004613630565b610ad5565b60405190151581526020015b60405180910390f35b6103b06103d3366004613694565b6effffffffffffffffffffffffffffff8216600090815260056020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845260040190915290205460ff1692915050565b61043461042f3660046136cb565b610c1f565b6040516103bc91906136e6565b61039b61044f366004613694565b610c4b565b6103b0610462366004613694565b6effffffffffffffffffffffffffffff8216600090815260046020818152604080842073ffffffffffffffffffffffffffffffffffffffff86168552909201905290205460ff1692915050565b6104c26104bd366004613740565b610d2c565b6040516103bc919061375d565b6104346104dd3660046136cb565b610d74565b61039b6104f0366004613694565b5050565b61039b610502366004613795565b610d7f565b600154610522906effffffffffffffffffffffffffffff1681565b6040516effffffffffffffffffffffffffffff90911681526020016103bc565b61039b6105503660046137ca565b610d89565b6103b0610563366004613815565b611212565b61039b6105763660046135dd565b61125f565b6105b76040518060400160405280600381526020017f454f41000000000000000000000000000000000000000000000000000000000081525081565b6040516103bc9190613841565b61039b6105d23660046136cb565b6113b2565b61039b6105e53660046135dd565b6113bb565b6104c26105f83660046136cb565b611513565b61052261060b3660046138ef565b611542565b61039b61061e3660046135dd565b61154e565b6103b0610631366004613931565b611672565b61039b6106443660046135dd565b6116b9565b61039b610657366004613694565b61180c565b6104c261066a3660046136cb565b611863565b61039b61067d366004613694565b611892565b6103b061069036600461394d565b61189c565b6106a86106a3366004613740565b6118fd565b6040516103bc91906139ae565b6104346106c33660046136cb565b61198f565b6103b06106d6366004613740565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205460ff1690565b61039b61070f3660046136cb565b6119bb565b61039b6104f0366004613795565b6103b061073036600461394d565b6119c6565b6104c2610743366004613740565b611a27565b6103b0610756366004613694565b611a6f565b610434610769366004613740565b611abc565b61039b61077c3660046139e0565b611b04565b61079461078f366004613a2a565b611c41565b6040516103bc929190613a45565b61039b6107b03660046135dd565b611d75565b61039b6107c33660046135dd565b611f18565b61039b6107d63660046136cb565b50565b61080f6107e73660046136cb565b60026020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016103bc565b6105226108423660046138ef565b600092915050565b6103b0610858366004613815565b612070565b61052261086b3660046138ef565b6120b6565b61088361087e366004613740565b6121fb565b6040516103bc9190613a79565b61039b61089e366004613795565b6122f4565b6103b06108b1366004613931565b6123e3565b61039b6108c4366004613abd565b612422565b6105226108d7366004613ae9565b6124e2565b61039b6108ea3660046135dd565b6126db565b6104346108fd366004613740565b6127ff565b61039b6109103660046138ef565b612847565b61039b610923366004613694565b6129b7565b8261093281612a9a565b81600081900361096e576040517fd13675da00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6effffffffffffffffffffffffffffff8516600090815260046020526040812090805b85811015610acb578686828181106109ab576109ab613b3d565b90506020020160208101906109c09190613740565b915073ffffffffffffffffffffffffffffffffffffffff8216610a0f576040517f64019f1100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610a198383612b1f565b15610ac35773ffffffffffffffffffffffffffffffffffffffff82166effffffffffffffffffffffffffffff891660006040517fda8f3bd170446760f0f965a9b52bf271cb9679b5e0a70059eff2d49425229d1790600090a473ffffffffffffffffffffffffffffffffffffffff82166000908152600484016020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555b600101610991565b5050505050505050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f285fb8c8000000000000000000000000000000000000000000000000000000001480610b6857507fffffffff0000000000000000000000000000000000000000000000000000000082167f8f1d689900000000000000000000000000000000000000000000000000000000145b80610bb457507fffffffff0000000000000000000000000000000000000000000000000000000082167ff3417f1a00000000000000000000000000000000000000000000000000000000145b80610bdf57507fffffffff000000000000000000000000000000000000000000000000000000008216155b80610c0a57507fffffffff000000000000000000000000000000000000000000000000000000008216155b80610c195750610c1982612b41565b92915050565b6effffffffffffffffffffffffffffff81166000908152600460205260409020606090610c1990612bd8565b81610c5581612a9a565b6effffffffffffffffffffffffffffff83166000908152600560205260409020610c7f8184612be5565b15610d265773ffffffffffffffffffffffffffffffffffffffff83166effffffffffffffffffffffffffffff851660016040517f503012490a650739416858609e898957b874d17415a062945179c5735797884090600090a473ffffffffffffffffffffffffffffffffffffffff83166000908152600482016020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690555b50505050565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260036020526040902054606090610c199061010090046effffffffffffffffffffffffffffff16611863565b6060610c198261198f565b6104f082826122f4565b3360009081526003602052604081208054909161010082046effffffffffffffffffffffffffffff16918190610dc19060ff16611c41565b6effffffffffffffffffffffffffffff8516600090815260056020526040902091935091506001826002811115610dfa57610dfa61396b565b03610e8657853b15610e815773ffffffffffffffffffffffffffffffffffffffff8616600090815260048201602052604090205460ff16610e8157853f600090815260058201602052604090205460ff16610e81576040517faca58aa000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610f47565b6002826002811115610e9a57610e9a61396b565b03610f475773ffffffffffffffffffffffffffffffffffffffff861660009081526020819052604090205460ff16610f475773ffffffffffffffffffffffffffffffffffffffff8616600090815260048201602052604090205460ff16610f4757853f600090815260058201602052604090205460ff16610f47576040517fce32f2aa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8673ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff1603610f9d576003836003811115610f8e57610f8e61396b565b14610f9d575050505050505050565b6001836003811115610fb157610fb161396b565b03611089576effffffffffffffffffffffffffffff8416600090815260046020818152604080842073ffffffffffffffffffffffffffffffffffffffff8d1685529283019091529091205460ff1615611036576040517f409e6e1e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b883f600090815260058201602052604090205460ff1615611083576040517f409e6e1e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50610acb565b600283600381111561109d5761109d61396b565b036111335773ffffffffffffffffffffffffffffffffffffffff8816600090815260048201602052604090205460ff16156110dc575050505050505050565b873f600090815260058201602052604090205460ff1615611101575050505050505050565b6040517fef28f90100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60038360038111156111475761114761396b565b03610acb5773ffffffffffffffffffffffffffffffffffffffff8816600090815260048201602081905260409091205460ff161561118a57505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff881660009081526020829052604090205460ff16156111c357505050505050505050565b883f600090815260058301602081905260409091205460ff16156111ed5750505050505050505050565b883f60009081526020829052604090205460ff16156111015750505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff82166000908152600360205260408120546112589061010090046effffffffffffffffffffffffffffff16836123e3565b9392505050565b8261126981612a9a565b8160008190036112a5576040517fd13675da00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6effffffffffffffffffffffffffffff8516600090815260056020526040812090805b85811015610acb578686828181106112e2576112e2613b3d565b90506020020160208101906112f79190613740565b91506113038383612be5565b156113aa5773ffffffffffffffffffffffffffffffffffffffff82166effffffffffffffffffffffffffffff891660016040517f503012490a650739416858609e898957b874d17415a062945179c5735797884090600090a473ffffffffffffffffffffffffffffffffffffffff82166000908152600484016020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690555b6001016112c8565b6107d6816119bb565b826113c581612a9a565b816000819003611401576040517fd13675da00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6effffffffffffffffffffffffffffff8516600090815260056020526040812090805b85811015610acb5786868281811061143e5761143e613b3d565b60200291909101359250829050611481576040517f2bb30b6b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61148e6002840183612c07565b1561150b57816effffffffffffffffffffffffffffff891660016040517fc8615322788d404dfe307db9eef031bc148d1cec5e270a1fd6528a02b445d44590600090a46000828152600584016020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555b600101611424565b6effffffffffffffffffffffffffffff81166000908152600560205260409020606090610c1990600201612bd8565b600061125883836120b6565b8261155881612a9a565b816000819003611594576040517fd13675da00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6effffffffffffffffffffffffffffff8516600090815260056020526040812090805b85811015610acb578686828181106115d1576115d1613b3d565b9050602002013591506115f08284600201612c1390919063ffffffff16565b1561166a57816effffffffffffffffffffffffffffff891660016040517f061d78094976b1d9ae7bb858f141c915b46152756409caadb07482983c2ca30190600090a46000828152600584016020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690555b6001016115b7565b600081156116b0576effffffffffffffffffffffffffffff83166000908152600560208181526040808420868552909201905290205460ff16611258565b50600092915050565b826116c381612a9a565b8160008190036116ff576040517fd13675da00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6effffffffffffffffffffffffffffff8516600090815260046020526040812090805b85811015610acb5786868281811061173c5761173c613b3d565b90506020020160208101906117519190613740565b915061175d8383612be5565b156118045773ffffffffffffffffffffffffffffffffffffffff82166effffffffffffffffffffffffffffff891660006040517f503012490a650739416858609e898957b874d17415a062945179c5735797884090600090a473ffffffffffffffffffffffffffffffffffffffff82166000908152600484016020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690555b600101611722565b73ffffffffffffffffffffffffffffffffffffffff8116611859576040517f1f4ee59800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6104f08282612c1f565b6effffffffffffffffffffffffffffff81166000908152600460205260409020606090610c1990600201612bd8565b6104f0828261180c565b73ffffffffffffffffffffffffffffffffffffffff82811660009081526003602090815260408083205461010090046effffffffffffffffffffffffffffff168352600480835281842094861684529390930190529081205460ff16611258565b604080518082019091526000808252602082015273ffffffffffffffffffffffffffffffffffffffff82166000908152600360205260409081902081518083019092528054829060ff1660088111156119585761195861396b565b60088111156119695761196961396b565b8152905461010090046effffffffffffffffffffffffffffff1660209091015292915050565b6effffffffffffffffffffffffffffff81166000908152600560205260409020606090610c1990612bd8565b6107d6816000612c1f565b73ffffffffffffffffffffffffffffffffffffffff82811660009081526003602090815260408083205461010090046effffffffffffffffffffffffffffff168352600582528083209385168352600490930190529081205460ff16611258565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260036020526040902054606090610c199061010090046effffffffffffffffffffffffffffff16611513565b6effffffffffffffffffffffffffffff8216600090815260056020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845260040190915281205460ff16611258565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260036020526040902054606090610c199061010090046effffffffffffffffffffffffffffff16610c1f565b3360009081526020819052604090205460ff1615611b4e576040517fce8c510800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611b7a7fd3f5cd7a1487f8f0a2a12cf6e95545173640e44a3a845c5f2c9d00175aab4294848484612cb6565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611bde576040517f7640718d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360008181526020819052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055517fe7f8d62df5af850daa5d677e9e5c8065b7b549ec99ae61ba0ffaa9f5bf3e2d039190a2505050565b60008080836008811115611c5757611c5761396b565b03611c685750600290506000915091565b6001836008811115611c7c57611c7c61396b565b03611c8c57506000905080915091565b6002836008811115611ca057611ca061396b565b03611cb15750600190506000915091565b6003836008811115611cc557611cc561396b565b03611cd65750600290506000915091565b6004836008811115611cea57611cea61396b565b03611cfb5750600390506000915091565b6005836008811115611d0f57611d0f61396b565b03611d205750600290506001915091565b6006836008811115611d3457611d3461396b565b03611d4457506002905080915091565b6007836008811115611d5857611d5861396b565b03611d695750600390506001915091565b50600390506002915091565b82611d7f81612a9a565b816000819003611dbb576040517fd13675da00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6effffffffffffffffffffffffffffff8516600090815260056020526040812090805b85811015610acb57868682818110611df857611df8613b3d565b9050602002016020810190611e0d9190613740565b915073ffffffffffffffffffffffffffffffffffffffff8216611e5c576040517f64019f1100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611e668383612b1f565b15611f105773ffffffffffffffffffffffffffffffffffffffff82166effffffffffffffffffffffffffffff891660016040517fda8f3bd170446760f0f965a9b52bf271cb9679b5e0a70059eff2d49425229d1790600090a473ffffffffffffffffffffffffffffffffffffffff82166000908152600484016020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555b600101611dde565b82611f2281612a9a565b816000819003611f5e576040517fd13675da00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6effffffffffffffffffffffffffffff8516600090815260046020526040812090805b85811015610acb57868682818110611f9b57611f9b613b3d565b60200291909101359250829050611fde576040517f2bb30b6b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611feb6002840183612c07565b1561206857816effffffffffffffffffffffffffffff891660006040517fc8615322788d404dfe307db9eef031bc148d1cec5e270a1fd6528a02b445d44590600090a46000828152600584016020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555b600101611f81565b73ffffffffffffffffffffffffffffffffffffffff82166000908152600360205260408120546112589061010090046effffffffffffffffffffffffffffff1683611672565b60018054600091829182906120db906effffffffffffffffffffffffffffff16613b9b565b91906101000a8154816effffffffffffffffffffffffffffff02191690836effffffffffffffffffffffffffffff160217905590506121173390565b6effffffffffffffffffffffffffffff82166000818152600260205260409081902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff949094169390931790925590517f5cc365f89543268cb9f25c255f7f610e9147e733c589bc2732279575f125be14906121ae9087908790613bc9565b60405180910390a260405133906effffffffffffffffffffffffffffff8316907f9b0894203394c3cbb23140db7a23b224d3e18e0366e9f65bd9c8402650e2736790600090a39392505050565b604080516060810182526000808252602082018190529181019190915273ffffffffffffffffffffffffffffffffffffffff821660009081526003602052604080822081518083019092528054829060ff16600881111561225e5761225e61396b565b600881111561226f5761226f61396b565b8152905461010090046effffffffffffffffffffffffffffff166020909101526040805160608101909152815191925090819060088111156122b3576122b361396b565b815260200182602001516effffffffffffffffffffffffffffff16815260200182602001516effffffffffffffffffffffffffffff16815250915050919050565b6122fd82612cde565b6001546effffffffffffffffffffffffffffff908116908216111561234e576040517ff716872600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff821660008181526003602052604080822080547fffffffffffffffffffffffffffffffff000000000000000000000000000000ff166101006effffffffffffffffffffffffffffff87169081029190911790915590519092917fa66ff5557b7dc1562bb5e83306e15b513a25aa7537369bce38fc29c20847a79191a35050565b600081156116b0576effffffffffffffffffffffffffffff8316600090815260046020908152604080832085845260050190915290205460ff16611258565b61242b82612cde565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260036020526040902080548291907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600183600881111561248b5761248b61396b565b02179055508173ffffffffffffffffffffffffffffffffffffffff167fb39d8f1e6f05413a407e46fc950eb92e9f5b3d65a47c3f0bdc7a2741a6ec0f7d826040516124d69190613c16565b60405180910390a25050565b6001805460009182918290612507906effffffffffffffffffffffffffffff16613b9b565b91906101000a8154816effffffffffffffffffffffffffffff02191690836effffffffffffffffffffffffffffff16021790559050600181036effffffffffffffffffffffffffffff16836effffffffffffffffffffffffffffff16111561259b576040517ff716872600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6effffffffffffffffffffffffffffff81166000818152600260205260409081902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001633179055517f5cc365f89543268cb9f25c255f7f610e9147e733c589bc2732279575f125be14906126159088908890613bc9565b60405180910390a260405133906effffffffffffffffffffffffffffff8316907f9b0894203394c3cbb23140db7a23b224d3e18e0366e9f65bd9c8402650e2736790600090a36effffffffffffffffffffffffffffff8084166000908152600460208181526040808420600580845282862096881686529383528185209390925283209093926126a790868685612eb7565b6126b46000868685612fb8565b6126c16001868584612eb7565b6126ce6001868584612fb8565b5092979650505050505050565b826126e581612a9a565b816000819003612721576040517fd13675da00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6effffffffffffffffffffffffffffff8516600090815260046020526040812090805b85811015610acb5786868281811061275e5761275e613b3d565b90506020020135915061277d8284600201612c1390919063ffffffff16565b156127f757816effffffffffffffffffffffffffffff891660006040517f061d78094976b1d9ae7bb858f141c915b46152756409caadb07482983c2ca30190600090a46000828152600584016020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690555b600101612744565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260036020526040902054606090610c199061010090046effffffffffffffffffffffffffffff1661198f565b3360009081526020819052604090205460ff1615612891576040517fce8c510800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6128f17fd3f5cd7a1487f8f0a2a12cf6e95545173640e44a3a845c5f2c9d00175aab429483838080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061308692505050565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614612955576040517f7640718d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360008181526020819052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055517fe7f8d62df5af850daa5d677e9e5c8065b7b549ec99ae61ba0ffaa9f5bf3e2d039190a25050565b816129c181612a9a565b6effffffffffffffffffffffffffffff831660009081526005602052604090206129eb8184612b1f565b15610d265773ffffffffffffffffffffffffffffffffffffffff83166effffffffffffffffffffffffffffff851660016040517fda8f3bd170446760f0f965a9b52bf271cb9679b5e0a70059eff2d49425229d1790600090a473ffffffffffffffffffffffffffffffffffffffff83166000908152600482016020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905550505050565b6effffffffffffffffffffffffffffff811660009081526002602052604090205473ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146107d6576040517f4e680cb000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006112588373ffffffffffffffffffffffffffffffffffffffff84166130aa565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f89a9c855000000000000000000000000000000000000000000000000000000001480610c1957507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610c19565b60606000611258836130f9565b60006112588373ffffffffffffffffffffffffffffffffffffffff8416613155565b600061125883836130aa565b60006112588383613155565b612c2882612a9a565b6effffffffffffffffffffffffffffff821660008181526002602052604080822080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff861690811790915590519092917f9b0894203394c3cbb23140db7a23b224d3e18e0366e9f65bd9c8402650e2736791a35050565b6000806000612cc787878787613248565b91509150612cd481613337565b5095945050505050565b6000813b15612e8057503373ffffffffffffffffffffffffffffffffffffffff82161480612e80578173ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015612d8b575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201909252612d8891810190613c24565b60015b15612dab5773ffffffffffffffffffffffffffffffffffffffff16331490505b80612e805773ffffffffffffffffffffffffffffffffffffffff82166391d148546000336040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b168152600481019290925273ffffffffffffffffffffffffffffffffffffffff166024820152604401602060405180830381865afa925050508015612e78575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201909252612e7591810190613c41565b60015b15612e805790505b806104f0576040517f7f954ba100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8181600481016000612ec8846134ef565b90506000805b82811015612fac57612ee086826134f9565b9150612eec8583612b1f565b15612fa4578173ffffffffffffffffffffffffffffffffffffffff16896effffffffffffffffffffffffffffff168b6001811115612f2c57612f2c61396b565b6040517fda8f3bd170446760f0f965a9b52bf271cb9679b5e0a70059eff2d49425229d1790600090a473ffffffffffffffffffffffffffffffffffffffff8216600090815260208590526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555b600101612ece565b50505050505050505050565b6002808301908201600583016000612fcf846134ef565b90506000805b82811015612fac57612fe786826134f9565b9150612ff38583612c07565b1561307e5781896effffffffffffffffffffffffffffff168b600181111561301d5761301d61396b565b6040517fc8615322788d404dfe307db9eef031bc148d1cec5e270a1fd6528a02b445d44590600090a4600082815260208590526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555b600101612fd5565b60008060006130958585613505565b915091506130a281613337565b509392505050565b60008181526001830160205260408120546130f157508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610c19565b506000610c19565b60608160000180548060200260200160405190810160405280929190818152602001828054801561314957602002820191906000526020600020905b815481526020019060010190808311613135575b50505050509050919050565b6000818152600183016020526040812054801561323e576000613179600183613c63565b855490915060009061318d90600190613c63565b90508181146131f25760008660000182815481106131ad576131ad613b3d565b90600052602060002001549050808760000184815481106131d0576131d0613b3d565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061320357613203613c76565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610c19565b6000915050610c19565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083111561327f575060009050600361332e565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa1580156132d3573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff81166133275760006001925092505061332e565b9150600090505b94509492505050565b600081600481111561334b5761334b61396b565b036133535750565b60018160048111156133675761336761396b565b036133d3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f45434453413a20696e76616c6964207369676e6174757265000000000000000060448201526064015b60405180910390fd5b60028160048111156133e7576133e761396b565b0361344e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e6774680060448201526064016133ca565b60038160048111156134625761346261396b565b036107d6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f756500000000000000000000000000000000000000000000000000000000000060648201526084016133ca565b6000610c19825490565b6000611258838361354a565b600080825160410361353b5760208301516040840151606085015160001a61352f87828585613248565b94509450505050613543565b506000905060025b9250929050565b600082600001828154811061356157613561613b3d565b9060005260206000200154905092915050565b80356effffffffffffffffffffffffffffff8116811461359357600080fd5b919050565b60008083601f8401126135aa57600080fd5b50813567ffffffffffffffff8111156135c257600080fd5b6020830191508360208260051b850101111561354357600080fd5b6000806000604084860312156135f257600080fd5b6135fb84613574565b9250602084013567ffffffffffffffff81111561361757600080fd5b61362386828701613598565b9497909650939450505050565b60006020828403121561364257600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461125857600080fd5b73ffffffffffffffffffffffffffffffffffffffff811681146107d657600080fd5b600080604083850312156136a757600080fd5b6136b083613574565b915060208301356136c081613672565b809150509250929050565b6000602082840312156136dd57600080fd5b61125882613574565b6020808252825182820181905260009190848201906040850190845b8181101561373457835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101613702565b50909695505050505050565b60006020828403121561375257600080fd5b813561125881613672565b6020808252825182820181905260009190848201906040850190845b8181101561373457835183529284019291840191600101613779565b600080604083850312156137a857600080fd5b82356137b381613672565b91506137c160208401613574565b90509250929050565b6000806000606084860312156137df57600080fd5b83356137ea81613672565b925060208401356137fa81613672565b9150604084013561380a81613672565b809150509250925092565b6000806040838503121561382857600080fd5b823561383381613672565b946020939093013593505050565b600060208083528351808285015260005b8181101561386e57858101830151858201604001528201613852565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b60008083601f8401126138bf57600080fd5b50813567ffffffffffffffff8111156138d757600080fd5b60208301915083602082850101111561354357600080fd5b6000806020838503121561390257600080fd5b823567ffffffffffffffff81111561391957600080fd5b613925858286016138ad565b90969095509350505050565b6000806040838503121561394457600080fd5b61383383613574565b6000806040838503121561396057600080fd5b82356136b081613672565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600981106139aa576139aa61396b565b9052565b60006040820190506139c182845161399a565b6020928301516effffffffffffffffffffffffffffff16919092015290565b6000806000606084860312156139f557600080fd5b833560ff81168114613a0657600080fd5b95602085013595506040909401359392505050565b80356009811061359357600080fd5b600060208284031215613a3c57600080fd5b61125882613a1b565b6040810160048410613a5957613a5961396b565b83825260038310613a6c57613a6c61396b565b8260208301529392505050565b6000606082019050613a8c82845161399a565b60208301516effffffffffffffffffffffffffffff8082166020850152806040860151166040850152505092915050565b60008060408385031215613ad057600080fd5b8235613adb81613672565b91506137c160208401613a1b565b600080600060408486031215613afe57600080fd5b833567ffffffffffffffff811115613b1557600080fd5b613b21868287016138ad565b9094509250613b34905060208501613574565b90509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006effffffffffffffffffffffffffffff808316818103613bbf57613bbf613b6c565b6001019392505050565b60208152816020820152818360408301376000818301604090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160101919050565b60208101610c19828461399a565b600060208284031215613c3657600080fd5b815161125881613672565b600060208284031215613c5357600080fd5b8151801515811461125857600080fd5b81810381811115610c1957610c19613b6c565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea2646970667358221220b2e22ffac36fef1d4cc736309089b3d0e9c332fda01fd4faf1593371ad9d647a64736f6c63430008130033

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

00000000000000000000000067985b1f8b613b57077bbdb24a5defcdda458317

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

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 00000000000000000000000067985b1f8b613b57077bbdb24a5defcdda458317


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
Loading...
Loading
[ Download: CSV Export  ]
[ 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.