Mint Your NFT#

Before we dive into coding#

Introduction#

This tutorial aims at making you discover how to code in solidity in order to interact with the blockchain. You are going to learn how to code a Smart Contract, deploy a NFT and mint it in your wallet.

To write this assignment, I was greatly inspired by an article published on freecodecamp. This site is a real gold mine if you want to learn how to code or simply familirize yourself with the computer science world. Every content is free of access and of very good quality, have a look here : https://www.freecodecamp.org/.

🛠 Disclaimer This tutorial is easily accessible if you are familiar with programming tool. If it’s the first time you hear about terminal, bash, code editor or node.js, you may need to spend a little bit more time reading outside documentations to get familiar with these notions. Along this tutorial I put external links for you to get more information. It’s not wasted time for you to do so as it’s more and more useful to understand what these tools are used for in our society where computer science takes a growing part in our lives.

Open your crypto wallet#

First we need to open a wallet to store our crypto currency and our digital assets.

There are many wallet provider, but I advice you to open a MetaMak wallet as it is one of the most spread.

💡 Here is a nice Tutorial to open a MetaMask Ethereum wallet.

Design your avatar#

We are going to code a smart contract hosting a NFT. This NFT will be your “avatar” for the class. Design an avatar that you will eventually mint as a NFT. It can be whatever you want but it should be a png file.

Download a source code editor#

A source code editor is a software that enables you to open (almost) any type of code file. This will make it possible for you to open, edit and write your own programs.

If you don’t already have one I advice you to download VScode or Sublime text. If you are a beginner, you should choose VScode as it provides more hand-holding and is a great option for its debugging functionality.

Here is a tutorial on how to install VScode and Sublime Text.

Install Node.JS on your computer#

We will be using NodeJS for the project.

💡 If you don’t have it installed, follow this simple tutorial : https://phoenixnap.com/kb/install-node-js-npm-on-windows/.

Connect to an Ethereum node with Alchemy#

To interact with the Ethereum Network, you will need to be connected to an Ethereum Node.

Running your own Node and maintaining the infrastructure is a project on its own. Luckily, there are nodes-as-a-service providers which host the infrastructure for you. We will be using Alchemy as our node provider.

❓ Head over to their website, create an account, choose Ethereum as your network and create your app. You can choose Sepolia as your network. You can also use Goerli although it is in the process of being deprecated. It is recommended to use your dashboard, click “view details” on your app, then click “view key”. Save your http key somewhere as we will need that later.

Also, as you noticed, we will be using the Sepolia testnet. Sepolia is a testnet i.e. an instance of Ethereum blockchain used for testing and experimentation without risk to loose real funds or the main chain. That way you’ll learn to write smart contracts and mint NFTs without wasting money if you do a mistake using the mainnet.

