ETH Price: $3,418.26 (-1.44%)
Gas: 5 Gwei

Contract

0xA000027A9B2802E1ddf7000061001e5c005A0000
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Value
Add Accounts To ...201702472024-06-25 17:39:597 days ago1719337199IN
0xA000027A...c005A0000
0 ETH0.001903537.46473677
Create List195719262024-04-03 1:19:2390 days ago1712107163IN
0xA000027A...c005A0000
0 ETH0.0015387528.8236654
Create List195719242024-04-03 1:18:5990 days ago1712107139IN
0xA000027A...c005A0000
0 ETH0.0015317128.69192144
Create List195719222024-04-03 1:18:3590 days ago1712107115IN
0xA000027A...c005A0000
0 ETH0.0020026628.41261721

Latest 3 internal transactions

Advanced mode:
Parent Transaction Hash Block From To Value
195653442024-04-02 3:09:1191 days ago1712027351
0xA000027A...c005A0000
 Contract Creation0 ETH
195653442024-04-02 3:09:1191 days ago1712027351
0xA000027A...c005A0000
 Contract Creation0 ETH
195653442024-04-02 3:09:1191 days ago1712027351  Contract Creation0 ETH
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
StrictAuthorizedTransferSecurityRegistry

Compiler Version
v0.8.24+commit.e11b9ed9

Optimization Enabled:
Yes with 9999999 runs

Other Settings:
cancun EvmVersion, MIT license
File 1 of 14 : StrictAuthorizedTransferSecurityRegistry.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import {
    ListTypes,
    TransferSecurityLevels,
    IStrictAuthorizedTransferSecurityRegistry
} from "./interfaces/IStrictAuthorizedTransferSecurityRegistry.sol";

import {
    ICreatorTokenTransferValidator
} from "./interfaces/ICreatorTokenTransferValidator.sol";

import { IOwnable } from "./interfaces/IOwnable.sol";
import { IAccessControl } from "@openzeppelin/contracts/access/IAccessControl.sol";
import { EnumerableSet } from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import { ERC165 } from "@openzeppelin/contracts/utils/introspection/ERC165.sol";

import { Tstorish } from "tstorish/Tstorish.sol";

import { IEOARegistry } from "./interfaces/IEOARegistry.sol";

import {
    StrictAuthorizedTransferSecurityRegistryExtraViewFns
} from "./StrictAuthorizedTransferSecurityRegistryExtraViewFns.sol";

