ETH Price: $2,063.99 (+0.10%)

Contract

0x000000AB1a0786eE8c71516d9AbB8a36fbdDb7CB
 

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
Transfer Ownersh...199854312024-05-30 21:47:35651 days ago1717105655IN
0x000000AB...6fbdDb7CB
0 ETH0.0005375618.55087504

Latest 3 internal transactions

Advanced mode:
Parent Transaction Hash Method Block
From
To
0x3d602d80200861182024-06-13 23:17:35636 days ago1718320655
0x000000AB...6fbdDb7CB
 Contract Creation0 ETH
0x60c06040200861182024-06-13 23:17:35636 days ago1718320655
0x000000AB...6fbdDb7CB
 Contract Creation0 ETH
0x60e06040199852972024-05-30 21:20:47651 days ago1717104047  Contract Creation0 ETH
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
EngineFactoryV0

Compiler Version
v0.8.22+commit.4fc1097e

Optimization Enabled:
Yes with 10 runs

Other Settings:
paris EvmVersion
// SPDX-License-Identifier: LGPL-3.0-only
// Created By: Art Blocks Inc.

// @dev fixed to specific solidity version for clarity and for more clear
// source code verification purposes.
pragma solidity 0.8.22;

import {AdminACLV0} from "../../AdminACLV0.sol";
import {IGenArt721CoreContractV3_Engine, EngineConfiguration} from "../../interfaces/v0.8.x/IGenArt721CoreContractV3_Engine.sol";
import {ICoreRegistryV1} from "../../interfaces/v0.8.x/ICoreRegistryV1.sol";
import {IEngineFactoryV0} from "../../interfaces/v0.8.x/IEngineFactoryV0.sol";
import {IAdminACLV0_Extended} from "../../interfaces/v0.8.x/IAdminACLV0_Extended.sol";

import "@openzeppelin-5.0/contracts/access/Ownable.sol";
import {Clones} from "@openzeppelin-5.0/contracts/proxy/Clones.sol";
import {IERC20} from "@openzeppelin-5.0/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin-5.0/contracts/token/ERC20/utils/SafeERC20.sol";
import {Create2} from "@openzeppelin-5.0/contracts/utils/Create2.sol";

/**
 * @title EngineFactoryV0
 * @author Art Blocks Inc.
 * @notice Factory contract for creating new Engine and Engine Flex Core contracts.
 * @dev This contract is deployed once, and then used to create new Engine and Engine
 * Flex Core contracts. The contract may be abandoned once it is no longer needed.
 * Once abandoned, the contract can no longer be used to create new Engine and Engine
 * Flex Core contracts.
 * The contract is initialized with a required contract type.
 * The contract is initialized with an Engine and Engine Flex implementation contract, which is cloned
 * when creating new Engine and Engine Flex Core contracts.
 */
contract EngineFactoryV0 is Ownable, IEngineFactoryV0 {
    // public type
    bytes32 public constant type_ = "EngineFactoryV0";

    // base URI host for all Engine contracts on this network/chainID
    string public defaultBaseURIHost;

    /**
     * The implementation contract that is cloned when creating new Engine
     * contracts.
     */
    address public immutable engineImplementation;
    /**
     * The implementation contract that is cloned when creating new Engine
     * Flex contracts.
     */
    address public immutable engineFlexImplementation;

    // Address of core registry contract.
    address public immutable coreRegistry;

    /// version and type of Engine implementation contract
    string public engineCoreType;
    string public engineCoreVersion;

    /// version and type of Engine Flex implementation contract
    string public flexCoreType;
    string public flexCoreVersion;

    /**
     * Indicates whether the contract is abandoned.
     * Once abandoned, the contract can no longer be used to create new Engine
     * and Engine Flex contracts.
     */
    bool public isAbandoned; // default false

    // pseudorandom salt nonce to prevent collisions for multiple contract deployments in single block
    uint256 private _pseudorandomSaltNonce;

    /**
     * Represents a generic call operation.
     */
    struct Call {
        address to;
        bytes data;
    }

    /**
     * @notice validates and assigns immutable configuration variables and
     * sets state variables
     * @param engineImplementation_ address of the Engine
     * implementation contract
     * @param engineFlexImplementation_ address of the Engine Flex
     * implementation contract
     * @param coreRegistry_ address of the core registry contract
     * @param owner_ address of the initial owner
     * @param defaultBaseURIHost_ default base URI prefix for all Engine contracts,
     * e.g. "https://token.artblocks.io/" for mainnet, "https://token.arbitrum.artblocks.io/" for arbitrum, etc.
     */
    constructor(
        address engineImplementation_,
        address engineFlexImplementation_,
        address coreRegistry_,
        address owner_,
        string memory defaultBaseURIHost_
    ) Ownable(owner_) {
        _onlyNonZeroAddress(engineImplementation_);
        _onlyNonZeroAddress(engineFlexImplementation_);
        _onlyNonZeroAddress(coreRegistry_);
        _onlyNonZeroAddress(owner_);

        defaultBaseURIHost = defaultBaseURIHost_;

        engineImplementation = engineImplementation_;
        engineFlexImplementation = engineFlexImplementation_;
        coreRegistry = coreRegistry_;

        engineCoreType = IGenArt721CoreContractV3_Engine(engineImplementation)
            .coreType();
        engineCoreVersion = IGenArt721CoreContractV3_Engine(
            engineImplementation
        ).coreVersion();
        flexCoreType = IGenArt721CoreContractV3_Engine(engineFlexImplementation)
            .coreType();
        flexCoreVersion = IGenArt721CoreContractV3_Engine(
            engineFlexImplementation
        ).coreVersion();

        // emit event
        emit Deployed({
            engineImplementation: engineImplementation_,
            engineFlexImplementation: engineFlexImplementation_,
            type_: type_
        });
    }

    /**
     * @notice Creates a new Engine or Engine Flex contract with the provided
     * `engineConfiguration`, depending on the `engineCoreContractType`.
     * Reverts if invalid configuration is provided, or if in an invalid deployment
     * state (e.g. if the contract is abandoned or does not own the core registry).
     * @param engineCoreContractType Type of Engine Core contract.
     * @param engineConfiguration EngineConfiguration data to configure the
     * contract with.
     * @param adminACLContract Address of admin access control contract, to be
     * set as contract owner. A new contract will be deployed if address is null.
     * @param salt Salt used to deterministically deploy the clone. If null, a
     * pseudorandom salt is generated.
     * @return engineContract The address of the newly created Engine or Engine Flex
     * contract. The address is also emitted in the `EngineContractCreated` event.
     */
    function createEngineContract(
        IEngineFactoryV0.EngineCoreType engineCoreContractType,
        EngineConfiguration calldata engineConfiguration,
        address adminACLContract,
        bytes32 salt
    ) external onlyOwner returns (address engineContract) {
        require(!isAbandoned, "factory is abandoned");
        // validate engine contract configuration
        _onlyNonZeroAddress(engineConfiguration.renderProviderAddress);
        _onlyNonZeroAddress(engineConfiguration.randomizerContract);

        // check if salt is empty and generate a pseudorandom one if so
        if (salt == bytes32(0)) {
            salt = _generatePseudorandomSalt();
        }

        if (adminACLContract == address(0)) {
            _onlyNonZeroAddress(engineConfiguration.newSuperAdminAddress);
            // deploy new AdminACLV0 contract and update super admin
            adminACLContract = Create2.deploy({
                amount: 0,
                salt: _generatePseudorandomSalt(),
                bytecode: type(AdminACLV0).creationCode
            });
            address[] memory tmpEmptyArray = new address[](0);

            IAdminACLV0_Extended(adminACLContract).changeSuperAdmin(
                engineConfiguration.newSuperAdminAddress,
                tmpEmptyArray
            );
        } else {
            // Use existing Admin ACL Contract, newSuperAdminAddress should not be populated
            require(
                engineConfiguration.newSuperAdminAddress == address(0),
                "AdminACL already exists"
            );
        }

        address implementation = engineCoreContractType ==
            IEngineFactoryV0.EngineCoreType.Engine
            ? engineImplementation
            : engineFlexImplementation;

        engineContract = Clones.cloneDeterministic({
            implementation: implementation,
            salt: salt
        });

        IGenArt721CoreContractV3_Engine(engineContract).initialize({
            engineConfiguration: engineConfiguration,
            adminACLContract_: adminACLContract,
            defaultBaseURIHost: defaultBaseURIHost
        });

        (
            string memory coreContractType,
            string memory coreContractVersion
        ) = engineCoreContractType == IEngineFactoryV0.EngineCoreType.Engine
                ? (engineCoreType, engineCoreVersion)
                : (flexCoreType, flexCoreVersion);

        // register the new Engine contract
        ICoreRegistryV1(coreRegistry).registerContract(
            engineContract,
            _stringToBytes32(coreContractVersion),
            _stringToBytes32(coreContractType)
        );
        // emit event
        emit EngineContractCreated(engineContract);
    }

    /**
     * @notice Calls transferOwnership on the core registry.
     * Useful for updating the owner of the core registry contract.
     * @param _owner address of the new owner
     */
    function transferCoreRegistryOwnership(address _owner) external onlyOwner {
        Ownable(coreRegistry).transferOwnership(_owner);
    }

    /**
     * @notice Registers multiple contracts with the core registry.
     * @param contractAddresses An array of contract addresses to register.
     * @param coreVersions An array of versions corresponding to the contract addresses.
     * @param coreTypes An array of types corresponding to the contract addresses.
     */
    function registerMultipleContracts(
        address[] calldata contractAddresses,
        bytes32[] calldata coreVersions,
        bytes32[] calldata coreTypes
    ) external onlyOwner {
        // @dev pure forwarding - input validation is done in the core registry
        ICoreRegistryV1(coreRegistry).registerContracts({
            contractAddresses: contractAddresses,
            coreVersions: coreVersions,
            coreTypes: coreTypes
        });
    }

    /**
     * @notice Unregisters multiple contracts from the core registry.
     * @param contractAddresses An array of contract addresses to unregister.
     */
    function unregisterMultipleContracts(
        address[] calldata contractAddresses
    ) external onlyOwner {
        // @dev pure forwarding - input validation is done in the core registry
        ICoreRegistryV1(coreRegistry).unregisterContracts(contractAddresses);
    }

    /**
     * @notice Abandons the contract, preventing it from being used to create
     * new Engine and Engine Flex contracts.
     * Only callable by the owner, and only once; reverts otherwise.
     */
    function abandon() external onlyOwner {
        require(!isAbandoned, "factory is abandoned");
        // set isAbandoned to true
        isAbandoned = true;
        // emit event
        emit Abandoned();
    }

    /**
     * @dev This contract is not intended to hold funds. This function,
     * `drainETH`, and `drainERC20` are implemented to prevent the loss
     * of funds that might be sent to this contract inadvertently.
     */
    receive() external payable {}

    /**
     * @notice Drains the contract's balance to the `recipient`.
     * @param recipient The address to send funds to.
     * Only callable by the owner.
     */
    function drainETH(address payable recipient) external onlyOwner {
        uint256 balance = address(this).balance;
        if (balance > 0) {
            (bool success, ) = recipient.call{value: balance}("");
            require(success, "Payment failed");
        }
    }

    /**
     * @notice Drains the contract's balance of an input ERC20 token to
     * the `recipient`.
     * @param ERC20TokenAddress The address of the ERC20 token to withdraw.
     * @param recipient The address to send ERC20 tokens to.
     * Only callable by the owner.
     */
    function drainERC20(
        address ERC20TokenAddress,
        address recipient
    ) external onlyOwner {
        IERC20 token = IERC20(ERC20TokenAddress);
        uint256 balance = token.balanceOf(address(this));
        if (balance > 0) {
            SafeERC20.safeTransfer({
                token: token,
                to: recipient,
                value: balance
            });
        }
    }

    /**
     * @notice Execute a batch of calls.
     * @dev The calls are executed in order, reverting if any of them fails. Can
     * only be called by the owner. It is safe to check ownership only once here
     * because the owner status is only used to gate access to the function, not
     * to validate each individual call. Even if ownership is transferred during
     * the sequence of calls, it does not affect the execution logic or security,
     * as ownership is solely used to prevent unauthorized use of this batch
     * execution capability. This is particularly useful to safely interact
     * with contracts or addresses that might deem this contract eligible for
     * airdrops, thereby avoiding loss of funds.
     * @param _calls The calls to execute
     */
    function execCalls(
        Call[] calldata _calls
    )
        external
        onlyOwner
        returns (uint256 blockNumber, bytes[] memory returnData)
    {
        blockNumber = block.number;
        uint256 length = _calls.length;
        returnData = new bytes[](length);

        for (uint256 i = 0; i < length; ++i) {
            Call calldata calli = _calls[i];

            // check for existence of code at the target address
            if (calli.to.code.length == 0) {
                // when the call is to an EOA, the calldata must be empty.
                require(calli.data.length == 0, "Invalid call data");
            }

            (bool success, bytes memory data) = calli.to.call(calli.data);
            require(success, string(data));
            returnData[i] = data;
        }
    }

    /**
     * @dev Predict the deterministic address for a new core contract of type
     * `engineCoreContractType` and salt `salt`, deployed using the function
     * `createEngineContract`.
     * Reverts if `salt` is null, because the factory generates a pseudorandom
     * salt in that case.
     * @param engineCoreContractType Type of Engine Core contract.
     * @param salt Salt used to deterministically deploy the clone.
     */
    function predictDeterministicAddress(
        IEngineFactoryV0.EngineCoreType engineCoreContractType,
        bytes32 salt
    ) external view returns (address predicted) {
        // cannot predict if salt is null, because factory generates pseudorandom salt
        if (salt == bytes32(0)) {
            revert("null salt = pseudorandom addr");
        }
        return
            Clones.predictDeterministicAddress({
                implementation: engineCoreContractType ==
                    IEngineFactoryV0.EngineCoreType.Engine
                    ? engineImplementation
                    : engineFlexImplementation,
                salt: salt
            });
    }

    /**
     * @notice helper function to generate a pseudorandom salt
     * @return result pseudorandom salt
     */
    function _generatePseudorandomSalt() internal returns (bytes32 result) {
        // get and increment nonce to prevent same-block collisions
        uint256 nonce = _pseudorandomSaltNonce++;
        return
            keccak256(
                abi.encodePacked(
                    nonce,
                    block.timestamp,
                    block.number,
                    address(this)
                )
            );
    }

    /**
     * @notice helper function to convert a string to a bytes32.
     * Caution: This function only works properly for short strings.
     * @param source string to convert
     * @return result bytes32 representation of the string
     */
    function _stringToBytes32(
        string memory source
    ) internal pure returns (bytes32 result) {
        bytes memory tempString = bytes(source);
        if (tempString.length == 0) {
            return 0x0;
        }

        assembly {
            result := mload(add(source, 32))
        }
    }

    /**
     * @notice helper function to validate that an address is non-zero.
     * Reverts if the address is zero.
     * @param address_ address to validate
     */
    function _onlyNonZeroAddress(address address_) internal pure {
        require(address_ != address(0), "Must input non-zero address");
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)

pragma solidity ^0.8.0;

import "../utils/Context.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

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

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _transferOwnership(_msgSender());
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

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

pragma solidity ^0.8.0;

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

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

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

pragma solidity ^0.8.0;

import "./IERC165.sol";

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

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

pragma solidity ^0.8.0;

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

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)

