MON Price: $0.01887 (+3.00%)

Contract

0x00721CE73fDE1e57A9048E0e19B7ee7c8D3F10E3

Overview

MON Balance

Monad Chain LogoMonad Chain LogoMonad Chain Logo0 MON

MON Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

2 Internal Transactions found.

Latest 2 internal transactions

Advanced mode:
Parent Transaction Hash Block From To
337665322025-11-06 2:20:1279 days ago1762395612
0x00721CE7...c8D3F10E3
 Contract Creation0 MON
337665322025-11-06 2:20:1279 days ago1762395612  Contract Creation0 MON
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
RulesetWhitelist

Compiler Version
v0.8.24+commit.e11b9ed9

Optimization Enabled:
Yes with 1000000 runs

Other Settings:
cancun EvmVersion, MIT license
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

import "./RulesetBase.sol";
import "../interfaces/IWhitelistExtension.sol";
import "@limitbreak/tm-core-lib/src/utils/token/IEOARegistry.sol";

/**
 * @title RulesetWhitelist
 * @author Limit Break, Inc.
 * @notice A ruleset contract that blocks transfers by default, unless exceptions are made through various options and 
 *         whitelisting rules.  
 */
contract RulesetWhitelist is IRuleset, RulesetBase {
    using EnumerableSet for EnumerableSet.AddressSet;
    using EnumerableSet for EnumerableSet.Bytes32Set;

    struct Options {
        bool enableAccountFreezingMode;
        bool disableAuthorizationMode;
        bool customListSupplementsDefaultList;
        bool blockSmartWalletReceivers;
        bool blockUnverifiedEOAReceivers;
        bool blockAllOTC;
        bool allowOTCFor7702Delegates;
        bool allowOTCForSmartWallets;
    }

    /// @dev The address of the EOA Registry to use to validate an account is a verified EOA.
    address private immutable _eoaRegistry;

    constructor(address eoaRegistry_) RulesetBase() {
        if (eoaRegistry_ == address(0)) {
            revert CreatorTokenTransferValidator__InvalidConstructorArgs();
        }

        _eoaRegistry = eoaRegistry_;
    }

    /**
     * @notice Validates a transfer of a Creator Token.
     *
     * @notice Global Options Used: 
     *         - Disable Authorization Mode: Toggles authorization mode logic on/off (default: enabled)
     *         - Enable Account Freezing Mode: Toggles account freezing logic on/off (default: disabled)     
     *         - Custom List Supplements Default List Mode: When toggled on, whitelist includes both custom list 
     *                                                      values and default managed list values (default: off)
     *
     * @notice Ruleset-Specific Options Used: 
     *         - Block Smart Wallet Receivers: When enabled, blocks transfers to receivers with 
     *                                         code length > 0, unless `to` is whitelisted (default: disabled)
     *         - Block Unverified EOA Receivers: When enabled, blocks transfers to receivers that have not verified
     *                                           an ECDSA signature on the EOA registry, unless `to` is whitelisted 
     *                                           (default: disabled)
     *         - Block All OTC: When enabled, blocks all OTC transfers, unless `caller` or `from` are whitelisted 
     *                          (default: disabled) 
     *                          [OTC transfer is defined as any owner-initiated transfer where caller == from]
     *         - Allow OTC For 7702 Delegates: Unused when Block All OTC is enabled. When enabled, allows OTC transfers 
     *                                         from EOAs that currently have EIP-7702 delegates attached. When disabled,
     *                                         blocks OTC transfers from EOAs that currently have EIP-7702 delegates 
     *                                         attached, unless the attached delegate is whitelisted. 
     *                                         (default: disabled)
     *         - Allow OTC For Smart Wallets: Unused when Block All OTC is enabled. When enabled, allows OTC transfers
     *                                        from smart wallets. When disabled, blocks OTC transfers from smart wallets,
     *                                        unless the smart wallet is whitelisted. (default: disabled)
     *
     * @notice Validation Flow: 
     *         1. If account freezing mode is enabled, check if the sender or recipient is frozen.
     *            If frozen, block transfer and return.
     *         2. If authorization mode is enabled, check if an authorizer has pre-authorized transfer of 
     *            collection/token id/amount by operator (msg.sender). If authorized, allow transfer and return.
     *         3. If block smart wallet receivers is enabled, check if the receiver has code length > 0. If so,
     *            check if the receiver is whitelisted. If not whitelisted, block transfer and return. 
     *            If whitelisted, continue.
     *         4. If block unverified EOA receivers is enabled, check if the receiver has verified an ECDSA signature
     *            on the EOA registry. If not verified, check if the receiver is whitelisted. If not whitelisted, 
     *            block transfer and return. If whitelisted, continue.
     *         5. If transfer is OTC (caller == from):
     *            5a. If block all OTC is enabled, check if `caller` or `from` are whitelisted.  
     *                If not whitelisted, block transfer and return.  If whitelisted, allow transfer and return.
     *            5b. If block all OTC is disabled, and code length of `from` address equals 0, allow transfer and return.
     *            5c. If block all OTC is disabled, and code length of `from` address is greater than 0:
     *                5ci. If `from` is an EOA with delegation attached: when allow OTC for 7702 delegates is enabled, 
     *                     allow transfer an return.  Otherwise, when allow OTC for 7702 delegates is disabled, check
     *                     if delegate is whitelisted. If not whitelisted, block transfer and return. If whitelisted,
     *                     allow transfer and return.
     *                5cii. Otherwise, `from` is a smart wallet. If allow OTC for smart wallets is enabled, allow 
     *                      transfer and return. Otherwise, check if `from` is whitelisted. If not whitelisted, block
     *                      transfer and return. If whitelisted, allow transfer and return.
     *          6. If transfer is not OTC (caller != from), check if `caller` is whitelisted. If not whitelisted, 
     *             block transfer and return. If whitelisted, allow transfer and return.
     *
     * @notice Whitelisting Notes:
     *         - When performing a whitelist check, when custom list supplements default list mode is enabled, the
     *           default whitelist is checked first.  If the operator is not whitelisted in the default list, the
     *           custom list specified in the collection security policy is checked.
     *         - When performing whitelist checks, accounts are first checked by address, then by codehash, and finally
     *           evaluated against a set of 0 or more whitelist extensions.
     */
    function validateTransfer(
        uint256 authorizerCheckType,
        address collection,
        address caller, 
        address from,
        address to,
        uint256 tokenId,
        uint256 amount) external view returns (bytes4) {
        CollectionSecurityPolicy storage collectionSecurityPolicy = 
            validatorStorage().collectionSecurityPolicies[collection];

        Options memory opts = 
            _getOptions(collectionSecurityPolicy.globalOptions, collectionSecurityPolicy.rulesetOptions);

        if (opts.enableAccountFreezingMode) {
            AccountList storage frozenAccountList = validatorStorage().frozenAccounts[collection];
            
            if (frozenAccountList.nonEnumerableAccounts[from]) {
                return CreatorTokenTransferValidator__SenderAccountIsFrozen.selector;
            }

            if (frozenAccountList.nonEnumerableAccounts[to]) {
                return CreatorTokenTransferValidator__ReceiverAccountIsFrozen.selector;
            }
        }

        if (!opts.disableAuthorizationMode) {
            if (_isAuthorized(authorizerCheckType, collection, caller, tokenId, amount)) {
                return SELECTOR_NO_ERROR;
            }
        }

        return _doWhitelistChecks(
            opts, 
            collectionSecurityPolicy.listId,
            collection, 
            to, 
            caller, 
            from);
    }

    function _doWhitelistChecks(
        Options memory opts,
        uint48 listId,
        address collection,
        address to,
        address caller, 
        address from
    ) internal view returns (bytes4) {
        (
            mapping (address => bool) storage accountWhitelist,
            mapping (bytes32 => bool) storage codehashWhitelist,
            EnumerableSet.AddressSet storage whitelistExtensions
        ) = _getWhitelistStoragePointers(listId);

        if (opts.blockSmartWalletReceivers) {
            if (_getCodeLengthAsm(to) > 0) {
                if (!_isWhitelisted(opts.customListSupplementsDefaultList, accountWhitelist, codehashWhitelist, whitelistExtensions, collection, to)) {
                    return CreatorTokenTransferValidator__ReceiverMustNotHaveDeployedCode.selector;
                }
            }
        }

        if (opts.blockUnverifiedEOAReceivers) {
            if (!_isVerifiedEOA(to)) {
                if (!_isWhitelisted(opts.customListSupplementsDefaultList, accountWhitelist, codehashWhitelist, whitelistExtensions, collection, to)) {
                    return CreatorTokenTransferValidator__ReceiverProofOfEOASignatureUnverified.selector;
                }
            }
        }

        if (caller == from) {
            if (!opts.blockAllOTC) {
                if (_getCodeLengthAsm(from) > 0) {
                    (bool isDelegate, address delegate) = _check7702(from);

                    if (opts.allowOTCFor7702Delegates) {
                        // If allowing OTC for 7702 delegates, check if the owner is delegated or not
                        if (!isDelegate) {
                            // This is a non-delegated smart wallet account, if OTC is not allowed for smart wallets check against whitelist
                            if (!opts.allowOTCForSmartWallets) {
                                if (!_isWhitelisted(opts.customListSupplementsDefaultList, accountWhitelist, codehashWhitelist, whitelistExtensions, collection, from)) {
                                    return CreatorTokenTransferValidator__OTCNotAllowedForSmartWallets.selector;
                                }
                            }
                        }
                    } else {
                        // If not allowing OTC for 7702 delegates, check if the owner is delegated or not
                        if (isDelegate) { 
                            // This is a delegated EOA account, block unless delegate is whitelisted
                            if (!_is7702DelegateWhitelisted(opts.customListSupplementsDefaultList, listId, collection, delegate)) {
                                return CreatorTokenTransferValidator__OTCNotAllowedFor7702Delegates.selector;
                            }
                        } else {
                            // This is a non-delegated smart wallet account, if OTC is not allowed for smart wallets check against whitelist
                            if (!opts.allowOTCForSmartWallets) {
                                if (!_isWhitelisted(opts.customListSupplementsDefaultList, accountWhitelist, codehashWhitelist, whitelistExtensions, collection, from)) {
                                    return CreatorTokenTransferValidator__OTCNotAllowedForSmartWallets.selector;
                                }
                            }
                        }
                    }
                }

                return SELECTOR_NO_ERROR;
            }
        }

        if (!_isWhitelisted(opts.customListSupplementsDefaultList, accountWhitelist, codehashWhitelist, whitelistExtensions, collection, caller, from)) {
            return CreatorTokenTransferValidator__CallerOrFromMustBeWhitelisted.selector;
        }

        return SELECTOR_NO_ERROR;
    }

    function _isWhitelisted(
        bool customListSupplementsDefaultList,
        mapping (address => bool) storage accountWhitelist,
        mapping (bytes32 => bool) storage codehashWhitelist,
        EnumerableSet.AddressSet storage whitelistExtensions,
        address collection,
        address account
    ) internal view returns (bool isWhitelisted) {
        if (customListSupplementsDefaultList) {
            (
                mapping (address => bool) storage defaultAccountWhitelist,
                mapping (bytes32 => bool) storage defaultCodehashWhitelist,
                EnumerableSet.AddressSet storage defaultWhitelistExtensions
            ) = _getWhitelistStoragePointers(DEFAULT_LIST_ID);

            if (_checkWhitelist(
                    defaultAccountWhitelist, 
                    defaultCodehashWhitelist, 
                    defaultWhitelistExtensions, 
                    collection, 
                    account)) {
                return true;
            }
        }

        return _checkWhitelist(accountWhitelist, codehashWhitelist, whitelistExtensions, collection, account);
    }

    function _isWhitelisted(
        bool customListSupplementsDefaultList,
        mapping (address => bool) storage accountWhitelist,
        mapping (bytes32 => bool) storage codehashWhitelist,
        EnumerableSet.AddressSet storage whitelistExtensions,
        address collection,
        address account1,
        address account2
    ) internal view returns (bool isWhitelisted) {
        if (customListSupplementsDefaultList) {
            (
                mapping (address => bool) storage defaultAccountWhitelist,
                mapping (bytes32 => bool) storage defaultCodehashWhitelist,
                EnumerableSet.AddressSet storage defaultWhitelistExtensions
            ) = _getWhitelistStoragePointers(DEFAULT_LIST_ID);

            if (_checkWhitelist(
                    defaultAccountWhitelist, 
                    defaultCodehashWhitelist, 
                    defaultWhitelistExtensions, 
                    collection, 
                    account1,
                    account2)) {
                return true;
            }
        }

        return _checkWhitelist(accountWhitelist, codehashWhitelist, whitelistExtensions, collection, account1, account2);
    }

    function _is7702DelegateWhitelisted(
        bool customListSupplementsDefaultList,
        uint48 listId,
        address collection,
        address account
    ) internal view returns (bool isWhitelisted) {
        if (customListSupplementsDefaultList) {
            (
                mapping (address => bool) storage defaultAccountWhitelist,
                mapping (bytes32 => bool) storage defaultCodehashWhitelist,
                EnumerableSet.AddressSet storage defaultWhitelistExtensions
            ) = _get7702DelegateWhitelistStoragePointers(DEFAULT_LIST_ID);

            if (_checkWhitelist(
                    defaultAccountWhitelist, 
                    defaultCodehashWhitelist, 
                    defaultWhitelistExtensions, 
                    collection, 
                    account)) {
                return true;
            }
        }

        (
            mapping (address => bool) storage accountWhitelist,
            mapping (bytes32 => bool) storage codehashWhitelist,
            EnumerableSet.AddressSet storage whitelistExtensions
        ) = _get7702DelegateWhitelistStoragePointers(listId);

        return _checkWhitelist(accountWhitelist, codehashWhitelist, whitelistExtensions, collection, account);
    }

    function _checkWhitelist(
        mapping (address => bool) storage accountWhitelist,
        mapping (bytes32 => bool) storage codehashWhitelist,
        EnumerableSet.AddressSet storage whitelistExtensions,
        address collection,
        address account
    ) internal view returns (bool isWhitelisted) {
        isWhitelisted = 
                accountWhitelist[account] || 
                codehashWhitelist[_getCodeHashAsm(account)];

        if (!isWhitelisted) {
            uint256 lengthOfExtensionsList = whitelistExtensions.length();
            for (uint256 i = 0; i < lengthOfExtensionsList; ++i) {
                IWhitelistExtension whitelistExtension = IWhitelistExtension(whitelistExtensions.at(i));
                if (whitelistExtension.isWhitelisted(collection, account)) {
                    isWhitelisted = true;
                    break;
                }
            }
        }
    }

    function _checkWhitelist(
        mapping (address => bool) storage accountWhitelist,
        mapping (bytes32 => bool) storage codehashWhitelist,
        EnumerableSet.AddressSet storage whitelistExtensions,
        address collection,
        address account1,
        address account2
    ) internal view returns (bool isWhitelisted) {
        isWhitelisted = 
            accountWhitelist[account1] || 
            accountWhitelist[account2] || 
            codehashWhitelist[_getCodeHashAsm(account1)] ||
            codehashWhitelist[_getCodeHashAsm(account2)];

        if (!isWhitelisted) {
            uint256 lengthOfExtensionsList = whitelistExtensions.length();
            for (uint256 i = 0; i < lengthOfExtensionsList; ++i) {
                IWhitelistExtension whitelistExtension = IWhitelistExtension(whitelistExtensions.at(i));
                if (whitelistExtension.isWhitelisted(collection, account1) || 
                    whitelistExtension.isWhitelisted(collection, account2)) {
                    isWhitelisted = true;
                    break;
                }
            }
        }
    }

    /// @notice Returns true if the specified account has verified a signature on the registry, false otherwise.
    function _isVerifiedEOA(address account) internal view returns (bool) {
        return IEOARegistry(_eoaRegistry).isVerifiedEOA(account);
    }

    function _getOptions(uint8 globalOptions, uint16 whitelistOptions) internal pure returns (Options memory options) {
        options.enableAccountFreezingMode = 
            _isFlagSet(globalOptions, FLAG_GLOBAL_ENABLE_ACCOUNT_FREEZING_MODE);

        options.disableAuthorizationMode = 
            _isFlagSet(globalOptions, FLAG_GLOBAL_DISABLE_AUTHORIZATION_MODE);

        options.customListSupplementsDefaultList = 
            _isFlagSet(globalOptions, FLAG_GLOBAL_CUSTOM_LIST_SUPPLEMENTS_DEFAULT_LIST);

        options.blockSmartWalletReceivers = 
            _isFlagSet(whitelistOptions, FLAG_RULESET_WHITELIST_BLOCK_SMART_WALLET_RECEIVERS);

        options.blockUnverifiedEOAReceivers = 
            _isFlagSet(whitelistOptions, FLAG_RULESET_WHITELIST_BLOCK_UNVERIFIED_EOA_RECEIVERS);

        options.blockAllOTC = 
            _isFlagSet(whitelistOptions, FLAG_RULESET_WHITELIST_BLOCK_ALL_OTC);

        options.allowOTCFor7702Delegates = 
            _isFlagSet(whitelistOptions, FLAG_RULESET_WHITELIST_ALLOW_OTC_FOR_7702_DELEGATES);
            
        options.allowOTCForSmartWallets = 
            _isFlagSet(whitelistOptions, FLAG_RULESET_WHITELIST_ALLOW_OTC_FOR_SMART_WALLETS);
    }

    function _getWhitelistStoragePointers(uint48 listId) 
    internal 
    view 
    returns (
        mapping (address => bool) storage accountWhitelist,
        mapping (bytes32 => bool) storage codehashWhitelist,
        EnumerableSet.AddressSet storage whitelistExtensions
    ) {
        List storage whitelist = validatorStorage().lists[LIST_TYPE_WHITELIST][listId];
        accountWhitelist = whitelist.nonEnumerableAccounts;
        codehashWhitelist = whitelist.nonEnumerableCodehashes;
        whitelistExtensions = 
            validatorStorage().lists[EXPANSION_LIST_TYPE_WHITELIST_EXTENSION_CONTRACTS][listId].enumerableAccounts;
    }

    function _get7702DelegateWhitelistStoragePointers(uint48 listId) 
    internal 
    view 
    returns (
        mapping (address => bool) storage accountWhitelist,
        mapping (bytes32 => bool) storage codehashWhitelist,
        EnumerableSet.AddressSet storage whitelistExtensions
    ) {
        List storage whitelist = 
            validatorStorage().lists[EXPANSION_LIST_TYPE_7702_DELEGATE_WHITELIST][listId];
        accountWhitelist = whitelist.nonEnumerableAccounts;
        codehashWhitelist = whitelist.nonEnumerableCodehashes;
        whitelistExtensions = 
            validatorStorage().lists[EXPANSION_LIST_TYPE_7702_DELEGATE_WHITELIST_EXTENSION_CONTRACTS][listId].enumerableAccounts;
    }
}