/// @title StrictAuthorizedTransferSecurityRegistry
/// @dev Implementation of a simplified version of the Transfer Security Registry that only
///      supports authorizers and whitelisted operators, and allows collections to disable
///      direct transfers (where caller == from) and contract recipients (requiring EOA
///      registration by providing a signature). Note that a number of view functions on
///      collections that add this validator will not work.
contract StrictAuthorizedTransferSecurityRegistry is Tstorish, IStrictAuthorizedTransferSecurityRegistry, ERC165 {
    using EnumerableSet for EnumerableSet.AddressSet;

    /**
     * @dev This struct is used internally to represent an enumerable list of accounts.
     */
    struct AccountList {
        EnumerableSet.AddressSet enumerableAccounts;
        mapping (address => bool) nonEnumerableAccounts;
    }

    /**
     * @dev This struct is used internally for the storage of authorizer + operator lists.
     */
    struct List {
        address owner;
        AccountList authorizers;
        AccountList operators;
        AccountList blacklist;
    }

    struct CollectionConfiguration {
        uint120 listId;
        bool policyBypassed;
        bool blacklistBased;
        bool directTransfersDisabled;
        bool contractRecipientsDisabled;
        bool signatureRegistrationRequired;
    }
    
    /// @dev The default admin role value for contracts that implement access control.
    bytes32 private constant DEFAULT_ACCESS_CONTROL_ADMIN_ROLE = 0x00;

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

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

    /// @dev Mapping of collection addresses to list ids & security policies.
    mapping (address => CollectionConfiguration) private collectionConfiguration;

    // TSTORE slot: scope ++ 8 empty bytes ++ collection
    bytes4 private constant _AUTHORIZED_OPERATOR_SCOPE = 0x596a397a;

    // TSTORE slot: keccak256(scope ++ identifier ++ collection)
    bytes4 private constant _AUTHORIZED_IDENTIFIER_SCOPE = 0x7e746c61;

    // TSTORE slot: keccak256(scope ++ identifier ++ collection)
    bytes4 private constant _AUTHORIZED_AMOUNT_SCOPE = 0x71836d45;

    address private immutable _EXTRA_VIEW_FUNCTIONS;

    IEOARegistry private immutable _EOA_REGISTRY;

    /**
     * @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 StrictAuthorizedTransferSecurityRegistry__ArrayLengthCannotBeZero();
        }
        _;
    }

    constructor(address defaultOwner, address eoaRegistry) {
        uint120 id = 0;

        lists[id].owner = defaultOwner;

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

        // Deploy a contract containing legacy view functions.
        _EXTRA_VIEW_FUNCTIONS = address(new StrictAuthorizedTransferSecurityRegistryExtraViewFns());

        _EOA_REGISTRY = IEOARegistry(eoaRegistry);
    }

    // Delegatecall to contract with legacy view functions in the fallback.
    fallback() external {
        address target = _EXTRA_VIEW_FUNCTIONS;
        assembly {
            calldatacopy(0, 0, calldatasize())
            let status := delegatecall(gas(), target, 0, calldatasize(), 0, 0)
            returndatacopy(0, 0, returndatasize())
            switch status
            case 0 {
                revert(0, returndatasize())
            }
            default {
                return(0, returndatasize())
            }
        }
    }

    /// Manage lists of authorizers & operators that can be applied to collections
    function createList(string calldata name) external returns (uint120) {
        uint120 id = ++lastListId;

        lists[id].owner = msg.sender;

        emit CreatedList(id, name);
        emit ReassignedListOwnership(id, msg.sender);

        return id;
    }

    function createListCopy(string calldata name, uint120 sourceListId) external override returns (uint120) {
        uint120 id = ++lastListId;

        unchecked {
            if (sourceListId > id - 1) {
                revert StrictAuthorizedTransferSecurityRegistry__ListDoesNotExist();
            }
        }
        List storage sourceList = lists[sourceListId];
        List storage targetList = lists[id];

        targetList.owner = msg.sender;

        emit CreatedList(id, name);
        emit ReassignedListOwnership(id, msg.sender);

        _copyAddressSet(ListTypes.AuthorizerList, id, sourceList.authorizers, targetList.authorizers);
        _copyAddressSet(ListTypes.OperatorList, id, sourceList.operators, targetList.operators);
        _copyAddressSet(ListTypes.OperatorRequiringAuthorizationList, id, sourceList.blacklist, targetList.blacklist);

        return id;
    }

    function reassignOwnershipOfList(uint120 id, address newOwner) external onlyListOwner(id) {
        if (newOwner == address(0)) {
            revert StrictAuthorizedTransferSecurityRegistry__ListOwnershipCannotBeTransferredToZeroAddress();
        }

        lists[id].owner = newOwner;

        emit ReassignedListOwnership(id, newOwner);
    }

    function renounceOwnershipOfList(uint120 id) external onlyListOwner(id) {
        lists[id].owner = address(0);

        emit ReassignedListOwnership(id, address(0));
    }

    function applyListToCollection(address collection, uint120 id) external {
        _requireCallerIsNFTOrContractOwnerOrAdmin(collection);

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

        collectionConfiguration[collection].listId = id;

        emit AppliedListToCollection(collection, id);
    }

    function listOwners(uint120 id) external view returns (address) {
        return lists[id].owner;
    }

    /// Manage and query for authorizers on lists
    function addAccountToAuthorizers(uint120 id, address account) external onlyListOwner(id) {
        address[] memory accounts = new address[](1);
        accounts[0] = account;
        _addAccounts(id, accounts, lists[id].authorizers, ListTypes.AuthorizerList);
    }

    function addAccountsToAuthorizers(uint120 id, address[] calldata accounts) external onlyListOwner(id) notZero(accounts.length) {
        _addAccounts(id, accounts, lists[id].authorizers, ListTypes.AuthorizerList);
    }

    function addAuthorizers(uint120 id, address[] calldata accounts) external onlyListOwner(id) notZero(accounts.length) {
        _addAccounts(id, accounts, lists[id].authorizers, ListTypes.AuthorizerList);
    }

    function removeAccountFromAuthorizers(uint120 id, address account) external onlyListOwner(id) {
        address[] memory accounts = new address[](1);
        accounts[0] = account;
        _removeAccounts(id, accounts, lists[id].authorizers, ListTypes.AuthorizerList);
    }
    
    function removeAccountsFromAuthorizers(uint120 id, address[] calldata accounts) external onlyListOwner(id) notZero(accounts.length) {
        _removeAccounts(id, accounts, lists[id].authorizers, ListTypes.AuthorizerList);
    }

    function getAuthorizerAccounts(uint120 id) external view returns (address[] memory) {
        return lists[id].authorizers.enumerableAccounts.values();
    }

    function isAccountAuthorizer(uint120 id, address account) external view returns (bool) {
        return lists[id].authorizers.nonEnumerableAccounts[account];
    }

    function getAuthorizerAccountsByCollection(address collection) external view returns (address[] memory) {
        return lists[collectionConfiguration[collection].listId].authorizers.enumerableAccounts.values();
    }

    function isAccountAuthorizerOfCollection(address collection, address account) external view returns (bool) {
        return lists[collectionConfiguration[collection].listId].authorizers.nonEnumerableAccounts[account];
    }

    function _ensureCallerIsCollectionAuthorizer(address collection) internal view {
        if (!lists[collectionConfiguration[collection].listId].authorizers.nonEnumerableAccounts[msg.sender]) {
            revert StrictAuthorizedTransferSecurityRegistry__CallerIsNotValidAuthorizer();
        }
    }

    /// Manage and query for operators on lists
    function addAccountToWhitelist(uint120 id, address account) external onlyListOwner(id) {
        address[] memory accounts = new address[](1);
        accounts[0] = account;
        _addAccounts(id, accounts, lists[id].operators, ListTypes.OperatorList);
    }

    function addAccountsToWhitelist(uint120 id, address[] calldata accounts) external onlyListOwner(id) notZero(accounts.length) {
        _addAccounts(id, accounts, lists[id].operators, ListTypes.OperatorList);
    }

    function addOperators(uint120 id, address[] calldata accounts) external onlyListOwner(id) notZero(accounts.length) {
        _addAccounts(id, accounts, lists[id].operators, ListTypes.OperatorList);
    }

    function removeAccountFromWhitelist(uint120 id, address account) external onlyListOwner(id) {
        address[] memory accounts = new address[](1);
        accounts[0] = account;
        _removeAccounts(id, accounts, lists[id].operators, ListTypes.OperatorList);
    }

    function removeAccountsFromWhitelist(uint120 id, address[] calldata accounts) external onlyListOwner(id) notZero(accounts.length) {
        _removeAccounts(id, accounts, lists[id].operators, ListTypes.OperatorList);
    }
    
    function getWhitelistedAccounts(uint120 id) external view returns (address[] memory) {
        return lists[id].operators.enumerableAccounts.values();
    }

    function isAccountWhitelisted(uint120 id, address account) external view returns (bool) {
        return lists[id].operators.nonEnumerableAccounts[account];
    }
    function getWhitelistedAccountsByCollection(address collection) external view returns (address[] memory) {
        return lists[collectionConfiguration[collection].listId].operators.enumerableAccounts.values();
    }

    function isAccountWhitelistedByCollection(address collection, address account) external view returns (bool) {
        return lists[collectionConfiguration[collection].listId].operators.nonEnumerableAccounts[account];
    }

    /// Manage and query for blacklists on lists
    function addAccountToBlacklist(uint120 id, address account) external onlyListOwner(id) {
        address[] memory accounts = new address[](1);
        accounts[0] = account;
        _addAccounts(id, accounts, lists[id].blacklist, ListTypes.OperatorRequiringAuthorizationList);
    }

    function addAccountsToBlacklist(uint120 id, address[] calldata accounts) external onlyListOwner(id) notZero(accounts.length) {
        _addAccounts(id, accounts, lists[id].blacklist, ListTypes.OperatorRequiringAuthorizationList);
    }

    function removeAccountFromBlacklist(uint120 id, address account) external onlyListOwner(id) {
        address[] memory accounts = new address[](1);
        accounts[0] = account;
        _removeAccounts(id, accounts, lists[id].blacklist, ListTypes.OperatorRequiringAuthorizationList);
    }

    function removeAccountsFromBlacklist(uint120 id, address[] calldata accounts) external onlyListOwner(id) notZero(accounts.length) {
        _removeAccounts(id, accounts, lists[id].blacklist, ListTypes.OperatorRequiringAuthorizationList);
    } 

    function getBlacklistedAccounts(uint120 id) external view returns (address[] memory) {
        return lists[id].blacklist.enumerableAccounts.values();
    }

    function isAccountBlacklisted(uint120 id, address account) external view returns (bool) {
        return lists[id].blacklist.nonEnumerableAccounts[account];
    }
    function getBlacklistedAccountsByCollection(address collection) external view returns (address[] memory) {
        return lists[collectionConfiguration[collection].listId].blacklist.enumerableAccounts.values();
    }

    function isAccountBlacklistedByCollection(address collection, address account) external view returns (bool) {
        return lists[collectionConfiguration[collection].listId].blacklist.nonEnumerableAccounts[account];
    }

    /// Ensure that a specific operator has been authorized to transfer tokens
    function validateTransfer(address caller, address from, address to) external view {
        _validateTransfer(caller, from, to);
    }

    /// Ensure that a transfer has been authorized for a specific tokenId
    function validateTransfer(address caller, address from, address to, uint256 tokenId) external view {
        _validateTransferByIdentifer(caller, from, to, tokenId);
    }

    /// Ensure that a transfer has been authorized for a specific amount of a specific tokenId, and
    /// reduce the transferable amount remaining
    function validateTransfer(address caller, address from, address to, uint256 tokenId, uint256 amount) external {
        _validateTransferByAmount(caller, from, to, tokenId, amount);
    }

    /// Legacy alias for validateTransfer (address caller, address from, address to)
    function applyCollectionTransferPolicy(address caller, address from, address to) external view {
        _validateTransfer(caller, from, to);
    }

    /// Temporarily assign a specific allowed operator for a given collection
    function beforeAuthorizedTransfer(address operator, address token) external {
        _ensureCallerIsCollectionAuthorizer(token);

        _setTstorish(
            _getAuthorizedOperatorSlot(token),
            uint256(uint160(operator))
        );
    }

    /// Clear assignment of a specific allowed operator for a given collection
    function afterAuthorizedTransfer(address token) external {
        _ensureCallerIsCollectionAuthorizer(token);

        _clearTstorish(_getAuthorizedOperatorSlot(token));
    }

    /// Temporarily allow a specific tokenId from a given collection to be transferred
    function beforeAuthorizedTransfer(address token, uint256 tokenId) external {
        _ensureCallerIsCollectionAuthorizer(token);

        _setTstorish(
            _getAuthorizedIdentifierSlot(token, tokenId),
            1
        );
    }

    /// Clear assignment of an specific tokenId's transfer allowance
    function afterAuthorizedTransfer(address token, uint256 tokenId) external {
        _ensureCallerIsCollectionAuthorizer(token);

        _clearTstorish(_getAuthorizedIdentifierSlot(token, tokenId));
    }

    /// Temporarily allow a specific amount of a specific tokenId from a given collection to be transferred
    function beforeAuthorizedTransferWithAmount(address token, uint256 tokenId, uint256 amount) external {
        _ensureCallerIsCollectionAuthorizer(token);

        uint256 slot = _getAuthorizedAmountSlot(token, tokenId);

        uint256 currentAmount = _getTstorish(slot);

        uint256 newAmount = currentAmount + amount;

        _setTstorish(slot, newAmount);
    }

    /// Clear assignment of a tokenId's transfer allowance for a specific amount
    function afterAuthorizedTransferWithAmount(address token, uint256 tokenId) external {
        _ensureCallerIsCollectionAuthorizer(token);

        _clearTstorish(_getAuthorizedAmountSlot(token, tokenId));
    }

    function setTransferSecurityLevelOfCollection(
        address collection,
        uint8 level,
        bool enableAuthorizationMode,
        bool authorizersCanSetWildcardOperators,
        bool enableAccountFreezingMode
    ) external {
        if (!enableAuthorizationMode || !authorizersCanSetWildcardOperators || enableAccountFreezingMode) {
            revert StrictAuthorizedTransferSecurityRegistry__UnsupportedSecurityLevelDetail();
        }

        _setTransferSecurityLevelOfCollection(collection, TransferSecurityLevels(level));
    }

    function setTransferSecurityLevelOfCollection(
        address collection,
        TransferSecurityLevels level
    ) external {
        _setTransferSecurityLevelOfCollection(collection, level);
    }

    function isVerifiedEOA(address account) external view returns (bool) {
        return _EOA_REGISTRY.isVerifiedEOA(account);
    }

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

    function _setTransferSecurityLevelOfCollection(
        address collection,
        TransferSecurityLevels level
    ) internal {
        _requireCallerIsNFTOrContractOwnerOrAdmin(collection);

        if (level == TransferSecurityLevels.Recommended) {
            level = TransferSecurityLevels.Three;
        }

        CollectionConfiguration storage config = collectionConfiguration[collection];
        
        if (level == TransferSecurityLevels.One) {
            config.policyBypassed = true;
            config.blacklistBased = false;
            config.directTransfersDisabled = false;
            config.contractRecipientsDisabled = false;
            config.signatureRegistrationRequired = false;
        } else if (level == TransferSecurityLevels.Two) {
            config.policyBypassed = false;
            config.blacklistBased = true;
            config.directTransfersDisabled = false;
            config.contractRecipientsDisabled = false;
            config.signatureRegistrationRequired = false;
        } else if (level == TransferSecurityLevels.Three) {
            config.policyBypassed = false;
            config.blacklistBased = false;
            config.directTransfersDisabled = false;
            config.contractRecipientsDisabled = false;
            config.signatureRegistrationRequired = false;
        } else if (level == TransferSecurityLevels.Four) {
            config.policyBypassed = false;
            config.blacklistBased = false;
            config.directTransfersDisabled = true;
            config.contractRecipientsDisabled = false;
            config.signatureRegistrationRequired = false;
        } else if (level == TransferSecurityLevels.Five) {
            config.policyBypassed = false;
            config.blacklistBased = false;
            config.directTransfersDisabled = false;
            config.contractRecipientsDisabled = true;
            config.signatureRegistrationRequired = false;
        } else if (level == TransferSecurityLevels.Six) {
            config.policyBypassed = false;
            config.blacklistBased = false;
            config.directTransfersDisabled = false;
            config.contractRecipientsDisabled = false;
            config.signatureRegistrationRequired = true;
        } else if (level == TransferSecurityLevels.Seven) {
            config.policyBypassed = false;
            config.blacklistBased = false;
            config.directTransfersDisabled = true;
            config.contractRecipientsDisabled = true;
            config.signatureRegistrationRequired = false;
        } else if (level == TransferSecurityLevels.Eight) {
            config.policyBypassed = false;
            config.blacklistBased = false;
            config.directTransfersDisabled = true;
            config.contractRecipientsDisabled = false;
            config.signatureRegistrationRequired = true;
        } else {
            revert StrictAuthorizedTransferSecurityRegistry__UnsupportedSecurityLevel();
        }

        emit SetTransferSecurityLevel(collection, level);
    }

    /**
     * @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,
        AccountList storage ptrFromList,
        AccountList 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 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 (msg.sender != lists[id].owner) {
            revert StrictAuthorizedTransferSecurityRegistry__CallerDoesNotOwnList();
        }
    }

    /**
     * @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 {
        if (msg.sender == tokenAddress) {
            return;
        }

        if (msg.sender == _safeOwner(tokenAddress)) {
            return;
        }

        if (!_safeHasRole(tokenAddress)) {
            revert StrictAuthorizedTransferSecurityRegistry__CallerMustHaveElevatedPermissionsForSpecifiedNFT();
        }
    }

    /**
     * @dev A gas efficient, and fallback-safe way to call the owner function on a token contract.
     *      This will get the owner if it exists - and when the function is unimplemented, the
     *      presence of a fallback function will not result in halted execution.
     */
    function _safeOwner(
        address tokenAddress
    ) internal view returns(address owner) {
        assembly {
            mstore(0x00, 0x8da5cb5b)
            let status := staticcall(gas(), tokenAddress, 0x1c, 0x04, 0x00, 0x20)
            if and(iszero(lt(returndatasize(), 0x20)), status) {
                owner := mload(0x00)
            }
        }
    }
    
    /**
     * @dev A gas efficient, and fallback-safe way to call the hasRole function on a token contract.
     *      This will check if the account `hasRole` if `hasRole` exists - and when the function is unimplemented, the
     *      presence of a fallback function will not result in halted execution.
     */
    function _safeHasRole(
        address tokenAddress
    ) internal view returns(bool hasRole) {
        assembly {
            let ptr := mload(0x40)
            mstore(0x40, add(ptr, 0x60))
            mstore(ptr, 0x91d14854)
            mstore(add(0x20, ptr), DEFAULT_ACCESS_CONTROL_ADMIN_ROLE)
            mstore(add(0x40, ptr), caller())
            let status := staticcall(gas(), tokenAddress, add(ptr, 0x1c), 0x44, 0x00, 0x20)
            if and(iszero(lt(returndatasize(), 0x20)), status) {
                hasRole := mload(0x00)
            }
        }
    }


    /**
     * @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) }
    }

    function _addAccounts(
        uint120 id,
        address[] memory accounts,
        AccountList storage accountList,
        ListTypes listType
    ) internal {
        address account;
        for (uint256 i = 0; i < accounts.length;) {
            account = accounts[i];

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

            if (accountList.enumerableAccounts.add(account)) {
                emit AddedAccountToList(listType, id, account);
                accountList.nonEnumerableAccounts[account] = true;
            }

            unchecked {
                ++i;
            }
        }
    }

    function _removeAccounts(
        uint120 id,
        address[] memory accounts,
        AccountList storage accountList,
        ListTypes listType
    ) internal {
        address account;
        for (uint256 i = 0; i < accounts.length;) {
            account = accounts[i];

            if (accountList.enumerableAccounts.remove(account)) {
                emit RemovedAccountFromList(listType, id, account);
                delete accountList.nonEnumerableAccounts[account];
            }

            unchecked {
                ++i;
            }
        }
    }

    function _validateTransfer(address operator, address from, address to) internal view {
        CollectionConfiguration memory config = collectionConfiguration[msg.sender];

        if (config.policyBypassed) {
            return;
        }

        if (config.contractRecipientsDisabled) {
            if (to.code.length != 0) {
                revert StrictAuthorizedTransferSecurityRegistry__ReceiverMustNotHaveDeployedCode();
            }
        }
        
        if (config.signatureRegistrationRequired) {
            if (!_EOA_REGISTRY.isVerifiedEOA(to)) {
                revert StrictAuthorizedTransferSecurityRegistry__ReceiverProofOfEOASignatureUnverified();
            }
        }

        if (operator == from) {
            if (config.directTransfersDisabled) {
                revert StrictAuthorizedTransferSecurityRegistry__CallerMustBeWhitelistedOperator();
            }

            return;
        }

        uint256 slot = _getAuthorizedOperatorSlot(msg.sender);

        if (operator == address(uint160(_getTstorish(slot)))) {
            return;
        }

        if (config.blacklistBased) {
            if (lists[config.listId].blacklist.nonEnumerableAccounts[operator]) {
                revert StrictAuthorizedTransferSecurityRegistry__UnauthorizedTransfer();
            }
        } else {
            if (!lists[config.listId].operators.nonEnumerableAccounts[operator]) {
                revert StrictAuthorizedTransferSecurityRegistry__UnauthorizedTransfer();
            }
        }
    }

    function _validateTransferByIdentifer(address operator, address from, address to, uint256 identifier) internal view {
        CollectionConfiguration memory config = collectionConfiguration[msg.sender];

        if (config.policyBypassed) {
            return;
        }

        if (config.contractRecipientsDisabled) {
            if (to.code.length != 0) {
                revert StrictAuthorizedTransferSecurityRegistry__ReceiverMustNotHaveDeployedCode();
            }
        }
        
        if (config.signatureRegistrationRequired) {
            if (!_EOA_REGISTRY.isVerifiedEOA(to)) {
                revert StrictAuthorizedTransferSecurityRegistry__ReceiverProofOfEOASignatureUnverified();
            }
        }

        if (operator == from) {
            if (config.directTransfersDisabled) {
                revert StrictAuthorizedTransferSecurityRegistry__CallerMustBeWhitelistedOperator();
            }

            return;
        }

        uint256 slot = _getAuthorizedIdentifierSlot(msg.sender, identifier);

        uint256 authorizedIdentifier = _getTstorish(slot);

        if (authorizedIdentifier != 0) {
            return;
        }

        if (config.blacklistBased) {
            if (lists[config.listId].blacklist.nonEnumerableAccounts[operator]) {
                revert StrictAuthorizedTransferSecurityRegistry__UnauthorizedTransfer();
            }
        } else {
            if (!lists[config.listId].operators.nonEnumerableAccounts[operator]) {
                revert StrictAuthorizedTransferSecurityRegistry__UnauthorizedTransfer();
            }
        }
    }

    function _validateTransferByAmount(address operator, address from, address to, uint256 identifier, uint256 amount) internal {
        CollectionConfiguration memory config = collectionConfiguration[msg.sender];

        if (config.policyBypassed) {
            return;
        }

        if (config.contractRecipientsDisabled) {
            if (to.code.length != 0) {
                revert StrictAuthorizedTransferSecurityRegistry__ReceiverMustNotHaveDeployedCode();
            }
        }
        
        if (config.signatureRegistrationRequired) {
            if (!_EOA_REGISTRY.isVerifiedEOA(to)) {
                revert StrictAuthorizedTransferSecurityRegistry__ReceiverProofOfEOASignatureUnverified();
            }
        }

        if (operator == from) {
            if (config.directTransfersDisabled) {
                revert StrictAuthorizedTransferSecurityRegistry__CallerMustBeWhitelistedOperator();
            }

            return;
        }

        uint256 slot = _getAuthorizedAmountSlot(msg.sender, identifier);

        uint256 authorizedAmount = _getTstorish(slot);
        if (authorizedAmount >= amount) {
            unchecked {
                _setTstorish(slot, authorizedAmount - amount);
            }

            return;
        }

        if (config.blacklistBased) {
            if (lists[config.listId].blacklist.nonEnumerableAccounts[operator]) {
                revert StrictAuthorizedTransferSecurityRegistry__UnauthorizedTransfer();
            }
        } else {
            if (!lists[config.listId].operators.nonEnumerableAccounts[operator]) {
                revert StrictAuthorizedTransferSecurityRegistry__UnauthorizedTransfer();
            }
        }
    }

    function _getAuthorizedOperatorSlot(
        address collection
    ) internal pure returns (uint256 slot) {
        bytes4 authorizedOperatorScope = _AUTHORIZED_OPERATOR_SCOPE;
        assembly {
            slot := or(
                authorizedOperatorScope,
                and(collection, 0xffffffffffffffffffffffffffffffffffffffff)
            )
        }
    }

    function _getAuthorizedIdentifierSlot(
        address collection,
        uint256 identifier
    ) internal pure returns (uint256 slot) {
        bytes4 authorizedIdentifierScope = _AUTHORIZED_IDENTIFIER_SCOPE;
        assembly {
            mstore(0x0, authorizedIdentifierScope)
            mstore(0x18, collection)
            mstore(0x04, identifier)
            slot := keccak256(0x0, 0x38)
        }
    }

    function _getAuthorizedAmountSlot(
        address collection,
        uint256 identifier
    ) internal pure returns (uint256 slot) {
        bytes4 authorizedAmountScope = _AUTHORIZED_AMOUNT_SCOPE;
        assembly {
            mstore(0x0, authorizedAmountScope)
            mstore(0x18, collection)
            mstore(0x04, identifier)
            slot := keccak256(0x0, 0x38)
        }
    }
}

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

enum ListTypes {
    AuthorizerList,
    OperatorList,
    OperatorRequiringAuthorizationList
}

enum TransferSecurityLevels {
    Recommended,
    One,
    Two,
    Three,
    Four,
    Five,
    Six,
    Seven,
    Eight
}

/// @title IStrictAuthorizedTransferSecurityRegistry
/// @dev Interface for the Authorized Transfer Security Registry, a simplified version of the Transfer
///      Security Registry that only supports authorizers and whitelisted operators, and assumes a
///      security level of OperatorWhitelistEnableOTC + authorizers for all collections that use it.
///      Note that a number of view functions on collections that add this validator will not work.
interface IStrictAuthorizedTransferSecurityRegistry {
    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 RemovedAccountFromList(ListTypes indexed kind, uint256 indexed id, address indexed account);
    event SetTransferSecurityLevel(address collection, TransferSecurityLevels level);

    error StrictAuthorizedTransferSecurityRegistry__ListDoesNotExist();
    error StrictAuthorizedTransferSecurityRegistry__CallerDoesNotOwnList();
    error StrictAuthorizedTransferSecurityRegistry__ArrayLengthCannotBeZero();
    error StrictAuthorizedTransferSecurityRegistry__CallerMustHaveElevatedPermissionsForSpecifiedNFT();
    error StrictAuthorizedTransferSecurityRegistry__ListOwnershipCannotBeTransferredToZeroAddress();
    error StrictAuthorizedTransferSecurityRegistry__ZeroAddressNotAllowed();
    error StrictAuthorizedTransferSecurityRegistry__UnauthorizedTransfer();
    error StrictAuthorizedTransferSecurityRegistry__CallerIsNotValidAuthorizer();
    error StrictAuthorizedTransferSecurityRegistry__UnsupportedSecurityLevel();
    error StrictAuthorizedTransferSecurityRegistry__UnsupportedSecurityLevelDetail();
    error StrictAuthorizedTransferSecurityRegistry__CallerMustBeWhitelistedOperator();
    error StrictAuthorizedTransferSecurityRegistry__ReceiverMustNotHaveDeployedCode();
    error StrictAuthorizedTransferSecurityRegistry__ReceiverProofOfEOASignatureUnverified();

    /// Manage lists of authorizers & operators that can be applied to collections
    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 listOwners(uint120 id) external view returns (address);

    /// Manage and query for authorizers on lists
    function addAccountToAuthorizers(uint120 id, address account) external;

    function addAccountsToAuthorizers(uint120 id, address[] calldata accounts) external;

    function addAuthorizers(uint120 id, address[] calldata accounts) external;

    function removeAccountFromAuthorizers(uint120 id, address account) external;
    
    function removeAccountsFromAuthorizers(uint120 id, address[] calldata accounts) external;

    function getAuthorizerAccounts(uint120 id) external view returns (address[] memory);

    function isAccountAuthorizer(uint120 id, address account) external view returns (bool);

    function getAuthorizerAccountsByCollection(address collection) external view returns (address[] memory);

    function isAccountAuthorizerOfCollection(address collection, address account) external view returns (bool);

    /// Manage and query for operators on lists
    function addAccountToWhitelist(uint120 id, address account) external;

    function addAccountsToWhitelist(uint120 id, address[] calldata accounts) external;

    function addOperators(uint120 id, address[] calldata accounts) external;

    function removeAccountFromWhitelist(uint120 id, address account) external;

    function removeAccountsFromWhitelist(uint120 id, address[] calldata accounts) external;
    
    function getWhitelistedAccounts(uint120 id) external view returns (address[] memory);

    function isAccountWhitelisted(uint120 id, address account) external view returns (bool);
    function getWhitelistedAccountsByCollection(address collection) external view returns (address[] memory);

    function isAccountWhitelistedByCollection(address collection, address account) external view returns (bool);

    /// Manage and query for blacklists on lists
    function addAccountToBlacklist(uint120 id, address account) external;

    function addAccountsToBlacklist(uint120 id, address[] calldata accounts) external;

    function removeAccountFromBlacklist(uint120 id, address account) external;

    function removeAccountsFromBlacklist(uint120 id, address[] calldata accounts) external;

    function getBlacklistedAccounts(uint120 id) external view returns (address[] memory);

    function isAccountBlacklisted(uint120 id, address account) external view returns (bool);
    function getBlacklistedAccountsByCollection(address collection) external view returns (address[] memory);

    function isAccountBlacklistedByCollection(address collection, address account) external view returns (bool);

    function setTransferSecurityLevelOfCollection(
        address collection,
        uint8 level,
        bool enableAuthorizationMode,
        bool authorizersCanSetWildcardOperators,
        bool enableAccountFreezingMode
    ) external;

    function setTransferSecurityLevelOfCollection(
        address collection,
        TransferSecurityLevels level
    ) external;

    function isVerifiedEOA(address account) external view returns (bool);

    /// Ensure that a specific operator has been authorized to transfer tokens
    function validateTransfer(address caller, address from, address to) external view;

    /// Ensure that a transfer has been authorized for a specific tokenId
    function validateTransfer(address caller, address from, address to, uint256 tokenId) external view;

    /// Ensure that a transfer has been authorized for a specific amount of a specific tokenId, and
    /// reduce the transferable amount remaining
    function validateTransfer(address caller, address from, address to, uint256 tokenId, uint256 amount) external;

    /// Legacy alias for validateTransfer (address caller, address from, address to)
    function applyCollectionTransferPolicy(address caller, address from, address to) external view;

    /// Temporarily assign a specific allowed operator for a given collection
    function beforeAuthorizedTransfer(address operator, address token) external;

    /// Clear assignment of a specific allowed operator for a given collection
    function afterAuthorizedTransfer(address token) external;

    /// Temporarily allow a specific tokenId from a given collection to be transferred
    function beforeAuthorizedTransfer(address token, uint256 tokenId) external;

    /// Clear assignment of an specific tokenId's transfer allowance
    function afterAuthorizedTransfer(address token, uint256 tokenId) external;

    /// Temporarily allow a specific amount of a specific tokenId from a given collection to be transferred
    function beforeAuthorizedTransferWithAmount(address token, uint256 tokenId, uint256 amount) external;

    /// Clear assignment of a tokenId's transfer allowance for a specific amount
    function afterAuthorizedTransferWithAmount(address token, uint256 tokenId) external;
}

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

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

File 5 of 14 : 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 6 of 14 : 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 7 of 14 : 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 8 of 14 : Tstorish.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

contract Tstorish {
    // Declare a storage variable indicating if TSTORE support has been
    // activated post-deployment.
    bool private _tstoreSupport;

    /*
     * ------------------------------------------------------------------------+
     * Opcode      | Mnemonic         | Stack              | Memory            |
     * ------------------------------------------------------------------------|
     * 60 0x02     | PUSH1 0x02       | 0x02               |                   |
     * 60 0x1e     | PUSH1 0x1e       | 0x1e 0x02          |                   |
     * 61 0x3d5c   | PUSH2 0x3d5c     | 0x3d5c 0x1e 0x02   |                   |
     * 3d          | RETURNDATASIZE   | 0 0x3d5c 0x1e 0x02 |                   |
     *                                                                         |
     * :: store deployed bytecode in memory: (3d) RETURNDATASIZE (5c) TLOAD :: |
     * 52          | MSTORE           | 0x1e 0x02          | [0..0x20): 0x3d5c |
     * f3          | RETURN           |                    | [0..0x20): 0x3d5c |
     * ------------------------------------------------------------------------+
     */
    uint256 constant _TLOAD_TEST_PAYLOAD = 0x6002_601e_613d5c_3d_52_f3;
    uint256 constant _TLOAD_TEST_PAYLOAD_LENGTH = 0x0a;
    uint256 constant _TLOAD_TEST_PAYLOAD_OFFSET = 0x16;

    // Declare an immutable variable to store the tstore test contract address.
    address private immutable _tloadTestContract;

    // Declare an immutable variable to store the initial TSTORE support status.
    bool private immutable _tstoreInitialSupport;

    // Declare an immutable function type variable for the _setTstorish function
    // based on chain support for tstore at time of deployment.
    function(uint256,uint256) internal immutable _setTstorish;

    // Declare an immutable function type variable for the _getTstorish function
    // based on chain support for tstore at time of deployment.
    function(uint256) view returns (uint256) internal immutable _getTstorish;

    // Declare an immutable function type variable for the _clearTstorish function
    // based on chain support for tstore at time of deployment.
    function(uint256) internal immutable _clearTstorish;

    // Declare a few custom revert error types.
    error TStoreAlreadyActivated();
    error TStoreNotSupported();
    error TloadTestContractDeploymentFailed();
    error OnlyDirectCalls();

    /**
     * @dev Determine TSTORE availability during deployment. This involves
     *      attempting to deploy a contract that utilizes TLOAD as part of the
     *      contract construction bytecode, and configuring initial support for
     *      using TSTORE in place of SSTORE based on the result.
     */
    constructor() {
        // Deploy the contract testing TLOAD support and store the address.
        address tloadTestContract = _prepareTloadTest();

        // Ensure the deployment was successful.
        if (tloadTestContract == address(0)) {
            revert TloadTestContractDeploymentFailed();
        }

        // Determine if TSTORE is supported.
        bool tstoreInitialSupport = _testTload(tloadTestContract);

        if (tstoreInitialSupport) {
            // If TSTORE is supported, set functions to their versions that use
            // tstore/tload directly without support checks.
            _setTstorish = _setTstore;
            _getTstorish = _getTstore;
            _clearTstorish = _clearTstore;
        } else {
            // If TSTORE is not supported, set functions to their versions that 
            // fallback to sstore/sload until _tstoreSupport is true.
            _setTstorish = _setTstorishWithSstoreFallback;
            _getTstorish = _getTstorishWithSloadFallback;
            _clearTstorish = _clearTstorishWithSstoreFallback;
        }

        _tstoreInitialSupport = tstoreInitialSupport;

        // Set the address of the deployed TLOAD test contract as an immutable.
        _tloadTestContract = tloadTestContract;
    }

    /**
     * @dev External function to activate TSTORE usage. Does not need to be
     *      called if TSTORE is supported from deployment, and only needs to be
     *      called once. Reverts if TSTORE has already been activated or if the
     *      opcode is not available. Note that this must be called directly from
     *      an externally-owned account to avoid potential reentrancy issues.
     */
    function __activateTstore() external {
        // Ensure this function is triggered from an externally-owned account.
        if (msg.sender != tx.origin) {
            revert OnlyDirectCalls();
        }

        // Determine if TSTORE can potentially be activated.
        if (_tstoreInitialSupport || _tstoreSupport) {
            revert TStoreAlreadyActivated();
        }

        // Determine if TSTORE can be activated and revert if not.
        if (!_testTload(_tloadTestContract)) {
            revert TStoreNotSupported();
        }

        // Mark TSTORE as activated.
        _tstoreSupport = true;
    }

    /**
     * @dev Private function to set a TSTORISH value. Assigned to _setTstorish 
     *      internal function variable at construction if chain has tstore support.
     *
     * @param storageSlot The slot to write the TSTORISH value to.
     * @param value       The value to write to the given storage slot.
     */
    function _setTstore(uint256 storageSlot, uint256 value) private {
        assembly {
            tstore(storageSlot, value)
        }
    }

    /**
     * @dev Private function to set a TSTORISH value with sstore fallback. 
     *      Assigned to _setTstorish internal function variable at construction
     *      if chain does not have tstore support.
     *
     * @param storageSlot The slot to write the TSTORISH value to.
     * @param value       The value to write to the given storage slot.
     */
    function _setTstorishWithSstoreFallback(uint256 storageSlot, uint256 value) private {
        if (_tstoreSupport) {
            assembly {
                tstore(storageSlot, value)
            }
        } else {
            assembly {
                sstore(storageSlot, value)
            }
        }
    }

    /**
     * @dev Private function to read a TSTORISH value. Assigned to _getTstorish
     *      internal function variable at construction if chain has tstore support.
     *
     * @param storageSlot The slot to read the TSTORISH value from.
     *
     * @return value The TSTORISH value at the given storage slot.
     */
    function _getTstore(
        uint256 storageSlot
    ) private view returns (uint256 value) {
        assembly {
            value := tload(storageSlot)
        }
    }

    /**
     * @dev Private function to read a TSTORISH value with sload fallback. 
     *      Assigned to _getTstorish internal function variable at construction
     *      if chain does not have tstore support.
     *
     * @param storageSlot The slot to read the TSTORISH value from.
     *
     * @return value The TSTORISH value at the given storage slot.
     */
    function _getTstorishWithSloadFallback(
        uint256 storageSlot
    ) private view returns (uint256 value) {
        if (_tstoreSupport) {
            assembly {
                value := tload(storageSlot)
            }
        } else {
            assembly {
                value := sload(storageSlot)
            }
        }
    }

    /**
     * @dev Private function to clear a TSTORISH value. Assigned to _clearTstorish internal 
     *      function variable at construction if chain has tstore support.
     *
     * @param storageSlot The slot to clear the TSTORISH value for.
     */
    function _clearTstore(uint256 storageSlot) private {
        assembly {
            tstore(storageSlot, 0)
        }
    }

    /**
     * @dev Private function to clear a TSTORISH value with sstore fallback. 
     *      Assigned to _clearTstorish internal function variable at construction
     *      if chain does not have tstore support.
     *
     * @param storageSlot The slot to clear the TSTORISH value for.
     */
    function _clearTstorishWithSstoreFallback(uint256 storageSlot) private {
        if (_tstoreSupport) {
            assembly {
                tstore(storageSlot, 0)
            }
        } else {
            assembly {
                sstore(storageSlot, 0)
            }
        }
    }

    /**
     * @dev Private function to deploy a test contract that utilizes TLOAD as
     *      part of its fallback logic.
     */
    function _prepareTloadTest() private returns (address contractAddress) {
        // Utilize assembly to deploy a contract testing TLOAD support.
        assembly {
            // Write the contract deployment code payload to scratch space.
            mstore(0, _TLOAD_TEST_PAYLOAD)

            // Deploy the contract.
            contractAddress := create(
                0,
                _TLOAD_TEST_PAYLOAD_OFFSET,
                _TLOAD_TEST_PAYLOAD_LENGTH
            )
        }
    }

    /**
     * @dev Private view function to determine if TSTORE/TLOAD are supported by
     *      the current EVM implementation by attempting to call the test
     *      contract, which utilizes TLOAD as part of its fallback logic.
     */
    function _testTload(
        address tloadTestContract
    ) private view returns (bool ok) {
        // Call the test contract, which will perform a TLOAD test. If the call
        // does not revert, then TLOAD/TSTORE is supported. Do not forward all
        // available gas, as all forwarded gas will be consumed on revert.
        (ok, ) = tloadTestContract.staticcall{ gas: gasleft() / 10 }("");
    }
}

