ETH Price: $3,364.94 (-1.52%)
Gas: 7 Gwei

Contract

0x0711A9767a41290D7f52714204618345C584f450
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Value
Purchase169328672023-03-29 12:11:35455 days ago1680091895IN
0x0711A976...5C584f450
0 ETH0.0013042926.01408995
Purchase169328672023-03-29 12:11:35455 days ago1680091895IN
0x0711A976...5C584f450
0 ETH0.0013042926.01408995
Purchase To165328172023-02-01 8:36:47511 days ago1675240607IN
0x0711A976...5C584f450
0 ETH0.001062516.40597832
Transfer164442252023-01-19 23:47:11523 days ago1674172031IN
0x0711A976...5C584f450
0.2557 ETH0.0003364416.02126419
Purchase To163780582023-01-10 17:59:47533 days ago1673373587IN
0x0711A976...5C584f450
0 ETH0.0046350231
Purchase To163780562023-01-10 17:59:23533 days ago1673373563IN
0x0711A976...5C584f450
0 ETH0.003190328.20137282
Purchase To163780562023-01-10 17:59:23533 days ago1673373563IN
0x0711A976...5C584f450
0 ETH0.0034029429.43039564
Purchase To163780532023-01-10 17:58:47533 days ago1673373527IN
0x0711A976...5C584f450
0 ETH0.0044342630.09628541
Purchase To163780532023-01-10 17:58:47533 days ago1673373527IN
0x0711A976...5C584f450
0 ETH0.0035776731
Purchase To163780532023-01-10 17:58:47533 days ago1673373527IN
0x0711A976...5C584f450
0 ETH0.0036194831.30633982
Purchase To163780522023-01-10 17:58:35533 days ago1673373515IN
0x0711A976...5C584f450
0 ETH0.0047619631.86219391
Purchase To163780492023-01-10 17:57:59533 days ago1673373479IN
0x0711A976...5C584f450
0 ETH0.0049688933.2103278
Purchase To163780472023-01-10 17:57:35533 days ago1673373455IN
0x0711A976...5C584f450
0 ETH0.0053214932.50464589
Purchase To163780462023-01-10 17:57:23533 days ago1673373443IN
0x0711A976...5C584f450
0 ETH0.0040133834.78676068
Purchase To163780432023-01-10 17:56:47533 days ago1673373407IN
0x0711A976...5C584f450
0 ETH0.0037833632.73851307
Purchase To163780422023-01-10 17:56:35533 days ago1673373395IN
0x0711A976...5C584f450
0 ETH0.004964933.19786024
Purchase To163780412023-01-10 17:56:23533 days ago1673373383IN
0x0711A976...5C584f450
0 ETH0.0046911731.31936522
Purchase To163780402023-01-10 17:55:59533 days ago1673373359IN
0x0711A976...5C584f450
0 ETH0.0035445330.78535171
Purchase To163780392023-01-10 17:55:47533 days ago1673373347IN
0x0711A976...5C584f450
0 ETH0.0047212931.56641144
Purchase To163780352023-01-10 17:54:59533 days ago1673373299IN
0x0711A976...5C584f450
0 ETH0.0044673829.82095345
Purchase To163780332023-01-10 17:54:35533 days ago1673373275IN
0x0711A976...5C584f450
0 ETH0.0048643832.5666323
Purchase To163780262023-01-10 17:53:11533 days ago1673373191IN
0x0711A976...5C584f450
0 ETH0.0035065630.33806313
Purchase To163780262023-01-10 17:53:11533 days ago1673373191IN
0x0711A976...5C584f450
0 ETH0.0034950930.33806313
Purchase To163780242023-01-10 17:52:47533 days ago1673373167IN
0x0711A976...5C584f450
0 ETH0.0046904831.31644302
Purchase To163780242023-01-10 17:52:47533 days ago1673373167IN
0x0711A976...5C584f450
0 ETH0.0046848431.31644302
View all transactions

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
MinterMerkleV2

Compiler Version
v0.8.17+commit.8df45f5f

Optimization Enabled:
Yes with 25 runs

Other Settings:
default evmVersion
File 1 of 12 : MinterMerkleV2.sol
// SPDX-License-Identifier: LGPL-3.0-only
// Created By: Art Blocks Inc.

import "../../../interfaces/0.8.x/IGenArt721CoreContractV3.sol";
import "../../../interfaces/0.8.x/IMinterFilterV0.sol";
import "../../../interfaces/0.8.x/IFilteredMinterMerkleV0.sol";
import "../../../interfaces/0.8.x/IDelegationRegistry.sol";

import "@openzeppelin-4.7/contracts/utils/cryptography/MerkleProof.sol";
import "@openzeppelin-4.7/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin-4.7/contracts/security/ReentrancyGuard.sol";

pragma solidity 0.8.17;

/**
 * @title Filtered Minter contract that allows tokens to be minted with ETH
 * for addresses in a Merkle allowlist.
 * This is designed to be used with IGenArt721CoreContractV3 contracts.
 * @author Art Blocks Inc.
 * @notice Privileged Roles and Ownership:
 * This contract is designed to be managed, with limited powers.
 * Privileged roles and abilities are controlled by the project's artist, which
 * can be modified by the core contract's Admin ACL contract. Both of these
 * roles hold extensive power and can modify minter details.
 * Care must be taken to ensure that the admin ACL contract and artist
 * addresses are secure behind a multi-sig or other access control mechanism.
 * ----------------------------------------------------------------------------
 * The following functions are restricted to a project's artist:
 * - updateMerkleRoot
 * - updatePricePerTokenInWei
 * - setProjectInvocationsPerAddress
 * ----------------------------------------------------------------------------
 * Additional admin and artist privileged roles may be described on other
 * contracts that this minter integrates with.
 * ----------------------------------------------------------------------------
 * This contract allows vaults to configure token-level or wallet-level
 * delegation of minting privileges. This allows a vault on an allowlist to
 * delegate minting privileges to a wallet that is not on the allowlist,
 * enabling the vault to remain air-gapped while still allowing minting. The
 * delegation registry contract is responsible for managing these delegations,
 * and is available at the address returned by the public constant
 * `DELEGATION_REGISTRY_ADDRESS`. At the time of writing, the delegation
 * registry enables easy delegation configuring at https://delegate.cash/.
 * Art Blocks does not guarentee the security of the delegation registry, and
 * users should take care to ensure that the delegation registry is secure.
 * Token-level delegations are configured by the vault owner, and contract-
 * level delegations must be configured for the core token contract as returned
 * by the public immutable variable `genArt721CoreAddress`.
 */