pragma solidity ^0.8.4;

/**
 * @dev Interface of the ERC-165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[ERC].
 *
 * 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[ERC 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 3 of 13 : StorageTstorish.sol
pragma solidity ^0.8.24;

library StorageTstorish {   
    // keccak256(abi.encode(uint256(keccak256("storage.Tstorish")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant DATA_STORAGE_SLOT = 
        0xdacd49f6a6c42b45a5c3d195b83b324104542d9147bb8064a39c6a8d23ba9b00;

    struct Data {
        // Indicates if TSTORE support has been activated during or post-deployment.
        bool tstoreSupport;
    }

    function data() internal pure returns (Data storage ptr) {
        bytes32 slot = DATA_STORAGE_SLOT;
        assembly {
            ptr.slot := slot
        }
    }
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import "./StorageTstorish.sol";

/**
 * @title  Tloadish
 * @notice Based on https://github.com/ProjectOpenSea/tstorish/commit/a81ed74453ed7b9fe7e96a9906bc4def19b73e33
 */
abstract contract Tloadish {

    /*
     * ------------------------------------------------------------------------+
     * 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 tload test contract address.
    address private immutable _tloadTestContract;

    // Declare an immutable variable to store the initial TLOAD support status.
    bool internal immutable _tloadInitialSupport;

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

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

    /**
     * @dev Determine TLOAD 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 TLOAD in place of SLOAD 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 TLOAD is supported.
        _tloadInitialSupport = StorageTstorish.data().tstoreSupport = _testTload(tloadTestContract);

        if (_tloadInitialSupport) {
            // If TLOAD is supported, set functions to their versions that use
            // tload directly without support checks.
            _getTstorish = _getTstore;
        } else {
            // If TLOAD is not supported, set functions to their versions that 
            // fallback to sload until tstoreSupport is true.
            _getTstorish = _getTstorishWithSloadFallback;
        }

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

    /**
     * @dev Private function to read a TSTORISH value. Assigned to _getTstorish
     *      internal function variable at construction if chain has tload 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
    ) internal 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 tload 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
    ) internal view returns (uint256 value) {
        if (StorageTstorish.data().tstoreSupport) {
            assembly {
                value := tload(storageSlot)
            }
        } else {
            assembly {
                value := sload(storageSlot)
            }
        }
    }

    /**
     * @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 TLOAD is 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 is supported. Do not forward all
        // available gas, as all forwarded gas will be consumed on revert.
        (ok, ) = tloadTestContract.staticcall{ gas: gasleft() / 10 }("");
    }
}

pragma solidity ^0.8.4;

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

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

    /**
     * @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._positions[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 cache the value's position to prevent multiple reads from the same storage slot
        uint256 position = set._positions[value];

        if (position != 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 valueIndex = position - 1;
            uint256 lastIndex = set._values.length - 1;

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

                // Move the lastValue to the index where the value to delete is
                set._values[valueIndex] = lastValue;
                // Update the tracked position of the lastValue (that was just moved)
                set._positions[lastValue] = position;
            }

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

            // Delete the tracked position for the deleted slot
            delete set._positions[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._positions[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;
    }
}

pragma solidity ^0.8.4;

import "../introspection/IERC165.sol";

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

File 7 of 13 : Constants.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

/**************************************************************/
/*                        LIST TYPES                          */
/**************************************************************/

uint8 constant LIST_TYPE_BLACKLIST = 0;
uint8 constant LIST_TYPE_WHITELIST = 1;
uint8 constant LIST_TYPE_AUTHORIZERS = 2;
uint8 constant EXPANSION_LIST_TYPE_WHITELIST_EXTENSION_CONTRACTS = 3;
uint8 constant EXPANSION_LIST_TYPE_7702_DELEGATE_WHITELIST = 4;
uint8 constant EXPANSION_LIST_TYPE_7702_DELEGATE_WHITELIST_EXTENSION_CONTRACTS = 5;

/**************************************************************/
/*                        RULESET IDS                         */
/**************************************************************/

uint8 constant RULESET_ID_DEFAULT = 0;
uint8 constant RULESET_ID_VANILLA = 1;
uint8 constant RULESET_ID_SOULBOUND = 2;
uint8 constant RULESET_ID_BLACKLIST = 3;
uint8 constant RULESET_ID_WHITELIST = 4;
uint8 constant RULESET_ID_FIXED_OR_CUSTOM = 255;

/**************************************************************/
/*                    AUTHORIZER CHECK TYPES                  */
/**************************************************************/

uint256 constant AUTHORIZER_CHECK_TYPE_TOKEN = 1;
uint256 constant AUTHORIZER_CHECK_TYPE_COLLECTION = 2;
uint256 constant AUTHORIZER_CHECK_TYPE_TOKEN_AND_AMOUNT = 3;

/**************************************************************/
/*                       MISCELLANEOUS                        */
/**************************************************************/

bytes4 constant LEGACY_TRANSFER_VALIDATOR_INTERFACE_ID = bytes4(0x00000000);
bytes4 constant SELECTOR_NO_ERROR = bytes4(0x00000000);
bytes32 constant BYTES32_ZERO = 0x0000000000000000000000000000000000000000000000000000000000000000;
bytes32 constant DEFAULT_ACCESS_CONTROL_ADMIN_ROLE = 0x0000000000000000000000000000000000000000000000000000000000000000;
address constant WILDCARD_OPERATOR_ADDRESS = address(0x01);
uint48 constant DEFAULT_LIST_ID = 0;
uint16 constant DEFAULT_TOKEN_TYPE = 0;

/**************************************************************/
/*                       FLAGS - GLOBAL                       */
/**************************************************************/

// Flags are used to efficiently store and retrieve boolean values in a single uint8.
// Each flag is a power of 2, so they can be combined using bitwise OR (|) and checked using bitwise AND (&).
// For example, to set the first and third flags, you would use: flags = FLAG1 | FLAG3;
// To check if the first flag is set, you would use: if (flags & FLAG1 != 0) { ... }
uint8 constant FLAG_GLOBAL_DISABLE_AUTHORIZATION_MODE = 1 << 0;
uint8 constant FLAG_GLOBAL_AUTHORIZERS_CANNOT_SET_WILDCARD_OPERATORS = 1 << 1;
uint8 constant FLAG_GLOBAL_ENABLE_ACCOUNT_FREEZING_MODE = 1 << 2;
uint8 constant FLAG_GLOBAL_CUSTOM_LIST_SUPPLEMENTS_DEFAULT_LIST = 1 << 3;

/**************************************************************/
/*                  FLAGS - RULESET WHITELIST                 */
/**************************************************************/

uint16 constant FLAG_RULESET_WHITELIST_BLOCK_ALL_OTC = 1 << 0;
uint16 constant FLAG_RULESET_WHITELIST_ALLOW_OTC_FOR_7702_DELEGATES = 1 << 1;
uint16 constant FLAG_RULESET_WHITELIST_ALLOW_OTC_FOR_SMART_WALLETS = 1 << 2;
uint16 constant FLAG_RULESET_WHITELIST_BLOCK_SMART_WALLET_RECEIVERS = 1 << 3;
uint16 constant FLAG_RULESET_WHITELIST_BLOCK_UNVERIFIED_EOA_RECEIVERS = 1 << 4;

File 8 of 13 : DataTypes.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

import "@limitbreak/tm-core-lib/src/utils/structs/EnumerableSet.sol";

/**
 * @dev This struct contains the security policy settings for a collection.
 */
struct CollectionSecurityPolicy {
    uint8 rulesetId;
    uint48 listId;
    address customRuleset;
    uint8 globalOptions;
    uint16 rulesetOptions;
    uint16 tokenType;
}


/**
 * @dev This struct is internally for the storage of account and codehash lists.
 */
struct List {
    EnumerableSet.AddressSet enumerableAccounts;
    EnumerableSet.Bytes32Set enumerableCodehashes;
    mapping (address => bool) nonEnumerableAccounts;
    mapping (bytes32 => bool) nonEnumerableCodehashes;
}

/**
 * @dev This struct is internally for the storage of account lists.
 */
struct AccountList {
    EnumerableSet.AddressSet enumerableAccounts;
    mapping (address => bool) nonEnumerableAccounts;
}

/**
 * @dev This struct contains a key and value pair for future expansion data words that are 32 bytes long.
 */
struct ExpansionWord {
    bytes32 key;
    bytes32 value;
}

/**
 * @dev This struct contains a key and value pair for future expansion data bytes that are variable length.
 */
struct ExpansionDatum {
    bytes32 key;
    bytes value;
}

/**
 * @dev This struct contains the storage layout for the validator contract, excluding Permit-C and Tstorish data.
 */
struct ValidatorStorage {
    /// @notice Keeps track of the most recently created list id.
    uint48 lastListId;

    /// @dev Used as a collision guard.
    mapping (address => address) transientOperator;

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

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

    /// @dev Mapping of collections to accounts that are frozen for those collections
    mapping (address => AccountList) frozenAccounts;

    /// @dev Mapping of list ids to list data
    mapping (uint8 => mapping (uint48 => List)) lists;

    /// @dev Mapping of collection addressses to any future expansion data words settings that may be used in the future
    mapping (address collection => mapping (bytes32 extension => bytes32 word)) collectionExpansionWords;

    /// @dev Mapping of collection addressses to any future expansion data bytes settings that may be used in the future
    mapping (address collection => mapping (bytes32 extension => bytes data)) collectionExpansionDatums;

    /// @dev Mapping of addresses to a boolean indicating if they are registered trusted validator modules
    mapping (address => bool) registeredRulesets;

    /// @dev Mapping of security levels to their current implementation modules
    mapping (uint8 => address) rulesetBindings;
}

File 9 of 13 : Errors.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

/// @dev Thrown when admin attempts to bind a ruleset to the fixed/custom ruleset ID.
error CreatorTokenTransferValidator__AdminCannotAssignRulesetToRulesetIdCustom();

/// @dev Thrown when validating transfers with amount if authorization by amount mode is active and the amount
///      exceeds the pre-authorized amount.
error CreatorTokenTransferValidator__AmountExceedsAuthorization();

/// @dev Thrown when attempting to set a authorized operator when authorization mode is disabled.
error CreatorTokenTransferValidator__AuthorizationDisabledForCollection();

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

/// @dev Thrown when authorizing a transfer for a collection using authorizers and the msg.sender is not in the 
///      authorizer list.
error CreatorTokenTransferValidator__CallerMustBeAnAuthorizer();

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

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

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

/// @dev Thrown when attempting to renounce ownership of the default list id.
error CreatorTokenTransferValidator__CannotRenounceOwnershipOfDefaultList();

/// @dev Thrown when setting the ruleset for a collection when a reserved ruleset id is used, but a custom ruleset
///      is specified.
error CreatorTokenTransferValidator__CannotSetCustomRulesetOnManagedRulesetId();

/// @dev Thrown when constructor args are not valid
error CreatorTokenTransferValidator__InvalidConstructorArgs();

/// @dev Thrown when setting the transfer security level to an invalid value.
error CreatorTokenTransferValidator__InvalidTransferSecurityLevel();

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

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

/// @dev Thrown when attempting to call the transfer validation logic externally, as staticcall guarantees are needed.
error CreatorTokenTransferValidator__OnlyValidatorCanAccessThisFunction();

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

/// @dev Thrown when validating an OTC transfer with EIP-7702 Delegation when disabled by security settings.
error CreatorTokenTransferValidator__OTCNotAllowedFor7702Delegates();

/// @dev Thrown when validating an OTC transfer from Smart Wallets when disabled by security settings.
error CreatorTokenTransferValidator__OTCNotAllowedForSmartWallets();

/// @dev Thrown when a frozen account is the receiver of a transfer
error CreatorTokenTransferValidator__ReceiverAccountIsFrozen();

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

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

/// @dev Thrown when attempting to register a ruleset that is not a contract.
error CreatorTokenTransferValidator__RulesetIsNotContract();

/// @dev Thrown when attempting to register a ruleset that is not pure.
error CreatorTokenTransferValidator__RulesetIsNotPure();

/// @dev Thrown when admin attempts to bind a ruleset that is not registered, or a collection admin tries to 
///      set their fixed/custom ruleset to an unregistered ruleset.
error CreatorTokenTransferValidator__RulesetIsNotRegistered();

/// @dev Thrown when a frozen account is the sender of a transfer
error CreatorTokenTransferValidator__SenderAccountIsFrozen();

/// @dev Thrown when validating a transfer for a collection that is in soulbound token mode.
error CreatorTokenTransferValidator__TokenIsSoulbound();

/// @dev Thrown when attempting to validate a permitted transfer where the permit type does not match the 
///      collection-defined token type.
error CreatorTokenTransferValidator__TokenTypesDoNotMatch();

/// @dev Thrown when an authorizer attempts to set a wildcard authorized operator on collections that don't 
///      allow wildcards
error CreatorTokenTransferValidator__WildcardOperatorsCannotBeAuthorizedForCollection();

// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

import "./DataTypes.sol";
import "./Errors.sol";

/**
 * @title ValidatorBase
 * @author Limit Break, Inc.
 * @notice Base contract for all Creator Token Validator, Module, and Ruleset contracts. 
 *         Includes some helper functions and modifiers and easy access to validator diamond storage
 *         to allow modules and rulesets to access the storage of the validator contract.
 */
contract ValidatorBase {

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

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

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

    /**
     * @notice Requires the caller to be the owner of list `id`.
     * 
     * @dev    Throws when the caller is not the owner of the list.
     * 
     * @param id  The id of the list to check ownership of.
     */
    function _requireCallerOwnsList(uint48 id) private view {
        if (msg.sender != validatorStorage().listOwners[id]) {
            revert CreatorTokenTransferValidator__CallerDoesNotOwnList();
        }
    }

    /**
     * @dev Internal function used to compute the transient storage slot for the authorized 
     *      operator of a token in a collection.
     * 
     * @param collection The collection address of the token being transferred.
     * @param tokenId    The id of the token being transferred.
     * 
     * @return operatorSlot The storage slot location for the authorized operator value.
     */
    function _getTransientOperatorSlot(
        address collection, 
        uint256 tokenId
    ) internal pure returns (uint256 operatorSlot) {
        assembly {
            mstore(0x00, collection)
            mstore(0x20, tokenId)
            operatorSlot := shr(4, keccak256(0x00, 0x40))
       }
    }

    /**
     * @dev Internal function used to compute the transient storage slot for the authorized operator of a collection.
     * 
     * @param collection The collection address of the token being transferred.
     * 
     * @return operatorSlot The storage slot location for the authorized operator value.
     */
    function _getTransientOperatorSlot(address collection) internal view returns (uint256 operatorSlot) {
        mapping (address => address) storage _transientOperator = validatorStorage().transientOperator;
        assembly {
            mstore(0x00, collection)
            mstore(0x20, _transientOperator.slot)
            operatorSlot := keccak256(0x00, 0x40)
        }
    }

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

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

    /**
     * @notice Returns true if the `flagValue` has the `flag` set, false otherwise.
     *
     * @dev    This function uses the bitwise AND operator to check if the `flag` is set in `flagValue`.
     *
     * @param flagValue  The value to check for the presence of the `flag`.
     * @param flag       The flag to check for in the `flagValue`.
     */
    function _isFlagSet(uint256 flagValue, uint256 flag) internal pure returns (bool flagSet) {
        flagSet = (flagValue & flag) != 0;
    }

    /*************************************************************************/
    /*                                STORAGE                                */
    /*************************************************************************/

    /// @dev The base storage slot for Validator V5 contract storage items.
    bytes32 constant DIAMOND_STORAGE_VALIDATOR = 
        0x0000000000000000000000000000000000000000000000000000000000721C05;

    /**
     * @dev Returns a storage object that follows the Diamond standard storage pattern for
     * @dev contract storage across multiple module contracts.
     */
    function validatorStorage() internal pure returns (ValidatorStorage storage diamondStorage) {
        bytes32 slot = DIAMOND_STORAGE_VALIDATOR;
        assembly {
            diamondStorage.slot := slot
        }
    }
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

/** 
 * @title IRuleset
 * @author Limit Break, Inc.
 * @notice Interface for Creator Token Standards ruleset contracts.
 *
 * @dev Ruleset contracts are logic-gate contracts used to validate transfers of Creator Tokens
 *      (ERC20-C / ERC721-C / ERC1155-C). Rulesets are view-only, and may not contain any opcodes
 *      that could modify the state of the blockchain.
 */
interface IRuleset {

    /**
     * @notice Validates a transfer of a Creator Token.
     *
     * @param authorizerCheckType The type of authorizer check to perform.
     * @param collection          The address of the Creator Token contract.
     * @param caller              The address of the caller (msg.sender) of the transfer function.
     * @param from                The address of the sender of the token.
     * @param to                  The address of the recipient of the token.
     * @param tokenId             The ID of the token.
     * @param amount              The amount of the token to transfer.
     * @return 0x00000000 when the transfer is allowed, or a custom error selector to block a transfer.
     */
    function validateTransfer(
        uint256 authorizerCheckType,
        address collection,
        address caller, 
        address from, 
        address to,
        uint256 tokenId,
        uint256 amount) external view returns (bytes4);
}

File 12 of 13 : IWhitelistExtension.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

/** 
 * @title IRuleset
 * @author Limit Break, Inc.
 * @notice Interface for whitelist extension contracts for the Whitelist Ruleset.
 *
 * @dev The Whitelist Ruleset supports whitelisting of specific accounts and codehashes.  
 *      A Whitelist Extension contract offers an additional mechanism to perform more sophisticated
 *      checks to see if an account can be allowed to perform a transfer.  For example, imagine a collection
 *      that blocks OTC transfers from smart wallet accounts because a smart wallet could be used to faciliate
 *      a trade that violates the creator's rules on trading.  A Whitelist Extension contract could be used to
 *      query a trusted smart wallet factory that is known to adhere to the creator's rules, and allow any wallet
 *      originating from that factory to perform OTC trades or to receive tokens when in a mode that blocks contracts
 *      from receiving tokens.
 */
 
interface IWhitelistExtension {
    
    /**
     * @notice Perform an advanced check on an account to see if it should be whitelisted.
     *
     * @param collection The address of the Creator Token contract.
     * @param account    The address of the account to check.
     * @return true if the account is whitelisted, false otherwise.
     */
    function isWhitelisted(
        address collection,
        address account) external view returns (bool);
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

import "../Constants.sol";
import "../DataTypes.sol";
import "../Errors.sol";
import "../ValidatorBase.sol";
import "../interfaces/IRuleset.sol";
import "@limitbreak/tm-core-lib/src/utils/misc/Tloadish.sol";

/** 
* @title RulesetBase
* @author Limit Break, Inc.
* @notice Base contract that includes internal helper functions and diamond storage access that are
*         useful for implementations of Creator Token Standards ruleset contracts.
*/ 
abstract contract RulesetBase is ValidatorBase, Tloadish {

    /**
     * @dev Internal function to check if a caller is authorized to transfer a token/id/amount.
     * 
     * @param authorizerCheckType The type of authorizer check to perform.
     * @param collection          The address of the Creator Token contract.
     * @param caller              The address of the caller (msg.sender) of the transfer function.
     * @param tokenId             The ID of the token.
     * @param amount              The amount of the token to transfer.
     * 
     * @return isAuthorized       True if the caller is authorized to transfer the token, false otherwise.
     */
    function _isAuthorized(
        uint256 authorizerCheckType, 
        address collection,
        address caller,
        uint256 tokenId,
        uint256 amount
    ) internal view returns (bool isAuthorized) {
        isAuthorized = _getAuthorizerCheckFunctionPointer(authorizerCheckType)(
            collection, caller, tokenId, amount
        );
    }

    /**
     * @dev Internal function to get the function pointer for the authorizer check type.
     * 
     * @param authorizerCheckType The type of authorizer check to perform.
     * 
     * @return _callerAuthorizedCheck  The function pointer to the authorizer check function.
     */
    function _getAuthorizerCheckFunctionPointer(uint256 authorizerCheckType) internal pure returns (function(address,address,uint256, uint256) internal view returns(bool) _callerAuthorizedCheck) {
        if (authorizerCheckType == AUTHORIZER_CHECK_TYPE_TOKEN) {
            return _callerAuthorizedCheckToken;
        } else if (authorizerCheckType == AUTHORIZER_CHECK_TYPE_COLLECTION) {
            return _callerAuthorizedCheckCollection;
        } else {
            // The master validator handles the authorized amount check, so we won't do anything different here to use
            // the authorized amount and the amount parameter.
            // Current rulesets won't use this call, it is a placeholder for future ruleset use.
            return _callerAuthorizedCheckCollection;
        }
    }

    /**
     * @dev Internal function to check if a caller is an authorized operator for the token being transferred.
     * 
     * @param caller     The caller of the token transfer.
     * @param collection The collection address of the token being transferred.
     * @param tokenId    The id of the token being transferred.
     * 
     * @return isAuthorized  True if the caller is authorized to transfer the token, false otherwise.
     */
    function _callerAuthorizedCheckToken(
        address collection,
        address caller,
        uint256 tokenId,
        uint256 /*amount*/
    ) internal view returns (bool isAuthorized) {
        uint256 slotValue;
        (isAuthorized, ) = _callerAuthorized(caller, _getTransientOperatorSlot(collection, tokenId));
        if (isAuthorized) return true;
        (isAuthorized, slotValue) = _callerAuthorized(caller, _getTransientOperatorSlot(collection));
        isAuthorized = isAuthorized && slotValue >> 255 == 1;
    }

    /**
     * @dev Internal function to check if a caller is an authorized operator for the collection being transferred.
     * 
     * @param caller     The caller of the token transfer.
     * @param collection The collection address of the token being transferred.
     * 
     * @return isAuthorized  True if the caller is authorized to transfer the collection, false otherwise.
     */
    function _callerAuthorizedCheckCollection(
        address collection,
        address caller,
        uint256 /*tokenId*/,
        uint256 /*amount*/
    ) internal view returns (bool isAuthorized) {
        (isAuthorized, ) = _callerAuthorized(caller, _getTransientOperatorSlot(collection));
    }

    /**
     * @dev Internal function to check if a caller is an authorized operator. 
     * @dev This overload of `_callerAuthorized` checks a specific storage slot for the caller address.
     * 
     * @param caller     The caller of the token transfer.
     * @param slot       The storage slot to check for the caller address.
     * 
     * @return isAuthorized  True if the caller is authorized to transfer the token, false otherwise.
     * @return slotValue     The transient storage value in `slot`, used to check for allow any token id flag if necessary.
     */
    function _callerAuthorized(address caller, uint256 slot) internal view returns (bool isAuthorized, uint256 slotValue) {
        slotValue = _getTstorish(slot);
        address authorizedOperator = address(uint160(slotValue));
        isAuthorized = authorizedOperator == WILDCARD_OPERATOR_ADDRESS || authorizedOperator == caller;
    }

    /**
     * @dev Internal function to check if an address is an EOA in EIP-7702 delegation mode, and what address
     *      it is delegated to.
     * 
     * @param _address   The account to check for EIP-7702 delegation.
     * 
     * @return isDelegate True if the account is an EOA with an EIP-7702 delegate attached, false otherwise.
     * @return delegate   The address of the EIP-7702 delegate code, if one is attached.
     */
    function _check7702(address _address) internal view returns (bool isDelegate, address delegate) {
        assembly ("memory-safe") {
            mstore(0x00, 0x00)
            extcodecopy(_address, 0x1D, 0x00, 0x17)
            if eq(mload(0x00), 0xEF0100) {
                isDelegate := 1
                delegate := shr(0x60, mload(0x20))
            }
        }
    }
}

Settings
{
  "remappings": [
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "forge-std/=lib/forge-std/src/",
    "@limitbreak/tm-core-lib/=lib/tm-core-lib/",
    "@limitbreak/permit-c/=lib/PermitC/src/",
    "@openzeppelin/=lib/PermitC/lib/openzeppelin-contracts/",
    "@rari-capital/solmate/=lib/PermitC/lib/solmate/",
    "PermitC/=lib/PermitC/",
    "erc4626-tests/=lib/PermitC/lib/openzeppelin-contracts/lib/erc4626-tests/",
    "forge-gas-metering/=lib/PermitC/lib/forge-gas-metering/",
    "openzeppelin-contracts/=lib/PermitC/lib/openzeppelin-contracts/",
    "openzeppelin/=lib/PermitC/lib/openzeppelin-contracts/contracts/",
    "solady/=lib/PermitC/lib/forge-gas-metering/lib/solady/",
    "solmate/=lib/PermitC/lib/solmate/src/",
    "tm-core-lib/=lib/tm-core-lib/src/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 1000000
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "none",
    "appendCBOR": false
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "abi"
      ]
    }
  },
  "evmVersion": "cancun",
  "viaIR": false
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"eoaRegistry_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"CreatorTokenTransferValidator__InvalidConstructorArgs","type":"error"},{"inputs":[],"name":"TloadTestContractDeploymentFailed","type":"error"},{"inputs":[{"internalType":"uint256","name":"authorizerCheckType","type":"uint256"},{"internalType":"address","name":"collection","type":"address"},{"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":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"}]

