Let’s build a Fullstack Minting dapp using blockchain

Let’s build a Fullstack Minting dapp using blockchain

Fullstack minting decentralized application using blockchain

Introduction

Hey there 👋,

So in this tutorial of hashnode writeathon, we're gonna build a Fullstack minting dapp (decentralized app) using blockchain.

Introducing EmojiMint

EmojiMint is a full-stack minting decentralized application that is built on blockchain technologies, it is built with the purpose of providing an entry point for future NFT minting products. EmojiMint lets you mint NFTs that are available on it for free!

Features of EmojiMint

Well, there are a few things that EmojiMint can do:

  1. Modern User Interface (built with thinking of easy to use interface).
  2. Mint a unique NFTs that you'd like.
  3. Mint 5 per NFTs in a single click.
  4. Super simple Metamask wallet connection
  5. Last but not least - over 7,777 ERC-721 NFTs with different Emoji faces.

Tech Stack used in EmojiMint

Alright, so here are some tech stacks that I've used in making EmojiMint

  1. NextJS
  2. Tailwind CSS

Talking about server-side:

  1. Solidity
  2. Hardhat
  3. Alchemy
  4. Openzepplin

Demo 💻

Let's see a sneak peek of what EmojiMint looks like:

Alright, so here's what we're gonna build in this tutorial. We'll be going through some steps in this build. So, without wasting any further time let's start building it!

Setup

So, as we're going to use NextJS you've to create a next app:

npx create-next-app EmojiMint

Next, we've to install ether.js and hardhat library into our project directory:

npm install ethers hardhat @nomiclabs/hardhat-waffle ethereum-waffle chai @nomiclabs/hardhat-ethers

Alright, once our installation is done of required libraries we've to configure the installation

Initialize a new Ethereum Development Environment with Hardhat:

npx hardhat

? What do you want to do? Create a sample project
? Hardhat project root: <Choose default path>

Now you should see the following artifacts created for you in your root directory:

  • hardhat.config.js
  • Scripts
  • test
  • Contracts

As we're done with setting up the project folder and installing the dependencies that we need in this project. Now, it's time for writing our smart contracts code with our react/next app.

Starting with the Smart Contracts

Alright, so now let's get started with writing Smart Contracts for our EmojiMint dapp. As you can see there's a Contracts folder associated in your project directory in which there's a greeter.sol file is there.

We've to rename it to EmojiFaces.sol and remove all pre-written code from it. Once done, you've to import the following packages:

    import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
    import "@openzeppelin/contracts/access/Ownable.sol";
    import "@openzeppelin/contracts/utils/math/SafeMath.sol";
    import"@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";

Alright, Cool next we've to start with defining The ERC721 Token and writing EmojiFaces.sol