contract MinterMerkleV2 is ReentrancyGuard, IFilteredMinterMerkleV0 {
    using MerkleProof for bytes32[];

    /// Delegation registry address
    address public constant DELEGATION_REGISTRY_ADDRESS =
        0x00000000000076A84feF008CDAbe6409d2FE638B;

    /// Delegation registry address
    IDelegationRegistry private immutable delegationRegistryContract;

    /// Core contract address this minter interacts with
    address public immutable genArt721CoreAddress;

    /// This contract handles cores with interface IV3
    IGenArt721CoreContractV3 private immutable genArtCoreContract;

    /// Minter filter address this minter interacts with
    address public immutable minterFilterAddress;

    /// Minter filter this minter may interact with.
    IMinterFilterV0 private immutable minterFilter;

    /// minterType for this minter
    string public constant minterType = "MinterMerkleV2";

    /// project minter configuration keys used by this minter
    bytes32 private constant CONFIG_MERKLE_ROOT = "merkleRoot";
    bytes32 private constant CONFIG_USE_MAX_INVOCATIONS_PER_ADDRESS_OVERRIDE =
        "useMaxMintsPerAddrOverride"; // shortened to fit in 32 bytes
    bytes32 private constant CONFIG_MAX_INVOCATIONS_OVERRIDE =
        "maxMintsPerAddrOverride"; // shortened to match format of previous key

    uint256 constant ONE_MILLION = 1_000_000;

    uint256 public constant DEFAULT_MAX_INVOCATIONS_PER_ADDRESS = 1;

    struct ProjectConfig {
        bool maxHasBeenInvoked;
        bool priceIsConfigured;
        // initial value is false, so by default, projects limit allowlisted
        // addresses to a mint qty of `DEFAULT_MAX_INVOCATIONS_PER_ADDRESS`
        bool useMaxInvocationsPerAddressOverride;
        // a value of 0 means no limit
        // (only used if `useMaxInvocationsPerAddressOverride` is true)
        uint24 maxInvocationsPerAddressOverride;
        uint24 maxInvocations;
        uint256 pricePerTokenInWei;
    }

    mapping(uint256 => ProjectConfig) public projectConfig;

    /// projectId => merkle root
    mapping(uint256 => bytes32) public projectMerkleRoot;

    /// projectId => purchaser address => qty of mints purchased for project
    mapping(uint256 => mapping(address => uint256))
        public projectUserMintInvocations;

    modifier onlyArtist(uint256 _projectId) {
        require(
            msg.sender ==
                genArtCoreContract.projectIdToArtistAddress(_projectId),
            "Only Artist"
        );
        _;
    }

    /**
     * @notice Initializes contract to be a Filtered Minter for
     * `_minterFilter`, integrated with Art Blocks core contract
     * at address `_genArt721Address`.
     * @param _genArt721Address Art Blocks core contract address for
     * which this contract will be a minter.
     * @param _minterFilter Minter filter for which this will be a
     * filtered minter.
     */
    constructor(address _genArt721Address, address _minterFilter)
        ReentrancyGuard()
    {
        genArt721CoreAddress = _genArt721Address;
        genArtCoreContract = IGenArt721CoreContractV3(_genArt721Address);
        delegationRegistryContract = IDelegationRegistry(
            DELEGATION_REGISTRY_ADDRESS
        );
        minterFilterAddress = _minterFilter;
        minterFilter = IMinterFilterV0(_minterFilter);
        require(
            minterFilter.genArt721CoreAddress() == _genArt721Address,
            "Illegal contract pairing"
        );
        // broadcast default max invocations per address for this minter
        emit DefaultMaxInvocationsPerAddress(
            DEFAULT_MAX_INVOCATIONS_PER_ADDRESS
        );
    }

    /**
     * @notice Update the Merkle root for project `_projectId`.
     * @param _projectId Project ID to be updated.
     * @param _root root of Merkle tree defining addresses allowed to mint
     * on project `_projectId`.
     */
    function updateMerkleRoot(uint256 _projectId, bytes32 _root)
        external
        onlyArtist(_projectId)
    {
        require(_root != bytes32(0), "Root must be provided");
        projectMerkleRoot[_projectId] = _root;
        emit ConfigValueSet(_projectId, CONFIG_MERKLE_ROOT, _root);
    }

    /**
     * @notice Returns hashed address (to be used as merkle tree leaf).
     * Included as a public function to enable users to calculate their hashed
     * address in Solidity when generating proofs off-chain.
     * @param _address address to be hashed
     * @return bytes32 hashed address, via keccak256 (using encodePacked)
     */
    function hashAddress(address _address) public pure returns (bytes32) {
        return keccak256(abi.encodePacked(_address));
    }

    /**
     * @notice Verify if address is allowed to mint on project `_projectId`.
     * @param _projectId Project ID to be checked.
     * @param _proof Merkle proof for address.
     * @param _address Address to check.
     * @return inAllowlist true only if address is allowed to mint and valid
     * Merkle proof was provided
     */
    function verifyAddress(
        uint256 _projectId,
        bytes32[] calldata _proof,
        address _address
    ) public view returns (bool) {
        return
            _proof.verifyCalldata(
                projectMerkleRoot[_projectId],
                hashAddress(_address)
            );
    }

    /**
     * @notice Sets maximum allowed invocations per allowlisted address for
     * project `_project` to `limit`. If `limit` is set to 0, allowlisted
     * addresses will be able to mint as many times as desired, until the
     * project reaches its maximum invocations.
     * Default is a value of 1 if never configured by artist.
     * @param _projectId Project ID to toggle the mint limit.
     * @param _maxInvocationsPerAddress Maximum allowed invocations per
     * allowlisted address.
     * @dev default value stated above must be updated if the value of
     * CONFIG_USE_MAX_INVOCATIONS_PER_ADDRESS_OVERRIDE is changed.
     */
    function setProjectInvocationsPerAddress(
        uint256 _projectId,
        uint24 _maxInvocationsPerAddress
    ) external onlyArtist(_projectId) {
        ProjectConfig storage _projectConfig = projectConfig[_projectId];
        // use override value instead of the contract's default
        // @dev this never changes from true to false; default value is only
        // used if artist has never configured project invocations per address
        _projectConfig.useMaxInvocationsPerAddressOverride = true;
        // update the override value
        _projectConfig
            .maxInvocationsPerAddressOverride = _maxInvocationsPerAddress;
        // generic events
        emit ConfigValueSet(
            _projectId,
            CONFIG_USE_MAX_INVOCATIONS_PER_ADDRESS_OVERRIDE,
            true
        );
        emit ConfigValueSet(
            _projectId,
            CONFIG_MAX_INVOCATIONS_OVERRIDE,
            uint256(_maxInvocationsPerAddress)
        );
    }

    /**
     * @notice Syncs local maximum invocations of project `_projectId` based on
     * the value currently defined in the core contract. Only used for gas
     * optimization of mints after maxInvocations has been reached.
     * @param _projectId Project ID to set the maximum invocations for.
     * @dev this enables gas reduction after maxInvocations have been reached -
     * core contracts shall still enforce a maxInvocation check during mint.
     * @dev function is intentionally not gated to any specific access control;
     * it only syncs a local state variable to the core contract's state.
     */
    function setProjectMaxInvocations(uint256 _projectId) external {
        uint256 maxInvocations;
        (, maxInvocations, , , , ) = genArtCoreContract.projectStateData(
            _projectId
        );
        // update storage with results
        projectConfig[_projectId].maxInvocations = uint24(maxInvocations);
    }

    /**
     * @notice Warning: Disabling purchaseTo is not supported on this minter.
     * This method exists purely for interface-conformance purposes.
     */
    function togglePurchaseToDisabled(uint256 _projectId)
        external
        view
        onlyArtist(_projectId)
    {
        revert("Action not supported");
    }

    /**
     * @notice projectId => has project reached its maximum number of
     * invocations? Note that this returns a local cache of the core contract's
     * state, and may be out of sync with the core contract. This is
     * intentional, as it only enables gas optimization of mints after a
     * project's maximum invocations has been reached. A false negative will
     * only result in a gas cost increase, since the core contract will still
     * enforce a maxInvocation check during minting. A false positive is not
     * possible because the V3 core contract only allows maximum invocations
     * to be reduced, not increased. Based on this rationale, we intentionally
     * do not do input validation in this method as to whether or not the input
     * `_projectId` is an existing project ID.
     */
    function projectMaxHasBeenInvoked(uint256 _projectId)
        external
        view
        returns (bool)
    {
        return projectConfig[_projectId].maxHasBeenInvoked;
    }

    /**
     * @notice projectId => project's maximum number of invocations.
     * Optionally synced with core contract value, for gas optimization.
     * Note that this returns a local cache of the core contract's
     * state, and may be out of sync with the core contract. This is
     * intentional, as it only enables gas optimization of mints after a
     * project's maximum invocations has been reached.
     * @dev A number greater than the core contract's project max invocations
     * will only result in a gas cost increase, since the core contract will
     * still enforce a maxInvocation check during minting. A number less than
     * the core contract's project max invocations is only possible when the
     * project's max invocations have not been synced on this minter, since the
     * V3 core contract only allows maximum invocations to be reduced, not
     * increased. When this happens, the minter will enable minting, allowing
     * the core contract to enforce the max invocations check. Based on this
     * rationale, we intentionally do not do input validation in this method as
     * to whether or not the input `_projectId` is an existing project ID.
     */
    function projectMaxInvocations(uint256 _projectId)
        external
        view
        returns (uint256)
    {
        return uint256(projectConfig[_projectId].maxInvocations);
    }

    /**
     * @notice Updates this minter's price per token of project `_projectId`
     * to be '_pricePerTokenInWei`, in Wei.
     * This price supersedes any legacy core contract price per token value.
     * @dev Note that it is intentionally supported here that the configured
     * price may be explicitly set to `0`.
     */
    function updatePricePerTokenInWei(
        uint256 _projectId,
        uint256 _pricePerTokenInWei
    ) external onlyArtist(_projectId) {
        projectConfig[_projectId].pricePerTokenInWei = _pricePerTokenInWei;
        projectConfig[_projectId].priceIsConfigured = true;
        emit PricePerTokenInWeiUpdated(_projectId, _pricePerTokenInWei);
    }

    /**
     * @notice Inactive function - requires Merkle proof to purchase.
     */
    function purchase(uint256) external payable returns (uint256) {
        revert("Must provide Merkle proof");
    }

    /**
     * @notice Inactive function - requires Merkle proof to purchase.
     */
    function purchaseTo(address, uint256) public payable returns (uint256) {
        revert("Must provide Merkle proof");
    }

    /**
     * @notice Purchases a token from project `_projectId`.
     * @param _projectId Project ID to mint a token on.
     * @param _proof Merkle proof.
     * @return tokenId Token ID of minted token
     */
    function purchase(uint256 _projectId, bytes32[] calldata _proof)
        external
        payable
        returns (uint256 tokenId)
    {
        tokenId = purchaseTo_kem(msg.sender, _projectId, _proof, address(0));
        return tokenId;
    }

    /**
     * @notice gas-optimized version of purchase(uint256,bytes32[]).
     */
    function purchase_gD5(uint256 _projectId, bytes32[] calldata _proof)
        external
        payable
        returns (uint256 tokenId)
    {
        tokenId = purchaseTo_kem(msg.sender, _projectId, _proof, address(0));
        return tokenId;
    }

    /**
     * @notice Purchases a token from project `_projectId` and sets
     * the token's owner to `_to`.
     * @param _to Address to be the new token's owner.
     * @param _projectId Project ID to mint a token on.
     * @param _proof Merkle proof.
     * @return tokenId Token ID of minted token
     */
    function purchaseTo(
        address _to,
        uint256 _projectId,
        bytes32[] calldata _proof
    ) external payable returns (uint256 tokenId) {
        return purchaseTo_kem(_to, _projectId, _proof, address(0));
    }

    /**
     * @notice Purchases a token from project `_projectId` and sets
     *         the token's owner to `_to`, as a delegate, (the `msg.sender`)
     *         on behalf of an explicitly defined vault.
     * @param _to Address to be the new token's owner.
     * @param _projectId Project ID to mint a token on.
     * @param _proof Merkle proof.
     * @param _vault Vault being purchased on behalf of.
     * @return tokenId Token ID of minted token
     */
    function purchaseTo(
        address _to,
        uint256 _projectId,
        bytes32[] calldata _proof,
        address _vault
    ) external payable returns (uint256 tokenId) {
        return purchaseTo_kem(_to, _projectId, _proof, _vault);
    }

    /**
     * @notice gas-optimized version of
     * purchaseTo(address,uint256,bytes32[],address).
     * @param _to Address to be the new token's owner.
     * @param _projectId Project ID to mint a token on.
     * @param _proof Merkle proof. Must be a valid proof of either `msg.sender`
     * if `_vault` is `address(0)`, or `_vault` if `_vault` is not `address(0)`.
     * @param _vault Vault being purchased on behalf of. Acceptable to be
     * address(0) if no vault.
     */
    function purchaseTo_kem(
        address _to,
        uint256 _projectId,
        bytes32[] calldata _proof,
        address _vault // acceptable to be `address(0)` if no vault
    ) public payable nonReentrant returns (uint256 tokenId) {
        // CHECKS
        ProjectConfig storage _projectConfig = projectConfig[_projectId];

        // Note that `maxHasBeenInvoked` is only checked here to reduce gas
        // consumption after a project has been fully minted.
        // `_projectConfig.maxHasBeenInvoked` is locally cached to reduce
        // gas consumption, but if not in sync with the core contract's value,
        // the core contract also enforces its own max invocation check during
        // minting.
        require(
            !_projectConfig.maxHasBeenInvoked,
            "Maximum number of invocations reached"
        );

        // load price of token into memory
        uint256 _pricePerTokenInWei = _projectConfig.pricePerTokenInWei;

        require(
            msg.value >= _pricePerTokenInWei,
            "Must send minimum value to mint!"
        );

        // require artist to have configured price of token on this minter
        require(_projectConfig.priceIsConfigured, "Price not configured");

        // no contract filter since Merkle tree controls allowed addresses

        // NOTE: delegate-vault handling **begins here**.

        // handle that the vault may be either the `msg.sender` in the case
        // that there is not a true vault, or may be `_vault` if one is
        // provided explicitly (and it is valid).
        address vault = msg.sender;
        if (_vault != address(0)) {
            // If a vault is provided, it must be valid, otherwise throw rather
            // than optimistically-minting with original `msg.sender`.
            // Note, we do not check `checkDelegateForAll` as well, as it is known
            // to be implicitly checked by calling `checkDelegateForContract`.
            bool isValidDelegee = delegationRegistryContract
                .checkDelegateForContract(
                    msg.sender, // delegate
                    _vault, // vault
                    genArt721CoreAddress // contract
                );
            require(isValidDelegee, "Invalid delegate-vault pairing");
            vault = _vault;
        }

        // require valid Merkle proof
        require(
            verifyAddress(_projectId, _proof, vault),
            "Invalid Merkle proof"
        );

        // limit mints per address by project
        uint256 _maxProjectInvocationsPerAddress = _projectConfig
            .useMaxInvocationsPerAddressOverride
            ? _projectConfig.maxInvocationsPerAddressOverride
            : DEFAULT_MAX_INVOCATIONS_PER_ADDRESS;

        // note that mint limits index off of the `vault` (when applicable)
        require(
            projectUserMintInvocations[_projectId][vault] <
                _maxProjectInvocationsPerAddress ||
                _maxProjectInvocationsPerAddress == 0,
            "Maximum number of invocations per address reached"
        );

        // EFFECTS
        // increment user's invocations for this project
        unchecked {
            // this will never overflow since user's invocations on a project
            // are limited by the project's max invocations
            projectUserMintInvocations[_projectId][vault]++;
        }

        // mint token
        tokenId = minterFilter.mint(_to, _projectId, vault);

        // NOTE: delegate-vault handling **ends here**.

        // okay if this underflows because if statement will always eval false.
        // this is only for gas optimization (core enforces maxInvocations).
        unchecked {
            if (tokenId % ONE_MILLION == _projectConfig.maxInvocations - 1) {
                _projectConfig.maxHasBeenInvoked = true;
            }
        }

        // INTERACTIONS
        _splitFundsETH(_projectId, _pricePerTokenInWei);

        return tokenId;
    }

    /**
     * @dev splits ETH funds between sender (if refund), foundation,
     * artist, and artist's additional payee for a token purchased on
     * project `_projectId`.
     * @dev possible DoS during splits is acknowledged, and mitigated by
     * business practices, including end-to-end testing on mainnet, and
     * admin-accepted artist payment addresses.
     */
    function _splitFundsETH(uint256 _projectId, uint256 _pricePerTokenInWei)
        internal
    {
        if (msg.value > 0) {
            bool success_;
            // send refund to sender
            uint256 refund = msg.value - _pricePerTokenInWei;
            if (refund > 0) {
                (success_, ) = msg.sender.call{value: refund}("");
                require(success_, "Refund failed");
            }
            // split remaining funds between foundation, artist, and artist's
            // additional payee
            (
                uint256 artblocksRevenue_,
                address payable artblocksAddress_,
                uint256 artistRevenue_,
                address payable artistAddress_,
                uint256 additionalPayeePrimaryRevenue_,
                address payable additionalPayeePrimaryAddress_
            ) = genArtCoreContract.getPrimaryRevenueSplits(
                    _projectId,
                    _pricePerTokenInWei
                );
            // Art Blocks payment
            if (artblocksRevenue_ > 0) {
                (success_, ) = artblocksAddress_.call{value: artblocksRevenue_}(
                    ""
                );
                require(success_, "Art Blocks payment failed");
            }
            // artist payment
            if (artistRevenue_ > 0) {
                (success_, ) = artistAddress_.call{value: artistRevenue_}("");
                require(success_, "Artist payment failed");
            }
            // additional payee payment
            if (additionalPayeePrimaryRevenue_ > 0) {
                (success_, ) = additionalPayeePrimaryAddress_.call{
                    value: additionalPayeePrimaryRevenue_
                }("");
                require(success_, "Additional Payee payment failed");
            }
        }
    }

    /**
     * @notice projectId => maximum invocations per allowlisted address. If a
     * a value of 0 is returned, there is no limit on the number of mints per
     * allowlisted address.
     * Default behavior is limit 1 mint per address.
     * This value can be changed at any time by the artist.
     * @dev default value stated above must be updated if the value of
     * CONFIG_USE_MAX_INVOCATIONS_PER_ADDRESS_OVERRIDE is changed.
     */
    function projectMaxInvocationsPerAddress(uint256 _projectId)
        public
        view
        returns (uint256)
    {
        ProjectConfig storage _projectConfig = projectConfig[_projectId];
        if (_projectConfig.useMaxInvocationsPerAddressOverride) {
            return uint256(_projectConfig.maxInvocationsPerAddressOverride);
        } else {
            return DEFAULT_MAX_INVOCATIONS_PER_ADDRESS;
        }
    }

    /**
     * @notice Returns remaining invocations for a given address.
     * If `projectLimitsMintInvocationsPerAddress` is false, individual
     * addresses are only limited by the project's maximum invocations, and a
     * dummy value of zero is returned for `mintInvocationsRemaining`.
     * If `projectLimitsMintInvocationsPerAddress` is true, the quantity of
     * remaining mint invocations for address `_address` is returned as
     * `mintInvocationsRemaining`.
     * Note that mint invocations per address can be changed at any time by the
     * artist of a project.
     * Also note that all mint invocations are limited by a project's maximum
     * invocations as defined on the core contract. This function may return
     * a value greater than the project's remaining invocations.
     */
    function projectRemainingInvocationsForAddress(
        uint256 _projectId,
        address _address
    )
        external
        view
        returns (
            bool projectLimitsMintInvocationsPerAddress,
            uint256 mintInvocationsRemaining
        )
    {
        uint256 maxInvocationsPerAddress = projectMaxInvocationsPerAddress(
            _projectId
        );
        if (maxInvocationsPerAddress == 0) {
            // project does not limit mint invocations per address, so leave
            // `projectLimitsMintInvocationsPerAddress` at solidity initial
            // value of false. Also leave `mintInvocationsRemaining` at
            // solidity initial value of zero, as indicated in this function's
            // documentation.
        } else {
            projectLimitsMintInvocationsPerAddress = true;
            uint256 userMintInvocations = projectUserMintInvocations[
                _projectId
            ][_address];
            // if user has not reached max invocations per address, return
            // remaining invocations
            if (maxInvocationsPerAddress > userMintInvocations) {
                unchecked {
                    // will never underflow due to the check above
                    mintInvocationsRemaining =
                        maxInvocationsPerAddress -
                        userMintInvocations;
                }
            }
            // else user has reached their maximum invocations, so leave
            // `mintInvocationsRemaining` at solidity initial value of zero
        }
    }

    /**
     * @notice Process proof for an address. Returns Merkle root. Included to
     * enable users to easily verify a proof's validity.
     * @param _proof Merkle proof for address.
     * @param _address Address to process.
     * @return merkleRoot Merkle root for `_address` and `_proof`
     */
    function processProofForAddress(bytes32[] calldata _proof, address _address)
        external
        pure
        returns (bytes32)
    {
        return _proof.processProofCalldata(hashAddress(_address));
    }

    /**
     * @notice Gets if price of token is configured, price of minting a
     * token on project `_projectId`, and currency symbol and address to be
     * used as payment. Supersedes any core contract price information.
     * @param _projectId Project ID to get price information for.
     * @return isConfigured true only if token price has been configured on
     * this minter
     * @return tokenPriceInWei current price of token on this minter - invalid
     * if price has not yet been configured
     * @return currencySymbol currency symbol for purchases of project on this
     * minter. This minter always returns "ETH"
     * @return currencyAddress currency address for purchases of project on
     * this minter. This minter always returns null address, reserved for ether
     */
    function getPriceInfo(uint256 _projectId)
        external
        view
        returns (
            bool isConfigured,
            uint256 tokenPriceInWei,
            string memory currencySymbol,
            address currencyAddress
        )
    {
        ProjectConfig storage _projectConfig = projectConfig[_projectId];
        isConfigured = _projectConfig.priceIsConfigured;
        tokenPriceInWei = _projectConfig.pricePerTokenInWei;
        currencySymbol = "ETH";
        currencyAddress = address(0);
    }
}

