ETH Price: $2,970.66 (-4.12%)
 

Overview

ETH Balance

0 ETH

ETH Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

Please try again later

View more zero value Internal Transactions in Advanced View mode

Advanced mode:

Cross-Chain Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
ThreeDNSRegControl

Compiler Version
v0.8.18+commit.87f61d96

Optimization Enabled:
Yes with 200 runs

Other Settings:
paris EvmVersion
// solhint-disable func-name-mixedcase

// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;

/// External References ---------------------------------------------------------------------------

import {Initializable} from "openzeppelin-upgradeable/proxy/utils/Initializable.sol";
import {IERC20Upgradeable as IERC20} from "openzeppelin-upgradeable/token/ERC20/IERC20Upgradeable.sol";

/// Internal References ---------------------------------------------------------------------------

import {IThreeDNSAuthority} from "src/utils/access/interfaces/IThreeDNSAuthority.sol";
import {ThreeDNSAccessControlled} from "src/utils/access/ThreeDNSAccessControlled.sol";

import {CommitmentOrderflow} from "src/regcontrol/modules/CommitmentOrderflow.sol";
import {DomainController} from "src/regcontrol/modules/DomainController.sol";
import {PaymentProcessor} from "src/regcontrol/modules/PaymentProcessor.sol";
import {RegistrarController} from "src/regcontrol/modules/RegistrarController.sol";

import {Multicall} from "src/regcontrol/modules/Multicall.sol";

import {RegControlStorage} from "src/regcontrol/storage/Storage.sol";
import {ReentrancyGuardStorage} from "src/utils/access/storage/ReentrancyGuardStorage.sol";

/// Diamond Params --------------------------------------------------------------------------------

import {IDiamondCut} from "src/regcontrol/interfaces/diamond/IDiamondCut.sol";
import {LibDiamond} from "src/regcontrol/libraries/LibDiamond.sol";

/// Errors ----------------------------------------------------------------------------------------

error ThreeDNSRegControl_accessDenied();