61010060405234801562000011575f80fd5b5060405162001164380380620011648339810160408190526200003491620001dc565b5f6200003f62000127565b90506001600160a01b0381166200006957604051632aea588760e01b815260040160405180910390fd5b620000748162000140565b7fdacd49f6a6c42b45a5c3d195b83b324104542d9147bb8064a39c6a8d23ba9b00805460ff19169115801592831790915560a091909152620000ce576001600160401b0362000277620001a260201b171660c052620000e7565b6001600160401b036200027b620001a660201b171660c0525b6001600160a01b039081166080528116620001155760405163c56e5d7360e01b815260040160405180910390fd5b6001600160a01b031660e0526200022b565b5f696002601e613d5c3d52f35f52600a60165ff0905090565b5f816001600160a01b0316600a5a6200015a91906200020b565b6040515f8181818686fa925050503d805f811462000194576040519150601f19603f3d011682016040523d82523d5f602084013e62000199565b606091505b50909392505050565b5c90565b5f7fdacd49f6a6c42b45a5c3d195b83b324104542d9147bb8064a39c6a8d23ba9b005460ff1615620001d757505c90565b505490565b5f60208284031215620001ed575f80fd5b81516001600160a01b038116811462000204575f80fd5b9392505050565b5f826200022657634e487b7160e01b5f52601260045260245ffd5b500490565b60805160a05160c05160e051610f0b620002595f395f6106c901525f610d3401525f50505f5050610f0b5ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c80630be200ea1461002d575b5f80fd5b61004061003b366004610e26565b610075565b6040517fffffffff00000000000000000000000000000000000000000000000000000000909116815260200160405180910390f35b73ffffffffffffffffffffffffffffffffffffffff86165f90815262721c08602052604081208054829061014f9060ff7b010000000000000000000000000000000000000000000000000000008204169061ffff7c01000000000000000000000000000000000000000000000000000000009091041660408051610100810182526004848116151582526001808616151560208401526008958616151593830193909352938316151560608201526010831615156080820152908216151560a082015260028216151560c08201529116151560e082015290565b8051909150156102235773ffffffffffffffffffffffffffffffffffffffff8981165f90815262721c0960209081526040808320938b1683526002840190915290205460ff16156101c657507f2b635c8800000000000000000000000000000000000000000000000000000000925061026c915050565b73ffffffffffffffffffffffffffffffffffffffff87165f90815260028201602052604090205460ff161561022157507f2a5cb1c300000000000000000000000000000000000000000000000000000000925061026c915050565b505b8060200151610249576102398a8a8a88886102b4565b1561024957505f915061026c9050565b8154610267908290610100900465ffffffffffff168b898c8c6102d7565b925050505b979650505050505050565b5c90565b5f7fdacd49f6a6c42b45a5c3d195b83b324104542d9147bb8064a39c6a8d23ba9b005460ff16156102ab57505c90565b5080545b919050565b5f6102cd858585856102c58b610594565b63ffffffff16565b9695505050505050565b65ffffffffffff85165f9081527fdddabf5c2ba4d65801ab32cdb63ad695571faeb901010108d1a350518718439e602090815260408083207f2841ea725888be53292047902c89cc990fdbb15dbc2e5b558a6a052c722a0ede90925282206060890151600483019260050191901561039257863b15610392576103628a604001518484848c8c6105c2565b61039257507faca58aa00000000000000000000000000000000000000000000000000000000092506102cd915050565b8960800151156103eb576103a587610682565b6103eb576103bb8a604001518484848c8c6105c2565b6103eb57507fce32f2aa0000000000000000000000000000000000000000000000000000000092506102cd915050565b8473ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff1603610542578960a0015161054257843b15610536575f806104398761073a565b915091508b60c001511561049e5781610499578b60e00151610499576104678c604001518686868e8c6105c2565b61049957507f42d0e0e40000000000000000000000000000000000000000000000000000000094506102cd9350505050565b610533565b81156104e6576104b48c604001518c8c84610762565b61049957507f369c2f4c0000000000000000000000000000000000000000000000000000000094506102cd9350505050565b8b60e00151610533576105018c604001518686868e8c6105c2565b61053357507f42d0e0e40000000000000000000000000000000000000000000000000000000094506102cd9350505050565b50505b505f92506102cd915050565b6105558a604001518484848c8b8b610898565b61058557507fe1f1d02e0000000000000000000000000000000000000000000000000000000092506102cd915050565b505f9998505050505050505050565b610df9600182036105a85750610966919050565b600282036105b957506109d3919050565b506109d3919050565b5f8615610675575f80527f2841ea725888be53292047902c89cc990fdbb15dbc2e5b558a6a052c722a0ede6020527f938cff0dbdc4b4032da5e0e3a4947fb40aba826911a8ad09a80c555fd5830d5b7f938cff0dbdc4b4032da5e0e3a4947fb40aba826911a8ad09a80c555fd5830d5c7fe6367c6c33ddbb3b5b8a8c588253bb03f885a3f85345efae1611865a80acc52361066083838389896109f7565b1561067157600193505050506102cd565b5050505b61026c86868686866109f7565b6040517f89a9c85500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82811660048301525f917f0000000000000000000000000000000000000000000000000000000000000000909116906389a9c85590602401602060405180830381865afa158015610710573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107349190610e92565b92915050565b5f805f805260175f601d853c62ef01005f510361075d57505060205160019060601c5b915091565b5f8415610815575f80527fe91a6628aa83f010ff9afa7f160b18736f245c1821f24ffae38c046526028eb16020527f739a1fa67523b96335a4175253d835d43315604e3ab95d6deb68d9488a6242f17f739a1fa67523b96335a4175253d835d43315604e3ab95d6deb68d9488a6242f27fa731cdb379c53870826417699a62d8514fe9e04ae3343c38d8e6940d1ccb6bca61080083838389896109f7565b156108115760019350505050610890565b5050505b65ffffffffffff84165f9081527f5e58bed0817b31bdcd1d55e32930f39f8107eac1d4c0fd8dbef0c8c7e7389b6f602090815260408083207fe91a6628aa83f010ff9afa7f160b18736f245c1821f24ffae38c046526028eb190925290912060048201916005019061088a83838389896109f7565b93505050505b949350505050565b5f871561094c575f80527f2841ea725888be53292047902c89cc990fdbb15dbc2e5b558a6a052c722a0ede6020527f938cff0dbdc4b4032da5e0e3a4947fb40aba826911a8ad09a80c555fd5830d5b7f938cff0dbdc4b4032da5e0e3a4947fb40aba826911a8ad09a80c555fd5830d5c7fe6367c6c33ddbb3b5b8a8c588253bb03f885a3f85345efae1611865a80acc5236109378383838a8a8a610b1f565b15610948576001935050505061026c565b5050505b61095a878787878787610b1f565b98975050505050505050565b5f806109878561098288875f9182526020526040902060041c90565b610d2c565b509150811561099a576001915050610890565b6109b485610982885f90815262721c066020526040902090565b90925090508180156102cd575060ff81901c6001149695505050505050565b5f84815262721c06602052604081206109ed908590610d2c565b5095945050505050565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526020869052604081205460ff1680610a395750813f5f9081526020869052604090205460ff165b905080610b16575f610a4a85610db8565b90505f5b81811015610b13575f610a618783610dc1565b6040517fb6b3527200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff888116600483015287811660248301529192509082169063b6b3527290604401602060405180830381865afa158015610ad7573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610afb9190610e92565b15610b0a576001935050610b13565b50600101610a4e565b50505b95945050505050565b73ffffffffffffffffffffffffffffffffffffffff82165f9081526020879052604081205460ff1680610b76575073ffffffffffffffffffffffffffffffffffffffff82165f9081526020889052604090205460ff165b80610b905750823f5f9081526020879052604090205460ff165b80610baa5750813f5f9081526020879052604090205460ff165b9050806102cd575f610bbb86610db8565b90505f5b81811015610d20575f610bd28883610dc1565b6040517fb6b3527200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff898116600483015288811660248301529192509082169063b6b3527290604401602060405180830381865afa158015610c48573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c6c9190610e92565b80610d0857506040517fb6b3527200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8881166004830152868116602483015282169063b6b3527290604401602060405180830381865afa158015610ce4573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d089190610e92565b15610d17576001935050610d20565b50600101610bbf565b50509695505050505050565b5f80610d5b837f000000000000000000000000000000000000000000000000000000000000000063ffffffff16565b90508073ffffffffffffffffffffffffffffffffffffffff811660011480610dae57508473ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b9250509250929050565b5f610734825490565b5f610dcc8383610dd3565b9392505050565b5f825f018281548110610de857610de8610eb1565b905f5260205f200154905092915050565b610e01610ede565b565b803573ffffffffffffffffffffffffffffffffffffffff811681146102af575f80fd5b5f805f805f805f60e0888a031215610e3c575f80fd5b87359650610e4c60208901610e03565b9550610e5a60408901610e03565b9450610e6860608901610e03565b9350610e7660808901610e03565b925060a0880135915060c0880135905092959891949750929550565b5f60208284031215610ea2575f80fd5b81518015158114610dcc575f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52605160045260245ffd000000000000000000000000e0a0004dfa318fc38298ae81a666710eadceba5c