File 9 of 14 : 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 10 of 14 : StrictAuthorizedTransferSecurityRegistryExtraViewFns.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import { EnumerableSet } from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";

import { Tstorish } from "tstorish/Tstorish.sol";

import { TransferSecurityLevels } from "./interfaces/IStrictAuthorizedTransferSecurityRegistry.sol";

/// @title StrictAuthorizedTransferSecurityRegistryExtraViewFns
/// @dev Additional view functions, called by StrictAuthorizedTransferSecurityRegistry
///      via delegatecall in the fallback.
contract StrictAuthorizedTransferSecurityRegistryExtraViewFns is Tstorish {
    using EnumerableSet for EnumerableSet.AddressSet;

    error StrictAuthorizedTransferSecurityRegistry__NotImplemented();

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

    struct AccountList {
        EnumerableSet.AddressSet enumerableAccounts;
        mapping (address => bool) nonEnumerableAccounts;
    }

    struct List {
        address owner;
        AccountList authorizers;
        AccountList operators;
    }

    struct CollectionConfiguration {
        uint120 listId;
        bool policyBypassed;
        bool blacklistBased;
        bool directTransfersDisabled;
        bool contractRecipientsDisabled;
        bool signatureRegistrationRequired;
    }

    uint120 private UNUSED_lastListId;

    mapping (uint120 => List) private lists;

    /// @dev Mapping of collection addresses to list ids & security policies.
    mapping (address => CollectionConfiguration) private collectionConfiguration;

    // view functions from other transfer security registries, included for completeness
    function getBlacklistedAccounts(uint120) external pure returns (address[] memory) {}
    function getWhitelistedAccounts(uint120 id) external view returns (address[] memory) {
        return lists[id].operators.enumerableAccounts.values();
    }
    function getBlacklistedCodeHashes(uint120) external pure returns (bytes32[] memory) {}
    function getWhitelistedCodeHashes(uint120) external pure returns (bytes32[] memory) {}
    function isAccountBlacklisted(uint120, address) external pure returns (bool) {
        return false;
    }
    function isAccountWhitelisted(uint120 id, address account) external view returns (bool) {
        return lists[id].operators.nonEnumerableAccounts[account];
    }
    function isCodeHashBlacklisted(uint120, bytes32) external pure returns (bool) {
        return false;
    }
    function isCodeHashWhitelisted(uint120, bytes32) external pure returns (bool) {
        return false;
    }
    function getBlacklistedAccountsByCollection(address) external pure returns (address[] memory) {}
    function getWhitelistedAccountsByCollection(address collection) external view returns (address[] memory) {
        return lists[collectionConfiguration[collection].listId].operators.enumerableAccounts.values();
    }
    function getBlacklistedCodeHashesByCollection(address) external pure returns (bytes32[] memory) {}
    function getWhitelistedCodeHashesByCollection(address) external pure returns (bytes32[] memory) {}
    function isAccountBlacklistedByCollection(address, address) external pure returns (bool) {
        return false;
    }
    function isAccountWhitelistedByCollection(
        address collection, address account
    ) external view returns (bool) {
        return lists[collectionConfiguration[collection].listId].operators.nonEnumerableAccounts[account];
    }
    function isCodeHashBlacklistedByCollection(address, bytes32) external pure returns (bool) {
        return false;
    }
    function isCodeHashWhitelistedByCollection(address, bytes32) external pure returns (bool) {
        return false;
    }
    function getCollectionSecurityPolicy(
        address collection
    ) external view returns (CollectionSecurityPolicy memory) {
        CollectionConfiguration memory config = collectionConfiguration[collection];

        return CollectionSecurityPolicy({
            transferSecurityLevel: _getSecurityLevel(config),
            operatorWhitelistId: config.listId,
            permittedContractReceiversId: 0
        });
    }
    function getWhitelistedOperators(uint120 id) external view returns (address[] memory) {
        return lists[id].operators.enumerableAccounts.values();
    }
    function getPermittedContractReceivers(uint120) external pure returns (address[] memory) {}
    function isOperatorWhitelisted(uint120 id, address operator) external view returns (bool) {
        return lists[id].operators.nonEnumerableAccounts[operator];
    }
    function isContractReceiverPermitted(uint120, address) external pure returns (bool) {
        return true;
    }

    function _getSecurityLevel(
        CollectionConfiguration memory config
    ) internal pure returns (TransferSecurityLevels level) {
        bool policyBypassed = config.policyBypassed;
        bool blacklistBased = config.blacklistBased;
        bool directTransfersDisabled = config.directTransfersDisabled;
        bool contractRecipientsDisabled = config.contractRecipientsDisabled;
        bool signatureRegistrationRequired = config.signatureRegistrationRequired;

        if (policyBypassed) {
            return TransferSecurityLevels.One;
        }

        if (blacklistBased) {
            return TransferSecurityLevels.Two;
        }

        if (directTransfersDisabled) {
            if (signatureRegistrationRequired) {
                return TransferSecurityLevels.Eight;
            } else if (contractRecipientsDisabled) {
                return TransferSecurityLevels.Seven;
            }

            return TransferSecurityLevels.Four;
        }

        if (signatureRegistrationRequired) {
            return TransferSecurityLevels.Six;
        } else if (contractRecipientsDisabled) {
            return TransferSecurityLevels.Five;
        }

        return TransferSecurityLevels.Three;
    }

    fallback() external {
        revert StrictAuthorizedTransferSecurityRegistry__NotImplemented();
    }
}