contract ThreeDNSRegControl is
    Initializable,
    ThreeDNSAccessControlled
    // CommitmentOrderflow              -> Moved into diamond facets
    // CommitmentOrderflowExtensions    -> Moved into diamond facets
    // DomainController                 -> Moved into diamond facets
    // RegistrarController,             -> Moved into diamond facets
    // Multicall                        -> Moved into diamond facets
{

    /// Initialization Functions ------------------------------------------------------------------

    /// @dev Disable initializers for template contracts, as they are not meant to be initialized.
    constructor() {
        _disableInitializers();
    }
    
    function initialize(
        IThreeDNSAuthority _authority,
        address resolver_,
        string memory domainName_,
        string memory domainVersion_,
        uint64 chainId_,
        IERC20 usdc_
    ) public initializer {
        ThreeDNSAccessControlled.__ThreeDNSAccessControlled_init(_authority);

        // Moved into diamond facets
        // CommitmentOrderflow.__CommitmentOrderflow_init(domainName_, domainVersion_, chainId_, usdc_);

        ReentrancyGuardStorage.initialize();
        RegControlStorage.setPrimaryResolver(resolver_);
    }

    /// @note Have done 5 initializations
    //   next -> function initializeV6(...) public reinitializer(5) { }

    /// Diamond Fallback Functions ----------------------------------------------------------------

    // Find facet for function that is called and execute the
    // function if a facet is found and return any value.
    fallback() external payable {
        LibDiamond.DiamondStorage storage ds;
        bytes32 position = LibDiamond.DIAMOND_STORAGE_POSITION;
        assembly {
            ds.slot := position
        }
        address facet = ds.selectorToFacetAndPosition[msg.sig].facetAddress;
        require(facet != address(0), "Diamond: Function does not exist");
        assembly {
            calldatacopy(0, 0, calldatasize())
            let result := delegatecall(gas(), facet, 0, calldatasize(), 0, 0)
            returndatacopy(0, 0, returndatasize())
            switch result
            case 0 { revert(0, returndatasize()) }
            default { return(0, returndatasize()) }
        }
    }

    receive() external payable {
        // require(msg.sender == address(WETH));
    }
    
    /// Diamond Management Functions --------------------------------------------------------------

    function diamondCut(IDiamondCut.FacetCut[] calldata _diamondCut, address _init, bytes calldata _calldata) external {
        _callerIsProxyAdmin__validate();

        LibDiamond.diamondCut(_diamondCut, _init, _calldata);
    }

    function trackInterface(bytes4 interfaceId_, bool enabled_) external {
        // Run access control validation
        _callerIsProxyAdmin__validate();

        // Track interface
        LibDiamond.diamondStorage().supportedInterfaces[interfaceId_] = enabled_;
    }

    /// ERC165 Functions --------------------------------------------------------------------------

    /// @dev ERC165 introspection support.
    function supportsInterface(bytes4 interfaceId_) public view returns (bool) {
        return LibDiamond.diamondStorage().supportedInterfaces[interfaceId_];
    }

    /// Access Control Functions ------------------------------------------------------------------

    function _callerIsProxyAdmin__validate() internal view {
        if (!authority().isRole(authority().ROLE__PROXY_ADMIN(), msg.sender)) {
            revert ThreeDNSRegControl_accessDenied();
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol)

pragma solidity ^0.8.2;

import "../../utils/AddressUpgradeable.sol";

/**
 * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
 * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
 * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
 * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
 *
 * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
 * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
 * case an upgrade adds a module that needs to be initialized.
 *
 * For example:
 *
 * [.hljs-theme-light.nopadding]
 * ```solidity
 * contract MyToken is ERC20Upgradeable {
 *     function initialize() initializer public {
 *         __ERC20_init("MyToken", "MTK");
 *     }
 * }
 *
 * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
 *     function initializeV2() reinitializer(2) public {
 *         __ERC20Permit_init("MyToken");
 *     }
 * }
 * ```
 *
 * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
 * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
 *
 * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
 * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
 *
 * [CAUTION]
 * ====
 * Avoid leaving a contract uninitialized.
 *
 * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
 * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
 * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * /// @custom:oz-upgrades-unsafe-allow constructor
 * constructor() {
 *     _disableInitializers();
 * }
 * ```
 * ====
 */
abstract contract Initializable {
    /**
     * @dev Indicates that the contract has been initialized.
     * @custom:oz-retyped-from bool
     */
    uint8 private _initialized;

    /**
     * @dev Indicates that the contract is in the process of being initialized.
     */
    bool private _initializing;

    /**
     * @dev Triggered when the contract has been initialized or reinitialized.
     */
    event Initialized(uint8 version);

    /**
     * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
     * `onlyInitializing` functions can be used to initialize parent contracts.
     *
     * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
     * constructor.
     *
     * Emits an {Initialized} event.
     */
    modifier initializer() {
        bool isTopLevelCall = !_initializing;
        require(
            (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
            "Initializable: contract is already initialized"
        );
        _initialized = 1;
        if (isTopLevelCall) {
            _initializing = true;
        }
        _;
        if (isTopLevelCall) {
            _initializing = false;
            emit Initialized(1);
        }
    }

    /**
     * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
     * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
     * used to initialize parent contracts.
     *
     * A reinitializer may be used after the original initialization step. This is essential to configure modules that
     * are added through upgrades and that require initialization.
     *
     * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
     * cannot be nested. If one is invoked in the context of another, execution will revert.
     *
     * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
     * a contract, executing them in the right order is up to the developer or operator.
     *
     * WARNING: setting the version to 255 will prevent any future reinitialization.
     *
     * Emits an {Initialized} event.
     */
    modifier reinitializer(uint8 version) {
        require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
        _initialized = version;
        _initializing = true;
        _;
        _initializing = false;
        emit Initialized(version);
    }

    /**
     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
     * {initializer} and {reinitializer} modifiers, directly or indirectly.
     */
    modifier onlyInitializing() {
        require(_initializing, "Initializable: contract is not initializing");
        _;
    }

    /**
     * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
     * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
     * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
     * through proxies.
     *
     * Emits an {Initialized} event the first time it is successfully executed.
     */
    function _disableInitializers() internal virtual {
        require(!_initializing, "Initializable: contract is initializing");
        if (_initialized != type(uint8).max) {
            _initialized = type(uint8).max;
            emit Initialized(type(uint8).max);
        }
    }

    /**
     * @dev Returns the highest version that has been initialized. See {reinitializer}.
     */
    function _getInitializedVersion() internal view returns (uint8) {
        return _initialized;
    }

    /**
     * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
     */
    function _isInitializing() internal view returns (bool) {
        return _initializing;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20Upgradeable {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 amount) external returns (bool);
}

// SPDX-License-Identifier: BUSL-1.1

pragma solidity ^0.8.18;

interface IThreeDNSAuthority {

    /*//////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

    /// @notice Event raised when a new gateway URL is set.
    event OperatorChanged(address previousOperator, address newOperator);

    event RoleAdded(bytes32 indexed role, address indexed manager);
    event RoleRemoved(bytes32 indexed role, address indexed manager);

    /*//////////////////////////////////////////////////////////////
                    External Administration Functions
    //////////////////////////////////////////////////////////////*/

    function setRole(bytes32 _role, address _sender) external;
    function removeRole(bytes32 _role, address _sender) external;
    function isRole(bytes32 _role, address _sender) external view returns (bool);

    /*//////////////////////////////////////////////////////////////
                        External View Functions
    //////////////////////////////////////////////////////////////*/

    function operator() external view returns (address);

    /*//////////////////////////////////////////////////////////////
                        External View Functions
    //////////////////////////////////////////////////////////////*/

    /// @dev Super Admin
    function ROLE__OPERATOR() external view returns (bytes32);

    /// @dev Management Admin
    function ROLE__MANAGER_ADMIN() external view returns (bytes32);

    /// @dev Management roles
    function ROLE__DEPLOYMENT_MANAGER() external view returns (bytes32);
    function ROLE__SIGNER_MANAGER() external view returns (bytes32);
    function ROLE__ISSUER_MANAGER() external view returns (bytes32);

    /// @dev Auditor roles
    function ROLE__AUDITOR() external view returns (bytes32);

    /// @dev Constant specifing action specific roles
    function ROLE__DEPLOYER() external view returns (bytes32);
    function ROLE__PROXY_ADMIN() external view returns (bytes32);
    function ROLE__REGISTRAR_ADMIN() external view returns (bytes32);
    function ROLE__SIGNER() external view returns (bytes32);
    function ROLE__ISSUER() external view returns (bytes32);
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;

/// External References ---------------------------------------------------------------------------

import {Initializable} from "openzeppelin-upgradeable/proxy/utils/Initializable.sol";

/// Internal References ---------------------------------------------------------------------------

// import {IThreeDNSAccessControlled} from "./interfaces/IThreeDNSAccessControlled.sol";
import {IThreeDNSAuthority} from "./interfaces/IThreeDNSAuthority.sol";
import {IThreeDNSAccessControlled} from "./interfaces/IThreeDNSAccessControlled.sol";

import {
    AccessControlledStorage as Storage
} from "./storage/AccessControlledStorage.sol";

/// Errors ---------------------------------------------------------------------------

error ThreeDNSAccessControlled_unauthorized(address);
error ThreeDNSAccessControlled_invalidAuthority();

contract ThreeDNSAccessControlled is 
    Initializable,
    IThreeDNSAccessControlled
{
    /// Modifiers ------------------------------------------------------------------------------

    modifier onlyOperator() {
        _callerIsOperator__validate();
        _;
    }

    /// @dev Included in AccessControlEnumerable
    // modifier onlyRole(bytes32 _role)

    /// Initializer ----------------------------------------------------------------------------

    function __ThreeDNSAccessControlled_init(IThreeDNSAuthority _newAuthority) internal onlyInitializing {
        // Set the authority
        _changeAuthority(_newAuthority);
    }

    /// Accessor Function -------------------------------------------------------------------------

    function authority() 
    public view 
    override 
    returns (IThreeDNSAuthority) 
    {
        return Storage.authority();
    }

    /// External Admin Functions ==================================================================

    function changeAuthority(IThreeDNSAuthority _newAuthority) external override onlyOperator {
        _changeAuthority(_newAuthority);
    }

    /// Internal Admin Functions ==================================================================

    function _setInitialAuthority(IThreeDNSAuthority _newAuthority) internal {
        if (address(Storage.authority()) != address(0)) 
            revert ThreeDNSAccessControlled_invalidAuthority();
        _changeAuthority(_newAuthority);
    }

    /// Private Admin Functions -------------------------------------------------------------------
    
    function _changeAuthority(IThreeDNSAuthority _newAuthority) private {
        if (address(_newAuthority) == address(0)) 
            revert ThreeDNSAccessControlled_invalidAuthority();

        // Get the current authority contract
        IThreeDNSAuthority _oldAuthority = Storage.authority();

        // Set the new authority contract
        Storage.changeAuthority(_newAuthority);

        // Log the mutation
        emit AuthorityChanged(_oldAuthority, _newAuthority);
    }

    /// Access Control Functions ==================================================================

    function _callerIsOperator__validate() internal view {
        if (!_isOperator()) 
            revert ThreeDNSAccessControlled_unauthorized(msg.sender);
    }

    /// Administrative Action Validators ==========================================================

    function _isOperator() internal view returns (bool) {
        return Storage.authority().operator() == msg.sender;
    }
}

// solhint-disable func-name-mixedcase

// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;

/// External References ---------------------------------------------------------------------------

import {Initializable} from "openzeppelin-upgradeable/proxy/utils/Initializable.sol";
import {IERC20Upgradeable as IERC20} from "openzeppelin-upgradeable/token/ERC20/IERC20Upgradeable.sol";

/// Internal References ---------------------------------------------------------------------------

import {ICommitmentOrderflow} from "src/regcontrol/interfaces/ICommitmentOrderflow.sol";

import {ThreeDNSAccessControlled} from "src/utils/access/ThreeDNSAccessControlled.sol";
import {PaymentProcessor} from "src/regcontrol/modules/PaymentProcessor.sol";
import {RegistrationAuthorizor} from "src/regcontrol/modules/types/RegistrationAuthorizor.sol";
import {ReentrancyGuardDiamond} from "src/utils/access/ReentrancyGuardDiamond.sol";
import {SponsorShieldDiamond} from "src/utils/access/SponsorShieldDiamond.sol";

import {Registry} from "src/regcontrol/modules/types/Registry.sol";

import {BytesUtils} from "src/regcontrol/libraries/BytesUtils.sol";
import {CommitmentStorage as Storage} from "src/regcontrol/storage/Storage.sol";
import {Datastructures} from "src/regcontrol/storage/Datastructures.sol";

import {IWETH} from "src/utils/interfaces/IWETH.sol";

/// Errors -------------------------------------------------------------------------------------

error CommitmentOrderflow_invalidCommitter();
error CommitmentOrderflow_accessDenied();
error CommitmentOrderflow_transferDoesNotExist();

error CommitmentOrderflow_notCalledThroughMulticall();

error CommitmentOrderflow_invalidCommitmentType(Datastructures.CommitmentType commitmentType_);
error CommitmentOrderflow_invalidDuration(uint64 duration_);
error CommitmentOrderflow_invalidPaymentType(Datastructures.PaymentType paymentType_);
error CommitmentOrderflow_invalidNonce();

error CommitmentOrderflow_commitmentTypeNonRefundable(Datastructures.CommitmentType commitmentType_);
error CommitmentOrderflow_commitmentDoesNotExist(bytes32 commitmentHash_);
error CommitmentOrderflow_commitmentAlreadyExists(bytes32 commitmentHash_);

error CommitmentOrderflow_commitmentNotRefundable(bytes32 commitmentHash_);
error CommitmentOrderflow_commitmentNotRevokable(bytes32 commitmentHash_, uint64 revokableAt_);

/// Contract -----------------------------------------------------------------------------------
contract CommitmentOrderflow is
    Initializable,
    ICommitmentOrderflow,

    RegistrationAuthorizor,
    PaymentProcessor,
    Registry,

    // Access Control
    ThreeDNSAccessControlled,
    ReentrancyGuardDiamond,
    SponsorShieldDiamond 
{
    /// Constants ------------------------------------------------------------------------------

    address private constant WETH = 0x4200000000000000000000000000000000000006;

    /// Initialization Functions ==================================================================

    function __CommitmentOrderflow_init(string memory domainName_, string memory domainVersion_, uint64 chainId_, IERC20 usdc_)
        internal
        onlyInitializing
    {
        // Initialize the RegistrationAuthorizor contract
        RegistrationAuthorizor.__RegistrationAuthorizor_init(domainName_, domainVersion_, chainId_);
        PaymentProcessor.__PaymentProcessor_init(usdc_);
        
        ReentrancyGuardDiamond.__ReentrancyGuard_init();
        SponsorShieldDiamond.__SponsorShield_init();

        Storage.initialize();
    }

    /// Purchase Orderflows -----------------------------------------------------------------------

    function validateCommitmentV2(
        bytes calldata fqdn_,
        address registrant_,
        bytes32 nonce_,
        Datastructures.RegistrationRequest memory req_
    ) public view returns (bytes32 secretHash_) {
        // Validate the commitment
        secretHash_ = _commitment__validate(fqdn_, registrant_, nonce_, req_);

        // Prepare the commitment
        _twoPhase__validateMake(_twoPhase__prepare(req_, secretHash_));

        // Return the secret hash
        return secretHash_;
    }

    function makeCommitmentV2(
        bytes32 secretHash_,
        Datastructures.RegistrationRequest memory req_,
        Datastructures.AuthorizationSignature memory sig_,
        address committer_
    ) public payable {
        // If sender is not the committer, verify this is being called in a permit flow
        if (msg.sender != committer_) {
            // Track and validate the sponsored action
            _trackSponsoredPayment(
                committer_,
                uint256(req_.registrationPayment.paymentType), 
                req_.registrationPayment.amount + req_.servicePayment.amount
            );
        }

        // Verify this is only being called in a nonReentrant context
        if (!_reentrancyGuardEntered()) 
            revert CommitmentOrderflow_notCalledThroughMulticall();

        // Prepare the commitment
        bytes32 commitmentHash_ = _twoPhase__prepare(req_, secretHash_);

        // Validate commitment type is not offchain
        if (_isOffchainCommitment(req_.commitmentType)) {
            revert CommitmentOrderflow_invalidCommitmentType(req_.commitmentType);
        }

        // Validate the commitment
        _twoPhase__validateMake(commitmentHash_);

        // Verify the commitment
        _commitment__verify(commitmentHash_, sig_);

        // Handle the payment
        _handlePayment(req_.registrationPayment, true, committer_);
        if (req_.servicePayment.amount > 0) _handlePayment(req_.servicePayment, true, committer_);

        // Handle and store the commitment
        uint64 revocableAt_ = _commitment__store(commitmentHash_, req_.commitmentType, committer_);

        // Emit the event
        emit PendingCommitment(
            commitmentHash_,
            revocableAt_,
            msg.sender,
            req_.registrationPayment,
            req_.servicePayment,
            sig_.v,
            sig_.r,
            sig_.s
        );
    }

    function processCommitmentV2(  
        bytes calldata fqdn_,
        address registrant_,
        bytes32 nonce_,
        Datastructures.RegistrationRequest calldata req_,
        uint64 customDuration_
    ) public {
        // Run access control check
        _callerIsIssuer__validate();

        // Validate, prepare, and process the commitment
        bytes32 commitmentHash_ = _commitment__process(_twoPhase__prepare(req_, _commitment__validate(fqdn_, registrant_, nonce_, req_)));

        if (customDuration_ > req_.duration) {
            revert CommitmentOrderflow_invalidDuration(customDuration_);
        }

        bytes32 tld_;
        if(_isRegistrationCommitment(req_.commitmentType, false)) {
            // Register the domain
            (, tld_) = _createRegistration(
                fqdn_, registrant_, 
                _setTraderTokenizationTier(0, _isTraderTokenization(req_.commitmentType)), 
                customDuration_
            );
        } else if (_isRenewalCommitment(req_.commitmentType, false)) {
            // Parse the label from the fqdn
            (, bytes32 labelHash_, uint256 offset_) = BytesUtils.readAndReturnLabel(fqdn_, 0);

            // Parse the tld from the fqdn
            tld_ = BytesUtils.namehash(fqdn_, offset_);

            // Extend the registration
            _extendRegistration(labelHash_, tld_, customDuration_);
        } else if (_isTransferCommitment(req_.commitmentType)) {
            // Parse the label from the fqdn
            (, bytes32 labelHash_, uint256 offset_) = BytesUtils.readAndReturnLabel(fqdn_, 0);

            // Parse the tld from the fqdn
            tld_ = BytesUtils.namehash(fqdn_, offset_);

            // Calculate the node
            bytes32 node_ = _calculateNode(labelHash_, tld_);

            // Track the transfer so it can be completed / claimed later
            Storage.setDomainTransferFlag(registrant_, node_, customDuration_, _isTraderTokenization(req_.commitmentType));
        } else {
            revert CommitmentOrderflow_invalidCommitmentType(req_.commitmentType);
        }

        // Move the payment
        _handlePayout(req_.registrationPayment, _getPayoutAddress(tld_));
        if (req_.servicePayment.amount > 0) _handlePayout(req_.servicePayment, _getPayoutAddress(0x0));

        // Emit the event
        emit ProcessCommitment(commitmentHash_, msg.sender);
    }

    function refundCommitment(Datastructures.RegistrationRequest calldata req_, bytes32 secretHash_) external {
        // Run access control check
        _callerIsIssuer__validate();

        // Prepare the commitment
        bytes32 commitmentHash_ = _twoPhase__prepare(req_, secretHash_);

        // Verify the action
        _twoPhase__validateRefund(commitmentHash_);

        // Proccess the refund
        address committer_ = _commitment__refund(commitmentHash_, req_);

        // Emit the event
        emit RefundCommitment(
            commitmentHash_, msg.sender, committer_, req_.commitmentType, req_.registrationPayment, req_.servicePayment
        );
    }

    function revokeCommitment(Datastructures.RegistrationRequest calldata req_, bytes32 secretHash_) external {
        // Prepare the commitment
        bytes32 commitmentHash_ = _twoPhase__prepare(req_, secretHash_);

        // Verify the action
        _twoPhase__validateRevoke(commitmentHash_);

        // Proccess the refund
        address committer_ = _commitment__refund(commitmentHash_, req_);

        // Emit the event
        emit RevokeCommitment(
            commitmentHash_, committer_, req_.commitmentType, req_.registrationPayment, req_.servicePayment
        );
    }

    function processOffchainCommitment(
        bytes calldata fqdn_, 
        address registrant_, 
        uint64 duration_, 
        Datastructures.CommitmentType commitmentType_,
        Datastructures.AuthorizationSignature memory sig_
    ) external {
        // Calculate the node
        bytes32 node_ = _calculateNode(fqdn_);

        // Validate the request
        _offchainCommitment__validate(node_, registrant_, duration_, commitmentType_, sig_);

        if (_isRegistrationCommitment(commitmentType_, true)) {
            // Create the registration
            _createRegistration(
                fqdn_, registrant_, 
                _setTraderTokenizationTier(0, _isTraderTokenization(commitmentType_)), 
                duration_
            );
        
            // Lock the domain 
            _lockRegistration(node_, 30 * 24 * 60 * 60);

            // Emit the event
            emit IssuedDomainName(node_, msg.sender);
        } else if (_isRenewalCommitment(commitmentType_, true)) {
            // Parse the label from the fqdn
            (, bytes32 labelHash_, uint256 offset_) = BytesUtils.readAndReturnLabel(fqdn_, 0);

            // Parse the tld from the fqdn
            bytes32 tld_ = BytesUtils.namehash(fqdn_, offset_);

            // Extend the registration
            _extendRegistration(labelHash_, tld_, duration_);

            // If the renewal is a trader tokenization, downgrade the registration to the trader tier
            if (_isTraderTokenization(commitmentType_)) {
                // TODO: Implement downgrade
                // _downgradeTraderTokenizationTier(labelHash_, tld_);
                revert CommitmentOrderflow_invalidCommitmentType(commitmentType_);
            }
        } else {
            revert CommitmentOrderflow_invalidCommitmentType(commitmentType_);
        }
    }

    function issueTransferredDomainName(
        bytes calldata fqdn_,
        address registrant_
    ) external {
        bytes32 node_ = _calculateNode(fqdn_);

        // Validate the request
        _transferCommitment__validate(node_, registrant_);

        (uint64 duration_, bool isTrader_) = Storage.getDomainTransferFlag(registrant_, node_);

        // Create the registration
        _createRegistration(
            fqdn_, registrant_, 
            _setTraderTokenizationTier(0, isTrader_), 
            duration_
        );

        // Remove the transfer flag
        Storage.deleteDomainTransferFlag(registrant_, node_);
    }

    /// Access Control Functions ==================================================================

    function _callerIsIssuer__validate() internal view {
        if (!_isValidIssuer(msg.sender)) {
            revert CommitmentOrderflow_accessDenied();
        }
    }

    /// Validation Functions ----------------------------------------------------------------------

    function _commitment__validate(
        bytes calldata fqdn_,
        address registrant_,
        bytes32 nonce_,
        Datastructures.RegistrationRequest memory req_
    ) internal view returns (bytes32 secretHash_) {
        bytes32 tld_;
        bytes32 node_;
        
        // Validate the registration relative to the commitment type
        if(_isRegistrationCommitment(req_.commitmentType, false) || _isTransferCommitment(req_.commitmentType)) {
            bytes memory label_;
            (label_, tld_) = _createRegistration__validate(fqdn_, registrant_, req_.duration);

            // Calculate the target node
            node_ = _calculateNode(label_, tld_);
        } else if (_isRenewalCommitment(req_.commitmentType, false)) {
            // Parse the label from the fqdn
            (, bytes32 labelHash_, uint256 offset_) = BytesUtils.readAndReturnLabel(fqdn_, 0);

            // Parse the tld from the fqdn
            tld_ = BytesUtils.namehash(fqdn_, offset_);

            // Validate the renewal
            _extendRegistration__validate(labelHash_, tld_, req_.duration);

            // Calculate the node
            node_ = _calculateNode(labelHash_, tld_);
        } else {
            revert CommitmentOrderflow_invalidCommitmentType(req_.commitmentType);
        }

        // Validate the request
        _validateRegistrationRequest(tld_, req_);

        // Validate nonce is not null nonce
        if (nonce_ == NULL_NONCE) 
            revert CommitmentOrderflow_invalidNonce();

        // Build the secret
        Datastructures.RegistrationSecret memory secret_;
        secret_.registrant = registrant_;
        secret_.node = node_;
        secret_.nonce = nonce_;

        // Calculate the secret hash
        return _calculateSecretHash(secret_);
    }

    bytes32 constant private NULL_NONCE = 0xf490de2920c8a35fabeb13208852aa28c76f9be9b03a4dd2b3c075f7a26923b4;

    function _offchainCommitment__validate(
        bytes32 node_,
        address registrant_,
        uint64 duration_,
        Datastructures.CommitmentType commitmentType_,
        Datastructures.AuthorizationSignature memory sig_
    ) internal view {
        // Run access control check
        _callerIsIssuer__validate();

        // Validate the commitment type
        if (!_isOffchainCommitment(commitmentType_)) {
            revert CommitmentOrderflow_invalidCommitmentType(commitmentType_);
        }

        // Build the issue domain request
        Datastructures.RegistrationRequest memory req_;
        req_.commitmentType = commitmentType_;
        req_.duration = duration_;
                
        // Build the secret
        Datastructures.RegistrationSecret memory secret_;
        secret_.registrant = registrant_;
        secret_.node = node_;
        secret_.nonce = NULL_NONCE;

        // Build and verify the commitment hash
        _commitment__verify(
            _twoPhase__prepare(req_, _calculateSecretHash(secret_)), 
            sig_
        );
    }    

    function _transferCommitment__validate(bytes32 node_, address registrant_) internal view {
        // Run access control check
        _callerIsIssuer__validate();

        // Confirm that the registrant has a transfer flag enabled for the node
        if (!Storage.hasDomainTransferFlag(registrant_, node_))
            revert CommitmentOrderflow_transferDoesNotExist();
    }    

    function _commitment__verify(bytes32 commitmentHash_, Datastructures.AuthorizationSignature memory sig_)
        internal
        view
    {
        // Build the RegistrationAuthorization struct
        RegistrationAuthorization memory authorization_;
        authorization_.commitmentHash_ = commitmentHash_;
        authorization_.issuedAt = sig_.issuedAt;
        authorization_.expiresAt = sig_.expiresAt;

        // Validate the signature
        _validateSignature(authorization_, sig_.v, sig_.r, sig_.s);
    }

    function _commitment__store(
        bytes32 commitmentHash_,
        Datastructures.CommitmentType commitmentType_,
        address committer_
    ) private returns (uint64 revocableAt_) {
        // Calculate recovableAt from COMMITMENT_HALF_LIFE
        revocableAt_ = uint64(block.timestamp + Storage.COMMITMENT_HALF_LIFE());

        // Store the commitment
        Storage.setCommitmentData(commitmentHash_, committer_, revocableAt_);
    }

    function _commitment__process(bytes32 commitmentHash_) private returns (bytes32) {
        // Get the commitment data
        (address committer_, uint64 revokableAt_) = Storage.getCommitmentData(commitmentHash_);

        // Validate the commitment
        if (committer_ == address(0) || revokableAt_ == 0) {
            revert CommitmentOrderflow_commitmentDoesNotExist(commitmentHash_);
        }

        // Remove the commitment
        Storage.deleteCommitment(commitmentHash_);

        return commitmentHash_;
    }

    function _commitment__refund(bytes32 commitmentHash_, Datastructures.RegistrationRequest calldata req_)
        private
        returns (address recipient_)
    {
        // Get the commitment data
        (address committer_, uint64 revokableAt_) = Storage.getCommitmentData(commitmentHash_);

        // Validate the commitment
        if (committer_ == address(0) || revokableAt_ == 0) {
            revert CommitmentOrderflow_commitmentDoesNotExist(commitmentHash_);
        }

        // Remove the commitment
        Storage.deleteCommitment(commitmentHash_);

        // Refund the registration payment & service payment
        if (_isTransferCommitment(req_.commitmentType)) {
            _handlePayout(req_.registrationPayment, _getPayoutAddress(0x0));
        } else {
            _handlePayout(req_.registrationPayment, committer_);
        }
        if (req_.servicePayment.amount > 0) _handlePayout(req_.servicePayment, committer_);

        return committer_;
    }

    /// Two Phase Helpers ///

    function _twoPhase__prepare(Datastructures.RegistrationRequest memory req_, bytes32 secretHash_)
        private
        pure
        returns (bytes32 commitmentHash_)
    {
        // Build the secret hash & the commitment hash
        //
        // The secret hash shields the registration details from the public
        // and the commitment hash binds the payment to the secret hash.
        // The commitment hash is valid until the commitment is either
        // processed, extended, or revoked.
        //
        // The commitment hash half life is calculated when the commitment
        // is made ~ it is valid till block.timestamp + COMMITMENT_HALF_LIFE.
        Datastructures.InternalCommitment memory commitment_;
        commitment_.request = req_;
        commitment_.secretHash_ = secretHash_;

        return _calculateCommitmentHash(commitment_);
    }

    function _twoPhase__validateMake(bytes32 commitmentHash_) private view {
        (address committer_, uint64 revokableAt_) = Storage.getCommitmentData(commitmentHash_);
        // Validate the uniqueness of the commitment
        if (committer_ != address(0) || revokableAt_ != 0) {
            revert CommitmentOrderflow_commitmentAlreadyExists(commitmentHash_);
        }
    }

    function _twoPhase__validateRefund(bytes32 commitmentHash_) private view {
        // Get the commitment data
        (address committer_, uint64 revokableAt_) = Storage.getCommitmentData(commitmentHash_);

        // Validate the commitment exists
        if (committer_ == address(0) || revokableAt_ == 0) {
            revert CommitmentOrderflow_commitmentDoesNotExist(commitmentHash_);
        }

        // Verify the commitment has not expired, if so, let the user revoke it
        if (block.timestamp >= revokableAt_) {
            revert CommitmentOrderflow_commitmentNotRefundable(commitmentHash_);
        }
    }

    function _twoPhase__validateRevoke(bytes32 commitmentHash_) private view {
        // Get the commitment data
        (address committer_, uint64 revokableAt_) = Storage.getCommitmentData(commitmentHash_);

        // Validate the commitment exists
        if (committer_ == address(0) || revokableAt_ == 0) {
            revert CommitmentOrderflow_commitmentDoesNotExist(commitmentHash_);
        }

        // Verify the commitment has expired, if not, reject the revocation
        if (block.timestamp < revokableAt_) {
            revert CommitmentOrderflow_commitmentNotRevokable(commitmentHash_, revokableAt_);
        }
    }

    /// Accessor Functions ------------------------------------------------------------------------

    /// ... ///
    
    /// Helper Functions --------------------------------------------------------------------------

    function _setTraderTokenizationTier(uint32 controlBitmap_, bool isTrader_) internal returns (uint32) {
        return isTrader_ ? controlBitmap_ | 1 << 16 : controlBitmap_; // & ~(1 << 16);
    }

    function _isRegistrationCommitment(Datastructures.CommitmentType commitmentType_, bool offchain_) internal pure returns (bool) {
        return offchain_ ? (
            commitmentType_ == Datastructures.CommitmentType.OFFCHAIN__FULL_TOKENIZATION || 
            commitmentType_ == Datastructures.CommitmentType.OFFCHAIN__TRADER_TOKENIZATION
        ) : (
            commitmentType_ == Datastructures.CommitmentType.REGISTRATION__FULL_TOKENIZATION || 
            commitmentType_ == Datastructures.CommitmentType.REGISTRATION__TRADER_TOKENIZATION
        );
    }

    function _isTransferCommitment(Datastructures.CommitmentType commitmentType_) internal pure returns (bool) {
        return 
            commitmentType_ == Datastructures.CommitmentType.TRANSFER__FULL_TOKENIZATION || 
            commitmentType_ == Datastructures.CommitmentType.TRANSFER__TRADER_TOKENIZATION;
    }

    function _isRenewalCommitment(Datastructures.CommitmentType commitmentType_, bool offchain_) internal pure returns (bool) {
        return offchain_ ? (
            commitmentType_ == Datastructures.CommitmentType.OFFCHAIN_RENEWAL || 
            commitmentType_ == Datastructures.CommitmentType.OFFCHAIN_RENEWAL__TRADER_TOKENIZATION
        ) : (
            commitmentType_ == Datastructures.CommitmentType.RENEWAL ||
            commitmentType_ == Datastructures.CommitmentType.RENEWAL__TRADER_TOKENIZATION
        );
    }

    function _isTraderTokenization(Datastructures.CommitmentType commitmentType_) internal pure returns (bool) {
        return commitmentType_ == Datastructures.CommitmentType.REGISTRATION__TRADER_TOKENIZATION||
        commitmentType_ == Datastructures.CommitmentType.TRANSFER__TRADER_TOKENIZATION ||
        commitmentType_ == Datastructures.CommitmentType.RENEWAL__TRADER_TOKENIZATION ||
        commitmentType_ == Datastructures.CommitmentType.OFFCHAIN__TRADER_TOKENIZATION ||
        commitmentType_ == Datastructures.CommitmentType.OFFCHAIN_RENEWAL__TRADER_TOKENIZATION;
    }

    function _isOffchainCommitment(Datastructures.CommitmentType commitmentType_) internal pure returns (bool) {
        return commitmentType_ == Datastructures.CommitmentType.OFFCHAIN__FULL_TOKENIZATION || 
        commitmentType_ == Datastructures.CommitmentType.OFFCHAIN__TRADER_TOKENIZATION ||
        commitmentType_ == Datastructures.CommitmentType.OFFCHAIN_RENEWAL || 
        commitmentType_ == Datastructures.CommitmentType.OFFCHAIN_RENEWAL__TRADER_TOKENIZATION;
    }

    /// Misc Validators ---------------------------------------------------------------------------

    function _validateRegistrationRequest(bytes32 tld_, Datastructures.RegistrationRequest memory req_) internal view {
        // Validate the commitment type
        /// @note duration is validated in _createRegistration__validate

        // Validate the registration & service payments
        _validateRegistrationPayment(req_.registrationPayment, tld_, req_.duration);
        _validatePayment(req_.servicePayment, true);

        // Validate the service payment type matches the registration
        if (req_.registrationPayment.paymentType != req_.servicePayment.paymentType) {
            revert CommitmentOrderflow_invalidPaymentType(req_.servicePayment.paymentType);
        }
    }

    /// Administrative Action Validators ==========================================================

    /// @dev Message signature function override for signer role check.
    function _isValidSigner(address signer_) internal view override returns (bool) {
        return authority().isRole(authority().ROLE__SIGNER(), signer_);
    }

    /// @dev Internal function for issuer role check.
    function _isValidIssuer(address issuer_) internal view returns (bool) {
        return authority().isRole(authority().ROLE__ISSUER(), issuer_);
    }
}

// solhint-disable func-name-mixedcase

// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;

/// External References ---------------------------------------------------------------------------

import {IERC165Upgradeable as IERC165} from "openzeppelin-upgradeable/utils/introspection/IERC165Upgradeable.sol";

import {IERC721, IERC721Metadata} from "src/regcontrol/interfaces/tokens/IERC721.sol";
import {IERC1155, IERC1155MetadataURI} from "src/regcontrol/interfaces/tokens/IERC1155.sol";

/// Internal References ---------------------------------------------------------------------------

import {ThreeDNSAccessControlled} from "src/utils/access/ThreeDNSAccessControlled.sol";

import {CustomToken} from "src/regcontrol/modules/types/custom/CustomToken.sol";
import {CustomENS} from "src/regcontrol/modules/types/custom/CustomENS.sol";

import {IDomainController} from "src/regcontrol/interfaces/IDomainController.sol";
import {IENS} from "src/regcontrol/interfaces/tokens/IENS.sol";
import {ICustomToken} from "src/regcontrol/interfaces/tokens/ICustomToken.sol";

import {RegControlStorage} from "src/regcontrol/storage/Storage.sol";

/// Errors ----------------------------------------------------------------------------------------


contract DomainController is 
    IDomainController,

    CustomToken, 
    CustomENS,
    
    ThreeDNSAccessControlled
{

    /// Management Functions ----------------------------------------------------------------------
    
    function setPrimaryResolver(address resolver_) external {
        // Run access control validation
        _callerIsOperator__validate();

        RegControlStorage.setPrimaryResolver(resolver_);
    }

    /// Shared Management Functions ---------------------------------------------------------------

    function setApprovalForAll(address operator_, bool approval) public override(IDomainController, IENS, ICustomToken) {
        // Function uses msg.sender for account indexed operations
        _setAccountOperatorApproval(operator_, approval);
    }

    function isApprovedForAll(address account_, address operator_) public view override(IDomainController, IENS, ICustomToken) returns (bool) {
        return _isApprovedAccountOperator(account_, operator_);
    }

    function tokenData(uint256 node_) external view returns (address registrant, uint32 controlBitmap, uint64 expiration) {
        return _getNodeData(bytes32(node_));
    }

    /// Accessor Functions ------------------------------------------------------------------------

    function _tokenExists(uint256 node_) internal view override returns (bool) {
        return _getRegistrant(bytes32(node_)) != address(0x00);
    }

    /// ERC165 Functions ---------------------------------------------------------------------------

    /// @dev ERC165 introspection support.
    function supportsInterface(bytes4 interfaceId_) public view returns (bool) {
        return 
            interfaceId_ == type(IENS).interfaceId || 
            interfaceId_ == type(IERC1155).interfaceId || 
            interfaceId_ == type(IERC1155MetadataURI).interfaceId || 
            interfaceId_ == type(IERC721).interfaceId || 
            interfaceId_ == type(IERC721Metadata).interfaceId || 
            interfaceId_ == type(IERC165).interfaceId;
    }
}

// solhint-disable func-name-mixedcase

// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;

/// External References ---------------------------------------------------------------------------

import {Initializable} from "openzeppelin-upgradeable/proxy/utils/Initializable.sol";
import {IERC20Upgradeable as IERC20} from "openzeppelin-upgradeable/token/ERC20/IERC20Upgradeable.sol";

/// Internal References ---------------------------------------------------------------------------

import {AbstractPaymentProcessor} from "src/regcontrol/modules/types/abstracts/AbstractPaymentProcessor.sol";

import {Datastructures} from "src/regcontrol/storage/Datastructures.sol";
import {PaymentStorage as Storage} from "src/regcontrol/storage/Storage.sol";

import {IWETH} from "src/utils/interfaces/IWETH.sol";

/// Errors -------------------------------------------------------------------------------------

error PaymentProcessor_insufficientPayment(
    Datastructures.PaymentType paymentType, uint256 paymentAmount, uint256 amount
);
error PaymentProcessor_insufficientBalance(
    Datastructures.PaymentType paymentType, uint256 paymentAmount, uint256 amount
);
error PaymentProcessor_insufficientAllowance(
    Datastructures.PaymentType paymentType, uint256 paymentAmount, uint256 amount
);
error PaymentProcessor_invalidPaymentType(Datastructures.PaymentType paymentType);
error PaymentProcessor_transferFailed();
error PaymentProcessor_permitFailed();

contract PaymentProcessor is Initializable, AbstractPaymentProcessor {    
    /// Constants ------------------------------------------------------------------------------

    address payable constant private WETH = payable(0x4200000000000000000000000000000000000006);

    bytes32 internal constant _TLD_NODE__BOX = 0x665b1306e8eb7fc67d224df1c4ceb9003655ecffaf26d78c2832fe4788a22617;

    address internal constant _WITHDRAWL_ADDRESS__3DNS = 0xBBa294D303555032C6BD1021C639654b95e77Fa8;
    address internal constant _WITHDRAWL_ADDRESS__BOX = 0xBff9E8b1F5eBd6B248238fAAF02F6eC09255ad51;

    /// Initialization Functions ==================================================================

    function __PaymentProcessor_init(IERC20 _usdc) internal onlyInitializing {
        Storage.initialize(_usdc);
    }

    /// Abstract Payment Function Implemantations =================================================

    function _validateRegistrationPayment(Datastructures.OrderPayment memory payment_, bytes32 tld_, uint64 duration_)
        internal
        view
        override
    {
        // TODO: Validate the payment amount relative to the tld

        // Validate the payment
        _validatePayment(payment_, false);
    }

    function _validatePayment(Datastructures.OrderPayment memory payment_, bool zeroPayments_)
        internal
        pure
        override
    {
        // Validate that the payment currency is supported
        if (
            payment_.paymentType != Datastructures.PaymentType.ETH
                && payment_.paymentType != Datastructures.PaymentType.USDC
        ) {
            revert PaymentProcessor_invalidPaymentType(payment_.paymentType);
        }

        // Validate the payment amount
        if (!zeroPayments_ && payment_.amount == 0) {
            revert PaymentProcessor_insufficientPayment(payment_.paymentType, 0, 0);
        }
    }

    function _handlePayment(Datastructures.OrderPayment memory payment_, bool isCommitment_)
        internal
        override
    {
        return _handlePayment(payment_, isCommitment_, msg.sender);
    }

    function _handlePayment(Datastructures.OrderPayment memory payment_, bool isCommitment_, address payee_)
        internal
    {
        uint256 amount_;
        // TODO: Add onchain bounds and handling for the payment amount

        // If this is a commitment payment, then this contract becomes the recipient of the funds
        address recipient_ = isCommitment_ ? address(this) : _WITHDRAWL_ADDRESS__3DNS;

        // Handle the payment
        if (payment_.paymentType == Datastructures.PaymentType.ETH) {
            // ETH payments are processed in WETH
            if ((amount_ = IWETH(WETH).balanceOf(address(this))) < payment_.amount) {
                revert PaymentProcessor_insufficientBalance(payment_.paymentType, uint256(payment_.amount), amount_);
            }

            // Unwrap the WETH
            IWETH(WETH).withdraw(payment_.amount);

            if (!isCommitment_) {
                (bool success,) = payable(recipient_).call{value: payment_.amount}("");
                if (!success) revert PaymentProcessor_transferFailed();
            }
        } else if (payment_.paymentType == Datastructures.PaymentType.USDC) {
            if ((amount_ = Storage.ERC20_USDC_ADDRESS().balanceOf(payee_)) < payment_.amount) {
                revert PaymentProcessor_insufficientBalance(payment_.paymentType, uint256(payment_.amount), amount_);
            }
            if ((amount_ = Storage.ERC20_USDC_ADDRESS().allowance(payee_, address(this))) < payment_.amount) {
                revert PaymentProcessor_insufficientAllowance(payment_.paymentType, uint256(payment_.amount), amount_);
            }

            // Pull USDC from the caller
            Storage.ERC20_USDC_ADDRESS().transferFrom(payee_, recipient_, uint256(payment_.amount));
        } else {
            revert PaymentProcessor_invalidPaymentType(payment_.paymentType);
        }
    }

    function _handlePayout(Datastructures.OrderPayment memory payment_, address recipient_) internal override {
        uint256 amount_;
        if (payment_.paymentType == Datastructures.PaymentType.ETH) {
            if (address(this).balance < payment_.amount) {
                revert PaymentProcessor_insufficientPayment(
                    payment_.paymentType, uint256(payment_.amount), address(this).balance
                );
            }

            // Transfer ETH to the recipient
            (bool success_,) = payable(recipient_).call{value: payment_.amount}("");
            if (!success_) revert PaymentProcessor_transferFailed();
        } else if (payment_.paymentType == Datastructures.PaymentType.USDC) {
            if ((amount_ = Storage.ERC20_USDC_ADDRESS().balanceOf(address(this))) < payment_.amount) {
                revert PaymentProcessor_insufficientBalance(payment_.paymentType, uint256(payment_.amount), amount_);
            }

            // Send USDC from the contract to the recipient
            bool success_ = Storage.ERC20_USDC_ADDRESS().transfer(recipient_, uint256(payment_.amount));
            if (!success_) revert PaymentProcessor_transferFailed();
        } else {
            revert PaymentProcessor_invalidPaymentType(payment_.paymentType);
        }
    }

    function _getPayoutAddress(bytes32 tld_) internal pure override returns (address) {
        // TODO: Update this to the root owner / custodian
        if (tld_ == _TLD_NODE__BOX) return _WITHDRAWL_ADDRESS__BOX;
        return _WITHDRAWL_ADDRESS__3DNS;
    }

    /// Accessor Functions ------------------------------------------------------------------------

    function ERC20_USDC_ADDRESS() public view override returns (IERC20) {
        return Storage.ERC20_USDC_ADDRESS();
    }

    // function rentPrice(
    //     string memory label_,
    //     bytes32 tld_,
    //     uint256 duration_,
    //     Datastructures.PaymentType paymentType_
    // ) external view returns (uint256 amount_) {
    //     revert PaymentModule_notSupported();
    // }
}

// solhint-disable func-name-mixedcase

// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;

/// External References ---------------------------------------------------------------------------

import {Initializable} from "openzeppelin-upgradeable/proxy/utils/Initializable.sol";
import {IERC20Upgradeable as IERC20} from "openzeppelin-upgradeable/token/ERC20/IERC20Upgradeable.sol";

/// Internal References ---------------------------------------------------------------------------

import {IRegistrarController} from "src/regcontrol/interfaces/IRegistrarController.sol";

// import {AbstractAccessControlled} from "src/utils/access/abstracts/AbstractAccessControlled.sol";

import {ThreeDNSAccessControlled} from "src/utils/access/ThreeDNSAccessControlled.sol";
import {IThreeDNSAuthority} from "src/utils/access/interfaces/IThreeDNSAuthority.sol";

import {Registry} from "src/regcontrol/modules/types/Registry.sol";

import {RegistryStorage, RegistrarStorage, PaymentStorage} from "src/regcontrol/storage/Storage.sol";
import {Datastructures} from "src/regcontrol/storage/Datastructures.sol";
import {HybridMetadataStorage} from "src/regcontrol/storage/Storage.sol";

/// Errors ----------------------------------------------------------------------------------------

error RegistrarController_accessDenied();
error RegistrarController_tldExists();
error RegistrarController_tldDoesntExist();
error RegistrarController_invalidLabel(bytes label);

/// Contract --------------------------------------------------------------------------------------
contract RegistrarController is
    IRegistrarController,

    Initializable,
    ThreeDNSAccessControlled,
    Registry
{
    
    constructor(IThreeDNSAuthority _authority) initializer {
        ThreeDNSAccessControlled.__ThreeDNSAccessControlled_init(_authority);
    }    

    /// Management Functions ----------------------------------------------------------------------

    function registerTLD(bytes calldata tld_) external {
        // Run access control check
        _callerIsRegistrarAdmin__validate();

        // Validate & register the tld
        _registerTLD(tld_);
    }

    function setTLDMetadata(bytes32 tld_, string calldata baseUrl_, string calldata description_) external {
        // Run access control check
        _callerIsRegistrarAdmin__validate();

        // Validate tld is registered
        if (tld_ != bytes32(0) && !_isRegisteredTLD(tld_))
            revert RegistrarController_tldDoesntExist();
            
        // Set the metadata
        HybridMetadataStorage.setMetadata(tld_, baseUrl_, description_);
    }

    // TODO: Add updateTLD and disableTLD functions

    /// Inforcement Functions ---------------------------------------------------------------------

    event UDRPDecision(bytes32 indexed node, address recipient, string caseLink);

    function processUDRPdecision(bytes32 node_, address recipient_, string memory caseLink_) external {
        // Run access control check
        _callerIsRegistrarAdmin__validate();

        // If recipient address is 0, burn the domain
        if (recipient_ == address(0)) {
            // Burn the domain
            _burnRegistration(node_);
        } else {
            // Transfer the domain to the recipient
            _transferRegistration(node_, recipient_);
        }

        emit UDRPDecision(node_, recipient_, caseLink_);
    }

    function lockRegistration(bytes32 node_, uint64 duration_) external {
        // Run access control check
        _callerIsRegistrarAdmin__validate();

        // Lock the domain
        _lockRegistration(node_, duration_);
    }

    function unlockRegistration(bytes32 node_) external {
        // Run access control check
        _callerIsRegistrarAdmin__validate();

        // Unlock the domain
        _removeRegistrationLock(node_);
    }

    /// Accessor Functions ------------------------------------------------------------------------

    function getTLDData(bytes32 tld_) external view returns (bool enabled_) {
        // Return the tld data
        return _isRegisteredTLD(tld_);
    }

    function getTLDMetadata(bytes32 tld_) external view returns (string memory baseUrl_, string memory description_) {
        // Validate tld is registered
        if (!_isRegisteredTLD(tld_)) 
            revert RegistrarController_tldExists();

        return HybridMetadataStorage.getMetadata(tld_);
    }

    /// Internal Helper Functions -----------------------------------------------------------------

    function _registerTLD(bytes calldata tld_) internal {
        // Validate the tld & accessory data
        bytes32 node_ = _tld__prepare(tld_);

        // Validate uniqueness and register the tld
        _tld__register(tld_, node_);

        // Emit events //

        // ERC721 Event
        emit Transfer(address(0x00), address(this), uint256(node_));

        // ERC1155 Event
        emit TransferSingle(msg.sender, address(0x00), address(this), uint256(node_), 1);

        // ENS Event
        emit NewOwner(bytes32(0x00), keccak256(tld_), address(this));
        emit Transfer(node_, address(this));
    }
    
    /// Validation Functions ----------------------------------------------------------------------

    function _tld__prepare(bytes calldata tld_) internal pure returns (bytes32 node_) {
        // Validate the tld
        if (!_isValidTLDLabel(tld_)) {
            revert RegistrarController_invalidLabel(tld_);
        }

        // Calculate node
        node_ = _calculateNode(tld_, bytes32(0));

        // TODO: Add additional state specific validations

        // Return the node
        return node_;
    }

    /// Private State Management Functions --------------------------------------------------------

    function _tld__register(bytes calldata label_, bytes32 node_) private {
        // Validate tld is not already registered
        if (_isRegisteredTLD(node_)) 
            revert RegistrarController_tldExists();

        /// @dev Registry Storage
        // Store node in root registry with a parent of 0x00

        // Initialize the record data
        // Set the registrant as self and the expiration to max uint64
        RegistryStorage.createNewRecord(node_, address(this), 0, ~uint64(0));

        // Track the ownership
        RegistryStorage.trackNewOwnership(node_, address(this));

        // Build a reverse record mapping for the tld to the root label
        RegistryStorage.trackReverseRecord(bytes32(0x00), label_);

        /// @dev Registrar Storage
        // Register the tld in the registrar
        RegistrarStorage.registerTLD(node_);
    }

    /// Validation Helper Functions ---------------------------------------------------------------

    function _isRegisteredTLD(bytes32 node_) internal view returns (bool) {
        (bool enabled) = RegistrarStorage.getTLDData(node_);
        return enabled;
    }

    function _isValidTLDLabel(bytes calldata label_) internal pure returns (bool) {
        // Check if label is less than 2 or exceeds 18 characters
        if (label_.length < 0x02 || label_.length > 0x12) return false;

        // Check if label contains invalid characters
        for (uint256 i = 0; i < label_.length; i++) {
            bytes1 char_ = label_[i];

            // Ensure alphanumeric.
            if (!(char_ >= 0x61 && char_ <= 0x7A)) {
                return false;
            }
        }
        return true;
    }

    /// Access Control Functions ------------------------------------------------------------------

    function _callerIsRegistrarAdmin__validate() internal view {
        if (!_isValidRegistrarAdmin(msg.sender)) {
            revert RegistrarController_accessDenied();
        }
    }

    /// Administrative Action Validators ----------------------------------------------------------

    function _isValidRegistrarAdmin(address sender_) internal view returns (bool) {
        return authority().isRole(authority().ROLE__REGISTRAR_ADMIN(), sender_);
    }
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;

/// External References ---------------------------------------------------------------------------

import {AddressUpgradeable} from "openzeppelin-upgradeable/utils/AddressUpgradeable.sol";
import {Initializable} from "openzeppelin-upgradeable/proxy/utils/Initializable.sol";

/// Internal References ---------------------------------------------------------------------------

import {ReentrancyGuardDiamond} from "src/utils/access/ReentrancyGuardDiamond.sol";
import {SponsorShieldDiamond} from "src/utils/access/SponsorShieldDiamond.sol";

import {IMulticall} from "src/regcontrol/interfaces/IMulticall.sol";
import {IWETH} from "src/utils/interfaces/IWETH.sol";

// import {RegControl} from "src/regcontrol/RegControl.sol";

/// Multicall ----------------------------------------------------------------------------------

contract Multicall is 
    IMulticall, 
    Initializable,
    ReentrancyGuardDiamond,
    SponsorShieldDiamond 
{

    /// @dev Disable initializers for template contracts, as they are not meant to be initialized.
    constructor(bool embed) {
        if (!embed) __Multicall_init__self();
    }

    function __Multicall_init__self() internal initializer {
        __ReentrancyGuard_init();
    }

    /// @dev Initializes the contract state.
    function __Multicall_init() internal onlyInitializing {
        __ReentrancyGuard_init();
    }

    /// @dev WETH address

    address payable private constant WETH = payable(0x4200000000000000000000000000000000000006);

    /// @dev Receives and executes a batch of function calls on this contract.
    function multicall(bytes[] calldata data) external payable override nonReentrant returns (bytes[] memory results) {
        bool hasValue_ = false;
        if (msg.value > 0) {
            // Take passed ETH and convert to WETH
            IWETH(WETH).deposit{value: msg.value}();

            hasValue_ = true;
        }

        results = new bytes[](data.length);
        for (uint256 i = 0; i < data.length; i++) {
            // @audit 'delegatecall' forwards 'msg.value' 
            results[i] = AddressUpgradeable.functionDelegateCall(address(this), data[i]);
        }

        // Clear hooks
        _clearHooks();

        // Transfer any remaining WETH back to the sender
        if (hasValue_ && IWETH(WETH).balanceOf(address(this)) > 0) {
            IWETH(WETH).transfer(msg.sender, IWETH(WETH).balanceOf(address(this)));
        }

        return results;
    }

    function _clearHooks() private {
        // Clear sponsor shield hook
        _cleanupSponsorShield();
    }
}

File 11 of 63 : Storage.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;

import "./types/CommitmentStorage.sol";

import "./types/PaymentStorage.sol";

import "./types/RebateIssuerStorage.sol";

import "./types/RegistryStorage.sol";
import "./types/RegistrarStorage.sol";
import "./types/RegControlStorage.sol";

import "./types/MetadataStorage.sol";
import "./types/HybridMetadataStorage.sol";

import "./types/IAMStorage.sol";

// solhint-disable func-name-mixedcase

// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;

/// Internal References ---------------------------------------------------------------------------

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

library ReentrancyGuardStorage {
    /// SLO Offsets -------------------------------------------------------------------------------

    /// @dev Constant specifing the storage location of the payment state
    bytes32 public constant THREE_DNS__REENTRANCY_GUARD_STORAGE__V1 =
        keccak256("3dns.access_controlled.reentrancy_guard.v1.state");

    /// Constants ---------------------------------------------------------------------------------
    
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 internal constant _NOT_ENTERED = 1;
    uint256 internal constant _ENTERED = 2;

    /// Contract State ----------------------------------------------------------------------------

    /// @dev Struct used to define the state variables for the 3dns registry.
    struct Layout {
        uint256 status;
    }

    function layout() internal pure returns (Layout storage l) {
        bytes32 slot = THREE_DNS__REENTRANCY_GUARD_STORAGE__V1;

        /// @solidity memory-safe-assembly
        assembly {
            l.slot := slot
        }
    }

    function initialize() internal {
        _setStatus(_NOT_ENTERED);
    }

    /// Helper Functions --------------------------------------------------------------------------

    function _setStatus(uint256 status) internal {
        layout().status = status;
    }

    function _getStatus() internal view returns (uint256) {
        return layout().status;
    }
}

File 13 of 63 : IDiamondCut.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;

/******************************************************************************\
* Author: Nick Mudge <[email protected]> (https://twitter.com/mudgen)
* EIP-2535 Diamond Standard: https://eips.ethereum.org/EIPS/eip-2535
/******************************************************************************/

interface IDiamondCut {
    enum FacetCutAction {Add, Replace, Remove}
    // Add=0, Replace=1, Remove=2

    struct FacetCut {
        address facetAddress;
        FacetCutAction action;
        bytes4[] functionSelectors;
    }

    /// @notice Add/replace/remove any number of functions and optionally execute
    ///         a function with delegatecall
    /// @param _diamondCut Contains the facet addresses and function selectors
    /// @param _init The address of the contract or facet to execute _calldata
    /// @param _calldata A function call, including function selector and arguments
    ///                  _calldata is executed with delegatecall on _init
    function diamondCut(
        FacetCut[] calldata _diamondCut,
        address _init,
        bytes calldata _calldata
    ) external;

    event DiamondCut(FacetCut[] _diamondCut, address _init, bytes _calldata);
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;

/******************************************************************************\
* Author: Nick Mudge <[email protected]> (https://twitter.com/mudgen)
* EIP-2535 Diamond Standard: https://eips.ethereum.org/EIPS/eip-2535
/******************************************************************************/

import "src/regcontrol/interfaces/diamond/IDiamondCut.sol";

error LibDiamondCut_facetAlreadyExists(address addr, bytes4 selector);
error LibDiamondCut_facetDoesNotExist(address addr, bytes4 selector);
error LibDiamondCut_immutableFunction(address addr, bytes4 selector);


// LibDiamondCut: Incorrect FacetCutAction
// LibDiamondCut: No selectors in facet to cut
// LibDiamondCut: Add facet can't be address(0)
// LibDiamondCut: New facet has no code
// LibDiamondCut: Can't add function that already exists
// LibDiamondCut: No selectors in facet to cut
// LibDiamondCut: Add facet can't be address(0)
// LibDiamondCut: New facet has no code
// LibDiamondCut: Can't replace function with same function
// LibDiamondCut: No selectors in facet to cut
// LibDiamondCut: Remove facet address must be address(0)
// LibDiamondCut: Can't remove function that doesn't exist
// LibDiamondCut: Can't remove immutable function
// LibDiamondCut: _init is address(0) but_calldata is not empty
// LibDiamondCut: _calldata is empty but _init is not address(0)
// LibDiamondCut: _init address has no code
// LibDiamondCut: _init function reverted

library LibDiamond {
    bytes32 constant DIAMOND_STORAGE_POSITION = keccak256("diamond.standard.diamond.storage");

    struct FacetAddressAndPosition {
        address facetAddress;
        uint16 functionSelectorPosition; // position in facetFunctionSelectors.functionSelectors array
    }

    struct FacetFunctionSelectors {
        bytes4[] functionSelectors;
        uint16 facetAddressPosition; // position of facetAddress in facetAddresses array
    }

    struct DiamondStorage {
        // maps function selector to the facet address and
        // the position of the selector in the facetFunctionSelectors.selectors array
        mapping(bytes4 => FacetAddressAndPosition) selectorToFacetAndPosition;
        // maps facet addresses to function selectors
        mapping(address => FacetFunctionSelectors) facetFunctionSelectors;
        // facet addresses
        address[] facetAddresses;
        // Used to query if a contract implements an interface.
        // Used to implement ERC-165.
        mapping(bytes4 => bool) supportedInterfaces;
        // owner of the contract
        address contractOwner;
    }

    function diamondStorage() internal pure returns (DiamondStorage storage ds) {
        bytes32 position = DIAMOND_STORAGE_POSITION;
        assembly {
            ds.slot := position
        }
    }

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    function setContractOwner(address _newOwner) internal {
        DiamondStorage storage ds = diamondStorage();
        address previousOwner = ds.contractOwner;
        ds.contractOwner = _newOwner;
        emit OwnershipTransferred(previousOwner, _newOwner);
    }

    function contractOwner() internal view returns (address contractOwner_) {
        contractOwner_ = diamondStorage().contractOwner;
    }

    function enforceIsContractOwner() internal view {
        require(msg.sender == diamondStorage().contractOwner, "LibDiamond: Must be contract owner");
    }

    event DiamondCut(IDiamondCut.FacetCut[] _diamondCut, address _init, bytes _calldata);

    // Internal function version of diamondCut
    function diamondCut(
        IDiamondCut.FacetCut[] memory _diamondCut,
        address _init,
        bytes memory _calldata
    ) internal {
        for (uint256 facetIndex; facetIndex < _diamondCut.length; facetIndex++) {
            IDiamondCut.FacetCutAction action = _diamondCut[facetIndex].action;
            if (action == IDiamondCut.FacetCutAction.Add) {
                addFunctions(_diamondCut[facetIndex].facetAddress, _diamondCut[facetIndex].functionSelectors);
            } else if (action == IDiamondCut.FacetCutAction.Replace) {
                replaceFunctions(_diamondCut[facetIndex].facetAddress, _diamondCut[facetIndex].functionSelectors);
            } else if (action == IDiamondCut.FacetCutAction.Remove) {
                removeFunctions(_diamondCut[facetIndex].facetAddress, _diamondCut[facetIndex].functionSelectors);
            } else {
                revert("LibDiamondCut: Incorrect FacetCutAction");
            }
        }
        emit DiamondCut(_diamondCut, _init, _calldata);
        initializeDiamondCut(_init, _calldata);
    }

    function addFunctions(address _facetAddress, bytes4[] memory _functionSelectors) internal {
        require(_functionSelectors.length > 0, "LibDiamondCut: No selectors in facet to cut");
        DiamondStorage storage ds = diamondStorage();
        // uint16 selectorCount = uint16(diamondStorage().selectors.length);
        require(_facetAddress != address(0), "LibDiamondCut: Add facet can't be address(0)");
        uint16 selectorPosition = uint16(ds.facetFunctionSelectors[_facetAddress].functionSelectors.length);
        // add new facet address if it does not exist
        if (selectorPosition == 0) {
            enforceHasContractCode(_facetAddress, "LibDiamondCut: New facet has no code");
            ds.facetFunctionSelectors[_facetAddress].facetAddressPosition = uint16(ds.facetAddresses.length);
            ds.facetAddresses.push(_facetAddress);
        }
        for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {
            bytes4 selector = _functionSelectors[selectorIndex];
            address oldFacetAddress = ds.selectorToFacetAndPosition[selector].facetAddress;
            if (oldFacetAddress != address(0)) revert LibDiamondCut_facetAlreadyExists(oldFacetAddress, selector);
            // require(oldFacetAddress == address(0), "LibDiamondCut: Can't add function that already exists");
            ds.facetFunctionSelectors[_facetAddress].functionSelectors.push(selector);
            ds.selectorToFacetAndPosition[selector].facetAddress = _facetAddress;
            ds.selectorToFacetAndPosition[selector].functionSelectorPosition = selectorPosition;
            selectorPosition++;
        }
    }

    function replaceFunctions(address _facetAddress, bytes4[] memory _functionSelectors) internal {
        require(_functionSelectors.length > 0, "LibDiamondCut: No selectors in facet to cut");
        DiamondStorage storage ds = diamondStorage();
        require(_facetAddress != address(0), "LibDiamondCut: Add facet can't be address(0)");
        uint16 selectorPosition = uint16(ds.facetFunctionSelectors[_facetAddress].functionSelectors.length);
        // add new facet address if it does not exist
        if (selectorPosition == 0) {
            enforceHasContractCode(_facetAddress, "LibDiamondCut: New facet has no code");
            ds.facetFunctionSelectors[_facetAddress].facetAddressPosition = uint16(ds.facetAddresses.length);
            ds.facetAddresses.push(_facetAddress);
        }
        for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {
            bytes4 selector = _functionSelectors[selectorIndex];
            address oldFacetAddress = ds.selectorToFacetAndPosition[selector].facetAddress;
            require(oldFacetAddress != _facetAddress, "LibDiamondCut: Can't replace function with same function");
            removeFunction(oldFacetAddress, selector);
            // add function
            ds.selectorToFacetAndPosition[selector].functionSelectorPosition = selectorPosition;
            ds.facetFunctionSelectors[_facetAddress].functionSelectors.push(selector);
            ds.selectorToFacetAndPosition[selector].facetAddress = _facetAddress;
            selectorPosition++;
        }
    }

    function removeFunctions(address _facetAddress, bytes4[] memory _functionSelectors) internal {
        require(_functionSelectors.length > 0, "LibDiamondCut: No selectors in facet to cut");
        DiamondStorage storage ds = diamondStorage();
        // if function does not exist then do nothing and return
        require(_facetAddress == address(0), "LibDiamondCut: Remove facet address must be address(0)");
        for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {
            bytes4 selector = _functionSelectors[selectorIndex];
            address oldFacetAddress = ds.selectorToFacetAndPosition[selector].facetAddress;
            removeFunction(oldFacetAddress, selector);
        }
    }

    function removeFunction(address _facetAddress, bytes4 _selector) internal {
        DiamondStorage storage ds = diamondStorage();
        if (_facetAddress == address(0)) revert LibDiamondCut_facetDoesNotExist(_facetAddress, _selector);
        // an immutable function is a function defined directly in a diamond
        if (_facetAddress == address(this)) revert LibDiamondCut_immutableFunction(_facetAddress, _selector);
        // replace selector with last selector, then delete last selector
        uint256 selectorPosition = ds.selectorToFacetAndPosition[_selector].functionSelectorPosition;
        uint256 lastSelectorPosition = ds.facetFunctionSelectors[_facetAddress].functionSelectors.length - 1;
        // if not the same then replace _selector with lastSelector
        if (selectorPosition != lastSelectorPosition) {
            bytes4 lastSelector = ds.facetFunctionSelectors[_facetAddress].functionSelectors[lastSelectorPosition];
            ds.facetFunctionSelectors[_facetAddress].functionSelectors[selectorPosition] = lastSelector;
            ds.selectorToFacetAndPosition[lastSelector].functionSelectorPosition = uint16(selectorPosition);
        }
        // delete the last selector
        ds.facetFunctionSelectors[_facetAddress].functionSelectors.pop();
        delete ds.selectorToFacetAndPosition[_selector];

        // if no more selectors for facet address then delete the facet address
        if (lastSelectorPosition == 0) {
            // replace facet address with last facet address and delete last facet address
            uint256 lastFacetAddressPosition = ds.facetAddresses.length - 1;
            uint256 facetAddressPosition = ds.facetFunctionSelectors[_facetAddress].facetAddressPosition;
            if (facetAddressPosition != lastFacetAddressPosition) {
                address lastFacetAddress = ds.facetAddresses[lastFacetAddressPosition];
                ds.facetAddresses[facetAddressPosition] = lastFacetAddress;
                ds.facetFunctionSelectors[lastFacetAddress].facetAddressPosition = uint16(facetAddressPosition);
            }
            ds.facetAddresses.pop();
            delete ds.facetFunctionSelectors[_facetAddress].facetAddressPosition;
        }
    }

    function initializeDiamondCut(address _init, bytes memory _calldata) internal {
        if (_init == address(0)) {
            require(_calldata.length == 0, "LibDiamondCut: _init is address(0) but_calldata is not empty");
        } else {
            require(_calldata.length > 0, "LibDiamondCut: _calldata is empty but _init is not address(0)");
            if (_init != address(this)) {
                enforceHasContractCode(_init, "LibDiamondCut: _init address has no code");
            }
            (bool success, bytes memory error) = _init.delegatecall(_calldata);
            if (!success) {
                if (error.length > 0) {
                    // bubble up the error
                    revert(string(error));
                } else {
                    revert("LibDiamondCut: _init function reverted");
                }
            }
        }
    }

    function enforceHasContractCode(address _contract, string memory _errorMessage) internal view {
        uint256 contractSize;
        assembly {
            contractSize := extcodesize(_contract)
        }
        require(contractSize > 0, _errorMessage);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library AddressUpgradeable {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     *
     * Furthermore, `isContract` will also return true if the target contract within
     * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
     * which only has an effect at the end of a transaction.
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
     *
     * _Available since v4.8._
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        if (success) {
            if (returndata.length == 0) {
                // only check isContract if the call was successful and the return data is empty
                // otherwise we already know that it was a contract
                require(isContract(target), "Address: call to non-contract");
            }
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason or using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    function _revert(bytes memory returndata, string memory errorMessage) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert(errorMessage);
        }
    }
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;

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

interface IThreeDNSAccessControlled {
  event AuthorityChanged(IThreeDNSAuthority indexed previousAuthority, IThreeDNSAuthority indexed newAuthority);

  function authority() external view returns (IThreeDNSAuthority);
  function changeAuthority(IThreeDNSAuthority _newAuthority) external;
}

// solhint-disable func-name-mixedcase

// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;

/// Internal References ---------------------------------------------------------------------------

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

library AccessControlledStorage {
    /// SLO Offsets -------------------------------------------------------------------------------

    /// @dev Constant specifing the storage location of the payment state
    bytes32 public constant THREE_DNS__ACCESS_CONTROLLED_STORAGE__V1 =
        keccak256("3dns.access_controlled.authority.v1.state");

    /// Contract State ----------------------------------------------------------------------------

    /// @dev Struct used to define the state variables for the 3dns registry.
    struct Layout {
        /// @dev authority contract
        IThreeDNSAuthority authority;
    }

    function layout() internal pure returns (Layout storage l) {
        bytes32 slot = THREE_DNS__ACCESS_CONTROLLED_STORAGE__V1;

        /// @solidity memory-safe-assembly
        assembly {
            l.slot := slot
        }
    }

    function initialize(IThreeDNSAuthority authority_) internal {
        changeAuthority(authority_);
    }

    /// Accessor Functions ------------------------------------------------------------------------

    function authority() internal view returns (IThreeDNSAuthority) {
        return layout().authority;
    }

    function changeAuthority(IThreeDNSAuthority newAuthority_) internal {
        if (address(newAuthority_) == address(0)) {
            revert();
        }

        layout().authority = newAuthority_;
    }
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;

/// Internal References ---------------------------------------------------------------------------

import {Datastructures} from "src/regcontrol/storage/Datastructures.sol";

interface ICommitmentOrderflow {
    /// Events ---------------------------------------------------------------------------------

    /// Two Phase Commitments ///

    // Commitment V1 Signature
    // event PendingCommitment(
    //     bytes32 indexed commitmentHash_, uint64 indexed revocableAt_, address indexed committer,
    //     Datastructures.OrderPayment payment,
    //     uint8 v_, bytes32 r_, bytes32 s_
    // );
    //
    // event RefundCommitment(
    //     bytes32 indexed commitmentHash_, address indexed issuer,  address indexed committer,
    //     Datastructures.OrderPayment payment
    // );
    //
    // event RevokeCommitment(
    //     bytes32 indexed commitmentHash_, address indexed committer,
    //     Datastructures.OrderPayment payment
    // );

    event PendingCommitment(
        bytes32 indexed commitmentHash_,
        uint64 indexed revocableAt_,
        address indexed committer,
        Datastructures.OrderPayment registrationPayment,
        Datastructures.OrderPayment servicePayment,
        uint8 v_,
        bytes32 r_,
        bytes32 s_
    );

    event RefundCommitment(
        bytes32 indexed commitmentHash_,
        address indexed issuer,
        address indexed committer,
        Datastructures.CommitmentType commitmentType,
        Datastructures.OrderPayment registrationPayment,
        Datastructures.OrderPayment servicePayment
    );

    event RevokeCommitment(
        bytes32 indexed commitmentHash_,
        address indexed committer,
        Datastructures.CommitmentType commitmentType,
        Datastructures.OrderPayment registrationPayment,
        Datastructures.OrderPayment servicePayment
    );

    event ProcessCommitment(bytes32 indexed commitmentHash_, address indexed processor);

    /// Offchain Commitments ///

    event IssuedDomainName(bytes32 indexed node_, address indexed issuer_);
    // event IssuedDomainName(bytes32 indexed node_, address indexed issuer_, uint64 indexed lockedUntil_);

    /// Service Orderflows ///

    event PurchasedService(
        bytes32 indexed commitment_, address indexed registrant_, Datastructures.OrderPayment payment
    );

    /// Purchase Orderflows -----------------------------------------------------------------------

    /// Two Phase Orderflows ///

    function validateCommitmentV2(
        bytes calldata fqdn_,
        address registrant_,
        bytes32 nonce_,
        Datastructures.RegistrationRequest memory req_
    ) external view returns (bytes32 secretHash_);

    function makeCommitmentV2(
        bytes32 secretHash_,
        Datastructures.RegistrationRequest memory req_,
        Datastructures.AuthorizationSignature memory sig_,
        address committer_
    ) external payable;

    // // Purchasing a domain will trigger a series of events:
    // // 1. A NewRegistration event will be emitted
    // // 2. A TransferSingle event will be emitted
    // // 3. A Renewed event will be emitted with the expiry date of the domain
    // // function validateCommitment(
    // //     bytes calldata fqdn_,
    // //     address registrant_,
    // //     uint64 duration_,
    // //     bytes32 nonce_,
    // //     Datastructures.OrderPayment calldata payment_
    // // ) external view returns (bytes32 secretHash_);

    // function validateCommitmentV2(
    //     bytes calldata fqdn_,
    //     address registrant_,
    //     bytes32 nonce_,
    //     Datastructures.RegistrationRequest calldata req_
    // ) external view returns (bytes32 secretHash_);

    // // function makeCommitment(
    // //     bytes32 secretHash_,
    // //     uint64 duration_,
    // //     Datastructures.OrderPayment calldata payment_,
    // //     uint64 issuedAt_,
    // //     uint64 expiresAt_,
    // //     uint8 v_,
    // //     bytes32 r_,
    // //     bytes32 s_
    // // ) external payable;

    // function processCommitment(
    //     bytes calldata fqdn_,
    //     address registrant_,
    //     bytes32 nonce_,
    //     Datastructures.RegistrationRequest calldata req_
    // ) external;

    // function refundCommitment(Datastructures.RegistrationRequest calldata req_, bytes32 secretHash_) external;

    // function revokeCommitment(Datastructures.RegistrationRequest calldata req_, bytes32 secretHash_) external;

    /// Off-Chain Issuance ------------------------------------------------------------------------

    /// Off-Chain Orderflows ///

    // // Issued domain names cant be transferred for the first 30 days
    // function issueDomainName(
    //     bytes calldata fqdn_, address registrant_, uint64 duration_, 
    //     Datastructures.AuthorizationSignature memory sig_
    // ) external;
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.17;

/// External References ---------------------------------------------------------------------------

import {Initializable} from "openzeppelin-upgradeable/proxy/utils/Initializable.sol";

/// Internal References ---------------------------------------------------------------------------

import {Datastructures} from "src/regcontrol/storage/Datastructures.sol";
import {TypedDataSignature} from "src/utils/signature/TypedDataSignature.sol";

abstract contract RegistrationAuthorizor is TypedDataSignature {
    /// Datastructures ----------------------------------------------------------------------------

    /// @title RegistrationAuthorization
    /// @notice Represents the details of a typed data signature.
    /// @param commitment The commitment being signed.
    /// @param payment The payment details for the order.
    /// @param issuedAt The timestamp of when the signature was issued.
    /// @param expiresAt The timestamp of when the signature expires.
    struct RegistrationAuthorization {
        Datastructures.InternalCommitment commitment;
        uint64 issuedAt;
        uint64 expiresAt;

        bytes32 commitmentHash_;
    }

    /// Peusdo Constants ---------------------------------------------------------------------------

    // Define the EIP712 Type for the TypedDataSignature struct
    bytes32 public immutable override TYPED_DATA_SIGNATURE_TYPEHASH;

    constructor() {
        TYPED_DATA_SIGNATURE_TYPEHASH = keccak256(
            "RegistrationAuthorizationV2(InternalCommitment commitment,uint64 issuedAt,uint64 expiresAt)InternalCommitment(RegistrationRequest request,RegistrationSecret secret)RegistrationRequest(CommitmentType commitmentType,uint64 duration,OrderPayment registrationPayment,OrderPayment servicePayment)RegistrationSecret(address registrant,bytes32 node,bytes32 nonce)OrderPayment(PaymentType paymentType,uint248 amount)"
        );
    }

    /// Initializer ----------------------------------------------------------------------------

    function __RegistrationAuthorizor_init(
        string memory domainName_,
        string memory domainVersion_,
        uint64 chainId_
    ) internal onlyInitializing {
        TypedDataSignature.__TypedDataSignature_init(domainName_, domainVersion_, chainId_);
    }

    /// Typed Data Signature Functions ============================================================

    function _validateSignature(RegistrationAuthorization memory sig_, uint8 v_, bytes32 r_, bytes32 s_) internal view {
        _validateSignature(
            abi.encode(sig_),
            v_, r_, s_
        );
    }

    function _calculateTypeHash(bytes memory data_) internal view override returns (bytes32) {
        RegistrationAuthorization memory sig_ = abi.decode(data_, (RegistrationAuthorization));

        if (sig_.commitmentHash_ == bytes32(0))
            sig_.commitmentHash_ = _calculateCommitmentHash(sig_.commitment);

        // Return the internale type-hash of the data
        return keccak256(
            abi.encode(
                TYPED_DATA_SIGNATURE_TYPEHASH,
                sig_.commitmentHash_,
                sig_.issuedAt,
                sig_.expiresAt
            )
        );
    }

    function _calculateCommitmentHash(Datastructures.InternalCommitment memory commitment_) internal pure returns (bytes32) {
        if (commitment_.secretHash_ == bytes32(0))
            commitment_.secretHash_ = _calculateSecretHash(commitment_.secret);

        // Return the internale type-hash of the commitment
        return keccak256(
            abi.encode(
                _calculateRequestHash(commitment_.request),
                commitment_.secretHash_
            )
        );
    }

    function _calculateRequestHash(Datastructures.RegistrationRequest memory req) internal pure returns (bytes32) {
        // Return the internale type-hash of the req
        return keccak256(
            abi.encode(
                req.commitmentType,
                req.duration,
                _calculatePaymentHash(req.registrationPayment),
                _calculatePaymentHash(req.servicePayment)
            )
        );
    }

    function _calculateSecretHash(Datastructures.RegistrationSecret memory secret) internal pure returns (bytes32) {
        // Return the internale type-hash of the secret
        return keccak256(
            abi.encode(
                secret.registrant,
                secret.node,
                secret.nonce
            )
        );
    }

    function _calculatePaymentHash(Datastructures.OrderPayment memory payment_) internal pure returns (bytes32) {
        // Return the internale type-hash of the payment
        return keccak256(
            abi.encode(
                payment_.paymentType,
                payment_.amount
            )
        );
    }


    function _validPayload(bytes memory data_) internal view virtual override returns (bool) {
        RegistrationAuthorization memory sig_ = abi.decode(data_, (RegistrationAuthorization));

        // Verify that the signature is not expired and not issued in the future
        return (block.timestamp < sig_.expiresAt) && (block.timestamp > sig_.issuedAt);
    }
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;

/// External References ---------------------------------------------------------------------------

import {Initializable} from "openzeppelin-upgradeable/proxy/utils/Initializable.sol";

/// Internal References ---------------------------------------------------------------------------

import {ReentrancyGuardStorage as Storage} from "src/utils/access/storage/ReentrancyGuardStorage.sol";

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuardDiamond is Initializable {

    function __ReentrancyGuard_init() internal onlyInitializing {
        __ReentrancyGuard_init_unchained();
    }

    function __ReentrancyGuard_init_unchained() internal onlyInitializing {
        Storage.initialize();
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    function _nonReentrantBefore() private {
        // On the first call to nonReentrant, _status will be _NOT_ENTERED
        require(Storage._getStatus() != Storage._ENTERED, "ReentrancyGuard: reentrant call");

        // Any calls to nonReentrant after this point will fail
        Storage._setStatus(Storage._ENTERED);
    }

    function _nonReentrantAfter() private {
        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        Storage._setStatus(Storage._NOT_ENTERED);
    }

    /**
     * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
     * `nonReentrant` function in the call stack.
     */
    function _reentrancyGuardEntered() internal view returns (bool) {
        return Storage._getStatus() == Storage._ENTERED;
    }
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;

/// External References ---------------------------------------------------------------------------

import {Initializable} from "openzeppelin-upgradeable/proxy/utils/Initializable.sol";

/// Internal References ---------------------------------------------------------------------------

import {SponsorShieldStorage as Storage} from "src/utils/access/storage/SponsorShieldStorage.sol";

error sponsorShield_invalidPaymentType();
error sponsorShield_insufficientAmount();
error sponsorShield_alreadySponsored();
error sponsorShield_unsponsoredPayment();

abstract contract SponsorShieldDiamond is Initializable {
    function __SponsorShield_init() internal onlyInitializing {
        __SponsorShield_init_unchained();
    }

    function __SponsorShield_init_unchained() internal onlyInitializing {
        Storage.initialize();
    }

    function _startSponsorShield(address payee_, uint256 paymentType_, uint256 paymentAmount_) internal {
        // Validate guard is not already active
        if (Storage._getStatus() == Storage._SPONSORED) 
            revert sponsorShield_alreadySponsored();

        // Start guard
        Storage._setStatus(Storage._SPONSORED);

        // Track action
        Storage._setPayee(payee_);
        Storage._setPaymentType(paymentType_);
        Storage._setPaymentAmount(paymentAmount_);
    }

    function _trackSponsoredPayment(address payee_, uint256 paymentType_, uint256 paymentAmount_) internal {
        // Validate guard is active
        if (Storage._getStatus() != Storage._SPONSORED) 
            revert sponsorShield_unsponsoredPayment();

        // Track action
        if (Storage._getPayee() != payee_) 
            revert sponsorShield_unsponsoredPayment();
        if (Storage._getPaymentType() != paymentType_) 
            revert sponsorShield_invalidPaymentType();
        if (!Storage._decrementPaymentAmount(paymentAmount_)) 
            revert sponsorShield_insufficientAmount();
    }

    function _cleanupSponsorShield() internal {
        if (Storage._getStatus() == Storage._SPONSORED) {
            // Cleanup guard
            Storage._setStatus(Storage._NOT_SPONSORED);
            Storage._clearPayment();
        }
    }
}

// solhint-disable func-name-mixedcase

// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;

/// Internal References ---------------------------------------------------------------------------

import {BytesUtils} from "src/regcontrol/libraries/BytesUtils.sol";
import {
    RegistryStorage as Storage, 
    RegistrarStorage
} from "src/regcontrol/storage/Storage.sol";

import {AccessManagement} from "src/regcontrol/modules/types/AccessManagement.sol";
import {Enforcer} from "src/regcontrol/modules/types/Enforcer.sol";
import "src/regcontrol/modules/types/Errors.sol";

/// Contract -----------------------------------------------------------------------------------
contract Registry is AccessManagement, Enforcer {

    /// Internal Functions ------------------------------------------------------------------------

    function _createRegistration(bytes calldata fqdn_, address registrant_, uint32 controlBitmap_, uint64 duration_)
        internal
        returns (bytes32 node_, bytes32 tld_)
    {
        // Validate the registration
        bytes memory label_;
        (label_, tld_) = _createRegistration__validate(fqdn_, registrant_, duration_);

        // Update internal state to track the registration
        uint64 expiration_ = uint64(block.timestamp) + uint64(duration_);
        (node_) = _createRegistration__private(label_, tld_, registrant_, controlBitmap_, expiration_);

        // Emit a RegistrationCreated event
        emit RegistrationCreated(node_, tld_, fqdn_, registrant_, controlBitmap_, expiration_);

        // ERC721 Event
        emit Transfer(address(0x00), registrant_, uint256(node_));

        // ERC1155 Event
        emit TransferSingle(msg.sender, address(0x00), registrant_, uint256(node_), 1);

        // ENS Event
        emit NewOwner(tld_, keccak256(label_), registrant_);
        emit Transfer(node_, registrant_);
    }

    function _extendRegistration(bytes32 labelHash_, bytes32 tld_, uint64 duration_) internal {
        // Validate the registration duration extension
        (bytes32 node_, uint64 newExpiry_) = _extendRegistration__validate(labelHash_, tld_, duration_);

        // Update internal state to track the new expiry
        _extendRegistration__private(node_, newExpiry_);

        // Emit a RegistrationExtended event
        emit RegistrationExtended(node_, duration_, newExpiry_);
    }

    function _transferRegistration(bytes32 node_, address newRegistrant_) internal {
        // Validate the transfer
        _transferRegistration__validate(node_, newRegistrant_);

        // Update internal state to track the transfer
        address oldRegistrant_ = _transferRegistration__private(node_, newRegistrant_);

        // Emit a RegistrationTransferred event
        emit RegistrationTransferred(node_, newRegistrant_, msg.sender);

        // ERC721 Event
        emit Transfer(oldRegistrant_, newRegistrant_, uint256(node_));

        // ERC1155 Event
        emit TransferSingle(msg.sender, oldRegistrant_, newRegistrant_, uint256(node_), 1);

        // ENS Event
        emit Transfer(node_, newRegistrant_);
    }

    function _burnRegistration(bytes32 node_) internal {
        // Validate the registration exits and has no subdomains
        _burnRegistration__validate(node_);

        // Update internal state to remove the registration
        address registrant_ = _burnRegistration__private(node_);

        // Emit a RegistrationBurned event
        emit RegistrationBurned(node_, msg.sender);

        // ERC721 Event
        emit Transfer(registrant_, address(0x00), uint256(node_));

        // ERC1155 Event
        emit TransferSingle(msg.sender, registrant_, address(0x00), uint256(node_), 1);

        // ENS Event
        emit Transfer(node_, address(0x00));
    }

    /// Validators --------------------------------------------------------------------------------

    function _createRegistration__validate(bytes calldata fqdn_, address registrant_, uint64 duration_)
        internal
        view
        returns (bytes memory label_, bytes32 tld_)
    {
        bytes32 labelHash_;
        uint256 offset_;

        // Parse the label from the fqdn
        (label_, labelHash_, offset_) = BytesUtils.readAndReturnLabel(fqdn_, 0);

        // Validate the label
        if (!_isValidDomainLabel(label_)) {
            revert BaseRegControl_invalidLabel(label_);
        }

        // Parse the tld from the fqdn
        tld_ = BytesUtils.namehash(fqdn_, offset_);

        // Validate the tld
        if (!_isTLDEnabled(tld_)) {
            revert BaseRegControl_invalidTLD(tld_);
        }

        // Validate the uniqueness of the node
        if (!_isSubdomainAvailable(labelHash_, tld_)) {
            revert BaseRegControl_subdomainUnavailable(label_, tld_);
        }

        // Validate the registrant is not the zero address
        if (registrant_ == address(0x00)) {
            revert BaseRegControl_invalidRegistrant(registrant_);
        }

        // Validate the duration
        if (!_isValidRegistrationDuration(duration_)) {
            revert BaseRegControl_invalidDuration(duration_);
        }

        return (label_, tld_);
    }

    function _extendRegistration__validate(bytes32 labelHash_, bytes32 tld_, uint64 duration_)
        internal
        view
        returns (bytes32 node_, uint64 newExpiry_)
    {
        // Calculate the node
        node_ = _calculateNode(labelHash_, tld_);

        // Validate the node exists
        if (_isNodeAvailable(node_)) {
            revert BaseRegControl_nodeDoesNotExist(node_);
        }

        // Validate the node has not already expired
        if (_isNodeExpired(node_)) {
            revert BaseRegControl_nodeExpired(node_);
        }

        // Validate the tld is enabled
        if (!_isTLDEnabled(tld_)) {
            revert BaseRegControl_invalidTLD(tld_);
        }

        // TODO: Validate the tld is not locked

        // Validate the new expiry
        bool valid_;
        (valid_, newExpiry_) = _isValidRegistrationDurationExtension(node_, duration_);
        if (!valid_) {
            revert BaseRegControl_invalidDurationExtension(duration_);
        }

        return (node_, newExpiry_);
    }

    function _transferRegistration__validate(bytes32 node_, address newRegistrant_) internal view {
        // Validate the node exists
        if (_isNodeAvailable(node_)) {
            revert BaseRegControl_nodeDoesNotExist(node_);
        }

        // Validate the node is transferable (not expired or locked)
        if (!_isNodeTransferable(node_)) {
            revert BaseRegControl_nodeNotTransferable(node_);
        }

        // Validate the new registrant is not the zero address
        if (newRegistrant_ == address(0x00)) {
            revert BaseRegControl_invalidRegistrant(newRegistrant_);
        }
    }

    function _burnRegistration__validate(bytes32 node_) internal view {
        // Validate the node exists
        if (_isNodeAvailable(node_)) {
            revert BaseRegControl_nodeDoesNotExist(node_);
        }

        // Validate the node has not already expired
        if (_isNodeExpired(node_)) {
            revert BaseRegControl_nodeExpired(node_);
        }

        // Validate the node has no children/subdomains
        if (_hasSubdomains(node_)) {
            revert BaseRegControl_nodeHasSubdomains(node_);
        }
    }

    /// Private Functions -------------------------------------------------------------------------

    function _createRegistration__private(
        bytes memory label_,
        bytes32 parent_,
        address registrant_,
        uint32 controlBitmap_,
        uint64 expiration_
    ) private returns (bytes32 node_) {
        // Calculate the node
        node_ = _calculateNode(keccak256(label_), parent_);

        // Initialize the record data
        (address owner_,,) = Storage.getRecordData(node_);
        if (owner_ == address(0)) {
            // Create the new record
            Storage.createNewRecord(node_, registrant_, controlBitmap_, expiration_);

            // Build a reverse record mapping for the node to the parent
            Storage.trackReverseRecord(parent_, label_);
        } else {
            // Update the record data
            Storage.setRecordData(node_, registrant_, controlBitmap_, expiration_);

            // Renounce it from the previous owner
            Storage.renounceOwnership(node_, registrant_);
        }

        // Track the ownership
        Storage.trackNewOwnership(node_, registrant_);

        // Remove approvals
        _clearRegistrationApprovals(node_);
    }

    function _extendRegistration__private(bytes32 node_, uint64 newExpiry_) private {
        // Get the current record data
        (address registrant_, uint32 controlBitmap_,) = Storage.getRecordData(node_);

        // Update the current expiry of the node
        Storage.setRecordData(node_, registrant_, controlBitmap_, newExpiry_);
    }

    function _transferRegistration__private(bytes32 node_, address newRegistrant_) private returns (address) {
        // Get the current registrant of the node
        (address registrant_, uint32 controlBitmap, uint64 expiry_) = Storage.getRecordData(node_);

        // Remove the node from the registrant's enumerable set
        Storage.renounceOwnership(node_, registrant_);

        // Update the registrant record
        Storage.setRecordData(node_, newRegistrant_, controlBitmap, expiry_);

        // Track the ownership with the new registrant
        Storage.trackNewOwnership(node_, newRegistrant_);
        
        // Remove approvals
        _clearRegistrationApprovals(node_);

        return registrant_;
    }

    function _burnRegistration__private(bytes32 node_) private returns (address) {
        address registrant_ = _getRegistrant(node_);

        // Renounce the ownership of the node
        Storage.renounceOwnership(node_, registrant_);

        // Remove the reverse record mapping
        Storage.untrackReverseRecord(node_);

        // Remove the node from the records mapping
        Storage.deleteRecord(node_);

        // Remove approval
        _clearRegistrationApprovals(node_);

        // Delete any locks on the domain
        RegistrarStorage.setDomainLockData(node_, 0);

        return registrant_;
    }

    /// Helper Functions --------------------------------------------------------------------------

    function _isValidDomainLabel(bytes memory label_) internal pure returns (bool) {
        // Check if label is empty or exceeds 63 characters
        if (label_.length == 0x00 || label_.length > 0x3f) return false;

        // Check first and last character for hyphen
        if (label_[0] == 0x2d || label_[label_.length - 1] == 0x2d) return false;

        // Check if label contains invalid characters
        for (uint256 i = 0; i < label_.length; i++) {
            bytes1 char_ = label_[i];

            // Ensure alphanumeric and lowercase.
            // ASCII values: 0-9 => 48-57, a-z => 97-122
            // 45 is hyphen ("-")
            if (
                !(char_ >= 0x30 && char_ <= 0x39) // Check for 0-9
                    && !(char_ >= 0x61 && char_ <= 0x7A) // Check for a-z
                    && char_ != 0x2d
            ) {
                // Check for hyphen, but we already checked the start and end
                return false;
            }
        }
        return true;
    }

    function _isValidRegistrationDuration(uint64 duration_) internal pure returns (bool) {
        return duration_ > 0 && duration_ <= 10 * YEAR;
    }

    function _isValidRegistrationDurationExtension(bytes32 node_, uint64 durationExtension_)
        internal
        view
        returns (bool valid_, uint64 newExpiry_)
    {
        // Renewal must be non zero and in years
        // The new cumulative duration must be less than 10 years

        // Get the current expiry & calculate the new expiry.
        (,, newExpiry_) = Storage.getRecordData(node_);
        newExpiry_ += durationExtension_;

        // Validate the extension and the new expiry.
        valid_ = _isValidRegistrationDuration(durationExtension_) && newExpiry_ <= (block.timestamp + 10 * YEAR);

        // Return the validity and the new expiration.
        return (valid_, newExpiry_);
    }

    function _isTLDEnabled(bytes32 tld_) internal view returns (bool) {
        (bool enabled_) = RegistrarStorage.getTLDData(tld_);
        return enabled_;
    }
}

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

error IndexOutOfBounds(uint256 index, uint256 length);
error NoLabelAtSpecifiedIndex();
error SubstringOverflow();
error JunkAtEndOfName();

error BytesUtils_notFullyQualified();

library BytesUtils {
    /*
     * @dev Returns the keccak-256 hash of a byte range.
     * @param self The byte string to hash.
     * @param offset The position to start hashing at.
     * @param len The number of bytes to hash.
     * @return The hash of the byte range.
     */
    function keccak(bytes memory self, uint256 offset, uint256 len) internal pure returns (bytes32 ret) {
        if (offset + len > self.length) revert IndexOutOfBounds(offset + len, self.length);
        assembly {
            ret := keccak256(add(add(self, 32), offset), len)
        }
    }

    /**
     * @dev Returns the ENS namehash of a DNS-encoded name.
     * @param self The DNS-encoded name to hash.
     * @param offset The offset at which to start hashing.
     * @return The namehash of the name.
     */
    function namehash(bytes memory self, uint256 offset) internal pure returns (bytes32) {
        (bytes32 labelhash, uint256 newOffset) = readLabel(self, offset);
        if (labelhash == bytes32(0)) {
            if (offset != self.length - 1) revert JunkAtEndOfName();
            return bytes32(0);
        }
        return keccak256(abi.encodePacked(namehash(self, newOffset), labelhash));
    }

    /**
     * @dev Returns the keccak-256 hash of a DNS-encoded label, and the offset to the start of the next label.
     * @param self The byte string to read a label from.
     * @param idx The index to read a label at.
     * @return labelhash The hash of the label at the specified index, or 0 if it is the last label.
     * @return newIdx The index of the start of the next label.
     */
    function readLabel(bytes memory self, uint256 idx) internal pure returns (bytes32 labelhash, uint256 newIdx) {
        if (idx >= self.length) revert IndexOutOfBounds(idx, self.length);
        uint256 len = uint256(uint8(self[idx]));
        if (len > 0) {
            labelhash = keccak(self, idx + 1, len);
        } else {
            labelhash = bytes32(0);
        }
        newIdx = idx + len + 1;
    }

    /**
     * @dev Qualifies that the host is fully qualified relative to the parent node & returns the ending index of the label.
     * @param self The wire-encoded host.
     * @param parent The namehash of the parent node.
     * @return hostNodes The namehash of all children leading up to the host.
     */
    function validateHost(
        bytes memory self,
        bytes32 parent,
        bool qualifyHost
    ) internal pure returns (bytes32[] memory hostNodes) {
        // Calculate all label hashes
        (bytes32[] memory labelhashes) = hashParts(self, 0);

        // Calculate the namehash
        bytes32 node;
        bool qualified;
        uint256 pos = labelhashes.length;

        if (!qualifyHost) {
            node = parent;
            qualified = true;
            hostNodes = new bytes32[](pos);
        }
        for (; pos > 0; pos--) {
            node = keccak256(abi.encodePacked(node, labelhashes[pos - 1]));
            if (!qualified) {
                if (node == parent) {
                    qualified = true;
                    hostNodes = new bytes32[](pos - 1);
                }
            } else {
                // Once we are qualified, we can start storing the host nodes
                hostNodes[hostNodes.length - pos] = node;
            }
        }

        // Ensure that the name is fully qualified
        if (!qualified) revert BytesUtils_notFullyQualified();
        return hostNodes;
    }

    /**
     * @dev Returns the keccak-256 hash of a wire-encoded labeles.
     * @param self The wire-encoded host.
     * @param idx The index to start reading labels from.
     * @return labelhashes The hash of the label from the wire-encoded host.
     */
    function hashParts(
        bytes memory self,
        uint256 idx
    ) internal pure returns (bytes32[] memory labelhashes) {
        // Count the number of labels
        uint256 count;
        uint256 offset = idx;
        while (offset < self.length && self[offset] != 0x00) {
            offset += uint256(uint8(self[offset])) + 1;
            count++;
        }

        // Ensure that we consumed the entire input
        require(isEnd(self, offset), "hashParts: Junk at end of name");

        // Initialize the output array
        labelhashes = new bytes32[](count);

        // Hash the labels
        offset = idx;
        for (uint256 i = 0; i < count; i++) {
            (labelhashes[i], offset) = readLabel(self, offset);
        }

        // Return the output
        return labelhashes;
    }

    function isEnd(bytes memory self, uint256 offset) internal pure returns (bool) {
        return offset == self.length - 1 && self[offset] == 0x00;
    }

    function readAndReturnLabel(bytes memory self, uint256 idx)
        internal
        pure
        returns (bytes memory label, bytes32 labelhash, uint256 newIdx)
    {
        (labelhash, newIdx) = readLabel(self, idx);
        if (idx == newIdx) {
            revert NoLabelAtSpecifiedIndex();
        }
        label = substring(self, idx + 1, uint256(uint8(self[idx])));
    }

    /*
     * @dev Copies a substring into a new byte string.
     * @param self The byte string to copy from.
     * @param offset The offset to start copying at.
     * @param len The number of bytes to copy.
     */
    function substring(bytes memory self, uint256 offset, uint256 len) internal pure returns (bytes memory) {
        if (offset + len > self.length) revert SubstringOverflow();

        bytes memory ret = new bytes(len);
        uint256 dest;
        uint256 src;

        assembly {
            dest := add(ret, 32)
            src := add(add(self, 32), offset)
        }
        _memcpy(dest, src, len);

        return ret;
    }

    function _memcpy(uint256 dest, uint256 src, uint256 len) private pure {
        // Copy word-length chunks while possible
        for (; len >= 32; len -= 32) {
            assembly {
                mstore(dest, mload(src))
            }
            dest += 32;
            src += 32;
        }

        // Copy remaining bytes
        unchecked {
            uint256 mask = (256 ** (32 - len)) - 1;
            assembly {
                let srcpart := and(mload(src), not(mask))
                let destpart := and(mload(dest), mask)
                mstore(dest, or(destpart, srcpart))
            }
        }
    }
}

File 24 of 63 : Datastructures.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;

library Datastructures {
    /// Registration Datastructures ---------------------------------------------------------------

    /// Payment Datastructures --------------------------------------------------------------------

    /// @title OrderPayment
    /// @notice Represents the details of the payment for an order.
    /// @param paymentType The method/type of payment chosen.
    /// @param amount The amount of the payment made, stored in the smallest unit (like wei for ETH).
    struct OrderPayment {
        PaymentType paymentType; // Type of payment (e.g., ETH or USDC)
        uint248 amount; // Amount of payment made. Using uint248 can save storage if combined with other small types in future.
    }

    /// @title PaymentType
    /// @notice Enumerated types of accepted payment methods.
    enum PaymentType {
        UNDEFINED,
        USDC,
        ETH
    }

    /// Commitment Datastructures -----------------------------------------------------------------

    /// @title InternalCommitment
    /// @notice Represents the details of a commitment.
    /// @param secret The registration secret being committed to.
    /// @param request The duration of the registration.
    struct InternalCommitment {
        RegistrationRequest request;
        RegistrationSecret secret;
        bytes32 secretHash_;
    }

    /// @title RegistrationRequest
    /// @notice Represents the details of a registration request.
    /// (uint8,uint64,(uint8,uint248),(uint8,uint248))
    struct RegistrationRequest {
        CommitmentType commitmentType;
        uint64 duration;
        OrderPayment registrationPayment;
        OrderPayment servicePayment;
    }

    /// @title RegistrationSecret
    /// @notice Represents the details of a registration secret.
    /// @param registrant The address of the registrant.
    /// @param node The namehash-encoded domain name being registered.
    /// @param nonce The nonce of the registration secret.
    struct RegistrationSecret {
        address registrant;
        bytes32 node;
        bytes32 nonce;
    }

    /// @title CommitmentType
    /// @notice Enumerated types of commitments.
    enum CommitmentType {
        UNDEFINED,
        REGISTRATION__FULL_TOKENIZATION,  
        RENEWAL,        
        OFFCHAIN__FULL_TOKENIZATION,
        TRANSFER__FULL_TOKENIZATION,
        REGISTRATION__TRADER_TOKENIZATION,
        OFFCHAIN__TRADER_TOKENIZATION,
        TRANSFER__TRADER_TOKENIZATION,
        OFFCHAIN_RENEWAL,
        OFFCHAIN_RENEWAL__TRADER_TOKENIZATION,
        RENEWAL__TRADER_TOKENIZATION,
        SERVICE_PAYMENT
    }

    /// @title Signature
    /// @notice
    /// (uint64,uint64,uint8,bytes32,bytes32)
    struct AuthorizationSignature {
        uint64 issuedAt;
        uint64 expiresAt;
        uint8 v;
        bytes32 r;
        bytes32 s;
    }

    struct Signature {
        uint8 v;
        bytes32 r;
        bytes32 s;
    }
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;

interface IWETH {
    function deposit() external payable;
    function withdraw(uint256 wad) external;

    function balanceOf(address account) external view returns (uint256);
    function allowance(address owner, address spender) external view returns (uint256);

    function totalSupply() external view returns (uint256);

    function approve(address guy, uint256 wad) external returns (bool);

    function transfer(address dst, uint256 wad) external returns (bool);

    function transferFrom(address src, address dst, uint256 wad) external returns (bool);
}

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

pragma solidity ^0.8.0;

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

// SPDX-License-Identifier: BUSL-1.1
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/IERC721.sol)

pragma solidity ^0.8.0;

import {IERC165Upgradeable as IERC165} from
    "openzeppelin-contracts-upgradeable/contracts/utils/introspection/IERC165Upgradeable.sol";

/**
 * @dev Required interface of an ERC721 compliant contract.
 */
interface IERC721 is IERC165 {
    /**
     * @dev Returns the number of tokens in ``owner``'s account.
     */
    function balanceOf(address owner) external view returns (uint256 balance);

    /**
     * @dev Returns the owner of the `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function ownerOf(uint256 tokenId) external view returns (address owner);

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
     * are aware of the ERC721 protocol to prevent tokens from being forever locked.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(address from, address to, uint256 tokenId) external;

    /**
     * @dev Transfers `tokenId` token from `from` to `to`.
     *
     * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
     * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
     * understand this adds an external call which potentially creates a reentrancy vulnerability.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 tokenId) external;

    /**
     * @dev Gives permission to `to` to transfer `tokenId` token to another account.
     * The approval is cleared when the token is transferred.
     *
     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
     *
     * Requirements:
     *
     * - The caller must own the token or be an approved operator.
     * - `tokenId` must exist.
     *
     * Emits an {Approval} event.
     */
    function approve(address to, uint256 tokenId) external;

    /**
     * @dev Approve or remove `operator` as an operator for the caller.
     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
     *
     * Requirements:
     *
     * - The `operator` cannot be the caller.
     *
     * Emits an {ApprovalForAll} event.
     */
    function setApprovalForAll(address operator, bool approved) external;

    /**
     * @dev Returns the account approved for `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function getApproved(uint256 tokenId) external view returns (address operator);

    /**
     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
     *
     * See {setApprovalForAll}
     */
    function isApprovedForAll(address owner, address operator) external view returns (bool);
}

/**
 * @title ERC721 token receiver interface
 * @dev Interface for any contract that wants to support safeTransfers
 * from ERC721 asset contracts.
 */
interface IERC721Receiver {
    /**
     * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
     * by `operator` from `from`, this function is called.
     *
     * It must return its Solidity selector to confirm the token transfer.
     * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
     *
     * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
     */
    function onERC721Received(
        address operator,
        address from,
        uint256 tokenId,
        bytes calldata data
    ) external returns (bytes4);
}


/**
 * @title ERC-721 Non-Fungible Token Standard, optional metadata extension
 * @dev See https://eips.ethereum.org/EIPS/eip-721
 */
interface IERC721Metadata is IERC721 {
    /**
     * @dev Returns the token collection name.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the token collection symbol.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
     */
    function tokenURI(uint256 tokenId) external view returns (string memory);
}

// SPDX-License-Identifier: BUSL-1.1
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC1155/IERC1155.sol)

pragma solidity ^0.8.0;

import {IERC165Upgradeable as IERC165} from
    "openzeppelin-contracts-upgradeable/contracts/utils/introspection/IERC165Upgradeable.sol";

interface IERC1155 is IERC165 {
    // /**
    //  * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.
    //  */
    // event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);

    // /**
    //  * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
    //  * transfers.
    //  */
    // event TransferBatch(
    //     address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] values
    // );

    // /**
    //  * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
    //  * `approved`.
    //  */
    // event ApprovalForAll(address indexed account, address indexed operator, bool approved);

    // /**
    //  * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
    //  *
    //  * If an {URI} event was emitted for `id`, the standard
    //  * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
    //  * returned by {IERC1155MetadataURI-uri}.
    //  */
    // event URI(string value, uint256 indexed id);

    // /**
    //  * @dev Returns the amount of tokens of token type `id` owned by `account`.
    //  *
    //  * Requirements:
    //  *
    //  * - `account` cannot be the zero address.
    //  */
    function balanceOf(address account, uint256 id) external view returns (uint256);

    // /**
    //  * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
    //  *
    //  * Requirements:
    //  *
    //  * - `accounts` and `ids` must have the same length.
    //  */
    function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids)
        external
        view
        returns (uint256[] memory);

    /**
     * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,
     *
     * Emits an {ApprovalForAll} event.
     *
     * Requirements:
     *
     * - `operator` cannot be the caller.
     */
    function setApprovalForAll(address operator, bool approved) external;

    /**
     * @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
     *
     * See {setApprovalForAll}.
     */
    function isApprovedForAll(address account, address operator) external view returns (bool);

    // /**
    //  * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
    //  *
    //  * Emits a {TransferSingle} event.
    //  *
    //  * Requirements:
    //  *
    //  * - `to` cannot be the zero address.
    //  * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.
    //  * - `from` must have a balance of tokens of type `id` of at least `amount`.
    //  * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
    //  * acceptance magic value.
    //  */
    function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes calldata data) external;

    // /**
    //  * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
    //  *
    //  * Emits a {TransferBatch} event.
    //  *
    //  * Requirements:
    //  *
    //  * - `ids` and `amounts` must have the same length.
    //  * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
    //  * acceptance magic value.
    //  */
    function safeBatchTransferFrom(
        address from,
        address to,
        uint256[] calldata ids,
        uint256[] calldata amounts,
        bytes calldata data
    ) external;
}

interface IERC1155MetadataURI is IERC1155 {
/**
 * @dev Returns the URI for token type `id`.
 *
 * If the `\{id\}` substring is present in the URI, it must be replaced by
 * clients with the actual token type ID.
 */
function uri(uint256 id) external view returns (string memory);
}

interface IERC1155Receiver is IERC165 {
    /**
     * @dev Handles the receipt of a single ERC1155 token type. This function is
     * called at the end of a `safeTransferFrom` after the balance has been updated.
     *
     * NOTE: To accept the transfer, this must return
     * `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
     * (i.e. 0xf23a6e61, or its own function selector).
     *
     * @param operator The address which initiated the transfer (i.e. msg.sender)
     * @param from The address which previously owned the token
     * @param id The ID of the token being transferred
     * @param value The amount of tokens being transferred
     * @param data Additional data with no specified format
     * @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed
     */
    function onERC1155Received(address operator, address from, uint256 id, uint256 value, bytes calldata data)
        external
        returns (bytes4);

    /**
     * @dev Handles the receipt of a multiple ERC1155 token types. This function
     * is called at the end of a `safeBatchTransferFrom` after the balances have
     * been updated.
     *
     * NOTE: To accept the transfer(s), this must return
     * `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
     * (i.e. 0xbc197c81, or its own function selector).
     *
     * @param operator The address which initiated the batch transfer (i.e. msg.sender)
     * @param from The address which previously owned the token
     * @param ids An array containing ids of each token being transferred (order and length must match values array)
     * @param values An array containing amounts of each token being transferred (order and length must match ids array)
     * @param data Additional data with no specified format
     * @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed
     */
    function onERC1155BatchReceived(
        address operator,
        address from,
        uint256[] calldata ids,
        uint256[] calldata values,
        bytes calldata data
    ) external returns (bytes4);
}

// solhint-disable func-name-mixedcase

// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;

/// External References ---------------------------------------------------------------------------

import {Initializable} from "openzeppelin-upgradeable/proxy/utils/Initializable.sol";

/// Internal References ---------------------------------------------------------------------------

import {ICustomToken} from "src/regcontrol/interfaces/tokens/ICustomToken.sol";

import {IERC721, IERC721Receiver} from "src/regcontrol/interfaces/tokens/IERC721.sol";
import {IERC1155, IERC1155MetadataURI, IERC1155Receiver} from "src/regcontrol/interfaces/tokens/IERC1155.sol";

import {IIAM} from "src/regcontrol/interfaces/IIAM.sol";

import {HybridMetadataService} from "src/regcontrol/modules/types/metadata/HybridMetadataService.sol";

import {Registry} from "src/regcontrol/modules/types/Registry.sol";
import {AccessManagement} from "src/regcontrol/modules/types/AccessManagement.sol";

import {AddressUpgradeable} from "openzeppelin-upgradeable/utils/AddressUpgradeable.sol";

/// Errors -------------------------------------------------------------------------------------

error CustomToken_ArrayLengthMismatch();
error CustomToken_InsufficientBalance();

error CustomToken_SenderNotOwnerOrOperator();

error CustomToken_ZeroAddress();
error CustomToken_InvalidAddress();

error CustomToken_ERC721ReceiverRejectedTokens();
error CustomToken_ERC1155ReceiverRejectedTokens();
error CustomToken_NotTokenReceiver();

abstract contract CustomToken is
    ICustomToken,
    AccessManagement,
    Registry,
    HybridMetadataService
{
    /// Libraries ---------------------------------------------------------------------------------

    using AddressUpgradeable for address;

    /// Accessor Functions ------------------------------------------------------------------------

    function _getFQDN(bytes32 node_) internal view override returns (string memory fqdn_, bytes32 tld_) {
        if (node_ == bytes32(0x00)) {
            return ("", bytes32(0x00));
        }

        (fqdn_, tld_) = _getFQDN(_getParent(node_));
        if (tld_ == bytes32(0x00)) {
            tld_ = _getParent(node_);
        }

        if (bytes(fqdn_).length == 0) {
            fqdn_ = string(_getLabel(node_));
        } else {
            fqdn_ = string(abi.encodePacked(_getLabel(node_), ".", fqdn_));
        }

        return (fqdn_, tld_);
    }

    /// Approval Functions ------------------------------------------------------------------------

    function approve(address to, uint256 tokenId) external override {
        // Validate caller has permission to approve the operator
        if (!_permissionCheck_registration(bytes32(tokenId), msg.sender, IIAM.IAMRole.ADMIN, IIAM.IAMPermission.MANAGE)) {
            revert CustomToken_SenderNotOwnerOrOperator();
        }

        // Function uses msg.sender for account indexed operations
        _setRegistrationApproval(bytes32(tokenId), to);
    }

    function getApproved(uint256 tokenId) external view returns (address operator) {
        if ((operator = ownerOf(tokenId)) == address(0)) {
            revert CustomToken_ZeroAddress();
        }
        return _getApprovedRegistrationOperator(bytes32(tokenId));
    }

    /// ERC721 ------------------------------------------------------------------------------------

    function totalSupply() external view returns (uint256) {
        return _getRecordCount();
    }

    function ownerOf(uint256 tokenId) public view returns (address) {
        return _getRegistrant(bytes32(tokenId));
    }

    function balanceOf(address owner_) external view returns (uint256) {
        if (owner_ == address(0)) {
            revert CustomToken_ZeroAddress();
        }
        return _getDomainNameOwnershipCount(owner_);
    }

    function transferFrom(address from_, address to_, uint256 tokenId_) external override {
        // Run access control check
        _transfer__validate(from_, to_, tokenId_, 1);

        // Execute the transfer
        _transfer__execute(from_, to_, tokenId_);
    }

    function safeTransferFrom(address from_, address to_, uint256 tokenId_, bytes calldata data_) external override {
        // Run access control check
        _transfer__validate(from_, to_, tokenId_, 1);

        // Execute the transfer
        _transfer__execute(from_, to_, tokenId_);

        // Run the callback
        _transfer__callback(from_, to_, tokenId_, data_);
    }

    function safeTransferFrom(address from_, address to_, uint256 tokenId_) external override {
        // Run access control check
        _transfer__validate(from_, to_, tokenId_, 1);

        // Execute the transfer
        _transfer__execute(from_, to_, tokenId_);

        // Run the callback
        _transfer__callback(from_, to_, tokenId_, "");
    }

    /// ERC1155 Methods ---------------------------------------------------------------------------

    /// @dev See {IERC1155-balanceOf}.
    function balanceOf(address account_, uint256 id_) public view virtual override returns (uint256) {
        if (account_ == address(0)) {
            revert CustomToken_ZeroAddress();
        }
        return account_ == ownerOf(id_) ? 1 : 0;
    }

    /// @dev See {IERC1155-balanceOfBatch}.
    function balanceOfBatch(address[] calldata accounts_, uint256[] calldata ids_)
        public
        view
        virtual
        override
        returns (uint256[] memory balances_)
    {
        if (accounts_.length != ids_.length) {
            revert CustomToken_ArrayLengthMismatch();
        }

        balances_ = new uint256[](accounts_.length);
        for (uint256 i = 0; i < accounts_.length; ++i) {
            balances_[i] = balanceOf(accounts_[i], ids_[i]);
        }
    }

    /// @dev See {IERC1155-safeTransferFrom}.
    function safeTransferFrom(address from_, address to_, uint256 id_, uint256 amount_, bytes calldata data_)
        public
        virtual
        override
    {
        _transfer__validate(from_, to_, id_, amount_);
        _transfer__execute(from_, to_, id_);
        _transfer__callback(from_, to_, id_, data_);
    }

    /// @dev See {IERC1155-safeBatchTransferFrom_}.
    function safeBatchTransferFrom(
        address from_,
        address to_,
        uint256[] calldata ids_,
        uint256[] calldata amounts_,
        bytes calldata data_
    ) public virtual override {
        if (ids_.length != amounts_.length) {
            revert CustomToken_ArrayLengthMismatch();
        }

        uint256 index_ = 0;
        for (; index_ < ids_.length; ++index_) {
            uint256 id_ = ids_[index_];

            // Validate the transfer
            _transfer__validate(from_, to_, id_, amounts_[index_]);

            // Execute the transfer
            _transfer__execute(from_, to_, id_);
        }

        // emit TransferBatch(msg.sender, from_, to_, ids_, amounts_);

        _doSafeBatchTransferAcceptanceCheck(msg.sender, from_, to_, ids_, amounts_, data_);
    }

    /// Transfer Functions ------------------------------------------------------------------------

    function _transfer__validate(address from_, address to_, uint256 id_, uint256 amount_) internal view virtual {
        if (from_ == address(0) || to_ == address(0)) {
            revert CustomToken_ZeroAddress();
        }
        if (amount_ != 1) {
            revert CustomToken_ArrayLengthMismatch();
        }
        if (from_ != _getRegistrant(bytes32(id_))) {
            revert CustomToken_InsufficientBalance();
        }

        // Caller is node operator
        if(!_permissionCheck_registration(bytes32(id_), msg.sender, IIAM.IAMRole.ADMIN, IIAM.IAMPermission.MANAGE)) {
            revert CustomToken_SenderNotOwnerOrOperator();
        }
    }

    function _transfer__execute(address from_, address to_, uint256 id_) internal {
        if (from_ == to_) {
            return;
        }

        // TODO: Determine if other checks are needed
        _transferRegistration(bytes32(id_), to_);
    }

    /// @dev internal helper function for transfering a node
    function _transfer__callback(address from_, address to_, uint256 id_, bytes memory data_) internal {
        _doSafeTransferAcceptanceCheck(msg.sender, from_, to_, id_, 1, data_);
    }

    /// Internal Helper Functions =================================================================

    /// @dev internal helper function for performing a post transfer check on non-EOA receivers.
    function _doSafeTransferAcceptanceCheck(
        address operator_,
        address from_,
        address to_,
        uint256 id_,
        uint256 amount_,
        bytes memory data_
    ) private {
        if (to_.isContract()) {
            /* ERC1155 handling */
            (bool success1, bytes memory data1) = to_.call(abi.encodeCall(IERC1155Receiver.onERC1155Received, (operator_, from_, id_, amount_, data_)));
            if (success1 && data1.length != 0) {  // success AND has return data -> check return data, expect it to have 4 bytes
                if (abi.decode(data1, (bytes4)) != IERC1155Receiver.onERC1155Received.selector) {
                    revert CustomToken_ERC1155ReceiverRejectedTokens();
                }
            } else { // failure OR no return data: fallback OR low-level failure (without error message) OR high-level error message
                /* ERC721 handling */
                (bool success2, bytes memory data2) = to_.call(abi.encodeCall(IERC721Receiver.onERC721Received, (operator_, from_, id_, data_)));
                if (data2.length != 0) { // has return data
                    if (success2) { // success -> check return data, expect it to have 4 bytes
                        if (abi.decode(data2, (bytes4)) != IERC721Receiver.onERC721Received.selector) {
                            revert CustomToken_ERC721ReceiverRejectedTokens();
                        }
                    }
                    else { // failure -> forward error message
                        /// @solidity memory-safe-assembly
                        assembly {
                            revert(add(32, data2), mload(data2))
                        }
                    }
                } else  { // no return data: failure without error message -> forward previous error message
                    if (data1.length != 0) {
                        /// @solidity memory-safe-assembly
                        assembly {
                            revert(add(32, data1), mload(data1))
                        }
                    }
                    else {
                        revert CustomToken_NotTokenReceiver();
                    }
                }
            }
        }
    }

    /// @dev internal helper function for performing a post batch-transfer check on non-EOA receivers.
    function _doSafeBatchTransferAcceptanceCheck(
        address operator_,
        address from,
        address to_,
        uint256[] memory ids,
        uint256[] memory amounts,
        bytes memory data_
    ) private {
        if (to_.isContract()) {
            try IERC1155Receiver(to_).onERC1155BatchReceived(operator_, from, ids, amounts, data_) returns (
                bytes4 response
            ) {
                if (response != IERC1155Receiver(to_).onERC1155BatchReceived.selector) {
                    revert CustomToken_ERC1155ReceiverRejectedTokens();
                }
            } catch Error(string memory reason) {
                revert(reason);
            } catch {
                revert CustomToken_NotTokenReceiver();
            }
        }
    }
}

// solhint-disable func-name-mixedcase

// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;

/// External References ---------------------------------------------------------------------------

import {Initializable} from "openzeppelin-upgradeable/proxy/utils/Initializable.sol";

/// Internal References ---------------------------------------------------------------------------

import {IENS} from "src/regcontrol/interfaces/tokens/IENS.sol";

import {IIAM} from "src/regcontrol/interfaces/IIAM.sol";

import {AccessManagement} from "src/regcontrol/modules/types/AccessManagement.sol";
import {Registry} from "src/regcontrol/modules/types/Registry.sol";

import {RegControlStorage} from "src/regcontrol/storage/Storage.sol";

/// Errors -------------------------------------------------------------------------------------

error DomainController_accessDenied();
error DomainController_notSupported();

abstract contract CustomENS is 
    IENS,
    AccessManagement, 
    Registry
{

    /// Constants ---------------------------------------------------------------------------------

    uint64 public constant DEFAULT_TTL = 3600;

    /// User Functions ----------------------------------------------------------------------------

    function transfer(bytes32 node_, address recipient_) external {
        // Run access control check
        if (!_permissionCheck_registration(node_, msg.sender, IIAM.IAMRole.ADMIN, IIAM.IAMPermission.MANAGE)) {
            revert DomainController_accessDenied();
        }

        // Transfer
        _transferRegistration(node_, recipient_);
    }

    /// Approval Functions ------------------------------------------------------------------------

    function setRecord(
        bytes32 node,
        address owner,
        address resolver,
        uint64 ttl
    ) external override {
        revert DomainController_notSupported();
    }

    function setSubnodeRecord(
        bytes32 node,
        bytes32 label,
        address owner,
        address resolver,
        uint64 ttl
    ) external override {
        revert DomainController_notSupported();
    }

    function setSubnodeOwner(
        bytes32 node,
        bytes32 label,
        address owner
    ) external override returns (bytes32) {
        revert DomainController_notSupported();
    }

    function setResolver(bytes32 node, address resolver) external override {
        revert DomainController_notSupported();
    }

    function setOwner(bytes32 node_, address owner_) external override {
        // Run access control check
        if (!_permissionCheck_registration(node_, msg.sender, IIAM.IAMRole.ADMIN, IIAM.IAMPermission.MANAGE)) {
            revert DomainController_accessDenied();
        }

        // Transfer
        _transferRegistration(node_, owner_);
    }

    function setTTL(bytes32 node, uint64 ttl) external override {
        revert DomainController_notSupported();
    }

    /// Accessor Functions ------------------------------------------------------------------------

    function owner(bytes32 node) public view override returns (address) {
        return _getRegistrant(node);
    }

    function resolver(bytes32 node) external view override returns (address) {
        return _resolver(node);
    }

    function ttl(bytes32 node) external view override returns (uint64) {
        return DEFAULT_TTL;
    }

    function recordExists(bytes32 node) external view override returns (bool) {
        return !_isNodeAvailable(node);
    }
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;

/// Internal References ---------------------------------------------------------------------------

import {IENS} from "src/regcontrol/interfaces/tokens/IENS.sol";
import {ICustomToken} from "src/regcontrol/interfaces/tokens/ICustomToken.sol";

interface IDomainController is 
    IENS,
    ICustomToken
{
    function setApprovalForAll(address operator_, bool approved_) external override(IENS, ICustomToken);

    function isApprovedForAll(address account_, address operator_)
        external
        view
        override(IENS, ICustomToken)
        returns (bool);
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;

interface IENS {
    
    // /// Events ---------------------------------------------------------------------------------
    
    // // Logged when the owner of a node assigns a new owner to a subnode.
    // event NewOwner(bytes32 indexed node, bytes32 indexed label, address owner);

    // // Logged when the owner of a node transfers ownership to a new account.
    // event Transfer(bytes32 indexed node, address owner);

    // // Logged when the resolver for a node changes.
    // event NewResolver(bytes32 indexed node, address resolver);

    // // Logged when the TTL of a node changes
    // event NewTTL(bytes32 indexed node, uint64 ttl);

    // // Logged when an operator is added or removed.
    // event ApprovalForAll(
    //     address indexed owner,
    //     address indexed operator,
    //     bool approved
    // );
    
    /// Management Functions ----------------------------------------------------------------------

    function setRecord(
        bytes32 node,
        address owner,
        address resolver,
        uint64 ttl
    ) external;

    function setSubnodeRecord(
        bytes32 node,
        bytes32 label,
        address owner,
        address resolver,
        uint64 ttl
    ) external;

    function setSubnodeOwner(
        bytes32 node,
        bytes32 label,
        address owner
    ) external returns (bytes32);

    function setResolver(bytes32 node, address resolver) external;

    function setOwner(bytes32 node, address owner) external;

    function setTTL(bytes32 node, uint64 ttl) external;

    function setApprovalForAll(address operator, bool approved) external;

    /// Accessor Functions ------------------------------------------------------------------------

    function owner(bytes32 node) external view returns (address);

    function resolver(bytes32 node) external view returns (address);

    function ttl(bytes32 node) external view returns (uint64);

    function recordExists(bytes32 node) external view returns (bool);

    function isApprovedForAll(
        address owner,
        address operator
    ) external view returns (bool);
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;

/// Internal References ---------------------------------------------------------------------------

import {IERC721, IERC721Metadata} from "src/regcontrol/interfaces/tokens/IERC721.sol";
import {IERC1155, IERC1155MetadataURI} from "src/regcontrol/interfaces/tokens/IERC1155.sol";

interface ICustomToken is IERC721Metadata, IERC1155MetadataURI {
    /// Shared Function Overrides -----------------------------------------------------------------

    function setApprovalForAll(address operator_, bool approved_) external override(IERC721, IERC1155);

    function isApprovedForAll(address account_, address operator_)
        external
        view
        override(IERC721, IERC1155)
        returns (bool);

    /// ERC-1155 Compliance -----------------------------------------------------------------------

    function uri(uint256 tokenId) external view returns (string memory);
    
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.17;

/// Internal References ---------------------------------------------------------------------------

import {IPaymentProcessor} from "src/regcontrol/interfaces/IPaymentProcessor.sol";

import {Datastructures} from "src/regcontrol/storage/Datastructures.sol";

/// Errors -------------------------------------------------------------------------------------

error PaymentModule_notSupported();

abstract contract AbstractPaymentProcessor is IPaymentProcessor {

    /// Internal Payment Functions ================================================================

    function _validateRegistrationPayment(
        Datastructures.OrderPayment memory payment_, 
        bytes32 tld_, uint64 duration_
    ) internal view virtual;

    function _validatePayment(
        Datastructures.OrderPayment memory payment_,
        bool zeroPayments_
    ) internal pure virtual;

    function _handlePayment(Datastructures.OrderPayment memory payment_, bool isCommitment_) internal virtual;

    function _handlePayout(Datastructures.OrderPayment memory payment_, address recipient_) internal virtual;

    function _getPayoutAddress(bytes32 tld_) internal virtual returns (address);

    // function _handleGaslessApproval(
    //     Datastructures.PaymentType payment_, 
    //     address from_,
    //     address sponsor_,
    //     uint256 permitAmount_,
    //     uint256 permitFee_,
    //     uint256 deadline_,
    //     bytes memory permitSig_
    // ) internal virtual;

    /// Accessor Functions ------------------------------------------------------------------------

    // function rentPrice(
    //     string memory label_,
    //     bytes32 tld_,
    //     uint256 duration_,
    //     Datastructures.PaymentType paymentType_
    // ) external view returns (uint256 amount_) {
    //     revert PaymentModule_notSupported();
    // }    
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;

interface IRegistrarController {

    /// Registration Functions --------------------------------------------------------------------

    function registerTLD(bytes calldata tld_) external;
    function setTLDMetadata(bytes32 tld_, string calldata baseUrl_, string calldata description_) external;

    // TODO: Add updateTLD and disableTLD functions

    /// Accessor Functions ------------------------------------------------------------------------

    
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;

/// External References ---------------------------------------------------------------------------

import {AddressUpgradeable} from "openzeppelin-upgradeable/utils/AddressUpgradeable.sol";

import {IWETH} from "src/utils/interfaces/IWETH.sol";

/// Multicall ----------------------------------------------------------------------------------

interface IMulticall {
    /// @dev Receives and executes a batch of function calls on this contract. Payable. All ETH 
    ///  paid via msg.value is wrapped to WETH and used to execute the function calls. Any 
    ///  remaining WETH is returned to the sender.
    function multicall(bytes[] calldata data) external payable returns (bytes[] memory results);
}

// solhint-disable func-name-mixedcase

// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;

/// External References ---------------------------------------------------------------------------

import { EnumerableSetUpgradeable } from "openzeppelin-upgradeable/utils/structs/EnumerableSetUpgradeable.sol";

/// Internal References ---------------------------------------------------------------------------

import { LeadingHashStorage } from "src/utils/storage/LeadingHashStorage.sol";

library CommitmentStorage {
    /// SLO Offsets -------------------------------------------------------------------------------

    /// @dev Constant specifing the storage location of the payment state
    bytes32 public constant THREE_DNS__COMMITMENT_STORAGE__V1 = keccak256("3dns.reg_control.commitment.v1.state");

    /// Datastructures ----------------------------------------------------------------------------
    
    /// @dev Struct used to define a payment object...
    struct RegistrationCommitment {
        // 32 Bytes Packed Data
        // | 32 bits | address - 160 bits |     uint64 - 64 bits      |
        // |   ...   |   Owner Address    | Expiration (unix seconds) |
        bytes32 data;
    }

    /// Contract State ----------------------------------------------------------------------------

    /// @dev Struct used to define the state variables for the commitment store.
    struct Layout {
        /// @param commitments Mapping of commitment hash to commitment data.
        mapping (bytes32 => RegistrationCommitment) commitments;

        uint64 commitmentHalfLife;
        uint64 signatureHalfLife;
        uint64 transferCommitmentHalfLife;

        /// @param domainTransferFlags Mapping of pending transfers for a user.
        mapping (address => mapping (bytes32 => uint72)) domainTransferFlags;
    }

    function layout() internal pure returns (Layout storage l) {
        bytes32 slot = THREE_DNS__COMMITMENT_STORAGE__V1;

        /// @solidity memory-safe-assembly
        assembly {
            l.slot := slot
        }
    }

    function initialize() internal {
        layout().commitmentHalfLife = 90 minutes;
        layout().transferCommitmentHalfLife = 30 minutes;
        layout().signatureHalfLife = 5 minutes;
    }

    /// Shared Helper Functions -------------------------------------------------------------------

    function setCommitmentData(bytes32 commitmentHash_, address committer_, uint64 revokableAt_) internal {
        bytes32 commitmentData_;

        assembly {
            commitmentData_ := shl(64, committer_)
            commitmentData_ := or(commitmentData_, revokableAt_)
        }

        layout().commitments[commitmentHash_].data = commitmentData_;
    }

    function getCommitmentData(bytes32 commitmentHash_) internal view returns (address committer_, uint64 revokableAt_) {
        bytes32 commitmentData_ = layout().commitments[commitmentHash_].data;

        assembly {
            committer_ := shr(64, commitmentData_)
            revokableAt_ := commitmentData_
        }
    }

    function deleteCommitment(bytes32 commitmentHash_) internal {
        delete layout().commitments[commitmentHash_];
    }

    function setDomainTransferFlag(address registrant_, bytes32 commitmentHash_, uint64 duration_, bool isTrader_) internal {
        layout().domainTransferFlags[registrant_][commitmentHash_] = duration_ | (isTrader_ ? 1 << 64 : 0);
    }

    function hasDomainTransferFlag(address registrant_, bytes32 commitmentHash_) internal view returns (bool) {
        (uint64 duration_, ) = getDomainTransferFlag(registrant_, commitmentHash_);
        return duration_ > 0;
    }

    function getDomainTransferFlag(address registrant_, bytes32 commitmentHash_) internal view returns (uint64, bool) {
        uint64 flag = uint64(layout().domainTransferFlags[registrant_][commitmentHash_]);
        bool isTrader = layout().domainTransferFlags[registrant_][commitmentHash_] & (1 << 64) > 0;
        return (flag, isTrader);
    }

    function deleteDomainTransferFlag(address registrant_, bytes32 commitmentHash_) internal {
        delete layout().domainTransferFlags[registrant_][commitmentHash_];
    }

    /// Accessor Functions ------------------------------------------------------------------------

    function COMMITMENT_HALF_LIFE() internal view returns (uint64) {
        return layout().commitmentHalfLife;
    }

    function MAX_SIG_HALF_LIFE() internal view returns (uint64) {
        return layout().signatureHalfLife;
    }
}

// solhint-disable func-name-mixedcase

// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;

/// External References ---------------------------------------------------------------------------

import {IERC20Upgradeable as IERC20} from "openzeppelin-upgradeable/token/ERC20/IERC20Upgradeable.sol";
import { EnumerableSetUpgradeable } from "openzeppelin-upgradeable/utils/structs/EnumerableSetUpgradeable.sol";

/// Internal References ---------------------------------------------------------------------------

import { LeadingHashStorage } from "src/utils/storage/LeadingHashStorage.sol";

library PaymentStorage {
    /// SLO Offsets -------------------------------------------------------------------------------

    /// @dev Constant specifing the storage location of the payment state
    bytes32 public constant THREE_DNS__PAYMENT_STORAGE__V1 = keccak256("3dns.reg_control.payment.v1.state");

    /// Datastructures ----------------------------------------------------------------------------
    
    /// @dev Struct used to define a payment object...
    struct Payment {
        // 32 Bytes Packed Data
        // | address - 160 bits | uint32 - 32 bits | uint64 - 64 bits |
        // | Owner Address | Control Bitmap | Expiration (unix seconds) |
        bytes32 data;
    }

    /// Contract State ----------------------------------------------------------------------------

    /// @dev Struct used to define the state variables for the 3dns registry.
    struct Layout {
        /// @param payments Mapping of subdomain payment rules from a corresponding node.
        mapping (bytes32 => Payment) payments;
        
        // Supported Payment Types
        IERC20 usdc;
    }

    function layout() internal pure returns (Layout storage l) {
        bytes32 slot = THREE_DNS__PAYMENT_STORAGE__V1;

        /// @solidity memory-safe-assembly
        assembly {
            l.slot := slot
        }
    }

    function initialize(IERC20 _usdc) internal {
        setUSDCTokenAddress(_usdc);
    }

    /// Shared Helper Functions -------------------------------------------------------------------

    function setUSDCTokenAddress(IERC20 usdc) internal {
        layout().usdc = IERC20(usdc);
    }

    /// Accessor Functions ------------------------------------------------------------------------

    function ERC20_USDC_ADDRESS() internal view returns (IERC20) {
        return layout().usdc;
    }
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;

/// External References ---------------------------------------------------------------------------

import { EnumerableSetUpgradeable } from "openzeppelin-upgradeable/utils/structs/EnumerableSetUpgradeable.sol";

library RebateIssuerStorage {
    /// SLO Offsets -------------------------------------------------------------------------------

    /// @dev Constant specifing the storage location of the payment state
    bytes32 public constant THREE_DNS__REBATE_ISSUER_STORAGE__V1 = keccak256("3dns.reg_control.rebate_issuer.v1.state");

    /// Datastructures ----------------------------------------------------------------------------
    
    /// @dev Struct used to define a payment object...
    struct Rebate {
        uint256 oustanding;
        uint256 claimed;
        uint32[] indexes;
    }

    /// Contract State ----------------------------------------------------------------------------

    /// @dev Struct used to define the state variables for the rebate issuer.
    struct Layout {
        /// @param rebates Mapping of address to rebate.
        mapping (address => Rebate) rebates;

        uint32 domains;
    }

    function layout() internal pure returns (Layout storage l) {
        bytes32 slot = THREE_DNS__REBATE_ISSUER_STORAGE__V1;

        /// @solidity memory-safe-assembly
        assembly {
            l.slot := slot
        }
    }

    /// Shared Helper Functions -------------------------------------------------------------------

    ///
    function getRebate(address registrant_) internal view returns (Rebate storage rebate) {
        return layout().rebates[registrant_];
    }

    function incrementOutstandingRebate(address registrant_, uint256 amount) internal {
        Rebate storage rebate = getRebate(registrant_);
        rebate.oustanding += amount;
    }

    function addIndex(address registrant_) internal {
        Rebate storage rebate = getRebate(registrant_);
        rebate.indexes.push(uint32(rebate.indexes.length + 1));
    }

    function resetOutstandingRebate(address registrant_) internal {
        Rebate storage rebate = getRebate(registrant_);
        rebate.oustanding = 0;
    }
}

File 40 of 63 : RegistryStorage.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;

/// External References ---------------------------------------------------------------------------

import {EnumerableSetUpgradeable} from "openzeppelin-upgradeable/utils/structs/EnumerableSetUpgradeable.sol";

/// Internal References ---------------------------------------------------------------------------

import {LeadingHashStorage} from "src/utils/storage/LeadingHashStorage.sol";

library RegistryStorage {
    // Libraries -------------------------------------------------------------------------------

    using EnumerableSetUpgradeable for EnumerableSetUpgradeable.Bytes32Set;
    using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet;

    using LeadingHashStorage for LeadingHashStorage.LHBytes;

    /// SLO Offsets -------------------------------------------------------------------------------

    /// @dev Constant specifing the storage location of the registry state
    bytes32 public constant THREE_DNS__REGISTRY_STORAGE__V1 = keccak256("3dns.reg_control.registry.v1.state");

    /// Datastructures ----------------------------------------------------------------------------

    /// @dev Struct used to define a record, the base notion of ownership for a zone (primary/apex domain name).
    struct Record {
        // 32 Bytes Packed Data
        // | address - 160 bits | uint32 - 32 bits | uint64 - 64 bits |
        // | Owner Address | Control Bitmap | Expiration (unix seconds) |
        bytes32 data;
        // An enumerable set of all subdomains
        EnumerableSetUpgradeable.Bytes32Set children;
    }

    /// @dev Mapping of child node to its parent node & label. keccak256(parent, keccak256(label)) <=> node
    struct ReverseRecord {
        // The parent node
        bytes32 parent;
        // The label
        LeadingHashStorage.LHBytes label;
    }

    /// Contract State ----------------------------------------------------------------------------

    /// @dev Struct used to define the state variables for the 3dns registry.
    struct Layout {
        /// @param records Mapping of zone (notioned as node) to its record.
        mapping(bytes32 => Record) records;
        uint256 recordCount;

        /// @param reverseRecords Mapping of child node to its parent node. It also stores the label.
        mapping(bytes32 => ReverseRecord) reverseRecords;
        /// @param ownershipEnumerations Mapping of address (owner) to an enumerable set of owned
        /// zones (notioned as node).
        mapping(address => EnumerableSetUpgradeable.Bytes32Set) ownershipEnumerations;
        
        /// @param operators Mapping of owner to an enumerable set of authorized operators.
        mapping(address => EnumerableSetUpgradeable.AddressSet) accountOperators;

        /// @param approvals Mapping of registration to an approved operator
        mapping(bytes32 => address) registrationOperatorApprovals;
    }

    function layout() internal pure returns (Layout storage l) {
        bytes32 slot = THREE_DNS__REGISTRY_STORAGE__V1;

        /// @solidity memory-safe-assembly
        assembly {
            l.slot := slot
        }
    }

    /// Shared Helper Functions -------------------------------------------------------------------

    function recordCount() internal view returns (uint256) {
        return layout().recordCount;
    }

    /// Ownership State Actions ///

    function trackNewOwnership(bytes32 node, address registrant) internal {
        return _trackNewOwnership(layout().ownershipEnumerations[registrant], node);
    }

    function renounceOwnership(bytes32 node, address registrant) internal {
        return _renounceOwnership(layout().ownershipEnumerations[registrant], node);
    }

    function getOwnershipCount(address registrant) internal view returns (uint256) {
        return _getOwnershipCount(layout().ownershipEnumerations[registrant]);
    }

    /// Operator State Actions ///

    // Registrant => Account Operator Approval (can manage all of the users domains)

    function addAccountOperatorApproval(address registrant, address operator) internal {
        return _registerOperator(
            layout().accountOperators[registrant], 
            operator
        );
    }

    function removeAccountOperatorApproval(address registrant, address operator) internal {
        return _removeOperator(
            layout().accountOperators[registrant], 
            operator
        );
    }

    function isApprovedAccountOperator(address registrant, address operator) internal view returns (bool) {
        return _isApprovedAccountOperator(
            layout().accountOperators[registrant], 
            operator
        );
    }

    // Registration => Operator Approval

    function approveRegistrationOperator(bytes32 node, address addr) internal {
        layout().registrationOperatorApprovals[node] = addr;
    }

    function removeApprovedRegistrationOperator(bytes32 node) internal {
        delete layout().registrationOperatorApprovals[node];
    }

    function getApprovedRegistrationOperator(bytes32 node) internal view returns (address) {
        return layout().registrationOperatorApprovals[node];
    }

    /// Record State Actions ///

    function createNewRecord(bytes32 node, address owner, uint32 controlBitmap, uint64 expiration) internal {
        // Increment the record count
        layout().recordCount++;

        // Set the record data
        _setRecordData(layout().records[node], owner, controlBitmap, expiration);
    }

    function setRecordData(bytes32 node, address owner, uint32 controlBitmap, uint64 expiration) internal {
        _setRecordData(layout().records[node], owner, controlBitmap, expiration);
    }

    function deleteRecord(bytes32 node) internal {
        // Revert if the record has children
        if (recordHasChildren(node)) revert();

        // Decrement the record count
        layout().recordCount--;

        // Delete the record
        delete layout().records[node];
    }

    /// Reverse Record State Actions ///

    function trackReverseRecord(bytes32 parent, bytes memory label) internal {
        // Calculate the node from the parent and label
        bytes32 node_ = keccak256(abi.encodePacked(parent, keccak256(label)));

        // Register the reverse record
        _addReverseRecord(node_, parent, label);
    }

    function untrackReverseRecord(bytes32 node) internal {
        // Delete the reverse record & mapping
        _removeReverseRecord(node);
    }

    function getParent_reverseRecord(bytes32 node) internal view returns (bytes32) {
        return layout().reverseRecords[node].parent;
    }

    function getLabel_reverseRecord(bytes32 node) internal view returns (bytes memory) {
        return layout().reverseRecords[node].label.get();
    }

    /// Record Specific Functions =================================================================

    // Data Helper Functions

    function getRecord(bytes32 node) internal view returns (Record storage) {
        return layout().records[node];
    }

    function getRecordData(bytes32 node)
        internal
        view
        returns (address owner, uint32 controlBitmap, uint64 expiration)
    {
        return _getRecordData(layout().records[node]);
    }

    function getRecordChildren(bytes32 node) internal view returns (EnumerableSetUpgradeable.Bytes32Set storage) {
        return _getRecordChildren(layout().records[node]);
    }

    function recordHasChildren(bytes32 node) internal view returns (bool) {
        return _recordHasChildren(layout().records[node]);
    }

    /// Children Helper Functions

    function addChild(bytes32 node, bytes32 child) internal {
        return _addChild(layout().records[node], child);
    }

    function removeChild(bytes32 node, bytes32 child) internal {
        return _removeChild(layout().records[node], child);
    }

    function getChildAtIndex(bytes32 node, uint256 index) internal view returns (bytes32) {
        return _getChildAtIndex(layout().records[node], index);
    }

    function containsChild(bytes32 node, bytes32 child) internal view returns (bool) {
        return _containsChild(layout().records[node], child);
    }

    /// Record Storage Functions ///

    function _getRecordData(Record storage r_)
        private
        view
        returns (address owner, uint32 controlBitmap, uint64 expiration)
    {
        bytes32 data_ = r_.data;

        assembly {
            owner := shr(96, data_)
            controlBitmap := shr(64, data_)
            expiration := data_
        }
    }

    function _setRecordData(Record storage r_, address owner_, uint32 controlBitmap_, uint64 expiration_) private {
        // bytes32 data_;

        // assembly {
        //     // Zero out any extra bits by shifting right then left
        //     let ownerMasked := shl(96, shr(96, owner_))
        //     let controlBitmapMasked := shl(64, shr(192, controlBitmap_))
        //     let expirationMasked := shl(0, shr(192, expiration_))

        //     // Combine the masked and shifted values
        //     data_ := or(or(ownerMasked, controlBitmapMasked), expirationMasked)

        //     data_ := or(or(shl(96, owner_), shl(64, controlBitmap_)), expiration_)
        // }

        // r_.data = data_;
        r_.data = bytes32(uint256(uint160(owner_))) << 96 | (bytes32(uint256(controlBitmap_)) << 64)
            | bytes32(uint256(expiration_));
    }

    function _getRecordChildren(Record storage r_) private view returns (EnumerableSetUpgradeable.Bytes32Set storage) {
        return r_.children;
    }

    function _recordHasChildren(Record storage r_) private view returns (bool) {
        return r_.children.length() > 0;
    }

    /// Children Storage Functions ///

    function _addChild(Record storage r_, bytes32 child) private {
        r_.children.add(child);
    }

    function _removeChild(Record storage r_, bytes32 child) private {
        r_.children.remove(child);
    }

    function _getChildAtIndex(Record storage r_, uint256 index) private view returns (bytes32) {
        return r_.children.at(index);
    }

    function _containsChild(Record storage r_, bytes32 child) private view returns (bool) {
        return r_.children.contains(child);
    }

    /// Ownership Enumeration Storage Functions ///

    function _trackNewOwnership(EnumerableSetUpgradeable.Bytes32Set storage s_, bytes32 node_) private {
        s_.add(node_);
    }

    function _renounceOwnership(EnumerableSetUpgradeable.Bytes32Set storage s_, bytes32 node_) private {
        s_.remove(node_);
    }

    function _getOwnershipCount(EnumerableSetUpgradeable.Bytes32Set storage s_) private view returns (uint256) {
        return s_.length();
    }

    /// Operator Storage Functions ///

    function _registerOperator(EnumerableSetUpgradeable.AddressSet storage s_, address registrant_) private {
        s_.add(registrant_);
    }

    function _removeOperator(EnumerableSetUpgradeable.AddressSet storage s_, address registrant_) private {
        s_.remove(registrant_);
    }

    function _isApprovedAccountOperator(EnumerableSetUpgradeable.AddressSet storage s_, address operator_)
        private
        view
        returns (bool)
    {
        return s_.contains(operator_);
    }

    /// Reverse Record Storage Functions ///

    function _addReverseRecord(bytes32 node, bytes32 parent, bytes memory label) private {
        // Register node as child of parent
        addChild(parent, node);

        // Set the reverse record
        _setReverseRecord(layout().reverseRecords[node], parent, label);
    }

    function _removeReverseRecord(bytes32 node) private {
        // Remove node as child of parent
        removeChild(layout().reverseRecords[node].parent, node);

        // Delete the reverse record
        delete layout().reverseRecords[node];
    }

    function _setReverseRecord(ReverseRecord storage rr_, bytes32 parent, bytes memory label) private {
        rr_.parent = parent;
        rr_.label.set(label);
    }
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;

library RegistrarStorage {
    /// SLO Offsets -------------------------------------------------------------------------------

    /// @dev Constant specifing the storage location of the registry state
    bytes32 public constant THREE_DNS__REGISTRAR_STORAGE__V1 = keccak256("3dns.reg_control.registrar.v1.state");

    /// Datastructures ----------------------------------------------------------------------------

    /// @dev Struct used to define a record, the base notion of ownership for a zone (primary/apex domain name).
    struct TopLevelDomain {
        // 32 Bytes Packed Data
        // | address  |   uint64   |            bytes4             |
        // |  x[20]   |    x[8]    |      x[3]      | Enabled Flag |
        // | IPremium | Base Price | Accessory Data + Enabled Flag |
        bytes32 data;
    }

    /// Contract State ----------------------------------------------------------------------------

    /// @dev Struct used to define the state variables for the 3dns registry.
    struct Layout {
        /// @param tlds Mapping of node to TopLevelDomain definition.
        mapping(bytes32 => TopLevelDomain) tlds;
        /// @param domainLocks Mapping of domain to 32 byte slot
        /// | uint192 |        uint64       |
        /// |   ...   | settlementTimestamp |
        mapping(bytes32 => bytes32) domainLocks;
    }

    function layout() internal pure returns (Layout storage l) {
        bytes32 slot = THREE_DNS__REGISTRAR_STORAGE__V1;

        /// @solidity memory-safe-assembly
        assembly {
            l.slot := slot
        }
    }

    /// State Management Functions ----------------------------------------------------------------

    /// TLD Actions ///

    function registerTLD(bytes32 tld) internal {
        bytes32 data_ = bytes32(uint256(1));
        return _registerTLD(layout().tlds[tld], data_);
    }

    function getTLDData(bytes32 tld) internal view returns (bool enabled) {
        return _getTLDData(layout().tlds[tld]);
    }

    function disableTLD(bytes32 tld) internal {
        return _disableTLD(layout().tlds[tld]);
    }

    /// DomainLocks Actions ///

    function getDomainLockData(bytes32 node_) internal view returns (uint64 settlementTimestamp) {
        return _getDomainLockData(layout().domainLocks[node_]);
    }

    function setDomainLockData(bytes32 node_, uint64 settlementTimestamp) internal {
        _setDomainLockData(node_, settlementTimestamp);
    }

    /// Attribute Specific Helper Functions -------------------------------------------------------

    /// TLD Actions ///

    function _registerTLD(TopLevelDomain storage tld_, bytes32 data_) private {
        tld_.data = data_;
    }

    function _getTLDData(TopLevelDomain storage tld_) private view returns (bool enabled_) {
        bytes32 data_ = tld_.data;

        assembly {
            enabled_ := shr(7, shl(255, data_))
        }

        return enabled_;
    }

    function _disableTLD(TopLevelDomain storage tld_) private {
        tld_.data = tld_.data & ~bytes32(uint256(1));
    }

    /// DomainLocks Actions ///

    function _getDomainLockData(bytes32 domainLock_) private pure returns (uint64 settlementTimestamp) {
        assembly {
            settlementTimestamp := shr(192, domainLock_)
        }
    }

    function _setDomainLockData(bytes32 node_, uint64 settlementTimestamp_) private {
        bytes32 data_;
        assembly {
            data_ := shl(192, settlementTimestamp_)
        }
        layout().domainLocks[node_] = data_;
    }
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;

/// External References ---------------------------------------------------------------------------

import { EnumerableSetUpgradeable } from "openzeppelin-upgradeable/utils/structs/EnumerableSetUpgradeable.sol";

/// Internal References ---------------------------------------------------------------------------

import { LeadingHashStorage } from "src/utils/storage/LeadingHashStorage.sol";

library RegControlStorage {
    // Libraries ----------------------------------------------------------------------------------

    using EnumerableSetUpgradeable for EnumerableSetUpgradeable.Bytes32Set;
    using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet;

    using LeadingHashStorage for LeadingHashStorage.LHBytes;

    /// SLO Offsets -------------------------------------------------------------------------------

    /// @dev Constant specifing the storage location of the registry state
    bytes32 public constant THREE_DNS__REG_CONTROL_CORE_STORAGE__V1 = keccak256("3dns.reg_control.core.v1.state");


    /// Contract State ----------------------------------------------------------------------------

    /// @dev Struct used to define the state variables for the core 3dns registry controller.
    struct Layout {
        /// @dev default & primary resolver for all nodes.
        address primaryResolver;
    }

    function layout() internal pure returns (Layout storage l) {
        bytes32 slot = THREE_DNS__REG_CONTROL_CORE_STORAGE__V1;

        /// @solidity memory-safe-assembly
        assembly {
            l.slot := slot
        }
    }
    
    /// State Management Functions ----------------------------------------------------------------

    function primaryResolver() internal view returns (address) {
        return layout().primaryResolver;
    }

    function setPrimaryResolver(address resolver_) internal {
        if (address(resolver_) == address(0))
            revert();
        layout().primaryResolver = resolver_;
    }
}

// solhint-disable func-name-mixedcase

// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;

/// Internal References ---------------------------------------------------------------------------

import { LeadingHashStorage } from "src/utils/storage/LeadingHashStorage.sol";

library MetadataStorage {
    /// SLO Offsets -------------------------------------------------------------------------------

    /// @dev Constant specifing the storage location of the payment state
    bytes32 public constant THREE_DNS__BASIC_METADATA_STORAGE__V1 = keccak256("3dns.nft.metadata.basic.v1.state");

    /// Datastructures ----------------------------------------------------------------------------
    
    /// Contract State ----------------------------------------------------------------------------

    /// @dev Struct used to define the state variables for the 3dns token metadata.
    struct Layout {
        string baseUri;
    }

    function layout() internal pure returns (Layout storage l) {
        bytes32 slot = THREE_DNS__BASIC_METADATA_STORAGE__V1;

        /// @solidity memory-safe-assembly
        assembly {
            l.slot := slot
        }
    }

    function initialize(string memory _baseUri) internal {
        layout().baseUri = _baseUri;
    }

    /// Shared Helper Functions -------------------------------------------------------------------

    /// Accessor Functions ------------------------------------------------------------------------

    function baseURI() internal view returns (string memory) {
        return layout().baseUri;
    }

    function setBaseURI(string memory _baseUri) internal {
        layout().baseUri = _baseUri;
    }
}

// solhint-disable func-name-mixedcase

// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;

/// Internal References ---------------------------------------------------------------------------

import {LeadingHashStorage} from "src/utils/storage/LeadingHashStorage.sol";

library HybridMetadataStorage {
    /// SLO Offsets -------------------------------------------------------------------------------

    /// @dev Constant specifing the storage location of the payment state
    bytes32 public constant THREE_DNS__HYBRID_METADATA_STORAGE__V1 = keccak256("3dns.nft.metadata.hybrid.v1.state");

    /// Datastructures ----------------------------------------------------------------------------

    /// Contract State ----------------------------------------------------------------------------

    /// @dev Struct used to define the state variables for the 3dns token metadata.
    struct Layout {
        mapping(bytes32 => string) baseUrl;
        mapping(bytes32 => string) description;
    }

    function layout() internal pure returns (Layout storage l) {
        bytes32 slot = THREE_DNS__HYBRID_METADATA_STORAGE__V1;

        /// @solidity memory-safe-assembly
        assembly {
            l.slot := slot
        }
    }

    /// Shared Helper Functions -------------------------------------------------------------------

    function name() internal pure returns (string memory) {
        return "3DNS Powered Domain Name";
    }

    function symbol() internal pure returns (string memory) {
        return "3DNS";
    }

    function setMetadata(bytes32 tld_, string memory baseUrl_, string memory description_) internal {
        layout().baseUrl[tld_] = baseUrl_;
        layout().description[tld_] = description_;
    }

    function getMetadata(bytes32 tld_) internal view returns (string memory baseUrl_, string memory description_) {
        baseUrl_ = layout().baseUrl[tld_];
        description_ = layout().description[tld_];
    }

    /// Accessor Functions ------------------------------------------------------------------------

    function baseUrl(bytes32 tld_) internal view returns (string memory resp) {
        resp = layout().baseUrl[tld_];
        if (bytes(resp).length == 0) {
            resp = layout().baseUrl[bytes32(0x00)];
        }
    }

    function description(bytes32 tld_) internal view returns (string memory resp) {
        resp = layout().description[tld_];
        if (bytes(resp).length == 0) {
            resp = layout().description[bytes32(0x00)];
        }
    }

    /// Bytes32 encoding --------------------------------------------------------------------------

    function bytes32ToHexString(bytes32 data_) internal pure returns (string memory hex_) {
        bytes memory byteArray = new bytes(64);
        for (uint256 i = 0; i < 32; i++) {
            bytes1 b = data_[i];
            bytes1 hi = bytes1(uint8(b) / 16);
            bytes1 lo = bytes1(uint8(b) - 16 * uint8(hi));
            byteArray[i * 2] = _char(hi);
            byteArray[i * 2 + 1] = _char(lo);
        }
        return string(byteArray);
    }

    function _char(bytes1 b_) private pure returns (bytes1 c) {
        if (uint8(b_) < 10) return bytes1(uint8(b_) + 0x30);
        else return bytes1(uint8(b_) + 0x57);
    }

    /// Base64 encoding ---------------------------------------------------------------------------

    string private constant _B64_CHARACTER_TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

    function base64(bytes memory data_) internal pure returns (string memory) {
        if (data_.length == 0) return "";

        // load the table into memory
        string memory table = _B64_CHARACTER_TABLE;

        // multiply by 4/3 rounded up
        uint256 encodedLen = 4 * ((data_.length + 2) / 3);

        // add some extra buffer at the end required for the writing
        string memory result_ = new string(encodedLen + 32);

        assembly {
            // set the actual output length
            mstore(result_, encodedLen)

            // prepare the lookup table
            let tablePtr := add(table, 1)

            // input ptr
            let dataPtr := data_
            let endPtr := add(dataPtr, mload(data_))

            // result ptr, jump over length
            let resultPtr := add(result_, 32)

            // run over the input, 3 bytes at a time
            for {} lt(dataPtr, endPtr) {} {
                dataPtr := add(dataPtr, 3)

                // read 3 bytes
                let input := mload(dataPtr)

                // write 4 characters
                mstore(resultPtr, shl(248, mload(add(tablePtr, and(shr(18, input), 0x3F)))))
                resultPtr := add(resultPtr, 1)
                mstore(resultPtr, shl(248, mload(add(tablePtr, and(shr(12, input), 0x3F)))))
                resultPtr := add(resultPtr, 1)
                mstore(resultPtr, shl(248, mload(add(tablePtr, and(shr(6, input), 0x3F)))))
                resultPtr := add(resultPtr, 1)
                mstore(resultPtr, shl(248, mload(add(tablePtr, and(input, 0x3F)))))
                resultPtr := add(resultPtr, 1)
            }

            // padding with '='
            switch mod(mload(data_), 3)
            case 1 { mstore(sub(resultPtr, 2), shl(240, 0x3d3d)) }
            case 2 { mstore(sub(resultPtr, 1), shl(248, 0x3d)) }
        }

        return result_;
    }
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;

/// External References ---------------------------------------------------------------------------

import {EnumerableSetUpgradeable} from "openzeppelin-upgradeable/utils/structs/EnumerableSetUpgradeable.sol";

/// Internal References ---------------------------------------------------------------------------

import {LeadingHashStorage} from "src/utils/storage/LeadingHashStorage.sol";

library IAMStorage {
    // Libraries -------------------------------------------------------------------------------

    using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet;

    /// SLO Offsets -------------------------------------------------------------------------------

    /// @dev Constant specifing the storage location of the iam state
    bytes32 public constant THREE_DNS__IAM_STORAGE__V1 = keccak256("3dns.reg_control.iam.v1.state");

    /// Datastructures ----------------------------------------------------------------------------

    struct IAMProfiles {
        EnumerableSetUpgradeable.AddressSet profiles;
        mapping(address => bytes32) permissions;
    }

    /// Contract State ----------------------------------------------------------------------------

    /// @dev Struct used to define the state variables for the 3dns registry.
    struct Layout {
        /// @param approvals Mapping of token to IAM permissions
        mapping(bytes32 => mapping(uint256 => IAMProfiles)) iamProfiles;
        mapping(bytes32 => uint256) iamProfilesVersion;
    }

    function layout() internal pure returns (Layout storage l) {
        bytes32 slot = THREE_DNS__IAM_STORAGE__V1;

        /// @solidity memory-safe-assembly
        assembly {
            l.slot := slot
        }
    }

    /// Shared Helper Functions -------------------------------------------------------------------

    function getIAMProfilesVersion(bytes32 node) internal view returns (uint256) {
        return layout().iamProfilesVersion[node];
    }

    function clearIAMProfiles(bytes32 node) internal {
        layout().iamProfilesVersion[node]++;
    }

    function hasIAMProfile(bytes32 node, address user) internal view returns (bool) {
        return layout().iamProfiles[node][getIAMProfilesVersion(node)].profiles.contains(user);
    }

    function getIAMProfiles(bytes32 node) internal view returns (address[] memory) {
        return layout().iamProfiles[node][getIAMProfilesVersion(node)].profiles.values();
    }

    function getIAMProfile(bytes32 node, address user) internal view returns (bytes32) {
        return layout().iamProfiles[node][getIAMProfilesVersion(node)].permissions[user];
    }

    function setIAMProfile(bytes32 node, address user, bytes32 profile) internal {
        if (profile == 0) {
            deleteIAMProfile(node, user);
        } else {
            if (!hasIAMProfile(node, user)) {
                layout().iamProfiles[node][getIAMProfilesVersion(node)].profiles.add(user);
            }
            layout().iamProfiles[node][getIAMProfilesVersion(node)].permissions[user] = profile;
        }
    }

    function deleteIAMProfile(bytes32 node, address user) internal {
        layout().iamProfiles[node][getIAMProfilesVersion(node)].profiles.remove(user);
        delete layout().iamProfiles[node][getIAMProfilesVersion(node)].permissions[user];
    }
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.17;

/// External References ---------------------------------------------------------------------------

import {Initializable} from "openzeppelin-upgradeable/proxy/utils/Initializable.sol";

/// Internal References ---------------------------------------------------------------------------

import {BaseSignature} from "src/utils/signature/BaseSignature.sol";

abstract contract TypedDataSignature is Initializable, BaseSignature {

    function signatureType() public override pure returns (string memory) {
        return "EIP712";
    }
    
    /// Domain Variables --------------------------------------------------------------------------

    /// @dev Internal variable calculated from the domain name, version, chainId, and contract address.
    bytes32 public DOMAIN_SEPARATOR;

    /// @dev Internal variable specifing the domain name of the 712 typed signature.
    string public DOMAIN_NAME;
    /// @dev Internal variable specifing the version of the 712 typed signature.
    string public DOMAIN_VERSION;
    /// @dev Internal variable specifing the chainId of the 712 typed signature.
    uint64 public CHAIN_ID;


    function TYPED_DATA_SIGNATURE_TYPEHASH() external view virtual returns (bytes32);

    /// Initializer ----------------------------------------------------------------------------

    /// @dev Initializes an internal helper contract used for verifying 712 typed signatures.
    function __TypedDataSignature_init(
        string memory domainName_,
        string memory domainVersion_,
        uint64 chainId_
    ) internal onlyInitializing {
        DOMAIN_NAME = domainName_;
        DOMAIN_VERSION = domainVersion_;
        CHAIN_ID = chainId_;

        DOMAIN_SEPARATOR = keccak256(
            abi.encode(
                keccak256(
                    "EIP712Domain(string name,string version,uint64 chainId,address verifyingContract)"
                ),
                keccak256(bytes(DOMAIN_NAME)),
                keccak256(bytes(DOMAIN_VERSION)),
                CHAIN_ID,
                address(this)
            )
        );
    }

    function getDomainSeparator() public view returns (bytes32) {
        return DOMAIN_SEPARATOR;
    }

    function _calculateDigest(
        bytes memory data_
    ) internal view override returns (bytes32) {
        return
            keccak256(
                abi.encodePacked(
                    "\x19\x01", 
                    DOMAIN_SEPARATOR, 
                    _calculateTypeHash(data_)
                )
            );
    }

    /// Abstract Function Declarations ============================================================
    
    function _calculateTypeHash(bytes memory data_) internal view virtual returns (bytes32);
}

// solhint-disable func-name-mixedcase

// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;

/// Internal References ---------------------------------------------------------------------------

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

library SponsorShieldStorage {
    /// SLO Offsets -------------------------------------------------------------------------------

    /// @dev Constant specifing the storage location of the payment state
    bytes32 public constant THREE_DNS__SPONSOR_SHIELD_STORAGE__V1 =
        keccak256("3dns.access_controlled.sponsor_shield.v1.state");

    /// Constants ---------------------------------------------------------------------------------
    
    uint256 internal constant _NOT_SPONSORED = 1;
    uint256 internal constant _SPONSORED = 2;

    /// Contract State ----------------------------------------------------------------------------

    /// @dev Struct used to define the state variables for the 3dns registry.
    struct Layout {
        uint256 status;

        address payee;
        uint256 paymentType;
        uint256 paymentAmount;
    }

    function layout() internal pure returns (Layout storage l) {
        bytes32 slot = THREE_DNS__SPONSOR_SHIELD_STORAGE__V1;

        /// @solidity memory-safe-assembly
        assembly {
            l.slot := slot
        }
    }

    function initialize() internal {
        _setStatus(_NOT_SPONSORED);
    }

    /// Helper Functions --------------------------------------------------------------------------

    function _setStatus(uint256 status) internal {
        layout().status = status;
    }

    function _setPayee(address payee) internal {
        layout().payee = payee;
    }

    function _getPayee() internal view returns (address) {
        return layout().payee;
    }

    function _setPaymentType(uint256 paymentType) internal {
        layout().paymentType = paymentType;
    }

    function _getPaymentType() internal view returns (uint256) {
        return layout().paymentType;
    }

    function _setPaymentAmount(uint256 paymentAmount) internal {
        layout().paymentAmount = paymentAmount;
    }

    function _decrementPaymentAmount(uint256 amount) internal returns (bool) {
        if (layout().paymentAmount < amount) {
            return false;
        }
        layout().paymentAmount -= amount;
        return true;
    }

    function _clearPayment() internal {
        layout().paymentType = 0;
        layout().paymentAmount = 0;
    }

    function _getStatus() internal view returns (uint256) {
        return layout().status;
    }
}

// solhint-disable func-name-mixedcase

// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;

/// Internal References ---------------------------------------------------------------------------

import {
    IAMStorage as Storage,
    RegistryStorage
} from "src/regcontrol/storage/Storage.sol";

import {IIAM} from "src/regcontrol/interfaces/IIAM.sol";

import {RegControlBase} from "src/regcontrol/modules/types/RegControlBase.sol";
import "src/regcontrol/modules/types/Errors.sol";

/// Contract -----------------------------------------------------------------------------------
contract AccessManagement is RegControlBase {

    /// Authorization Functions -------------------------------------------------------------------

    function _permissionCheck_registration(
        bytes32 node_, address operator_, IIAM.IAMRole role_, IIAM.IAMPermission perm_
    ) internal view returns (bool) {
        if (perm_ == IIAM.IAMPermission.UNDEFINED) {
            revert BaseRegControl_invalidPermission();
        }

        // Operators and controlers are treated as accounts with ADMIN role
        // - Controllers are account level administrators
        // - Operators are token level administrators
        if (_isApprovedRegistrationOperator(node_, operator_) || _isApprovedAccountOperator(node_, operator_)) {
            return true;
        }

        // Check if the operator has the required role
        return _checkRegistrationIAM_hasRole(node_, operator_, role_, perm_);
    }

    /// Administrative Functions ------------------------------------------------------------------

    function _clearRegistrationApprovals(bytes32 node_) internal {
        // Remove the registration approval
        _setRegistrationApproval(node_, address(0));

        // Clear the registration IAM profiles
        _clearRegistrationIAMProfiles(node_);
    }

    function _clearRegistrationIAMProfiles(bytes32 node_) internal {
        // Increment the version number of the IAM profiles to invalidate all existing profiles
        Storage.clearIAMProfiles(node_);

        // Emit event
        emit RegistrationIAMCleared(node_);
    }

    // Token Operator Compliance //

    function _setRegistrationApproval(bytes32 node_, address operator_) internal {
        // Validate operation
        _setRegistrationApproval__validate(node_, operator_);

        if (operator_ == address(0)) {
            // Remove the operator
            RegistryStorage.removeApprovedRegistrationOperator(node_);
        } else {
            // Approve the operator
            RegistryStorage.approveRegistrationOperator(node_, operator_);
        }

        (address registrant_, ,) = RegistryStorage.getRecordData(node_);

        // Emit approval events
        // ERC721 & ERC1155 events are the same
        emit Approval(registrant_, operator_, uint256(node_));
    }

    // Account Operator //

    function _setAccountOperatorApproval(address operator_, bool approval_) internal {
        // Validate operation
        _setAccountOperatorApproval__validate(msg.sender, operator_, approval_);

        // Process request
        _setAccountOperatorApproval__private(msg.sender, operator_, approval_);

        // Emit approval events
        // ENS & ERC721 & ERC1155 events are the same
        emit ApprovalForAll(msg.sender, operator_, approval_);
    }

    // IAM Roles //

    function _setRegistrationIAMAuthorization(
        bytes32 node_, 
        address account_, 
        IIAM.IAMAuthorization[] memory profile_
    ) internal {
        bytes32 perms_;

        // Build the permissions
        for (uint8 i = 0; i < profile_.length; i++) {
            // If the permission has already been set, revert
            if ((perms_ >> (uint8(profile_[i].role) * 2) & bytes32(uint256(3))) > 0)
                revert BaseRegControl_invalidPermission();
            perms_ |= bytes32(uint256(uint8(profile_[i].permission)) << (uint8(profile_[i].role) * 2));
        }
        
        // Set the IAM profile permissions
        Storage.setIAMProfile(node_, account_, perms_);

        // Emit event
        emit RegistrationIAMAuthorization(node_, account_, perms_);
    }
    
    function _setRegistrationIAMRolePermission(
        bytes32 node_, 
        address account_, 
        IIAM.IAMRole role_, 
        IIAM.IAMPermission perm_
    ) internal {
        // Grab the current permissions
        bytes32 perms_ = Storage.getIAMProfile(node_, account_);

        perms_ &= ~bytes32(uint256(uint8(3) << (uint8(role_) * 2)));
        perms_ |= bytes32(uint256(uint8(perm_) << (uint8(role_) * 2)));

        // Update the permissions
        Storage.setIAMProfile(node_, account_, perms_);
        
        // Emit event
        emit RegistrationIAMAuthorization(node_, account_, perms_);
    }

    /// Internal Functions ------------------------------------------------------------------------
       
    // function _getRegistrationIAMProfileAccounts(bytes32 node_) internal view returns (address[] memory) {
    //     return Storage.getIAMProfiles(node_);
    // }
       
    function _getRegistrationIAMProfiles(bytes32 node_) internal view returns (IIAM.IAMProfile[] memory) {
        // Get the accounts with IAM profiles
        address[] memory accounts = Storage.getIAMProfiles(node_);

        // Create the IAM profiles
        IIAM.IAMProfile[] memory profiles = new IIAM.IAMProfile[](accounts.length);
        for (uint256 i = 0; i < accounts.length; i++) 
            profiles[i] = IIAM.IAMProfile(accounts[i], _getRegistrationIAMProfile(node_, accounts[i]));

        return profiles;
    }

    function _getRegistrationIAMProfile(bytes32 node_, address account_) internal view returns (IIAM.IAMAuthorization[] memory) {
        // Grab the current profile permissions
        bytes32 permissions_ = Storage.getIAMProfile(node_, account_);

        // Create the IAM profile
        IIAM.IAMAuthorization[] memory profile = new IIAM.IAMAuthorization[](4);
        for (uint8 i = 0; i < 4; i++)
            profile[i] = IIAM.IAMAuthorization(IIAM.IAMRole(i), IIAM.IAMPermission((uint256(permissions_) >> (i * 2)) & 0x03));

        return profile;
    }
    
    function _getRegistrationIAMRole(
        bytes32 node_, 
        address account_, 
        IIAM.IAMRole role_
    ) internal view returns (IIAM.IAMPermission) {
        // Grab the current permissions
        bytes32 currentPermissions = Storage.getIAMProfile(node_, account_);
        uint8 role = uint8((uint256(currentPermissions) >> (uint8(role_) * 2)) & 0x03);
        return IIAM.IAMPermission(role);
    }

    function _checkRegistrationIAM_hasRole(
        bytes32 node_, 
        address account_, 
        IIAM.IAMRole role_,
        IIAM.IAMPermission perm_
    ) internal view returns (bool) {
        // If the current role is greater than or equal to the desired permission, return true
        return _getRegistrationIAMRole(node_, account_, role_) >= perm_;
    }

    /// Validators --------------------------------------------------------------------------------
    
    function _setAccountOperatorApproval__validate(
        address account_, address operator_, bool approval_
    ) private {
        // Validate the operator is not the sender or the zero address
        if (account_ == operator_ || operator_ == address(0)) {
            revert BaseRegControl_invalidOperator(operator_);
        }

        // Validate the operator is not the desired approval state
        if (_isApprovedAccountOperator(account_, operator_) == approval_) {
            revert BaseRegControl_operatorStateUnchanged(operator_, approval_);
        }
    }

    function _setRegistrationApproval__validate(bytes32 node_, address operator_) private {
        // Validate the operator is not the sender
        address registrant_ = _getRegistrant(node_);
        if (registrant_ != address(0) && registrant_ == operator_) {
            revert BaseRegControl_invalidOperator(operator_);
        }

        // Validate the registration exists
        if (_isNodeAvailable(node_)) {
            revert BaseRegControl_nodeDoesNotExist(node_);
        }

        // Validate the operator is not the current approved address
        if (operator_ != address(0) && _getApprovedRegistrationOperator(node_) == operator_) {
            revert BaseRegControl_invalidOperator(operator_);
        }
    }

    /// Private Functions -------------------------------------------------------------------------
    
    function _setAccountOperatorApproval__private(
        address registrant_, address operator_, bool approval_
    ) private {
        // Update internal state to track the approval
        if (approval_) {
            RegistryStorage.addAccountOperatorApproval(registrant_, operator_);
        } else {
            RegistryStorage.removeAccountOperatorApproval(registrant_, operator_);
        }
    }

    /// Accessor Functions ------------------------------------------------------------------------
    
    function _isApprovedAccountOperator(bytes32 node_, address operator_) private view returns (bool) {
        return _isApprovedAccountOperator(_getRegistrant(node_), operator_);
    }
    
    function _isApprovedAccountOperator(address owner_, address operator_) internal view returns (bool) {
        // Return true if operator is the owner or the account operator
        return owner_ == operator_ || 
            RegistryStorage.isApprovedAccountOperator(owner_, operator_);
    }

    function _isApprovedRegistrationOperator(bytes32 node_, address operator_) private view returns (bool) {
        // Return true if operator is account operator or token operator
        return _getApprovedRegistrationOperator(node_) == operator_;
    }

    function _getApprovedRegistrationOperator(bytes32 node_) internal view returns (address) {
        return RegistryStorage.getApprovedRegistrationOperator(node_);
    }
}

// solhint-disable func-name-mixedcase

// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;

/// Internal References ---------------------------------------------------------------------------

import {
    RegistryStorage as Storage, 
    RegistrarStorage
} from "src/regcontrol/storage/Storage.sol";

import {RegControlBase} from "src/regcontrol/modules/types/RegControlBase.sol";
import "src/regcontrol/modules/types/Errors.sol";

/// Contract -----------------------------------------------------------------------------------
contract Enforcer is RegControlBase {

    /// Internal Functions ------------------------------------------------------------------------

    function _lockRegistration(bytes32 node_, uint64 duration_) internal {
        // Validate the registration exists
        if (_isNodeAvailable(node_)) {
            revert BaseRegControl_nodeDoesNotExist(node_);
        }

        // Validate the node has not already expired
        if (_isNodeExpired(node_)) {
            revert BaseRegControl_nodeExpired(node_);
        }


        uint64 lockedUtil_ = uint64(block.timestamp + duration_);

        // Set the lock on the domain
        RegistrarStorage.setDomainLockData(node_, lockedUtil_);

        // Emit a RegistrationLocked event
        emit RegistrationLocked(node_, duration_);
    }

    function _removeRegistrationLock(bytes32 node_) internal {
        // Validate the registration exists
        if (_isNodeAvailable(node_)) {
            revert BaseRegControl_nodeDoesNotExist(node_);
        }

        // Validate the node has not already expired
        if (_isNodeExpired(node_)) {
            revert BaseRegControl_nodeExpired(node_);
        }

        // Remove the lock on the domain
        RegistrarStorage.setDomainLockData(node_, 0);

        // Emit a RegistrationUnlocked event
        emit RegistrationUnlocked(node_);
    }
    
    /// Accessor Functions ------------------------------------------------------------------------

    function _isNodeTransferable(bytes32 node_) internal view returns (bool) {
        return !_isNodeExpired(node_) && !_isNodeLocked(node_);
    }

    function _isNodeLocked(bytes32 node_) internal view returns (bool) {
        // TODO: Add controlBitmap check ~ when implemented
        // Check the registrar storage for domain locks
        (uint64 settlement_) = RegistrarStorage.getDomainLockData(node_);
        return settlement_ > block.timestamp;
    }

    function _isNodeExpired(bytes32 node_) internal view returns (bool) {
        (,, uint64 expiration_) = Storage.getRecordData(node_);
        return expiration_ < block.timestamp;
    }
}

File 50 of 63 : Errors.sol
// solhint-disable func-name-mixedcase

// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;

/// Errors -------------------------------------------------------------------------------------

error BaseRegControl_nodeDoesNotExist(bytes32 node_);
error BaseRegControl_nodeExpired(bytes32 node_);
error BaseRegControl_nodeNotTransferable(bytes32 node_);
error BaseRegControl_nodeHasSubdomains(bytes32 node_);

error BaseRegControl_invalidTLD(bytes32 tld_);
error BaseRegControl_invalidLabel(bytes label_);
error BaseRegControl_subdomainUnavailable(bytes label_, bytes32 parent_);

error BaseRegControl_invalidDuration(uint64 duration_);
error BaseRegControl_invalidDurationExtension(uint64 duration_);
error BaseRegControl_invalidRegistrant(address registrant_);

error BaseRegControl_invalidOperator(address operator_);
error BaseRegControl_operatorStateUnchanged(address operator_, bool approved_);
error BaseRegControl_registrantNotCurrent(bytes32 node_, address registrant_);

error BaseRegControl_invalidPermission();

error BaseRegControl_notImplemented();

// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;

interface IIAM {
    struct IAMProfile {
        address account;
        IAMAuthorization[] perms;
    }

    struct IAMAuthorization {
        IAMRole role;
        IAMPermission permission;
    }

    enum IAMRole {
        ADMIN,
        WEB_MANAGER,
        IDENTITY_MANAGER,
        OFFCHAIN_MANAGER
    }

    enum IAMPermission {
        UNDEFINED,
        VIEW,
        PROPOSE,
        MANAGE
    }

    // Delete all IAM profiles associated with the node
    function clearIAMProfiles(bytes32 node_) external;

    // Setting a profile to 0 will remove it
    function setIAMProfile(bytes32 node_, address account_, IAMAuthorization[] memory perms_) external;
    
    function setIAMPermission(
        bytes32 node_, 
        address account_, 
        IAMRole role_, 
        IAMPermission perm_
    ) external;
    
    function getIAMProfiles(bytes32 node_) external view returns (IAMProfile[] memory);
    function getIAMProfile(bytes32 node_, address account_) external view returns (IAMAuthorization[] memory);

    function getIAMPermission(
        bytes32 node_, 
        address account_, 
        IAMRole role_
    ) external view returns (IAMPermission perm_);

    function hasIAMRole(
        bytes32 node_, 
        address account_, 
        IAMRole role_, 
        IAMPermission perm_
    ) external view returns (bool);
}

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

/// External References ---------------------------------------------------------------------------

import {StringsUpgradeable} from "openzeppelin-upgradeable/utils/StringsUpgradeable.sol";

/// Internal References ---------------------------------------------------------------------------

import {ICustomToken} from "src/regcontrol/interfaces/tokens/ICustomToken.sol";

import {AbstractDomainController} from "src/regcontrol/modules/types/abstracts/AbstractDomainController.sol";
import {HybridMetadataStorage} from "src/regcontrol/storage/Storage.sol";

/// Errors -------------------------------------------------------------------------------------

error HybridMetadataService__uri__tokenDoesNotExist(uint256 tokenId_);

abstract contract HybridMetadataService is ICustomToken, AbstractDomainController {
    /// Libraries ---------------------------------------------------------------------------------

    using StringsUpgradeable for uint256;

    /// Accessor Functions ---------------------------------------------------------------------

    /// @dev See {IERC721Metadata-name}.
    function name() external pure returns (string memory) {
        return HybridMetadataStorage.name();
    }

    /// @dev See {IERC721Metadata-symbol}.
    function symbol() external pure returns (string memory) {
        return HybridMetadataStorage.symbol();
    }

    /// Function overrides -----------------------------------------------------------------------------

    /// @dev See {IERC721Metadata-tokenURI}.
    function tokenURI(uint256 tokenId_) public view returns (string memory) {
        return uri(tokenId_);
    }

    /// @dev See {IERC1155MetadataURI-URI}.
    function uri(uint256 tokenId_) public view returns (string memory) {
        if (!_tokenExists(tokenId_)) {
            revert HybridMetadataService__uri__tokenDoesNotExist(tokenId_);
        }

        (string memory fqdn_, bytes32 tld_) = _getFQDN(bytes32(tokenId_));

        return string(
            abi.encodePacked(
                "data:application/json;base64,",
                HybridMetadataStorage.base64(
                    abi.encodePacked(
                        '{"name":"',
                        fqdn_,
                        '","description":"',
                        _renderDescription(fqdn_, tld_),
                        '","traits":[],"image":"',
                        _imageUrl(tld_, bytes32(tokenId_)),
                        '"}'
                    )
                )
            )
        );
    }

    function _imageUrl(bytes32 tld_, bytes32 node_) private view returns (string memory url_) {
        return string(
            abi.encodePacked(HybridMetadataStorage.baseUrl(tld_), HybridMetadataStorage.bytes32ToHexString(node_))
        );
    }

    function _renderDescription(string memory fqdn_, bytes32 tld_) private view returns (string memory) {
        return string(abi.encodePacked(fqdn_, HybridMetadataStorage.description(tld_)));
    }

    /// Abstract Accessor Functions ===============================================================

    function _getFQDN(bytes32 node_) internal view virtual returns (string memory, bytes32);
}

File 53 of 63 : IPaymentProcessor.sol
// solhint-disable func-name-mixedcase

// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;

/// External References ---------------------------------------------------------------------------

import {IERC20Upgradeable} from "openzeppelin-upgradeable/token/ERC20/IERC20Upgradeable.sol";

/// Internal References ---------------------------------------------------------------------------

import {Datastructures} from "src/regcontrol/storage/Datastructures.sol";

interface IPaymentProcessor {
    /// Events ---------------------------------------------------------------------------------

    /// Management Functions ----------------------------------------------------------------------

    /// Accessor Functions ------------------------------------------------------------------------

    function ERC20_USDC_ADDRESS() external returns (IERC20Upgradeable);

    // function rentPrice(
    //     string memory label_,
    //     bytes32 tld_,
    //     uint256 duration_,
    //     Datastructures.PaymentType paymentType_
    // ) external view returns (uint256 amount_);
}

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

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

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

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

            return true;
        } else {
            return false;
        }
    }

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

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

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

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

    // Bytes32Set

    struct Bytes32Set {
        Set _inner;
    }

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

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

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

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

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

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

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

        return result;
    }

    // AddressSet

    struct AddressSet {
        Set _inner;
    }

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

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

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

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

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

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

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

        return result;
    }

    // UintSet

    struct UintSet {
        Set _inner;
    }

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

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

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

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

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

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

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

        return result;
    }
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.17;

library LeadingHashStorage {
    struct LHBytes {
        bytes32 leadingHash;
        bytes data;
    }

    function get(LHBytes storage self) internal view returns (bytes memory) {
        return self.data;
    }

    function getLeadingHash(LHBytes storage self) internal view returns (bytes32) {
        return self.leadingHash;
    }

    function set(LHBytes storage self, bytes memory data) internal {
        self.leadingHash = keccak256(data);
        self.data = data;
    }

    struct LHString {
        LHBytes lhBytes;
    }

    function get(LHString storage self) internal view returns (string memory) {
        return string(LeadingHashStorage.get(self.lhBytes));
    }

    function getLeadingHash(LHString storage self) internal view returns (bytes32) {
        return LeadingHashStorage.getLeadingHash(self.lhBytes);
    }

    function set(LHString storage self, string memory data) internal {
        LeadingHashStorage.set(self.lhBytes, bytes(data));
    }
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.17;

/// Errors ---------------------------------------------------------------------------------

error InvalidPayload();
error InvalidSignature();

abstract contract BaseSignature {

    /// Functions ------------------------------------------------------------------------------

    function signatureType() public virtual pure returns (string memory) {
        return "EIP191";
    }

    function _validateSignature(
        bytes memory data_,
        uint8 v_, bytes32 r_, bytes32 s_
    ) internal view {
        // Verify payload
        if (!_validPayload(data_))
            revert InvalidPayload();

        address signer_ = ecrecover(
            _calculateDigest(data_), 
            v_, r_, s_
        );

        if (
            signer_ == address(0) || 
            !_isValidSigner(signer_)
        ) revert InvalidSignature();
    }

    /// Abstract Function Declarations ============================================================
    
    function _validPayload(bytes memory data_) internal view virtual returns (bool);

    function _calculateDigest(bytes memory data_) internal view virtual returns (bytes32);

    function _isValidSigner(address signer) internal view virtual returns (bool);
}

// solhint-disable func-name-mixedcase

// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;

/// Internal References ---------------------------------------------------------------------------

import {BytesUtils} from "src/regcontrol/libraries/BytesUtils.sol";
import {
    RegistryStorage as Storage,
    RegControlStorage
} from "src/regcontrol/storage/Storage.sol";

import {GlobalEvents} from "src/regcontrol/modules/types/GlobalEvents.sol";
import "src/regcontrol/modules/types/Errors.sol";

/// Contract -----------------------------------------------------------------------------------
contract RegControlBase is GlobalEvents {

    /// Constants ------------------------------------------------------------------------------

    uint64 internal constant YEAR = 31557600; // 365.25 * 24 * 60 * 60;

    /// Accessor Functions ------------------------------------------------------------------------

    function _getRegistrant(bytes32 node_) internal view returns (address registrant_) {
        uint64 expiration_;
        (registrant_,, expiration_) = Storage.getRecordData(node_);
        if (expiration_ < block.timestamp) {
            registrant_ = address(0x00);
        }
        return registrant_;
    }
    
    function _getNodeData(bytes32 node_) internal view returns (address registrant, uint32 controlBitmap, uint64 expiration) {
        (registrant, controlBitmap, expiration) = Storage.getRecordData(node_);
        if (expiration < block.timestamp) {
            registrant = address(0x00);
        }
        return (registrant, controlBitmap, expiration);
    }

    function _getDomainNameOwnershipCount(address registrant_) internal view returns (uint256) {
        return Storage.getOwnershipCount(registrant_);
    }

    function _getRecordCount() internal view returns (uint256) {
        return Storage.recordCount();
    }

    function _getParent(bytes32 node_) internal view returns (bytes32) {
        return Storage.getParent_reverseRecord(node_);
    }

    function _getLabel(bytes32 node_) internal view returns (bytes memory) {
        return Storage.getLabel_reverseRecord(node_);
    }

    function _resolver(bytes32 node_) internal view returns (address) {
        return RegControlStorage.primaryResolver();
    }

    /// Helper Functions --------------------------------------------------------------------------

    function _isNodeAvailable(bytes32 node_) internal view returns (bool) {
        (address registrant_,, uint64 expiration_) = Storage.getRecordData(node_);
        return registrant_ == address(0x00) || expiration_ < block.timestamp;
    }

    function _isSubdomainAvailable(bytes32 labelHash_, bytes32 parent_) internal view returns (bool) {
        return _isNodeAvailable(_calculateNode(labelHash_, parent_));
    }

    function _hasSubdomains(bytes32 node_) internal view returns (bool) {
        return Storage.recordHasChildren(node_);
    }

    /// Helper Functions --------------------------------------------------------------------------

    function _calculateNode(bytes calldata fqdn_) internal pure returns (bytes32) {
        // Parse the label from the fqdn
        (, bytes32 labelHash_, uint256 offset_) = BytesUtils.readAndReturnLabel(fqdn_, 0);

        // Parse the tld from the fqdn
        bytes32 tld_ = BytesUtils.namehash(fqdn_, offset_);

        // Calculate the node
        return _calculateNode(labelHash_, tld_);
    }

    function _calculateNode(bytes memory label_, bytes32 parent_) internal pure returns (bytes32) {
        return _calculateNode(keccak256(label_), parent_);
    }

    function _calculateNode(bytes32 labelHash_, bytes32 parent_) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked(parent_, labelHash_));
    }
}

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

pragma solidity ^0.8.0;

import "./math/MathUpgradeable.sol";
import "./math/SignedMathUpgradeable.sol";

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

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

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

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

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

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

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

File 59 of 63 : AbstractDomainController.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.17;

/// Internal References ---------------------------------------------------------------------------

import {AbstractAccessControlled} from "src/utils/access/abstracts/AbstractAccessControlled.sol";

abstract contract AbstractDomainController /* is AbstractAccessControlled */ {
    /// Accessor Functions ------------------------------------------------------------------------

    function _tokenExists(uint256 node_) internal view virtual returns (bool);


    // function _callerIsMetadataAdmin__validate() internal view virtual;
}

File 60 of 63 : GlobalEvents.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;

contract GlobalEvents {

    /// ERC721 ---------------------------------------------------------------------------------

    /**
     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
     */
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
     */
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
     */
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    /// ERC1155 --------------------------------------------------------------------------------

    /**
     * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.
     */
    event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);

    // /**
    // * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
    // * transfers.
    // */
    // event TransferBatch(
    //     address indexed operator,
    //     address indexed from,
    //     address indexed to,
    //     uint256[] ids,
    //     uint256[] values
    // );

    // /**
    // * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
    // * `approved`.
    // */
    // event ApprovalForAll(address indexed account, address indexed operator, bool approved);

    /**
     * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
     *
     * If an {URI} event was emitted for `id`, the standard
     * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
     * returned by {IERC1155MetadataURI-uri}.
     */
    event URI(string value, uint256 indexed id);

    /// ENS ------------------------------------------------------------------------------------

    // Logged when the owner of a node assigns a new owner to a subnode.
    event NewOwner(bytes32 indexed node, bytes32 indexed label, address owner);

    // Logged when the owner of a node transfers ownership to a new account.
    event Transfer(bytes32 indexed node, address owner);

    // Logged when the resolver for a node changes.
    event NewResolver(bytes32 indexed node, address resolver);

    // Logged when the TTL of a node changes
    event NewTTL(bytes32 indexed node, uint64 ttl);

    // // Logged when an operator is added or removed.
    // event ApprovalForAll(
    //     address indexed owner,
    //     address indexed operator,
    //     bool approved
    // );

    /// 3DNS -----------------------------------------------------------------------------------

    event RegistrationCreated(
        bytes32 indexed node, bytes32 indexed tld, bytes fqdn, address registrant, uint32 controlBitmap, uint64 expiry
    );

    event RegistrationExtended(bytes32 indexed node, uint64 indexed duration, uint64 indexed newExpiry);

    event RegistrationTransferred(bytes32 indexed node, address indexed newOwner, address indexed operator);

    event RegistrationBurned(bytes32 indexed node, address indexed burner);

    event RegistrationLocked(bytes32 indexed node, uint64 lockedUntil);
    
    event RegistrationUnlocked(bytes32 indexed node);

    event RegistrationIAMAuthorization(bytes32 indexed node, address indexed operator, bytes32 permissions);
    event RegistrationIAMCleared(bytes32 indexed node);
}

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

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

pragma solidity ^0.8.0;

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

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

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

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

// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.17;

/// Internal References ---------------------------------------------------------------------------

import {IThreeDNSAccessControlled} from "../interfaces/IThreeDNSAccessControlled.sol";
import {IThreeDNSAuthority} from "../interfaces/IThreeDNSAuthority.sol";

abstract contract AbstractAccessControlled is IThreeDNSAccessControlled {

    /// Abstract Authority Accessor ===============================================================

    function authority() public view virtual returns (IThreeDNSAuthority);

    /// Access Control Functions ==================================================================

    function _callerIsOperator__validate() internal view virtual;
    
}

Settings
{
  "remappings": [
    "ds-test/=lib/solmate/lib/ds-test/src/",
    "ens-contracts/=lib/ens-contracts/contracts/",
    "ens/=lib/ens/contracts/",
    "forge-std/=lib/forge-std/src/",
    "openzeppelin-not-upgradeable/=lib/openzeppelin-contracts/contracts/",
    "openzeppelin-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
    "solmate/=lib/solmate/src/",
    "@openzeppelin/=lib/openzeppelin-contracts/",
    "create2deployer/=lib/create2deployer/",
    "diamond-3/=lib/diamond-3/contracts/",
    "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
    "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/",
    "openzeppelin/=lib/openzeppelin-contracts/contracts/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "paris",
  "viaIR": false,
  "libraries": {}
}

Contract Security Audit

Contract ABI

API
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"bytes4","name":"selector","type":"bytes4"}],"name":"LibDiamondCut_facetAlreadyExists","type":"error"},{"inputs":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"bytes4","name":"selector","type":"bytes4"}],"name":"LibDiamondCut_facetDoesNotExist","type":"error"},{"inputs":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"bytes4","name":"selector","type":"bytes4"}],"name":"LibDiamondCut_immutableFunction","type":"error"},{"inputs":[],"name":"ThreeDNSAccessControlled_invalidAuthority","type":"error"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"ThreeDNSAccessControlled_unauthorized","type":"error"},{"inputs":[],"name":"ThreeDNSRegControl_accessDenied","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract IThreeDNSAuthority","name":"previousAuthority","type":"address"},{"indexed":true,"internalType":"contract IThreeDNSAuthority","name":"newAuthority","type":"address"}],"name":"AuthorityChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"authority","outputs":[{"internalType":"contract IThreeDNSAuthority","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IThreeDNSAuthority","name":"_newAuthority","type":"address"}],"name":"changeAuthority","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"facetAddress","type":"address"},{"internalType":"enum IDiamondCut.FacetCutAction","name":"action","type":"uint8"},{"internalType":"bytes4[]","name":"functionSelectors","type":"bytes4[]"}],"internalType":"struct IDiamondCut.FacetCut[]","name":"_diamondCut","type":"tuple[]"},{"internalType":"address","name":"_init","type":"address"},{"internalType":"bytes","name":"_calldata","type":"bytes"}],"name":"diamondCut","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IThreeDNSAuthority","name":"_authority","type":"address"},{"internalType":"address","name":"resolver_","type":"address"},{"internalType":"string","name":"domainName_","type":"string"},{"internalType":"string","name":"domainVersion_","type":"string"},{"internalType":"uint64","name":"chainId_","type":"uint64"},{"internalType":"contract IERC20Upgradeable","name":"usdc_","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId_","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId_","type":"bytes4"},{"internalType":"bool","name":"enabled_","type":"bool"}],"name":"trackInterface","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

608060405234801561001057600080fd5b5061001961001e565b6100dd565b600054610100900460ff161561008a5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff908116146100db576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b611d72806100ec6000396000f3fe6080604052600436106100595760003560e01c806301ffc9a71461010d578063116877cc1461017b5780631f931c1c1461019b5780633cbd93e6146101bb578063bf7e214f146101db578063c0d18dad1461020857610060565b3661006057005b600080356001600160e01b0319168152600080516020611cd1833981519152602081905260409091205481906001600160a01b0316806100e75760405162461bcd60e51b815260206004820181905260248201527f4469616d6f6e643a2046756e6374696f6e20646f6573206e6f7420657869737460448201526064015b60405180910390fd5b3660008037600080366000845af43d6000803e808015610106573d6000f35b3d6000fd5b005b34801561011957600080fd5b5061016661012836600461150b565b6001600160e01b03191660009081527fc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131f602052604090205460ff1690565b60405190151581526020015b60405180910390f35b34801561018757600080fd5b5061010b610196366004611542565b610228565b3480156101a757600080fd5b5061010b6101b63660046115b3565b61023c565b3480156101c757600080fd5b5061010b6101d6366004611673565b610295565b3480156101e757600080fd5b506101f06102e8565b6040516001600160a01b039091168152602001610172565b34801561021457600080fd5b5061010b61022336600461178a565b6102f7565b610230610420565b61023981610449565b50565b6102446104c9565b61028e6102518587611863565b8484848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506105cb92505050565b5050505050565b61029d6104c9565b6001600160e01b03199190911660009081527fc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131f60205260409020805460ff1916911515919091179055565b60006102f26107dc565b905090565b600054610100900460ff16158080156103175750600054600160ff909116105b806103315750303b158015610331575060005460ff166001145b6103945760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016100de565b6000805460ff1916600117905580156103b7576000805461ff0019166101001790555b6103c08761080a565b6103c8610875565b6103d18661089d565b8015610417576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050565b6104286108f4565b61044757604051636508181b60e01b81523360048201526024016100de565b565b6001600160a01b03811661047057604051630b208f6960e11b815260040160405180910390fd5b600061047a6107dc565b90506104858261096f565b816001600160a01b0316816001600160a01b03167f275720694d99bebae3e30a093350471a8a15db9c771974d841c724b07a55f39260405160405180910390a35050565b6104d16102e8565b6001600160a01b031663c33888306104e76102e8565b6001600160a01b0316636112f7076040518163ffffffff1660e01b8152600401602060405180830381865afa158015610524573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105489190611999565b6040516001600160e01b031960e084901b1681526004810191909152336024820152604401602060405180830381865afa15801561058a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105ae91906119b2565b610447576040516306a573bb60e41b815260040160405180910390fd5b60005b83518110156107915760008482815181106105eb576105eb6119cf565b60200260200101516020015190506000600281111561060c5761060c6119e5565b81600281111561061e5761061e6119e5565b0361066c57610667858381518110610638576106386119cf565b602002602001015160000151868481518110610656576106566119cf565b6020026020010151604001516109a9565b61077e565b6001816002811115610680576106806119e5565b036106c95761066785838151811061069a5761069a6119cf565b6020026020010151600001518684815181106106b8576106b86119cf565b602002602001015160400151610bc1565b60028160028111156106dd576106dd6119e5565b03610726576106678583815181106106f7576106f76119cf565b602002602001015160000151868481518110610715576107156119cf565b602002602001015160400151610e4b565b60405162461bcd60e51b815260206004820152602760248201527f4c69624469616d6f6e644375743a20496e636f727265637420466163657443756044820152663a20b1ba34b7b760c91b60648201526084016100de565b508061078981611a11565b9150506105ce565b507f8faa70878671ccd212d20771b795c50af8fd3ff6cf27f4bde57e5d4de0aeb6738383836040516107c593929190611a7a565b60405180910390a16107d78282610f68565b505050565b7fd130673014572f7121caf912a5f962365c11e8f2a364051a5111e361375c0d84546001600160a01b031690565b600054610100900460ff166102305760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b60648201526084016100de565b61044760017efb1582097edca5730fdb99215e4455bb86a33d4dfb2e772de67f816dc82a6755565b6001600160a01b0381166108b057600080fd5b807f12ae3e04032463d545323c69dad532e95f65241ef43aee9d1febe281cd74afe95b80546001600160a01b0319166001600160a01b039290921691909117905550565b6000336108ff6107dc565b6001600160a01b031663570ca7356040518163ffffffff1660e01b8152600401602060405180830381865afa15801561093c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109609190611b7a565b6001600160a01b031614905090565b6001600160a01b03811661098257600080fd5b807fd130673014572f7121caf912a5f962365c11e8f2a364051a5111e361375c0d846108d3565b60008151116109ca5760405162461bcd60e51b81526004016100de90611b97565b600080516020611cd18339815191526001600160a01b0383166109ff5760405162461bcd60e51b81526004016100de90611be2565b6001600160a01b03831660009081526001820160205260408120549061ffff82169003610aa457610a4884604051806060016040528060248152602001611d1960249139611175565b6002820180546001600160a01b038616600081815260018087016020908152604083208201805461ffff191661ffff90961695909517909455845490810185559381529190912090910180546001600160a01b03191690911790555b60005b835181101561028e576000848281518110610ac457610ac46119cf565b6020908102919091018101516001600160e01b031981166000908152918690526040909120549091506001600160a01b03168015610b195780826040516379e539eb60e11b81526004016100de929190611c2e565b6001600160a01b03871660008181526001878101602090815260408084208054938401815584528184206008840401805463ffffffff60079095166004026101000a948502191660e089901c94909402939093179092556001600160e01b031986168352889052902080546001600160b01b031916909117600160a01b61ffff87160217905583610ba981611c51565b94505050508080610bb990611a11565b915050610aa7565b6000815111610be25760405162461bcd60e51b81526004016100de90611b97565b600080516020611cd18339815191526001600160a01b038316610c175760405162461bcd60e51b81526004016100de90611be2565b6001600160a01b03831660009081526001820160205260408120549061ffff82169003610cbc57610c6084604051806060016040528060248152602001611d1960249139611175565b6002820180546001600160a01b038616600081815260018087016020908152604083208201805461ffff191661ffff90961695909517909455845490810185559381529190912090910180546001600160a01b03191690911790555b60005b835181101561028e576000848281518110610cdc57610cdc6119cf565b6020908102919091018101516001600160e01b031981166000908152918690526040909120549091506001600160a01b039081169087168103610d875760405162461bcd60e51b815260206004820152603860248201527f4c69624469616d6f6e644375743a2043616e2774207265706c6163652066756e60448201527f6374696f6e20776974682073616d652066756e6374696f6e000000000000000060648201526084016100de565b610d918183611196565b6001600160e01b03198216600081815260208781526040808320805461ffff60a01b1916600160a01b61ffff8b16021781556001600160a01b038c168085526001808c0185529285208054938401815585528385206008840401805463ffffffff60079095166004026101000a948502191660e08a901c94909402939093179092559390925287905281546001600160a01b03191617905583610e3381611c51565b94505050508080610e4390611a11565b915050610cbf565b6000815111610e6c5760405162461bcd60e51b81526004016100de90611b97565b600080516020611cd18339815191526001600160a01b03831615610ef15760405162461bcd60e51b815260206004820152603660248201527f4c69624469616d6f6e644375743a2052656d6f76652066616365742061646472604482015275657373206d757374206265206164647265737328302960501b60648201526084016100de565b60005b8251811015610f62576000838281518110610f1157610f116119cf565b6020908102919091018101516001600160e01b031981166000908152918590526040909120549091506001600160a01b0316610f4d8183611196565b50508080610f5a90611a11565b915050610ef4565b50505050565b6001600160a01b038216610fef57805115610feb5760405162461bcd60e51b815260206004820152603c60248201527f4c69624469616d6f6e644375743a205f696e697420697320616464726573732860448201527f3029206275745f63616c6c64617461206973206e6f7420656d7074790000000060648201526084016100de565b5050565b60008151116110665760405162461bcd60e51b815260206004820152603d60248201527f4c69624469616d6f6e644375743a205f63616c6c6461746120697320656d707460448201527f7920627574205f696e6974206973206e6f74206164647265737328302900000060648201526084016100de565b6001600160a01b03821630146110985761109882604051806060016040528060288152602001611cf160289139611175565b600080836001600160a01b0316836040516110b39190611c72565b600060405180830381855af49150503d80600081146110ee576040519150601f19603f3d011682016040523d82523d6000602084013e6110f3565b606091505b509150915081610f625780511561111e578060405162461bcd60e51b81526004016100de9190611c8e565b60405162461bcd60e51b815260206004820152602660248201527f4c69624469616d6f6e644375743a205f696e69742066756e6374696f6e2072656044820152651d995c9d195960d21b60648201526084016100de565b813b8181610f625760405162461bcd60e51b81526004016100de9190611c8e565b600080516020611cd18339815191526001600160a01b0383166111d057828260405163013e763960e21b81526004016100de929190611c2e565b306001600160a01b038416036111fd57828260405163c66c256160e01b81526004016100de929190611c2e565b6001600160e01b03198216600090815260208281526040808320546001600160a01b0387168452600180860190935290832054600160a01b90910461ffff16929161124791611ca1565b9050808214611333576001600160a01b0385166000908152600184016020526040812080548390811061127c5761127c6119cf565b600091825260208083206008830401546001600160a01b038a168452600188019091526040909220805460079092166004026101000a90920460e01b9250829190859081106112cd576112cd6119cf565b600091825260208083206008830401805463ffffffff60079094166004026101000a938402191660e09590951c929092029390931790556001600160e01b031992909216825284905260409020805461ffff60a01b1916600160a01b61ffff8516021790555b6001600160a01b0385166000908152600184016020526040902080548061135c5761135c611cba565b60008281526020808220600860001990940193840401805463ffffffff600460078716026101000a0219169055919092556001600160e01b0319861682528490526040812080546001600160b01b031916905581900361028e5760028301546000906113ca90600190611ca1565b6001600160a01b038716600090815260018087016020526040909120015490915061ffff1680821461148957600085600201838154811061140d5761140d6119cf565b6000918252602090912001546002870180546001600160a01b03909216925082918490811061143e5761143e6119cf565b600091825260208083209190910180546001600160a01b0319166001600160a01b0394851617905592909116815260018781019092526040902001805461ffff191661ffff83161790555b8460020180548061149c5761149c611cba565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b03891682526001878101909152604090912001805461ffff1916905550505050505050565b80356001600160e01b03198116811461150657600080fd5b919050565b60006020828403121561151d57600080fd5b611526826114ee565b9392505050565b6001600160a01b038116811461023957600080fd5b60006020828403121561155457600080fd5b81356115268161152d565b80356115068161152d565b60008083601f84011261157c57600080fd5b50813567ffffffffffffffff81111561159457600080fd5b6020830191508360208285010111156115ac57600080fd5b9250929050565b6000806000806000606086880312156115cb57600080fd5b853567ffffffffffffffff808211156115e357600080fd5b818801915088601f8301126115f757600080fd5b81358181111561160657600080fd5b8960208260051b850101111561161b57600080fd5b602083019750809650506116316020890161155f565b9450604088013591508082111561164757600080fd5b506116548882890161156a565b969995985093965092949392505050565b801515811461023957600080fd5b6000806040838503121561168657600080fd5b61168f836114ee565b9150602083013561169f81611665565b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b6040516060810167ffffffffffffffff811182821017156116e3576116e36116aa565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715611712576117126116aa565b604052919050565b600082601f83011261172b57600080fd5b813567ffffffffffffffff811115611745576117456116aa565b611758601f8201601f19166020016116e9565b81815284602083860101111561176d57600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060008060c087890312156117a357600080fd5b86356117ae8161152d565b955060208701356117be8161152d565b9450604087013567ffffffffffffffff808211156117db57600080fd5b6117e78a838b0161171a565b955060608901359150808211156117fd57600080fd5b6118098a838b0161171a565b945060808901359150808216821461182057600080fd5b50915060a08701356118318161152d565b809150509295509295509295565b600067ffffffffffffffff821115611859576118596116aa565b5060051b60200190565b60006118766118718461183f565b6116e9565b83815260208082019190600586811b86013681111561189457600080fd5b865b8181101561198c57803567ffffffffffffffff808211156118b75760008081fd5b818a019150606082360312156118cd5760008081fd5b6118d56116c0565b82356118e08161152d565b815282870135600381106118f45760008081fd5b818801526040838101358381111561190c5760008081fd5b939093019236601f85011261192357600092508283fd5b833592506119336118718461183f565b83815292871b840188019288810190368511156119505760008081fd5b948901945b8486101561197557611966866114ee565b82529489019490890190611955565b918301919091525088525050948301948301611896565b5092979650505050505050565b6000602082840312156119ab57600080fd5b5051919050565b6000602082840312156119c457600080fd5b815161152681611665565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060018201611a2357611a236119fb565b5060010190565b60005b83811015611a45578181015183820152602001611a2d565b50506000910152565b60008151808452611a66816020860160208601611a2a565b601f01601f19169290920160200192915050565b60006060808301818452808751808352608092508286019150828160051b8701016020808b0160005b84811015611b4a57898403607f19018652815180516001600160a01b03168552838101518986019060038110611ae957634e487b7160e01b600052602160045260246000fd5b868601526040918201519186018a905281519081905290840190600090898701905b80831015611b355783516001600160e01b0319168252928601926001929092019190860190611b0b565b50978501979550505090820190600101611aa3565b50506001600160a01b038a16908801528681036040880152611b6c8189611a4e565b9a9950505050505050505050565b600060208284031215611b8c57600080fd5b81516115268161152d565b6020808252602b908201527f4c69624469616d6f6e644375743a204e6f2073656c6563746f727320696e206660408201526a1858d95d081d1bc818dd5d60aa1b606082015260800190565b6020808252602c908201527f4c69624469616d6f6e644375743a204164642066616365742063616e2774206260408201526b65206164647265737328302960a01b606082015260800190565b6001600160a01b039290921682526001600160e01b031916602082015260400190565b600061ffff808316818103611c6857611c686119fb565b6001019392505050565b60008251611c84818460208701611a2a565b9190910192915050565b6020815260006115266020830184611a4e565b81810381811115611cb457611cb46119fb565b92915050565b634e487b7160e01b600052603160045260246000fdfec8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131c4c69624469616d6f6e644375743a205f696e6974206164647265737320686173206e6f20636f64654c69624469616d6f6e644375743a204e657720666163657420686173206e6f20636f6465a264697066735822122061949b18f6f37521360e5faa7c6a902adf83acbbb22fd9eb434375c31637950a64736f6c63430008120033

Deployed Bytecode

0x6080604052600436106100595760003560e01c806301ffc9a71461010d578063116877cc1461017b5780631f931c1c1461019b5780633cbd93e6146101bb578063bf7e214f146101db578063c0d18dad1461020857610060565b3661006057005b600080356001600160e01b0319168152600080516020611cd1833981519152602081905260409091205481906001600160a01b0316806100e75760405162461bcd60e51b815260206004820181905260248201527f4469616d6f6e643a2046756e6374696f6e20646f6573206e6f7420657869737460448201526064015b60405180910390fd5b3660008037600080366000845af43d6000803e808015610106573d6000f35b3d6000fd5b005b34801561011957600080fd5b5061016661012836600461150b565b6001600160e01b03191660009081527fc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131f602052604090205460ff1690565b60405190151581526020015b60405180910390f35b34801561018757600080fd5b5061010b610196366004611542565b610228565b3480156101a757600080fd5b5061010b6101b63660046115b3565b61023c565b3480156101c757600080fd5b5061010b6101d6366004611673565b610295565b3480156101e757600080fd5b506101f06102e8565b6040516001600160a01b039091168152602001610172565b34801561021457600080fd5b5061010b61022336600461178a565b6102f7565b610230610420565b61023981610449565b50565b6102446104c9565b61028e6102518587611863565b8484848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506105cb92505050565b5050505050565b61029d6104c9565b6001600160e01b03199190911660009081527fc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131f60205260409020805460ff1916911515919091179055565b60006102f26107dc565b905090565b600054610100900460ff16158080156103175750600054600160ff909116105b806103315750303b158015610331575060005460ff166001145b6103945760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016100de565b6000805460ff1916600117905580156103b7576000805461ff0019166101001790555b6103c08761080a565b6103c8610875565b6103d18661089d565b8015610417576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050565b6104286108f4565b61044757604051636508181b60e01b81523360048201526024016100de565b565b6001600160a01b03811661047057604051630b208f6960e11b815260040160405180910390fd5b600061047a6107dc565b90506104858261096f565b816001600160a01b0316816001600160a01b03167f275720694d99bebae3e30a093350471a8a15db9c771974d841c724b07a55f39260405160405180910390a35050565b6104d16102e8565b6001600160a01b031663c33888306104e76102e8565b6001600160a01b0316636112f7076040518163ffffffff1660e01b8152600401602060405180830381865afa158015610524573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105489190611999565b6040516001600160e01b031960e084901b1681526004810191909152336024820152604401602060405180830381865afa15801561058a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105ae91906119b2565b610447576040516306a573bb60e41b815260040160405180910390fd5b60005b83518110156107915760008482815181106105eb576105eb6119cf565b60200260200101516020015190506000600281111561060c5761060c6119e5565b81600281111561061e5761061e6119e5565b0361066c57610667858381518110610638576106386119cf565b602002602001015160000151868481518110610656576106566119cf565b6020026020010151604001516109a9565b61077e565b6001816002811115610680576106806119e5565b036106c95761066785838151811061069a5761069a6119cf565b6020026020010151600001518684815181106106b8576106b86119cf565b602002602001015160400151610bc1565b60028160028111156106dd576106dd6119e5565b03610726576106678583815181106106f7576106f76119cf565b602002602001015160000151868481518110610715576107156119cf565b602002602001015160400151610e4b565b60405162461bcd60e51b815260206004820152602760248201527f4c69624469616d6f6e644375743a20496e636f727265637420466163657443756044820152663a20b1ba34b7b760c91b60648201526084016100de565b508061078981611a11565b9150506105ce565b507f8faa70878671ccd212d20771b795c50af8fd3ff6cf27f4bde57e5d4de0aeb6738383836040516107c593929190611a7a565b60405180910390a16107d78282610f68565b505050565b7fd130673014572f7121caf912a5f962365c11e8f2a364051a5111e361375c0d84546001600160a01b031690565b600054610100900460ff166102305760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b60648201526084016100de565b61044760017efb1582097edca5730fdb99215e4455bb86a33d4dfb2e772de67f816dc82a6755565b6001600160a01b0381166108b057600080fd5b807f12ae3e04032463d545323c69dad532e95f65241ef43aee9d1febe281cd74afe95b80546001600160a01b0319166001600160a01b039290921691909117905550565b6000336108ff6107dc565b6001600160a01b031663570ca7356040518163ffffffff1660e01b8152600401602060405180830381865afa15801561093c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109609190611b7a565b6001600160a01b031614905090565b6001600160a01b03811661098257600080fd5b807fd130673014572f7121caf912a5f962365c11e8f2a364051a5111e361375c0d846108d3565b60008151116109ca5760405162461bcd60e51b81526004016100de90611b97565b600080516020611cd18339815191526001600160a01b0383166109ff5760405162461bcd60e51b81526004016100de90611be2565b6001600160a01b03831660009081526001820160205260408120549061ffff82169003610aa457610a4884604051806060016040528060248152602001611d1960249139611175565b6002820180546001600160a01b038616600081815260018087016020908152604083208201805461ffff191661ffff90961695909517909455845490810185559381529190912090910180546001600160a01b03191690911790555b60005b835181101561028e576000848281518110610ac457610ac46119cf565b6020908102919091018101516001600160e01b031981166000908152918690526040909120549091506001600160a01b03168015610b195780826040516379e539eb60e11b81526004016100de929190611c2e565b6001600160a01b03871660008181526001878101602090815260408084208054938401815584528184206008840401805463ffffffff60079095166004026101000a948502191660e089901c94909402939093179092556001600160e01b031986168352889052902080546001600160b01b031916909117600160a01b61ffff87160217905583610ba981611c51565b94505050508080610bb990611a11565b915050610aa7565b6000815111610be25760405162461bcd60e51b81526004016100de90611b97565b600080516020611cd18339815191526001600160a01b038316610c175760405162461bcd60e51b81526004016100de90611be2565b6001600160a01b03831660009081526001820160205260408120549061ffff82169003610cbc57610c6084604051806060016040528060248152602001611d1960249139611175565b6002820180546001600160a01b038616600081815260018087016020908152604083208201805461ffff191661ffff90961695909517909455845490810185559381529190912090910180546001600160a01b03191690911790555b60005b835181101561028e576000848281518110610cdc57610cdc6119cf565b6020908102919091018101516001600160e01b031981166000908152918690526040909120549091506001600160a01b039081169087168103610d875760405162461bcd60e51b815260206004820152603860248201527f4c69624469616d6f6e644375743a2043616e2774207265706c6163652066756e60448201527f6374696f6e20776974682073616d652066756e6374696f6e000000000000000060648201526084016100de565b610d918183611196565b6001600160e01b03198216600081815260208781526040808320805461ffff60a01b1916600160a01b61ffff8b16021781556001600160a01b038c168085526001808c0185529285208054938401815585528385206008840401805463ffffffff60079095166004026101000a948502191660e08a901c94909402939093179092559390925287905281546001600160a01b03191617905583610e3381611c51565b94505050508080610e4390611a11565b915050610cbf565b6000815111610e6c5760405162461bcd60e51b81526004016100de90611b97565b600080516020611cd18339815191526001600160a01b03831615610ef15760405162461bcd60e51b815260206004820152603660248201527f4c69624469616d6f6e644375743a2052656d6f76652066616365742061646472604482015275657373206d757374206265206164647265737328302960501b60648201526084016100de565b60005b8251811015610f62576000838281518110610f1157610f116119cf565b6020908102919091018101516001600160e01b031981166000908152918590526040909120549091506001600160a01b0316610f4d8183611196565b50508080610f5a90611a11565b915050610ef4565b50505050565b6001600160a01b038216610fef57805115610feb5760405162461bcd60e51b815260206004820152603c60248201527f4c69624469616d6f6e644375743a205f696e697420697320616464726573732860448201527f3029206275745f63616c6c64617461206973206e6f7420656d7074790000000060648201526084016100de565b5050565b60008151116110665760405162461bcd60e51b815260206004820152603d60248201527f4c69624469616d6f6e644375743a205f63616c6c6461746120697320656d707460448201527f7920627574205f696e6974206973206e6f74206164647265737328302900000060648201526084016100de565b6001600160a01b03821630146110985761109882604051806060016040528060288152602001611cf160289139611175565b600080836001600160a01b0316836040516110b39190611c72565b600060405180830381855af49150503d80600081146110ee576040519150601f19603f3d011682016040523d82523d6000602084013e6110f3565b606091505b509150915081610f625780511561111e578060405162461bcd60e51b81526004016100de9190611c8e565b60405162461bcd60e51b815260206004820152602660248201527f4c69624469616d6f6e644375743a205f696e69742066756e6374696f6e2072656044820152651d995c9d195960d21b60648201526084016100de565b813b8181610f625760405162461bcd60e51b81526004016100de9190611c8e565b600080516020611cd18339815191526001600160a01b0383166111d057828260405163013e763960e21b81526004016100de929190611c2e565b306001600160a01b038416036111fd57828260405163c66c256160e01b81526004016100de929190611c2e565b6001600160e01b03198216600090815260208281526040808320546001600160a01b0387168452600180860190935290832054600160a01b90910461ffff16929161124791611ca1565b9050808214611333576001600160a01b0385166000908152600184016020526040812080548390811061127c5761127c6119cf565b600091825260208083206008830401546001600160a01b038a168452600188019091526040909220805460079092166004026101000a90920460e01b9250829190859081106112cd576112cd6119cf565b600091825260208083206008830401805463ffffffff60079094166004026101000a938402191660e09590951c929092029390931790556001600160e01b031992909216825284905260409020805461ffff60a01b1916600160a01b61ffff8516021790555b6001600160a01b0385166000908152600184016020526040902080548061135c5761135c611cba565b60008281526020808220600860001990940193840401805463ffffffff600460078716026101000a0219169055919092556001600160e01b0319861682528490526040812080546001600160b01b031916905581900361028e5760028301546000906113ca90600190611ca1565b6001600160a01b038716600090815260018087016020526040909120015490915061ffff1680821461148957600085600201838154811061140d5761140d6119cf565b6000918252602090912001546002870180546001600160a01b03909216925082918490811061143e5761143e6119cf565b600091825260208083209190910180546001600160a01b0319166001600160a01b0394851617905592909116815260018781019092526040902001805461ffff191661ffff83161790555b8460020180548061149c5761149c611cba565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b03891682526001878101909152604090912001805461ffff1916905550505050505050565b80356001600160e01b03198116811461150657600080fd5b919050565b60006020828403121561151d57600080fd5b611526826114ee565b9392505050565b6001600160a01b038116811461023957600080fd5b60006020828403121561155457600080fd5b81356115268161152d565b80356115068161152d565b60008083601f84011261157c57600080fd5b50813567ffffffffffffffff81111561159457600080fd5b6020830191508360208285010111156115ac57600080fd5b9250929050565b6000806000806000606086880312156115cb57600080fd5b853567ffffffffffffffff808211156115e357600080fd5b818801915088601f8301126115f757600080fd5b81358181111561160657600080fd5b8960208260051b850101111561161b57600080fd5b602083019750809650506116316020890161155f565b9450604088013591508082111561164757600080fd5b506116548882890161156a565b969995985093965092949392505050565b801515811461023957600080fd5b6000806040838503121561168657600080fd5b61168f836114ee565b9150602083013561169f81611665565b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b6040516060810167ffffffffffffffff811182821017156116e3576116e36116aa565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715611712576117126116aa565b604052919050565b600082601f83011261172b57600080fd5b813567ffffffffffffffff811115611745576117456116aa565b611758601f8201601f19166020016116e9565b81815284602083860101111561176d57600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060008060c087890312156117a357600080fd5b86356117ae8161152d565b955060208701356117be8161152d565b9450604087013567ffffffffffffffff808211156117db57600080fd5b6117e78a838b0161171a565b955060608901359150808211156117fd57600080fd5b6118098a838b0161171a565b945060808901359150808216821461182057600080fd5b50915060a08701356118318161152d565b809150509295509295509295565b600067ffffffffffffffff821115611859576118596116aa565b5060051b60200190565b60006118766118718461183f565b6116e9565b83815260208082019190600586811b86013681111561189457600080fd5b865b8181101561198c57803567ffffffffffffffff808211156118b75760008081fd5b818a019150606082360312156118cd5760008081fd5b6118d56116c0565b82356118e08161152d565b815282870135600381106118f45760008081fd5b818801526040838101358381111561190c5760008081fd5b939093019236601f85011261192357600092508283fd5b833592506119336118718461183f565b83815292871b840188019288810190368511156119505760008081fd5b948901945b8486101561197557611966866114ee565b82529489019490890190611955565b918301919091525088525050948301948301611896565b5092979650505050505050565b6000602082840312156119ab57600080fd5b5051919050565b6000602082840312156119c457600080fd5b815161152681611665565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060018201611a2357611a236119fb565b5060010190565b60005b83811015611a45578181015183820152602001611a2d565b50506000910152565b60008151808452611a66816020860160208601611a2a565b601f01601f19169290920160200192915050565b60006060808301818452808751808352608092508286019150828160051b8701016020808b0160005b84811015611b4a57898403607f19018652815180516001600160a01b03168552838101518986019060038110611ae957634e487b7160e01b600052602160045260246000fd5b868601526040918201519186018a905281519081905290840190600090898701905b80831015611b355783516001600160e01b0319168252928601926001929092019190860190611b0b565b50978501979550505090820190600101611aa3565b50506001600160a01b038a16908801528681036040880152611b6c8189611a4e565b9a9950505050505050505050565b600060208284031215611b8c57600080fd5b81516115268161152d565b6020808252602b908201527f4c69624469616d6f6e644375743a204e6f2073656c6563746f727320696e206660408201526a1858d95d081d1bc818dd5d60aa1b606082015260800190565b6020808252602c908201527f4c69624469616d6f6e644375743a204164642066616365742063616e2774206260408201526b65206164647265737328302960a01b606082015260800190565b6001600160a01b039290921682526001600160e01b031916602082015260400190565b600061ffff808316818103611c6857611c686119fb565b6001019392505050565b60008251611c84818460208701611a2a565b9190910192915050565b6020815260006115266020830184611a4e565b81810381811115611cb457611cb46119fb565b92915050565b634e487b7160e01b600052603160045260246000fdfec8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131c4c69624469616d6f6e644375743a205f696e6974206164647265737320686173206e6f20636f64654c69624469616d6f6e644375743a204e657720666163657420686173206e6f20636f6465a264697066735822122061949b18f6f37521360e5faa7c6a902adf83acbbb22fd9eb434375c31637950a64736f6c63430008120033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

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.