File 2 of 12 : IGenArt721CoreContractV3.sol
// SPDX-License-Identifier: LGPL-3.0-only
// Created By: Art Blocks Inc.

pragma solidity ^0.8.0;

import "./IAdminACLV0.sol";
/// use the Royalty Registry's IManifold interface for token royalties
import "./IManifold.sol";

interface IGenArt721CoreContractV3 is IManifold {
    /**
     * @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 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 projectIdToAdditionalPayeePrimarySales(uint256 _projectId)
        external
        view
        returns (address payable);

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

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

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

    // @dev Art Blocks primary sales payment address
    function artblocksPrimarySalesAddress()
        external
        view
        returns (address payable);

    /**
     * @notice Backwards-compatible (pre-V3) function returning Art Blocks
     * primary sales payment address (now called artblocksPrimarySalesAddress).
     */
    function artblocksAddress() external view returns (address payable);

    // @dev Percentage of primary sales allocated to Art Blocks
    function artblocksPrimarySalesPercentage() external view returns (uint256);

    /**
     * @notice Backwards-compatible (pre-V3) function returning Art Blocks
     * primary sales percentage (now called artblocksPrimarySalesPercentage).
     */
    function artblocksPercentage() external view returns (uint256);

    // @dev Art Blocks secondary sales royalties payment address
    function artblocksSecondarySalesAddress()
        external
        view
        returns (address payable);

    // @dev Basis points of secondary sales allocated to Art Blocks
    function artblocksSecondarySalesBPS() external view returns (uint256);

    // 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);

    /**
     * @notice Backwards-compatible (pre-V3) function  that gets artist +
     * artist's additional payee royalty data for token ID `_tokenId`.
     * WARNING: Does not include Art Blocks portion of royalties.
     */
    function getRoyaltyData(uint256 _tokenId)
        external
        view
        returns (
            address artistAddress,
            address additionalPayee,
            uint256 additionalPayeePercentage,
            uint256 royaltyFeeByID
        );
}

File 3 of 12 : IDelegationRegistry.sol
// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.17;

/// @dev Source: https://github.com/0xfoobar/delegation-registry/blob/main/src/IDelegationRegistry.sol

/**
 * @title An immutable registry contract to be deployed as a standalone primitive
 * @dev See EIP-5639, new project launches can read previous cold wallet -> hot wallet delegations
 * from here and integrate those permissions into their flow
 */
interface IDelegationRegistry {
    /// @notice Delegation type
    enum DelegationType {
        NONE,
        ALL,
        CONTRACT,
        TOKEN
    }

    /// @notice Info about a single delegation, used for onchain enumeration
    struct DelegationInfo {
        DelegationType type_;
        address vault;
        address delegate;
        address contract_;
        uint256 tokenId;
    }

    /// @notice Info about a single contract-level delegation
    struct ContractDelegation {
        address contract_;
        address delegate;
    }

    /// @notice Info about a single token-level delegation
    struct TokenDelegation {
        address contract_;
        uint256 tokenId;
        address delegate;
    }

    /// @notice Emitted when a user delegates their entire wallet
    event DelegateForAll(address vault, address delegate, bool value);

    /// @notice Emitted when a user delegates a specific contract
    event DelegateForContract(
        address vault,
        address delegate,
        address contract_,
        bool value
    );

    /// @notice Emitted when a user delegates a specific token
    event DelegateForToken(
        address vault,
        address delegate,
        address contract_,
        uint256 tokenId,
        bool value
    );

    /// @notice Emitted when a user revokes all delegations
    event RevokeAllDelegates(address vault);

    /// @notice Emitted when a user revoes all delegations for a given delegate
    event RevokeDelegate(address vault, address delegate);

    /**
     * -----------  WRITE -----------
     */

    /**
     * @notice Allow the delegate to act on your behalf for all contracts
     * @param delegate The hotwallet to act on your behalf
     * @param value Whether to enable or disable delegation for this address, true for setting and false for revoking
     */
    function delegateForAll(address delegate, bool value) external;

    /**
     * @notice Allow the delegate to act on your behalf for a specific contract
     * @param delegate The hotwallet to act on your behalf
     * @param contract_ The address for the contract you're delegating
     * @param value Whether to enable or disable delegation for this address, true for setting and false for revoking
     */
    function delegateForContract(
        address delegate,
        address contract_,
        bool value
    ) external;

