pragma solidity ^0.8.17;




//
//   /$$$$$$$$ /$$$$$$ /$$$$$$$$ /$$   /$$
//  | $$_____/|_  $$_/| $$_____/| $$$ | $$
//  | $$        | $$  | $$      | $$$$| $$
//  | $$$$$     | $$  | $$$$$   | $$ $$ $$
//  | $$__/     | $$  | $$__/   | $$  $$$$
//  | $$        | $$  | $$      | $$\  $$$
//  | $$$$$$$$ /$$$$$$| $$$$$$$$| $$ \  $$
//  |________/|______/|________/|__/  \__/
//
// EIEN Contract by arufa
// Twitter: https://twitter.com/arufa_nft
contract Eien is Ownable, ERC721 {
    uint256 public constant MAX_SUPPLY = 3333;
    uint256 public constant PUB_SALE_MINT_PRICE = 0.05 ether;
    uint256 public constant PRE_SALE_MINT_PRICE = 0.03 ether;
    uint256 private constant MAX_MINTS_PER_TX = 100;

    using Counters for Counters.Counter;
    Counters.Counter internal _totalSupply;

    uint16 internal constant NOT_SALE_ACTIVE_FLG = 0;
    uint16 internal constant PRE_SALE_ACTIVE_FLG = 1;
    uint16 internal constant FREE_MINT_ACTIVE_FLG = 2;
    uint16 internal constant THANKS_SALE_ACTIVE_FLG = 3;
    uint16 internal constant PUB_SALE_ACTIVE_FLG = 4;

    uint16 public saleState = NOT_SALE_ACTIVE_FLG;

    mapping(address => uint256) private _preSaleList;
    mapping(address => uint256) private _freeMintList;
    mapping(address => uint256) private _thanksSaleList;
    mapping(address => uint256) private _pubSaleList;

    string public baseTokenURI;
    string constant public uriSuffix = ".json";

    address public TeamWallet = 0xFBc8Ff6F62b84F535f224F9B14b5B92F37cb1263;

    constructor() ERC721("Eien", "EIEN") {}

    /**
     /$$$$$$$  /$$   /$$ /$$$$$$$  /$$       /$$$$$$  /$$$$$$        /$$$$$$$$ /$$   /$$ /$$   /$$  /$$$$$$  /$$$$$$$$ /$$$$$$  /$$$$$$  /$$   /$$  /$$$$$$ 
    | $$__  $$| $$  | $$| $$__  $$| $$      |_  $$_/ /$$__  $$      | $$_____/| $$  | $$| $$$ | $$ /$$__  $$|__  $$__/|_  $$_/ /$$__  $$| $$$ | $$ /$$__  $$
    | $$  \ $$| $$  | $$| $$  \ $$| $$        | $$  | $$  \__/      | $$      | $$  | $$| $$$$| $$| $$  \__/   | $$     | $$  | $$  \ $$| $$$$| $$| $$  \__/
    | $$$$$$$/| $$  | $$| $$$$$$$ | $$        | $$  | $$            | $$$$$   | $$  | $$| $$ $$ $$| $$         | $$     | $$  | $$  | $$| $$ $$ $$|  $$$$$$ 
    | $$____/ | $$  | $$| $$__  $$| $$        | $$  | $$            | $$__/   | $$  | $$| $$  $$$$| $$         | $$     | $$  | $$  | $$| $$  $$$$ \____  $$
    | $$      | $$  | $$| $$  \ $$| $$        | $$  | $$    $$      | $$      | $$  | $$| $$\  $$$| $$    $$   | $$     | $$  | $$  | $$| $$\  $$$ /$$  \ $$
    | $$      |  $$$$$$/| $$$$$$$/| $$$$$$$$ /$$$$$$|  $$$$$$/      | $$      |  $$$$$$/| $$ \  $$|  $$$$$$/   | $$    /$$$$$$|  $$$$$$/| $$ \  $$|  $$$$$$/
    |__/       \______/ |_______/ |________/|______/ \______/       |__/       \______/ |__/  \__/ \______/    |__/   |______/ \______/ |__/  \__/ \______/ 
    */

    function PreSale(uint256 quantity) public payable {
        uint256 price = PRE_SALE_MINT_PRICE;
        uint256 maxMintPerTransaction = MAX_MINTS_PER_TX;
        uint256 maxSupply = MAX_SUPPLY;
        uint256 remainingMint = _preSaleList[msg.sender];

        require(tx.origin == msg.sender, "Cannot be called by a contract");
        require(saleState == PRE_SALE_ACTIVE_FLG, "PreSale is paused");
        require(quantity <= maxMintPerTransaction, "More than max per transaction");
        require(remainingMint != 0, "There are no NFTs left to claim in the pre sale");
        require(remainingMint >= quantity, "User max mint limit");
        require(quantity + _totalSupply.current() <= maxSupply, "Exceeded maximum supply");
        require(msg.value == price * quantity, "Value sent is not correct");
        for (uint256 i = 1; i <= quantity; i++) {
            _preSaleList[msg.sender] = remainingMint-i;
            _totalSupply.increment();
            _safeMint(msg.sender, _totalSupply.current());
        }
    }

    function FreeMint(uint256 quantity) public payable {
        uint256 maxMintPerTransaction = MAX_MINTS_PER_TX;
        uint256 maxSupply = MAX_SUPPLY;
        uint256 remainingMint = _freeMintList[msg.sender];

        require(tx.origin == msg.sender, "Cannot be called by a contract");
        require(saleState == FREE_MINT_ACTIVE_FLG, "FreeMint is paused");
        require(quantity <= maxMintPerTransaction, "More than max per transaction");
        require(remainingMint != 0, "There are no NFTs left to claim in the free mint");
        require(remainingMint >= quantity, "User max mint limit");
        require(quantity + _totalSupply.current() <= maxSupply, "Exceeded maximum supply");
        for (uint256 i = 1; i <= quantity; i++) {
            _freeMintList[msg.sender] = remainingMint-i;
            _totalSupply.increment();
            _safeMint(msg.sender, _totalSupply.current());
        }
    }

    function ThanksSale(uint256 quantity) public payable {
        uint256 price = PUB_SALE_MINT_PRICE;
        uint256 maxMintPerTransaction = MAX_MINTS_PER_TX;
        uint256 maxSupply = MAX_SUPPLY;
        uint256 remainingMint = _thanksSaleList[msg.sender];

        require(tx.origin == msg.sender, "Cannot be called by a contract");
        require(saleState == THANKS_SALE_ACTIVE_FLG, "ThanksSale is paused");
        require(quantity <= maxMintPerTransaction, "More than max per transaction");
        require(remainingMint != 0, "There are no NFTs left to claim in the thanks sale");
        require(remainingMint >= quantity, "User max mint limit");
        require(quantity + _totalSupply.current() <= maxSupply, "Exceeded maximum supply");
        require(msg.value == price * quantity, "Value sent is not correct");
        for (uint256 i = 1; i <= quantity; i++) {
            _thanksSaleList[msg.sender] = remainingMint-i;
            _totalSupply.increment();
            _safeMint(msg.sender, _totalSupply.current());
        }
    }

    function PubSale(uint256 quantity) public payable {
        uint256 price = PUB_SALE_MINT_PRICE;
        uint256 maxMintPerTransaction = MAX_MINTS_PER_TX;
        uint256 maxSupply = MAX_SUPPLY;
        uint256 remainingMint = _pubSaleList[msg.sender];

        require(tx.origin == msg.sender, "Cannot be called by a contract");
        require(saleState == PUB_SALE_ACTIVE_FLG, "PubSale is paused");
        require(quantity <= maxMintPerTransaction, "More than max per transaction");
        require(remainingMint != 0, "There are no NFTs left to claim in the public sale");
        require(remainingMint >= quantity, "User max mint limit");
        require(quantity + _totalSupply.current() <= maxSupply, "Exceeded maximum supply");
        require(msg.value == price * quantity, "Value sent is not correct");
        for (uint256 i = 1; i <= quantity; i++) {
            _pubSaleList[msg.sender] = remainingMint-i;
            _totalSupply.increment();
            _safeMint(msg.sender, _totalSupply.current());
        }
    }

    /**
     /$$    /$$ /$$$$$$ /$$$$$$$$ /$$      /$$       /$$$$$$$$ /$$   /$$ /$$   /$$  /$$$$$$  /$$$$$$$$ /$$$$$$  /$$$$$$  /$$   /$$  /$$$$$$ 
    | $$   | $$|_  $$_/| $$_____/| $$  /$ | $$      | $$_____/| $$  | $$| $$$ | $$ /$$__  $$|__  $$__/|_  $$_/ /$$__  $$| $$$ | $$ /$$__  $$
    | $$   | $$  | $$  | $$      | $$ /$$$| $$      | $$      | $$  | $$| $$$$| $$| $$  \__/   | $$     | $$  | $$  \ $$| $$$$| $$| $$  \__/
    |  $$ / $$/  | $$  | $$$$$   | $$/$$ $$ $$      | $$$$$   | $$  | $$| $$ $$ $$| $$         | $$     | $$  | $$  | $$| $$ $$ $$|  $$$$$$ 
     \  $$ $$/   | $$  | $$__/   | $$$$_  $$$$      | $$__/   | $$  | $$| $$  $$$$| $$         | $$     | $$  | $$  | $$| $$  $$$$ \____  $$
      \  $$$/    | $$  | $$      | $$$/ \  $$$      | $$      | $$  | $$| $$\  $$$| $$    $$   | $$     | $$  | $$  | $$| $$\  $$$ /$$  \ $$
       \  $/    /$$$$$$| $$$$$$$$| $$/   \  $$      | $$      |  $$$$$$/| $$ \  $$|  $$$$$$/   | $$    /$$$$$$|  $$$$$$/| $$ \  $$|  $$$$$$/
        \_/    |______/|________/|__/     \__/      |__/       \______/ |__/  \__/ \______/    |__/   |______/ \______/ |__/  \__/ \______/                                                                                                                                         
    */

    function tokenURI(uint256 _tokenId) public view override returns (string memory) {
        require(_exists(_tokenId), "URI query for nonexistent token");
        return string(abi.encodePacked(baseTokenURI, Strings.toString(_tokenId), uriSuffix));
    }

    function totalSupply() public view returns (uint256) {
        return _totalSupply.current();
    }

    function getSaleState() public view returns (uint16) {
        return saleState;
    }

    function numAvailableMintToPreSale(address addr) external view returns (uint256) {
        return _preSaleList[addr];
    }

    function numAvailableMintToFreeMint(address addr) external view returns (uint256) {
        return _freeMintList[addr];
    }

    function numAvailableMintToThanksSale(address addr) external view returns (uint256) {
        return _thanksSaleList[addr];
    }

    function numAvailableMintToPubSale(address addr) external view returns (uint256) {
        return _pubSaleList[addr];
    }

    function getPreSaleMintPrice() external pure returns (uint256) {
        return PRE_SALE_MINT_PRICE;
    }
    
    function getPubSaleMintPrice() external pure returns (uint256) {
        return PUB_SALE_MINT_PRICE;
    }

    /**
      /$$$$$$  /$$   /$$ /$$   /$$     /$$        /$$$$$$  /$$      /$$ /$$   /$$ /$$$$$$$$ /$$$$$$$ 
     /$$__  $$| $$$ | $$| $$  |  $$   /$$/       /$$__  $$| $$  /$ | $$| $$$ | $$| $$_____/| $$__  $$
    | $$  \ $$| $$$$| $$| $$   \  $$ /$$/       | $$  \ $$| $$ /$$$| $$| $$$$| $$| $$      | $$  \ $$
    | $$  | $$| $$ $$ $$| $$    \  $$$$/        | $$  | $$| $$/$$ $$ $$| $$ $$ $$| $$$$$   | $$$$$$$/
    | $$  | $$| $$  $$$$| $$     \  $$/         | $$  | $$| $$$$_  $$$$| $$  $$$$| $$__/   | $$__  $$
    | $$  | $$| $$\  $$$| $$      | $$          | $$  | $$| $$$/ \  $$$| $$\  $$$| $$      | $$  \ $$
    |  $$$$$$/| $$ \  $$| $$$$$$$$| $$          |  $$$$$$/| $$/   \  $$| $$ \  $$| $$$$$$$$| $$  | $$
     \______/ |__/  \__/|________/|__/           \______/ |__/     \__/|__/  \__/|________/|__/  |__/
    */

    function ownerMint(address to, uint256 quantity) external onlyOwner {
        uint256 maxMintPerTransaction = MAX_MINTS_PER_TX;

        require(quantity <= maxMintPerTransaction, "More than max per transaction");
        require((quantity + _totalSupply.current()) <= MAX_SUPPLY, "Exceeded maximum supply");
        for (uint256 i = 0; i < quantity; i++) {
            _totalSupply.increment();
            _safeMint(to, _totalSupply.current());
        }
    }

    function setBaseURI(string calldata _baseTokenURI) external onlyOwner {
        baseTokenURI = _baseTokenURI;
    }

    function setTeamWallet(address _teamWallet) public onlyOwner {
        TeamWallet = _teamWallet;
    }

    function inactivateSale() external onlyOwner {
        saleState = NOT_SALE_ACTIVE_FLG;
    }

    function activatePreSale() external onlyOwner {
        saleState = PRE_SALE_ACTIVE_FLG;
    }

    function activateFreeMint() external onlyOwner {
        saleState = FREE_MINT_ACTIVE_FLG;
    }
    
    function activateThanksSale() external onlyOwner {
        saleState = THANKS_SALE_ACTIVE_FLG;
    }
    
    function activatePubSale() external onlyOwner {
        saleState = PUB_SALE_ACTIVE_FLG;
    }

    function setPreSaleList(address[] memory _addresses, uint256 numAllowedToMint) external onlyOwner {
        for (uint256 i = 0; i < _addresses.length; i++) {
            _preSaleList[_addresses[i]] = numAllowedToMint;
        }
    }

    function setFreeMintList(address[] memory _addresses, uint256 numAllowedToMint) external onlyOwner {
        for (uint256 i = 0; i < _addresses.length; i++) {
            _freeMintList[_addresses[i]] = numAllowedToMint;
        }
    }

    function setThanksSaleList(address[] memory _addresses, uint256 numAllowedToMint) external onlyOwner {
        for (uint256 i = 0; i < _addresses.length; i++) {
            _thanksSaleList[_addresses[i]] = numAllowedToMint;
        }
    }

    function setPubSaleList(address[] memory _addresses, uint256 numAllowedToMint) external onlyOwner {
        for (uint256 i = 0; i < _addresses.length; i++) {
            _pubSaleList[_addresses[i]] = numAllowedToMint;
        }
    }

    function withdraw() external payable onlyOwner {
        uint256 currBalance = address(this).balance;
        (bool succ, ) = payable(TeamWallet).call{
            value: currBalance
        }("");
        require(succ, "Team transfer failed");
    }
}
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"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":"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":[{"internalType":"uint256","name":"quantity","type":"uint256"}],"name":"FreeMint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"MAX_SUPPLY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PRE_SALE_MINT_PRICE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PUB_SALE_MINT_PRICE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"quantity","type":"uint256"}],"name":"PreSale","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"quantity","type":"uint256"}],"name":"PubSale","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"TeamWallet","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"quantity","type":"uint256"}],"name":"ThanksSale","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"activateFreeMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"activatePreSale","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"activatePubSale","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"activateThanksSale","outputs":[],"stateMutability":"nonpayable","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":[],"name":"baseTokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPreSaleMintPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getPubSaleMintPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getSaleState","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"inactivateSale","outputs":[],"stateMutability":"nonpayable","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":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"numAvailableMintToFreeMint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"numAvailableMintToPreSale","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"numAvailableMintToPubSale","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"numAvailableMintToThanksSale","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"quantity","type":"uint256"}],"name":"ownerMint","outputs":[],"stateMutability":"nonpayable","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":"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":[],"name":"saleState","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","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":"_baseTokenURI","type":"string"}],"name":"setBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_addresses","type":"address[]"},{"internalType":"uint256","name":"numAllowedToMint","type":"uint256"}],"name":"setFreeMintList","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_addresses","type":"address[]"},{"internalType":"uint256","name":"numAllowedToMint","type":"uint256"}],"name":"setPreSaleList","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_addresses","type":"address[]"},{"internalType":"uint256","name":"numAllowedToMint","type":"uint256"}],"name":"setPubSaleList","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_teamWallet","type":"address"}],"name":"setTeamWallet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_addresses","type":"address[]"},{"internalType":"uint256","name":"numAllowedToMint","type":"uint256"}],"name":"setThanksSaleList","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":[],"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":"uriSuffix","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdraw","outputs":[],"stateMutability":"payable","type":"function"}]