├── NFT-Minter.sol └── README.md /NFT-Minter.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | 3 | pragma solidity >=0.7.0 <0.9.0; 4 | 5 | // Open Zeppelin imports 6 | import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol"; 7 | import "@openzeppelin/contracts/access/Ownable.sol"; 8 | 9 | // Inherits 10 | contract NFT is ERC721Enumerable, Ownable { 11 | using Strings for uint256; 12 | 13 | string public baseURI; 14 | string public baseExtension = ".json"; 15 | uint256 public cost = 1; // Set this to your cost per NFT 16 | uint256 public maxSupply = 40; // Set this to your max # of NFTs for the collection 17 | uint256 public maxMintAmount = 5; // Set this to your max # of NFTs for any wallet 18 | address public owner1 = 0x71c7656ec7ab88b098defb751b7401b5f6d8976f; // Set this to first team member address 19 | address public owner2 = 0x71c7656ec7ab88b098defb751b7401b5f6d8976f; // Set this to second team member address (different address) 20 | 21 | bool public paused = false; 22 | mapping(address => uint256) public addressMintedBalance; 23 | 24 | constructor( 25 | string memory _name, 26 | string memory _symbol, 27 | string memory _initBaseURI, // usually in form of ipfs:// 28 | uint256 numTokenOnDeploy // This is how many NFTs are sent to the two owner addresses on deploy 29 | ) ERC721(_name, _symbol) { 30 | setBaseURI(_initBaseURI); 31 | mint(owner1, numTokenOnDeploy); 32 | mint(owner2, numTokenOnDeploy); 33 | } 34 | 35 | // internal 36 | function _baseURI() internal view virtual override returns (string memory) { 37 | return baseURI; 38 | } 39 | 40 | // public 41 | function mint(address _to, uint256 _mintAmount) public payable { 42 | require(!paused, "the contract is paused"); 43 | uint256 supply = totalSupply(); 44 | require(_mintAmount > 0, "need to mint at least 1 NFT"); 45 | require(_mintAmount <= maxMintAmount, "max mint amount per session exceeded"); 46 | require(supply + _mintAmount <= maxSupply, "max NFT limit exceeded"); 47 | 48 | if (msg.sender != owner() && msg.sender != owner2) { 49 | require(msg.value >= cost * _mintAmount, "insufficient funds"); 50 | } 51 | 52 | for (uint256 i = 1; i <= _mintAmount; i++) { 53 | addressMintedBalance[_to]++; 54 | _safeMint(_to, supply + i); 55 | } 56 | 57 | } 58 | 59 | function walletOfOwner(address _owner) /// Returns list of all token ids owned by given wallet 60 | public 61 | view 62 | returns (uint256[] memory) 63 | { 64 | uint256 ownerTokenCount = balanceOf(_owner); 65 | uint256[] memory tokenIds = new uint256[](ownerTokenCount); 66 | for (uint256 i; i < ownerTokenCount; i++) { 67 | tokenIds[i] = tokenOfOwnerByIndex(_owner, i); 68 | } 69 | return tokenIds; 70 | } 71 | 72 | function tokenURI(uint256 tokenId) 73 | public 74 | view 75 | virtual 76 | override 77 | returns (string memory) 78 | { 79 | require( 80 | _exists(tokenId), 81 | "ERC721Metadata: URI query for nonexistent token" 82 | ); 83 | 84 | string memory currentBaseURI = _baseURI(); 85 | return bytes(currentBaseURI).length > 0 86 | ? string(abi.encodePacked(currentBaseURI, "/NFTname", tokenId.toString(), baseExtension)) //Change "/NFTname" to "/YourNFTName". If is fine to use no name but DO NOT REMOVE THE SLASH 87 | : ""; 88 | } 89 | 90 | //only owner 91 | 92 | function setCost(uint256 _newCost) public onlyOwner { 93 | cost = _newCost; 94 | } 95 | 96 | function setmaxMintAmount(uint256 _newmaxMintAmount) public onlyOwner { 97 | maxMintAmount = _newmaxMintAmount; 98 | } 99 | 100 | function setBaseURI(string memory _newBaseURI) public onlyOwner { 101 | baseURI = _newBaseURI; 102 | } 103 | 104 | function pause(bool _state) public onlyOwner { 105 | paused = _state; 106 | } 107 | 108 | // This function withdraws all funds from the contract giving half to team member one and half to team member two 109 | function withdraw() public payable onlyOwner { 110 | (bool PP1, ) = payable(owner2).call{value: address(this).balance * 50 / 100}(""); 111 | require(PP1); 112 | (bool PP2, ) = payable(owner1).call{value: address(this).balance}(""); 113 | require(PP2); 114 | // ============================================================================= 115 | } 116 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This README assumes you have the Metamask Wallet extension installed in your browser. I will explain the code with the intention that it will be used on the Polygon network, but it will work exactly the same on Ethereum and the Ethereum network. 2 | 3 | # Solidity-NFT-Minting-Contract 4 | This contract allows you to lazy mint a NFT collection on the Ethereum or Polygon blockchains. 5 | 6 | With a few simple customization you will be able to deploy this contract onto one of these networks so people can pay to mint your NFTs. 7 | 8 |