pragma solidity ^0.8.20;

import {Context} from "../utils/Context.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * The initial owner is set to the address provided by the deployer. This can
 * later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    /**
     * @dev The caller account is not authorized to perform an operation.
     */
    error OwnableUnauthorizedAccount(address account);

    /**
     * @dev The owner is not a valid owner account. (eg. `address(0)`)
     */
    error OwnableInvalidOwner(address owner);

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

    /**
     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
     */
    constructor(address initialOwner) {
        if (initialOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(initialOwner);
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        if (owner() != _msgSender()) {
            revert OwnableUnauthorizedAccount(_msgSender());
        }
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby disabling any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        if (newOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/Clones.sol)

pragma solidity ^0.8.20;

/**
 * @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for
 * deploying minimal proxy contracts, also known as "clones".
 *
 * > To simply and cheaply clone contract functionality in an immutable way, this standard specifies
 * > a minimal bytecode implementation that delegates all calls to a known, fixed address.
 *
 * The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2`
 * (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the
 * deterministic method.
 */
library Clones {
    /**
     * @dev A clone instance deployment failed.
     */
    error ERC1167FailedCreateClone();

    /**
     * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
     *
     * This function uses the create opcode, which should never revert.
     */
    function clone(address implementation) internal returns (address instance) {
        /// @solidity memory-safe-assembly
        assembly {
            // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes
            // of the `implementation` address with the bytecode before the address.
            mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))
            // Packs the remaining 17 bytes of `implementation` with the bytecode after the address.
            mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))
            instance := create(0, 0x09, 0x37)
        }
        if (instance == address(0)) {
            revert ERC1167FailedCreateClone();
        }
    }

    /**
     * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
     *
     * This function uses the create2 opcode and a `salt` to deterministically deploy
     * the clone. Using the same `implementation` and `salt` multiple time will revert, since
     * the clones cannot be deployed twice at the same address.
     */
    function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) {
        /// @solidity memory-safe-assembly
        assembly {
            // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes
            // of the `implementation` address with the bytecode before the address.
            mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))
            // Packs the remaining 17 bytes of `implementation` with the bytecode after the address.
            mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))
            instance := create2(0, 0x09, 0x37, salt)
        }
        if (instance == address(0)) {
            revert ERC1167FailedCreateClone();
        }
    }

    /**
     * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
     */
    function predictDeterministicAddress(
        address implementation,
        bytes32 salt,
        address deployer
    ) internal pure returns (address predicted) {
        /// @solidity memory-safe-assembly
        assembly {
            let ptr := mload(0x40)
            mstore(add(ptr, 0x38), deployer)
            mstore(add(ptr, 0x24), 0x5af43d82803e903d91602b57fd5bf3ff)
            mstore(add(ptr, 0x14), implementation)
            mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73)
            mstore(add(ptr, 0x58), salt)
            mstore(add(ptr, 0x78), keccak256(add(ptr, 0x0c), 0x37))
            predicted := keccak256(add(ptr, 0x43), 0x55)
        }
    }

    /**
     * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
     */
    function predictDeterministicAddress(
        address implementation,
        bytes32 salt
    ) internal view returns (address predicted) {
        return predictDeterministicAddress(implementation, salt, address(this));
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 *
 * ==== Security Considerations
 *
 * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
 * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
 * considered as an intention to spend the allowance in any specific way. The second is that because permits have
 * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
 * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
 * generally recommended is:
 *
 * ```solidity
 * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
 *     try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
 *     doThing(..., value);
 * }
 *
 * function doThing(..., uint256 value) public {
 *     token.safeTransferFrom(msg.sender, address(this), value);
 *     ...
 * }
 * ```
 *
 * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
 * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
 * {SafeERC20-safeTransferFrom}).
 *
 * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
 * contracts should have entry points that don't rely on permit.
 */
interface IERC20Permit {
    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     *
     * CAUTION: See Security Considerations above.
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @dev Returns the current nonce for `owner`. This value must be
     * included whenever a signature is generated for {permit}.
     *
     * Every successful call to {permit} increases ``owner``'s nonce by one. This
     * prevents a signature from being used multiple times.
     */
    function nonces(address owner) external view returns (uint256);

    /**
     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}

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

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @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 value of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

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

    /**
     * @dev Moves a `value` amount of 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 value) 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 a `value` amount of tokens 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 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the
     * allowance mechanism. `value` 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 value) external returns (bool);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.20;

import {IERC20} from "../IERC20.sol";
import {IERC20Permit} from "../extensions/IERC20Permit.sol";
import {Address} from "../../../utils/Address.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    using Address for address;

    /**
     * @dev An operation with an ERC20 token failed.
     */
    error SafeERC20FailedOperation(address token);

    /**
     * @dev Indicates a failed `decreaseAllowance` request.
     */
    error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);

    /**
     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
    }

    /**
     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
     */
    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
    }

    /**
     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 oldAllowance = token.allowance(address(this), spender);
        forceApprove(token, spender, oldAllowance + value);
    }

    /**
     * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
     * value, non-reverting calls are assumed to be successful.
     */
    function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
        unchecked {
            uint256 currentAllowance = token.allowance(address(this), spender);
            if (currentAllowance < requestedDecrease) {
                revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
            }
            forceApprove(token, spender, currentAllowance - requestedDecrease);
        }
    }

    /**
     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
     * to be set to zero before setting it to a non-zero value, such as USDT.
     */
    function forceApprove(IERC20 token, address spender, uint256 value) internal {
        bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));

        if (!_callOptionalReturnBool(token, approvalCall)) {
            _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
            _callOptionalReturn(token, approvalCall);
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data);
        if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
     */
    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
        // and not revert is the subcall reverts.

        (bool success, bytes memory returndata) = address(token).call(data);
        return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;
    }
}

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

pragma solidity ^0.8.20;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev The ETH balance of the account is not enough to perform the operation.
     */
    error AddressInsufficientBalance(address account);

    /**
     * @dev There's no code at `target` (it is not a contract).
     */
    error AddressEmptyCode(address target);

    /**
     * @dev A call to an address target failed. The target may have reverted.
     */
    error FailedInnerCall();

    /**
     * @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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        if (address(this).balance < amount) {
            revert AddressInsufficientBalance(address(this));
        }

        (bool success, ) = recipient.call{value: amount}("");
        if (!success) {
            revert FailedInnerCall();
        }
    }

    /**
     * @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 or custom error, it is bubbled
     * up by this function (like regular Solidity function calls). However, if
     * the call reverted with no returned reason, this function reverts with a
     * {FailedInnerCall} error.
     *
     * 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.
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0);
    }

    /**
     * @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`.
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        if (address(this).balance < value) {
            revert AddressInsufficientBalance(address(this));
        }
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

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

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

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
     * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
     * unsuccessful call.
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata
    ) internal view returns (bytes memory) {
        if (!success) {
            _revert(returndata);
        } else {
            // only check if target is a contract if the call was successful and the return data is empty
            // otherwise we already know that it was a contract
            if (returndata.length == 0 && target.code.length == 0) {
                revert AddressEmptyCode(target);
            }
            return returndata;
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
     * revert reason or with a default {FailedInnerCall} error.
     */
    function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
        if (!success) {
            _revert(returndata);
        } else {
            return returndata;
        }
    }

    /**
     * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
     */
    function _revert(bytes memory returndata) 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 FailedInnerCall();
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity ^0.8.20;

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

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

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

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Create2.sol)

pragma solidity ^0.8.20;

/**
 * @dev Helper to make usage of the `CREATE2` EVM opcode easier and safer.
 * `CREATE2` can be used to compute in advance the address where a smart
 * contract will be deployed, which allows for interesting new mechanisms known
 * as 'counterfactual interactions'.
 *
 * See the https://eips.ethereum.org/EIPS/eip-1014#motivation[EIP] for more
 * information.
 */
library Create2 {
    /**
     * @dev Not enough balance for performing a CREATE2 deploy.
     */
    error Create2InsufficientBalance(uint256 balance, uint256 needed);

    /**
     * @dev There's no code to deploy.
     */
    error Create2EmptyBytecode();

    /**
     * @dev The deployment failed.
     */
    error Create2FailedDeployment();

    /**
     * @dev Deploys a contract using `CREATE2`. The address where the contract
     * will be deployed can be known in advance via {computeAddress}.
     *
     * The bytecode for a contract can be obtained from Solidity with
     * `type(contractName).creationCode`.
     *
     * Requirements:
     *
     * - `bytecode` must not be empty.
     * - `salt` must have not been used for `bytecode` already.
     * - the factory must have a balance of at least `amount`.
     * - if `amount` is non-zero, `bytecode` must have a `payable` constructor.
     */
    function deploy(uint256 amount, bytes32 salt, bytes memory bytecode) internal returns (address addr) {
        if (address(this).balance < amount) {
            revert Create2InsufficientBalance(address(this).balance, amount);
        }
        if (bytecode.length == 0) {
            revert Create2EmptyBytecode();
        }
        /// @solidity memory-safe-assembly
        assembly {
            addr := create2(amount, add(bytecode, 0x20), mload(bytecode), salt)
        }
        if (addr == address(0)) {
            revert Create2FailedDeployment();
        }
    }

    /**
     * @dev Returns the address where a contract will be stored if deployed via {deploy}. Any change in the
     * `bytecodeHash` or `salt` will result in a new destination address.
     */
    function computeAddress(bytes32 salt, bytes32 bytecodeHash) internal view returns (address) {
        return computeAddress(salt, bytecodeHash, address(this));
    }

    /**
     * @dev Returns the address where a contract will be stored if deployed via {deploy} from a contract located at
     * `deployer`. If `deployer` is this contract's address, returns the same value as {computeAddress}.
     */
    function computeAddress(bytes32 salt, bytes32 bytecodeHash, address deployer) internal pure returns (address addr) {
        /// @solidity memory-safe-assembly
        assembly {
            let ptr := mload(0x40) // Get free memory pointer

            // |                   | ↓ ptr ...  ↓ ptr + 0x0B (start) ...  ↓ ptr + 0x20 ...  ↓ ptr + 0x40 ...   |
            // |-------------------|---------------------------------------------------------------------------|
            // | bytecodeHash      |                                                        CCCCCCCCCCCCC...CC |
            // | salt              |                                      BBBBBBBBBBBBB...BB                   |
            // | deployer          | 000000...0000AAAAAAAAAAAAAAAAAAA...AA                                     |
            // | 0xFF              |            FF                                                             |
            // |-------------------|---------------------------------------------------------------------------|
            // | memory            | 000000...00FFAAAAAAAAAAAAAAAAAAA...AABBBBBBBBBBBBB...BBCCCCCCCCCCCCC...CC |
            // | keccak(start, 85) |            ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ |

            mstore(add(ptr, 0x40), bytecodeHash)
            mstore(add(ptr, 0x20), salt)
            mstore(ptr, deployer) // Right-aligned with 12 preceding garbage bytes
            let start := add(ptr, 0x0b) // The hashed data starts at the final garbage byte which we will set to 0xff
            mstore8(start, 0xff)
            addr := keccak256(start, 85)
        }
    }
}

// SPDX-License-Identifier: MIT

pragma solidity 0.8.22;

import "./interfaces/v0.8.x/IAdminACLV0.sol";
import {IAdminACLV0_Extended} from "./interfaces/v0.8.x/IAdminACLV0_Extended.sol";
import "@openzeppelin-4.7/contracts/access/Ownable.sol";
import "@openzeppelin-4.7/contracts/utils/introspection/ERC165.sol";

