Add a Mint Function to Your NFT Smart Contract

Ryan Harris
InstructorRyan Harris
Share this video with your friends

Social Share Links

Send Tweet
Published 2 years ago
Updated 2 years ago

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.

mathias gheno
mathias gheno
~ 2 years ago

The main function works as expect, but for me the mint function is not avaliable

pragma solidity >=0.8.0 <0.9.0;
//SPDX-License-Identifier: MIT

import "hardhat/console.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/utils/Counters.sol";

contract YourContract is ERC721URIStorage {
  using Counters for Counters.Counter;
  Counters.Counter private currentId;

  bool public saleIsActive;
  uint256 public totalTickets = 10;
  uint256 public availabelTickets = 10;
  mapping(address => uint256[]) public holderTokenIds;

  constructor() ERC721("NFTix", "NFTX") {

  function main() public {
    require(availabelTickets > 0, "Not enough tickets");
    _safeMint(msg.sender, currentId.current());

  function avaliableTicketsCount() public view returns (uint256) {
    return availabelTickets;

  function totalTicketsCount() public view returns (uint256) {
    return totalTickets;

  function openSale() public {
    saleIsActive = true;

  function closeSale() public {
    saleIsActive = false;
mathias gheno
mathias gheno
~ 2 years ago

Sorry, is mint the function you did not main. My bad.

Markdown supported.
Become a member to join the discussionEnroll Today