DEV Community

Michael Etokakpan
Michael Etokakpan

Posted on • Originally published at blog.michaeltech.xyz on

How to Create an NFT Token

NFT(Non-Fungible Tokens) are tokens used to represent digital assets with inherent properties that are unique and that cannot be exchanged or interchanged(fungible), in many cases, they are used to represent items like images, art, etc. The Ethereum blockchain has a unique standard called the ERC721 for defining the functionality of these tokens. We will follow the template pattern of using Hardhat, Metamask, Alchemy, etc to build our smart contract just like in our other solidity tutorials

Project Setup

mkdir MikNFT
cd MikNFT
npm init -y

npm install --save-dev hardhat
npx hardhat

npm i @openzeppelin/contracts

Enter fullscreen mode Exit fullscreen mode

The code below imports the ERC721 library and inherits all the function implementation for ERC721, it also uses the Counters library which will be used for counting the number of tokens and giving each a unique positive integer value.

The contract is initialized with the name and symbol for the token the mintNFT function takes into two parameters the address where the NFT will be sent and the tokenURI which gives the metadata description of the token, it then returns the unique integer id of the token

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

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

contract MikNFT is ERC721URIStorage {
    using Counters for Counters.Counter;
    Counters.Counter private _tokenIds;

    constructor() ERC721("MikNFT", "NFT") {}

    function mintNFT(address recipient, string memory tokenURI)
        public

        returns (uint256)
    {
        _tokenIds.increment();

        uint256 newItemId = _tokenIds.current();
        _mint(recipient, newItemId);
        _setTokenURI(newItemId, tokenURI);

        return newItemId;
    }
}

Enter fullscreen mode Exit fullscreen mode

after it has successfully complied with this command,

npx hardhat compile

Enter fullscreen mode Exit fullscreen mode

we'll install the dotenv package to enable us to interact with our environment variables. The environment variables that will be used are the wallet private key, API_URL, and API_KEY, these will be kept in a .env file that will be added to the project's .gitignore list as these variables are quite sensitive and are not to be uploaded to a public repository.

npm install dotenv --save


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

Enter fullscreen mode Exit fullscreen mode

We'll go straight ahead to create our hardhat.config.js in the root folder and deploy.js in the scripts folder respectively, the deploy.js script uses the Ethers.js library to handle the deployment of our smart contract.

require('dotenv').config();
require("@nomiclabs/hardhat-ethers");

const { API_URL, PRIVATE_KEY } = process.env;

module.exports = {
  solidity: "0.8.17",
  defaultNetwork: "goerli",
  networks: {
    hardhat: {},
    goerli: {
       url: API_URL,
       accounts: [`0x${PRIVATE_KEY}`]
    }
 },
};



async function main() {

// Grab Contract Factory
  const MikNFT = await ethers.getContractFactory("MikNFT");

     // Start deployment, returning a promise that resolves to a contract object
  const mikNFT= await MikNFT.deploy(); // Instance of the contract 

  console.log(
    "Contract deployed to address:", mikNFT.address );
}

// We recommend this pattern to be able to use async/await everywhere
// and properly handle errors.
main()
.then(()=> process.exit(0))
.catch((error) => {
  console.error(error);
  process.exit(1);
});

Enter fullscreen mode Exit fullscreen mode

Let's deploy the smart contract on the goerli testnet

npx hardhat run scripts/deploy.js --network goerli

Enter fullscreen mode Exit fullscreen mode

At the end of the deployment, the contract address will be shown, this is what we'll use to check the details of our transaction on goerli etherscan

Contract deployed to address: 0x52Fb82C6D01F4077F18508C1ab59560c651A9099

Enter fullscreen mode Exit fullscreen mode

You have successfully deployed your NFT smart contract! The next step is to use the contract to mint an NFT

Minting NFT

So we will decide what we want to put up as an NFT, I 'dreamed' up a really cool art piece using an AI image generation tool called Wombo, you can check it out.

The primary way to store NFTs is on IPFS(Interplanetary File System) platforms which are decentralized file-sharing networks for keeping data. We'll use Pinata for our example. After creating an account on the platform, we'll upload our image and copy the hash code or content identifier that was generated from the successful upload, the address of the image will be represented like this https://gateway.pinata.cloud/ipfs/<hash-code>