/**
 * @title Admin ACL contract, V0.
 * @author Art Blocks Inc.
 * @notice Privileged Roles and Ownership:
 * This contract has a single superAdmin that passes all ACL checks. All checks
 * for any other address will return false.
 * The superAdmin can be changed by the current superAdmin.
 * Care must be taken to ensure that the admin ACL contract is secure behind a
 * multi-sig or other secure access control mechanism.
 */
contract AdminACLV0 is IAdminACLV0, IAdminACLV0_Extended, ERC165 {
    string public AdminACLType = "AdminACLV0";

    /// superAdmin is the only address that passes any and all ACL checks
    address public superAdmin;

    constructor() {
        superAdmin = msg.sender;
    }

    /**
     * @notice Allows superAdmin change the superAdmin address.
     * @param _newSuperAdmin The new superAdmin address.
     * @param _genArt721CoreAddressesToUpdate Array of genArt721Core
     * addresses to update to the new superAdmin, for indexing purposes only.
     * @dev this function is gated to only superAdmin address.
     */
    function changeSuperAdmin(
        address _newSuperAdmin,
        address[] calldata _genArt721CoreAddressesToUpdate
    ) external {
        require(msg.sender == superAdmin, "Only superAdmin");
        address previousSuperAdmin = superAdmin;
        superAdmin = _newSuperAdmin;
        emit SuperAdminTransferred(
            previousSuperAdmin,
            _newSuperAdmin,
            _genArt721CoreAddressesToUpdate
        );
    }

    /**
     * Calls transferOwnership on other contract from this contract.
     * This is useful for updating to a new AdminACL contract.
     * @dev this function is gated to only superAdmin address.
     * @dev This implementation requires that the new AdminACL contract
     * broadcasts support of IAdminACLV0 via ERC165 interface detection.
     */
    function transferOwnershipOn(
        address _contract,
        address _newAdminACL
    ) external {
        require(msg.sender == superAdmin, "Only superAdmin");
        // ensure new AdminACL contract supports IAdminACLV0
        require(
            ERC165(_newAdminACL).supportsInterface(
                type(IAdminACLV0).interfaceId
            ),
            "AdminACLV0: new admin ACL does not support IAdminACLV0"
        );
        Ownable(_contract).transferOwnership(_newAdminACL);
    }

    /**
     * @notice Calls renounceOwnership on other contract from this contract.
     * @dev this function is gated to only superAdmin address.
     */
    function renounceOwnershipOn(address _contract) external {
        require(msg.sender == superAdmin, "Only superAdmin");
        Ownable(_contract).renounceOwnership();
    }

    /**
     * @notice Checks if sender `_sender` is allowed to call function with selector
     * `_selector` on contract `_contract`. Returns true if sender is superAdmin.
     */
    function allowed(
        address _sender,
        address /*_contract*/,
        bytes4 /*_selector*/
    ) external view returns (bool) {
        return superAdmin == _sender;
    }

    /**
     * @inheritdoc ERC165
     */
    function supportsInterface(
        bytes4 interfaceId
    ) public view virtual override(ERC165) returns (bool) {
        return
            interfaceId == type(IAdminACLV0).interfaceId ||
            // @dev IAdminACLV0_Extended added after original deployments, so do not rely on it
            // being present in all AdminACLV0 contracts.
            interfaceId == type(IAdminACLV0_Extended).interfaceId ||
            super.supportsInterface(interfaceId);
    }
}

// SPDX-License-Identifier: LGPL-3.0-only
// Created By: Art Blocks Inc.

pragma solidity ^0.8.0;

import "./IAdminACLV0.sol";

interface IAdminACLV0_Extended is IAdminACLV0 {
    /**
     * @notice Allows superAdmin change the superAdmin address.
     * @param _newSuperAdmin The new superAdmin address.
     * @param _genArt721CoreAddressesToUpdate Array of genArt721Core
     * addresses to update to the new superAdmin, for indexing purposes only.
     * @dev this function is gated to only superAdmin address.
     */
    function changeSuperAdmin(
        address _newSuperAdmin,
        address[] calldata _genArt721CoreAddressesToUpdate
    ) external;
}

// SPDX-License-Identifier: LGPL-3.0-only
// Created By: Art Blocks Inc.

pragma solidity ^0.8.0;

interface IAdminACLV0 {
    /**
     * @notice Token ID `_tokenId` minted to `_to`.
     * @param previousSuperAdmin The previous superAdmin address.
     * @param newSuperAdmin The new superAdmin address.
     * @param genArt721CoreAddressesToUpdate Array of genArt721Core
     * addresses to update to the new superAdmin, for indexing purposes only.
     */
    event SuperAdminTransferred(
        address indexed previousSuperAdmin,
        address indexed newSuperAdmin,
        address[] genArt721CoreAddressesToUpdate
    );

    /// Type of the Admin ACL contract, e.g. "AdminACLV0"
    function AdminACLType() external view returns (string memory);

    /// super admin address
    function superAdmin() external view returns (address);

    /**
     * @notice Calls transferOwnership on other contract from this contract.
     * This is useful for updating to a new AdminACL contract.
     * @dev this function should be gated to only superAdmin-like addresses.
     */
    function transferOwnershipOn(
        address _contract,
        address _newAdminACL
    ) external;

    /**
     * @notice Calls renounceOwnership on other contract from this contract.
     * @dev this function should be gated to only superAdmin-like addresses.
     */
    function renounceOwnershipOn(address _contract) external;

    /**
     * @notice Checks if sender `_sender` is allowed to call function with selector
     * `_selector` on contract `_contract`.
     */
    function allowed(
        address _sender,
        address _contract,
        bytes4 _selector
    ) external returns (bool);
}

// SPDX-License-Identifier: LGPL-3.0-only
// Created By: Art Blocks Inc.
pragma solidity ^0.8.0;

import "./IEngineRegistryV0.sol";

interface ICoreRegistryV1 is IEngineRegistryV0 {
    function registerContracts(
        address[] calldata contractAddresses,
        bytes32[] calldata coreVersions,
        bytes32[] calldata coreTypes
    ) external;

    function unregisterContracts(address[] calldata contractAddresses) external;

    function getNumRegisteredContracts() external view returns (uint256);

    function getRegisteredContractAt(
        uint256 index
    ) external view returns (address);

    function isRegisteredContract(
        address contractAddress
    ) external view returns (bool isRegistered);
}

// SPDX-License-Identifier: LGPL-3.0-only
// Creatd By: Art Blocks Inc.

pragma solidity ^0.8.0;

import {EngineConfiguration} from "./IGenArt721CoreContractV3_Engine.sol";

interface IEngineFactoryV0 {
    /// @notice Engine Core type
    enum EngineCoreType {
        Engine, // GenArt721CoreV3_Engine Contract
        EngineFlex // GenArt721CoreV3_Engine_Flex Contract
    }
    /**
     * @notice This contract was deployed.
     * @param engineImplementation address with the implementation of the Engine contract
     * @param engineFlexImplementation address with the implementation of the Engine Flex contract
     * @param type_ type of this contract
     */
    event Deployed(
        address indexed engineImplementation,
        address indexed engineFlexImplementation,
        bytes32 indexed type_
    );
    /**
     * @notice New Engine or Engine Flex contract was created.
     * @param engineContract address of the newly created Engine contract
     */
    event EngineContractCreated(address indexed engineContract);
    /**
     * @notice This contract was abandoned and no longer can be used to create
     * new Engine or Engine Flex contracts.
     */
    event Abandoned();

    /**
     * @notice Creates a new Engine or Engine Flex contract with the provided
     * `engineConfiguration`, depending on the `engineCoreContractType`.
     * @param engineCoreContractType Type of Engine Core contract.
     * @param engineConfiguration EngineConfiguration data to configure the
     * contract with.
     * @param adminACLContract Address of admin access control contract, to be
     * set as contract owner. A new contract will be deployed if address is null.
     * @param salt Salt used to deterministically deploy the clone.
     * @return engineContract The address of the newly created Engine or Engine Flex
     * contract. The address is also emitted in both the `EngineCreated` and
     * `EngineFlexCreated` events.
     */
    function createEngineContract(
        EngineCoreType engineCoreContractType,
        EngineConfiguration calldata engineConfiguration,
        address adminACLContract,
        bytes32 salt
    ) external returns (address engineContract);

    /**
     * @notice Drains the contract's balance to the `recipient`.
     * @param recipient The address to send funds to.
     * Only callable by the owner.
     */
    function drainETH(address payable recipient) external;

    /**
     * @notice Drains the contract's balance of an input ERC20 token to
     * the `recipient`.
     * @param ERC20TokenAddress The address of the ERC20 token to withdraw.
     * @param recipient The address to send ERC20 tokens to.
     * Only callable by the owner.
     */
    function drainERC20(address ERC20TokenAddress, address recipient) external;

    /**
     * @notice Calls transferOwnership on the core registry.
     * Useful for updating the owner of the core registry contract.
     * @param _owner address of the new owner
     */
    function transferCoreRegistryOwnership(address _owner) external;

    /**
     * @notice Registers multiple contracts with the core registry.
     * @param contractAddresses An array of contract addresses to register.
     * @param coreVersions An array of versions corresponding to the contract addresses.
     * @param coreTypes An array of types corresponding to the contract addresses.
     */
    function registerMultipleContracts(
        address[] calldata contractAddresses,
        bytes32[] calldata coreVersions,
        bytes32[] calldata coreTypes
    ) external;

    /**
     * @notice Unregisters multiple contracts from the core registry.
     * @param contractAddresses An array of contract addresses to unregister.
     */
    function unregisterMultipleContracts(
        address[] calldata contractAddresses
    ) external;

    /**
     * @notice The implementation contract that is cloned when creating new
     * Engine Core contracts.
     */
    function engineImplementation() external view returns (address);

    /**
     * @notice The implementation contract that is cloned when creating new
     * Engine Flex Core contracts.
     */
    function engineFlexImplementation() external view returns (address);

    /**
     * @notice Indicates whether the contract is abandoned.
     * Once abandoned, the contract can no longer be used to create new Engine
     * or Engine Flex contracts.
     * @return bool True if the contract is abandoned, false otherwise.
     */
    function isAbandoned() external view returns (bool);

    /**
     * @notice Indicates the type of the contract, e.g. `EngineFactoryV0`.
     * @return type_ The type of the contract.
     */
    function type_() external pure returns (bytes32);
}

// SPDX-License-Identifier: LGPL-3.0-only
// Created By: Art Blocks Inc.
pragma solidity ^0.8.0;

interface IEngineRegistryV0 {
    /// ADDRESS
    /**
     * @notice contract has been registered as a contract that is powered by the Art Blocks Engine.
     */
    event ContractRegistered(
        address indexed _contractAddress,
        bytes32 _coreVersion,
        bytes32 _coreType
    );

    /// ADDRESS
    /**
     * @notice contract has been unregistered as a contract that is powered by the Art Blocks Engine.
     */
    event ContractUnregistered(address indexed _contractAddress);

    /**
     * @notice Emits a `ContractRegistered` event with the provided information.
     * @dev this function should be gated to only deployer addresses.
     */
    function registerContract(
        address _contractAddress,
        bytes32 _coreVersion,
        bytes32 _coreType
    ) external;

    /**
     * @notice Emits a `ContractUnregistered` event with the provided information, validating that the provided
     *         address was indeed previously registered.
     * @dev this function should be gated to only deployer addresses.
     */
    function unregisterContract(address _contractAddress) external;
}

// SPDX-License-Identifier: LGPL-3.0-only
// Created By: Art Blocks Inc.

pragma solidity ^0.8.0;

import "./IAdminACLV0.sol";

/**
 * @title This interface is intended to house interface items that are common
 * across all GenArt721CoreContractV3 flagship and derivative implementations.
 * This interface extends the IManifold royalty interface in order to
 * add support the Royalty Registry by default.
 * @author Art Blocks Inc.
 */
interface IGenArt721CoreContractV3_Base {
    // This interface emits generic events that contain fields that indicate
    // which parameter has been updated. This is sufficient for application
    // state management, while also simplifying the contract and indexing code.
    // This was done as an alternative to having custom events that emit what
    // field-values have changed for each event, given that changed values can
    // be introspected by indexers due to the design of this smart contract
    // exposing these state changes via publicly viewable fields.

    /**
     * @notice Project's royalty splitter was updated to `_splitter`.
     * @dev New event in v3.2
     * @param projectId The project ID.
     * @param royaltySplitter The new splitter address to receive royalties.
     */
    event ProjectRoyaltySplitterUpdated(
        uint256 indexed projectId,
        address indexed royaltySplitter
    );

    // The following fields are used to indicate which contract-level parameter
    // has been updated in the `PlatformUpdated` event:
    // @dev only append to the end of this enum in the case of future updates
    enum PlatformUpdatedFields {
        FIELD_NEXT_PROJECT_ID, // 0
        FIELD_NEW_PROJECTS_FORBIDDEN, // 1
        FIELD_DEFAULT_BASE_URI, // 2
        FIELD_RANDOMIZER_ADDRESS, // 3
        FIELD_NEXT_CORE_CONTRACT, // 4
        FIELD_ARTBLOCKS_DEPENDENCY_REGISTRY_ADDRESS, // 5
        FIELD_ARTBLOCKS_ON_CHAIN_GENERATOR_ADDRESS, // 6
        FIELD_PROVIDER_SALES_ADDRESSES, // 7
        FIELD_PROVIDER_PRIMARY_SALES_PERCENTAGES, // 8
        FIELD_PROVIDER_SECONDARY_SALES_BPS, // 9
        FIELD_SPLIT_PROVIDER // 10
    }

