ETH Price: $3,263.59 (-0.55%)
Gas: 3 Gwei

Contract Diff Checker

Contract Name:
ERC721Token

Contract Source Code:

File 1 of 1 : ERC721Token

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @title ERC721 Token (Batch Mint)
 * @author 0xSumo <@PBADAO>
 */

abstract contract ERC721TokenReceiver {
    function onERC721Received(address, address, uint256, bytes calldata) external virtual returns (bytes4) { return ERC721TokenReceiver.onERC721Received.selector; }
}

abstract contract ERC721 {
    
    event Transfer(address indexed from_, address indexed to_, uint256 indexed tokenId_);
    event Approval(address indexed owner_, address indexed spender_, uint256 indexed id_);
    event ApprovalForAll(address indexed owner_, address indexed operator_, bool approved_);

    string public name; 
    string public symbol;

    uint256 public nextTokenId;
    uint256 public totalBurned;
    uint256 public constant maxBatchSize = 20;
    
    function startTokenId() public pure virtual returns (uint256) {
        return 0;
    }

    function totalSupply() public view virtual returns (uint256) {
        return nextTokenId - totalBurned - startTokenId();
    }

    constructor(string memory name_, string memory symbol_) {
        name = name_;
        symbol = symbol_;
        nextTokenId = startTokenId();
    }

    struct TokenData {
        address owner;
        uint40 lastTransfer;
        bool burned;
        bool nextInitialized;
    }
    struct BalanceData {
        uint32 balance;
        uint32 mintedAmount;
    }

    mapping(uint256 => TokenData) public _tokenData;
    mapping(address => BalanceData) public _balanceData;

    mapping(uint256 => address) public getApproved;
    mapping(address => mapping(address => bool)) public isApprovedForAll;

    function _getTokenDataOf(uint256 tokenId_) public view virtual returns (TokenData memory) {
        uint256 _lookupId = tokenId_;
        require(_lookupId >= startTokenId(), "_getTokenDataOf _lookupId < startTokenId");
        TokenData memory _TokenData = _tokenData[_lookupId];
        if (_TokenData.owner != address(0) && !_TokenData.burned) return _TokenData;
        require(!_TokenData.burned, "_getTokenDataOf burned token!");
        require(_lookupId < nextTokenId, "_getTokenDataOf _lookupId > _nextTokenId");
        unchecked { while(_tokenData[--_lookupId].owner == address(0)) {} }
        return _tokenData[_lookupId];
    }

    function balanceOf(address owner_) public virtual view returns (uint256) {
        require(owner_ != address(0), "balanceOf to 0x0");
        return _balanceData[owner_].balance;
    }

    function ownerOf(uint256 tokenId_) public view returns (address) {
        return _getTokenDataOf(tokenId_).owner;
    }

    function _mintInternal(address to_, uint256 amount_) internal virtual { unchecked {
        require(to_ != address(0), "_mint to 0x0");
        uint256 _startId = nextTokenId;
        uint256 _endId = _startId + amount_;
        _tokenData[_startId].owner = to_;
        _tokenData[_startId].lastTransfer = uint40(block.timestamp);
        _balanceData[to_].balance += uint32(amount_);
        _balanceData[to_].mintedAmount += uint32(amount_);
        do { emit Transfer(address(0), to_, _startId); } while (++_startId < _endId);
        nextTokenId = _endId;
    }}

    function _mint(address to_, uint256 amount_) internal virtual {
        uint256 _amountToMint = amount_;
        while (_amountToMint > maxBatchSize) {
            _amountToMint -= maxBatchSize;
            _mintInternal(to_, maxBatchSize);
        }
        _mintInternal(to_, _amountToMint);
    }

    function _burn(uint256 tokenId_, bool checkApproved_) internal virtual { unchecked {
        TokenData memory _TokenData = _getTokenDataOf(tokenId_);
        address _owner = _TokenData.owner;
        if (checkApproved_) require(_isApprovedOrOwner(_owner, msg.sender, tokenId_), "_burn not approved");
        delete getApproved[tokenId_];
        _tokenData[tokenId_].owner = _owner;
        _tokenData[tokenId_].lastTransfer = uint40(block.timestamp);
        _tokenData[tokenId_].burned = true;
        _tokenData[tokenId_].nextInitialized = true;

        if (!_TokenData.nextInitialized) {
            uint256 _tokenIdIncremented = tokenId_ + 1;
            if (_tokenData[_tokenIdIncremented].owner == address(0)) {
                if (tokenId_ < nextTokenId - 1) {
                    _tokenData[_tokenIdIncremented] = _TokenData;
                }
            }
        }
        
        _balanceData[_owner].balance--;
        emit Transfer(_owner, address(0), tokenId_);
        totalBurned++;
    }}

    function _transfer(address from_, address to_, uint256 tokenId_, bool checkApproved_) internal virtual { unchecked {
        require(to_ != address(0), "_transfer to 0x0");
        TokenData memory _TokenData = _getTokenDataOf(tokenId_);
        address _owner = _TokenData.owner;
        require(from_ == _owner, "_transfer not from owner");
        if (checkApproved_) require(_isApprovedOrOwner(_owner, msg.sender, tokenId_), "_transfer not approved");
        delete getApproved[tokenId_];
        _tokenData[tokenId_].owner = to_;
        _tokenData[tokenId_].lastTransfer = uint40(block.timestamp);
        _tokenData[tokenId_].nextInitialized = true;
        
        if (!_TokenData.nextInitialized) {
            uint256 _tokenIdIncremented = tokenId_ + 1;
            if (_tokenData[_tokenIdIncremented].owner == address(0)) {
                if (tokenId_ < nextTokenId - 1) {
                    _tokenData[_tokenIdIncremented] = _TokenData;
                }
            }
        }

        _balanceData[from_].balance--;
        _balanceData[to_].balance++;
        emit Transfer(from_, to_, tokenId_);
    }}

    function transferFrom(address from_, address to_, uint256 tokenId_) public virtual {
        _transfer(from_, to_, tokenId_, true);
    }

    function safeTransferFrom(address from_, address to_, uint256 tokenId_, bytes memory data_) public virtual {
        transferFrom(from_, to_, tokenId_);
        require(to_.code.length == 0 || ERC721TokenReceiver(to_).onERC721Received(msg.sender, from_, tokenId_, data_) ==
        ERC721TokenReceiver.onERC721Received.selector, "safeTransferFrom to unsafe address");
    }

    function safeTransferFrom(address from_, address to_, uint256 tokenId_) public virtual {
        safeTransferFrom(from_, to_, tokenId_, "");
    }

    function approve(address spender_, uint256 tokenId_) public virtual {
        address _owner = ownerOf(tokenId_);
        require(msg.sender == _owner || isApprovedForAll[_owner][msg.sender], "approve not authorized!");
        getApproved[tokenId_] = spender_;
        emit Approval(_owner, spender_, tokenId_);
    }

    function setApprovalForAll(address operator_, bool approved_) public virtual {
        isApprovedForAll[msg.sender][operator_] = approved_;
        emit ApprovalForAll(msg.sender, operator_, approved_);
    }

    function _isApprovedOrOwner(address owner_, address spender_, uint256 tokenId_) internal virtual view returns (bool) {
        return (owner_ == spender_ || getApproved[tokenId_] == spender_ || isApprovedForAll[owner_][spender_]);
    }

    function supportsInterface(bytes4 id_) public virtual view returns (bool) {
        return  id_ == 0x01ffc9a7 || id_ == 0x80ac58cd || id_ == 0x5b5e139f;
    }

    function tokenURI(uint256 tokenId_) public virtual view returns (string memory);
}

