// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9 <0.9.0;
import "https://github.com/FrankNFT-labs/ERC721F/blob/v1.0.0/ERC721F.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.4.0/contracts/token/ERC721/IERC721.sol";
/**
* @title Shrumies contract
* @dev Extends ERC721F Non-Fungible Token Standard basic implementation.
* Optimized to no longer use ERC721Enumarable , but still provide a totalSupply() implementation.
* @author @FrankPoncelet
*
*/
contract VOXCoodles is ERC721F {
uint256 public tokenPrice = 0.08 ether;
uint256 public discountedTokenPrice = 0.06 ether;
uint256 public wLTokenPrice = 0.07 ether;
uint256 public constant MAX_TOKENS=10000;
uint public constant MAX_PURCHASE = 26; // set 1 to high to avoid some gas
uint public constant MAX_RESERVE = 26; // set 1 to high to avoid some gas
bool public saleIsActive;
bool public preSaleIsActive;
mapping(address => uint256) private freeMintAmount;
mapping(address => bool) private whitelist;
mapping(address => uint256) private tokensMinted;
address private constant FRANK = 0xF40Fd88ac59A206D009A07F8c09828a01e2ACC0d;
address private constant JOOSE = 0xE6232CE1d78500DC9377daaE7DD87A609d2E8259;
address private constant JLOW = 0xa6bB71dd727C84c1F595587E100356fAfF730566;
address private constant MURDA = 0xCa96c691C79e4F57e6d659806Fe99bAEfE77DC36;
address private constant ASUKA = 0x812B50c025f0d950Df1E9B4F59C79BB00b08401c;
IERC721 coodles;
event PriceChange(address _by, uint256 price);
constructor() ERC721F("VOXCoodles", "VCDL") {
setBaseTokenURI("ipfs://QmVy7VQUFtTQawBsp4tbJPp9MgbTKS4L7WSDpZEdZUzsiD/");
_safeMint( FRANK, 0);
coodles = IERC721(0x9C38Bc76f282EB881a387C04fB67e9fc60aECF78);
}
/**
* Mint Tokens to a wallet.
*/
function mint(address to,uint numberOfTokens) public onlyOwner {
mintLoop(to, numberOfTokens);
}
/**
* Mint Tokens to the owners reserve.
*/
function reserveTokens() external onlyOwner {
mintLoop(owner(),MAX_RESERVE-1);
}
/**
* Pause sale if active, make active if paused
*/
function flipSaleState() public onlyOwner {
saleIsActive = !saleIsActive;
if(saleIsActive){
preSaleIsActive=false;
}
}
/**
* Pause sale if active, make active if paused
*/
function flipPreSaleState() public onlyOwner {
preSaleIsActive = !preSaleIsActive;
if(preSaleIsActive){
saleIsActive=false;
}
}
/**
* add an address and amount to the FreeMints
*/
function addFreeMint(address _address, uint256 amount) public onlyOwner {
freeMintAmount[_address] = amount;
}
/**
* add an array of address to the freemints
*/
function addFreeMints(address[] memory _address, uint256 amount) external onlyOwner {
for (uint i=0; i<_address.length; i++) {
addFreeMint(_address[i],amount);
}
}
/**
* remove an address off the freemints
*/
function removeFreeMint(address _address) external onlyOwner {
freeMintAmount[_address] = 0;
}
/**
* returns true if the wallet still has free mints.
*/
function freeMints(address _address) public view returns(uint256) {
return freeMintAmount[_address];
}
/**
* Set price
*/
function setPrice(uint256 price) public onlyOwner {
tokenPrice = price;
emit PriceChange(msg.sender, tokenPrice);
}
/**
* add an address to the WL
*/
function addWL(address _address) public onlyOwner {
whitelist[_address] = true;
}
/**
* add an array of address to the WL
*/
function addAdresses(address[] memory _address) external onlyOwner {
for (uint i=0; i<_address.length; i++) {
addWL(_address[i]);
}
}
/**
* remove an address off the WL
*/
function removeWL(address _address) external onlyOwner {
whitelist[_address] = false;
}
/**
* returns true if the wallet is Whitelisted.
*/
function isWhitelisted(address _address) public view returns(bool) {
return whitelist[_address];
}
function getSalePrice(uint256 numberOfTokens, address _address) public view returns (uint256) {
if (freeMints(_address)>0 && preSaleIsActive){
if (numberOfTokens>=freeMints(_address)){
numberOfTokens -= freeMints(_address);
}else{
numberOfTokens=0;
}
}
uint256 price=tokenPrice;
if (preSaleIsActive && coodles.balanceOf(_address)>0 ){
price=discountedTokenPrice;
}else if(preSaleIsActive && isWhitelisted(_address)){
price=wLTokenPrice;
}
return numberOfTokens * price;
}
function getMaxMintAmount(address _address) public view returns (uint256) {
if (preSaleIsActive && coodles.balanceOf(_address)>0 ){
return 3-tokensMinted[_address];
}else if(preSaleIsActive && isWhitelisted(_address)){
return 2-tokensMinted[_address];
}else if (saleIsActive){
return 25;
} else {
return 0;
}
}
function mint(uint256 numberOfTokens) external payable {
require(msg.sender == tx.origin);
if (preSaleIsActive){
if(coodles.balanceOf(msg.sender)>0){
require(tokensMinted[msg.sender]+numberOfTokens <4,"Max 3 tokens in presale");
}else{
require(tokensMinted[msg.sender]+numberOfTokens <3,"Max 2 tokens in presale");
require(isWhitelisted(msg.sender),"sender is NOT Whitelisted ");
}
} else {
require(saleIsActive, "Sale must be active to mint Tokens");
}
require(getSalePrice(numberOfTokens,msg.sender) <= msg.value, "Ether value sent is not correct");
if (numberOfTokens>= freeMints(msg.sender)){
freeMintAmount[msg.sender]=0;
}else{
freeMintAmount[msg.sender]-=numberOfTokens;
}
tokensMinted[msg.sender] += numberOfTokens;
mintLoop(msg.sender,numberOfTokens);
}
function mintLoop(address to,uint256 numberOfTokens) private {
require(numberOfTokens > 0, "numberOfNfts cannot be 0");
require(numberOfTokens < MAX_PURCHASE, "Can only mint 25 tokens at a time");
uint256 supply = totalSupply();
require(supply+numberOfTokens <= MAX_TOKENS, "Purchase would exceed max supply of Tokens");
for(uint256 i; i < numberOfTokens; i++){
_safeMint( to, supply + i );
}
}
/**
* Witdraw the funds from the contract.
*/
function withdraw() public onlyOwner {
uint256 balance = address(this).balance;
require(balance > 0, "Insufficent balance");
_withdraw(FRANK,(balance * 5) / 100);
_withdraw(JOOSE,(balance * 30) / 100);
_withdraw(JLOW,(balance * 9) / 100);
_withdraw(MURDA,(balance * 15) / 100);
_withdraw(ASUKA,(balance * 3) / 100);
_withdraw(owner(), address(this).balance);
}
}
{
"compilationTarget": {
"contracts/VOXCoodles.sol": "VOXCoodles"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 1000
},
"remappings": []
}
[{"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":false,"internalType":"address","name":"_by","type":"address"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"}],"name":"PriceChange","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"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"MAX_PURCHASE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_RESERVE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_TOKENS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"_address","type":"address[]"}],"name":"addAdresses","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"addFreeMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_address","type":"address[]"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"addFreeMints","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"}],"name":"addWL","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":"discountedTokenPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"flipPreSaleState","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"flipSaleState","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"}],"name":"freeMints","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"_address","type":"address"}],"name":"getMaxMintAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"numberOfTokens","type":"uint256"},{"internalType":"address","name":"_address","type":"address"}],"name":"getSalePrice","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":[{"internalType":"address","name":"_address","type":"address"}],"name":"isWhitelisted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"numberOfTokens","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"numberOfTokens","type":"uint256"}],"name":"mint","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":"preSaleIsActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"}],"name":"removeFreeMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"}],"name":"removeWL","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"reserveTokens","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":"saleIsActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"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":"baseURI","type":"string"}],"name":"setBaseTokenURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"price","type":"uint256"}],"name":"setPrice","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":[],"name":"tokenPrice","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":"wLTokenPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"walletOfOwner","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]