    // The following fields are used to indicate which project-level parameter
    // has been updated in the `ProjectUpdated` event:
    // @dev only append to the end of this enum in the case of future updates
    enum ProjectUpdatedFields {
        FIELD_PROJECT_COMPLETED, // 0
        FIELD_PROJECT_ACTIVE, // 1
        FIELD_PROJECT_ARTIST_ADDRESS, // 2
        FIELD_PROJECT_PAUSED, // 3
        FIELD_PROJECT_CREATED, // 4
        FIELD_PROJECT_NAME, // 5
        FIELD_PROJECT_ARTIST_NAME, // 6
        FIELD_PROJECT_SECONDARY_MARKET_ROYALTY_PERCENTAGE, // 7
        FIELD_PROJECT_DESCRIPTION, // 8
        FIELD_PROJECT_WEBSITE, // 9
        FIELD_PROJECT_LICENSE, // 10
        FIELD_PROJECT_MAX_INVOCATIONS, // 11
        FIELD_PROJECT_SCRIPT, // 12
        FIELD_PROJECT_SCRIPT_TYPE, // 13
        FIELD_PROJECT_ASPECT_RATIO, // 14
        FIELD_PROJECT_BASE_URI, // 15
        FIELD_PROJECT_PROVIDER_SECONDARY_FINANCIALS // 16
    }

    /**
     * @notice Error codes for the GenArt721 contract. Used by the GenArt721Error
     * custom error.
     * @dev only append to the end of this enum in the case of future updates
     */
    enum ErrorCodes {
        OnlyNonZeroAddress, // 0
        OnlyNonEmptyString, // 1
        OnlyNonEmptyBytes, // 2
        TokenDoesNotExist, // 3
        ProjectDoesNotExist, // 4
        OnlyUnlockedProjects, // 5
        OnlyAdminACL, // 6
        OnlyArtist, // 7
        OnlyArtistOrAdminACL, // 8
        OnlyAdminACLOrRenouncedArtist, // 9
        OnlyMinterContract, // 10
        MaxInvocationsReached, // 11
        ProjectMustExistAndBeActive, // 12
        PurchasesPaused, // 13
        OnlyRandomizer, // 14
        TokenHashAlreadySet, // 15
        NoZeroHashSeed, // 16
        OverMaxSumOfPercentages, // 17
        IndexOutOfBounds, // 18
        OverMaxSumOfBPS, // 19
        MaxOf100Percent, // 20
        PrimaryPayeeIsZeroAddress, // 21
        SecondaryPayeeIsZeroAddress, // 22
        MustMatchArtistProposal, // 23
        NewProjectsForbidden, // 24
        NewProjectsAlreadyForbidden, // 25
        OnlyArtistOrAdminIfLocked, // 26
        OverMaxSecondaryRoyaltyPercentage, // 27
        OnlyMaxInvocationsDecrease, // 28
        OnlyGteInvocations, // 29
        ScriptIdOutOfRange, // 30
        NoScriptsToRemove, // 31
        ScriptTypeAndVersionFormat, // 32
        AspectRatioTooLong, // 33
        AspectRatioNoNumbers, // 34
        AspectRatioImproperFormat, // 35
        OnlyNullPlatformProvider, // 36
        ContractInitialized // 37
    }

    /**
     * @notice Emits an error code `_errorCode` in the GenArt721Error event.
     * @dev Emitting error codes instead of error strings saves significant
     * contract bytecode size, allowing for more contract functionality within
     * the 24KB contract size limit.
     * @param _errorCode The error code to emit. See ErrorCodes enum.
     */
    error GenArt721Error(ErrorCodes _errorCode);

    /**
     * @notice Token ID `_tokenId` minted to `_to`.
     */
    event Mint(address indexed _to, uint256 indexed _tokenId);

    /**
     * @notice currentMinter updated to `_currentMinter`.
     * @dev Implemented starting with V3 core
     */
    event MinterUpdated(address indexed _currentMinter);

    /**
     * @notice Platform updated on bytes32-encoded field `_field`.
     */
    event PlatformUpdated(bytes32 indexed _field);

    /**
     * @notice Project ID `_projectId` updated on bytes32-encoded field
     * `_update`.
     */
    event ProjectUpdated(uint256 indexed _projectId, bytes32 indexed _update);

    event ProposedArtistAddressesAndSplits(
        uint256 indexed _projectId,
        address _artistAddress,
        address _additionalPayeePrimarySales,
        uint256 _additionalPayeePrimarySalesPercentage,
        address _additionalPayeeSecondarySales,
        uint256 _additionalPayeeSecondarySalesPercentage
    );

    event AcceptedArtistAddressesAndSplits(uint256 indexed _projectId);

    // version and type of the core contract
    // coreVersion is a string of the form "0.x.y"
    function coreVersion() external view returns (string memory);

    // coreType is a string of the form "GenArt721CoreV3"
    function coreType() external view returns (string memory);

    // owner (pre-V3 was named admin) of contract
    // this is expected to be an Admin ACL contract for V3
    function owner() external view returns (address);

    // Admin ACL contract for V3, will be at the address owner()
    function adminACLContract() external returns (IAdminACLV0);

    // backwards-compatible (pre-V3) admin - equal to owner()
    function admin() external view returns (address);

    /**
     * Function determining if _sender is allowed to call function with
     * selector _selector on contract `_contract`. Intended to be used with
     * peripheral contracts such as minters, as well as internally by the
     * core contract itself.
     */
    function adminACLAllowed(
        address _sender,
        address _contract,
        bytes4 _selector
    ) external returns (bool);

    /// getter function of public variable
    function startingProjectId() external view returns (uint256);

    // getter function of public variable
    function nextProjectId() external view returns (uint256);

    // getter function of public mapping
    function tokenIdToProjectId(
        uint256 tokenId
    ) external view returns (uint256 projectId);

    // @dev this is not available in V0
    function isMintWhitelisted(address minter) external view returns (bool);

    function projectIdToArtistAddress(
        uint256 _projectId
    ) external view returns (address payable);

    function projectIdToSecondaryMarketRoyaltyPercentage(
        uint256 _projectId
    ) external view returns (uint256);

    function projectURIInfo(
        uint256 _projectId
    ) external view returns (string memory projectBaseURI);

    // @dev new function in V3
    function projectStateData(
        uint256 _projectId
    )
        external
        view
        returns (
            uint256 invocations,
            uint256 maxInvocations,
            bool active,
            bool paused,
            uint256 completedTimestamp,
            bool locked
        );

    function projectDetails(
        uint256 _projectId
    )
        external
        view
        returns (
            string memory projectName,
            string memory artist,
            string memory description,
            string memory website,
            string memory license
        );

    function projectScriptDetails(
        uint256 _projectId
    )
        external
        view
        returns (
            string memory scriptTypeAndVersion,
            string memory aspectRatio,
            uint256 scriptCount
        );

    function projectScriptByIndex(
        uint256 _projectId,
        uint256 _index
    ) external view returns (string memory);

    function tokenIdToHash(uint256 _tokenId) external view returns (bytes32);

    // function to set a token's hash (must be guarded)
    function setTokenHash_8PT(uint256 _tokenId, bytes32 _hash) external;

    // @dev gas-optimized signature in V3 for `mint`
    function mint_Ecf(
        address _to,
        uint256 _projectId,
        address _by
    ) external returns (uint256 tokenId);
}

// SPDX-License-Identifier: LGPL-3.0-only
// Created By: Art Blocks Inc.

pragma solidity ^0.8.0;

import "./IAdminACLV0.sol";
import "./IGenArt721CoreContractV3_Base.sol";
import "./ISplitProviderV0.sol";

/**
 * @notice Struct representing Engine contract configuration.
 * @param tokenName Name of token.
 * @param tokenSymbol Token symbol.
 * @param renderProviderAddress address to send render provider revenue to
 * @param randomizerContract Randomizer contract.
 * @param splitProviderAddress Address to use as royalty splitter provider for the contract.
 * @param minterFilterAddress Address of the Minter Filter to set as the Minter
 * on the contract.
 * @param startingProjectId The initial next project ID.
 * @param autoApproveArtistSplitProposals Whether or not to always
 * auto-approve proposed artist split updates.
 * @param nullPlatformProvider Enforce always setting zero platform provider fees and addresses.
 * @param allowArtistProjectActivation Allow artist to activate their own projects.
 * @dev _startingProjectId should be set to a value much, much less than
 * max(uint248), but an explicit input type of `uint248` is used as it is
 * safer to cast up to `uint256` than it is to cast down for the purposes
 * of setting `_nextProjectId`.
 */
struct EngineConfiguration {
    string tokenName;
    string tokenSymbol;
    address renderProviderAddress;
    address platformProviderAddress;
    address newSuperAdminAddress;
    address randomizerContract;
    address splitProviderAddress;
    address minterFilterAddress;
    uint248 startingProjectId;
    bool autoApproveArtistSplitProposals;
    bool nullPlatformProvider;
    bool allowArtistProjectActivation;
}

interface IGenArt721CoreContractV3_Engine is IGenArt721CoreContractV3_Base {
    // @dev new function in V3.2
    /**
     * @notice Initializes the contract with the provided `engineConfiguration`.
     * This function should be called atomically, immediately after deployment.
     * Only callable once. Validation on `engineConfiguration` is performed by caller.
     * @param engineConfiguration EngineConfiguration to configure the contract with.
     * @param adminACLContract_ Address of admin access control contract, to be
     * set as contract owner.
     * @param defaultBaseURIHost Base URI prefix to initialize default base URI with.
     */
    function initialize(
        EngineConfiguration calldata engineConfiguration,
        address adminACLContract_,
        string memory defaultBaseURIHost
    ) external;

    // @dev new function in V3
    function getPrimaryRevenueSplits(
        uint256 _projectId,
        uint256 _price
    )
        external
        view
        returns (
            uint256 renderProviderRevenue_,
            address payable renderProviderAddress_,
            uint256 platformProviderRevenue_,
            address payable platformProviderAddress_,
            uint256 artistRevenue_,
            address payable artistAddress_,
            uint256 additionalPayeePrimaryRevenue_,
            address payable additionalPayeePrimaryAddress_
        );

    // @dev The render provider primary sales payment address
    function renderProviderPrimarySalesAddress()
        external
        view
        returns (address payable);

    // @dev The platform provider primary sales payment address
    function platformProviderPrimarySalesAddress()
        external
        view
        returns (address payable);

    // @dev Percentage of primary sales allocated to the render provider
    function renderProviderPrimarySalesPercentage()
        external
        view
        returns (uint256);

    // @dev Percentage of primary sales allocated to the platform provider
    function platformProviderPrimarySalesPercentage()
        external
        view
        returns (uint256);

    /** @notice The default render provider payment address for all secondary sales royalty
     * revenues, for all new projects. Individual project payment info is defined
     * in each project's ProjectFinance struct.
     * @return The default render provider payment address for secondary sales royalties.
     */
    function defaultRenderProviderSecondarySalesAddress()
        external
        view
        returns (address payable);

    /** @notice The default platform provider payment address for all secondary sales royalty
     * revenues, for all new projects. Individual project payment info is defined
     * in each project's ProjectFinance struct.
     * @return The default platform provider payment address for secondary sales royalties.
     */
    function defaultPlatformProviderSecondarySalesAddress()
        external
        view
        returns (address payable);

    /** @notice The default render provider payment basis points for all secondary sales royalty
     * revenues, for all new projects. Individual project payment info is defined
     * in each project's ProjectFinance struct.
     * @return The default render provider payment basis points for secondary sales royalties.
     */
    function defaultRenderProviderSecondarySalesBPS()
        external
        view
        returns (uint256);

    /** @notice The default platform provider payment basis points for all secondary sales royalty
     * revenues, for all new projects. Individual project payment info is defined
     * in each project's ProjectFinance struct.
     * @return The default platform provider payment basis points for secondary sales royalties.
     */
    function defaultPlatformProviderSecondarySalesBPS()
        external
        view
        returns (uint256);

    /**
     * @notice The address of the current split provider being used by the contract.
     * @return The address of the current split provider.
     */
    function splitProvider() external view returns (ISplitProviderV0);
}

// SPDX-License-Identifier: LGPL-3.0-only
// Created By: Art Blocks Inc. to support the 0xSplits V2 integration
// Sourced from:
//  - https://github.com/0xSplits/splits-contracts-monorepo/blob/main/packages/splits-v2/src/libraries/SplitV2.sol
//  - https://github.com/0xSplits/splits-contracts-monorepo/blob/main/packages/splits-v2/src/splitters/SplitFactoryV2.sol

pragma solidity ^0.8.0;

interface ISplitFactoryV2 {
    /* -------------------------------------------------------------------------- */
    /*                                   STRUCTS                                  */
    /* -------------------------------------------------------------------------- */

    /**
     * @notice Split struct
     * @dev This struct is used to store the split information.
     * @dev There are no hard caps on the number of recipients/totalAllocation/allocation unit. Thus the chain and its
     * gas limits will dictate these hard caps. Please double check if the split you are creating can be distributed on
     * the chain.
     * @param recipients The recipients of the split.
     * @param allocations The allocations of the split.
     * @param totalAllocation The total allocation of the split.
     * @param distributionIncentive The incentive for distribution. Limits max incentive to 6.5%.
     */
    struct Split {
        address[] recipients;
        uint256[] allocations;
        uint256 totalAllocation;
        uint16 distributionIncentive;
    }