File 11 of 14 : 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 12 of 14 : 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 13 of 14 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

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

File 14 of 14 : 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;
}

Settings
{
  "remappings": [
    "seaport-core/=lib/seaport-core/",
    "seaport-types/=lib/seaport-types/",
    "seaport-sol/=lib/seaport-sol/src/",
    "seaport-deploy/=lib/seaport-deploy/src/",
    "solady/=lib/solady/",
    "@openzeppelin/=lib/openzeppelin-contracts/",
    "@limitbreak/creator-token-standards/=lib/creator-token-standards/src/",
    "@rari-capital/solmate/=lib/seaport-sol/lib/seaport/lib/solmate/",
    "ERC721A/=lib/creator-token-standards/lib/ERC721A/contracts/",
    "creator-token-standards/=lib/creator-token-standards/",
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "erc4626-tests/=lib/seaport-sol/lib/seaport/lib/openzeppelin-contracts/lib/erc4626-tests/",
    "erc721a/=lib/creator-token-standards/lib/ERC721A/",
    "forge-std/=lib/forge-std/src/",
    "murky/=lib/creator-token-standards/lib/murky/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/",
    "seaport/=lib/seaport-sol/lib/seaport/contracts/",
    "solarray/=lib/seaport-sol/lib/solarray/src/",
    "solmate/=lib/seaport-sol/lib/seaport/lib/solmate/src/",
    "tstorish/=lib/tstorish/src/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 9999999
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "cancun",
  "viaIR": false,
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"defaultOwner","type":"address"},{"internalType":"address","name":"eoaRegistry","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"OnlyDirectCalls","type":"error"},{"inputs":[],"name":"StrictAuthorizedTransferSecurityRegistry__ArrayLengthCannotBeZero","type":"error"},{"inputs":[],"name":"StrictAuthorizedTransferSecurityRegistry__CallerDoesNotOwnList","type":"error"},{"inputs":[],"name":"StrictAuthorizedTransferSecurityRegistry__CallerIsNotValidAuthorizer","type":"error"},{"inputs":[],"name":"StrictAuthorizedTransferSecurityRegistry__CallerMustBeWhitelistedOperator","type":"error"},{"inputs":[],"name":"StrictAuthorizedTransferSecurityRegistry__CallerMustHaveElevatedPermissionsForSpecifiedNFT","type":"error"},{"inputs":[],"name":"StrictAuthorizedTransferSecurityRegistry__ListDoesNotExist","type":"error"},{"inputs":[],"name":"StrictAuthorizedTransferSecurityRegistry__ListOwnershipCannotBeTransferredToZeroAddress","type":"error"},{"inputs":[],"name":"StrictAuthorizedTransferSecurityRegistry__ReceiverMustNotHaveDeployedCode","type":"error"},{"inputs":[],"name":"StrictAuthorizedTransferSecurityRegistry__ReceiverProofOfEOASignatureUnverified","type":"error"},{"inputs":[],"name":"StrictAuthorizedTransferSecurityRegistry__UnauthorizedTransfer","type":"error"},{"inputs":[],"name":"StrictAuthorizedTransferSecurityRegistry__UnsupportedSecurityLevel","type":"error"},{"inputs":[],"name":"StrictAuthorizedTransferSecurityRegistry__UnsupportedSecurityLevelDetail","type":"error"},{"inputs":[],"name":"StrictAuthorizedTransferSecurityRegistry__ZeroAddressNotAllowed","type":"error"},{"inputs":[],"name":"TStoreAlreadyActivated","type":"error"},{"inputs":[],"name":"TStoreNotSupported","type":"error"},{"inputs":[],"name":"TloadTestContractDeploymentFailed","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":"address","name":"collection","type":"address"},{"indexed":true,"internalType":"uint120","name":"id","type":"uint120"}],"name":"AppliedListToCollection","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":"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":false,"internalType":"address","name":"collection","type":"address"},{"indexed":false,"internalType":"enum TransferSecurityLevels","name":"level","type":"uint8"}],"name":"SetTransferSecurityLevel","type":"event"},{"stateMutability":"nonpayable","type":"fallback"},{"inputs":[],"name":"__activateTstore","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint120","name":"id","type":"uint120"},{"internalType":"address","name":"account","type":"address"}],"name":"addAccountToAuthorizers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint120","name":"id","type":"uint120"},{"internalType":"address","name":"account","type":"address"}],"name":"addAccountToBlacklist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint120","name":"id","type":"uint120"},{"internalType":"address","name":"account","type":"address"}],"name":"addAccountToWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint120","name":"id","type":"uint120"},{"internalType":"address[]","name":"accounts","type":"address[]"}],"name":"addAccountsToAuthorizers","outputs":[],"stateMutability":"nonpayable","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":"address[]","name":"accounts","type":"address[]"}],"name":"addAuthorizers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint120","name":"id","type":"uint120"},{"internalType":"address[]","name":"accounts","type":"address[]"}],"name":"addOperators","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"afterAuthorizedTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"afterAuthorizedTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"afterAuthorizedTransferWithAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"caller","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"}],"name":"applyCollectionTransferPolicy","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"},{"internalType":"uint120","name":"id","type":"uint120"}],"name":"applyListToCollection","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"beforeAuthorizedTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"address","name":"token","type":"address"}],"name":"beforeAuthorizedTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"beforeAuthorizedTransferWithAmount","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":"uint120","name":"id","type":"uint120"}],"name":"getAuthorizerAccounts","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"}],"name":"getAuthorizerAccountsByCollection","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","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":"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"},{"internalType":"address","name":"account","type":"address"}],"name":"isAccountAuthorizer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"},{"internalType":"address","name":"account","type":"address"}],"name":"isAccountAuthorizerOfCollection","outputs":[{"internalType":"bool","name":"","type":"bool"}],"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":"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":"id","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":"account","type":"address"}],"name":"removeAccountFromAuthorizers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint120","name":"id","type":"uint120"},{"internalType":"address","name":"account","type":"address"}],"name":"removeAccountFromBlacklist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint120","name":"id","type":"uint120"},{"internalType":"address","name":"account","type":"address"}],"name":"removeAccountFromWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint120","name":"id","type":"uint120"},{"internalType":"address[]","name":"accounts","type":"address[]"}],"name":"removeAccountsFromAuthorizers","outputs":[],"stateMutability":"nonpayable","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"}],"name":"renounceOwnershipOfList","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"},{"internalType":"uint8","name":"level","type":"uint8"},{"internalType":"bool","name":"enableAuthorizationMode","type":"bool"},{"internalType":"bool","name":"authorizersCanSetWildcardOperators","type":"bool"},{"internalType":"bool","name":"enableAccountFreezingMode","type":"bool"}],"name":"setTransferSecurityLevelOfCollection","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"},{"internalType":"enum TransferSecurityLevels","name":"level","type":"uint8"}],"name":"setTransferSecurityLevelOfCollection","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"caller","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"validateTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"caller","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"}],"name":"validateTransfer","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"caller","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"validateTransfer","outputs":[],"stateMutability":"view","type":"function"}]