    /**
     * @notice Allow the delegate to act on your behalf for a specific token
     * @param delegate The hotwallet to act on your behalf
     * @param contract_ The address for the contract you're delegating
     * @param tokenId The token id for the token you're delegating
     * @param value Whether to enable or disable delegation for this address, true for setting and false for revoking
     */
    function delegateForToken(
        address delegate,
        address contract_,
        uint256 tokenId,
        bool value
    ) external;

    /**
     * @notice Revoke all delegates
     */
    function revokeAllDelegates() external;

    /**
     * @notice Revoke a specific delegate for all their permissions
     * @param delegate The hotwallet to revoke
     */
    function revokeDelegate(address delegate) external;

    /**
     * @notice Remove yourself as a delegate for a specific vault
     * @param vault The vault which delegated to the msg.sender, and should be removed
     */
    function revokeSelf(address vault) external;

    /**
     * -----------  READ -----------
     */

    /**
     * @notice Returns all active delegations a given delegate is able to claim on behalf of
     * @param delegate The delegate that you would like to retrieve delegations for
     * @return info Array of DelegationInfo structs
     */
    function getDelegationsByDelegate(address delegate)
        external
        view
        returns (DelegationInfo[] memory);

    /**
     * @notice Returns an array of wallet-level delegates for a given vault
     * @param vault The cold wallet who issued the delegation
     * @return addresses Array of wallet-level delegates for a given vault
     */
    function getDelegatesForAll(address vault)
        external
        view
        returns (address[] memory);

    /**
     * @notice Returns an array of contract-level delegates for a given vault and contract
     * @param vault The cold wallet who issued the delegation
     * @param contract_ The address for the contract you're delegating
     * @return addresses Array of contract-level delegates for a given vault and contract
     */
    function getDelegatesForContract(address vault, address contract_)
        external
        view
        returns (address[] memory);

    /**
     * @notice Returns an array of contract-level delegates for a given vault's token
     * @param vault The cold wallet who issued the delegation
     * @param contract_ The address for the contract holding the token
     * @param tokenId The token id for the token you're delegating
     * @return addresses Array of contract-level delegates for a given vault's token
     */
    function getDelegatesForToken(
        address vault,
        address contract_,
        uint256 tokenId
    ) external view returns (address[] memory);

    /**
     * @notice Returns all contract-level delegations for a given vault
     * @param vault The cold wallet who issued the delegations
     * @return delegations Array of ContractDelegation structs
     */
    function getContractLevelDelegations(address vault)
        external
        view
        returns (ContractDelegation[] memory delegations);

    /**
     * @notice Returns all token-level delegations for a given vault
     * @param vault The cold wallet who issued the delegations
     * @return delegations Array of TokenDelegation structs
     */
    function getTokenLevelDelegations(address vault)
        external
        view
        returns (TokenDelegation[] memory delegations);

    /**
     * @notice Returns true if the address is delegated to act on the entire vault
     * @param delegate The hotwallet to act on your behalf
     * @param vault The cold wallet who issued the delegation
     */
    function checkDelegateForAll(address delegate, address vault)
        external
        view
        returns (bool);

    /**
     * @notice Returns true if the address is delegated to act on your behalf for a token contract or an entire vault
     * @param delegate The hotwallet to act on your behalf
     * @param contract_ The address for the contract you're delegating
     * @param vault The cold wallet who issued the delegation
     */
    function checkDelegateForContract(
        address delegate,
        address vault,
        address contract_
    ) external view returns (bool);

    /**
     * @notice Returns true if the address is delegated to act on your behalf for a specific token, the token's contract or an entire vault
     * @param delegate The hotwallet to act on your behalf
     * @param contract_ The address for the contract you're delegating
     * @param tokenId The token id for the token you're delegating
     * @param vault The cold wallet who issued the delegation
     */
    function checkDelegateForToken(
        address delegate,
        address vault,
        address contract_,
        uint256 tokenId
    ) external view returns (bool);
}

File 4 of 12 : IFilteredMinterMerkleV0.sol
// SPDX-License-Identifier: LGPL-3.0-only
// Created By: Art Blocks Inc.

import "./IFilteredMinterV1.sol";

pragma solidity ^0.8.0;

/**
 * @title This interface extends the IFilteredMinterV1 interface in order to
 * add support for including Merkle proofs when purchasing.
 * @author Art Blocks Inc.
 */
interface IFilteredMinterMerkleV0 is IFilteredMinterV1 {
    /**
     * @notice Notifies of the contract's default maximum mints allowed per
     * user for a given project, on this minter. This value can be overridden
     * by the artist of any project at any time.
     */
    event DefaultMaxInvocationsPerAddress(
        uint256 defaultMaxInvocationsPerAddress
    );

    // Triggers a purchase of a token from the desired project, to the
    // TX-sending address. Requires Merkle proof.
    function purchase(uint256 _projectId, bytes32[] memory _proof)
        external
        payable
        returns (uint256 tokenId);

    // Triggers a purchase of a token from the desired project, to the specified
    // receiving address. Requires Merkle proof.
    function purchaseTo(
        address _to,
        uint256 _projectId,
        bytes32[] memory _proof
    ) external payable returns (uint256 tokenId);
}

File 5 of 12 : IMinterFilterV0.sol
// SPDX-License-Identifier: LGPL-3.0-only
// Created By: Art Blocks Inc.

pragma solidity ^0.8.0;

interface IMinterFilterV0 {
    /**
     * @notice Approved minter `_minterAddress`.
     */
    event MinterApproved(address indexed _minterAddress, string _minterType);

    /**
     * @notice Revoked approval for minter `_minterAddress`
     */
    event MinterRevoked(address indexed _minterAddress);

    /**
     * @notice Minter `_minterAddress` of type `_minterType`
     * registered for project `_projectId`.
     */
    event ProjectMinterRegistered(
        uint256 indexed _projectId,
        address indexed _minterAddress,
        string _minterType
    );

    /**
     * @notice Any active minter removed for project `_projectId`.
     */
    event ProjectMinterRemoved(uint256 indexed _projectId);

    function genArt721CoreAddress() external returns (address);

    function setMinterForProject(uint256, address) external;

    function removeMinterForProject(uint256) external;

    function mint(
        address _to,
        uint256 _projectId,
        address sender
    ) external returns (uint256);

    function getMinterForProject(uint256) external view returns (address);

    function projectHasMinter(uint256) external view returns (bool);
}

File 6 of 12 : ReentrancyGuard.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol)

pragma solidity ^0.8.0;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

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

    uint256 private _status;

    constructor() {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        // On the first call to nonReentrant, _notEntered will be true
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        // Any calls to nonReentrant after this point will fail
        _status = _ENTERED;

        _;

        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = _NOT_ENTERED;
    }
}

File 7 of 12 : MerkleProof.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/cryptography/MerkleProof.sol)

pragma solidity ^0.8.0;

/**
 * @dev These functions deal with verification of Merkle Tree proofs.
 *
 * The proofs can be generated using the JavaScript library
 * https://github.com/miguelmota/merkletreejs[merkletreejs].
 * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.
 *
 * See `test/utils/cryptography/MerkleProof.test.js` for some examples.
 *
 * WARNING: You should avoid using leaf values that are 64 bytes long prior to
 * hashing, or use a hash function other than keccak256 for hashing leaves.
 * This is because the concatenation of a sorted pair of internal nodes in
 * the merkle tree could be reinterpreted as a leaf value.
 */
library MerkleProof {
    /**
     * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree
     * defined by `root`. For this, a `proof` must be provided, containing
     * sibling hashes on the branch from the leaf to the root of the tree. Each
     * pair of leaves and each pair of pre-images are assumed to be sorted.
     */
    function verify(
        bytes32[] memory proof,
        bytes32 root,
        bytes32 leaf
    ) internal pure returns (bool) {
        return processProof(proof, leaf) == root;
    }

    /**
     * @dev Calldata version of {verify}
     *
     * _Available since v4.7._
     */
    function verifyCalldata(
        bytes32[] calldata proof,
        bytes32 root,
        bytes32 leaf
    ) internal pure returns (bool) {
        return processProofCalldata(proof, leaf) == root;
    }

    /**
     * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up
     * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt
     * hash matches the root of the tree. When processing the proof, the pairs
     * of leafs & pre-images are assumed to be sorted.
     *
     * _Available since v4.4._
     */
    function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {
        bytes32 computedHash = leaf;
        for (uint256 i = 0; i < proof.length; i++) {
            computedHash = _hashPair(computedHash, proof[i]);
        }
        return computedHash;
    }

    /**
     * @dev Calldata version of {processProof}
     *
     * _Available since v4.7._
     */
    function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) {
        bytes32 computedHash = leaf;
        for (uint256 i = 0; i < proof.length; i++) {
            computedHash = _hashPair(computedHash, proof[i]);
        }
        return computedHash;
    }

    /**
     * @dev Returns true if the `leaves` can be proved to be a part of a Merkle tree defined by
     * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}.
     *
     * _Available since v4.7._
     */
    function multiProofVerify(
        bytes32[] memory proof,
        bool[] memory proofFlags,
        bytes32 root,
        bytes32[] memory leaves
    ) internal pure returns (bool) {
        return processMultiProof(proof, proofFlags, leaves) == root;
    }

    /**
     * @dev Calldata version of {multiProofVerify}
     *
     * _Available since v4.7._
     */
    function multiProofVerifyCalldata(
        bytes32[] calldata proof,
        bool[] calldata proofFlags,
        bytes32 root,
        bytes32[] memory leaves
    ) internal pure returns (bool) {
        return processMultiProofCalldata(proof, proofFlags, leaves) == root;
    }

    /**
     * @dev Returns the root of a tree reconstructed from `leaves` and the sibling nodes in `proof`,
     * consuming from one or the other at each step according to the instructions given by
     * `proofFlags`.
     *
     * _Available since v4.7._
     */
    function processMultiProof(
        bytes32[] memory proof,
        bool[] memory proofFlags,
        bytes32[] memory leaves
    ) internal pure returns (bytes32 merkleRoot) {
        // This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by
        // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the
        // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of
        // the merkle tree.
        uint256 leavesLen = leaves.length;
        uint256 totalHashes = proofFlags.length;

        // Check proof validity.
        require(leavesLen + proof.length - 1 == totalHashes, "MerkleProof: invalid multiproof");

        // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using
        // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop".
        bytes32[] memory hashes = new bytes32[](totalHashes);
        uint256 leafPos = 0;
        uint256 hashPos = 0;
        uint256 proofPos = 0;
        // At each step, we compute the next hash using two values:
        // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we
        //   get the next hash.
        // - depending on the flag, either another value for the "main queue" (merging branches) or an element from the
        //   `proof` array.
        for (uint256 i = 0; i < totalHashes; i++) {
            bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
            bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++];
            hashes[i] = _hashPair(a, b);
        }

        if (totalHashes > 0) {
            return hashes[totalHashes - 1];
        } else if (leavesLen > 0) {
            return leaves[0];
        } else {
            return proof[0];
        }
    }

    /**
     * @dev Calldata version of {processMultiProof}
     *
     * _Available since v4.7._
     */
    function processMultiProofCalldata(
        bytes32[] calldata proof,
        bool[] calldata proofFlags,
        bytes32[] memory leaves
    ) internal pure returns (bytes32 merkleRoot) {
        // This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by
        // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the
        // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of
        // the merkle tree.
        uint256 leavesLen = leaves.length;
        uint256 totalHashes = proofFlags.length;

        // Check proof validity.
        require(leavesLen + proof.length - 1 == totalHashes, "MerkleProof: invalid multiproof");

        // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using
        // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop".
        bytes32[] memory hashes = new bytes32[](totalHashes);
        uint256 leafPos = 0;
        uint256 hashPos = 0;
        uint256 proofPos = 0;
        // At each step, we compute the next hash using two values:
        // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we
        //   get the next hash.
        // - depending on the flag, either another value for the "main queue" (merging branches) or an element from the
        //   `proof` array.
        for (uint256 i = 0; i < totalHashes; i++) {
            bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
            bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++];
            hashes[i] = _hashPair(a, b);
        }

        if (totalHashes > 0) {
            return hashes[totalHashes - 1];
        } else if (leavesLen > 0) {
            return leaves[0];
        } else {
            return proof[0];
        }
    }

    function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) {
        return a < b ? _efficientHash(a, b) : _efficientHash(b, a);
    }

    function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, a)
            mstore(0x20, b)
            value := keccak256(0x00, 0x40)
        }
    }
}