    /* -------------------------------------------------------------------------- */
    /*                                 FUNCTIONS                                  */
    /* -------------------------------------------------------------------------- */

    /**
     * @notice Create a new split with params and owner.
     * @param _splitParams Params to create split with.
     * @param _owner Owner of created split.
     * @param _creator Creator of created split.
     * @param _salt Salt for create2.
     * @return split Address of the created split.
     */
    function createSplitDeterministic(
        Split calldata _splitParams,
        address _owner,
        address _creator,
        bytes32 _salt
    ) external returns (address split);

    /**
     * @notice Predict the address of a new split and check if it is deployed.
     * @param _splitParams Params to create split with.
     * @param _owner Owner of created split.
     * @param _salt Salt for create2.
     */
    function isDeployed(
        Split calldata _splitParams,
        address _owner,
        bytes32 _salt
    ) external view returns (address split, bool exists);
}

// SPDX-License-Identifier: LGPL-3.0-only
// Creatd By: Art Blocks Inc.

pragma solidity ^0.8.0;

import {ISplitFactoryV2} from "./integration-refs/splits-0x-v2/ISplitFactoryV2.sol";

interface ISplitProviderV0 {
    /**
     * @notice SplitInputs struct defines the inputs for requested splitters.
     * It is defined in a way easily communicated from the Art Blocks GenArt721V3 contract,
     * to allow for easy integration and minimal additional bytecode in the GenArt721V3 contract.
     */
    struct SplitInputs {
        address platformProviderSecondarySalesAddress;
        uint16 platformProviderSecondarySalesBPS;
        address renderProviderSecondarySalesAddress;
        uint16 renderProviderSecondarySalesBPS;
        uint8 artistTotalRoyaltyPercentage;
        address artist;
        address additionalPayee;
        uint8 additionalPayeePercentage;
    }

    /**
     * @notice Emitted when a new splitter contract is created.
     * @param splitter address of the splitter contract
     */
    event SplitterCreated(address indexed splitter);

    /**
     * @notice Gets or creates an immutable splitter contract at a deterministic address.
     * Splits in the splitter contract are determined by the input split parameters,
     * so we can safely create the splitter contract at a deterministic address (or use
     * the existing splitter contract if it already exists at that address).
     * @dev Uses the 0xSplits v2 implementation to create a splitter contract
     * @param splitInputs The split input parameters.
     * @return splitter The newly created splitter contract address.
     */
    function getOrCreateSplitter(
        SplitInputs calldata splitInputs
    ) external returns (address);

    /**
     * @notice Indicates the type of the contract, e.g. `SplitProviderV0`.
     * @return type_ The type of the contract.
     */
    function type_() external pure returns (bytes32);
}

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

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"engineImplementation_","type":"address"},{"internalType":"address","name":"engineFlexImplementation_","type":"address"},{"internalType":"address","name":"coreRegistry_","type":"address"},{"internalType":"address","name":"owner_","type":"address"},{"internalType":"string","name":"defaultBaseURIHost_","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"Create2EmptyBytecode","type":"error"},{"inputs":[],"name":"Create2FailedDeployment","type":"error"},{"inputs":[{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"Create2InsufficientBalance","type":"error"},{"inputs":[],"name":"ERC1167FailedCreateClone","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"anonymous":false,"inputs":[],"name":"Abandoned","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"engineImplementation","type":"address"},{"indexed":true,"internalType":"address","name":"engineFlexImplementation","type":"address"},{"indexed":true,"internalType":"bytes32","name":"type_","type":"bytes32"}],"name":"Deployed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"engineContract","type":"address"}],"name":"EngineContractCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[],"name":"abandon","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"coreRegistry","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum IEngineFactoryV0.EngineCoreType","name":"engineCoreContractType","type":"uint8"},{"components":[{"internalType":"string","name":"tokenName","type":"string"},{"internalType":"string","name":"tokenSymbol","type":"string"},{"internalType":"address","name":"renderProviderAddress","type":"address"},{"internalType":"address","name":"platformProviderAddress","type":"address"},{"internalType":"address","name":"newSuperAdminAddress","type":"address"},{"internalType":"address","name":"randomizerContract","type":"address"},{"internalType":"address","name":"splitProviderAddress","type":"address"},{"internalType":"address","name":"minterFilterAddress","type":"address"},{"internalType":"uint248","name":"startingProjectId","type":"uint248"},{"internalType":"bool","name":"autoApproveArtistSplitProposals","type":"bool"},{"internalType":"bool","name":"nullPlatformProvider","type":"bool"},{"internalType":"bool","name":"allowArtistProjectActivation","type":"bool"}],"internalType":"struct EngineConfiguration","name":"engineConfiguration","type":"tuple"},{"internalType":"address","name":"adminACLContract","type":"address"},{"internalType":"bytes32","name":"salt","type":"bytes32"}],"name":"createEngineContract","outputs":[{"internalType":"address","name":"engineContract","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"defaultBaseURIHost","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"ERC20TokenAddress","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"name":"drainERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"recipient","type":"address"}],"name":"drainETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"engineCoreType","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"engineCoreVersion","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"engineFlexImplementation","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"engineImplementation","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"to","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct EngineFactoryV0.Call[]","name":"_calls","type":"tuple[]"}],"name":"execCalls","outputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"},{"internalType":"bytes[]","name":"returnData","type":"bytes[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"flexCoreType","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"flexCoreVersion","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isAbandoned","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum IEngineFactoryV0.EngineCoreType","name":"engineCoreContractType","type":"uint8"},{"internalType":"bytes32","name":"salt","type":"bytes32"}],"name":"predictDeterministicAddress","outputs":[{"internalType":"address","name":"predicted","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"contractAddresses","type":"address[]"},{"internalType":"bytes32[]","name":"coreVersions","type":"bytes32[]"},{"internalType":"bytes32[]","name":"coreTypes","type":"bytes32[]"}],"name":"registerMultipleContracts","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"transferCoreRegistryOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"type_","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"contractAddresses","type":"address[]"}],"name":"unregisterMultipleContracts","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