❓ To get some Sepolia, go to one of the faucets (e.g. https://sepoliafaucet.com/), connect with your Alchemy account and copy paste your public key.

Deploy your Smart Contract#

Set up your repository#

We are going to use the terminal to create folders and run files throughout the tutorial. If you are not familiar with using your terminal, I suggest you read this article.

Make sure you are in the C:\Users\Name folder and run this command to create a new directory for your project:

mkdir nft-project # this will create a folder in the root file of your computer
cd nft-project # this will enter the created folder

Now, let’s make another directory, ethereum/, inside nft-project/ and initialize it with Hardhat. Hardhat is a development environment that makes it easy to deploy and test your Ethereum software.

mkdir ethereum #this will create a new folder within the nft-project one
cd ethereum #this will enter the newly created ethereum folder
npm init # this will "initialize" node.js and create a "package" file in your ethereum folder.

Answer the questions however you want. You can press enter to all of them if you want to keep default features. Then, run those commands to make a Hardhat project:

npm install --save-dev hardhat # install hardhat on your computer, be careful, don't forget the "-" between save and dev otherwise it won't work
	npx hardhat init

After waiting a moment, you will see this prompt:

888    888                      888 888               888
888    888                      888 888               888
888    888                      888 888               888
8888888888  8888b.  888d888 .d88888 88888b.   8888b.  888888
888    888     "88b 888P"  d88" 888 888 "88b     "88b 888
888    888 .d888888 888    888  888 888  888 .d888888 888
888    888 888  888 888    Y88b 888 888  888 888  888 Y88b.
888    888 "Y888888 888     "Y88888 888  888 "Y888888  "Y888

Welcome to Hardhat v2.0.8

? What do you want to do? …
  Create a sample project
❯ Create an empty hardhat.config.js
  Quit

Select create an empty hardhat.config.js and enter. This will generate an empty hardhat.config.js file in your ethereum/ folder that we will later update.

Define your environment#

Remember the Alchemy key we grabbed from our test project earlier? We will use that along with our Metamask account’s public and private keys to interact with the blockchain.

Run the following commands to make a file called .env inside your ethereum/ directory, and install dotenv. We will use them later.

npm install touch-cli -g #use npm to install the touch package
touch .env #create the .env file
npm install dotenv --save #add a package

Open your .env file with your code editor and put the following keys:

  • Alchemycode . key you have exported in the beginning

  • Private key (follow those instructions to grab your Metamask’s private key)

  • Public key (i.e. wallet address)

🚨 Be extremely careful when handling your private key. Never share it, never copy paste it in a document accessible to any other person than you.

Open the .env file with the code editor of your choice (I personnaly use VS Code, but Sublime text or any other of your choice will fit) and add your keys.

Your .env file should look like this:

API_URL = "YOUR_ALCHEMY_KEY"
PRIVATE_KEY = "YOUR_METAMASK_PRIVATE_KEY"
PUBLIC_KEY = "YOUR_METAMASK_ADDRESS"

For the API_URL, be careful to copy paste the whole URL and not only your key.

Code the file#

Go to the ethereum/ folder and create two more directories: contracts and scripts. A simple hardhat project contains those folders.

  • contracts/ contains the source files of your contracts

  • scripts/ contains the scripts to deploy and mint our NFTs

mkdir contracts
mkdir scripts
  • contracts/ is where we’ll keep our NFT smart contract code

  • scripts/ is where we’ll keep scripts to deploy and interact with our smart contract

Then, install OpenZeppelin. OpenZeppelin Contract is an open-sourced library with pre-tested reusable code to make smart contract development easier.

npm install @openzeppelin/contracts

Finally, we will be writing the Smart Contract for our NFT. Navigate to your contracts directory and create a file titled avatar.sol. You can name your NFTs however you see fit.

The .sol extension refers to the Solidity language, which is what we will use to program our Smart Contract. We will only be writing 14 lines of code with Solidity, so no worries if you haven’t seen it before.

Start with this article to learn more about Smart Contract languages. You can also directly jump to this Solidity cheat sheet which contains the main syntax.

cd contracts
touch avatar.sol //create a solidity file
code avatar.sol //opens your file with your default code editor

Open the avatar.sol file with your code editor and copy paste the following code (this is our Smart Contract):

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

import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; 

contract avatar is ERC721 {
    uint256 private _tokenIdCounter;

    constructor() ERC721("avatarname", "NAME") {} //please here replace name and NAME by your real name

    function _baseURI() internal pure override returns (string memory) {
        return "YOUR_API_URL/api/erc721/"; //here you will replace it later by an URL
    }

    function mint(address to) public {
        uint256 tokenId = _tokenIdCounter;
        _safeMint(to, tokenId);
        _tokenIdCounter += 1;
    }
}

Let’s go through the code and understand what is going on:

  • At the top of the file, we specified which OpenZeppelin module to import. We need the ERC721 contract as it is the ‘base’ of our Smart Contract. It has already implemented all the methods specified in EIP-721 so we can safely use it. See here for documentation on the different types of smart contracts (token standards) : https://ethereum.org/en/developers/docs/standards/tokens/

  • A Counter is useful to generate incremental ids for our NFTs. Using the Counters library, we define unique IDs for every NFT minted using our smart contract. We named the variable _tokenIdCounter

  • In the constructor, we initialized our ERC721 with its name and its symbol. I chose avatar and NAME.

  • We override the default _baseURI function by returning our own. We will get to build that in a second.

  • In summary, it is the URL that will be added as ‘prefix’ to all our tokenURIs. In the above example, the metadata of our NFTs will live in a JSON file at OUR_API_URL/[api/erc721/](https://e110-99-121-58-31.ngrok.io/api/erc721/)1.

  • We implement the ‘mint’ function. It is the function that lets you publish an instance of this Smart Contract on the blockchain. I required the _tokenIdCounter variable to be less than 1 as I will only create one instance of my NFT. You can change that if you want to mint more.

  • Finally, inside the mint function, we increment the _tokenIdCounter **variable by 1, so in the case you want to mint many NFTs, our id will be 1, followed by 2, followed by 3 etc until the number your put in line 18.

  • Then, we call the function provided by OpenZeppelin _safeMint to publish the token.

Web app & metadata#

For the web app, we will use Next.js to initialize a fully-functional web app.

Go back to the root directory nft-project/ and initialize a boilerplate Next.js app called web:

cd .. #command to go back to the previous repository (folder)
mkdir web #create a new repository "web"
cd web #go into that newly created repository
npx create-next-app@latest #create a new app using the default Next.js template

You will be asked to name your project. Feel free to name it however your want. In this tutorial, we will name our project “avatar”.

Troubleshooting: If the command “npx create-next-app@latest” fail to create a new folder, create it manually. Also reject creating /src and App router folders when generating the next app.

Code the metadata#

Metadata is a central pillar of blockchain. It is used to provide additional information or data about an asset that may be useful when trying to complete a transaction with the asset itself. Indeed, our file (our png avatar) can’t be stored directly on chain otherwhise it would be insanely costly to run the network as there would be much more data for computers to process. So we need to host it off-chain.

Each NFT will refer to a file stored on the internet and retrieve the file each time it is asked to. ff-line. NFTs usually point to an IPFS (InterPlanetary File System) hash or an HTTP URL somewhere on the Internet. For more information about metadata, read this post.

In our case, we will be building a simple API endpoint which resolve in our NFT’s information as a JSON file.

Our Next.js project gives us a handy way to develop API routes.

Go to the web/ folder, find the api/ folder within the pages/ folder, and make our dynamic [id].js route in a erc721/ folder.

You can do it by hand or type the following code in your temrinal

cd web
cd avatar
cd pages
cd api
mkdir erc721 //create a new folder called erc721, this is usefull in case you have many different types of contracts
cd erc721
touch [id].js
code [id].js //this command wil open the file with your default code editor

Then open the file with your code editor and code your metadata:

const metadata = {//we add a constant in case we wanted to do a series/collection of many NFTs. This enables to have only 1 JSON file for the metadata of all your NFTs. 
  0: {
    description: "Name's avatar for the Blockchain class", //replace Name by your name
    image: "https://i.ibb.co/DC4BPR3/fmex6-avgaei3ue.jpg", // replace with the png or jpg of your avatar !
    name: "Name's avatar",//replace Name by your name
  }
};

export default function handler(req, res) {
  res.status(200).json(metadata[req.query.id] || {});
}

💡 We are naming the file [id].js and not 0.js for instance because we want to give the possibility to create many js files (1 for each NFT we want to mint) in case we wante to create a whole collection of NFT.

As we don’t have a server to store our image, we will use a free online host service. I used imgbb but feel free to use anyone you want. However, never upload personal or sensitive image on such servers.

🚨 To ensure your picture appears on Opensea, it’s crucial to complete the tutorial before the ngrok link expires, typically within an hour.

🚨 For the sake of this project, I made the code as easily understandable as possible. This is definitely not suited for production, you should add details, maybe properties to your NFT to make it more scarce, give it some properties.

Now, go to /web directory then /avatar, and start your Next.js app (be careful to run it in /avatar and not in /web otherwise it won’t work):

cd .. //go back to the avatar directory
npm run dev

It may take some time to run.

Your app should be running on localhost:3000. To make sure our endpoint works, go to http://localhost:3000/api/erc721/0 and it should resolve with a JSON object of your first NFT’s metadata.

To stop npm program from running in your terminal, do ctrl + C and enter Y (for Yes).

Publish your metadata#

Since your app is hosted locally, other apps cannot access it. Using a tool like ngrok, we can expose our local host to a publicly accessible URL.

Untitled

  1. Go to ngrok.com and complete the registration process

  2. Unzip the downloaded package and double click on ngork

  3. A terminal should appear, make sure you cd into the folder where you unzipped your ngrok package (this is very important)

  4. Follow the instruction on your dashboard and run

ngrok authtoken YOUR_AUTH_TOKEN //get your token on ngrok dashboard and copy past it here
  1. Then, run this command to create a tunnel to your web app hosted on localhost:3000

ngrok http 3000
  1. On your terminal, you should see something like this:

ngrok by @inconshreveable                                                                            (Ctrl+C to quit)

Session Status                online
Account                       YOUR_ACCOUNT (Plan: Free)
Version                       2.3.40
Region                        United States (us)
Web Interface                 http://127.0.0.1:4040
Forwarding                    http://YOUR_NGROK_ADDRESS -> http://localhost:3000
Forwarding                    https://YOUR_NGROK_ADDRESS -> http://localhost:3000

Go to https://YOUR_NGROK_ADDRESS/api/erc721/1 to make sure your endpoint works correctly. Note that in the instruction will work solely if you keep running “npm run dev”

You should see that (same as when you configure your terminal to work with ngrok by adding the ngrok executable to your PATH/api/erc721/1)

Untitled

Deploy the Smart Contract#

Now that we have done all the ground work, let’s go back to our ethereum/ folder and get ready to deploy our NFT (you can close and reopen your terminal to go faster).

Change the _baseURI function in your ethreum/contracts/avatar.sol file **to return your ngrok address.

// ethereum/conrtacts/avatar.sol

contract avatar is ERC721 {
...
	function _baseURI() internal pure override returns (string memory) {
		return "https://YOUR_NGROK_ADDRESS/api/erc721/";
	}
...
}

To deploy our NFT, we will first need to compile it using Hardhat. To make the process easier, we will install ethers.js.

npm install @nomiclabs/hardhat-ethers --save-dev

Now let’s update our hardhat.config.js in our ethereum/ folder:

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

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

Be careful to have the same solidity version as the one of your avatar.sol file (it might be more recent than “0.8.17”). Note: Remove $ and {} when entering your private key.

To learn more about the hardhat configuration file, take a look at their documentation. We have configured the Sepolia network with our Alchemy URL and provided it with the private key of your metamask account.

Finally, go back to the ethereum/ folder and run:

npx hardhat compile

This lets hardhat generate two files per compiled contract. We should see a newly created artifacts/ folder that contains your compiled contracts in the contracts/ folder. To learn more about how that works, read this tutorial by the Hardhat team.

Now, let’s write a script to finally deploy our NFT to the test network. In your scripts/ folder, create a file called deploy.js.

async function main() {
    const Avatar = await ethers.getContractFactory("avatar")
    const avatar = await Avatar.deploy()
    await avatar.deployed()
    console.log("Contract deployed to address:", avatar.address)
}

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

This code is inspired by the hardhat deployment tutorial.

A ContractFactory in ethers.js is an abstraction used to deploy new smart contracts, so avatar here is a factory for instances of our token contract. Calling deploy() on a ContractFactory will start the deployment, and return a Promise that resolves to a Contract . This is the object that has a method for each of your smart contract functions.

In your terminal, go to the /ethereum folder and run the deployment script:

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

You should see in your terminal avatar deployed: SOME_ADDRESS. This is the address where your Smart Contract is deployed on the Sepolia test network.

Keep this adress closely as we will need it for the mint.

View the Smart Contract on the blockchain#

If you head over to https://sepolia.etherscan.io/address/SOME_ADDRESS, you should see your freshly deployed Smart Contract.

You can also access it by copy pasting your MetaMask Wallet address.

Mint your NFT#

Code the mint.js file#

Now that you have deployed your NFT, it’s time to mint it for yourself! Create a new file called mint.js in your /scripts folder. We will be using ethers.js to help us.

cd scripts //go to the scripts folder
touch mint.js //create a mint.js file
npm install --save ethers //add the ether.js package
code mint.js //open the file with your code editor

Then, in the mint.js file, code the following:

require("dotenv").config();
const { ethers } = require("ethers");

const contract = require("../artifacts/contracts/avatar.sol/avatar.json");
const contractInterface = contract.abi;

// https://docs.ethers.io/v5/api/providers
const provider = ethers.getDefaultProvider("sepolia", {
  alchemy: process.env.API_URL,
});

// https://docs.ethers.io/v5/api/signer/#Wallet
const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider);

//https://docs.ethers.io/v5/api/contract/contract
const Avatar = new ethers.Contract(
	  "YOUR_NFT_ADDRESS", // replace by the NFT adresse given by the last step (adress of the smart contract)
    contractInterface,
    wallet
);

const main = () => {
  Avatar
    .mint(process.env.PUBLIC_KEY)
    .then((transaction) => console.log(transaction))
    .catch((e) => console.log("something went wrong", e));
};

main();

Some comments to where you can find more information about the different methods:

  • We first grab the contract’s interface (ABI). From ethereum.org: An application binary interface, or ABI, is the standard way to interact with contracts. Your ABI defines how others interact with your contract. Then, we created our provider with Alchemy (remember about node-as-a-service). Finally, we initialize our wallet with our private key.

  • The main() function calls the mint method in the Smart Contract we had just deployed. The mint method takes only one parameter, to, which indicate the receiver of the token. Since we are minting for ourself, we put the public address of our Metamask account.

Now run in your ethereum folder:

node scripts/mint.js

Troubleshooting: If you run into an error message, check the following thread. Note that the issue should not prevent you from minting your NFT.

If everything goes well, after a couple of seconds, you should see a response like this in your terminal:

The hash of your transaction is: xxxxxxxxxxxxxxxxx // a long hash
Check Alchemy's Mempool to view the status of your transaction!

Grab the hash property and go to https://sepolia.etherscan.io/tx/YOUR_HASH. You should see the minting transaction there!

View the NFT in your wallet#

First dowload the mobile version of Metamask.

Then, log into your account. You should see an NFTs tab along with an add NFT button.

Click on the button and enter the address of your Smart Contract along with the ids that you have minted. In our case, we only minter 1 NFT so id should be 1.


Further content to get more familiar with solidity#

If you want to go further into learning Solidity, there is a very nice tutorial named cryptozombies. This will drive you step by step to Code Blockchain DApps by Building Simple Games.