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

import {ERC721, ERC721A, IERC721A} from "./ERC721/ERC721.sol";
import {ERC721Burnable} from "./ERC721/ERC721Burnable.sol";
import {ERC721Metadata} from "./ERC721/ERC721Metadata.sol";
import {ERC721Queryable} from "./ERC721/ERC721Queryable.sol";
import {ERC721Royalty} from "./ERC721/ERC721Royalty.sol";
import {Mintable} from "./utilities/Mintable.sol";
import {Withdrawable} from "./utilities/Withdrawable.sol";

error FreeMintAlreadyClaimed();

contract ContractMinter is ERC721, ERC721Burnable, ERC721Metadata, ERC721Queryable, ERC721Royalty, Mintable, Withdrawable {

    uint256 public constant MAX_SUPPLY = 10000;


    struct MintConfig {
        uint64 allowlistMaxMint;
        uint64 allowlistPrice;
        uint64 publicMaxMint;
        uint64 publicPrice;
    }


    MintConfig public _config;


    bytes32 public _allowlistMerkleRoot;
    bytes32 public _giveawayMerkleRoot;
    bytes32 public _publicMerkleRoot;


    constructor() ERC721('Contract Minter', 'minter') ERC721Royalty(_msgSenderERC721A(), 1000) {
        setBaseURI('https://niftyvs.com/metadata/contract-minter/json/');
        _setMintState(STATE_MINT_ALLOWLIST);

        _allowlistMerkleRoot = 0xa9758466ebc51b4c11c2f26b7ec964a3d3cf7b7b3e86fbe4d5001587c1a503a7;
        _giveawayMerkleRoot = 0xa9758466ebc51b4c11c2f26b7ec964a3d3cf7b7b3e86fbe4d5001587c1a503a7;
        _publicMerkleRoot = 0xa9758466ebc51b4c11c2f26b7ec964a3d3cf7b7b3e86fbe4d5001587c1a503a7;

        _config = MintConfig({
            allowlistMaxMint: 3,
            allowlistPrice: 0.04 ether,
            publicMaxMint: 8,
            publicPrice: 0.05 ether
        });
    }


    function _baseURI() internal override(ERC721, ERC721Metadata, ERC721Queryable) view virtual returns (string memory) {
        return super._baseURI();
    }

    function _startTokenId() internal override(ERC721, ERC721Queryable) view virtual returns(uint256) {
        return super._startTokenId();
    }

    function mintAllowlist(bytes32[] calldata proof, uint256 quantity) external payable {
        uint256 available = MAX_SUPPLY - _totalMinted();
        address buyer = _msgSenderERC721A();

        _merkleProofGate(buyer, proof, _allowlistMerkleRoot);
        _mintGate(isMintAllowlist());
        _priceGate(buyer, _config.allowlistPrice, quantity, msg.value);
        _supplyGate(available, _config.allowlistMaxMint, _numberMinted(buyer), quantity);

        _safeMint(buyer, quantity);
    }

    function mintGiveaway(bytes32[] calldata proof) external payable {
        uint256 available = MAX_SUPPLY - _totalMinted();
        address buyer = _msgSenderERC721A();
        uint256 quantity = 1;

        _merkleProofGate(buyer, proof, _giveawayMerkleRoot);
        _mintGate(isMintOpen());
        _supplyGate(available, quantity);

        if (_getAux(buyer) > 0) {
            revert FreeMintAlreadyClaimed();
        }

        _setAux(buyer, 1);

        _safeMint(buyer, quantity);
    }

    function mintPublic(uint256 quantity) external payable {
        uint256 available = MAX_SUPPLY - _totalMinted();
        address buyer = _msgSenderERC721A();

        _mintGate(isMintPublic());
        _priceGate(buyer, _config.publicPrice, quantity, msg.value);
        _supplyGate(available, _config.publicMaxMint, _numberMinted(buyer), quantity);

        _safeMint(buyer, quantity);
    }

    function setAllowlistMerkleRoot(bytes32 root) external onlyOwner {
        _allowlistMerkleRoot = root;
    }

    function setAllowlistPrice(uint64 price) external onlyOwner {
        _config.allowlistPrice = price;
    }

    function setGiveawayMerkleRoot(bytes32 root) external onlyOwner {
        _giveawayMerkleRoot = root;
    }

    function setMintState(uint32 state) external onlyOwner {
        _setMintState(state);
    }

    function setPublicPrice(uint64 price) external onlyOwner {
        _config.publicPrice = price;
    }

    function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721A, ERC721Royalty, IERC721A) returns (bool) {
        return super.supportsInterface(interfaceId);
    }

    function tokenURI(uint256 tokenId) override(ERC721A, ERC721Metadata, IERC721A) public view virtual returns(string memory) {
        return super.tokenURI(tokenId);
    }

    function withdraw() external onlyOwner {
        uint256 split = (address(this).balance * 3300) / 10000;

        _withdraw(0x1D33Db15e1A8e85Ffc5b3a6983c2E1C45349a98B, split);
        _withdraw(0x266c3dF72B45F963192BcE641Eb4d56476D296D2, split);
        _withdraw(owner(), address(this).balance);
    }
}
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AddressNotAllowed","type":"error"},{"inputs":[{"internalType":"string","name":"method","type":"string"}],"name":"AmountExceedsBalance","type":"error"},{"inputs":[],"name":"ApprovalCallerNotOwnerNorApproved","type":"error"},{"inputs":[],"name":"ApprovalQueryForNonexistentToken","type":"error"},{"inputs":[],"name":"ApproveToCaller","type":"error"},{"inputs":[],"name":"BalanceQueryForZeroAddress","type":"error"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"CannotMintMoreThan","type":"error"},{"inputs":[],"name":"FreeMintAlreadyClaimed","type":"error"},{"inputs":[],"name":"InvalidMintState","type":"error"},{"inputs":[],"name":"InvalidQueryRange","type":"error"},{"inputs":[{"internalType":"uint256","name":"max","type":"uint256"}],"name":"MaxMintPerWalletWouldBeReached","type":"error"},{"inputs":[],"name":"MintClosed","type":"error"},{"inputs":[],"name":"MintERC2309QuantityExceedsLimit","type":"error"},{"inputs":[],"name":"MintToZeroAddress","type":"error"},{"inputs":[],"name":"MintZeroQuantity","type":"error"},{"inputs":[],"name":"NeedToSendMoreETH","type":"error"},{"inputs":[],"name":"OwnerQueryForNonexistentToken","type":"error"},{"inputs":[],"name":"OwnershipNotInitializedForExtraData","type":"error"},{"inputs":[],"name":"QuantityWouldExceedMaxSupply","type":"error"},{"inputs":[{"internalType":"string","name":"method","type":"string"}],"name":"QueryForNonexistentToken","type":"error"},{"inputs":[],"name":"TransferCallerNotOwnerNorApproved","type":"error"},{"inputs":[],"name":"TransferFailed","type":"error"},{"inputs":[],"name":"TransferFromIncorrectOwner","type":"error"},{"inputs":[],"name":"TransferToNonERC721ReceiverImplementer","type":"error"},{"inputs":[],"name":"TransferToZeroAddress","type":"error"},{"inputs":[],"name":"URIQueryForNonexistentToken","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"fromTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"toTokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"ConsecutiveTransfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"MAX_SUPPLY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STATE_MINT_ALL","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STATE_MINT_ALLOWLIST","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STATE_MINT_CLOSED","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STATE_MINT_PUBLIC","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_allowlistMerkleRoot","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_config","outputs":[{"internalType":"uint64","name":"allowlistMaxMint","type":"uint64"},{"internalType":"uint64","name":"allowlistPrice","type":"uint64"},{"internalType":"uint64","name":"publicMaxMint","type":"uint64"},{"internalType":"uint64","name":"publicPrice","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_giveawayMerkleRoot","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_publicMerkleRoot","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"explicitOwnershipOf","outputs":[{"components":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"uint64","name":"startTimestamp","type":"uint64"},{"internalType":"bool","name":"burned","type":"bool"},{"internalType":"uint24","name":"extraData","type":"uint24"}],"internalType":"struct IERC721A.TokenOwnership","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"explicitOwnershipsOf","outputs":[{"components":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"uint64","name":"startTimestamp","type":"uint64"},{"internalType":"bool","name":"burned","type":"bool"},{"internalType":"uint24","name":"extraData","type":"uint24"}],"internalType":"struct IERC721A.TokenOwnership[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isMintAllowlist","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isMintClosed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isMintOpen","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isMintPublic","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"},{"internalType":"uint256","name":"quantity","type":"uint256"}],"name":"mintAllowlist","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"}],"name":"mintGiveaway","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"quantity","type":"uint256"}],"name":"mintPublic","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"royaltyInfo","outputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"root","type":"bytes32"}],"name":"setAllowlistMerkleRoot","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"price","type":"uint64"}],"name":"setAllowlistPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"uri","type":"string"}],"name":"setBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"root","type":"bytes32"}],"name":"setGiveawayMerkleRoot","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"state","type":"uint32"}],"name":"setMintState","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"price","type":"uint64"}],"name":"setPublicPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"string","name":"uri","type":"string"}],"name":"setTokenURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"tokensOfOwner","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"start","type":"uint256"},{"internalType":"uint256","name":"stop","type":"uint256"}],"name":"tokensOfOwnerIn","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]