61016060405234801562000011575f80fd5b5060405162004d8138038062004d8183398101604081905262000034916200032c565b5f6200003f62000235565b90506001600160a01b0381166200006957604051632aea588760e01b815260040160405180910390fd5b5f62000075826200024e565b90508015620000c157620002b0602090811b62001d8d176001600160401b0390811660c052620002b7821b62001d9417811660e052620002bb90911b62001d98171661010052620000ff565b620002c1602090811b62001d9e176001600160401b0390811660c052620002d7821b62001db317811660e052620002f190911b62001dcc1716610100525b151560a0526001600160a01b039081166080525f80805260016020527fa6eef7e35abe7026729641147f7915573c7e97b47efa546f5f6e3230263bcb4980549285166001600160a01b03199093169290921790915560405181907f5cc365f89543268cb9f25c255f7f610e9147e733c589bc2732279575f125be1490620001a6906020808252600c908201526b1111519055531508131254d560a21b604082015260600190565b60405180910390a26040516001600160a01b038416906001600160781b038316907f9b0894203394c3cbb23140db7a23b224d3e18e0366e9f65bd9c8402650e27367905f90a3604051620001fa9062000307565b604051809103905ff08015801562000214573d5f803e3d5ffd5b506001600160a01b0390811661012052919091166101405250620003829050565b5f696002601e613d5c3d52f35f52600a60165ff0905090565b5f816001600160a01b0316600a5a62000268919062000362565b6040515f8181818686fa925050503d805f8114620002a2576040519150601f19603f3d011682016040523d82523d5f602084013e620002a7565b606091505b50909392505050565b80825d5050565b5c90565b5f815d50565b5f5460ff1615620002d35780825d5050565b9055565b5f805460ff1615620002e857505c90565b5080545b919050565b5f5460ff161562000302575f815d50565b5f9055565b610d07806200407a83390190565b80516001600160a01b0381168114620002ec575f80fd5b5f80604083850312156200033e575f80fd5b620003498362000315565b9150620003596020840162000315565b90509250929050565b5f826200037d57634e487b7160e01b5f52601260045260245ffd5b500490565b60805160a05160c05160e051610100516101205161014051613c67620004135f395f8181611424015281816122b2015281816126fd0152612f7a01525f61032001525f610adb01525f8181610c57015281816124040152818161283901526130cc01525f8181610c8f01528181610e0f01528181610f7c015261243801525f61116701525f6111ce0152613c675ff3fe608060405234801561000f575f80fd5b506004361061031e575f3560e01c806388c1d66d116101a5578063b8dcc68f116100ec578063ddae38f211610095578063e991dc301161006f578063e991dc30146108ec578063ede0fe31146108ff578063fd51f20f146109125761031e565b8063ddae38f214610615578063de02cbb1146108c6578063df5fd29a146108d95761031e565b8063caee23ea116100c6578063caee23ea1461088d578063da0194c0146108a0578063dda964e3146108b35761031e565b8063b8dcc68f14610854578063bf7bfd7e14610867578063c3d58f4d1461087a5761031e565b8063a1cc5cc11161014e578063b6e39ba111610128578063b6e39ba1146107d3578063b70510f5146107e6578063b89c4b0d146108415761031e565b8063a1cc5cc114610755578063a5ce71f514610755578063ae602f44146107685761031e565b80638b6ee8651161017f5780638b6ee865146106c85780638e28800f146106db578063982d03c0146107425761031e565b806388c1d66d1461068f57806389631626146106a257806389a9c855146106b55761031e565b8063317e3e8d116102695780636971082811610212578063755b6fd7116101ec578063755b6fd7146106155780637bac97de146106285780637c1e14b4146104e85761031e565b806369710828146105e75780636bfab91d146105fa5780637423eb3c1461060d5761031e565b80633e5c139d116102435780633e5c139d146105ae57806343999db8146105c157806350793315146105d45761031e565b8063317e3e8d146105215780633a0e3160146105345780633cda743a146105475761031e565b806316a17ce0116102cb578063285fb8c8116102a5578063285fb8c8146104e857806328cc1131146104fb5780632eb0b98a1461050e5761031e565b806316a17ce01461043b5780631854b2411461049657806323c99262146104a95761031e565b80630ad38899116102fc5780630ad38899146103f55780630b6153091461040857806310b5c6a01461041b5761031e565b8063015499301461035f57806301ffc9a714610372578063057497cb1461039a575b7f0000000000000000000000000000000000000000000000000000000000000000365f80375f80365f845af43d5f803e808015610359573d5ff35b3d5ffd5b005b61035d61036d36600461359c565b610925565b61038561038036600461361b565b6109d0565b60405190151581526020015b60405180910390f35b6103856103a836600461367d565b6effffffffffffffffffffffffffffff82165f90815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845260060190915290205460ff1692915050565b61035d6104033660046136ae565b610a93565b61035d61041636600461367d565b610b05565b61042e6104293660046136c7565b610bc4565b60405161039191906136e0565b61038561044936600461367d565b6effffffffffffffffffffffffffffff82165f90815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845260090190915290205460ff1692915050565b61035d6104a4366004613739565b610bf2565b5f546104c89061010090046effffffffffffffffffffffffffffff1681565b6040516effffffffffffffffffffffffffffff9091168152602001610391565b61035d6104f636600461378a565b610bff565b61035d6105093660046137ca565b610c0f565b61035d61051c36600461359c565b610cbe565b61035d61052f366004613807565b610d63565b61035d610542366004613877565b610dcb565b61038561055536600461389f565b73ffffffffffffffffffffffffffffffffffffffff9182165f908152600260209081526040808320546effffffffffffffffffffffffffffff168352600182528083209390941682526003909201909152205460ff1690565b61042e6105bc3660046136ae565b610e3a565b61035d6105cf36600461367d565b610e8b565b61035d6105e236600461389f565b610f1e565b61035d6105f536600461359c565b610fa3565b61035d61060836600461367d565b611047565b61035d61112c565b61035d61062336600461359c565b611254565b61038561063636600461389f565b73ffffffffffffffffffffffffffffffffffffffff9182165f908152600260209081526040808320546effffffffffffffffffffffffffffff168352600182528083209390941682526009909201909152205460ff1690565b61035d61069d36600461367d565b6112f6565b61042e6106b03660046136c7565b6113af565b6103856106c33660046136ae565b6113dd565b61035d6106d63660046136c7565b61148f565b6103856106e936600461389f565b73ffffffffffffffffffffffffffffffffffffffff9182165f908152600260209081526040808320546effffffffffffffffffffffffffffff168352600182528083209390941682526006909201909152205460ff1690565b61042e6107503660046136ae565b61150c565b61035d61076336600461359c565b61155d565b6107ae6107763660046136c7565b6effffffffffffffffffffffffffffff165f9081526001602052604090205473ffffffffffffffffffffffffffffffffffffffff1690565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610391565b61035d6107e1366004613877565b611602565b6103856107f436600461367d565b6effffffffffffffffffffffffffffff82165f90815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845260030190915290205460ff1692915050565b61035d61084f366004613877565b611647565b6104c86108623660046138fe565b61168c565b61035d61087536600461393d565b611796565b61035d61088836600461367d565b611881565b61035d61089b366004613965565b611914565b61035d6108ae3660046139ad565b611920565b61042e6108c13660046136c7565b61192a565b6104c86108d43660046139e5565b611959565b61035d6108e736600461359c565b611b26565b61042e6108fa3660046136ae565b611bc8565b61035d61090d36600461367d565b611c19565b61035d61092036600461367d565b611cd3565b8261092f81611de1565b815f81900361096a576040517f693f369c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6109c9858585808060200260200160405190810160405280939291908181526020018383602002808284375f9201829052506effffffffffffffffffffffffffffff8c168152600160205260409020600701925060029150611e4f9050565b5050505050565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082161580610a4157507fffffffff0000000000000000000000000000000000000000000000000000000082167f751a614900000000000000000000000000000000000000000000000000000000145b80610a8d57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b610a9c81611fa6565b610b027f596a397a0000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff8316175b7f000000000000000000000000000000000000000000000000000000000000000063ffffffff16565b50565b81610b0f81611de1565b6040805160018082528183019092525f916020808301908036833701905050905082815f81518110610b4357610b43613a2c565b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050610bbe848260015f886effffffffffffffffffffffffffffff166effffffffffffffffffffffffffffff1681526020019081526020015f206001015f61202d565b50505050565b6effffffffffffffffffffffffffffff81165f908152600160205260409020606090610a8d9060070161211f565b6109c98585858585612132565b610c0a83838361257d565b505050565b610c1883611fa6565b7f71836d45000000000000000000000000000000000000000000000000000000005f908152601884905260048390526038812090610c798263ffffffff7f000000000000000000000000000000000000000000000000000000000000000016565b90505f610c868483613a86565b9050610cb683827f000000000000000000000000000000000000000000000000000000000000000063ffffffff16565b505050505050565b82610cc881611de1565b815f819003610d03576040517f693f369c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6109c9858585808060200260200160405190810160405280939291908181526020018383602002808284375f9201829052506effffffffffffffffffffffffffffff8c1681526001602081905260409091206004019350915061202d9050565b821580610d6e575081155b80610d765750805b15610dad576040517f7ced84b900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6109c9858560ff166008811115610dc657610dc6613a99565b6129a0565b610dd482611fa6565b7f7e746c61000000000000000000000000000000000000000000000000000000005f9081526018839052600482905260389020610e369060017f000000000000000000000000000000000000000000000000000000000000000063ffffffff16565b5050565b73ffffffffffffffffffffffffffffffffffffffff81165f908152600260209081526040808320546effffffffffffffffffffffffffffff168352600191829052909120606091610a8d910161211f565b81610e9581611de1565b6040805160018082528183019092525f916020808301908036833701905050905082815f81518110610ec957610ec9613a2c565b73ffffffffffffffffffffffffffffffffffffffff9092166020928302919091018201526effffffffffffffffffffffffffffff85165f908152600190915260409020610bbe90859083906007016002611e4f565b610f2781611fa6565b610e367f596a397a0000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff8316178373ffffffffffffffffffffffffffffffffffffffff167f000000000000000000000000000000000000000000000000000000000000000063ffffffff16565b82610fad81611de1565b815f819003610fe8576040517f693f369c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6109c9858585808060200260200160405190810160405280939291908181526020018383602002808284375f9201829052506effffffffffffffffffffffffffffff8c16815260016020526040902060070192506002915061202d9050565b8161105181611de1565b73ffffffffffffffffffffffffffffffffffffffff821661109e576040517f2ba5f16500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6effffffffffffffffffffffffffffff83165f8181526001602052604080822080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff871690811790915590519092917f9b0894203394c3cbb23140db7a23b224d3e18e0366e9f65bd9c8402650e2736791a3505050565b333214611165576040517f2599431400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000008061119257505f5460ff165b156111c9576040517ff45b98b000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6111f27f0000000000000000000000000000000000000000000000000000000000000000612d08565b611228576040517f70a4078f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b8261125e81611de1565b815f819003611299576040517f693f369c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6109c9858585808060200260200160405190810160405280939291908181526020018383602002808284375f9201829052506effffffffffffffffffffffffffffff8c16815260016020819052604082200193509150611e4f9050565b8161130081611de1565b6040805160018082528183019092525f916020808301908036833701905050905082815f8151811061133457611334613a2c565b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050610bbe848260015f886effffffffffffffffffffffffffffff166effffffffffffffffffffffffffffff1681526020019081526020015f206001015f611e4f565b6effffffffffffffffffffffffffffff81165f908152600160205260409020606090610a8d9060040161211f565b6040517f89a9c85500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82811660048301525f917f0000000000000000000000000000000000000000000000000000000000000000909116906389a9c85590602401602060405180830381865afa15801561146b573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a8d9190613ac6565b8061149981611de1565b6effffffffffffffffffffffffffffff82165f8181526001602052604080822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055519091907f9b0894203394c3cbb23140db7a23b224d3e18e0366e9f65bd9c8402650e27367908390a35050565b73ffffffffffffffffffffffffffffffffffffffff81165f908152600260209081526040808320546effffffffffffffffffffffffffffff16835260019091529020606090610a8d9060070161211f565b8261156781611de1565b815f8190036115a2576040517f693f369c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6109c9858585808060200260200160405190810160405280939291908181526020018383602002808284375f9201829052506effffffffffffffffffffffffffffff8c16815260016020819052604090912060040193509150611e4f9050565b61160b82611fa6565b7f71836d45000000000000000000000000000000000000000000000000000000005f9081526018839052600482905260389020610e3690610ad9565b61165082611fa6565b7f7e746c61000000000000000000000000000000000000000000000000000000005f9081526018839052600482905260389020610e3690610ad9565b5f805f600181819054906101000a90046effffffffffffffffffffffffffffff166116b690613ae1565b82546effffffffffffffffffffffffffffff8083166101009490940a848102910219909116179092555f818152600160205260409081902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000163317905551919250907f5cc365f89543268cb9f25c255f7f610e9147e733c589bc2732279575f125be149061174a9087908790613b0e565b60405180910390a260405133906effffffffffffffffffffffffffffff8316907f9b0894203394c3cbb23140db7a23b224d3e18e0366e9f65bd9c8402650e27367905f90a39392505050565b61179f82612d73565b5f546effffffffffffffffffffffffffffff610100909104811690821611156117f4576040517f3fbf501e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff82165f8181526002602052604080822080547fffffffffffffffffffffffffffffffffff000000000000000000000000000000166effffffffffffffffffffffffffffff861690811790915590519092917fa66ff5557b7dc1562bb5e83306e15b513a25aa7537369bce38fc29c20847a79191a35050565b8161188b81611de1565b6040805160018082528183019092525f916020808301908036833701905050905082815f815181106118bf576118bf613a2c565b73ffffffffffffffffffffffffffffffffffffffff9092166020928302919091018201526effffffffffffffffffffffffffffff85165f908152600190915260409020610bbe9085908390600701600261202d565b610bbe84848484612dfa565b610e3682826129a0565b6effffffffffffffffffffffffffffff81165f908152600160208190526040909120606091610a8d910161211f565b5f805f600181819054906101000a90046effffffffffffffffffffffffffffff1661198390613ae1565b91906101000a8154816effffffffffffffffffffffffffffff02191690836effffffffffffffffffffffffffffff16021790559050600181036effffffffffffffffffffffffffffff16836effffffffffffffffffffffffffffff161115611a17576040517f3fbf501e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6effffffffffffffffffffffffffffff8084165f908152600160205260408082209284168083529181902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000163317815590519091907f5cc365f89543268cb9f25c255f7f610e9147e733c589bc2732279575f125be1490611a9e908a908a90613b0e565b60405180910390a260405133906effffffffffffffffffffffffffffff8516907f9b0894203394c3cbb23140db7a23b224d3e18e0366e9f65bd9c8402650e27367905f90a3611af55f848460010184600101613213565b611b086001848460040184600401613213565b611b1b6002848460070184600701613213565b509095945050505050565b82611b3081611de1565b815f819003611b6b576040517f693f369c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6109c9858585808060200260200160405190810160405280939291908181526020018383602002808284375f9201829052506effffffffffffffffffffffffffffff8c1681526001602081905260408220019350915061202d9050565b73ffffffffffffffffffffffffffffffffffffffff81165f908152600260209081526040808320546effffffffffffffffffffffffffffff16835260019091529020606090610a8d9060040161211f565b81611c2381611de1565b6040805160018082528183019092525f916020808301908036833701905050905082815f81518110611c5757611c57613a2c565b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050610bbe848260015f886effffffffffffffffffffffffffffff166effffffffffffffffffffffffffffff1681526020019081526020015f206004016001611e4f565b81611cdd81611de1565b6040805160018082528183019092525f916020808301908036833701905050905082815f81518110611d1157611d11613a2c565b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050610bbe848260015f886effffffffffffffffffffffffffffff166effffffffffffffffffffffffffffff1681526020019081526020015f20600401600161202d565b80825d5050565b5c90565b5f815d50565b5f5460ff1615611daf5780825d5050565b9055565b5f805460ff1615611dc357505c90565b5080545b919050565b5f5460ff1615611ddc575f815d50565b5f9055565b6effffffffffffffffffffffffffffff81165f9081526001602052604090205473ffffffffffffffffffffffffffffffffffffffff163314610b02576040517fd5f2492900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f805b8451811015610cb657848181518110611e6d57611e6d613a2c565b602002602001015191505f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603611edc576040517f8f6e844e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611ee68483613310565b15611f9e578173ffffffffffffffffffffffffffffffffffffffff16866effffffffffffffffffffffffffffff16846002811115611f2657611f26613a99565b6040517fda8f3bd170446760f0f965a9b52bf271cb9679b5e0a70059eff2d49425229d17905f90a473ffffffffffffffffffffffffffffffffffffffff82165f908152600285016020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555b600101611e52565b73ffffffffffffffffffffffffffffffffffffffff81165f908152600260209081526040808320546effffffffffffffffffffffffffffff1683526001825280832033845260030190915290205460ff16610b02576040517feab2f2de00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f805b8451811015610cb65784818151811061204b5761204b613a2c565b602090810291909101015191506120628483613331565b15612117578173ffffffffffffffffffffffffffffffffffffffff16866effffffffffffffffffffffffffffff168460028111156120a2576120a2613a99565b6040517f503012490a650739416858609e898957b874d17415a062945179c57357978840905f90a473ffffffffffffffffffffffffffffffffffffffff82165f908152600285016020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690555b600101612030565b60605f61212b83613352565b9392505050565b335f90815260026020908152604091829020825160c08101845290546effffffffffffffffffffffffffffff8116825260ff6f01000000000000000000000000000000820481161580159484019490945270010000000000000000000000000000000082048116151594830194909452710100000000000000000000000000000000008104841615156060830152720100000000000000000000000000000000000081048416151560808301527301000000000000000000000000000000000000009004909216151560a083015261220a57506109c9565b8060800151156122635773ffffffffffffffffffffffffffffffffffffffff84163b15612263576040517f52245b9800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060a0015115612351576040517f89a9c85500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301527f000000000000000000000000000000000000000000000000000000000000000016906389a9c85590602401602060405180830381865afa1580156122f7573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061231b9190613ac6565b612351576040517fa451bf2a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8473ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff16036123c6578060600151156123c0576040517ff87c961400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b506109c9565b7f71836d45000000000000000000000000000000000000000000000000000000005f90815233601852600484905260388120906124268263ffffffff7f000000000000000000000000000000000000000000000000000000000000000016565b90508381106124675761245f828583037f000000000000000000000000000000000000000000000000000000000000000063ffffffff16565b5050506109c9565b8260400151156124f55782516effffffffffffffffffffffffffffff165f90815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8c16845260090190915290205460ff16156124f0576040517f1de5204e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612573565b82516effffffffffffffffffffffffffffff165f90815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8c16845260060190915290205460ff16612573576040517f1de5204e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050505050565b335f90815260026020908152604091829020825160c08101845290546effffffffffffffffffffffffffffff8116825260ff6f01000000000000000000000000000000820481161580159484019490945270010000000000000000000000000000000082048116151594830194909452710100000000000000000000000000000000008104841615156060830152720100000000000000000000000000000000000081048416151560808301527301000000000000000000000000000000000000009004909216151560a08301526126555750505050565b8060800151156126ae5773ffffffffffffffffffffffffffffffffffffffff82163b156126ae576040517f52245b9800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060a001511561279c576040517f89a9c85500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83811660048301527f000000000000000000000000000000000000000000000000000000000000000016906389a9c85590602401602060405180830381865afa158015612742573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906127669190613ac6565b61279c576040517fa451bf2a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff160361280b57806060015115610bbe576040517ff87c961400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b337f596a397a000000000000000000000000000000000000000000000000000000001761285b8163ffffffff7f000000000000000000000000000000000000000000000000000000000000000016565b73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1603612894575050505050565b8160400151156129225781516effffffffffffffffffffffffffffff165f90815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8916845260090190915290205460ff161561291d576040517f1de5204e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6109c9565b81516effffffffffffffffffffffffffffff165f90815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8916845260060190915290205460ff166109c9576040517f1de5204e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6129a982612d73565b5f8160088111156129bc576129bc613a99565b036129c5575060035b73ffffffffffffffffffffffffffffffffffffffff82165f90815260026020526040902060018260088111156129fd576129fd613a99565b03612a3f5780547fffffffffffffffffffffffff0000000000ffffffffffffffffffffffffffffff166f01000000000000000000000000000000178155612cca565b6002826008811115612a5357612a53613a99565b03612a965780547fffffffffffffffffffffffff0000000000ffffffffffffffffffffffffffffff16700100000000000000000000000000000000178155612cca565b6003826008811115612aaa57612aaa613a99565b03612ada5780547fffffffffffffffffffffffff0000000000ffffffffffffffffffffffffffffff168155612cca565b6004826008811115612aee57612aee613a99565b03612b325780547fffffffffffffffffffffffff0000000000ffffffffffffffffffffffffffffff1671010000000000000000000000000000000000178155612cca565b6005826008811115612b4657612b46613a99565b03612b8b5780547fffffffffffffffffffffffff0000000000ffffffffffffffffffffffffffffff167201000000000000000000000000000000000000178155612cca565b6006826008811115612b9f57612b9f613a99565b03612be55780547fffffffffffffffffffffffff0000000000ffffffffffffffffffffffffffffff16730100000000000000000000000000000000000000178155612cca565b6007826008811115612bf957612bf9613a99565b03612c3e5780547fffffffffffffffffffffffff0000000000ffffffffffffffffffffffffffffff167201010000000000000000000000000000000000178155612cca565b6008826008811115612c5257612c52613a99565b03612c985780547fffffffffffffffffffffffff0000000000ffffffffffffffffffffffffffffff16730100010000000000000000000000000000000000178155612cca565b6040517f5ec600e300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fb39d8f1e6f05413a407e46fc950eb92e9f5b3d65a47c3f0bdc7a2741a6ec0f7d8383604051612cfb929190613b5a565b60405180910390a1505050565b5f8173ffffffffffffffffffffffffffffffffffffffff16600a5a612d2d9190613bb9565b6040515f8181818686fa925050503d805f8114612d65576040519150601f19603f3d011682016040523d82523d5f602084013e612d6a565b606091505b50909392505050565b73ffffffffffffffffffffffffffffffffffffffff81163303612d935750565b612d9c816133ab565b73ffffffffffffffffffffffffffffffffffffffff163303612dbb5750565b612dc4816133d4565b610b02576040517f05b3336400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b335f90815260026020908152604091829020825160c08101845290546effffffffffffffffffffffffffffff8116825260ff6f01000000000000000000000000000000820481161580159484019490945270010000000000000000000000000000000082048116151594830194909452710100000000000000000000000000000000008104841615156060830152720100000000000000000000000000000000000081048416151560808301527301000000000000000000000000000000000000009004909216151560a0830152612ed25750610bbe565b806080015115612f2b5773ffffffffffffffffffffffffffffffffffffffff83163b15612f2b576040517f52245b9800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060a0015115613019576040517f89a9c85500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301527f000000000000000000000000000000000000000000000000000000000000000016906389a9c85590602401602060405180830381865afa158015612fbf573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612fe39190613ac6565b613019576040517fa451bf2a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff160361308e57806060015115613088576040517ff87c961400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50610bbe565b7f7e746c61000000000000000000000000000000000000000000000000000000005f90815233601852600483905260388120906130ee8263ffffffff7f000000000000000000000000000000000000000000000000000000000000000016565b905080156130fe57505050610bbe565b82604001511561318c5782516effffffffffffffffffffffffffffff165f90815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8b16845260090190915290205460ff1615613187576040517f1de5204e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61320a565b82516effffffffffffffffffffffffffffff165f90815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8b16845260060190915290205460ff1661320a576040517f1de5204e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050505050565b8181600281015f61322384613415565b90505f805b828110156133045761323a868261341e565b91506132468583613310565b156132fc578173ffffffffffffffffffffffffffffffffffffffff16896effffffffffffffffffffffffffffff168b600281111561328657613286613a99565b6040517fda8f3bd170446760f0f965a9b52bf271cb9679b5e0a70059eff2d49425229d17905f90a473ffffffffffffffffffffffffffffffffffffffff82165f90815260208590526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555b600101613228565b50505050505050505050565b5f61212b8373ffffffffffffffffffffffffffffffffffffffff8416613429565b5f61212b8373ffffffffffffffffffffffffffffffffffffffff8416613475565b6060815f0180548060200260200160405190810160405280929190818152602001828054801561339f57602002820191905f5260205f20905b81548152602001906001019080831161338b575b50505050509050919050565b5f638da5cb5b5f5260205f6004601c855afa8060203d101516156133ce575f5191505b50919050565b5f604051606081016040526391d1485481525f816020015233816040015260205f6044601c8401865afa90508060203d101516156133ce5750505f51919050565b5f610a8d825490565b5f61212b8383613558565b5f81815260018301602052604081205461346e57508154600181810184555f848152602080822090930184905584548482528286019093526040902091909155610a8d565b505f610a8d565b5f818152600183016020526040812054801561354f575f613497600183613bf1565b85549091505f906134aa90600190613bf1565b9050818114613509575f865f0182815481106134c8576134c8613a2c565b905f5260205f200154905080875f0184815481106134e8576134e8613a2c565b5f918252602080832090910192909255918252600188019052604090208390555b855486908061351a5761351a613c04565b600190038181905f5260205f20015f90559055856001015f8681526020019081526020015f205f905560019350505050610a8d565b5f915050610a8d565b5f825f01828154811061356d5761356d613a2c565b905f5260205f200154905092915050565b80356effffffffffffffffffffffffffffff81168114611dc7575f80fd5b5f805f604084860312156135ae575f80fd5b6135b78461357e565b9250602084013567ffffffffffffffff808211156135d3575f80fd5b818601915086601f8301126135e6575f80fd5b8135818111156135f4575f80fd5b8760208260051b8501011115613608575f80fd5b6020830194508093505050509250925092565b5f6020828403121561362b575f80fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461212b575f80fd5b803573ffffffffffffffffffffffffffffffffffffffff81168114611dc7575f80fd5b5f806040838503121561368e575f80fd5b6136978361357e565b91506136a56020840161365a565b90509250929050565b5f602082840312156136be575f80fd5b61212b8261365a565b5f602082840312156136d7575f80fd5b61212b8261357e565b602080825282518282018190525f9190848201906040850190845b8181101561372d57835173ffffffffffffffffffffffffffffffffffffffff16835292840192918401916001016136fb565b50909695505050505050565b5f805f805f60a0868803121561374d575f80fd5b6137568661365a565b94506137646020870161365a565b93506137726040870161365a565b94979396509394606081013594506080013592915050565b5f805f6060848603121561379c575f80fd5b6137a58461365a565b92506137b36020850161365a565b91506137c16040850161365a565b90509250925092565b5f805f606084860312156137dc575f80fd5b6137e58461365a565b95602085013595506040909401359392505050565b8015158114610b02575f80fd5b5f805f805f60a0868803121561381b575f80fd5b6138248661365a565b9450602086013560ff81168114613839575f80fd5b93506040860135613849816137fa565b92506060860135613859816137fa565b91506080860135613869816137fa565b809150509295509295909350565b5f8060408385031215613888575f80fd5b6138918361365a565b946020939093013593505050565b5f80604083850312156138b0575f80fd5b6136978361365a565b5f8083601f8401126138c9575f80fd5b50813567ffffffffffffffff8111156138e0575f80fd5b6020830191508360208285010111156138f7575f80fd5b9250929050565b5f806020838503121561390f575f80fd5b823567ffffffffffffffff811115613925575f80fd5b613931858286016138b9565b90969095509350505050565b5f806040838503121561394e575f80fd5b6139578361365a565b91506136a56020840161357e565b5f805f8060808587031215613978575f80fd5b6139818561365a565b935061398f6020860161365a565b925061399d6040860161365a565b9396929550929360600135925050565b5f80604083850312156139be575f80fd5b6139c78361365a565b91506020830135600981106139da575f80fd5b809150509250929050565b5f805f604084860312156139f7575f80fd5b833567ffffffffffffffff811115613a0d575f80fd5b613a19868287016138b9565b90945092506137c190506020850161357e565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b80820180821115610a8d57610a8d613a59565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b5f60208284031215613ad6575f80fd5b815161212b816137fa565b5f6effffffffffffffffffffffffffffff808316818103613b0457613b04613a59565b6001019392505050565b60208152816020820152818360408301375f818301604090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160101919050565b73ffffffffffffffffffffffffffffffffffffffff831681526040810160098310613bac577f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b8260208301529392505050565b5f82613bec577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b81810381811115610a8d57610a8d613a59565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603160045260245ffdfea2646970667358221220160996c94b1d698a40469e3f97911dd81a027efec7d78941305ede91222dd7d864736f6c6343000818003361012060405234801562000011575f80fd5b505f6200001d620000f4565b90506001600160a01b0381166200004757604051632aea588760e01b815260040160405180910390fd5b5f62000053826200010d565b905080156200009f576200016f602090811b62000678176001600160401b0390811660c05262000176821b6200067f17811660e0526200017a90911b62000683171661010052620000dd565b62000180602090811b62000689176001600160401b0390811660c05262000196821b6200069e17811660e052620001ac90911b620006b71716610100525b151560a0526001600160a01b0316608052620001e2565b5f696002601e613d5c3d52f35f52600a60165ff0905090565b5f816001600160a01b0316600a5a620001279190620001c2565b6040515f8181818686fa925050503d805f811462000161576040519150601f19603f3d011682016040523d82523d5f602084013e62000166565b606091505b50909392505050565b80825d5050565b5c90565b5f815d50565b5f5460ff1615620001925780825d5050565b9055565b5f805460ff1615620001a757505c90565b505490565b5f5460ff1615620001bd575f815d50565b5f9055565b5f82620001dd57634e487b7160e01b5f52601260045260245ffd5b500490565b60805160a05160c05160e05161010051610af0620002175f395f50505f50505f50505f6103f501525f61045c0152610af05ff3fe608060405234801561000f575f80fd5b5060043610610180575f3560e01c80637bac97de116100d6578063982d03c01161008a578063d415f62f11610064578063d415f62f146102a2578063d72dde5e146101b2578063e991dc301461037357610180565b8063982d03c014610345578063b67d8f9914610273578063b95545521461035357610180565b80638e28800f116100bb5780638e28800f146102c85780639340a7cc146102585780639445f5301461032f57610180565b80637bac97de146102ba578063896316261461028157610180565b80632c7fe70a116101385780635e17263d116101125780635e17263d146102a25780637161ac8d146102945780637423eb3c146102b057610180565b80632c7fe70a146102735780633fe5df99146102815780634c9d0b451461029457610180565b806316a17ce01161016957806316a17ce01461024357806316f18d741461025857806317e94a6c1461022257610180565b8063057497cb146101b257806310b5c6a014610222575b6040517f89452af100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61020d6101c0366004610895565b6effffffffffffffffffffffffffffff82165f90815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845260060190915290205460ff1692915050565b60405190151581526020015b60405180910390f35b6102366102303660046108c6565b50606090565b60405161021991906108df565b61020d610251366004610895565b5f92915050565b610266610230366004610938565b6040516102199190610951565b61020d610251366004610988565b61023661028f3660046108c6565b610386565b6102666102303660046108c6565b61020d6102513660046109b0565b6102b86103ba565b005b61020d6102513660046109ca565b61020d6102d63660046109ca565b73ffffffffffffffffffffffffffffffffffffffff9182165f908152600260209081526040808320546effffffffffffffffffffffffffffff168352600182528083209390941682526006909201909152205460ff1690565b61020d61033d366004610895565b600192915050565b610236610230366004610938565b610366610361366004610938565b6104e2565b6040516102199190610a11565b610236610381366004610938565b610627565b6effffffffffffffffffffffffffffff81165f9081526001602052604090206060906103b4906004016106cc565b92915050565b3332146103f3576040517f2599431400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000008061042057505f5460ff165b15610457576040517ff45b98b000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6104807f00000000000000000000000000000000000000000000000000000000000000006106df565b6104b6576040517f70a4078f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b60408051606080820183525f808352602080840182905283850182905273ffffffffffffffffffffffffffffffffffffffff861682526002815290849020845160c08101865290546effffffffffffffffffffffffffffff8116825260ff6f0100000000000000000000000000000082048116151593830193909352700100000000000000000000000000000000810483161515828701527101000000000000000000000000000000000081048316151582850152720100000000000000000000000000000000000081048316151560808301527301000000000000000000000000000000000000009004909116151560a08201528351918201909352909190806105ec8361074a565b60088111156105fd576105fd6109e4565b815291516effffffffffffffffffffffffffffff1660208301525f60409092019190915292915050565b73ffffffffffffffffffffffffffffffffffffffff81165f908152600260209081526040808320546effffffffffffffffffffffffffffff168352600190915290206060906103b4906004016106cc565b80825d5050565b5c90565b5f815d50565b5f5460ff161561069a5780825d5050565b9055565b5f805460ff16156106ae57505c90565b5080545b919050565b5f5460ff16156106c7575f815d50565b5f9055565b60605f6106d8836107fb565b9392505050565b5f8173ffffffffffffffffffffffffffffffffffffffff16600a5a6107049190610a82565b6040515f8181818686fa925050503d805f811461073c576040519150601f19603f3d011682016040523d82523d5f602084013e610741565b606091505b50909392505050565b602081015160408201516060830151608084015160a08501515f9493929190841561077c575060019695505050505050565b831561078f575060029695505050505050565b82156107c85780156107a8575060089695505050505050565b81156107bb575060079695505050505050565b5060049695505050505050565b80156107db575060069695505050505050565b81156107ee575060059695505050505050565b5060039695505050505050565b6060815f0180548060200260200160405190810160405280929190818152602001828054801561084857602002820191905f5260205f20905b815481526020019060010190808311610834575b50505050509050919050565b80356effffffffffffffffffffffffffffff811681146106b2575f80fd5b803573ffffffffffffffffffffffffffffffffffffffff811681146106b2575f80fd5b5f80604083850312156108a6575f80fd5b6108af83610854565b91506108bd60208401610872565b90509250929050565b5f602082840312156108d6575f80fd5b6106d882610854565b602080825282518282018190525f9190848201906040850190845b8181101561092c57835173ffffffffffffffffffffffffffffffffffffffff16835292840192918401916001016108fa565b50909695505050505050565b5f60208284031215610948575f80fd5b6106d882610872565b602080825282518282018190525f9190848201906040850190845b8181101561092c5783518352928401929184019160010161096c565b5f8060408385031215610999575f80fd5b6109a283610872565b946020939093013593505050565b5f80604083850312156109c1575f80fd5b6109a283610854565b5f80604083850312156109db575f80fd5b6108af83610872565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b8151606082019060098110610a4d577f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b8083525060208301516effffffffffffffffffffffffffffff8082166020850152806040860151166040850152505092915050565b5f82610ab5577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b50049056fea2646970667358221220c104b63905a188c6b1e795f6018b36d9c876d6bd4f6ea96593fb37a009e87c1c64736f6c634300081800330000000000000000000000000000000000a1793068b5b7e278de7c641e9e75c8000000000000000000000000721c00182a990771244d7a71b9fa2ea789a3b433

