Mint an NFT

This tutorial describes how to mint an NFT using the viem and the smart contract from Part I: Write & deploy an Nft.

Step 1: Download NFT Minter starterkits

Download the starter kits below that contains the contract code from the previous project: Write and Deploy an Nft.

mint nft starter kits

follow the guidlines on the README.md file to get your starter kits ready.

Doing so should open http://localhost:3000/ in your browser, where you'll see the frontend for our project. It should consist of 3 fields: a place to input a link to your NFT's asset, enter the name of your NFT, and provide a description.

Step 2: NFT Metadata 101

So remember the NFT metadata we just talked about in Step 1 of this tutorial—it brings an NFT to life, allowing it to have properties, such as a digital asset, name, description, and other attributes.

We're going to need to configure this metadata as a JSON object and store it, so we can pass it in as the tokenURI parameter when calling our smart contract's mintNFT function.

The text in the "Link to Asset", "Name", "Description" fields will comprise the different properties of our NFT's metadata. We'll format this metadata as a JSON object, but there are a couple options for where we can store this JSON object:

  • We could store it on the Asset Chain blockchain; however, doing so would be SUPER expensive (we're talking upwards of hundreds of dollars).

  • We could store it on a centralized server, like AWS or Firebase. But that would defeat our decentralization ethos. ❌

  • We could use IPFS, a decentralized protocol and peer-to-peer network for storing and sharing data in a distributed file system. As this protocol is decentralized and free, it is our best option! ✅

To store our metadata on IPFS, we will use Pinata, a convenient IPFS API and toolkit. In the next step, we'll explain exactly how to do this!

Step 3: Use Pinata to pin your metadata to IPFS

If you don't have a Pinata account, sign up for a free account here and complete the steps to verify your email and account.

Create your Pinata API key

Navigate to the https://app.pinata.cloud/developers/api-keys page, then select the "New Key" button at the top, set the Admin widget as enabled, and name your key.

You'll then be shown a popup with your API info. Make sure to put this somewhere safe.

Create a .env file

create a .env file in the root directory of your frontend and navigate to your .env file and add your Pinata API key and API secret to it, like so:

NEXT_PUBLIC_PINATA_KEY=<pinata-api-key>
NEXT_PUBLIC_PINATA_SECRET=<pinata-api-secret>

Save the file, and then you're ready to start writing the function to upload your JSON metadata to IPFS!

Implement pinJSONToIPFS

Fortunately for us, Pinata has an API specifically for uploading JSON data to IPFS and a convenient JavaScript with axios example that we can use, with some slight modifications.

In your utils folder, let's create another file called pinPinata.ts and then import our Pinata secret and key from the .env file like so:

const key = process.env.NEXT_PUBLIC_PINATA_KEY;
const secret = process.env.NEXT_PUBLIC_PINATA_SECRET;

Next, paste the additional code from below into your pinPinata.ts file. Don't worry, we'll break down what everything means!

import axios from "axios";
import toast from "react-hot-toast";

const key = process.env.NEXT_PUBLIC_PINATA_KEY;
const secret = process.env.NEXT_PUBLIC_PINATA_SECRET;


export const pinJsontoIPFS = async (JsonFile: any) => {
  const url = "https://api.pinata.cloud/pinning/pinJSONToIPFS";


  try {
    const res = await axios.post(url, JsonFile, {
      headers: {
        'pinata_api_key': key,
        'pinata_secret_api_key': secret,
      },
    });
    return "https://gateway.pinata.cloud/ipfs/" + res.data.IpfsHash;

  } catch (e: any) {
    toast.error(e.message);
  }
};

So what does this code do exactly?

First, it imports axios, a promise based HTTP client for the browser and node.js, which we will use to make a request to Pinata.

Then we have our asynchronous function pinJSONToIPFS, which takes a JSONBody as its input and the Pinata api key and secret in its header, all to make a POST request to theirpinJSONToIPFS API.

  • If this POST request is successful, then our function returns ahashstring where our metadata was pinned. We will use this hashstring returned as the tokenURI input to our smart contract's mint function.

  • If this post request fails, then our function returns a JSON object with the a message string that relays our error.

Step 4: Implement the MintNFt function

Inside your Debug.tsx file, let's define our function, MintNFt , which will mint our NFT as the name implies.

The three inputs to our function will be the url of our digital asset, name, and description.

Input error handling

Naturally, it makes sense to have some sort of input error handling at the start of the function, so we exit this function if our input parameters aren't correct. Inside our function, let's add the following code:

 if (url.trim() == "" || name.trim() == "" || description.trim() == "") {
      toast.error(
        "❗Please make sure all fields are completed before minting."
      );
      setLoading(false);
    }

Essentially, if any of the input parameters are an empty string, then we return a JSON object where the toast.error string relays that all fields in our UI must be complete.

Upload the metadata to IPFS

Once we know our metadata is formatted properly, the next step is to wrap it into a JSON object and upload it to IPFS via the pinJSONToIPFS we wrote!

To do so, we firstly need to import the pinJSONToIPFS function into our Debug.tsx file. At the very top of the Debug.tsx, let's add:

import { pinJsontoIPFS } from "@/utils/pinPinata";

Recall that pinJSONToIPFS takes in a JSON body. So before we make a call to it, we're going to need to format our url, name, and description parameters into a JSON object.


 if (url.trim() == "" || name.trim() == "" || description.trim() == "") {
      toast.error(
        "❗Please make sure all fields are completed before minting."
      );
      setLoading(false);
    }

    setLoading(true);
    const metaData = {
      url: url,
      name: name,
      description: description,
    };
    const pinataResponse = await pinJsontoIPFS(metaData);

The last thing to add in our mintNFT function is our Ethereum transaction:


 if (!account) return;
    const { request } = await publicClient.simulateContract({
      address: deployedContracts.assetchain_testnet.address as `0x${string}`,
      abi: deployedContracts.assetchain_testnet.abi,
      functionName: "mintNft", //refrence to the smartcontract code to get the function name
      //This args object takes in the two arguments needed in the mintNft function
      args: [account, pinataResponse],
      account,
    });
    const hash = await walletClient.writeContract(request);

That's a giant function! Below is the full code example of the MintNFT function

const MintNFt = async () => {
    if (url.trim() == "" || name.trim() == "" || description.trim() == "") {
      toast.error(
        "❗Please make sure all fields are completed before minting."
      );
      setLoading(false);
    }

    setLoading(true);
    const metaData = {
      url: url,
      name: name,
      description: description,
    };
    const pinataResponse = await pinJsontoIPFS(metaData);

    toast.success("Successfully Upload Metadata to IPFS", {
      duration: 4000,
    });
    toast.loading("Minting Nft.........", {
      duration: 8000,
    });

    if (!account) return;
    const { request } = await publicClient.simulateContract({
      address: deployedContracts.assetchain_testnet.address as `0x${string}`,
      abi: deployedContracts.assetchain_testnet.abi,
      functionName: "mintNft",
      args: [account, pinataResponse],
      account,
    });
    console.log("pinataResponse", pinataResponse);
    const hash = await walletClient.writeContract(request);
    setTransactionHash(hash);
     toast.success("Successfully Minted your NFT", {
       duration: 4000,
     });
     setLoading(false);
  };

Hurray, YourNFtMinter Project is Complete.

Below are link to preview project and the Completed Code for the Nft Minter

If you have questions, join our Telegram and say hello 👋. We're Active!

Last updated