60e06040523480156200001157600080fd5b5060405162002f5038038062002f5083398101604081905262000034916200049d565b816001600160a01b0381166200006557604051631e4fbdf760e01b8152600060048201526024015b60405180910390fd5b62000070816200030d565b506200007c856200035d565b62000087846200035d565b62000092836200035d565b6200009d826200035d565b6001620000ab8282620005ba565b506001600160a01b03808616608081905285821660a05290841660c052604080516315c8b5b360e31b8152905163ae45ad98916004808201926000929091908290030181865afa15801562000104573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526200012e919081019062000686565b6002906200013d9082620005ba565b506080516001600160a01b0316634e1d64af6040518163ffffffff1660e01b8152600401600060405180830381865afa1580156200017f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052620001a9919081019062000686565b600390620001b89082620005ba565b5060a0516001600160a01b031663ae45ad986040518163ffffffff1660e01b8152600401600060405180830381865afa158015620001fa573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405262000224919081019062000686565b600490620002339082620005ba565b5060a0516001600160a01b0316634e1d64af6040518163ffffffff1660e01b8152600401600060405180830381865afa15801562000275573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526200029f919081019062000686565b600590620002ae9082620005ba565b506e0456e67696e65466163746f7279563608c1b846001600160a01b0316866001600160a01b03167f8a667a762c6b11836243ef58bb98850c7a4210d0226eb030bb2e03e3b7cc01e360405160405180910390a45050505050620006c6565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b038116620003b55760405162461bcd60e51b815260206004820152601b60248201527f4d75737420696e707574206e6f6e2d7a65726f2061646472657373000000000060448201526064016200005c565b50565b80516001600160a01b0381168114620003d057600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620003fd57600080fd5b81516001600160401b03808211156200041a576200041a620003d5565b604051601f8301601f19908116603f01168101908282118183101715620004455762000445620003d5565b81604052838152602092508660208588010111156200046357600080fd5b600091505b8382101562000487578582018301518183018401529082019062000468565b6000602085830101528094505050505092915050565b600080600080600060a08688031215620004b657600080fd5b620004c186620003b8565b9450620004d160208701620003b8565b9350620004e160408701620003b8565b9250620004f160608701620003b8565b60808701519092506001600160401b038111156200050e57600080fd5b6200051c88828901620003eb565b9150509295509295909350565b600181811c908216806200053e57607f821691505b6020821081036200055f57634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620005b5576000816000526020600020601f850160051c81016020861015620005905750805b601f850160051c820191505b81811015620005b1578281556001016200059c565b5050505b505050565b81516001600160401b03811115620005d657620005d6620003d5565b620005ee81620005e7845462000529565b8462000565565b602080601f8311600181146200062657600084156200060d5750858301515b600019600386901b1c1916600185901b178555620005b1565b600085815260208120601f198616915b82811015620006575788860151825594840194600190910190840162000636565b5085821015620006765787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000602082840312156200069957600080fd5b81516001600160401b03811115620006b057600080fd5b620006be84828501620003eb565b949350505050565b60805160a05160c0516128226200072e6000396000818161024101528181610530015281816105d701528181610b670152610fa20152600081816103d00152818161094f0152610ee501526000818161019e015281816109760152610f0c01526128226000f3fe608060405260043610620001205760003560e01c806310a2e110146200012d57806324377e9f146200015d57806328d6edbf146200018a5780634e93d7e514620001cf57806366a2d9b014620001f65780636bf3d05a146200022d578063715018a614620002635780637390bb50146200027b5780637e56402f14620002a05780638831883414620002c55780638da5cb5b14620002dd5780638e6cee5214620002f55780639f1dc8f8146200031a5780639fc087391462000332578063af8181ff1462000367578063b8967f25146200037f578063e02878fd1462000397578063f21e018c14620003bc578063f2fde38b14620003f2578063f470c9911462000417578063f4ebf9e4146200043c578063fd24b937146200045457600080fd5b366200012857005b600080fd5b3480156200013a57600080fd5b506200014562000479565b604051620001549190620015c2565b60405180910390f35b3480156200016a57600080fd5b50600654620001799060ff1681565b604051901515815260200162000154565b3480156200019757600080fd5b50620001c07f000000000000000000000000000000000000000000000000000000000000000081565b604051620001549190620015e4565b348015620001dc57600080fd5b50620001f4620001ee36600462001620565b6200050f565b005b3480156200020357600080fd5b506200021e6e0456e67696e65466163746f7279563608c1b81565b60405190815260200162000154565b3480156200023a57600080fd5b50620001c07f000000000000000000000000000000000000000000000000000000000000000081565b3480156200027057600080fd5b50620001f46200059e565b3480156200028857600080fd5b50620001f46200029a3660046200168e565b620005b6565b348015620002ad57600080fd5b50620001f4620002bf366004620016d3565b62000648565b348015620002d257600080fd5b50620001f4620006e5565b348015620002ea57600080fd5b50620001c062000756565b3480156200030257600080fd5b50620001c06200031436600462001721565b62000765565b3480156200032757600080fd5b506200014562000c52565b3480156200033f57600080fd5b5062000357620003513660046200168e565b62000c61565b6040516200015492919062001795565b3480156200037457600080fd5b506200014562000e53565b3480156200038c57600080fd5b506200014562000e62565b348015620003a457600080fd5b50620001c0620003b636600462001805565b62000e71565b348015620003c957600080fd5b50620001c07f000000000000000000000000000000000000000000000000000000000000000081565b348015620003ff57600080fd5b50620001f46200041136600462001620565b62000f3c565b3480156200042457600080fd5b50620001f46200043636600462001832565b62000f81565b3480156200044957600080fd5b50620001456200101f565b3480156200046157600080fd5b50620001f46200047336600462001620565b6200102e565b600480546200048890620018d5565b80601f0160208091040260200160405190810160405280929190818152602001828054620004b690620018d5565b8015620005075780601f10620004db5761010080835404028352916020019162000507565b820191906000526020600020905b815481529060010190602001808311620004e957829003601f168201915b505050505081565b62000519620010de565b60405163f2fde38b60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063f2fde38b9062000567908490600401620015e4565b600060405180830381600087803b1580156200058257600080fd5b505af115801562000597573d6000803e3d6000fd5b5050505050565b620005a8620010de565b620005b4600062001115565b565b620005c0620010de565b604051631cdd23b160e21b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906373748ec4906200061090859085906004016200195e565b600060405180830381600087803b1580156200062b57600080fd5b505af115801562000640573d6000803e3d6000fd5b505050505050565b62000652620010de565b6040516370a0823160e01b815282906000906001600160a01b038316906370a082319062000685903090600401620015e4565b602060405180830381865afa158015620006a3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620006c991906200197c565b90508015620006df57620006df82848362001165565b50505050565b620006ef620010de565b60065460ff16156200071e5760405162461bcd60e51b8152600401620007159062001996565b60405180910390fd5b6006805460ff191660011790556040517ffb03bbbb81551103a80dda8d3bda55d93637ca4a96390de3719644774bdf1e9890600090a1565b6000546001600160a01b031690565b600062000771620010de565b60065460ff1615620007975760405162461bcd60e51b8152600401620007159062001996565b620007b3620007ad606086016040870162001620565b620011b9565b620007c9620007ad60c0860160a0870162001620565b81620007dc57620007d96200120f565b91505b6001600160a01b038316620008c95762000801620007ad60a086016080870162001620565b6200083b6000620008116200120f565b604051620008226020820162001560565b601f1982820381018352601f9091011660405262001274565b6040805160008152602081019091529093506001600160a01b03841663377a7d1a6200086e60a088016080890162001620565b836040518363ffffffff1660e01b81526004016200088e929190620019da565b600060405180830381600087803b158015620008a957600080fd5b505af1158015620008be573d6000803e3d6000fd5b50505050506200092f565b6000620008dd60a086016080870162001620565b6001600160a01b0316146200092f5760405162461bcd60e51b815260206004820152601760248201527641646d696e41434c20616c72656164792065786973747360481b604482015260640162000715565b60008086600181111562000947576200094762001a38565b1462000974577f000000000000000000000000000000000000000000000000000000000000000062000996565b7f00000000000000000000000000000000000000000000000000000000000000005b9050620009a48184620012ff565b604051630dcdda2360e21b81529092506001600160a01b03831690633737688c90620009da908890889060019060040162001b9f565b600060405180830381600087803b158015620009f557600080fd5b505af115801562000a0a573d6000803e3d6000fd5b506000925082915081905088600181111562000a2a5762000a2a62001a38565b1462000a3a576004600562000a3f565b600260035b805462000a4c90620018d5565b80601f016020809104026020016040519081016040528092919081815260200182805462000a7a90620018d5565b801562000acb5780601f1062000a9f5761010080835404028352916020019162000acb565b820191906000526020600020905b81548152906001019060200180831162000aad57829003601f168201915b50505050509150805462000adf90620018d5565b80601f016020809104026020016040519081016040528092919081815260200182805462000b0d90620018d5565b801562000b5e5780601f1062000b325761010080835404028352916020019162000b5e565b820191906000526020600020905b81548152906001019060200180831162000b4057829003601f168201915b505050505091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663f889b3ed8562000ba0846200136e565b62000bab866200136e565b6040516001600160e01b031960e086901b1681526001600160a01b03909316600484015260248301919091526044820152606401600060405180830381600087803b15801562000bfa57600080fd5b505af115801562000c0f573d6000803e3d6000fd5b50506040516001600160a01b03871692507f72dba3aac69e7eadf1383243bbb649ff575d0d530bfecf3d33ef4a0cc0a77b8d9150600090a2505050949350505050565b600380546200048890620018d5565b6000606062000c6f620010de565b43915082806001600160401b0381111562000c8e5762000c8e620019c4565b60405190808252806020026020018201604052801562000cc357816020015b606081526020019060019003908162000cad5790505b50915060005b8181101562000e4a573686868381811062000ce85762000ce862001d5f565b905060200281019062000cfc919062001d75565b905062000d0d602082018262001620565b6001600160a01b03163b60000362000d735762000d2e602082018262001d96565b15905062000d735760405162461bcd60e51b8152602060048201526011602482015270496e76616c69642063616c6c206461746160781b604482015260640162000715565b60008062000d85602084018462001620565b6001600160a01b031662000d9d602085018562001d96565b60405162000dad92919062001ddf565b6000604051808303816000865af19150503d806000811462000dec576040519150601f19603f3d011682016040523d82523d6000602084013e62000df1565b606091505b509150915081819062000e195760405162461bcd60e51b8152600401620007159190620015c2565b508086858151811062000e305762000e3062001d5f565b602002602001018190525050505080600101905062000cc9565b50509250929050565b600180546200048890620018d5565b600580546200048890620018d5565b60008162000ec25760405162461bcd60e51b815260206004820152601d60248201527f6e756c6c2073616c74203d2070736575646f72616e646f6d2061646472000000604482015260640162000715565b62000f33600084600181111562000edd5762000edd62001a38565b1462000f0a577f000000000000000000000000000000000000000000000000000000000000000062000f2c565b7f00000000000000000000000000000000000000000000000000000000000000005b836200138e565b90505b92915050565b62000f46620010de565b6001600160a01b03811662000f73576000604051631e4fbdf760e01b8152600401620007159190620015e4565b62000f7e8162001115565b50565b62000f8b620010de565b60405163b3cdf53760e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063b3cdf5379062000fe39089908990899089908990899060040162001e22565b600060405180830381600087803b15801562000ffe57600080fd5b505af115801562001013573d6000803e3d6000fd5b50505050505050505050565b600280546200048890620018d5565b62001038620010de565b478015620010da576000826001600160a01b03168260405160006040518083038185875af1925050503d80600081146200108f576040519150601f19603f3d011682016040523d82523d6000602084013e62001094565b606091505b5050905080620010d85760405162461bcd60e51b815260206004820152600e60248201526d14185e5b595b9d0819985a5b195960921b604482015260640162000715565b505b5050565b33620010e962000756565b6001600160a01b031614620005b4573360405163118cdaa760e01b8152600401620007159190620015e4565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052620010d8908490620013ef565b6001600160a01b03811662000f7e5760405162461bcd60e51b815260206004820152601b60248201527a4d75737420696e707574206e6f6e2d7a65726f206164647265737360281b604482015260640162000715565b6007805460009182919082620012258362001e71565b909155506040805160208082019390935242818301524360608083019190915230901b6001600160601b0319166080820152815180820360740181526094909101909152805191012092915050565b600083471015620012a25760405163392efb2b60e21b81524760048201526024810185905260440162000715565b8151600003620012c557604051631328927760e21b815260040160405180910390fd5b8282516020840186f590506001600160a01b038116620012f857604051633a0ba96160e11b815260040160405180910390fd5b9392505050565b6000763d602d80600a3d3981f3363d3d373d3d3d363d730000008360601b60e81c176000526e5af43d82803e903d91602b57fd5bf38360781b1760205281603760096000f590506001600160a01b03811662000f36576040516330be1a3d60e21b815260040160405180910390fd5b805160009082908203620013855750600092915050565b50506020015190565b6040513060388201526f5af43d82803e903d91602b57fd5bf3ff602482015260148101839052733d602d80600a3d3981f3363d3d373d3d3d363d738152605881018290526037600c8201206078820152605560439091012060009062000f33565b6000620014066001600160a01b0384168362001451565b905080516000141580156200142e5750808060200190518101906200142c919062001e99565b155b15620010d85782604051635274afe760e01b8152600401620007159190620015e4565b606062000f338383600084600080856001600160a01b031684866040516200147a919062001eb9565b60006040518083038185875af1925050503d8060008114620014b9576040519150601f19603f3d011682016040523d82523d6000602084013e620014be565b606091505b5091509150620014d0868383620014da565b9695505050505050565b606082620014f357620014ed8262001536565b620012f8565b81511580156200150b57506001600160a01b0384163b155b156200152e5783604051639996b31560e01b8152600401620007159190620015e4565b5080620012f8565b805115620015475780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b61091f8062001ece83390190565b60005b838110156200158b57818101518382015260200162001571565b50506000910152565b60008151808452620015ae8160208601602086016200156e565b601f01601f19169290920160200192915050565b60208152600062000f33602083018462001594565b6001600160a01b03169052565b6001600160a01b0391909116815260200190565b6001600160a01b038116811462000f7e57600080fd5b80356200161b81620015f8565b919050565b6000602082840312156200163357600080fd5b8135620012f881620015f8565b60008083601f8401126200165357600080fd5b5081356001600160401b038111156200166b57600080fd5b6020830191508360208260051b85010111156200168757600080fd5b9250929050565b60008060208385031215620016a257600080fd5b82356001600160401b03811115620016b957600080fd5b620016c78582860162001640565b90969095509350505050565b60008060408385031215620016e757600080fd5b8235620016f481620015f8565b915060208301356200170681620015f8565b809150509250929050565b8035600281106200161b57600080fd5b600080600080608085870312156200173857600080fd5b620017438562001711565b935060208501356001600160401b038111156200175f57600080fd5b850161018081880312156200177357600080fd5b925060408501356200178581620015f8565b9396929550929360600135925050565b60006040820184835260206040602085015281855180845260608601915060608160051b87010193506020870160005b82811015620017f757605f19888703018452620017e486835162001594565b95509284019290840190600101620017c5565b509398975050505050505050565b600080604083850312156200181957600080fd5b620018248362001711565b946020939093013593505050565b600080600080600080606087890312156200184c57600080fd5b86356001600160401b03808211156200186457600080fd5b620018728a838b0162001640565b909850965060208901359150808211156200188c57600080fd5b6200189a8a838b0162001640565b90965094506040890135915080821115620018b457600080fd5b50620018c389828a0162001640565b979a9699509497509295939492505050565b600181811c90821680620018ea57607f821691505b6020821081036200190b57634e487b7160e01b600052602260045260246000fd5b50919050565b8183526000602080850194508260005b85811015620019535781356200193781620015f8565b6001600160a01b03168752958201959082019060010162001921565b509495945050505050565b6020815260006200197460208301848662001911565b949350505050565b6000602082840312156200198f57600080fd5b5051919050565b602080825260149082015273199858dd1bdc9e481a5cc81858985b991bdb995960621b604082015260600190565b634e487b7160e01b600052604160045260246000fd5b6001600160a01b038381168252604060208084018290528451918401829052600092858201929091906060860190855b8181101562001a2a57855185168352948301949183019160010162001a0a565b509098975050505050505050565b634e487b7160e01b600052602160045260246000fd5b6000808335601e1984360301811262001a6657600080fd5b83016020810192503590506001600160401b0381111562001a8657600080fd5b8036038213156200168757600080fd5b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b80356001600160f81b03811681146200161b57600080fd5b801515811462000f7e57600080fd5b80356200161b8162001ad7565b8054600090600181811c908083168062001b0e57607f831692505b6020808410820362001b3057634e487b7160e01b600052602260045260246000fd5b8388526020880182801562001b4e576001811462001b655762001b92565b60ff198716825285151560051b8201975062001b92565b60008981526020902060005b8781101562001b8c5781548482015290860190840162001b71565b83019850505b5050505050505092915050565b60608152600062001bb1858662001a4e565b61018080606086015262001bcb6101e08601838562001a96565b925062001bdc602089018962001a4e565b868503605f19016080880152925062001bf784848362001a96565b93505062001c08604089016200160e565b915062001c1960a0860183620015d7565b62001c27606089016200160e565b915062001c3860c0860183620015d7565b62001c46608089016200160e565b915062001c5760e0860183620015d7565b62001c6560a089016200160e565b915061010062001c7881870184620015d7565b62001c8660c08a016200160e565b925061012062001c9981880185620015d7565b62001ca760e08b016200160e565b935061014062001cba81890186620015d7565b62001cc7838c0162001abf565b9450610160925062001ce3838901866001600160f81b03169052565b62001cf0828c0162001ae6565b80151589860152945062001d06818c0162001ae6565b9450505062001d1a6101a087018415159052565b62001d27818a0162001ae6565b9250505062001d3b6101c085018215159052565b5062001d4b6020840186620015d7565b8281036040840152620014d0818562001af3565b634e487b7160e01b600052603260045260246000fd5b60008235603e1983360301811262001d8c57600080fd5b9190910192915050565b6000808335601e1984360301811262001dae57600080fd5b8301803591506001600160401b0382111562001dc957600080fd5b6020019150368190038213156200168757600080fd5b8183823760009101908152919050565b81835260006001600160fb1b0383111562001e0957600080fd5b8260051b80836020870137939093016020019392505050565b60608152600062001e3860608301888a62001911565b828103602084015262001e4d81878962001def565b9050828103604084015262001e6481858762001def565b9998505050505050505050565b60006001820162001e9257634e487b7160e01b600052601160045260246000fd5b5060010190565b60006020828403121562001eac57600080fd5b8151620012f88162001ad7565b6000825162001d8c8184602087016200156e56fe60c0604052600a608090815269041646d696e41434c56360b41b60a05260009061002990826100ef565b5034801561003657600080fd5b50600180546001600160a01b031916331790556101ae565b634e487b7160e01b600052604160045260246000fd5b600181811c9082168061007857607f821691505b60208210810361009857634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156100ea576000816000526020600020601f850160051c810160208610156100c75750805b601f850160051c820191505b818110156100e6578281556001016100d3565b5050505b505050565b81516001600160401b038111156101085761010861004e565b61011c816101168454610064565b8461009e565b602080601f83116001811461015157600084156101395750858301515b600019600386901b1c1916600185901b1785556100e6565b600085815260208120601f198616915b8281101561018057888601518255948401946001909101908401610161565b508582101561019e5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b610762806101bd6000396000f3fe608060405234801561001057600080fd5b506004361061006d5760003560e01c806301ffc9a71461007257806305de62c01461009a57806329575f6a146100be578063377a7d1a146100de578063985d1968146100f3578063bcc91a1014610106578063c81a396e14610119575b600080fd5b6100856100803660046104a9565b61012e565b60405190151581526020015b60405180910390f35b6100856100a83660046104e2565b50506001546001600160a01b0391821691161490565b6001546100d1906001600160a01b031681565b6040516100919190610525565b6100f16100ec366004610539565b610180565b005b6100f16101013660046105be565b610218565b6100f16101143660046105d9565b610298565b6101216103fe565b604051610091919061060c565b60006001600160e01b03198216633001c1ef60e21b148061015f57506001600160e01b03198216631bbd3e8d60e11b145b8061017a57506301ffc9a760e01b6001600160e01b03198316145b92915050565b6001546001600160a01b031633146101b35760405162461bcd60e51b81526004016101aa9061065b565b60405180910390fd5b600180546001600160a01b038581166001600160a01b0319831681179093556040519116919082907f3f6845104f9728af7979eed8814320daba008953c8db93b9fe32602d1f34b4759061020a9087908790610684565b60405180910390a350505050565b6001546001600160a01b031633146102425760405162461bcd60e51b81526004016101aa9061065b565b806001600160a01b031663715018a66040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561027d57600080fd5b505af1158015610291573d6000803e3d6000fd5b5050505050565b6001546001600160a01b031633146102c25760405162461bcd60e51b81526004016101aa9061065b565b6040516301ffc9a760e01b8152633001c1ef60e21b60048201526001600160a01b038216906301ffc9a790602401602060405180830381865afa15801561030d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061033191906106d0565b61039c5760405162461bcd60e51b815260206004820152603660248201527f41646d696e41434c56303a206e65772061646d696e2041434c20646f6573206e60448201527506f7420737570706f7274204941646d696e41434c56360541b60648201526084016101aa565b60405163f2fde38b60e01b81526001600160a01b0383169063f2fde38b906103c8908490600401610525565b600060405180830381600087803b1580156103e257600080fd5b505af11580156103f6573d6000803e3d6000fd5b505050505050565b6000805461040b906106f2565b80601f0160208091040260200160405190810160405280929190818152602001828054610437906106f2565b80156104845780601f1061045957610100808354040283529160200191610484565b820191906000526020600020905b81548152906001019060200180831161046757829003601f168201915b505050505081565b80356001600160e01b0319811681146104a457600080fd5b919050565b6000602082840312156104bb57600080fd5b6104c48261048c565b9392505050565b80356001600160a01b03811681146104a457600080fd5b6000806000606084860312156104f757600080fd5b610500846104cb565b925061050e602085016104cb565b915061051c6040850161048c565b90509250925092565b6001600160a01b0391909116815260200190565b60008060006040848603121561054e57600080fd5b610557846104cb565b925060208401356001600160401b038082111561057357600080fd5b818601915086601f83011261058757600080fd5b81358181111561059657600080fd5b8760208260051b85010111156105ab57600080fd5b6020830194508093505050509250925092565b6000602082840312156105d057600080fd5b6104c4826104cb565b600080604083850312156105ec57600080fd5b6105f5836104cb565b9150610603602084016104cb565b90509250929050565b60006020808352835180602085015260005b8181101561063a5785810183015185820160400152820161061e565b506000604082860101526040601f19601f8301168501019250505092915050565b6020808252600f908201526e27b7363c9039bab832b920b236b4b760891b604082015260600190565b60208082528181018390526000908460408401835b868110156106c5576001600160a01b036106b2846104cb565b1682529183019190830190600101610699565b509695505050505050565b6000602082840312156106e257600080fd5b815180151581146104c457600080fd5b600181811c9082168061070657607f821691505b60208210810361072657634e487b7160e01b600052602260045260246000fd5b5091905056fea2646970667358221220830f3c30ad4d14df1865965a76cbb302e6938979ee6e646e3a277a8abebb5fd164736f6c63430008160033a26469706673582212200750368963d281eadeb2667f0d1409504d011ab31a68b6699554729037b78c7e64736f6c63430008160033000000000000000000000000000000f74f006ce6480042f001c45c928d1ae6e70000000000000000000000000066009b13b8dfdabbe07800ee00004b008257d90000000000000000000000002ee7b9bb2e038be7323a119701a191c030a61ec600000000000000000000000000df4e8d293d57718aac0b18cbfbe128c5d484ef00000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000001b68747470733a2f2f746f6b656e2e617274626c6f636b732e696f2f0000000000