File 8 of 12 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @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 amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

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

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

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

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

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

File 9 of 12 : IManifold.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/// @dev Royalty Registry interface, used to support the Royalty Registry.
/// @dev Source: https://github.com/manifoldxyz/royalty-registry-solidity/blob/main/contracts/specs/IManifold.sol

/// @author: manifold.xyz

/**
 * @dev Royalty interface for creator core classes
 */
interface IManifold {
    /**
     * @dev Get royalites of a token.  Returns list of receivers and basisPoints
     *
     *  bytes4(keccak256('getRoyalties(uint256)')) == 0xbb3bafd6
     *
     *  => 0xbb3bafd6 = 0xbb3bafd6
     */
    function getRoyalties(uint256 tokenId)
        external
        view
        returns (address payable[] memory, uint256[] memory);
}

File 10 of 12 : IAdminACLV0.sol
// 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);
}

File 11 of 12 : IFilteredMinterV1.sol
// SPDX-License-Identifier: LGPL-3.0-only
// Created By: Art Blocks Inc.

import "./IFilteredMinterV0.sol";

pragma solidity ^0.8.0;

/**
 * @title This interface extends the IFilteredMinterV0 interface in order to
 * add support for generic project minter configuration updates.
 * @dev keys represent strings of finite length encoded in bytes32 to minimize
 * gas.
 * @author Art Blocks Inc.
 */
interface IFilteredMinterV1 is IFilteredMinterV0 {
    /// ANY
    /**
     * @notice Generic project minter configuration event. Removes key `_key`
     * for project `_projectId`.
     */
    event ConfigKeyRemoved(uint256 indexed _projectId, bytes32 _key);

    /// BOOL
    /**
     * @notice Generic project minter configuration event. Sets value of key
     * `_key` to `_value` for project `_projectId`.
     */
    event ConfigValueSet(uint256 indexed _projectId, bytes32 _key, bool _value);

    /// UINT256
    /**
     * @notice Generic project minter configuration event. Sets value of key
     * `_key` to `_value` for project `_projectId`.
     */
    event ConfigValueSet(
        uint256 indexed _projectId,
        bytes32 _key,
        uint256 _value
    );

    /**
     * @notice Generic project minter configuration event. Adds value `_value`
     * to the set of uint256 at key `_key` for project `_projectId`.
     */
    event ConfigValueAddedToSet(
        uint256 indexed _projectId,
        bytes32 _key,
        uint256 _value
    );

    /**
     * @notice Generic project minter configuration event. Removes value
     * `_value` to the set of uint256 at key `_key` for project `_projectId`.
     */
    event ConfigValueRemovedFromSet(
        uint256 indexed _projectId,
        bytes32 _key,
        uint256 _value
    );

    /// ADDRESS
    /**
     * @notice Generic project minter configuration event. Sets value of key
     * `_key` to `_value` for project `_projectId`.
     */
    event ConfigValueSet(
        uint256 indexed _projectId,
        bytes32 _key,
        address _value
    );

    /**
     * @notice Generic project minter configuration event. Adds value `_value`
     * to the set of addresses at key `_key` for project `_projectId`.
     */
    event ConfigValueAddedToSet(
        uint256 indexed _projectId,
        bytes32 _key,
        address _value
    );

    /**
     * @notice Generic project minter configuration event. Removes value
     * `_value` to the set of addresses at key `_key` for project `_projectId`.
     */
    event ConfigValueRemovedFromSet(
        uint256 indexed _projectId,
        bytes32 _key,
        address _value
    );

    /// BYTES32
    /**
     * @notice Generic project minter configuration event. Sets value of key
     * `_key` to `_value` for project `_projectId`.
     */
    event ConfigValueSet(
        uint256 indexed _projectId,
        bytes32 _key,
        bytes32 _value
    );

    /**
     * @notice Generic project minter configuration event. Adds value `_value`
     * to the set of bytes32 at key `_key` for project `_projectId`.
     */
    event ConfigValueAddedToSet(
        uint256 indexed _projectId,
        bytes32 _key,
        bytes32 _value
    );

    /**
     * @notice Generic project minter configuration event. Removes value
     * `_value` to the set of bytes32 at key `_key` for project `_projectId`.
     */
    event ConfigValueRemovedFromSet(
        uint256 indexed _projectId,
        bytes32 _key,
        bytes32 _value
    );

    /**
     * @dev Strings not supported. Recommend conversion of (short) strings to
     * bytes32 to remain gas-efficient.
     */
}

File 12 of 12 : IFilteredMinterV0.sol
// SPDX-License-Identifier: LGPL-3.0-only
// Created By: Art Blocks Inc.

pragma solidity ^0.8.0;

interface IFilteredMinterV0 {
    /**
     * @notice Price per token in wei updated for project `_projectId` to
     * `_pricePerTokenInWei`.
     */
    event PricePerTokenInWeiUpdated(
        uint256 indexed _projectId,
        uint256 indexed _pricePerTokenInWei
    );

    /**
     * @notice Currency updated for project `_projectId` to symbol
     * `_currencySymbol` and address `_currencyAddress`.
     */
    event ProjectCurrencyInfoUpdated(
        uint256 indexed _projectId,
        address indexed _currencyAddress,
        string _currencySymbol
    );

    /// togglePurchaseToDisabled updated
    event PurchaseToDisabledUpdated(
        uint256 indexed _projectId,
        bool _purchaseToDisabled
    );

    // getter function of public variable
    function minterType() external view returns (string memory);

    function genArt721CoreAddress() external returns (address);

    function minterFilterAddress() external returns (address);

    // Triggers a purchase of a token from the desired project, to the
    // TX-sending address.
    function purchase(uint256 _projectId)
        external
        payable
        returns (uint256 tokenId);

    // Triggers a purchase of a token from the desired project, to the specified
    // receiving address.
    function purchaseTo(address _to, uint256 _projectId)
        external
        payable
        returns (uint256 tokenId);

    // Toggles the ability for `purchaseTo` to be called directly with a
    // specified receiving address that differs from the TX-sending address.
    function togglePurchaseToDisabled(uint256 _projectId) external;

    // Called to make the minter contract aware of the max invocations for a
    // given project.
    function setProjectMaxInvocations(uint256 _projectId) external;

    // Gets if token price is configured, token price in wei, currency symbol,
    // and currency address, assuming this is project's minter.
    // Supersedes any defined core price.
    function getPriceInfo(uint256 _projectId)
        external
        view
        returns (
            bool isConfigured,
            uint256 tokenPriceInWei,
            string memory currencySymbol,
            address currencyAddress
        );
}

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

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_genArt721Address","type":"address"},{"internalType":"address","name":"_minterFilter","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_projectId","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"_key","type":"bytes32"}],"name":"ConfigKeyRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_projectId","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"_key","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"_value","type":"uint256"}],"name":"ConfigValueAddedToSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_projectId","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"_key","type":"bytes32"},{"indexed":false,"internalType":"address","name":"_value","type":"address"}],"name":"ConfigValueAddedToSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_projectId","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"_key","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"_value","type":"bytes32"}],"name":"ConfigValueAddedToSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_projectId","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"_key","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"_value","type":"uint256"}],"name":"ConfigValueRemovedFromSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_projectId","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"_key","type":"bytes32"},{"indexed":false,"internalType":"address","name":"_value","type":"address"}],"name":"ConfigValueRemovedFromSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_projectId","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"_key","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"_value","type":"bytes32"}],"name":"ConfigValueRemovedFromSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_projectId","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"_key","type":"bytes32"},{"indexed":false,"internalType":"bool","name":"_value","type":"bool"}],"name":"ConfigValueSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_projectId","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"_key","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"_value","type":"uint256"}],"name":"ConfigValueSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_projectId","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"_key","type":"bytes32"},{"indexed":false,"internalType":"address","name":"_value","type":"address"}],"name":"ConfigValueSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_projectId","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"_key","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"_value","type":"bytes32"}],"name":"ConfigValueSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"defaultMaxInvocationsPerAddress","type":"uint256"}],"name":"DefaultMaxInvocationsPerAddress","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_projectId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"_pricePerTokenInWei","type":"uint256"}],"name":"PricePerTokenInWeiUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_projectId","type":"uint256"},{"indexed":true,"internalType":"address","name":"_currencyAddress","type":"address"},{"indexed":false,"internalType":"string","name":"_currencySymbol","type":"string"}],"name":"ProjectCurrencyInfoUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_projectId","type":"uint256"},{"indexed":false,"internalType":"bool","name":"_purchaseToDisabled","type":"bool"}],"name":"PurchaseToDisabledUpdated","type":"event"},{"inputs":[],"name":"DEFAULT_MAX_INVOCATIONS_PER_ADDRESS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DELEGATION_REGISTRY_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"genArt721CoreAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_projectId","type":"uint256"}],"name":"getPriceInfo","outputs":[{"internalType":"bool","name":"isConfigured","type":"bool"},{"internalType":"uint256","name":"tokenPriceInWei","type":"uint256"},{"internalType":"string","name":"currencySymbol","type":"string"},{"internalType":"address","name":"currencyAddress","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"}],"name":"hashAddress","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"minterFilterAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minterType","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"_proof","type":"bytes32[]"},{"internalType":"address","name":"_address","type":"address"}],"name":"processProofForAddress","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"projectConfig","outputs":[{"internalType":"bool","name":"maxHasBeenInvoked","type":"bool"},{"internalType":"bool","name":"priceIsConfigured","type":"bool"},{"internalType":"bool","name":"useMaxInvocationsPerAddressOverride","type":"bool"},{"internalType":"uint24","name":"maxInvocationsPerAddressOverride","type":"uint24"},{"internalType":"uint24","name":"maxInvocations","type":"uint24"},{"internalType":"uint256","name":"pricePerTokenInWei","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_projectId","type":"uint256"}],"name":"projectMaxHasBeenInvoked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_projectId","type":"uint256"}],"name":"projectMaxInvocations","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_projectId","type":"uint256"}],"name":"projectMaxInvocationsPerAddress","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"projectMerkleRoot","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_projectId","type":"uint256"},{"internalType":"address","name":"_address","type":"address"}],"name":"projectRemainingInvocationsForAddress","outputs":[{"internalType":"bool","name":"projectLimitsMintInvocationsPerAddress","type":"bool"},{"internalType":"uint256","name":"mintInvocationsRemaining","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"projectUserMintInvocations","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_projectId","type":"uint256"},{"internalType":"bytes32[]","name":"_proof","type":"bytes32[]"}],"name":"purchase","outputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"purchase","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_projectId","type":"uint256"},{"internalType":"bytes32[]","name":"_proof","type":"bytes32[]"}],"name":"purchaseTo","outputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"purchaseTo","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_projectId","type":"uint256"},{"internalType":"bytes32[]","name":"_proof","type":"bytes32[]"},{"internalType":"address","name":"_vault","type":"address"}],"name":"purchaseTo","outputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_projectId","type":"uint256"},{"internalType":"bytes32[]","name":"_proof","type":"bytes32[]"},{"internalType":"address","name":"_vault","type":"address"}],"name":"purchaseTo_kem","outputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_projectId","type":"uint256"},{"internalType":"bytes32[]","name":"_proof","type":"bytes32[]"}],"name":"purchase_gD5","outputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_projectId","type":"uint256"},{"internalType":"uint24","name":"_maxInvocationsPerAddress","type":"uint24"}],"name":"setProjectInvocationsPerAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_projectId","type":"uint256"}],"name":"setProjectMaxInvocations","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_projectId","type":"uint256"}],"name":"togglePurchaseToDisabled","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_projectId","type":"uint256"},{"internalType":"bytes32","name":"_root","type":"bytes32"}],"name":"updateMerkleRoot","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_projectId","type":"uint256"},{"internalType":"uint256","name":"_pricePerTokenInWei","type":"uint256"}],"name":"updatePricePerTokenInWei","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_projectId","type":"uint256"},{"internalType":"bytes32[]","name":"_proof","type":"bytes32[]"},{"internalType":"address","name":"_address","type":"address"}],"name":"verifyAddress","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]

