Virago: The Beginning

Updated on July 29 2022

Virago: The Beginning is the first Collection of 7,777 Viragos on the Ethereum Blockchain.

These Viragos are not only beautiful, but dangerous. The metaverse might be new but the Viragos have always existed. Where did they come from? What are they looking for? Did they come to help or did they come to harm us? Every question seems to lead to more mysteries.

Traits

14 Backgrounds

20 Skin Colors

34 Clothes

45 Eyes

61 Hair Colors

26 Mouth

4 Necklace

Audit

Virago: The Beginning Contract

https://etherscan.io/address/0x06220ab8413f9911403548a36d4c9dc6481e6918

//Contract based on [https://docs.openzeppelin.com/contracts/3.x/erc721](https://docs.openzeppelin.com/contracts/3.x/erc721)
// SPDX-License-Identifier: MIT
pragma solidity 0.8.12;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";

contract MetaMilf is ERC721, ERC721Enumerable, Ownable {

	
	uint public constant MAX_TOKENS = 7769;
	uint public constant MAX_TOKENS_VIP = 8;
	
	uint private _currentToken = 0;
	
	uint public CURR_MINT_COST = 0.1 ether;
	
	//---- Round based supplies
	string private CURR_ROUND_NAME = "Presale";
	uint private CURR_ROUND_SUPPLY = 2000;
	uint private CURR_ROUND_TIME = 0;
	uint private maxMintAmount = 2;
	uint private nftPerAddressLimit = 2;
	bytes32 private verificationHash = 0x3b25f67d4e97f5c0030ea90ca2882dbcefa05d1ef454bb67a77533172f4c6f38;

	uint private currentVIPs = 0;
	
	bool public hasSaleStarted = false;
	bool public onlyWhitelisted = true;
	
	string public baseURI;
	
    uint256 private remaining = MAX_TOKENS;
    mapping(uint256 => uint256) private cache;
	
	constructor() ERC721("MetaMilfs", "METAMILFS") {
		setBaseURI("http://api.metamilfs.io/metamilf/");
	}

	function totalSupply() public view override returns(uint) {
		return _currentToken;
	}

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

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

    function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal override(ERC721, ERC721Enumerable) {
        super._beforeTokenTransfer(from, to, tokenId);
    }
	
	function walletOfOwner(address _owner) public view returns (uint256[] memory)
	{
		uint256 ownerTokenCount = balanceOf(_owner);
		uint256[] memory tokenIds = new uint256[](ownerTokenCount);
		for (uint256 i; i < ownerTokenCount; i++) {
			tokenIds[i] = tokenOfOwnerByIndex(_owner, i);
		}
		return tokenIds;
	}

  
    function drawIndex() private returns (uint256) {
        uint256 i = uint(keccak256(abi.encodePacked(block.timestamp, msg.sender, remaining))) % remaining;

        uint index = cache[i] == 0 ? i : cache[i];
		index = index == 0 ? MAX_TOKENS : index;
		
        cache[i] = cache[remaining - 1] == 0 ? remaining - 1 : cache[remaining - 1];
        remaining = remaining - 1;
		
		return index;
    }

	function mintNFT(uint _mintAmount, bytes32[] memory proof) external payable {
		require(msg.value >= CURR_MINT_COST * _mintAmount, "Insufficient funds");
		require(hasSaleStarted == true, "Sale hasn't started");
		require(_mintAmount > 0, "Need to mint at least 1 NFT");
		require(_mintAmount <= maxMintAmount, "Max mint amount per transaction exceeded");
		require(_mintAmount <= CURR_ROUND_SUPPLY, "We're at max supply!");
		require((_mintAmount  + balanceOf(msg.sender)) <= nftPerAddressLimit, "Max NFT per address exceeded");

        if(onlyWhitelisted == true) {
			bytes32 user = keccak256(abi.encodePacked(msg.sender));
			require(verify(user,proof), "User is not whitelisted");
        }

		for (uint256 i = 1; i <= _mintAmount; i++) {
			_currentToken++;
			CURR_ROUND_SUPPLY--;
			uint theToken = drawIndex();
			_safeMint(msg.sender, theToken);
		}
	}
	
	
   function getInformations() external view returns (string memory, uint, uint, uint, uint,uint,uint, bool,bool)
   {
		return (CURR_ROUND_NAME,CURR_ROUND_SUPPLY,CURR_ROUND_TIME,CURR_MINT_COST,maxMintAmount,nftPerAddressLimit, _currentToken, hasSaleStarted, onlyWhitelisted);
   }
	
	function verify(bytes32 user, bytes32[] memory proof) internal view returns (bool)
	{
		bytes32 computedHash = user;

		for (uint256 i = 0; i < proof.length; i++) {
			bytes32 proofElement = proof[i];

			if (computedHash <= proofElement) {
				computedHash = keccak256(abi.encodePacked(computedHash, proofElement));
			} else {
				computedHash = keccak256(abi.encodePacked(proofElement, computedHash));
			}
		}
		return computedHash == verificationHash;
	}

	//only owner functions
	
	function setNewRound(uint _supply, uint cost, string memory name, uint perTransactionLimit, uint perAddressLimit, uint theTime, bool isOnlyWhitelisted, bool saleState) external onlyOwner {
		require(_supply <= (MAX_TOKENS - _currentToken), "Exceeded supply");
		CURR_ROUND_SUPPLY = _supply;
		CURR_MINT_COST = cost;
		CURR_ROUND_NAME = name;
		maxMintAmount = perTransactionLimit;
		nftPerAddressLimit = perAddressLimit;
		CURR_ROUND_TIME = theTime;
		hasSaleStarted = saleState;
		onlyWhitelisted = isOnlyWhitelisted;
	}

	function setVerificationHash(bytes32 hash) external onlyOwner
	{
		verificationHash = hash;
	}	
	
	function setOnlyWhitelisted(bool _state) external onlyOwner {
		onlyWhitelisted = _state;
	}

	function setBaseURI(string memory _newBaseURI) public onlyOwner {
		baseURI = _newBaseURI;
	}

	function reserveVIP(uint numTokens, address recipient) external onlyOwner {
		require((currentVIPs + numTokens) <= MAX_TOKENS_VIP, "Exceeded VIP supply");
		uint index;
		for(index = 1; index <= numTokens; index++) {
			_currentToken++;
			currentVIPs = currentVIPs + 1;
			uint theToken = currentVIPs + MAX_TOKENS;
			_safeMint(recipient, theToken);
		}
	}

	function Giveaways(uint numTokens, address recipient) external onlyOwner {
		require((_currentToken + numTokens) <= MAX_TOKENS, "Exceeded supply");
		uint index;
		for(index = 1; index <= numTokens; index++) {
			_currentToken++;
			uint theToken = drawIndex();
			_safeMint(recipient, theToken);
		}
	}

	function withdraw(uint amount) external onlyOwner {
		require(payable(msg.sender).send(amount));
	}
	
	
	function setSaleStarted(bool _state) external onlyOwner {
		hasSaleStarted = _state;
	}
}

Last updated