Deployed Bytecode

0x608060405260043610620001205760003560e01c806310a2e110146200012d57806324377e9f146200015d57806328d6edbf146200018a5780634e93d7e514620001cf57806366a2d9b014620001f65780636bf3d05a146200022d578063715018a614620002635780637390bb50146200027b5780637e56402f14620002a05780638831883414620002c55780638da5cb5b14620002dd5780638e6cee5214620002f55780639f1dc8f8146200031a5780639fc087391462000332578063af8181ff1462000367578063b8967f25146200037f578063e02878fd1462000397578063f21e018c14620003bc578063f2fde38b14620003f2578063f470c9911462000417578063f4ebf9e4146200043c578063fd24b937146200045457600080fd5b366200012857005b600080fd5b3480156200013a57600080fd5b506200014562000479565b604051620001549190620015c2565b60405180910390f35b3480156200016a57600080fd5b50600654620001799060ff1681565b604051901515815260200162000154565b3480156200019757600080fd5b50620001c07f000000000000000000000000000000f74f006ce6480042f001c45c928d1ae6e781565b604051620001549190620015e4565b348015620001dc57600080fd5b50620001f4620001ee36600462001620565b6200050f565b005b3480156200020357600080fd5b506200021e6e0456e67696e65466163746f7279563608c1b81565b60405190815260200162000154565b3480156200023a57600080fd5b50620001c07f0000000000000000000000002ee7b9bb2e038be7323a119701a191c030a61ec681565b3480156200027057600080fd5b50620001f46200059e565b3480156200028857600080fd5b50620001f46200029a3660046200168e565b620005b6565b348015620002ad57600080fd5b50620001f4620002bf366004620016d3565b62000648565b348015620002d257600080fd5b50620001f4620006e5565b348015620002ea57600080fd5b50620001c062000756565b3480156200030257600080fd5b50620001c06200031436600462001721565b62000765565b3480156200032757600080fd5b506200014562000c52565b3480156200033f57600080fd5b5062000357620003513660046200168e565b62000c61565b6040516200015492919062001795565b3480156200037457600080fd5b506200014562000e53565b3480156200038c57600080fd5b506200014562000e62565b348015620003a457600080fd5b50620001c0620003b636600462001805565b62000e71565b348015620003c957600080fd5b50620001c07f0000000000000000000000000066009b13b8dfdabbe07800ee00004b008257d981565b348015620003ff57600080fd5b50620001f46200041136600462001620565b62000f3c565b3480156200042457600080fd5b50620001f46200043636600462001832565b62000f81565b3480156200044957600080fd5b50620001456200101f565b3480156200046157600080fd5b50620001f46200047336600462001620565b6200102e565b600480546200048890620018d5565b80601f0160208091040260200160405190810160405280929190818152602001828054620004b690620018d5565b8015620005075780601f10620004db5761010080835404028352916020019162000507565b820191906000526020600020905b815481529060010190602001808311620004e957829003601f168201915b505050505081565b62000519620010de565b60405163f2fde38b60e01b81526001600160a01b037f0000000000000000000000002ee7b9bb2e038be7323a119701a191c030a61ec6169063f2fde38b9062000567908490600401620015e4565b600060405180830381600087803b1580156200058257600080fd5b505af115801562000597573d6000803e3d6000fd5b5050505050565b620005a8620010de565b620005b4600062001115565b565b620005c0620010de565b604051631cdd23b160e21b81526001600160a01b037f0000000000000000000000002ee7b9bb2e038be7323a119701a191c030a61ec616906373748ec4906200061090859085906004016200195e565b600060405180830381600087803b1580156200062b57600080fd5b505af115801562000640573d6000803e3d6000fd5b505050505050565b62000652620010de565b6040516370a0823160e01b815282906000906001600160a01b038316906370a082319062000685903090600401620015e4565b602060405180830381865afa158015620006a3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620006c991906200197c565b90508015620006df57620006df82848362001165565b50505050565b620006ef620010de565b60065460ff16156200071e5760405162461bcd60e51b8152600401620007159062001996565b60405180910390fd5b6006805460ff191660011790556040517ffb03bbbb81551103a80dda8d3bda55d93637ca4a96390de3719644774bdf1e9890600090a1565b6000546001600160a01b031690565b600062000771620010de565b60065460ff1615620007975760405162461bcd60e51b8152600401620007159062001996565b620007b3620007ad606086016040870162001620565b620011b9565b620007c9620007ad60c0860160a0870162001620565b81620007dc57620007d96200120f565b91505b6001600160a01b038316620008c95762000801620007ad60a086016080870162001620565b6200083b6000620008116200120f565b604051620008226020820162001560565b601f1982820381018352601f9091011660405262001274565b6040805160008152602081019091529093506001600160a01b03841663377a7d1a6200086e60a088016080890162001620565b836040518363ffffffff1660e01b81526004016200088e929190620019da565b600060405180830381600087803b158015620008a957600080fd5b505af1158015620008be573d6000803e3d6000fd5b50505050506200092f565b6000620008dd60a086016080870162001620565b6001600160a01b0316146200092f5760405162461bcd60e51b815260206004820152601760248201527641646d696e41434c20616c72656164792065786973747360481b604482015260640162000715565b60008086600181111562000947576200094762001a38565b1462000974577f0000000000000000000000000066009b13b8dfdabbe07800ee00004b008257d962000996565b7f000000000000000000000000000000f74f006ce6480042f001c45c928d1ae6e75b9050620009a48184620012ff565b604051630dcdda2360e21b81529092506001600160a01b03831690633737688c90620009da908890889060019060040162001b9f565b600060405180830381600087803b158015620009f557600080fd5b505af115801562000a0a573d6000803e3d6000fd5b506000925082915081905088600181111562000a2a5762000a2a62001a38565b1462000a3a576004600562000a3f565b600260035b805462000a4c90620018d5565b80601f016020809104026020016040519081016040528092919081815260200182805462000a7a90620018d5565b801562000acb5780601f1062000a9f5761010080835404028352916020019162000acb565b820191906000526020600020905b81548152906001019060200180831162000aad57829003601f168201915b50505050509150805462000adf90620018d5565b80601f016020809104026020016040519081016040528092919081815260200182805462000b0d90620018d5565b801562000b5e5780601f1062000b325761010080835404028352916020019162000b5e565b820191906000526020600020905b81548152906001019060200180831162000b4057829003601f168201915b505050505091507f0000000000000000000000002ee7b9bb2e038be7323a119701a191c030a61ec66001600160a01b031663f889b3ed8562000ba0846200136e565b62000bab866200136e565b6040516001600160e01b031960e086901b1681526001600160a01b03909316600484015260248301919091526044820152606401600060405180830381600087803b15801562000bfa57600080fd5b505af115801562000c0f573d6000803e3d6000fd5b50506040516001600160a01b03871692507f72dba3aac69e7eadf1383243bbb649ff575d0d530bfecf3d33ef4a0cc0a77b8d9150600090a2505050949350505050565b600380546200048890620018d5565b6000606062000c6f620010de565b43915082806001600160401b0381111562000c8e5762000c8e620019c4565b60405190808252806020026020018201604052801562000cc357816020015b606081526020019060019003908162000cad5790505b50915060005b8181101562000e4a573686868381811062000ce85762000ce862001d5f565b905060200281019062000cfc919062001d75565b905062000d0d602082018262001620565b6001600160a01b03163b60000362000d735762000d2e602082018262001d96565b15905062000d735760405162461bcd60e51b8152602060048201526011602482015270496e76616c69642063616c6c206461746160781b604482015260640162000715565b60008062000d85602084018462001620565b6001600160a01b031662000d9d602085018562001d96565b60405162000dad92919062001ddf565b6000604051808303816000865af19150503d806000811462000dec576040519150601f19603f3d011682016040523d82523d6000602084013e62000df1565b606091505b509150915081819062000e195760405162461bcd60e51b8152600401620007159190620015c2565b508086858151811062000e305762000e3062001d5f565b602002602001018190525050505080600101905062000cc9565b50509250929050565b600180546200048890620018d5565b600580546200048890620018d5565b60008162000ec25760405162461bcd60e51b815260206004820152601d60248201527f6e756c6c2073616c74203d2070736575646f72616e646f6d2061646472000000604482015260640162000715565b62000f33600084600181111562000edd5762000edd62001a38565b1462000f0a577f0000000000000000000000000066009b13b8dfdabbe07800ee00004b008257d962000f2c565b7f000000000000000000000000000000f74f006ce6480042f001c45c928d1ae6e75b836200138e565b90505b92915050565b62000f46620010de565b6001600160a01b03811662000f73576000604051631e4fbdf760e01b8152600401620007159190620015e4565b62000f7e8162001115565b50565b62000f8b620010de565b60405163b3cdf53760e01b81526001600160a01b037f0000000000000000000000002ee7b9bb2e038be7323a119701a191c030a61ec6169063b3cdf5379062000fe39089908990899089908990899060040162001e22565b600060405180830381600087803b15801562000ffe57600080fd5b505af115801562001013573d6000803e3d6000fd5b50505050505050505050565b600280546200048890620018d5565b62001038620010de565b478015620010da576000826001600160a01b03168260405160006040518083038185875af1925050503d80600081146200108f576040519150601f19603f3d011682016040523d82523d6000602084013e62001094565b606091505b5050905080620010d85760405162461bcd60e51b815260206004820152600e60248201526d14185e5b595b9d0819985a5b195960921b604482015260640162000715565b505b5050565b33620010e962000756565b6001600160a01b031614620005b4573360405163118cdaa760e01b8152600401620007159190620015e4565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052620010d8908490620013ef565b6001600160a01b03811662000f7e5760405162461bcd60e51b815260206004820152601b60248201527a4d75737420696e707574206e6f6e2d7a65726f206164647265737360281b604482015260640162000715565b6007805460009182919082620012258362001e71565b909155506040805160208082019390935242818301524360608083019190915230901b6001600160601b0319166080820152815180820360740181526094909101909152805191012092915050565b600083471015620012a25760405163392efb2b60e21b81524760048201526024810185905260440162000715565b8151600003620012c557604051631328927760e21b815260040160405180910390fd5b8282516020840186f590506001600160a01b038116620012f857604051633a0ba96160e11b815260040160405180910390fd5b9392505050565b6000763d602d80600a3d3981f3363d3d373d3d3d363d730000008360601b60e81c176000526e5af43d82803e903d91602b57fd5bf38360781b1760205281603760096000f590506001600160a01b03811662000f36576040516330be1a3d60e21b815260040160405180910390fd5b805160009082908203620013855750600092915050565b50506020015190565b6040513060388201526f5af43d82803e903d91602b57fd5bf3ff602482015260148101839052733d602d80600a3d3981f3363d3d373d3d3d363d738152605881018290526037600c8201206078820152605560439091012060009062000f33565b6000620014066001600160a01b0384168362001451565b905080516000141580156200142e5750808060200190518101906200142c919062001e99565b155b15620010d85782604051635274afe760e01b8152600401620007159190620015e4565b606062000f338383600084600080856001600160a01b031684866040516200147a919062001eb9565b60006040518083038185875af1925050503d8060008114620014b9576040519150601f19603f3d011682016040523d82523d6000602084013e620014be565b606091505b5091509150620014d0868383620014da565b9695505050505050565b606082620014f357620014ed8262001536565b620012f8565b81511580156200150b57506001600160a01b0384163b155b156200152e5783604051639996b31560e01b8152600401620007159190620015e4565b5080620012f8565b805115620015475780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b61091f8062001ece83390190565b60005b838110156200158b57818101518382015260200162001571565b50506000910152565b60008151808452620015ae8160208601602086016200156e565b601f01601f19169290920160200192915050565b60208152600062000f33602083018462001594565b6001600160a01b03169052565b6001600160a01b0391909116815260200190565b6001600160a01b038116811462000f7e57600080fd5b80356200161b81620015f8565b919050565b6000602082840312156200163357600080fd5b8135620012f881620015f8565b60008083601f8401126200165357600080fd5b5081356001600160401b038111156200166b57600080fd5b6020830191508360208260051b85010111156200168757600080fd5b9250929050565b60008060208385031215620016a257600080fd5b82356001600160401b03811115620016b957600080fd5b620016c78582860162001640565b90969095509350505050565b60008060408385031215620016e757600080fd5b8235620016f481620015f8565b915060208301356200170681620015f8565b809150509250929050565b8035600281106200161b57600080fd5b600080600080608085870312156200173857600080fd5b620017438562001711565b935060208501356001600160401b038111156200175f57600080fd5b850161018081880312156200177357600080fd5b925060408501356200178581620015f8565b9396929550929360600135925050565b60006040820184835260206040602085015281855180845260608601915060608160051b87010193506020870160005b82811015620017f757605f19888703018452620017e486835162001594565b95509284019290840190600101620017c5565b509398975050505050505050565b600080604083850312156200181957600080fd5b620018248362001711565b946020939093013593505050565b600080600080600080606087890312156200184c57600080fd5b86356001600160401b03808211156200186457600080fd5b620018728a838b0162001640565b909850965060208901359150808211156200188c57600080fd5b6200189a8a838b0162001640565b90965094506040890135915080821115620018b457600080fd5b50620018c389828a0162001640565b979a9699509497509295939492505050565b600181811c90821680620018ea57607f821691505b6020821081036200190b57634e487b7160e01b600052602260045260246000fd5b50919050565b8183526000602080850194508260005b85811015620019535781356200193781620015f8565b6001600160a01b03168752958201959082019060010162001921565b509495945050505050565b6020815260006200197460208301848662001911565b949350505050565b6000602082840312156200198f57600080fd5b5051919050565b602080825260149082015273199858dd1bdc9e481a5cc81858985b991bdb995960621b604082015260600190565b634e487b7160e01b600052604160045260246000fd5b6001600160a01b038381168252604060208084018290528451918401829052600092858201929091906060860190855b8181101562001a2a57855185168352948301949183019160010162001a0a565b509098975050505050505050565b634e487b7160e01b600052602160045260246000fd5b6000808335601e1984360301811262001a6657600080fd5b83016020810192503590506001600160401b0381111562001a8657600080fd5b8036038213156200168757600080fd5b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b80356001600160f81b03811681146200161b57600080fd5b801515811462000f7e57600080fd5b80356200161b8162001ad7565b8054600090600181811c908083168062001b0e57607f831692505b6020808410820362001b3057634e487b7160e01b600052602260045260246000fd5b8388526020880182801562001b4e576001811462001b655762001b92565b60ff198716825285151560051b8201975062001b92565b60008981526020902060005b8781101562001b8c5781548482015290860190840162001b71565b83019850505b5050505050505092915050565b60608152600062001bb1858662001a4e565b61018080606086015262001bcb6101e08601838562001a96565b925062001bdc602089018962001a4e565b868503605f19016080880152925062001bf784848362001a96565b93505062001c08604089016200160e565b915062001c1960a0860183620015d7565b62001c27606089016200160e565b915062001c3860c0860183620015d7565b62001c46608089016200160e565b915062001c5760e0860183620015d7565b62001c6560a089016200160e565b915061010062001c7881870184620015d7565b62001c8660c08a016200160e565b925061012062001c9981880185620015d7565b62001ca760e08b016200160e565b935061014062001cba81890186620015d7565b62001cc7838c0162001abf565b9450610160925062001ce3838901866001600160f81b03169052565b62001cf0828c0162001ae6565b80151589860152945062001d06818c0162001ae6565b9450505062001d1a6101a087018415159052565b62001d27818a0162001ae6565b9250505062001d3b6101c085018215159052565b5062001d4b6020840186620015d7565b8281036040840152620014d0818562001af3565b634e487b7160e01b600052603260045260246000fd5b60008235603e1983360301811262001d8c57600080fd5b9190910192915050565b6000808335601e1984360301811262001dae57600080fd5b8301803591506001600160401b0382111562001dc957600080fd5b6020019150368190038213156200168757600080fd5b8183823760009101908152919050565b81835260006001600160fb1b0383111562001e0957600080fd5b8260051b80836020870137939093016020019392505050565b60608152600062001e3860608301888a62001911565b828103602084015262001e4d81878962001def565b9050828103604084015262001e6481858762001def565b9998505050505050505050565b60006001820162001e9257634e487b7160e01b600052601160045260246000fd5b5060010190565b60006020828403121562001eac57600080fd5b8151620012f88162001ad7565b6000825162001d8c8184602087016200156e56fe60c0604052600a608090815269041646d696e41434c56360b41b60a05260009061002990826100ef565b5034801561003657600080fd5b50600180546001600160a01b031916331790556101ae565b634e487b7160e01b600052604160045260246000fd5b600181811c9082168061007857607f821691505b60208210810361009857634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156100ea576000816000526020600020601f850160051c810160208610156100c75750805b601f850160051c820191505b818110156100e6578281556001016100d3565b5050505b505050565b81516001600160401b038111156101085761010861004e565b61011c816101168454610064565b8461009e565b602080601f83116001811461015157600084156101395750858301515b600019600386901b1c1916600185901b1785556100e6565b600085815260208120601f198616915b8281101561018057888601518255948401946001909101908401610161565b508582101561019e5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b610762806101bd6000396000f3fe608060405234801561001057600080fd5b506004361061006d5760003560e01c806301ffc9a71461007257806305de62c01461009a57806329575f6a146100be578063377a7d1a146100de578063985d1968146100f3578063bcc91a1014610106578063c81a396e14610119575b600080fd5b6100856100803660046104a9565b61012e565b60405190151581526020015b60405180910390f35b6100856100a83660046104e2565b50506001546001600160a01b0391821691161490565b6001546100d1906001600160a01b031681565b6040516100919190610525565b6100f16100ec366004610539565b610180565b005b6100f16101013660046105be565b610218565b6100f16101143660046105d9565b610298565b6101216103fe565b604051610091919061060c565b60006001600160e01b03198216633001c1ef60e21b148061015f57506001600160e01b03198216631bbd3e8d60e11b145b8061017a57506301ffc9a760e01b6001600160e01b03198316145b92915050565b6001546001600160a01b031633146101b35760405162461bcd60e51b81526004016101aa9061065b565b60405180910390fd5b600180546001600160a01b038581166001600160a01b0319831681179093556040519116919082907f3f6845104f9728af7979eed8814320daba008953c8db93b9fe32602d1f34b4759061020a9087908790610684565b60405180910390a350505050565b6001546001600160a01b031633146102425760405162461bcd60e51b81526004016101aa9061065b565b806001600160a01b031663715018a66040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561027d57600080fd5b505af1158015610291573d6000803e3d6000fd5b5050505050565b6001546001600160a01b031633146102c25760405162461bcd60e51b81526004016101aa9061065b565b6040516301ffc9a760e01b8152633001c1ef60e21b60048201526001600160a01b038216906301ffc9a790602401602060405180830381865afa15801561030d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061033191906106d0565b61039c5760405162461bcd60e51b815260206004820152603660248201527f41646d696e41434c56303a206e65772061646d696e2041434c20646f6573206e60448201527506f7420737570706f7274204941646d696e41434c56360541b60648201526084016101aa565b60405163f2fde38b60e01b81526001600160a01b0383169063f2fde38b906103c8908490600401610525565b600060405180830381600087803b1580156103e257600080fd5b505af11580156103f6573d6000803e3d6000fd5b505050505050565b6000805461040b906106f2565b80601f0160208091040260200160405190810160405280929190818152602001828054610437906106f2565b80156104845780601f1061045957610100808354040283529160200191610484565b820191906000526020600020905b81548152906001019060200180831161046757829003601f168201915b505050505081565b80356001600160e01b0319811681146104a457600080fd5b919050565b6000602082840312156104bb57600080fd5b6104c48261048c565b9392505050565b80356001600160a01b03811681146104a457600080fd5b6000806000606084860312156104f757600080fd5b610500846104cb565b925061050e602085016104cb565b915061051c6040850161048c565b90509250925092565b6001600160a01b0391909116815260200190565b60008060006040848603121561054e57600080fd5b610557846104cb565b925060208401356001600160401b038082111561057357600080fd5b818601915086601f83011261058757600080fd5b81358181111561059657600080fd5b8760208260051b85010111156105ab57600080fd5b6020830194508093505050509250925092565b6000602082840312156105d057600080fd5b6104c4826104cb565b600080604083850312156105ec57600080fd5b6105f5836104cb565b9150610603602084016104cb565b90509250929050565b60006020808352835180602085015260005b8181101561063a5785810183015185820160400152820161061e565b506000604082860101526040601f19601f8301168501019250505092915050565b6020808252600f908201526e27b7363c9039bab832b920b236b4b760891b604082015260600190565b60208082528181018390526000908460408401835b868110156106c5576001600160a01b036106b2846104cb565b1682529183019190830190600101610699565b509695505050505050565b6000602082840312156106e257600080fd5b815180151581146104c457600080fd5b600181811c9082168061070657607f821691505b60208210810361072657634e487b7160e01b600052602260045260246000fd5b5091905056fea2646970667358221220830f3c30ad4d14df1865965a76cbb302e6938979ee6e646e3a277a8abebb5fd164736f6c63430008160033a26469706673582212200750368963d281eadeb2667f0d1409504d011ab31a68b6699554729037b78c7e64736f6c63430008160033

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