abstract contract ERC721TokenURI {
    string public baseTokenURI;
    function _setBaseTokenURI(string memory uri_) internal virtual {
        baseTokenURI = uri_;
    }
    function _toString(uint256 value_) internal pure virtual returns (string memory _str) {
        assembly {
            let m := add(mload(0x40), 0xa0)
            mstore(0x40, m)
            _str := sub(m, 0x20)
            mstore(_str, 0)
            let end := _str
            for { let temp := value_ } 1 {} {
                _str := sub(_str, 1)
                mstore8(_str, add(48, mod(temp, 10)))
                temp := div(temp, 10)
                if iszero(temp) { break }
            }
            let length := sub(end, _str)
            _str := sub(_str, 0x20)
            mstore(_str, length)
        }
    }
    function _getTokenURI(uint256 tokenId_) internal virtual view returns (string memory) {
        return string(abi.encodePacked(baseTokenURI, _toString(tokenId_), ".json"));
    }
}

abstract contract MerkleProof {
    bytes32 internal _merkleRoot;
    function _setMerkleRoot(bytes32 merkleRoot_) internal virtual { _merkleRoot = merkleRoot_; }
    function isWhitelisted(address address_, bytes32[] memory proof_) public view returns (bool) {
        bytes32 _leaf = keccak256(abi.encodePacked(address_));
        for (uint256 i = 0; i < proof_.length; i++) {
            _leaf = _leaf < proof_[i] ? keccak256(abi.encodePacked(_leaf, proof_[i])) : keccak256(abi.encodePacked(proof_[i], _leaf));
        }
        return _leaf == _merkleRoot;
    }
}

