FRGG Froggies
Featured: Register HENS (.etc) Domain Name Click to register
Overview [ERC-721]
Max Total Supply:
7,777
Holders:
50
Transfers:
11,888
Profile Summary
Decimals:
0
Official Site:
Contract name:
Froggies
Optimization enabled :
false
Compiler version:
0.8.17+commit.8df45f5f
EVM Version:
london
Contract source code
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;

import "@openzeppelin/contracts@4.8.2/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts@4.8.2/token/ERC721/extensions/ERC721Enumerable.sol";
import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import "@openzeppelin/contracts@4.8.2/security/Pausable.sol";
import "@openzeppelin/contracts@4.8.2/access/Ownable.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
import "@thirdweb-dev/contracts/eip/interface/IERC20.sol";


contract Froggies is ERC721, ERC721Enumerable, Pausable, Ownable {
    using SafeMath for uint256;
    using EnumerableSet for EnumerableSet.UintSet;

    constructor() ERC721("Froggies", "FRGG") {}

    bytes32 private merkleRoot = 0x7b83c8ea4644507afaaa60c15c9ddb6239b4787cd286065e2144b6df0cbd9cd2;
    using EnumerableSet for EnumerableSet.UintSet;
    address private withdrawalAddress1;
    address private withdrawalAddress2;
    address private withdrawalAddress3;
    uint256 private constant MAX_MINTS_PER_TX = 20;
    string public baseExtension = ".json";
    uint256 public constant maxSupply = 7777;
    uint256 public maxMintAmount = 20;
    bool public revealed = true;
    bool private isMintingEnabled = false;
    address public burnAddress = 0x000000000000000000000000000000000000dEaD;

    string public notRevealedUri;
    string public baseUri = "ipfs://bafybeih2yqav3jcyvw7veszemipucimug4y3eoaoy263p7k4vgursvvscu/";
    uint256 public mintPrice = .4 ether;
    uint256 internal totalMinted = 0;
    // Random
    uint256 internal nonce = 0;
    uint256[maxSupply] internal indices;

    //Claim Variables
    address public eligibleTokenAddress = 0x731e2E78c318f6763DbBc9EFA4675a8061C11164;

    // storage
    mapping (uint256 => address) internal tokenToOwner;
    mapping (uint256 => address) internal tokenToApproval;
    mapping (address => mapping (address => bool)) internal ownerToOperators;

    address internal addressZero = address(0);

    EnumerableSet.UintSet internal tokensOnSale;
    bool internal isReentrancyLock = false;

    mapping(address => EnumerableSet.UintSet) private _ownedNFTs;
    
    function changeMaxMintAmount(uint256 newMax) public onlyOwner {
        require(newMax > 0, "Mint price must be greater than 0");
        maxMintAmount = newMax;
    }

    function pause() public onlyOwner {
        isMintingEnabled = false;
    }

    function unpause() public onlyOwner {
        isMintingEnabled = true;
    }

    function transferOwnership(address newOwner) public onlyOwner override{
        require(newOwner != address(0), "New owner cannot be zero address");
        _transferOwnership(newOwner);
    }

    function _beforeTokenTransfer(address from, address to, uint256 tokenId, uint256 batchSize)
        internal
        whenNotPaused
        override(ERC721, ERC721Enumerable)
    {
        super._beforeTokenTransfer(from, to, tokenId, batchSize);
    }

    function supportsInterface(bytes4 interfaceId)
        public
        view
        override(ERC721, ERC721Enumerable)
        returns (bool)
    {
        return super.supportsInterface(interfaceId);
    }

    function sendBatch(address recipient, uint256[] memory tokenIds) public onlyOwner{
        
        for (uint256 i = 0; i < tokenIds.length; i++) {
            _safeMint(recipient, tokenIds[i]);
        }
    }

    function claimNFT() external {
        // Check for at least 1 eligible token balance
        require(IERC20(eligibleTokenAddress).balanceOf(msg.sender) >= 1 ether, "You need to hold at least 1 eligible token");
        require(IERC20(eligibleTokenAddress).allowance(msg.sender, address(this)) >= 1 ether, "Please approve this contract to spend your tokens");
        // Transfer 1 token to the contract
        require(IERC20(eligibleTokenAddress).transferFrom(msg.sender, address(this), 1 ether), "Payment failed");
        _mint(msg.sender);
        
    }

    function airdrop(address[] memory recipients, uint256 amount) public onlyOwner {
    require(amount >= 1, 'You cannot mint lower than 1 NFT');
    require((totalMinted + amount) < maxSupply, "Exceeds maximum supply. Please try to mint fewer NFTs.");
    require(recipients.length <= amount, "Number of recipients exceeds the specified amount.");

        for (uint256 i = 0; i < amount; i++) {
            _mint(recipients[i]);
        }
    }

    function getNFTPrice(uint256 amount) public view returns (uint256) {
        require(totalMinted < maxSupply, "Sale has already ended.");
        return amount.mul(mintPrice);
    }

    function mint(uint256 amount) external payable reentrancyGuard mintingEnabled {
        require(msg.value >= (mintPrice * amount), "Insufficient funds to purchase");
        require(amount >= 1, 'You cannot mint lower than 1 NFT');
        require(amount <= maxMintAmount, 'You cannot mint more than 20 NFTs per once');
        require((totalMinted + amount) < maxSupply, "Exceeds maximum supply. Please try to mint less NFTs.");

        if (msg.value > getNFTPrice(amount)) {
            payable(msg.sender).transfer(msg.value - getNFTPrice(amount));
        }

        for (uint i = 0; i < amount; i++) {
            _mint(msg.sender);
        }
    }

    function _mint(address _to) internal notZeroAddress(_to) returns (uint256 _mintedTokenId) {
        require(totalMinted <= maxSupply, "All tokens are minted");
        uint randomId = _tryGenerateRandomId();
        totalMinted++;

        if (randomId == 0) {
            randomId = _tryGenerateRandomId();
            totalMinted++;
        }
        if (randomId != 0) {
            _safeMint(_to, randomId );
            emit Mint(randomId, msg.sender, _to);
        }
        return randomId;
    }

    function _tryGenerateRandomId() private returns (uint256) {
        uint256 randId = _generateRandomId();
        
        if (tokenToOwner[randId] == addressZero) {
            return randId;
        } else {
            return 0;
        }
    }

    function _generateRandomId() private returns (uint256) {
        uint256 totalSize = maxSupply - totalMinted;
        uint256 index = uint256(keccak256(abi.encodePacked(nonce, msg.sender, block.difficulty, block.timestamp))) % totalSize;
        uint256 value = 0;

        if (indices[index] != 0) {
            value = indices[index];
        } else {
            value = index;
        }

        // Move last value to selected position
        if (indices[totalSize - 1] == 0) {
            indices[index] = totalSize - 1;    // Array position not initialized, so use position
        } else { 
            indices[index] = indices[totalSize - 1];   // Array position holds a value so use that
        }
        nonce++;
        // Don't allow a zero index, start counting at 1
        return value + 1;
    }

    function setWithdrawalAddresses(address _withdrawalAddress1, address _withdrawalAddress2, address _withdrawalAddress3) public onlyOwner {
        withdrawalAddress1 = _withdrawalAddress1;
        withdrawalAddress2 = _withdrawalAddress2;
        withdrawalAddress3 = _withdrawalAddress3;
    }

    function withdraw() public onlyOwner {
        require(withdrawalAddress1 != address(0) && withdrawalAddress2 != address(0) && withdrawalAddress3 != address(0), "Withdrawal addresses not set");

        uint256 balance = address(this).balance;
        require(balance > 0, "Insufficient balance");

        uint256 amountPerAddress = balance / 3;

        (bool success1,) = withdrawalAddress1.call{value: amountPerAddress}("");
        require(success1, "Withdrawal failed for address 1");

        (bool success2,) = withdrawalAddress2.call{value: amountPerAddress}("");
        require(success2, "Withdrawal failed for address 2");

        (bool success3,) = withdrawalAddress3.call{value: amountPerAddress}("");
        require(success3, "Withdrawal failed for address 3");
    }

    function uintToString(uint256 value) internal pure returns (string memory) {
        if (value == 0) {
            return "0";
        }
        
        uint256 temp = value;
        uint256 digits;
        
        while (temp != 0) {
            digits++;
            temp /= 10;
        }
        
        bytes memory buffer = new bytes(digits);
        
        while (value != 0) {
            digits -= 1;
            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
            value /= 10;
        }
    
        return string(buffer);
    }

    function _baseURI() internal view virtual override returns (string memory) {
        return baseUri;
    }

    function setBaseURI(string memory newBaseURI) public onlyOwner {
        require(bytes(newBaseURI).length > 0, "Base URI cannot be empty");
        baseUri = newBaseURI;
    }

    function tokenURI(uint256 tokenId) public view virtual override(ERC721) returns (string memory){
        require(
        _exists(tokenId),
        "ERC721Metadata: URI query for nonexistent token"
        );
        
        if(revealed == false) {
            return notRevealedUri;
        }
        string memory currentBaseURI = _baseURI();
        return bytes(currentBaseURI).length > 0 ? string(abi.encodePacked(currentBaseURI, uintToString(tokenId), baseExtension)) : "";
    }


    function changeMintPrice(uint256 newMintPrice) public onlyOwner {
        require(newMintPrice > 0, "Mint price must be greater than 0");
        mintPrice = newMintPrice;
    }

    modifier notZeroAddress(address _addr) {
        require(_addr != addressZero, 'Address can not be 0x0');
        _;
    }

    event Mint(uint indexed tokenId, address indexed mintedBy, address indexed mintedTo);

    modifier reentrancyGuard {
        if (isReentrancyLock) {
            require(!isReentrancyLock, 'Reentrancy is locked');
        }
        isReentrancyLock = true;
        _;
        isReentrancyLock = false;
    }

    modifier mintingEnabled() {
        require(isMintingEnabled, 'Minting disabled');
        _;
    }


}

Contract ABI
[{"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":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"mintedBy","type":"address"},{"indexed":true,"internalType":"address","name":"mintedTo","type":"address"}],"name":"Mint","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":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","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"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[{"internalType":"address[]","name":"recipients","type":"address[]"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"airdrop","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":"baseExtension","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseUri","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"burnAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"newMax","type":"uint256"}],"name":"changeMaxMintAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newMintPrice","type":"uint256"}],"name":"changeMintPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimNFT","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"eligibleTokenAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"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":"uint256","name":"amount","type":"uint256"}],"name":"getNFTPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"maxMintAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"mintPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"notRevealedUri","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":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"revealed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"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":"address","name":"recipient","type":"address"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"sendBatch","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":"newBaseURI","type":"string"}],"name":"setBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_withdrawalAddress1","type":"address"},{"internalType":"address","name":"_withdrawalAddress2","type":"address"},{"internalType":"address","name":"_withdrawalAddress3","type":"address"}],"name":"setWithdrawalAddresses","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":"index","type":"uint256"}],"name":"tokenByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenOfOwnerByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]