Deployed Bytecode

0x608060405234801561000f575f80fd5b5060043610610029575f3560e01c80630be200ea1461002d575b5f80fd5b61004061003b366004610e26565b610075565b6040517fffffffff00000000000000000000000000000000000000000000000000000000909116815260200160405180910390f35b73ffffffffffffffffffffffffffffffffffffffff86165f90815262721c08602052604081208054829061014f9060ff7b010000000000000000000000000000000000000000000000000000008204169061ffff7c01000000000000000000000000000000000000000000000000000000009091041660408051610100810182526004848116151582526001808616151560208401526008958616151593830193909352938316151560608201526010831615156080820152908216151560a082015260028216151560c08201529116151560e082015290565b8051909150156102235773ffffffffffffffffffffffffffffffffffffffff8981165f90815262721c0960209081526040808320938b1683526002840190915290205460ff16156101c657507f2b635c8800000000000000000000000000000000000000000000000000000000925061026c915050565b73ffffffffffffffffffffffffffffffffffffffff87165f90815260028201602052604090205460ff161561022157507f2a5cb1c300000000000000000000000000000000000000000000000000000000925061026c915050565b505b8060200151610249576102398a8a8a88886102b4565b1561024957505f915061026c9050565b8154610267908290610100900465ffffffffffff168b898c8c6102d7565b925050505b979650505050505050565b5c90565b5f7fdacd49f6a6c42b45a5c3d195b83b324104542d9147bb8064a39c6a8d23ba9b005460ff16156102ab57505c90565b5080545b919050565b5f6102cd858585856102c58b610594565b63ffffffff16565b9695505050505050565b65ffffffffffff85165f9081527fdddabf5c2ba4d65801ab32cdb63ad695571faeb901010108d1a350518718439e602090815260408083207f2841ea725888be53292047902c89cc990fdbb15dbc2e5b558a6a052c722a0ede90925282206060890151600483019260050191901561039257863b15610392576103628a604001518484848c8c6105c2565b61039257507faca58aa00000000000000000000000000000000000000000000000000000000092506102cd915050565b8960800151156103eb576103a587610682565b6103eb576103bb8a604001518484848c8c6105c2565b6103eb57507fce32f2aa0000000000000000000000000000000000000000000000000000000092506102cd915050565b8473ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff1603610542578960a0015161054257843b15610536575f806104398761073a565b915091508b60c001511561049e5781610499578b60e00151610499576104678c604001518686868e8c6105c2565b61049957507f42d0e0e40000000000000000000000000000000000000000000000000000000094506102cd9350505050565b610533565b81156104e6576104b48c604001518c8c84610762565b61049957507f369c2f4c0000000000000000000000000000000000000000000000000000000094506102cd9350505050565b8b60e00151610533576105018c604001518686868e8c6105c2565b61053357507f42d0e0e40000000000000000000000000000000000000000000000000000000094506102cd9350505050565b50505b505f92506102cd915050565b6105558a604001518484848c8b8b610898565b61058557507fe1f1d02e0000000000000000000000000000000000000000000000000000000092506102cd915050565b505f9998505050505050505050565b610df9600182036105a85750610966919050565b600282036105b957506109d3919050565b506109d3919050565b5f8615610675575f80527f2841ea725888be53292047902c89cc990fdbb15dbc2e5b558a6a052c722a0ede6020527f938cff0dbdc4b4032da5e0e3a4947fb40aba826911a8ad09a80c555fd5830d5b7f938cff0dbdc4b4032da5e0e3a4947fb40aba826911a8ad09a80c555fd5830d5c7fe6367c6c33ddbb3b5b8a8c588253bb03f885a3f85345efae1611865a80acc52361066083838389896109f7565b1561067157600193505050506102cd565b5050505b61026c86868686866109f7565b6040517f89a9c85500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82811660048301525f917f000000000000000000000000e0a0004dfa318fc38298ae81a666710eadceba5c909116906389a9c85590602401602060405180830381865afa158015610710573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107349190610e92565b92915050565b5f805f805260175f601d853c62ef01005f510361075d57505060205160019060601c5b915091565b5f8415610815575f80527fe91a6628aa83f010ff9afa7f160b18736f245c1821f24ffae38c046526028eb16020527f739a1fa67523b96335a4175253d835d43315604e3ab95d6deb68d9488a6242f17f739a1fa67523b96335a4175253d835d43315604e3ab95d6deb68d9488a6242f27fa731cdb379c53870826417699a62d8514fe9e04ae3343c38d8e6940d1ccb6bca61080083838389896109f7565b156108115760019350505050610890565b5050505b65ffffffffffff84165f9081527f5e58bed0817b31bdcd1d55e32930f39f8107eac1d4c0fd8dbef0c8c7e7389b6f602090815260408083207fe91a6628aa83f010ff9afa7f160b18736f245c1821f24ffae38c046526028eb190925290912060048201916005019061088a83838389896109f7565b93505050505b949350505050565b5f871561094c575f80527f2841ea725888be53292047902c89cc990fdbb15dbc2e5b558a6a052c722a0ede6020527f938cff0dbdc4b4032da5e0e3a4947fb40aba826911a8ad09a80c555fd5830d5b7f938cff0dbdc4b4032da5e0e3a4947fb40aba826911a8ad09a80c555fd5830d5c7fe6367c6c33ddbb3b5b8a8c588253bb03f885a3f85345efae1611865a80acc5236109378383838a8a8a610b1f565b15610948576001935050505061026c565b5050505b61095a878787878787610b1f565b98975050505050505050565b5f806109878561098288875f9182526020526040902060041c90565b610d2c565b509150811561099a576001915050610890565b6109b485610982885f90815262721c066020526040902090565b90925090508180156102cd575060ff81901c6001149695505050505050565b5f84815262721c06602052604081206109ed908590610d2c565b5095945050505050565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526020869052604081205460ff1680610a395750813f5f9081526020869052604090205460ff165b905080610b16575f610a4a85610db8565b90505f5b81811015610b13575f610a618783610dc1565b6040517fb6b3527200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff888116600483015287811660248301529192509082169063b6b3527290604401602060405180830381865afa158015610ad7573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610afb9190610e92565b15610b0a576001935050610b13565b50600101610a4e565b50505b95945050505050565b73ffffffffffffffffffffffffffffffffffffffff82165f9081526020879052604081205460ff1680610b76575073ffffffffffffffffffffffffffffffffffffffff82165f9081526020889052604090205460ff165b80610b905750823f5f9081526020879052604090205460ff165b80610baa5750813f5f9081526020879052604090205460ff165b9050806102cd575f610bbb86610db8565b90505f5b81811015610d20575f610bd28883610dc1565b6040517fb6b3527200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff898116600483015288811660248301529192509082169063b6b3527290604401602060405180830381865afa158015610c48573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c6c9190610e92565b80610d0857506040517fb6b3527200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8881166004830152868116602483015282169063b6b3527290604401602060405180830381865afa158015610ce4573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d089190610e92565b15610d17576001935050610d20565b50600101610bbf565b50509695505050505050565b5f80610d5b837f000000000000000000000000000000000000000000000000000001a20000027763ffffffff16565b90508073ffffffffffffffffffffffffffffffffffffffff811660011480610dae57508473ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b9250509250929050565b5f610734825490565b5f610dcc8383610dd3565b9392505050565b5f825f018281548110610de857610de8610eb1565b905f5260205f200154905092915050565b610e01610ede565b565b803573ffffffffffffffffffffffffffffffffffffffff811681146102af575f80fd5b5f805f805f805f60e0888a031215610e3c575f80fd5b87359650610e4c60208901610e03565b9550610e5a60408901610e03565b9450610e6860608901610e03565b9350610e7660808901610e03565b925060a0880135915060c0880135905092959891949750929550565b5f60208284031215610ea2575f80fd5b81518015158114610dcc575f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52605160045260245ffd

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