We need to follow a strict folder structure. It's super important because we're building on top of Hardhat, and the default paths for our /contracts, /scripts and /test are pre-defined. Not following this structure will lead to our Hardhat tasks failing. Be careful!

    pragma solidity ^0.8.4;
    pragma abicoder v2;

    contract EmojiFaces is ERC721, Ownable, ERC721Enumerable {
      using SafeMath for uint256;
      using Strings for uint256;

      uint256 public constant tokenPrice = 1900000000000000; // 0.0019 ETH 
      uint256 public constant maxTokenPurchase = 3;
      uint256 public constant MAX_TOKENS = 10000;

      string public baseURI = ""; // IPFS URI WILL BE SET AFTER ALL TOKENS SOLD OUT

      bool public saleIsActive = false;
      bool public presaleIsActive = false;
      bool public isRevealed = false;
      mapping(address => bool) private _presaleList;
      mapping(address => uint256) private _presaleListClaimed
      uint256 public presaleMaxMint = 2;
      uint256 public devReserve = 64;
      event EmojiMinted(uint256 tokenId, address owner);
      constructor() ERC721("EmojiFacesNew", "EFS") {}
      function _baseURI() internal view virtual override returns (string memory) {
        return baseURI;
      }
      function setBaseURI(string memory _newBaseURI) public onlyOwner {
        baseURI = _newBaseURI;
      }
      function withdraw() public payable onlyOwner {
        (bool os, ) = payable(owner()).call{ value: address(this).balance }("");
        require(os);
      }
      function reveal() public onlyOwner {
        isRevealed = true;
      }
      function reserveTokens(address _to, uint256 _reserveAmount)
        external
        onlyOwner
      {
        require(
          _reserveAmount > 0 && _reserveAmount <= devReserve,
          "Not enough reserve left for team"
        );
        for (uint256 i = 0; i < _reserveAmount; i++) {
          uint256 id = totalSupply();
          _safeMint(_to, id);
        }
        devReserve = devReserve.sub(_reserveAmount);
      }
      function toggleSaleState() external onlyOwner {
        saleIsActive = !saleIsActive;
      }
      function togglePresaleState() external onlyOwner {
        presaleIsActive = !presaleIsActive;
      }
      function tokensOfOwner(address _owner)
        external
        view
        returns (uint256[] memory)
      {
        uint256 tokenCount = balanceOf(_owner);
        if (tokenCount == 0) {
          // Return an empty array
          return new uint256[](0);
        } else {
          uint256[] memory result = new uint256[](tokenCount);
          uint256 index;
          for (index = 0; index < tokenCount; index++) {
            result[index] = tokenOfOwnerByIndex(_owner, index);
          }
          return result;
        }
      }

Alright, So in the above written smart contracts we've used bool and mappingfunctions to check if the sale of the EmjojiFaces is still active and to check if our NFTs are presale. There are some functions like bool and mapping to construct the properties for the base URI. Next, we'll be going to see mintEmoji and check if the sale is still active:

function mintEmoji(uint256 numberOfTokens) external payable {
        require(saleIsActive, "Sale must be active to mint Token");
        require(
          numberOfTokens > 0 && numberOfTokens <= maxTokenPurchase,
          "Can only mint one or more tokens at a time"
        );
        require(
          totalSupply().add(numberOfTokens) <= MAX_TOKENS,
          "Purchase would exceed max supply of tokens"
        );
        require(
          msg.value >= tokenPrice.mul(numberOfTokens),
          "Ether value sent is not correct"
        );

        for (uint256 i = 0; i < numberOfTokens; i++) {
          uint256 id = totalSupply().add(1);
          if (totalSupply() < MAX_TOKENS) {
            _safeMint(msg.sender, id);
            emit EmojiMinted(id, msg.sender);
          }
        }
      }

As in the above code, you can see that we can check if the sale of NFTs are still active and now in the next contract we're going to define if the Pre-sale is active and add the presale to the list and remove it from the list:

function presaleEmoji(uint256 numberOfTokens) external payable {
        require(presaleIsActive, "Presale is not active");
        require(_presaleList[msg.sender], "You are not on the Presale List");
        require(
          totalSupply().add(numberOfTokens) <= MAX_TOKENS,
          "Purchase would exceed max supply of token"
        );
        require(
          numberOfTokens > 0 && numberOfTokens <= presaleMaxMint,
          "Cannot purchase this many tokens"
        );
        require(
          _presaleListClaimed[msg.sender].add(numberOfTokens) <= presaleMaxMint,
          "Purchase exceeds max allowed"
        );
        require(
          msg.value >= tokenPrice.mul(numberOfTokens),
          "Ether value sent is not correct"
        );

        for (uint256 i = 0; i < numberOfTokens; i++) {
          uint256 id = totalSupply().add(1);
          if (totalSupply() < MAX_TOKENS) {
            _presaleListClaimed[msg.sender] += 1;
            _safeMint(msg.sender, id);
            emit EmojiMinted(id, msg.sender);
          }
        }
      }
      function addToPresaleList(address[] calldata addresses) external onlyOwner {
        for (uint256 i = 0; i < addresses.length; i++) {
          require(addresses[i] != address(0), "Can't add the null address");

          _presaleList[addresses[i]] = true;
        }
      }

      function removeFromPresaleList(address[] calldata addresses)
        external
        onlyOwner
      {
        for (uint256 i = 0; i < addresses.length; i++) {
          require(addresses[i] != address(0), "Can't add the null address");
          _presaleList[addresses[i]] = false;
        }
      }
      function setPresaleMaxMint(uint256 maxMint) external onlyOwner {
        presaleMaxMint = maxMint;
      }
      function onPreSaleList(address addr) external view returns (bool) {
        return _presaleList[addr];
      }

Next, Let's Finish the Contract Logic:

function tokenURI(uint256 tokenId)
        public
        view
        virtual
        override
        returns (string memory)
      {
        require(
          _exists(tokenId),
          "ERC721Metadata: URI query for nonexistent token"
        );

        string memory currentBaseURI = _baseURI();

        if (isRevealed == false) {
          return
            "ipfs://QmYGAp3Gz1m5UmFhV4PVRRPYE3HL1AmCwEKFPxng498vfb/hidden.json";
        }

        return
          bytes(currentBaseURI).length > 0
            ? string(abi.encodePacked(currentBaseURI, tokenId.toString(), ".json"))
            : "";

      }

      function _beforeTokenTransfer(
        address from,
        address to,
        uint256 tokenId
      ) internal override(ERC721, ERC721Enumerable) {
        super._beforeTokenTransfer(from, to, tokenId);
      }

      function supportsInterface(bytes4 interfaceId)
        public
        view
        override(ERC721, ERC721Enumerable)
        returns (bool)
      {
        return super.supportsInterface(interfaceId);
      }
    }

