Skip to main content

How to Mint an NFT (Part 2/3 of NFT Tutorial Series)

ERC-721
alchemy
solidity
smart contracts
Beginner
Sumi Mudgil
April 22, 2021
9 minute read

“Minting an NFT” is the act of publishing a unique instance of your ERC-721 token on the blockchain. Using our smart contract from Part 1 of this NFT tutorial series, let’s flex our Web3 skills and mint an NFT. At the end of this tutorial, you’ll be able to mint as many NFTs as your heart (and wallet) desires!

Let’s get started!

Step 1: Check your setup

If you followed the first tutorial on creating your NFT smart contract, you already have everything you need: a Hardhat 3 project with the Ethers plugin (opens in a new tab) and ethers.js (opens in a new tab), a library used to make creating requests to the Ethereum blockchain easier. We’ll write our minting code as a Hardhat script, so it reuses the Sepolia network settings and the API_URL and PRIVATE_KEY values from Part 1 — there’s nothing new to install.

Step 2: Create a mint-nft.js file

Inside your scripts directory, create a mint-nft.js file and add the following lines of code:

import { network } from "hardhat"

const { ethers } = await network.create()

As in our deploy script, network.create() connects to the network you choose with --network when you run the script, and gives us an ethers object for it.

Step 3: Grab your contract ABI

Our contract ABI (Application Binary Interface) is the interface to interact with our smart contract. You can learn more about . Hardhat automatically generates an ABI for us when it compiles the contract and saves it in the artifacts/contracts/MyNFT.sol/MyNFT.json file. The Hardhat Ethers plugin reads it from there for us when we create our contract instance in step 5, so we don't need to load it ourselves.

If you want to see the ABI you can print it to your console. From your project's root directory, run:

node -p "JSON.stringify(require('./artifacts/contracts/MyNFT.sol/MyNFT.json').abi)"

Step 4: Configure the metadata for your NFT using IPFS

If you remember from our tutorial in Part 1, our mintNFT smart contract function takes in a tokenURI parameter that should resolve to a JSON document describing the NFT's metadata— which is really what brings the NFT to life, allowing it to have configurable properties, such as a name, description, image, and other attributes.

Interplanetary File System (IPFS) is a decentralized protocol and peer-to-peer network for storing and sharing data in a distributed file system.

We will use Pinata, a convenient IPFS API and toolkit, to store our NFT asset and metadata to ensure our NFT is truly decentralized. If you don’t have a Pinata account, sign up for a free account here (opens in a new tab) and complete the steps to verify your email.

Once you’ve created an account:

  • Navigate to the Files page (opens in a new tab) and click the "Add" button in the top right corner of the page.

  • Upload an image to Pinata — this will be the image asset for your NFT. Feel free to name the asset whatever you wish. Make sure you upload it to public IPFS: files on Private IPFS (opens in a new tab) can't be fetched by wallets and marketplaces that display your NFT.

  • After you upload, you'll see the file listed on the Files page together with its CID (content identifier). Copy the CID. You can view your upload at: https://gateway.pinata.cloud/ipfs/<CID>, or through the dedicated gateway listed under "Gateways" in the Pinata sidebar. You can find the image we used on IPFS here (opens in a new tab), for example.

Now, we’re going to want to upload one more document to Pinata. But before we do that, we need to create it!

In your root directory, make a new file called nft-metadata.json and add the following json code:

Feel free to change the data in the json. You can remove or add to the attributes section. Most importantly, make sure the image field points to the location of your IPFS image, in the form ipfs://<image-CID> — otherwise, your NFT will include a photo of a (very cute!) dog.

Once you’re done editing the JSON file, save it and upload it to Pinata, following the same steps we did for uploading the image. Copy the CID of nft-metadata.json too; we'll need it in step 9.

Step 5: Create an instance of your contract

Now, to interact with our contract, we need to create an instance of it in our code. To do so we'll need our contract address, which our deploy script printed in Part 1. You can also find it on Etherscan (opens in a new tab) or Blockscout (opens in a new tab) by looking up the address you used to deploy the contract.

View your contract address on Etherscan

In the above example, our contract address is 0x5a738a5c5fe46a1fd5ee7dd7e38f722e2aef7778.

Next we will use the Hardhat Ethers plugin's getContractAt method to create our contract using its name (which tells it which ABI to use) and its address. In your mint-nft.js file, add the following, replacing the address with your own:

const contractAddress = "0x5a738a5c5fe46a1fd5ee7dd7e38f722e2aef7778"
const nftContract = await ethers.getContractAt("MyNFT", contractAddress)

Step 6: Check the .env file

Every transaction we send has to be signed with your account's private key. If you completed part 1 of the tutorial, our .env file should already look like this:

API_URL="https://eth-sepolia.g.alchemy.com/v2/your-api-key"
PRIVATE_KEY="your-metamask-private-key"

There's no need to add your public address: ethers works it out from the private key.

Step 7: Create your transaction

First, let’s define a function named mintNFT(tokenURI) and create our transaction by doing the following:

  1. Get the account we send the transaction from. ethers.getSigners() returns the accounts configured for the network, which on Sepolia is the account whose private key is in .env. Since mintNFT is onlyOwner, this must be the same account that deployed the contract.

  2. Call the mintNFT function on our contract instance, with our own address as the recipient and the metadata URI. This is the computation we wish to perform in this transaction — which in this case is minting an NFT.

You don't need to work out the nonce (the number of transactions sent from your address, which prevents replay attacks), the gas limit, or the fees yourself: ethers fetches or estimates them before sending the transaction.

Your mint-nft.js file should look like this now:

Step 8: Sign the transaction

Because the network is configured with our private key, ethers signs the transaction with it automatically before sending it.

Calling mintNFT returns once the transaction has been sent, and gives us the transaction hash, which we can use to make sure our transaction was mined and didn't get dropped by the network. tx.wait() then waits until the transaction is included in a block. We've also added some error checking so we know if our transaction successfully went through.

Step 9: Call mintNFT and run mint-nft.js

Remember the nft-metadata.json you uploaded to Pinata? Get its CID from Pinata and pass ipfs://<metadata-CID> as the parameter to the function mintNFT. Wallets and marketplaces resolve ipfs:// URIs through an IPFS gateway of their choice, so your NFT doesn't depend on any single gateway.

Double check that the CID you copied links to your nft-metadata.json by loading https://gateway.pinata.cloud/ipfs/<metadata-CID> into a separate window. The page should look similar to the screenshot below:

Your page should display the json metadataYour page should display the json metadata

Altogether, your code should look something like this:

Now, run the script against Sepolia to mint your NFT:

npx hardhat run scripts/mint-nft.js --network sepolia

After a few seconds, you should see a response like this in your terminal:

The hash of your transaction is: 0x301791fdf492001fcd9d5e5b12f3aa1bbbea9a88ed24993a8ab2cdae2d06e1e8
Your NFT was minted in block <block number>

To see the details of your transaction, search for its hash on Etherscan (opens in a new tab) or Blockscout (opens in a new tab).

View your NFT transaction hash on EtherscanView your NFT transaction hash on Etherscan

And that’s it! You’ve now deployed AND minted with a NFT on the Ethereum blockchain

Using the mint-nft.js you can mint as many NFTs as your heart (and wallet) desires! Just be sure to pass in a new tokenURI describing the NFT's metadata (otherwise, you'll just end up making a bunch of identical ones with different IDs).

Presumably, you’d like to be able to show off your NFT in your wallet — so be sure to check out Part 3: How to View Your NFT in Your Wallet!