We need our users to be able to mint their NFT tickets. We also need to limit the number of available tickets.
Start by making sure each NFT has a unique ID. OpenZeppelin gives us the handy utility Counters
for this. We will increment the ID each time an NFT is minted.
Once your NFTs have IDs you can use the inherited _safeMint
function from OpenZeppelin in your mint
function to mint an NFT for the initiator of the function. Also, make sure to increment the ID and decrement the number of remaining NFTs.
Instructor: [0:00] First, we're going to import hardhat/console.sol. This will allow us to log messages to the Hardhat console running on the right. We're also going to import a helper utility called Counters from OpenZeppelin. This is going to help us keep track of our token IDs and how many tickets are left.
[0:16] In our contract below, we also need to import Counters, using Counters for Counters.Counter. Then, we'll create an instance of a Counter, Counters.Counter, make it a private state variable, and call it currentID.
[0:33] This new variable, currentID, is going to be used to keep track of each token's ID as its created. Since it wouldn't make sense for there to be a token zero, we're going to come in to our Constructor and add a new statement, currentID.increment.
[0:48] To prove this works, we can add a console statement to the Constructor, console.log(currentID.current). Then, if we run yarn deploy, you'll see that we logged out the value 1 when our contract was deployed above.
[1:10] Back in our smart contract, let's add two new state variables. We'll say uint256, make this a public state variable and call it Total Tickets. We'll set it to 10. Now we'll add another integer, uint256. It'll also be a public variable, and we'll call this Available Tickets. We'll also set that to 10.
[1:34] Now that we have all that set up, let's come down below and add a new mint function, function mint. This will be a public method, meaning, it can be called by other smart contracts and dApps.
[1:46] Inside the mint function, we're going to call safeMint, which is a function we've inherited from the OpenZeppelin library. We're going to pass it two arguments. The first is going to be message.sender. This is the address of the blockchain account initiating this transaction.
[2:01] Next, we'll pass it currentID.current, which is the ID of the token being minted. Anytime someone mints a new ticket, we're going to want to increment this currentID value.
[2:14] Let's come down into our mint function again. We'll say, current ID.increment. Now, there are certain cases where we wouldn't want this transaction to succeed. For example, there aren't enough available tickets left in order to mint a new one.
[2:30] Let's go into our mint function again, and at the very top, add a require statement. In this case, we will want to check that there are enough available tickets before minting a new one. We'll say, require availableTickets >. If it's not, we'll add this optional log and say, "Not enough tickets."
[2:48] We're also going to need to decrement the amount of available tickets every time an NFT is minted. Let's come down below and say, availableTickets = availableTickets - 1. Let's come down here, and we're going to add a new function, function availableTicketCount, which will take no arguments. It will be a public method.
[3:16] We can add the view keyword here as well, since it won't be modifying our contract state. This method will return a uint256. Inside, we'll just return availableTickets. Below, we'll add another method. We'll say, function totalTicketCount. This will be a public method with the view keyword, and it will also return a uint256. Inside, we'll just return totalTickets.
[3:48] Let's add one more variable to our contract state. Let's come up to the top of the contract. We'll add a new mapping here, which is an object of key-value pairs. In this case, it'll be a public variable, and we'll call it holderTokenID.
[4:04] In this case, the keys will be wallet addresses that hold our NFTs. We'll say address here. The values will be integer arrays, uint256, which represent the token IDs the address holds.
[4:20] Now let's jump into our terminal and deploy the contract -- yarn deploy. If we open a third terminal window here, we can spin up our React application. In the scaffold-eth UI, you can see some of the new things we've added to the contract.
[4:38] Down below, we actually have a mint function here. Let's grab some funds from the faucet. We can send a transaction to mint, and we have a success. If we go up, you can see that we have nine tickets available, but there are still 10 total tickets.
[4:56] In summary, we imported counters from OpenZeppelin to keep track of our current token ID, added some values to our contract state, and created a function for minting new tokens.