Deployed Bytecode

0x608060405234801561000f575f80fd5b506004361061031e575f3560e01c806388c1d66d116101a5578063b8dcc68f116100ec578063ddae38f211610095578063e991dc301161006f578063e991dc30146108ec578063ede0fe31146108ff578063fd51f20f146109125761031e565b8063ddae38f214610615578063de02cbb1146108c6578063df5fd29a146108d95761031e565b8063caee23ea116100c6578063caee23ea1461088d578063da0194c0146108a0578063dda964e3146108b35761031e565b8063b8dcc68f14610854578063bf7bfd7e14610867578063c3d58f4d1461087a5761031e565b8063a1cc5cc11161014e578063b6e39ba111610128578063b6e39ba1146107d3578063b70510f5146107e6578063b89c4b0d146108415761031e565b8063a1cc5cc114610755578063a5ce71f514610755578063ae602f44146107685761031e565b80638b6ee8651161017f5780638b6ee865146106c85780638e28800f146106db578063982d03c0146107425761031e565b806388c1d66d1461068f57806389631626146106a257806389a9c855146106b55761031e565b8063317e3e8d116102695780636971082811610212578063755b6fd7116101ec578063755b6fd7146106155780637bac97de146106285780637c1e14b4146104e85761031e565b806369710828146105e75780636bfab91d146105fa5780637423eb3c1461060d5761031e565b80633e5c139d116102435780633e5c139d146105ae57806343999db8146105c157806350793315146105d45761031e565b8063317e3e8d146105215780633a0e3160146105345780633cda743a146105475761031e565b806316a17ce0116102cb578063285fb8c8116102a5578063285fb8c8146104e857806328cc1131146104fb5780632eb0b98a1461050e5761031e565b806316a17ce01461043b5780631854b2411461049657806323c99262146104a95761031e565b80630ad38899116102fc5780630ad38899146103f55780630b6153091461040857806310b5c6a01461041b5761031e565b8063015499301461035f57806301ffc9a714610372578063057497cb1461039a575b7f0000000000000000000000001fca38fd099c7701b4f28fbc3f0ba57ed4067137365f80375f80365f845af43d5f803e808015610359573d5ff35b3d5ffd5b005b61035d61036d36600461359c565b610925565b61038561038036600461361b565b6109d0565b60405190151581526020015b60405180910390f35b6103856103a836600461367d565b6effffffffffffffffffffffffffffff82165f90815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845260060190915290205460ff1692915050565b61035d6104033660046136ae565b610a93565b61035d61041636600461367d565b610b05565b61042e6104293660046136c7565b610bc4565b60405161039191906136e0565b61038561044936600461367d565b6effffffffffffffffffffffffffffff82165f90815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845260090190915290205460ff1692915050565b61035d6104a4366004613739565b610bf2565b5f546104c89061010090046effffffffffffffffffffffffffffff1681565b6040516effffffffffffffffffffffffffffff9091168152602001610391565b61035d6104f636600461378a565b610bff565b61035d6105093660046137ca565b610c0f565b61035d61051c36600461359c565b610cbe565b61035d61052f366004613807565b610d63565b61035d610542366004613877565b610dcb565b61038561055536600461389f565b73ffffffffffffffffffffffffffffffffffffffff9182165f908152600260209081526040808320546effffffffffffffffffffffffffffff168352600182528083209390941682526003909201909152205460ff1690565b61042e6105bc3660046136ae565b610e3a565b61035d6105cf36600461367d565b610e8b565b61035d6105e236600461389f565b610f1e565b61035d6105f536600461359c565b610fa3565b61035d61060836600461367d565b611047565b61035d61112c565b61035d61062336600461359c565b611254565b61038561063636600461389f565b73ffffffffffffffffffffffffffffffffffffffff9182165f908152600260209081526040808320546effffffffffffffffffffffffffffff168352600182528083209390941682526009909201909152205460ff1690565b61035d61069d36600461367d565b6112f6565b61042e6106b03660046136c7565b6113af565b6103856106c33660046136ae565b6113dd565b61035d6106d63660046136c7565b61148f565b6103856106e936600461389f565b73ffffffffffffffffffffffffffffffffffffffff9182165f908152600260209081526040808320546effffffffffffffffffffffffffffff168352600182528083209390941682526006909201909152205460ff1690565b61042e6107503660046136ae565b61150c565b61035d61076336600461359c565b61155d565b6107ae6107763660046136c7565b6effffffffffffffffffffffffffffff165f9081526001602052604090205473ffffffffffffffffffffffffffffffffffffffff1690565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610391565b61035d6107e1366004613877565b611602565b6103856107f436600461367d565b6effffffffffffffffffffffffffffff82165f90815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845260030190915290205460ff1692915050565b61035d61084f366004613877565b611647565b6104c86108623660046138fe565b61168c565b61035d61087536600461393d565b611796565b61035d61088836600461367d565b611881565b61035d61089b366004613965565b611914565b61035d6108ae3660046139ad565b611920565b61042e6108c13660046136c7565b61192a565b6104c86108d43660046139e5565b611959565b61035d6108e736600461359c565b611b26565b61042e6108fa3660046136ae565b611bc8565b61035d61090d36600461367d565b611c19565b61035d61092036600461367d565b611cd3565b8261092f81611de1565b815f81900361096a576040517f693f369c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6109c9858585808060200260200160405190810160405280939291908181526020018383602002808284375f9201829052506effffffffffffffffffffffffffffff8c168152600160205260409020600701925060029150611e4f9050565b5050505050565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082161580610a4157507fffffffff0000000000000000000000000000000000000000000000000000000082167f751a614900000000000000000000000000000000000000000000000000000000145b80610a8d57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b610a9c81611fa6565b610b027f596a397a0000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff8316175b7f000000000000000000000000000000000000000000000000000002bb00001d9863ffffffff16565b50565b81610b0f81611de1565b6040805160018082528183019092525f916020808301908036833701905050905082815f81518110610b4357610b43613a2c565b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050610bbe848260015f886effffffffffffffffffffffffffffff166effffffffffffffffffffffffffffff1681526020019081526020015f206001015f61202d565b50505050565b6effffffffffffffffffffffffffffff81165f908152600160205260409020606090610a8d9060070161211f565b6109c98585858585612132565b610c0a83838361257d565b505050565b610c1883611fa6565b7f71836d45000000000000000000000000000000000000000000000000000000005f908152601884905260048390526038812090610c798263ffffffff7f000000000000000000000000000000000000000000000000000002b700001d9416565b90505f610c868483613a86565b9050610cb683827f000000000000000000000000000000000000000000000000000002b000001d8d63ffffffff16565b505050505050565b82610cc881611de1565b815f819003610d03576040517f693f369c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6109c9858585808060200260200160405190810160405280939291908181526020018383602002808284375f9201829052506effffffffffffffffffffffffffffff8c1681526001602081905260409091206004019350915061202d9050565b821580610d6e575081155b80610d765750805b15610dad576040517f7ced84b900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6109c9858560ff166008811115610dc657610dc6613a99565b6129a0565b610dd482611fa6565b7f7e746c61000000000000000000000000000000000000000000000000000000005f9081526018839052600482905260389020610e369060017f000000000000000000000000000000000000000000000000000002b000001d8d63ffffffff16565b5050565b73ffffffffffffffffffffffffffffffffffffffff81165f908152600260209081526040808320546effffffffffffffffffffffffffffff168352600191829052909120606091610a8d910161211f565b81610e9581611de1565b6040805160018082528183019092525f916020808301908036833701905050905082815f81518110610ec957610ec9613a2c565b73ffffffffffffffffffffffffffffffffffffffff9092166020928302919091018201526effffffffffffffffffffffffffffff85165f908152600190915260409020610bbe90859083906007016002611e4f565b610f2781611fa6565b610e367f596a397a0000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff8316178373ffffffffffffffffffffffffffffffffffffffff167f000000000000000000000000000000000000000000000000000002b000001d8d63ffffffff16565b82610fad81611de1565b815f819003610fe8576040517f693f369c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6109c9858585808060200260200160405190810160405280939291908181526020018383602002808284375f9201829052506effffffffffffffffffffffffffffff8c16815260016020526040902060070192506002915061202d9050565b8161105181611de1565b73ffffffffffffffffffffffffffffffffffffffff821661109e576040517f2ba5f16500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6effffffffffffffffffffffffffffff83165f8181526001602052604080822080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff871690811790915590519092917f9b0894203394c3cbb23140db7a23b224d3e18e0366e9f65bd9c8402650e2736791a3505050565b333214611165576040517f2599431400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000018061119257505f5460ff165b156111c9576040517ff45b98b000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6111f27f000000000000000000000000bb0bffd7f8ef12ecaa0435aef8a7bd522798251c612d08565b611228576040517f70a4078f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b8261125e81611de1565b815f819003611299576040517f693f369c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6109c9858585808060200260200160405190810160405280939291908181526020018383602002808284375f9201829052506effffffffffffffffffffffffffffff8c16815260016020819052604082200193509150611e4f9050565b8161130081611de1565b6040805160018082528183019092525f916020808301908036833701905050905082815f8151811061133457611334613a2c565b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050610bbe848260015f886effffffffffffffffffffffffffffff166effffffffffffffffffffffffffffff1681526020019081526020015f206001015f611e4f565b6effffffffffffffffffffffffffffff81165f908152600160205260409020606090610a8d9060040161211f565b6040517f89a9c85500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82811660048301525f917f000000000000000000000000721c00182a990771244d7a71b9fa2ea789a3b433909116906389a9c85590602401602060405180830381865afa15801561146b573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a8d9190613ac6565b8061149981611de1565b6effffffffffffffffffffffffffffff82165f8181526001602052604080822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055519091907f9b0894203394c3cbb23140db7a23b224d3e18e0366e9f65bd9c8402650e27367908390a35050565b73ffffffffffffffffffffffffffffffffffffffff81165f908152600260209081526040808320546effffffffffffffffffffffffffffff16835260019091529020606090610a8d9060070161211f565b8261156781611de1565b815f8190036115a2576040517f693f369c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6109c9858585808060200260200160405190810160405280939291908181526020018383602002808284375f9201829052506effffffffffffffffffffffffffffff8c16815260016020819052604090912060040193509150611e4f9050565b61160b82611fa6565b7f71836d45000000000000000000000000000000000000000000000000000000005f9081526018839052600482905260389020610e3690610ad9565b61165082611fa6565b7f7e746c61000000000000000000000000000000000000000000000000000000005f9081526018839052600482905260389020610e3690610ad9565b5f805f600181819054906101000a90046effffffffffffffffffffffffffffff166116b690613ae1565b82546effffffffffffffffffffffffffffff8083166101009490940a848102910219909116179092555f818152600160205260409081902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000163317905551919250907f5cc365f89543268cb9f25c255f7f610e9147e733c589bc2732279575f125be149061174a9087908790613b0e565b60405180910390a260405133906effffffffffffffffffffffffffffff8316907f9b0894203394c3cbb23140db7a23b224d3e18e0366e9f65bd9c8402650e27367905f90a39392505050565b61179f82612d73565b5f546effffffffffffffffffffffffffffff610100909104811690821611156117f4576040517f3fbf501e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff82165f8181526002602052604080822080547fffffffffffffffffffffffffffffffffff000000000000000000000000000000166effffffffffffffffffffffffffffff861690811790915590519092917fa66ff5557b7dc1562bb5e83306e15b513a25aa7537369bce38fc29c20847a79191a35050565b8161188b81611de1565b6040805160018082528183019092525f916020808301908036833701905050905082815f815181106118bf576118bf613a2c565b73ffffffffffffffffffffffffffffffffffffffff9092166020928302919091018201526effffffffffffffffffffffffffffff85165f908152600190915260409020610bbe9085908390600701600261202d565b610bbe84848484612dfa565b610e3682826129a0565b6effffffffffffffffffffffffffffff81165f908152600160208190526040909120606091610a8d910161211f565b5f805f600181819054906101000a90046effffffffffffffffffffffffffffff1661198390613ae1565b91906101000a8154816effffffffffffffffffffffffffffff02191690836effffffffffffffffffffffffffffff16021790559050600181036effffffffffffffffffffffffffffff16836effffffffffffffffffffffffffffff161115611a17576040517f3fbf501e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6effffffffffffffffffffffffffffff8084165f908152600160205260408082209284168083529181902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000163317815590519091907f5cc365f89543268cb9f25c255f7f610e9147e733c589bc2732279575f125be1490611a9e908a908a90613b0e565b60405180910390a260405133906effffffffffffffffffffffffffffff8516907f9b0894203394c3cbb23140db7a23b224d3e18e0366e9f65bd9c8402650e27367905f90a3611af55f848460010184600101613213565b611b086001848460040184600401613213565b611b1b6002848460070184600701613213565b509095945050505050565b82611b3081611de1565b815f819003611b6b576040517f693f369c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6109c9858585808060200260200160405190810160405280939291908181526020018383602002808284375f9201829052506effffffffffffffffffffffffffffff8c1681526001602081905260408220019350915061202d9050565b73ffffffffffffffffffffffffffffffffffffffff81165f908152600260209081526040808320546effffffffffffffffffffffffffffff16835260019091529020606090610a8d9060040161211f565b81611c2381611de1565b6040805160018082528183019092525f916020808301908036833701905050905082815f81518110611c5757611c57613a2c565b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050610bbe848260015f886effffffffffffffffffffffffffffff166effffffffffffffffffffffffffffff1681526020019081526020015f206004016001611e4f565b81611cdd81611de1565b6040805160018082528183019092525f916020808301908036833701905050905082815f81518110611d1157611d11613a2c565b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050610bbe848260015f886effffffffffffffffffffffffffffff166effffffffffffffffffffffffffffff1681526020019081526020015f20600401600161202d565b80825d5050565b5c90565b5f815d50565b5f5460ff1615611daf5780825d5050565b9055565b5f805460ff1615611dc357505c90565b5080545b919050565b5f5460ff1615611ddc575f815d50565b5f9055565b6effffffffffffffffffffffffffffff81165f9081526001602052604090205473ffffffffffffffffffffffffffffffffffffffff163314610b02576040517fd5f2492900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f805b8451811015610cb657848181518110611e6d57611e6d613a2c565b602002602001015191505f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603611edc576040517f8f6e844e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611ee68483613310565b15611f9e578173ffffffffffffffffffffffffffffffffffffffff16866effffffffffffffffffffffffffffff16846002811115611f2657611f26613a99565b6040517fda8f3bd170446760f0f965a9b52bf271cb9679b5e0a70059eff2d49425229d17905f90a473ffffffffffffffffffffffffffffffffffffffff82165f908152600285016020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555b600101611e52565b73ffffffffffffffffffffffffffffffffffffffff81165f908152600260209081526040808320546effffffffffffffffffffffffffffff1683526001825280832033845260030190915290205460ff16610b02576040517feab2f2de00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f805b8451811015610cb65784818151811061204b5761204b613a2c565b602090810291909101015191506120628483613331565b15612117578173ffffffffffffffffffffffffffffffffffffffff16866effffffffffffffffffffffffffffff168460028111156120a2576120a2613a99565b6040517f503012490a650739416858609e898957b874d17415a062945179c57357978840905f90a473ffffffffffffffffffffffffffffffffffffffff82165f908152600285016020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690555b600101612030565b60605f61212b83613352565b9392505050565b335f90815260026020908152604091829020825160c08101845290546effffffffffffffffffffffffffffff8116825260ff6f01000000000000000000000000000000820481161580159484019490945270010000000000000000000000000000000082048116151594830194909452710100000000000000000000000000000000008104841615156060830152720100000000000000000000000000000000000081048416151560808301527301000000000000000000000000000000000000009004909216151560a083015261220a57506109c9565b8060800151156122635773ffffffffffffffffffffffffffffffffffffffff84163b15612263576040517f52245b9800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060a0015115612351576040517f89a9c85500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301527f000000000000000000000000721c00182a990771244d7a71b9fa2ea789a3b43316906389a9c85590602401602060405180830381865afa1580156122f7573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061231b9190613ac6565b612351576040517fa451bf2a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8473ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff16036123c6578060600151156123c0576040517ff87c961400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b506109c9565b7f71836d45000000000000000000000000000000000000000000000000000000005f90815233601852600484905260388120906124268263ffffffff7f000000000000000000000000000000000000000000000000000002b700001d9416565b90508381106124675761245f828583037f000000000000000000000000000000000000000000000000000002b000001d8d63ffffffff16565b5050506109c9565b8260400151156124f55782516effffffffffffffffffffffffffffff165f90815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8c16845260090190915290205460ff16156124f0576040517f1de5204e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612573565b82516effffffffffffffffffffffffffffff165f90815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8c16845260060190915290205460ff16612573576040517f1de5204e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050505050565b335f90815260026020908152604091829020825160c08101845290546effffffffffffffffffffffffffffff8116825260ff6f01000000000000000000000000000000820481161580159484019490945270010000000000000000000000000000000082048116151594830194909452710100000000000000000000000000000000008104841615156060830152720100000000000000000000000000000000000081048416151560808301527301000000000000000000000000000000000000009004909216151560a08301526126555750505050565b8060800151156126ae5773ffffffffffffffffffffffffffffffffffffffff82163b156126ae576040517f52245b9800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060a001511561279c576040517f89a9c85500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83811660048301527f000000000000000000000000721c00182a990771244d7a71b9fa2ea789a3b43316906389a9c85590602401602060405180830381865afa158015612742573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906127669190613ac6565b61279c576040517fa451bf2a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff160361280b57806060015115610bbe576040517ff87c961400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b337f596a397a000000000000000000000000000000000000000000000000000000001761285b8163ffffffff7f000000000000000000000000000000000000000000000000000002b700001d9416565b73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1603612894575050505050565b8160400151156129225781516effffffffffffffffffffffffffffff165f90815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8916845260090190915290205460ff161561291d576040517f1de5204e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6109c9565b81516effffffffffffffffffffffffffffff165f90815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8916845260060190915290205460ff166109c9576040517f1de5204e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6129a982612d73565b5f8160088111156129bc576129bc613a99565b036129c5575060035b73ffffffffffffffffffffffffffffffffffffffff82165f90815260026020526040902060018260088111156129fd576129fd613a99565b03612a3f5780547fffffffffffffffffffffffff0000000000ffffffffffffffffffffffffffffff166f01000000000000000000000000000000178155612cca565b6002826008811115612a5357612a53613a99565b03612a965780547fffffffffffffffffffffffff0000000000ffffffffffffffffffffffffffffff16700100000000000000000000000000000000178155612cca565b6003826008811115612aaa57612aaa613a99565b03612ada5780547fffffffffffffffffffffffff0000000000ffffffffffffffffffffffffffffff168155612cca565b6004826008811115612aee57612aee613a99565b03612b325780547fffffffffffffffffffffffff0000000000ffffffffffffffffffffffffffffff1671010000000000000000000000000000000000178155612cca565b6005826008811115612b4657612b46613a99565b03612b8b5780547fffffffffffffffffffffffff0000000000ffffffffffffffffffffffffffffff167201000000000000000000000000000000000000178155612cca565b6006826008811115612b9f57612b9f613a99565b03612be55780547fffffffffffffffffffffffff0000000000ffffffffffffffffffffffffffffff16730100000000000000000000000000000000000000178155612cca565b6007826008811115612bf957612bf9613a99565b03612c3e5780547fffffffffffffffffffffffff0000000000ffffffffffffffffffffffffffffff167201010000000000000000000000000000000000178155612cca565b6008826008811115612c5257612c52613a99565b03612c985780547fffffffffffffffffffffffff0000000000ffffffffffffffffffffffffffffff16730100010000000000000000000000000000000000178155612cca565b6040517f5ec600e300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fb39d8f1e6f05413a407e46fc950eb92e9f5b3d65a47c3f0bdc7a2741a6ec0f7d8383604051612cfb929190613b5a565b60405180910390a1505050565b5f8173ffffffffffffffffffffffffffffffffffffffff16600a5a612d2d9190613bb9565b6040515f8181818686fa925050503d805f8114612d65576040519150601f19603f3d011682016040523d82523d5f602084013e612d6a565b606091505b50909392505050565b73ffffffffffffffffffffffffffffffffffffffff81163303612d935750565b612d9c816133ab565b73ffffffffffffffffffffffffffffffffffffffff163303612dbb5750565b612dc4816133d4565b610b02576040517f05b3336400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b335f90815260026020908152604091829020825160c08101845290546effffffffffffffffffffffffffffff8116825260ff6f01000000000000000000000000000000820481161580159484019490945270010000000000000000000000000000000082048116151594830194909452710100000000000000000000000000000000008104841615156060830152720100000000000000000000000000000000000081048416151560808301527301000000000000000000000000000000000000009004909216151560a0830152612ed25750610bbe565b806080015115612f2b5773ffffffffffffffffffffffffffffffffffffffff83163b15612f2b576040517f52245b9800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060a0015115613019576040517f89a9c85500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301527f000000000000000000000000721c00182a990771244d7a71b9fa2ea789a3b43316906389a9c85590602401602060405180830381865afa158015612fbf573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612fe39190613ac6565b613019576040517fa451bf2a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff160361308e57806060015115613088576040517ff87c961400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50610bbe565b7f7e746c61000000000000000000000000000000000000000000000000000000005f90815233601852600483905260388120906130ee8263ffffffff7f000000000000000000000000000000000000000000000000000002b700001d9416565b905080156130fe57505050610bbe565b82604001511561318c5782516effffffffffffffffffffffffffffff165f90815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8b16845260090190915290205460ff1615613187576040517f1de5204e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61320a565b82516effffffffffffffffffffffffffffff165f90815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8b16845260060190915290205460ff1661320a576040517f1de5204e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050505050565b8181600281015f61322384613415565b90505f805b828110156133045761323a868261341e565b91506132468583613310565b156132fc578173ffffffffffffffffffffffffffffffffffffffff16896effffffffffffffffffffffffffffff168b600281111561328657613286613a99565b6040517fda8f3bd170446760f0f965a9b52bf271cb9679b5e0a70059eff2d49425229d17905f90a473ffffffffffffffffffffffffffffffffffffffff82165f90815260208590526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555b600101613228565b50505050505050505050565b5f61212b8373ffffffffffffffffffffffffffffffffffffffff8416613429565b5f61212b8373ffffffffffffffffffffffffffffffffffffffff8416613475565b6060815f0180548060200260200160405190810160405280929190818152602001828054801561339f57602002820191905f5260205f20905b81548152602001906001019080831161338b575b50505050509050919050565b5f638da5cb5b5f5260205f6004601c855afa8060203d101516156133ce575f5191505b50919050565b5f604051606081016040526391d1485481525f816020015233816040015260205f6044601c8401865afa90508060203d101516156133ce5750505f51919050565b5f610a8d825490565b5f61212b8383613558565b5f81815260018301602052604081205461346e57508154600181810184555f848152602080822090930184905584548482528286019093526040902091909155610a8d565b505f610a8d565b5f818152600183016020526040812054801561354f575f613497600183613bf1565b85549091505f906134aa90600190613bf1565b9050818114613509575f865f0182815481106134c8576134c8613a2c565b905f5260205f200154905080875f0184815481106134e8576134e8613a2c565b5f918252602080832090910192909255918252600188019052604090208390555b855486908061351a5761351a613c04565b600190038181905f5260205f20015f90559055856001015f8681526020019081526020015f205f905560019350505050610a8d565b5f915050610a8d565b5f825f01828154811061356d5761356d613a2c565b905f5260205f200154905092915050565b80356effffffffffffffffffffffffffffff81168114611dc7575f80fd5b5f805f604084860312156135ae575f80fd5b6135b78461357e565b9250602084013567ffffffffffffffff808211156135d3575f80fd5b818601915086601f8301126135e6575f80fd5b8135818111156135f4575f80fd5b8760208260051b8501011115613608575f80fd5b6020830194508093505050509250925092565b5f6020828403121561362b575f80fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461212b575f80fd5b803573ffffffffffffffffffffffffffffffffffffffff81168114611dc7575f80fd5b5f806040838503121561368e575f80fd5b6136978361357e565b91506136a56020840161365a565b90509250929050565b5f602082840312156136be575f80fd5b61212b8261365a565b5f602082840312156136d7575f80fd5b61212b8261357e565b602080825282518282018190525f9190848201906040850190845b8181101561372d57835173ffffffffffffffffffffffffffffffffffffffff16835292840192918401916001016136fb565b50909695505050505050565b5f805f805f60a0868803121561374d575f80fd5b6137568661365a565b94506137646020870161365a565b93506137726040870161365a565b94979396509394606081013594506080013592915050565b5f805f6060848603121561379c575f80fd5b6137a58461365a565b92506137b36020850161365a565b91506137c16040850161365a565b90509250925092565b5f805f606084860312156137dc575f80fd5b6137e58461365a565b95602085013595506040909401359392505050565b8015158114610b02575f80fd5b5f805f805f60a0868803121561381b575f80fd5b6138248661365a565b9450602086013560ff81168114613839575f80fd5b93506040860135613849816137fa565b92506060860135613859816137fa565b91506080860135613869816137fa565b809150509295509295909350565b5f8060408385031215613888575f80fd5b6138918361365a565b946020939093013593505050565b5f80604083850312156138b0575f80fd5b6136978361365a565b5f8083601f8401126138c9575f80fd5b50813567ffffffffffffffff8111156138e0575f80fd5b6020830191508360208285010111156138f7575f80fd5b9250929050565b5f806020838503121561390f575f80fd5b823567ffffffffffffffff811115613925575f80fd5b613931858286016138b9565b90969095509350505050565b5f806040838503121561394e575f80fd5b6139578361365a565b91506136a56020840161357e565b5f805f8060808587031215613978575f80fd5b6139818561365a565b935061398f6020860161365a565b925061399d6040860161365a565b9396929550929360600135925050565b5f80604083850312156139be575f80fd5b6139c78361365a565b91506020830135600981106139da575f80fd5b809150509250929050565b5f805f604084860312156139f7575f80fd5b833567ffffffffffffffff811115613a0d575f80fd5b613a19868287016138b9565b90945092506137c190506020850161357e565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b80820180821115610a8d57610a8d613a59565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b5f60208284031215613ad6575f80fd5b815161212b816137fa565b5f6effffffffffffffffffffffffffffff808316818103613b0457613b04613a59565b6001019392505050565b60208152816020820152818360408301375f818301604090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160101919050565b73ffffffffffffffffffffffffffffffffffffffff831681526040810160098310613bac577f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b8260208301529392505050565b5f82613bec577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b81810381811115610a8d57610a8d613a59565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603160045260245ffdfea2646970667358221220160996c94b1d698a40469e3f97911dd81a027efec7d78941305ede91222dd7d864736f6c63430008180033

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

0000000000000000000000000000000000a1793068B5b7e278dE7c641E9E75C8000000000000000000000000721C00182a990771244d7A71B9FA2ea789A3b433

-----Decoded View---------------
Arg [0] : defaultOwner (address): 0x0000000000a1793068B5b7e278dE7c641E9E75C8
Arg [1] : eoaRegistry (address): 0x721C00182a990771244d7A71B9FA2ea789A3b433

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000a1793068B5b7e278dE7c641E9E75C8
Arg [1] : 000000000000000000000000721C00182a990771244d7A71B9FA2ea789A3b433


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.