abstract contract OwnWithAuth {
    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
    event AdminSet(bytes32 indexed controllerType, bytes32 indexed controllerSlot, address indexed controller, bool status);
    address public owner;
    mapping(bytes32 => mapping(address => bool)) internal admin;
    constructor() { owner = msg.sender; }
    modifier onlyOwner() { require(owner == msg.sender, "only owner");_; }
    modifier onlyAdmin(string memory type_) { require(isAdmin(type_, msg.sender), "only admin");_; }
    function transferOwnership(address newOwner) external onlyOwner {
        emit OwnershipTransferred(owner, newOwner); owner = newOwner; 
    }
    function _setAdmin(string memory type_, address controller, bool status) internal {
        bytes32 typeHash = keccak256(abi.encodePacked(type_)); 
        admin[typeHash][controller] = status; 
        emit AdminSet(typeHash, typeHash, controller, status); 
    }
    function setAdmin(string memory type_, address controller, bool status) external onlyOwner { 
        bytes32 typeHash = keccak256(abi.encodePacked(type_)); 
        admin[typeHash][controller] = status; 
        emit AdminSet(typeHash, typeHash, controller, status); 
    }
    function isAdmin(string memory type_, address controller) public view returns (bool) { 
        bytes32 typeHash = keccak256(abi.encodePacked(type_)); 
        return admin[typeHash][controller]; 
    }
}

contract ERC721Token is ERC721, ERC721TokenURI, MerkleProof, OwnWithAuth {

    bool public active;

    uint256 public maxTokens = 400;

    uint256 public maxTokenPerMint = 2;

    uint256 public totalMintOut;

    uint256 public mintPrice = 0.003 ether;

    uint256 public mintPricePublic = 0.006 ether;

    mapping(address => uint256) public minted;

    modifier onlySender {
        require(msg.sender == tx.origin, "No smart contracts!");
        _;
    }

    constructor() ERC721("8CH1", "8CH1") {
        _setAdmin("MINTER", msg.sender, true);
        _setAdmin("BURNER", msg.sender, true);
        _setAdmin("ADMIN", msg.sender, true);
        _setMerkleRoot(0x94702ffeb6195bdd82ea3ceabb655836cf9440d40441d147519e4d9d4352671c);
    }

    function whitelistMint(uint256 amount_, bytes32[] memory proof_) external payable onlySender {
        require(active, "closed");
        require(isWhitelisted(msg.sender, proof_), "You are not whitelisted!");
        require(maxTokenPerMint >= amount_, "Exceed max");
        require(maxTokenPerMint >= minted[msg.sender] + amount_, "Exceed max per address");
        require(maxTokens >= totalMintOut + amount_, "No mints remaining");
        require(msg.value == mintPrice * amount_, "Invalid value sent");
        _mint(msg.sender, amount_);
        minted[msg.sender] += amount_;
        totalMintOut += amount_;
    }

    function publicMint(address to_, uint256 amount_) external payable onlySender {
        require(active, "closed");
        require(maxTokens >= totalMintOut + amount_, "No mints remaining");
        require(msg.value == mintPricePublic * amount_, "Invalid value sent");
        _mint(to_, amount_);
        totalMintOut += amount_;
    }

    function mint(address to_, uint256 amount_) external onlyAdmin("MINTER") {
        _mint(to_, amount_);
    }

    function burn(uint256 id_, bool approved_) external onlyAdmin("BURNER") {
        _burn(id_, approved_);
    }

    function setActive(bool bool_) external onlyAdmin("ADMIN") {
        active = bool_;
    }

    function setMaxTokens(uint256 amount_) external onlyAdmin("ADMIN") {
        maxTokens = amount_;
    }

    function setMintPrice(uint256 price_) external onlyAdmin("ADMIN") {
        mintPrice = price_;
    }

    function setMintPricePublic(uint256 price_) external onlyAdmin("ADMIN") {
        mintPricePublic = price_;
    }

    function setTokenToURI(string memory uri_) external onlyAdmin("ADMIN") {
        _setBaseTokenURI(uri_);
    }

    function setMerkleRoot(bytes32 merkleRoot_) external onlyAdmin("ADMIN") {
        _setMerkleRoot(merkleRoot_);
    }

    function startTokenId() public pure override returns (uint256) {
        return 1;
    }

    function tokenURI(uint256 tokenId_) public view override returns (string memory) {
        return _getTokenURI(tokenId_);
    }

    function withdraw() external onlyOwner {
        uint256 balance = address(this).balance;
        (bool transferTx, ) = msg.sender.call{value: balance}("");
        require(transferTx, "Transfer failed.");
    }
}

Please enter a contract address above to load the contract details and source code.

Context size (optional):