000000000000000000000000e0a0004dfa318fc38298ae81a666710eadceba5c

-----Decoded View---------------
Arg [0] : eoaRegistry_ (address): 0xE0A0004Dfa318fc38298aE81a666710eaDCEba5C

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000e0a0004dfa318fc38298ae81a666710eadceba5c


Deployed Bytecode Sourcemap

418:19776:12:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6531:1410;;;;;;:::i;:::-;;:::i;:::-;;;1010:66:13;998:79;;;980:98;;968:2;953:18;6531:1410:12;;;;;;;;6853:57;;;6762:6;6853:57;;;:45;:57;;;;;6968:38;;6762:6;;6956:92;;6968:38;;;;;;7008:39;;;;;;-1:-1:-1;;;;;;;;2858:6:5;4361:16:8;;;4360:23;;17750:116:12;;2713:6:5;4361:16:8;;;4360:23;;-1:-1:-1;;;17877:113:12;2932:6:5;4361:16:8;;;4360:23;;-1:-1:-1;;;18001:131:12;;;;4361:16:8;;;4360:23;;-1:-1:-1;;;18143:130:12;3505:6:5;4361:16:8;;4360:23;;-1:-1:-1;;;18284:134:12;4361:16:8;;;4360:23;;-1:-1:-1;;;18429:101:12;3270:6:5;4361:16:8;;4360:23;;-1:-1:-1;;;18541:129:12;4361:16:8;;4360:23;;-1:-1:-1;;;18693:127:12;-1:-1:-1;17626:1201:12;6956:92;7063:30;;6921:127;;-1:-1:-1;7059:490:12;;;7149:45;;;;7109:37;7149:45;;;:33;:45;;;;;;;;7225;;;;;:39;;;:45;;;;;;;;7221:152;;;-1:-1:-1;7297:61:12;;-1:-1:-1;7290:68:12;;-1:-1:-1;;7290:68:12;7221:152;7391:43;;;;;;;:39;;;:43;;;;;;;;7387:152;;;-1:-1:-1;7461:63:12;;-1:-1:-1;7454:70:12;;-1:-1:-1;;7454:70:12;7387:152;7095:454;7059:490;7564:4;:29;;;7559:194;;7613:71;7627:19;7648:10;7660:6;7668:7;7677:6;7613:13;:71::i;:::-;7609:134;;;-1:-1:-1;1720:10:5;;-1:-1:-1;7704:24:12;;-1:-1:-1;7704:24:12;7609:134;7821:31;;7770:164;;7802:4;;7821:31;;;;;7866:10;7891:2;7908:6;7929:4;7770:18;:164::i;:::-;7763:171;;;;6531:1410;;;;;;;;;;:::o;3690:169:2:-;3825:18;;3690:169::o;4236:360::-;4333:13;212:66:1;4362:36:2;;;4358:232;;;-1:-1:-1;4450:18:2;;4236:360::o;4358:232::-;-1:-1:-1;4548:18:2;;4358:232;4236:360;;;:::o;1183:356:11:-;1374:17;1418:114;1487:10;1499:6;1507:7;1516:6;1418:55;1453:19;1418:34;:55::i;:::-;:114;;:::i;:::-;1403:129;1183:356;-1:-1:-1;;;;;;1183:356:11:o;7947:3784:12:-;19148:53;;;8151:6;19148:53;;;:45;;:53;;;:45;:53;;;19369:75;:83;;;;;8428:30;;;;19230:31;;;;19148:24;19291:33;;19369:83;8424:376;;;3444:20:8;;8478:25:12;8474:316;;8528:127;8543:4;:37;;;8582:16;8600:17;8619:19;8640:10;8652:2;8528:14;:127::i;:::-;8523:253;;-1:-1:-1;8686:71:12;;-1:-1:-1;8679:78:12;;-1:-1:-1;;8679:78:12;8523:253;8814:4;:32;;;8810:378;;;8867:18;8882:2;8867:14;:18::i;:::-;8862:316;;8910:127;8925:4;:37;;;8964:16;8982:17;9001:19;9022:10;9034:2;8910:14;:127::i;:::-;8905:259;;-1:-1:-1;9068:77:12;;-1:-1:-1;9061:84:12;;-1:-1:-1;;9061:84:12;8905:259;9212:4;9202:14;;:6;:14;;;9198:2237;;9237:4;:16;;;9232:2193;;3444:20:8;;9277:27:12;9273:2095;;9329:15;9346:16;9366;9377:4;9366:10;:16::i;:::-;9328:54;;;;9409:4;:29;;;9405:1945;;;9573:10;9568:597;;9761:4;:28;;;9756:383;;9830:129;9845:4;:37;;;9884:16;9902:17;9921:19;9942:10;9954:4;9830:14;:129::i;:::-;9825:284;;-1:-1:-1;10006:68:12;;-1:-1:-1;9999:75:12;;-1:-1:-1;;;;9999:75:12;9825:284;9405:1945;;;10329:10;10325:1003;;;10478:95;10505:4;:37;;;10544:6;10552:10;10564:8;10478:26;:95::i;:::-;10473:243;;-1:-1:-1;10616:69:12;;-1:-1:-1;10609:76:12;;-1:-1:-1;;;;10609:76:12;10325:1003;10924:4;:28;;;10919:383;;10993:129;11008:4;:37;;;11047:16;11065:17;11084:19;11105:10;11117:4;10993:14;:129::i;:::-;10988:284;;-1:-1:-1;11169:68:12;;-1:-1:-1;11162:75:12;;-1:-1:-1;;;;11162:75:12;10988:284;9306:2062;;9273:2095;-1:-1:-1;1720:10:5;;-1:-1:-1;11386:24:12;;-1:-1:-1;;11386:24:12;9232:2193;11450:137;11465:4;:37;;;11504:16;11522:17;11541:19;11562:10;11574:6;11582:4;11450:14;:137::i;:::-;11445:245;;-1:-1:-1;11610:69:12;;-1:-1:-1;11603:76:12;;-1:-1:-1;;11603:76:12;11445:245;-1:-1:-1;1720:10:5;;7947:3784:12;-1:-1:-1;;;;;;;;;7947:3784:12:o;1835:802:11:-;1931:93;1284:1:5;2040:19:11;:50;2036:595;;-1:-1:-1;2113:27:11;;1835:802;-1:-1:-1;1835:802:11:o;2036:595::-;1339:1:5;2161:19:11;:55;2157:474;;-1:-1:-1;2239:32:11;;1835:802;-1:-1:-1;1835:802:11:o;2157:474::-;-1:-1:-1;2588:32:11;;1835:802;-1:-1:-1;1835:802:11:o;11737:1121:12:-;12073:18;12107:32;12103:637;;;12173:57;19148:53;;19369:75;19148:45;19369:83;19230:31;19291:33;19369:83;12464:220;19230:31;19291:33;19369:83;12643:10;12676:7;12464:15;:220::i;:::-;12460:270;;;12711:4;12704:11;;;;;;;12460:270;12141:599;;;12103:637;12757:94;12773:16;12791:17;12810:19;12831:10;12843:7;12757:15;:94::i;17477:143::-;17564:49;;;;;:40;1253:55:13;;;17564:49:12;;;1235:74:13;17541:4:12;;17577:12;17564:40;;;;;;1208:18:13;;17564:49:12;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;17557:56;17477:143;-1:-1:-1;;17477:143:12:o;5681:371:11:-;5742:15;5759:16;5839:4;5833;5826:18;5891:4;5885;5879;5869:8;5857:39;5928:8;5921:4;5915:11;5912:25;5909:127;;-1:-1:-1;;6016:4:11;6010:11;5970:1;;6004:4;6000:22;5909:127;5681:371;;;:::o;14060:1252:12:-;14248:18;14282:32;14278:649;;;14348:57;19824:77;;20069:89;19824:69;20069:97;19930:31;19991:33;20069:97;14651:220;19930:31;19991:33;20069:97;14830:10;14863:7;14651:15;:220::i;:::-;14647:270;;;14898:4;14891:11;;;;;;;14647:270;14316:611;;;14278:649;19824:77;;;14951:50;19824:77;;;:69;;:77;;;:69;:77;;;20069:89;:97;;;;;;506:1:5;19930:31:12;;;19824:24;19991:33;;15211:94;19930:31;19991:33;20069:97;15285:10;15297:7;15211:15;:94::i;:::-;15204:101;;;;;14060:1252;;;;;;;:::o;12864:1190::-;13227:18;13261:32;13257:668;;;13327:57;19148:53;;19369:75;19148:45;19369:83;19230:31;19291:33;19369:83;13618:251;19230:31;19291:33;19369:83;13797:10;13830:8;13860;13618:15;:251::i;:::-;13614:301;;;13896:4;13889:11;;;;;;;13614:301;13295:630;;;13257:668;13942:105;13958:16;13976:17;13995:19;14016:10;14028:8;14038;13942:15;:105::i;:::-;13935:112;12864:1190;-1:-1:-1;;;;;;;;12864:1190:12:o;3090:529:11:-;3261:17;3290;3336:73;3354:6;3362:46;3388:10;3400:7;2178:20:8;2233:24;;;2277:4;2270:21;2343:4;2327:21;;2324:1;2320:29;;2060:304;3362:46:11;3336:17;:73::i;:::-;-1:-1:-1;3317:92:11;-1:-1:-1;3419:29:11;;;;3444:4;3437:11;;;;;3419:29;3486:64;3504:6;3512:37;3538:10;2767:20:8;2926:24;;;2857:36;2970:4;2963:37;3045:4;3029:21;;;2689:377;3486:64:11;3458:92;;-1:-1:-1;3458:92:11;-1:-1:-1;3458:92:11;3575:37;;;;;3604:3;3591:9;:16;;3611:1;3591:21;3560:52;3090:529;-1:-1:-1;;;;;;3090:529:11:o;4018:299::-;4198:17;2926:24:8;;;2857:36;2970:4;2963:37;3045:4;3029:21;;4246:64:11;;4264:6;;3336:17;:73::i;4246:64::-;-1:-1:-1;4227:83:11;4018:299;-1:-1:-1;;;;;4018:299:11:o;15318:915:12:-;15671:25;;;15608:18;15671:25;;;;;;;;;;;;;;:89;;-1:-1:-1;3854:20:8;;15717:43:12;;;;;;;;;;;;;;15671:89;15638:122;;15776:13;15771:456;;15805:30;15838:28;:19;:26;:28::i;:::-;15805:61;;15885:9;15880:337;15904:22;15900:1;:26;15880:337;;;15951:38;16012:25;:19;16035:1;16012:22;:25::i;:::-;16060:53;;;;;:32;1855:15:13;;;16060:53:12;;;1837:34:13;1907:15;;;1887:18;;;1880:43;15951:87:12;;-1:-1:-1;16060:32:12;;;;;;1749:18:13;;16060:53:12;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;16056:147;;;16153:4;16137:20;;16179:5;;;16056:147;-1:-1:-1;15928:3:12;;15880:337;;;;15791:436;15771:456;15318:915;;;;;;;:::o;16239:1119::-;16615:26;;;16556:18;16615:26;;;;;;;;;;;;;;:69;;-1:-1:-1;16658:26:12;;;;;;;;;;;;;;;;;16615:69;:130;;;-1:-1:-1;3854:20:8;;16701:44:12;;;;;;;;;;;;;;16615:130;:190;;;-1:-1:-1;3854:20:8;;16761:44:12;;;;;;;;;;;;;;16615:190;16586:219;;16821:13;16816:536;;16850:30;16883:28;:19;:26;:28::i;:::-;16850:61;;16930:9;16925:417;16949:22;16945:1;:26;16925:417;;;16996:38;17057:25;:19;17080:1;17057:22;:25::i;:::-;17105:54;;;;;:32;1855:15:13;;;17105:54:12;;;1837:34:13;1907:15;;;1887:18;;;1880:43;16996:87:12;;-1:-1:-1;17105:32:12;;;;;;1749:18:13;;17105:54:12;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:133;;;-1:-1:-1;17184:54:12;;;;;:32;1855:15:13;;;17184:54:12;;;1837:34:13;1907:15;;;1887:18;;;1880:43;17184:32:12;;;;;1749:18:13;;17184:54:12;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;17101:227;;;17278:4;17262:20;;17304:5;;;17101:227;-1:-1:-1;16973:3:12;;16925:417;;;;16836:516;16239:1119;;;;;;;;:::o;4898:335:11:-;4978:17;4997;5038:18;5051:4;5038:12;:18;;:::i;:::-;5026:30;-1:-1:-1;5026:30:11;5147:47;;;2007:4:5;5147:47:11;;:79;;;5220:6;5198:28;;:18;:28;;;5147:79;5132:94;;5016:217;4898:335;;;;;:::o;8911:115:3:-;8974:7;9000:19;9008:3;4350:18;;4268:107;9368:156;9442:7;9492:22;9496:3;9508:5;9492:3;:22::i;:::-;9484:31;9368:156;-1:-1:-1;;;9368:156:3:o;4717:118::-;4784:7;4810:3;:11;;4822:5;4810:18;;;;;;;;:::i;:::-;;;;;;;;;4803:25;;4717:118;;;;:::o;-1:-1:-1:-;;;:::i;:::-;:::o;14:196:13:-;82:20;;142:42;131:54;;121:65;;111:93;;200:1;197;190:12;215:616;328:6;336;344;352;360;368;376;429:3;417:9;408:7;404:23;400:33;397:53;;;446:1;443;436:12;397:53;482:9;469:23;459:33;;511:38;545:2;534:9;530:18;511:38;:::i;:::-;501:48;;568:38;602:2;591:9;587:18;568:38;:::i;:::-;558:48;;625:38;659:2;648:9;644:18;625:38;:::i;:::-;615:48;;682:39;716:3;705:9;701:19;682:39;:::i;:::-;672:49;;768:3;757:9;753:19;740:33;730:43;;820:3;809:9;805:19;792:33;782:43;;215:616;;;;;;;;;;:::o;1320:277::-;1387:6;1440:2;1428:9;1419:7;1415:23;1411:32;1408:52;;;1456:1;1453;1446:12;1408:52;1488:9;1482:16;1541:5;1534:13;1527:21;1520:5;1517:32;1507:60;;1563:1;1560;1553:12;1934:184;1986:77;1983:1;1976:88;2083:4;2080:1;2073:15;2107:4;2104:1;2097:15;2123:184;2175:77;2172:1;2165:88;2272:4;2269:1;2262:15;2296:4;2293:1;2286:15

Block Transaction Gas Used Reward
view all blocks produced

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

Validator Index Block Amount
View All Withdrawals

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

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