000000000000000000000000000000f74f006ce6480042f001c45c928d1ae6e70000000000000000000000000066009b13b8dfdabbe07800ee00004b008257d90000000000000000000000002ee7b9bb2e038be7323a119701a191c030a61ec600000000000000000000000000df4e8d293d57718aac0b18cbfbe128c5d484ef00000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000001b68747470733a2f2f746f6b656e2e617274626c6f636b732e696f2f0000000000

-----Decoded View---------------
Arg [0] : engineImplementation_ (address): 0x000000F74f006CE6480042f001c45c928D1Ae6E7
Arg [1] : engineFlexImplementation_ (address): 0x0066009B13b8DfDabbE07800ee00004b008257D9
Arg [2] : coreRegistry_ (address): 0x2eE7B9bB2E038bE7323A119701A191c030A61ec6
Arg [3] : owner_ (address): 0x00df4E8d293d57718aac0B18cBfBE128c5d484Ef
Arg [4] : defaultBaseURIHost_ (string): https://token.artblocks.io/

-----Encoded View---------------
7 Constructor Arguments found :
Arg [0] : 000000000000000000000000000000f74f006ce6480042f001c45c928d1ae6e7
Arg [1] : 0000000000000000000000000066009b13b8dfdabbe07800ee00004b008257d9
Arg [2] : 0000000000000000000000002ee7b9bb2e038be7323a119701a191c030a61ec6
Arg [3] : 00000000000000000000000000df4e8d293d57718aac0b18cbfbe128c5d484ef
Arg [4] : 00000000000000000000000000000000000000000000000000000000000000a0
Arg [5] : 000000000000000000000000000000000000000000000000000000000000001b
Arg [6] : 68747470733a2f2f746f6b656e2e617274626c6f636b732e696f2f0000000000


Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

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