└── CustomNft.sol /CustomNft.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.2; 3 | 4 | /// @title Custom NFT Contract (ERC721 compliant) 5 | /// @author Manav Vagdoda (vagdonic.github.io) 6 | 7 | import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; 8 | import "@openzeppelin/contracts/access/Ownable.sol"; 9 | import "@openzeppelin/contracts/utils/Counters.sol"; 10 | import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; 11 | import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol"; 12 | import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol"; 13 | 14 | contract CustomNft is ERC721, Ownable, ERC721URIStorage, ERC721Burnable{ 15 | using Counters for Counters.Counter; 16 | 17 | Counters.Counter public _tokenIdCounter; 18 | 19 | address Owner; 20 | 21 | constructor() ERC721("Evolving Pandas Token", "EPT") { 22 | Owner = msg.sender; 23 | } 24 | 25 | // function _baseURI() internal pure override returns (string memory) { 26 | // return "https://api.mnft.com/tokens/"; 27 | // } 28 | 29 | function _burn(uint256 tokenId) internal override(ERC721, ERC721URIStorage) { 30 | super._burn(tokenId); 31 | } 32 | 33 | function tokenURI(uint256 tokenId) 34 | public 35 | view 36 | override(ERC721, ERC721URIStorage) 37 | returns (string memory) 38 | { 39 | return super.tokenURI(tokenId); 40 | } 41 | 42 | mapping(address => bool) public whitelist; 43 | 44 | uint256 public openingTime; 45 | uint256 public closingTime; 46 | uint public mintRate = 0.001 ether; 47 | string public myTokenURI = "ipfs://QmSb9KiZKkST5p4cm1bSNJKbD2EtEvv9NmArULNqjoxwpm/"; 48 | string public commonEndpoint = "commonURI"; 49 | string public rareEndpoint = "rareURI"; 50 | string public baseExtension = ".json"; 51 | 52 | enum Stage {locked, presale, publicsale} 53 | 54 | function uint2strk(uint256 _i) internal pure returns (string memory str) { 55 | if (_i == 0) 56 | { 57 | return "0"; 58 | } 59 | uint256 j = _i; 60 | uint256 length; 61 | while (j != 0) 62 | { 63 | length++; 64 | j /= 10; 65 | } 66 | bytes memory bstr = new bytes(length); 67 | uint256 k = length; 68 | j = _i; 69 | while (j != 0) 70 | { 71 | bstr[--k] = bytes1(uint8(48 + j % 10)); 72 | j /= 10; 73 | } 74 | str = string(bstr); 75 | } 76 | 77 | function addToWhitelist(address _beneficiary) public onlyOwner { 78 | whitelist[_beneficiary] = true; 79 | } 80 | 81 | function TimedCrowdsale(uint256 _openingTime, uint256 _closingTime) public onlyOwner{ 82 | require(_openingTime >= block.timestamp); 83 | require(_closingTime >= _openingTime); 84 | openingTime = _openingTime; 85 | closingTime = _closingTime; 86 | } 87 | 88 | function addManyToWhitelist(address[] memory _beneficiaries) public onlyOwner { 89 | for (uint256 i = 0; i < _beneficiaries.length; i++) { 90 | whitelist[_beneficiaries[i]] = true; 91 | } 92 | } 93 | 94 | function checkStage() public view returns (Stage stage){ 95 | if(block.timestamp < openingTime) { 96 | stage = Stage.locked; 97 | return stage; 98 | } 99 | else if(block.timestamp >= openingTime && block.timestamp <= closingTime) { 100 | stage = Stage.presale; 101 | return stage; 102 | } 103 | else if(block.timestamp >= closingTime) { 104 | stage = Stage.publicsale; 105 | return stage; 106 | } 107 | } 108 | 109 | modifier isPresale { 110 | require(checkStage() == Stage.presale); 111 | _; 112 | } 113 | 114 | function iswhitelisted(address xyz) public view isPresale returns (bool) { 115 | if(whitelist[xyz]) return true; 116 | else return false; 117 | } 118 | 119 | modifier buffer(address abc) { 120 | require(openingTime != 0); 121 | require(checkStage() != Stage.locked); 122 | require((checkStage() == Stage.publicsale || iswhitelisted(abc))); 123 | _; 124 | } 125 | 126 | modifier checkAmount(uint _mintAmt) { 127 | require(_mintAmt < 8 && _mintAmt > 0); 128 | _; 129 | } 130 | 131 | function random() public view returns (uint256) { 132 | return uint256(keccak256(abi.encodePacked(block.timestamp, block.difficulty)))%10; 133 | } 134 | 135 | function safeMint(address to, uint _amtOfTokensToMint) public payable checkAmount(_amtOfTokensToMint) buffer(to){ 136 | require(msg.value == (_amtOfTokensToMint * mintRate)); 137 | for (uint i = 0; i < _amtOfTokensToMint; i++) { 138 | _tokenIdCounter.increment(); 139 | uint256 tokenId = _tokenIdCounter.current(); 140 | _safeMint(to, tokenId); 141 | string memory finalURI = uint2strk(tokenId); 142 | if(random() == 5) { 143 | finalURI = string(abi.encodePacked(rareEndpoint, finalURI, baseExtension)); 144 | } 145 | else { 146 | finalURI = string(abi.encodePacked(commonEndpoint, finalURI, baseExtension)); 147 | } 148 | _setTokenURI(tokenId, finalURI); 149 | } 150 | } 151 | 152 | function reserveMint(address _owner, uint _reserveAmt) public onlyOwner{ 153 | for (uint i = 0; i < _reserveAmt; i++) { 154 | _tokenIdCounter.increment(); 155 | uint256 tokenId = _tokenIdCounter.current(); 156 | _safeMint(_owner, tokenId); 157 | string memory finalURI = uint2strk(tokenId); 158 | finalURI = string(abi.encodePacked(commonEndpoint, finalURI, baseExtension)); 159 | _setTokenURI(tokenId, finalURI); 160 | } 161 | } 162 | 163 | function giveAway(address winner, uint256 _tokenIdToGiveaway) public onlyOwner { 164 | safeTransferFrom(msg.sender, winner, _tokenIdToGiveaway); 165 | } 166 | 167 | function getMintedTknsAmt() public view returns(uint256) { 168 | uint256 currentItem = _tokenIdCounter.current(); 169 | return currentItem; 170 | } 171 | } --------------------------------------------------------------------------------