6101206040523480156200001257600080fd5b5060405162001df138038062001df183398101604081905262000035916200018e565b600160009081556001600160a01b0380841660a081905260c08190526d76a84fef008cdabe6409d2fe638b60805290831660e0819052610100819052604080516392a10f8360e01b81529051929391926392a10f83926004808401936020939290839003909101908290875af1158015620000b4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000da9190620001c6565b6001600160a01b031614620001355760405162461bcd60e51b815260206004820152601860248201527f496c6c6567616c20636f6e74726163742070616972696e670000000000000000604482015260640160405180910390fd5b604051600181527fb004e34bc1718c504fde68324f2eba80b0329056f240eaaa6803c286c4b9e7ed9060200160405180910390a15050620001eb565b80516001600160a01b03811681146200018957600080fd5b919050565b60008060408385031215620001a257600080fd5b620001ad8362000171565b9150620001bd6020840162000171565b90509250929050565b600060208284031215620001d957600080fd5b620001e48262000171565b9392505050565b60805160a05160c05160e05161010051611b976200025a6000396000610a050152600061055f015260008181610b9101528181610ce001528181610e730152818161101f0152818161117f01526112d80152600081816103a501526107b9015260006107e40152611b976000f3fe6080604052600436106101535760003560e01c806392a10f83116100bc57806392a10f83146103935780639775f86f146103df578063aea7d3b9146103f4578063b2543d021461042c578063c15127c01461044e578063c71b1b7114610461578063cc3352bf14610500578063d684ec6714610520578063da7e7c501461017e578063dd85582f1461054d578063e9d1e8ac14610581578063efef39a1146105c8578063f1e33115146105d6578063f7bd4b88146105f657600080fd5b806157b6146101585780615aa11461017e57806315bed159146101915780631ec2e523146101b1578063202c5805146101d15780633aa5fe59146101e457806340d1397e14610204578063462add461461022657806356690aaf146102665780636b453e701461029f5780636cb9b7ff146102d65780636ede4ade146102f6578063774159c614610316578063891407c014610380575b600080fd5b61016b61016636600461166e565b610616565b6040519081526020015b60405180910390f35b61016b61018c3660046116e1565b610abd565b34801561019d57600080fd5b5061016b6101ac36600461172c565b610ad5565b3480156101bd57600080fd5b5061016b6101cc366004611745565b610b0f565b61016b6101df36600461179b565b610b26565b3480156101f057600080fd5b5061016b6101ff3660046117f6565b610b3f565b34801561021057600080fd5b5061022461021f36600461172c565b610b79565b005b34801561023257600080fd5b5061025661024136600461172c565b60009081526001602052604090205460ff1690565b6040519015158152602001610175565b34801561027257600080fd5b5061016b61028136600461172c565b600090815260016020526040902054600160301b900462ffffff1690565b3480156102ab57600080fd5b506102bf6102ba36600461181a565b610c73565b604080519215158352602083019190915201610175565b3480156102e257600080fd5b506102246102f136600461184a565b610cc8565b34801561030257600080fd5b5061025661031136600461186c565b610dd6565b34801561032257600080fd5b5061037061033136600461172c565b600090815260016020818152604080842080549301548151808301909252600382526208aa8960eb1b9282019290925261010090920460ff1693909290565b6040516101759493929190611910565b61016b61038e36600461194a565b610dfb565b34801561039f57600080fd5b506103c77f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610175565b3480156103eb57600080fd5b5061016b600181565b34801561040057600080fd5b5061016b61040f36600461181a565b600360209081526000928352604080842090915290825290205481565b34801561043857600080fd5b506103c76d76a84fef008cdabe6409d2fe638b81565b61016b61045c36600461166e565b610e42565b34801561046d57600080fd5b506104c461047c36600461172c565b6001602081905260009182526040909120805491015460ff8083169261010081048216926201000082049092169162ffffff63010000008304811692600160301b9004169086565b60408051961515875294151560208701529215159385019390935262ffffff9081166060850152909116608083015260a082015260c001610175565b34801561050c57600080fd5b5061022461051b366004611976565b610e5b565b34801561052c57600080fd5b5061016b61053b36600461172c565b60026020526000908152604090205481565b34801561055957600080fd5b506103c77f000000000000000000000000000000000000000000000000000000000000000081565b34801561058d57600080fd5b506105bb6040518060400160405280600e81526020016d26b4b73a32b926b2b935b632ab1960911b81525081565b60405161017591906119a3565b61016b61038e36600461172c565b3480156105e257600080fd5b506102246105f136600461184a565b611007565b34801561060257600080fd5b5061022461061136600461172c565b611166565b600060026000540361066f5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064015b60405180910390fd5b60026000908155858152600160205260409020805460ff16156106e25760405162461bcd60e51b815260206004820152602560248201527f4d6178696d756d206e756d626572206f6620696e766f636174696f6e732072656044820152641858da195960da1b6064820152608401610666565b6001810154348111156107375760405162461bcd60e51b815260206004820181905260248201527f4d7573742073656e64206d696e696d756d2076616c756520746f206d696e74216044820152606401610666565b8154610100900460ff166107845760405162461bcd60e51b8152602060048201526014602482015273141c9a58d9481b9bdd0818dbdb999a59dd5c995960621b6044820152606401610666565b336001600160a01b038516156108a55760405163090c9a2d60e41b81523360048201526001600160a01b0386811660248301527f0000000000000000000000000000000000000000000000000000000000000000811660448301526000917f0000000000000000000000000000000000000000000000000000000000000000909116906390c9a2d090606401602060405180830381865afa15801561082d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061085191906119cb565b9050806108a05760405162461bcd60e51b815260206004820152601e60248201527f496e76616c69642064656c65676174652d7661756c742070616972696e6700006044820152606401610666565b859150505b6108b188888884610dd6565b6108f45760405162461bcd60e51b815260206004820152601460248201527324b73b30b634b21026b2b935b63290383937b7b360611b6044820152606401610666565b825460009062010000900460ff1661090d57600161091c565b83546301000000900462ffffff165b60008a81526003602090815260408083206001600160a01b038716845290915290205490915081118061094d575080155b6109b35760405162461bcd60e51b815260206004820152603160248201527f4d6178696d756d206e756d626572206f6620696e766f636174696f6e732070656044820152701c881859191c995cdcc81c995858da1959607a1b6064820152608401610666565b60008981526003602090815260408083206001600160a01b0386811680865291909352928190208054600101905551630d4d151360e01b81528c82166004820152602481018c905260448101929092527f00000000000000000000000000000000000000000000000000000000000000001690630d4d1513906064016020604051808303816000875af1158015610a4e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a7291906119e6565b845490955060001962ffffff600160301b90920482160116620f4240860603610aa157835460ff191660011784555b610aab898461122a565b50505050600160005595945050505050565b6000610acd338585856000610616565b949350505050565b6000818152600160205260408120805462010000900460ff1615610b0657546301000000900462ffffff1692915050565b50600192915050565b6000610acd610b1d83610b3f565b85908590611573565b6000610b36858585856000610616565b95945050505050565b6040516001600160601b0319606083901b166020820152600090603401604051602081830303815290604052805190602001209050919050565b60405163a47d29cb60e01b81526004810182905281907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063a47d29cb90602401602060405180830381865afa158015610be0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c0491906119ff565b6001600160a01b0316336001600160a01b031614610c345760405162461bcd60e51b815260040161066690611a1c565b60405162461bcd60e51b81526020600482015260146024820152731058dd1a5bdb881b9bdd081cdd5c1c1bdc9d195960621b6044820152606401610666565b6000806000610c8185610ad5565b90508015610cc05760008581526003602090815260408083206001600160a01b03881684529091529020546001935080821115610cbe5780820392505b505b509250929050565b60405163a47d29cb60e01b81526004810183905282907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063a47d29cb90602401602060405180830381865afa158015610d2f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d5391906119ff565b6001600160a01b0316336001600160a01b031614610d835760405162461bcd60e51b815260040161066690611a1c565b6000838152600160208190526040808320918201859055815461ff0019166101001790915551839185917f26118a27aca826f829f3bfe21b140b4455c00b434849bd0da50d1e1a9720fb5c9190a3505050565b600084815260026020526040812054610b3690610df284610b3f565b869186916115bf565b60405162461bcd60e51b815260206004820152601960248201527826bab9ba10383937bb34b2329026b2b935b63290383937b7b360391b6044820152600090606401610666565b6000610e518686868686610616565b9695505050505050565b60405163a47d29cb60e01b81526004810183905282907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063a47d29cb90602401602060405180830381865afa158015610ec2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ee691906119ff565b6001600160a01b0316336001600160a01b031614610f165760405162461bcd60e51b815260040161066690611a1c565b600083815260016020819052604091829020805462ffffff861663010000000265ffffffff0000199091161762010000178155915185917fc594e23b9382359e253cdaba84b0aefe5ad09ccfd5706891673743b37229c2d291610fa091797573654d61784d696e7473506572416464724f7665727269646560301b82521515602082015260400190565b60405180910390a260408051766d61784d696e7473506572416464724f7665727269646560481b815262ffffff8516602082015285917f8a5820ca7148caeda3176e8d60a3bb413b4bcca45922ac2178b1ee191fe320eb910160405180910390a250505050565b60405163a47d29cb60e01b81526004810183905282907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063a47d29cb90602401602060405180830381865afa15801561106e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061109291906119ff565b6001600160a01b0316336001600160a01b0316146110c25760405162461bcd60e51b815260040161066690611a1c565b816111075760405162461bcd60e51b8152602060048201526015602482015274149bdbdd081b5d5cdd081899481c1c9bdd9a591959605a1b6044820152606401610666565b6000838152600260209081526040918290208490558151691b595c9adb19549bdbdd60b21b815290810184905284917f729c0261c7e3c976b9a392f2bb08064d7a03c82f9f1473ab0ee284c985df0815910160405180910390a2505050565b604051630ea5613f60e01b8152600481018290526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690630ea5613f9060240160c060405180830381865afa1580156111ce573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111f29190611a41565b50505060009485525060016020526040909320805462ffffff909416600160301b0262ffffff60301b19909416939093179092555050565b341561156f5760008061123d8334611ab6565b905080156112cd5760405133908290600081818185875af1925050503d8060008114611285576040519150601f19603f3d011682016040523d82523d6000602084013e61128a565b606091505b505080925050816112cd5760405162461bcd60e51b815260206004820152600d60248201526c1499599d5b990819985a5b1959609a1b6044820152606401610666565b6000806000806000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638639415b8b8b6040518363ffffffff1660e01b815260040161132d929190918252602082015260400190565b60c060405180830381865afa15801561134a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061136e9190611ac9565b9550955095509550955095506000861115611420576040516001600160a01b038616908790600081818185875af1925050503d80600081146113cc576040519150601f19603f3d011682016040523d82523d6000602084013e6113d1565b606091505b505080985050876114205760405162461bcd60e51b8152602060048201526019602482015278105c9d08109b1bd8dadcc81c185e5b595b9d0819985a5b1959603a1b6044820152606401610666565b83156114bf576040516001600160a01b038416908590600081818185875af1925050503d806000811461146f576040519150601f19603f3d011682016040523d82523d6000602084013e611474565b606091505b505080985050876114bf5760405162461bcd60e51b8152602060048201526015602482015274105c9d1a5cdd081c185e5b595b9d0819985a5b1959605a1b6044820152606401610666565b8115611566576040516001600160a01b038216908390600081818185875af1925050503d806000811461150e576040519150601f19603f3d011682016040523d82523d6000602084013e611513565b606091505b505080985050876115665760405162461bcd60e51b815260206004820152601f60248201527f4164646974696f6e616c205061796565207061796d656e74206661696c6564006044820152606401610666565b50505050505050505b5050565b600081815b848110156115b6576115a28287878481811061159657611596611b32565b905060200201356115d7565b9150806115ae81611b48565b915050611578565b50949350505050565b6000826115cd868685611573565b1495945050505050565b60008183106115f3576000828152602084905260409020611602565b60008381526020839052604090205b90505b92915050565b6001600160a01b038116811461162057600080fd5b50565b60008083601f84011261163557600080fd5b5081356001600160401b0381111561164c57600080fd5b6020830191508360208260051b850101111561166757600080fd5b9250929050565b60008060008060006080868803121561168657600080fd5b85356116918161160b565b94506020860135935060408601356001600160401b038111156116b357600080fd5b6116bf88828901611623565b90945092505060608601356116d38161160b565b809150509295509295909350565b6000806000604084860312156116f657600080fd5b8335925060208401356001600160401b0381111561171357600080fd5b61171f86828701611623565b9497909650939450505050565b60006020828403121561173e57600080fd5b5035919050565b60008060006040848603121561175a57600080fd5b83356001600160401b0381111561177057600080fd5b61177c86828701611623565b90945092505060208401356117908161160b565b809150509250925092565b600080600080606085870312156117b157600080fd5b84356117bc8161160b565b93506020850135925060408501356001600160401b038111156117de57600080fd5b6117ea87828801611623565b95989497509550505050565b60006020828403121561180857600080fd5b81356118138161160b565b9392505050565b6000806040838503121561182d57600080fd5b82359150602083013561183f8161160b565b809150509250929050565b6000806040838503121561185d57600080fd5b50508035926020909101359150565b6000806000806060858703121561188257600080fd5b8435935060208501356001600160401b0381111561189f57600080fd5b6118ab87828801611623565b90945092505060408501356118bf8161160b565b939692955090935050565b6000815180845260005b818110156118f0576020818501810151868301820152016118d4565b506000602082860101526020601f19601f83011685010191505092915050565b841515815283602082015260806040820152600061193160808301856118ca565b905060018060a01b038316606083015295945050505050565b6000806040838503121561195d57600080fd5b82356119688161160b565b946020939093013593505050565b6000806040838503121561198957600080fd5b82359150602083013562ffffff8116811461183f57600080fd5b60208152600061160260208301846118ca565b805180151581146119c657600080fd5b919050565b6000602082840312156119dd57600080fd5b611602826119b6565b6000602082840312156119f857600080fd5b5051919050565b600060208284031215611a1157600080fd5b81516118138161160b565b6020808252600b908201526a13db9b1e48105c9d1a5cdd60aa1b604082015260600190565b60008060008060008060c08789031215611a5a57600080fd5b8651955060208701519450611a71604088016119b6565b9350611a7f606088016119b6565b925060808701519150611a9460a088016119b6565b90509295509295509295565b634e487b7160e01b600052601160045260246000fd5b8181038181111561160557611605611aa0565b60008060008060008060c08789031215611ae257600080fd5b865195506020870151611af48161160b565b604088015160608901519196509450611b0c8161160b565b608088015160a08901519194509250611b248161160b565b809150509295509295509295565b634e487b7160e01b600052603260045260246000fd5b600060018201611b5a57611b5a611aa0565b506001019056fea26469706673582212201a49e1efff7b0fc2d6e9c294eac51760b8f211bed47702c3d563dea63f83575d64736f6c63430008110033000000000000000000000000942bc2d3e7a589fe5bd4a5c6ef9727dfd82f5c8a0000000000000000000000003f4bbde879f9bb0e95aea08ff12f55e171495c8f