Boom! So, that's how we're done with the EmojiFaces.sol file. Pretty easy and simple right. There's nothing to do in it we've just defined how the sale is going to be active and the same flow goes with the pre-sale. It is just plain JavaScript with some functions in it like bool, mapping, constructor, etc.

Frontend

Alright Next, we've to start with the front end of our dapp. So, first thing first we've already created a NextJS app and installed some packages that we'd need in the front end. Next, we've to create a .env file for storing the API keys, etc.

So, we've to store some of the secret KEYS are:

  • API_URL: [your API URL here]
  • PRIVATE_KEY: [your private API key here]
  • Etherscan API_Key: [your etherscan API key here]

Cool, as we've stored our Secret API keys that we'd need to use. Next, let's start with coding our Frontend App.

So far as we've Components Folder in our NextJS app. First of all, we've to create some of the files in it looks like this: image.png

Okay Cool, Next let's start with the Header.js file. Let's design a good looking header for the dapp. Import all the needs:

import Head from "next/head";
import Link from "next/link";
import { useState, useEffect } from "react";
import { useStatus } from "../context/statusContext";
import { connectWallet, getCurrentWalletConnected } from "../utils/interact";

Next, Let's code metamask wallet authentication:

const Header = () => {
  const { setStatus } = useStatus();
  const [walletAddress, setWalletAddress] = useState("");

  const connectWalletPressed = async () => {
    const walletResponse = await connectWallet();
    setWalletAddress(walletResponse.address);
    setStatus(walletResponse.status);
  };

  useEffect(() => {
    const prepare = async () => {
      const walletResponse = await getCurrentWalletConnected();
      setWalletAddress(walletResponse.address);
      setStatus(walletResponse.status);

      addWalletListener();
    };
    prepare();
  }, []);

  const addWalletListener = () => {
    if (window.ethereum) {
      window.ethereum.on("accountsChanged", async (accounts) => {
        if (accounts.length > 0) {
          setWalletAddress(accounts[0]);
          setStatus("");
        } else {
          setWalletAddress("");
          setStatus("🦊 Connect to Metamask using Connect Wallet button.");
        }
      });
    }
  };

Let's define the logo and our Navigation:

return (
    <>
      <Head>
        <title>EmojiMint</title>
        <meta name="description" content="Nft Minting Tutorial" />
        <link rel="icon" href="/favicon.ico" />
      </Head>

      <header className="sticky inset-x-0 top-0 z-10 h-20 min-w-full text-white border-b border-purple-900 bg-primary backdrop-filter backdrop-blur-lg bg-opacity-30">
        <div className="flex items-center container mx-auto max-w-7xl justify-between h-full">
          {/* Logo */}
          <Link href="#">
            <a className="text-2xl font-bold">
              <span className="pr-2 text-transparent bg-clip-text bg-gradient-to-br from-pink-500 to-purple-500">
                Emoji
              </span>
              Mint
            </a>
          </Link>

//Navigation:

{/* Navigation */}

          <nav aria-label="Main Menu">
            <ul className="flex items-center space-x-8">
              <li className="text-gray-200 text-semibold">
                <Link href="#about">
                  <a>About</a>
                </Link>
              </li>

              <li className="text-gray-200 text-semibold">
                <Link href="#gallery">
                  <a>The Gallery</a>
                </Link>
              </li>

              <li className="text-gray-200 text-semibold">
                <Link href="#faq">
                  <a>FAQ</a>
                </Link>
              </li>

              <li className="hover:text-purple-500 hover:border-purple-500 cursor-pointer px-4 py-2 font-extrabold text-purple-300 border border-purple-300 rounded-md">
                <a
                  className=""
                  id="walletButton"
                  onClick={connectWalletPressed}
                >
                  {walletAddress.length > 0 ? (
                    "Connected: " +
                    String(walletAddress).substring(0, 6) +
                    "..." +
                    String(walletAddress).substring(38)
                  ) : (
                    <span>Connect Wallet</span>
                  )}
                </a>
              </li>
            </ul>
          </nav>

//Social Links:

{/* Opensea Twitter Discord Links */}
          <nav aria-label="Contact Menu">
            <ul className="flex items-center space-x-6">
              <li>
                <a href="https://opensea.io" target="_blank" rel="noreferrer">
                  <svg
                    className="w-7 h-7"
                    viewBox="0 0 90 90"
                    fill="none"
                    xmlns="http://www.w3.org/2000/svg"
                  >
                    <path
                      d="{svg path}"
                      fill="#fff"
                    ></path>
                  </svg>
                </a>
              </li>

              <li>
                <a
                  href="https://twitter.com/Darshanshub"
                  target="_blank"
                  rel="noreferrer"
                >
                  <svg
                    className="w-7 h-7"
                    stroke="currentColor"
                    fill="currentColor"
                    strokeWidth="0"
                    viewBox="0 0 512 512"
                    xmlns="http://www.w3.org/2000/svg"
                  >
                    <path d="{svg path}"></path>
                  </svg>
                </a>
              </li>

              <li>
                <a
                  href="https://discord.gg/DKH23etbAZ"
                  target="_blank"
                  rel="noreferrer"
                >
                  <svg
                    className="w-7 h-7"
                    stroke="currentColor"
                    fill="currentColor"
                    strokeWidth="0"
                    viewBox="0 0 448 512"
                    xmlns="http://www.w3.org/2000/svg"
                  >
                    <path d="{svg path}"></path>
                  </svg>
                </a>
              </li>
            </ul>
          </nav>
        </div>
      </header>
    </>
  );
};