CUSTOMIZE

9 | 10 | First you will need to customize the code to suit your project. Things you will need to decide: 11 | 12 | - cost - What you want to charge for each NFT. Will be ETH or MATIC depending which chain you deploy on. 13 | - maxMintAmount - The maximum number of NFTs the contract can produce. 14 | - maxMintAmount - The max number of NFTs from your collection that can be minted per transaction 15 | - numTokenOnDeploy - The number of NFTs you want to give yourself when you deploy the contract. 16 | - owner1 and owner2 - The wallet addresses you want to send your portion of the NFTs to AND the wallets that get paid when you withdraw any funds used for purchase. 17 | 18 | These are all in the initial contract variables (numTokenOnDeploy is in the contructor). 19 | 20 |

COMPILE

21 | 22 | We are going to deploy this contract using the remix IDE. I experimented with Brownie for Python and it seemed like a useful package for smart contracts but I found Remix to be much simpler. Go to https://remix.ethereum.org/. You can past the NFT-Minter.sol code right into the IDE. Click throught the tabs on the left side menu. We will be using the "Compile" and "Deploy" tabs. Click into the Compile tab. Make sure that in the contract selection drop-down "NFT-Minter.sol" is selected (for me it was defaulting to "Ownable.sol") and click the big Compile button. 23 | 24 | Tip: Open up a txt doc for storing some data we are going to need later. Scroll down to the bottom of the Solidity Compiler left-hand sidebar. Click on the little Copy ABI button and paste this into your text doc. If you plan on verifying your contract or if you plan on making the Web3 enabled minting website (code coming soon) you will need this. 25 | 26 |

DEPLOY

27 | 28 | Click into the "Deploy" tab on the left-hand menu. Set the Environment drop-down to "Injected Web3". This will then open up your Metamask and ask for you to sign-in. Set your Metamask network to "Polygon Mainnet". Connect the Metamask account that you wish to be "owner1" in the contract to Remix. Ensure you've got some MATIC in that wallet. After connecting the right account to Remix you should see the public key for that wallet in the "Account" drop-down back in the "Deploy & Run Transactions" left-hand menu. Ensure that account is selected. Select the "NFT-Minter.sol" contract in the Contract drop-down. 29 | 30 | Now you are almost ready to click the "Deploy" button. In order to deploy this contract you will need to set the \_name, \_symbol, \_initBaseUri, and numTokenCreate. You will see a accordion menu apear beneath the Deploy button, this will give you four text fields to submit these four items. The \_name and \_symbol are the name and symbol for the collection, these will be read by exchanges. numTokenCreate is simply the number of tokens you want sent to each of the owner1 and onwer2 wallet addresses when the contract deploys. 31 | 32 | \_initBaseUri is VERY IMPORTANT. This is the CID address from the metadata directory you uploaded to Pinata using my Python-NFT-Collection-Generator repository instructions. If you do not enter this EXACTLY your smart contract will not be connected to your NFT artwork. You must type "ipfs://". Cut "" and replace it with your actual CID. Your CID can be found in your Pinata account. Remember it is the CID for your metadata directory, not for your images directory. 33 | 34 | Once you have entered all 4 constructor parameters entered correctly - click that deploy button. Metamask will once again ask for your confirmation and this time will charge you for the transaction. Once deployed, you will see your new contract under the "Deployed Contracts". Click the arrow to expand and interact with it. 35 | 36 | Tip: Copy the contract address and paste it at the top of that same txt doc when you pasted your contract ABI. 37 | 38 | Congratulations! You've successfully deployed your contract! You should have some cool new NFTs in your Metamask wallet. (You have to "Import Token" before they apear in your wallet. If you don't know how to do this a quick Google search will show you) 39 | 40 | You should now be able to see your NFTs on Opensea.io! Head over to the website and log in with the same wallet address you used to deploy your contract. If can take some time before Opensea loads the images and metadata, but your should be able to see the contract and number of tokens you own right away. Great! 41 | 42 | This is cool, but how do can people buy your NFTs? Next I'm going to post the code for a fully functioning Web3 enabled React website for you to make some sweet sales! 43 | --------------------------------------------------------------------------------