Then go ahead to create a nft-metadata.json file that provides all the vital attributes for your NFT, make sure the image points to the address of the image, and when this is done make sure this is also uploaded to Pinata and the URL address noted.

{
    "attributes" : [ {
      "trait_type" : "Background",
      "value" : "forest"
    }, {
      "trait_type" : "flag",
      "value" : "Nigeria"
    } ],
    "description" : "car moving in a country background, flag seen in the skyline, locally dressed man",
    "image" : "https://gateway.pinata.cloud/ipfs/Qmcp8yj1rBBSJAHmUq3rd3oYF5Uhy2ftBLGLGG4SpPSvzP",
    "name" : "Nairaland"
}

Enter fullscreen mode Exit fullscreen mode

we then create a mint-nft.js file that will execute the minting of our NFT, we'll use the contracts' ABI for that, the ABI is a json formatted interface used to interact with the contract, it is automatically generated by hardhat when the contract is compiled, the ABI for this contract is generated in this location.

const contract = require("../artifacts/contracts/MikNFT.sol/MikNFT.json");

Enter fullscreen mode Exit fullscreen mode

the contract will use the ether library to connect with our node provider using our API key earlier defined in our .env file, it will also use the wallet's private key, the contract's address and the contract's abi to define the contract

require('dotenv').config();
const { AlchemyProvider } = require('@ethersproject/providers');
const ethers= require('ethers');

// Get Alchemy API key
const API_KEY= process.env.API_KEY;
// Define an Alchemy Provider
const provider= new ethers.providers.AlchemyProvider('goerli', API_KEY);

const privateKey=process.env.PRIVATE_KEY;
const signer= new ethers.Wallet(privateKey, provider);
// Get contract ABI and address
const abi=contract.abi;
const contractAddress='0x52fb82c6d01f4077f18508c1ab59560c651a9099';

// Create a contract instance
const myNftContract= new ethers.Contract(contractAddress, abi, signer);

Enter fullscreen mode Exit fullscreen mode

the tokenURI for our NFT image will now be used and defined in our script, this is how the final version of our mint-nft.js script will look like

const contract = require("../artifacts/contracts/MikNFT.sol/MikNFT.json");
require('dotenv').config();
const { AlchemyProvider } = require('@ethersproject/providers');
const ethers= require('ethers');

// Get Alchemy API key
const API_KEY= process.env.API_KEY;
// Define an Alchemy Provider
const provider= new ethers.providers.AlchemyProvider('goerli', API_KEY);

const privateKey=process.env.PRIVATE_KEY;
const signer= new ethers.Wallet(privateKey, provider);

// Get contract ABI and address
const abi=contract.abi;
const contractAddress='0x52fb82c6d01f4077f18508c1ab59560c651a9099';

// Create a contract instance
const myNftContract= new ethers.Contract(contractAddress, abi, signer);

const tokenUri= "https://gateway.pinata.cloud/ipfs/QmQRJK9mMtueyJN9APfQGCdsT1pHELZ9dKN1mcjaRV8qHo";

// Call mintNFT function
const mintNFT = async () => {
    let nftTxn = await myNftContract.mintNFT(signer.address, tokenUri)
    await nftTxn.wait()
    console.log(`NFT Minted! Check it out at: https://goerli.etherscan.io/tx/${nftTxn.hash}`)
}

mintNFT()
    .then(() => process.exit(0))
    .catch((error) => {
        console.error(error);
        process.exit(1);
    });

Enter fullscreen mode Exit fullscreen mode

run the below command to execute our script

node scripts/mint-nft.js

Enter fullscreen mode Exit fullscreen mode

Our output will be like this

NFT Minted! Check it out at: https://goerli.etherscan.io/tx/0x907e775d3b45507eb17af5bd97b65c58457b7354354157c7ef148e32f2f8f31c

Enter fullscreen mode Exit fullscreen mode

Awesome! what cool NFT project can you spin-off? Happy NFTing!

Top comments (0)