export default Header;

Alright, we're now done with the Header.js. Now let's code our homepage design in Hero.js

import React, { useState, useEffect } from "react";
import Image from "next/image";
import { useStatus } from "../context/statusContext";

import {
  getMaxMintAmount,
  getTotalSupply,
  getNftPrice,
  mintNFT,
  getSaleState,
} from "../utils/interact";

Let's define hooks and code for Total supply of NFTs:

const Hero = () => {
  const { status, setStatus } = useStatus();

  const [count, setCount] = useState(1);
  const [maxMintAmount, setMaxMintAmount] = useState(0);
  const [totalSupply, setTotalSupply] = useState(0);
  const [nftPrice, setNftPrice] = useState("0.01");
  const [isSaleActive, setIsSaleActive] = useState(false);

  useEffect(() => {
    const prepare = async () => {
      setMaxMintAmount(await getMaxMintAmount());
      setNftPrice(await getNftPrice());
      setIsSaleActive(await getSaleState());
      await updateTotalSupply();
    };

    prepare();
  });

  const updateTotalSupply = async () => {
    const mintedCount = await getTotalSupply();
    setTotalSupply(mintedCount);
  };

  const incrementCount = () => {
    if (count < maxMintAmount) {
      setCount(count + 1);
    }
  };

  const decrementCount = () => {
    if (count > 1) {
      setCount(count - 1);
    }
  };

  const mintEmojiFace = async () => {
    const { status } = await mintNFT(count);
    setStatus(status);

    // We minted a new emoji face, so we need to update the total supply
    updateTotalSupply();
  };

Next, let's code the hero page design:

return (
    <main id="main" className="h-screen py-16 bg-pattern">
      <div className="container max-w-6xl mx-auto flex flex-col items-center pt-4">
        <div className="flex flex-col items-center">
          <Image
            src="/images/preview.gif"
            width="270"
            height="270"
            alt="emoji faces gif"
            className="rounded-md"
          />

          {isSaleActive ? (
            <>
              {/* Minted NFT Ratio */}
              <p className="bg-gray-100 rounded-md text-gray-800 font-extrabold text-lg my-4 py-1 px-3">
                <span className="text-purple-600">{`${totalSupply}`}</span> /
                10K
              </p>

              <div className="flex items-center mt-6 text-3xl font-bold text-gray-200">
                <button
                  className="flex items-center justify-center w-12 h-12 bg-white rounded-md text-black hover:bg-pink-200 text-center"
                  onClick={incrementCount}
                >
                  <svg
                    xmlns="http://www.w3.org/2000/svg"
                    className="w-6 h-6 text-pink-400"
                    fill="none"
                    viewBox="0 0 24 24"
                    stroke="currentColor"
                  >
                    <path
                      strokeLinecap="round"
                      strokeLinejoin="round"
                      strokeWidth="2"
                      d="M12 4v16m8-8H4"
                    />
                  </svg>
                </button>

                <h2 className="mx-8">{count}</h2>

                <button
                  className="flex items-center justify-center w-12 h-12 bg-white rounded-md hover:bg-pink-200 text-center"
                  onClick={decrementCount}
                >
                  <svg
                    xmlns="http://www.w3.org/2000/svg"
                    className="w-6 h-6 text-pink-400"
                    fill="none"
                    viewBox="0 0 24 24"
                    stroke="currentColor"
                  >
                    <path
                      strokeLinecap="round"
                      strokeLinejoin="round"
                      strokeWidth="2"
                      d="M20 12H4"
                    />
                  </svg>
                </button>
              </div>

              <h4 className="mt-2 font-semibold text-center text-white">
                {nftPrice} ETH{" "}
                <span className="text-sm text-gray-300"> + GAS</span>
              </h4>

              {/* Mint Button */}
              <button
                className="mt-6 py-2 px-4 text-center text-white uppercase bg-pink-500 border-b-4 border-pink-700 rounded hover:bg-pink-400 hover:border-pink-500"
                onClick={mintEmojiFace}
              >
                Mint now!
              </button>
            </>
          ) : (
            <p className="text-white text-2xl mt-8">
              {" "}
              😥 Sale is not active yet!
            </p>
          )}

          {/* Status */}

          {status && (
            <div className="flex items-center justify-center px-4 py-4 mt-8 font-semibold text-white bg-red-400 rounded-md ">
              {status}
            </div>
          )}
        </div>
      </div>
    </main>
  );
};

