Asset Chain Academy
  • Join the Asset Chain Academy
  • MODULE 1: GETTING STARTED
    • Introduction to Asset Chain
    • Environment Setup & Installation
    • Contributing
    • Asset Chain Starter Kits
  • MODULE 2: DEVELOPER RESOURCES
    • Resources Explained
    • Cyfrin Updraft
    • Learnweb3
    • Chainlink Bootcamps
    • Alchemy University
    • Smart Contract Programmer
  • MODULE 3: BEGINNER TUTORIALS
    • Create a Token
    • Write & Deploy an NFT
    • Mint an NFT
    • Asset Chain Explorers
    • Payments
    • Building with Thirdweb
    • Mobile Apps on Asset Chain
    • ⁠ Connecting to wallet
      • Wallet Connect
  • MODULE 4: INTERMEDIATE TUTORIALS
    • Smart Contract Verification
    • MultiSig Wallet
    • Setup a node
    • Staking
    • Setting up an Indexer
    • Asset Chain Telegram Mini App Demo
  • MODULE 5: ADVANCED TUTORIALS
    • EVM-Gas-Optimizations
    • Smart Contract Audit
    • Decentralized Exchanges
    • Arbitrage Bots
    • References
Powered by GitBook
On this page
  • Step 1: Download NFT Minter starterkits
  • Step 2: NFT Metadata 101
  • Step 3: Use Pinata to pin your metadata to IPFS
  • Step 4: Implement the MintNFt function
  1. MODULE 3: BEGINNER TUTORIALS

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.

PreviousWrite & Deploy an NFTNextAsset Chain Explorers

Last updated 10 months ago

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.

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! ✅

Create your Pinata API 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

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?

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

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

Doing so should open 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.

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

Step 3: Use to pin your metadata to IPFS

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

Navigate to the page, then select the "New Key" button at the top, set the Admin widget as enabled, and name your key.

Fortunately for us, Pinata has an and a convenient JavaScript with axios example that we can use, with some slight modifications.

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

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

README.md
http://localhost:3000/
Pinata
Pinata
here
https://app.pinata.cloud/developers/api-keys
API specifically for uploading JSON data to IPFS
axios
Telegram
https://github.com/xendfinance/Mint-an-Nftgithub.com
mint nft starter kits
https://github.com/xendfinance/Mint-an-Nft/tree/updatedgithub.com
updated codebase
Asset Chain Starterkits
live link to preview the nft minter
Logo
What your UI should look like.
Create your Pinata API key
Make sure to save your API key and secret in a safe place