Deployed Bytecode

0x6080604052600436106101535760003560e01c806392a10f83116100bc57806392a10f83146103935780639775f86f146103df578063aea7d3b9146103f4578063b2543d021461042c578063c15127c01461044e578063c71b1b7114610461578063cc3352bf14610500578063d684ec6714610520578063da7e7c501461017e578063dd85582f1461054d578063e9d1e8ac14610581578063efef39a1146105c8578063f1e33115146105d6578063f7bd4b88146105f657600080fd5b806157b6146101585780615aa11461017e57806315bed159146101915780631ec2e523146101b1578063202c5805146101d15780633aa5fe59146101e457806340d1397e14610204578063462add461461022657806356690aaf146102665780636b453e701461029f5780636cb9b7ff146102d65780636ede4ade146102f6578063774159c614610316578063891407c014610380575b600080fd5b61016b61016636600461166e565b610616565b6040519081526020015b60405180910390f35b61016b61018c3660046116e1565b610abd565b34801561019d57600080fd5b5061016b6101ac36600461172c565b610ad5565b3480156101bd57600080fd5b5061016b6101cc366004611745565b610b0f565b61016b6101df36600461179b565b610b26565b3480156101f057600080fd5b5061016b6101ff3660046117f6565b610b3f565b34801561021057600080fd5b5061022461021f36600461172c565b610b79565b005b34801561023257600080fd5b5061025661024136600461172c565b60009081526001602052604090205460ff1690565b6040519015158152602001610175565b34801561027257600080fd5b5061016b61028136600461172c565b600090815260016020526040902054600160301b900462ffffff1690565b3480156102ab57600080fd5b506102bf6102ba36600461181a565b610c73565b604080519215158352602083019190915201610175565b3480156102e257600080fd5b506102246102f136600461184a565b610cc8565b34801561030257600080fd5b5061025661031136600461186c565b610dd6565b34801561032257600080fd5b5061037061033136600461172c565b600090815260016020818152604080842080549301548151808301909252600382526208aa8960eb1b9282019290925261010090920460ff1693909290565b6040516101759493929190611910565b61016b61038e36600461194a565b610dfb565b34801561039f57600080fd5b506103c77f000000000000000000000000942bc2d3e7a589fe5bd4a5c6ef9727dfd82f5c8a81565b6040516001600160a01b039091168152602001610175565b3480156103eb57600080fd5b5061016b600181565b34801561040057600080fd5b5061016b61040f36600461181a565b600360209081526000928352604080842090915290825290205481565b34801561043857600080fd5b506103c76d76a84fef008cdabe6409d2fe638b81565b61016b61045c36600461166e565b610e42565b34801561046d57600080fd5b506104c461047c36600461172c565b6001602081905260009182526040909120805491015460ff8083169261010081048216926201000082049092169162ffffff63010000008304811692600160301b9004169086565b60408051961515875294151560208701529215159385019390935262ffffff9081166060850152909116608083015260a082015260c001610175565b34801561050c57600080fd5b5061022461051b366004611976565b610e5b565b34801561052c57600080fd5b5061016b61053b36600461172c565b60026020526000908152604090205481565b34801561055957600080fd5b506103c77f0000000000000000000000003f4bbde879f9bb0e95aea08ff12f55e171495c8f81565b34801561058d57600080fd5b506105bb6040518060400160405280600e81526020016d26b4b73a32b926b2b935b632ab1960911b81525081565b60405161017591906119a3565b61016b61038e36600461172c565b3480156105e257600080fd5b506102246105f136600461184a565b611007565b34801561060257600080fd5b5061022461061136600461172c565b611166565b600060026000540361066f5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064015b60405180910390fd5b60026000908155858152600160205260409020805460ff16156106e25760405162461bcd60e51b815260206004820152602560248201527f4d6178696d756d206e756d626572206f6620696e766f636174696f6e732072656044820152641858da195960da1b6064820152608401610666565b6001810154348111156107375760405162461bcd60e51b815260206004820181905260248201527f4d7573742073656e64206d696e696d756d2076616c756520746f206d696e74216044820152606401610666565b8154610100900460ff166107845760405162461bcd60e51b8152602060048201526014602482015273141c9a58d9481b9bdd0818dbdb999a59dd5c995960621b6044820152606401610666565b336001600160a01b038516156108a55760405163090c9a2d60e41b81523360048201526001600160a01b0386811660248301527f000000000000000000000000942bc2d3e7a589fe5bd4a5c6ef9727dfd82f5c8a811660448301526000917f00000000000000000000000000000000000076a84fef008cdabe6409d2fe638b909116906390c9a2d090606401602060405180830381865afa15801561082d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061085191906119cb565b9050806108a05760405162461bcd60e51b815260206004820152601e60248201527f496e76616c69642064656c65676174652d7661756c742070616972696e6700006044820152606401610666565b859150505b6108b188888884610dd6565b6108f45760405162461bcd60e51b815260206004820152601460248201527324b73b30b634b21026b2b935b63290383937b7b360611b6044820152606401610666565b825460009062010000900460ff1661090d57600161091c565b83546301000000900462ffffff165b60008a81526003602090815260408083206001600160a01b038716845290915290205490915081118061094d575080155b6109b35760405162461bcd60e51b815260206004820152603160248201527f4d6178696d756d206e756d626572206f6620696e766f636174696f6e732070656044820152701c881859191c995cdcc81c995858da1959607a1b6064820152608401610666565b60008981526003602090815260408083206001600160a01b0386811680865291909352928190208054600101905551630d4d151360e01b81528c82166004820152602481018c905260448101929092527f0000000000000000000000003f4bbde879f9bb0e95aea08ff12f55e171495c8f1690630d4d1513906064016020604051808303816000875af1158015610a4e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a7291906119e6565b845490955060001962ffffff600160301b90920482160116620f4240860603610aa157835460ff191660011784555b610aab898461122a565b50505050600160005595945050505050565b6000610acd338585856000610616565b949350505050565b6000818152600160205260408120805462010000900460ff1615610b0657546301000000900462ffffff1692915050565b50600192915050565b6000610acd610b1d83610b3f565b85908590611573565b6000610b36858585856000610616565b95945050505050565b6040516001600160601b0319606083901b166020820152600090603401604051602081830303815290604052805190602001209050919050565b60405163a47d29cb60e01b81526004810182905281907f000000000000000000000000942bc2d3e7a589fe5bd4a5c6ef9727dfd82f5c8a6001600160a01b03169063a47d29cb90602401602060405180830381865afa158015610be0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c0491906119ff565b6001600160a01b0316336001600160a01b031614610c345760405162461bcd60e51b815260040161066690611a1c565b60405162461bcd60e51b81526020600482015260146024820152731058dd1a5bdb881b9bdd081cdd5c1c1bdc9d195960621b6044820152606401610666565b6000806000610c8185610ad5565b90508015610cc05760008581526003602090815260408083206001600160a01b03881684529091529020546001935080821115610cbe5780820392505b505b509250929050565b60405163a47d29cb60e01b81526004810183905282907f000000000000000000000000942bc2d3e7a589fe5bd4a5c6ef9727dfd82f5c8a6001600160a01b03169063a47d29cb90602401602060405180830381865afa158015610d2f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d5391906119ff565b6001600160a01b0316336001600160a01b031614610d835760405162461bcd60e51b815260040161066690611a1c565b6000838152600160208190526040808320918201859055815461ff0019166101001790915551839185917f26118a27aca826f829f3bfe21b140b4455c00b434849bd0da50d1e1a9720fb5c9190a3505050565b600084815260026020526040812054610b3690610df284610b3f565b869186916115bf565b60405162461bcd60e51b815260206004820152601960248201527826bab9ba10383937bb34b2329026b2b935b63290383937b7b360391b6044820152600090606401610666565b6000610e518686868686610616565b9695505050505050565b60405163a47d29cb60e01b81526004810183905282907f000000000000000000000000942bc2d3e7a589fe5bd4a5c6ef9727dfd82f5c8a6001600160a01b03169063a47d29cb90602401602060405180830381865afa158015610ec2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ee691906119ff565b6001600160a01b0316336001600160a01b031614610f165760405162461bcd60e51b815260040161066690611a1c565b600083815260016020819052604091829020805462ffffff861663010000000265ffffffff0000199091161762010000178155915185917fc594e23b9382359e253cdaba84b0aefe5ad09ccfd5706891673743b37229c2d291610fa091797573654d61784d696e7473506572416464724f7665727269646560301b82521515602082015260400190565b60405180910390a260408051766d61784d696e7473506572416464724f7665727269646560481b815262ffffff8516602082015285917f8a5820ca7148caeda3176e8d60a3bb413b4bcca45922ac2178b1ee191fe320eb910160405180910390a250505050565b60405163a47d29cb60e01b81526004810183905282907f000000000000000000000000942bc2d3e7a589fe5bd4a5c6ef9727dfd82f5c8a6001600160a01b03169063a47d29cb90602401602060405180830381865afa15801561106e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061109291906119ff565b6001600160a01b0316336001600160a01b0316146110c25760405162461bcd60e51b815260040161066690611a1c565b816111075760405162461bcd60e51b8152602060048201526015602482015274149bdbdd081b5d5cdd081899481c1c9bdd9a591959605a1b6044820152606401610666565b6000838152600260209081526040918290208490558151691b595c9adb19549bdbdd60b21b815290810184905284917f729c0261c7e3c976b9a392f2bb08064d7a03c82f9f1473ab0ee284c985df0815910160405180910390a2505050565b604051630ea5613f60e01b8152600481018290526000907f000000000000000000000000942bc2d3e7a589fe5bd4a5c6ef9727dfd82f5c8a6001600160a01b031690630ea5613f9060240160c060405180830381865afa1580156111ce573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111f29190611a41565b50505060009485525060016020526040909320805462ffffff909416600160301b0262ffffff60301b19909416939093179092555050565b341561156f5760008061123d8334611ab6565b905080156112cd5760405133908290600081818185875af1925050503d8060008114611285576040519150601f19603f3d011682016040523d82523d6000602084013e61128a565b606091505b505080925050816112cd5760405162461bcd60e51b815260206004820152600d60248201526c1499599d5b990819985a5b1959609a1b6044820152606401610666565b6000806000806000807f000000000000000000000000942bc2d3e7a589fe5bd4a5c6ef9727dfd82f5c8a6001600160a01b0316638639415b8b8b6040518363ffffffff1660e01b815260040161132d929190918252602082015260400190565b60c060405180830381865afa15801561134a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061136e9190611ac9565b9550955095509550955095506000861115611420576040516001600160a01b038616908790600081818185875af1925050503d80600081146113cc576040519150601f19603f3d011682016040523d82523d6000602084013e6113d1565b606091505b505080985050876114205760405162461bcd60e51b8152602060048201526019602482015278105c9d08109b1bd8dadcc81c185e5b595b9d0819985a5b1959603a1b6044820152606401610666565b83156114bf576040516001600160a01b038416908590600081818185875af1925050503d806000811461146f576040519150601f19603f3d011682016040523d82523d6000602084013e611474565b606091505b505080985050876114bf5760405162461bcd60e51b8152602060048201526015602482015274105c9d1a5cdd081c185e5b595b9d0819985a5b1959605a1b6044820152606401610666565b8115611566576040516001600160a01b038216908390600081818185875af1925050503d806000811461150e576040519150601f19603f3d011682016040523d82523d6000602084013e611513565b606091505b505080985050876115665760405162461bcd60e51b815260206004820152601f60248201527f4164646974696f6e616c205061796565207061796d656e74206661696c6564006044820152606401610666565b50505050505050505b5050565b600081815b848110156115b6576115a28287878481811061159657611596611b32565b905060200201356115d7565b9150806115ae81611b48565b915050611578565b50949350505050565b6000826115cd868685611573565b1495945050505050565b60008183106115f3576000828152602084905260409020611602565b60008381526020839052604090205b90505b92915050565b6001600160a01b038116811461162057600080fd5b50565b60008083601f84011261163557600080fd5b5081356001600160401b0381111561164c57600080fd5b6020830191508360208260051b850101111561166757600080fd5b9250929050565b60008060008060006080868803121561168657600080fd5b85356116918161160b565b94506020860135935060408601356001600160401b038111156116b357600080fd5b6116bf88828901611623565b90945092505060608601356116d38161160b565b809150509295509295909350565b6000806000604084860312156116f657600080fd5b8335925060208401356001600160401b0381111561171357600080fd5b61171f86828701611623565b9497909650939450505050565b60006020828403121561173e57600080fd5b5035919050565b60008060006040848603121561175a57600080fd5b83356001600160401b0381111561177057600080fd5b61177c86828701611623565b90945092505060208401356117908161160b565b809150509250925092565b600080600080606085870312156117b157600080fd5b84356117bc8161160b565b93506020850135925060408501356001600160401b038111156117de57600080fd5b6117ea87828801611623565b95989497509550505050565b60006020828403121561180857600080fd5b81356118138161160b565b9392505050565b6000806040838503121561182d57600080fd5b82359150602083013561183f8161160b565b809150509250929050565b6000806040838503121561185d57600080fd5b50508035926020909101359150565b6000806000806060858703121561188257600080fd5b8435935060208501356001600160401b0381111561189f57600080fd5b6118ab87828801611623565b90945092505060408501356118bf8161160b565b939692955090935050565b6000815180845260005b818110156118f0576020818501810151868301820152016118d4565b506000602082860101526020601f19601f83011685010191505092915050565b841515815283602082015260806040820152600061193160808301856118ca565b905060018060a01b038316606083015295945050505050565b6000806040838503121561195d57600080fd5b82356119688161160b565b946020939093013593505050565b6000806040838503121561198957600080fd5b82359150602083013562ffffff8116811461183f57600080fd5b60208152600061160260208301846118ca565b805180151581146119c657600080fd5b919050565b6000602082840312156119dd57600080fd5b611602826119b6565b6000602082840312156119f857600080fd5b5051919050565b600060208284031215611a1157600080fd5b81516118138161160b565b6020808252600b908201526a13db9b1e48105c9d1a5cdd60aa1b604082015260600190565b60008060008060008060c08789031215611a5a57600080fd5b8651955060208701519450611a71604088016119b6565b9350611a7f606088016119b6565b925060808701519150611a9460a088016119b6565b90509295509295509295565b634e487b7160e01b600052601160045260246000fd5b8181038181111561160557611605611aa0565b60008060008060008060c08789031215611ae257600080fd5b865195506020870151611af48161160b565b604088015160608901519196509450611b0c8161160b565b608088015160a08901519194509250611b248161160b565b809150509295509295509295565b634e487b7160e01b600052603260045260246000fd5b600060018201611b5a57611b5a611aa0565b506001019056fea26469706673582212201a49e1efff7b0fc2d6e9c294eac51760b8f211bed47702c3d563dea63f83575d64736f6c63430008110033

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

000000000000000000000000942bc2d3e7a589fe5bd4a5c6ef9727dfd82f5c8a0000000000000000000000003f4bbde879f9bb0e95aea08ff12f55e171495c8f

-----Decoded View---------------
Arg [0] : _genArt721Address (address): 0x942BC2d3e7a589FE5bd4A5C6eF9727DFd82F5C8a
Arg [1] : _minterFilter (address): 0x3F4bbde879F9BB0E95AEa08fF12F55E171495C8f

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000942bc2d3e7a589fe5bd4a5c6ef9727dfd82f5c8a
Arg [1] : 0000000000000000000000003f4bbde879f9bb0e95aea08ff12f55e171495c8f


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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

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.