export default Hero;

Awesome! So we've two pages designed right now Header.js and Hero.js , Next we've to code About.js, So let's get started:

import Link from "next/link";

const About = () => {
  return (
    <div id="about" className="py-10 mt-16 mb-60 ">
      <h1 className="mb-20 font-mono text-6xl font-semibold text-center text-gray-100 uppercase">
        About The Project
      </h1>
      <div className="container relative max-w-6xl py-3 pt-16 mx-auto mt-20 sm:max-w-xl sm:mx-auto">
        <div className="absolute inset-0 transform shadow-lg gradient-background -skew-y-6sm:skew-y-0 sm:-rotate-6 sm:rounded-3xl"></div>
        <div className="relative px-4 py-10 bg-white shadow-lg sm:rounded-3xl sm:p-20">
          <div className="max-w-md mx-auto">
            <div>
              <h1 className="font-mono text-3xl font-bold text-gray-900 underlined">
                THE EMOJI FACES
              </h1>
            </div>
            <div className="divide-y divide-gray-200">
              <div className="py-8 space-y-4 text-base leading-6 text-gray-700 sm:text-lg sm:leading-7">
                <ul className="space-y-2 list-disc">
                  <li className="flex items-start">
                    <span className="flex items-center h-6 sm:h-7">
                      <svg
                        className="flex-shrink-0 w-5 h-5 text-cyan-500"
                        viewBox="0 0 20 20"
                        fill="currentColor"
                      >
                        <path
                          fillRule="evenodd"
                          d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z"
                          clipRule="evenodd"
                        />
                      </svg>
                    </span>
                    <p className="ml-2">
                      <code className="font-semibold text-gray-900">7,777</code>{" "}
                      ERC-721 NFTs.
                    </p>
                  </li>
                  <li className="flex items-start">
                    <span className="flex items-center h-6 sm:h-7">
                      <svg
                        className="flex-shrink-0 w-5 h-5 text-cyan-500"
                        viewBox="0 0 20 20"
                        fill="currentColor"
                      >
                        <path
                          fillRule="evenodd"
                          d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z"
                          clipRule="evenodd"
                        />
                      </svg>
                    </span>
                    <p className="ml-2">
                      high-res scanned. Irresistible.
                    </p>
                  </li>
                  <li className="flex items-start">
                    <span className="flex items-center h-6 sm:h-7">
                      <svg
                        className="flex-shrink-0 w-5 h-5 text-cyan-500"
                        viewBox="0 0 20 20"
                        fill="currentColor"
                      >
                        <path
                          fillRule="evenodd"
                          d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z"
                          clipRule="evenodd"
                        />
                      </svg>
                    </span>
                    <p className="ml-2">
                      Over 170 traits, several rarity levels.
                    </p>
                  </li>
                  <li className="flex items-start">
                    <span className="flex items-center h-6 sm:h-7">
                      <svg
                        className="flex-shrink-0 w-5 h-5 text-cyan-500"
                        viewBox="0 0 20 20"
                        fill="currentColor"
                      >
                        <path
                          fillRule="evenodd"
                          d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z"
                          clipRule="evenodd"
                        />
                      </svg>
                    </span>
                    <p className="ml-2">0.01 ETH per FACES.</p>
                  </li>
                </ul>
              </div>
              <div className="pt-6 text-base leading-6 font-extralight sm:text-lg sm:leading-7">
                <p>
                  {`Emoji Faces are some cool ERC721 NFTs, they are high-resistible and 
                   unique pre-made Emoji Faces NFTs.`}
                </p>
                <p className="mt-8">
                  <Link href="#main">
                    <a className="text-cyan-600 hover:text-cyan-700">
                      {" "}
                      Mint one
                    </a>
                  </Link>
                </p>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
};

export default About;

Alright, Next if you want to code some other extra pages like FAQ.js, etc. I'm not gonna code it because it's an extra page just for an example if you are able to do it then you can o with it, Pssst! Already our article's too long.

Well, as we've our Smart Contracts build, we do have our Frontend build. But as we all know it is not designed yet so let's get started designing it with CSS.

In your Styles folder create a file named globals.css. In this file, we're gonna code the styling of EmojiMint. Let's get Started🔥🚀

@import url("https://fonts.googleapis.com/css2?family=Roboto&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Comfortaa:wght@600;700&display=swap");

@tailwind base;
@tailwind components;
@tailwind utilities;

html {
  scroll-behavior: smooth;
}

.bg-pattern {
  background-color: #7d08ff;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='{xmlns path}");
  background-attachment: fixed;
  background-size: cover;
}

::-moz-selection {
  /* Code for Firefox */
  color: #f4f4f4;
  background: #6e0cca;
}

::selection {
  color: #f4f4f4;
  background: #6e0cca;
}

.gradient-background {
  background: linear-gradient(213deg, #b312dd, #ff4e58, #9222d4, #33c2d0);
  background-size: 240% 240%;
  animation: gradient-animation 12s ease infinite;
}

.underlined {
  position: relative;
}

.underlined::after {
  content: "";
  position: absolute;
  bottom: -1.525rem;
  left: -0.5rem;
  right: -0.5rem;
  height: 40px;
  z-index: 0;

  background-image: url("https://s3-us-west-2.amazonaws.com/s.cdpn.io/664131/underline.svg");
  background-repeat: no-repeat;
}

@keyframes gradient-animation {
  0% {
    background-position: 0% 50%;
  }
  50% {
    background-position: 100% 50%;
  }
  100% {
    background-position: 0% 50%;
  }
}

Awesome! We've our styling Ready Now. Next, we've to Deploy our Smart Contract for that create a folder named Scripts and create a file named Deploy.js in it. And add this deploy code to it:

// We require the Hardhat Runtime Environment explicitly here. This is optional
// but useful for running the script in a standalone fashion through `node <script>`.
//
// When running the script with `npx hardhat run <script>` you'll find the Hardhat
// Runtime Environment's members available in the global scope.
const hre = require("hardhat");

async function main() {
  // We get the contract to deploy
  const EmojiFaces = await hre.ethers.getContractFactory("EmojiFaces");
  const emojiFaces = await EmojiFaces.deploy();

  await emojiFaces.deployed();

  console.log("EmojiFaces deployed to:", emojiFaces.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);
  });

🧪Testing the Project Once

Alright, Let's test our Project once. In your VS Code Terminal type npm run dev it'll take some seconds and it'll start your development server, once the dev server is started the terminal will look like this: image.png Your development server will start on http://localhost:3000 Click or type it in your browser and then Boom! The EmojiMint Decentralised application is Ready-To-Use and now available on the development server. Next, Let's deploy our EmojiMint dapp.

✨Let's Deploy

Let's deploy the frontend on Vercel. If you are building a Next.js application and want to deploy it, Vercel is the best option in my opinion.

Let's first create a initialize a git repository from the root directory of the project.

git init

Create a new GitHub repository (Just go to New repo 👀) and push the code to the repository.

Next, We'll be gonna use vercel for deploying so head over to vercel.com/dashboard to create a new project Next, Let's see the process below:

image.png

Next, Click on Deploy and let the site deploy:

image.png Let it deploy as it is, it'll take some 2-5 seconds to deploy our app.

Once done, BOOM! our EmojiMint NFT Minting dapp is now deployed and we can go on the deployed link provided by vercel.

👋The End

All those who have read the blog post until here deserve a big round of applause. Hope y'all have learned something new from this blog post.

Did you find this article valuable?

Support Darshan Mandade by becoming a sponsor. Any amount is appreciated!