{"id":419,"date":"2022-02-17T09:42:34","date_gmt":"2022-02-17T09:42:34","guid":{"rendered":"https:\/\/metaschool.so\/articles\/?p=419"},"modified":"2024-06-28T11:41:02","modified_gmt":"2024-06-28T11:41:02","slug":"build-full-stack-nft-minting-dapp","status":"publish","type":"post","link":"https:\/\/metaschool.so\/articles\/build-full-stack-nft-minting-dapp\/","title":{"rendered":"Build a Full Stack NFT minting Dapp w\/ Hardhat, ethers.js, Next.js &#038; TailwindCSS"},"content":{"rendered":"<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_56_1 ez-toc-wrap-left counter-hierarchy ez-toc-counter ez-toc-custom ez-toc-container-direction\">\n<div class=\"ez-toc-title-container\">\n<p class=\"ez-toc-title \" >Table of Contents<\/p>\n<span class=\"ez-toc-title-toggle\"><\/span><\/div>\n<nav><ul class='ez-toc-list ez-toc-list-level-1 ' ><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/metaschool.so\/articles\/build-full-stack-nft-minting-dapp\/#Prerequisites\" title=\"Prerequisites\">Prerequisites<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/metaschool.so\/articles\/build-full-stack-nft-minting-dapp\/#Resources\" title=\"Resources\">Resources<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/metaschool.so\/articles\/build-full-stack-nft-minting-dapp\/#About_the_project_Build_a_full_stack_NFT_minting_dapp\" title=\"About the project: Build a full stack NFT minting dapp\">About the project: Build a full stack NFT minting dapp<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/metaschool.so\/articles\/build-full-stack-nft-minting-dapp\/#Project_setup\" title=\"Project setup\">Project setup<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-5\" href=\"https:\/\/metaschool.so\/articles\/build-full-stack-nft-minting-dapp\/#Creating_an_Ethereum_API_key_using_Alchemy\" title=\"Creating an Ethereum API key using Alchemy\">Creating an Ethereum API key using Alchemy<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-6\" href=\"https:\/\/metaschool.so\/articles\/build-full-stack-nft-minting-dapp\/#Updating_hardhatconfigjs\" title=\"Updating hardhat.config.js\">Updating hardhat.config.js<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-7\" href=\"https:\/\/metaschool.so\/articles\/build-full-stack-nft-minting-dapp\/#Creating_Smart_Contract_logic\" title=\"Creating Smart Contract logic\">Creating Smart Contract logic<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-8\" href=\"https:\/\/metaschool.so\/articles\/build-full-stack-nft-minting-dapp\/#Testing_the_Smart_Contracts\" title=\"Testing the Smart Contracts\">Testing the Smart Contracts<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-9\" href=\"https:\/\/metaschool.so\/articles\/build-full-stack-nft-minting-dapp\/#Deploying_the_contracts_to_the_Rinkeby_Network\" title=\"Deploying the contracts to the Rinkeby Network\">Deploying the contracts to the Rinkeby Network<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-10\" href=\"https:\/\/metaschool.so\/articles\/build-full-stack-nft-minting-dapp\/#Building_the_frontend\" title=\"Building the frontend\">Building the frontend<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-11\" href=\"https:\/\/metaschool.so\/articles\/build-full-stack-nft-minting-dapp\/#Next_steps\" title=\"Next steps\">Next steps<\/a><\/li><\/ul><\/nav><\/div>\n\n<h2 class=\"wp-block-heading\" id=\"heading-prerequisites\"><span class=\"ez-toc-section\" id=\"Prerequisites\"><\/span>Prerequisites<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>In order to build a full stack NFT minting <a href=\"https:\/\/metaschool.so\/courses\/build-your-own-web3-twitter-dapp-with-solidity?ref=Article&amp;utm_source=Blog_Organic\">dApp<\/a> and be successful in this guide, you must have the following:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><a href=\"https:\/\/nodejs.org\/en\/\" target=\"_blank\" rel=\"noreferrer noopener\">Node.js<\/a>&nbsp;installed on your machine<\/li><li><a href=\"https:\/\/metamask.io\/\" target=\"_blank\" rel=\"noreferrer noopener\">Metamask<\/a>&nbsp;wallet extension installed as a browser extension. <\/li><\/ul>\n\n\n\n<p>New to all this? Learn here to <a href=\"https:\/\/metaschool.so\/courses\/understand-and-setup-metamask-account?ref=Articles&amp;utm_source=Blog_Organic\" target=\"_blank\" rel=\"noreferrer noopener\">set up your MetaMask account<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"heading-resources\"><span class=\"ez-toc-section\" id=\"Resources\"><\/span>Resources<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<ul class=\"wp-block-list\"><li><a target=\"_blank\" href=\"https:\/\/docs.soliditylang.org\/en\/v0.8.11\/\" rel=\"noreferrer noopener\">Solidity docs<\/a><\/li><li><a target=\"_blank\" href=\"https:\/\/solidity-by-example.org\/\" rel=\"noreferrer noopener\">Solidity by example<\/a>: An introduction to Solidity with simple examples<\/li><\/ul>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"heading-about-the-project\"><span class=\"ez-toc-section\" id=\"About_the_project_Build_a_full_stack_NFT_minting_dapp\"><\/span>About the project: Build a full stack NFT minting dapp<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>Going forward be will build a full stack <a href=\"https:\/\/metaschool.so\/courses\/learn-everything-about-nfts\" target=\"_blank\" rel=\"noreferrer noopener\">NFT<\/a> minting dapp using\u00a0<a href=\"https:\/\/metaschool.so\/articles\/guide-solidity-contracts\/\">Solidity<\/a>,\u00a0<a href=\"https:\/\/hardhat.org\/\" target=\"_blank\" rel=\"noreferrer noopener\">Hardhat<\/a>,\u00a0<a href=\"https:\/\/docs.ethers.io\/v5\/\" target=\"_blank\" rel=\"noreferrer noopener\">ethers.js<\/a>,\u00a0<a href=\"https:\/\/nextjs.org\/\" target=\"_blank\" rel=\"noreferrer noopener\">Next.js<\/a>, and\u00a0<a href=\"https:\/\/tailwindcss.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">TailwindCSS<\/a>.<\/p>\n\n\n\n<div class=\"wp-block-image is-style-default\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"576\" src=\"https:\/\/metaschool.so\/articles\/wp-content\/uploads\/2022\/02\/Sph5SPrm3-1024x576.jpeg\" alt=\"build full stack NFT minting dapp\" class=\"wp-image-430\" srcset=\"https:\/\/metaschool.so\/articles\/wp-content\/uploads\/2022\/02\/Sph5SPrm3-1024x576.jpeg 1024w, https:\/\/metaschool.so\/articles\/wp-content\/uploads\/2022\/02\/Sph5SPrm3-300x169.jpeg 300w, https:\/\/metaschool.so\/articles\/wp-content\/uploads\/2022\/02\/Sph5SPrm3-768x432.jpeg 768w, https:\/\/metaschool.so\/articles\/wp-content\/uploads\/2022\/02\/Sph5SPrm3-1536x864.jpeg 1536w, https:\/\/metaschool.so\/articles\/wp-content\/uploads\/2022\/02\/Sph5SPrm3.jpeg 1920w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure><\/div>\n\n\n\n<ul class=\"wp-block-list\"><li>To view the final source code for this project, visit&nbsp;<a target=\"_blank\" href=\"https:\/\/github.com\/AbhinavXT\/EternalNFT\" rel=\"noreferrer noopener\">this repo<\/a><\/li><li>To view the deployed site visit&nbsp;<a target=\"_blank\" href=\"https:\/\/eternal-nft.vercel.app\/\" rel=\"noreferrer noopener\">this website<\/a><\/li><\/ul>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"heading-project-setup\"><span class=\"ez-toc-section\" id=\"Project_setup\"><\/span>Project setup<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>To get started we need to create a hardhat project. To do so, open your terminal. Create or change into a new empty directory and run the following command:<\/p>\n\n\n\n<pre class=\"wp-block-code has-black-color has-text-color has-background\" style=\"background-color:#dacde6\"><code>npm install ethers hardhat @nomiclabs\/hardhat-waffle \\\nethereum-waffle chai @nomiclabs\/hardhat-ethers \\\n@openzeppelin\/contracts dotenv\n<\/code><\/pre>\n\n\n\n<p>This will install the dependencies for setting up a hardhat project and some other dependencies for the project.<\/p>\n\n\n\n<p>Next, initialize a new Hardhat development environment from the root of your project. To do so, run the following command in your terminal:<\/p>\n\n\n\n<pre class=\"wp-block-code has-background\" style=\"background-color:#dacde6\"><code>npx hardhat\n<\/code><\/pre>\n\n\n\n<p>The output will be similar to what is shown below. Select&nbsp;<code>Create a basic sample project<\/code>&nbsp;to create a new hardhat project in your directory.<\/p>\n\n\n\n<pre class=\"wp-block-code has-background\" style=\"background-color:#dacde6\"><code>What do you want to do? \u2026 \nCreate a basic sample project\nCreate an advanced sample project\n. . .\n<\/code><\/pre>\n\n\n\n<p>Now you should see the following files and folders created for you in your root directory:<\/p>\n\n\n\n<p><strong>hardhat.config.js &#8211;<\/strong>&nbsp;The entirety of your Hardhat setup (i.e. your config, plugins, and custom tasks) is contained in this file.<\/p>\n\n\n\n<p><strong>scripts &#8211;<\/strong>&nbsp;A folder containing a script named sample-script.js that will deploy your smart contract when executed.<\/p>\n\n\n\n<p><strong>test &#8211;&nbsp;<\/strong>A folder containing an example testing script.<\/p>\n\n\n\n<p><strong>contracts &#8211;<\/strong>&nbsp;A folder holding an example Solidity smart contract.<\/p>\n\n\n\n<p>Now, we need to create a new Next.js project for the frontend of the dapp. To do so, run the following command in your terminal:<\/p>\n\n\n\n<pre class=\"wp-block-code has-background\" style=\"background-color:#dacde6\"><code>npx create-next-app -e with-tailwindcss client\n<\/code><\/pre>\n\n\n\n<p>This will create a new Next project using tailwindcss for styling in a folder &#8216;client&#8217;.<\/p>\n\n\n\n<p>After this install dependencies for the frontend inside the&nbsp;<code>client<\/code>&nbsp;folder. To do this run the following command in your terminal:<\/p>\n\n\n\n<pre class=\"wp-block-code has-background\" style=\"background-color:#dacde6\"><code>cd client\n\nnpm install axios ethers react-loader-spinner\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"heading-creating-an-ethereum-api-key-using-alchemy\"><span class=\"ez-toc-section\" id=\"Creating_an_Ethereum_API_key_using_Alchemy\"><\/span>Creating an Ethereum API key using Alchemy<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>Alchemy is a blockchain developer platform focused on making blockchain development easy. They&#8217;ve built a suite of developer tools, enhanced APIs, and superior node infrastructure to make building and running blockchain applications seamless.<\/p>\n\n\n\n<p>To create an API key follow the video below. Things to note:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Select the network as goerli.<\/li><li>Copy the HTTP key after the creation of the app on alchemy.<\/li><\/ul>\n\n\n\n<figure class=\"wp-block-embed is-type-rich is-provider-embed-handler wp-block-embed-embed-handler wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<div class=\"nv-iframe-embed\"><iframe loading=\"lazy\" title=\"Create an Ethereum API Key with Alchemy\" width=\"1200\" height=\"675\" src=\"https:\/\/www.youtube.com\/embed\/tfggWxfG9o0?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe><\/div>\n<\/div><\/figure>\n\n\n\n<p>Next, create a&nbsp;<code>.env<\/code>&nbsp;file to store your&nbsp;<code>Alchemy key<\/code>&nbsp;and your&nbsp;<code>Account Private Key<\/code><\/p>\n\n\n\n<pre class=\"wp-block-code has-background\" style=\"background-color:#dacde6\"><code>ALCHEMY_GOERLI_URL = \"ALCHEMY_HTTP_API_KEY\"\nACCOUNT_KEY = \"YOUR_ACCOUNT_PRIVATE_KEY\n<\/code><\/pre>\n\n\n\n<p><strong>Important<\/strong>: Do not push the&nbsp;<code>.env<\/code> file to GitHub as it contains your private data.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"heading-updating-hardhatconfigjs\"><span class=\"ez-toc-section\" id=\"Updating_hardhatconfigjs\"><\/span>Updating hardhat.config.js<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>After this, update the configuration at hardhat.config.js with the following:<\/p>\n\n\n\n<pre class=\"wp-block-code has-background\" style=\"background-color:#dacde6\"><code>require('@nomiclabs\/hardhat-waffle')\nrequire('dotenv').config()\n\nmodule.exports = {\n    solidity: '0.8.3',\n    networks: {\n        rinkeby: {\n            url: process.env.ALCHEMY_GOERLI_URL,\n            accounts: &#91;process.env.ACCOUNT_KEY],\n        },\n    },\n}\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"heading-creating-smart-contract-logic\"><span class=\"ez-toc-section\" id=\"Creating_Smart_Contract_logic\"><\/span>Creating Smart Contract logic<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>Next, we&#8217;ll create our <a href=\"https:\/\/metaschool.so\/courses\/writing-your-first-hello-world-contract-in-solidity\" target=\"_blank\" rel=\"noreferrer noopener\">smart contracts<\/a>! We&#8217;ll create an NFT contract for the creation of NFT assets. Create a new file in the contracts directory named&nbsp;<code>EternalNFT.sol<\/code>. Here, add the following code:<\/p>\n\n\n\n<p>You can view the gist at&nbsp;<a href=\"https:\/\/gist.github.com\/AbhinavXT\/f2956b592b926625e4d868e010cdc63e\" target=\"_blank\" rel=\"noreferrer noopener\">EternalNFT.sol<\/a><\/p>\n\n\n\n<pre class=\"wp-block-code has-background\" style=\"background-color:#dacde6\"><code>\/\/SPDX-License-Identifier: MIT\npragma solidity 0.8.3;\n\nimport \"@openzeppelin\/contracts\/utils\/Counters.sol\";\nimport \"@openzeppelin\/contracts\/token\/ERC721\/extensions\/ERC721URIStorage.sol\";\nimport { Base64 } from \".\/libraries\/Base64.sol\";\n\ncontract EternalNFT is ERC721URIStorage {\n    using Counters for Counters.Counter;\n    Counters.Counter private _tokenId;\n\n    string public collectionName;\n    string public collectionSymbol;\n\n\n    string baseSvg = \"&lt;svg xmlns='http:\/\/www.w3.org\/2000\/svg' preserveAspectRatio='xMinYMin meet' viewBox='0 0 350 350'&gt;&lt;style&gt;.base { fill: white; font-family: serif; font-size: 24px; }&lt;\/style&gt;&lt;rect width='100%' height='100%' fill='black' \/&gt;&lt;text x='50%' y='50%' class='base' dominant-baseline='middle' text-anchor='middle'&gt;\";\n\n    string&#91;] element = &#91;\n        'Fire',\n        'Wind',\n        'Wave',\n        'Earth',\n        'Thunder',\n        'Space',\n        'Time'\n    ];\n\n    string&#91;] weapon = &#91;\n        'Sword',\n        'Spear',\n        'Shield',\n        'Hammer',\n        'Saber',\n        'Axe',\n        'Bow'\n    ];\n\n    string&#91;] rank = &#91;\n        'Lord',\n        'King',\n        'Emperor',\n        'Venerable',\n        'Ancestor',\n        'Saint',\n        'God'\n    ];\n\n    constructor() ERC721(\"EternalNFT\", \"ENFT\") {\n        collectionName = name();\n        collectionSymbol = symbol();\n    }\n\n    function random(string memory _input) internal pure returns(uint256) {\n        return uint256(keccak256(abi.encodePacked(_input)));\n    }\n\n\n    function pickFirstWord(uint256 tokenId) public view returns(string memory) {\n        uint256 rand = random(string(abi.encodePacked(\"element\", Strings.toString(tokenId))));\n        rand = rand % element.length;\n        return element&#91;rand];\n    }\n\n\n    function pickSecondWord(uint256 tokenId) public view returns(string memory) {\n        uint256 rand = random(string(abi.encodePacked(\"weapon\", Strings.toString(tokenId))));\n        rand = rand % weapon.length;\n        return weapon&#91;rand];\n    }\n\n    function pickThirdWord(uint256 tokenId) public view returns(string memory) {\n        uint256 rand = random(string(abi.encodePacked(\"rank\", Strings.toString(tokenId))));\n        rand = rand % rank.length;\n        return rank&#91;rand];\n    }\n\n\n    function createEternalNFT() public returns(uint256) {\n        uint256 newItemId = _tokenId.current();\n\n        string memory first = pickFirstWord(newItemId);\n        string memory second = pickSecondWord(newItemId);\n        string memory third = pickThirdWord(newItemId);\n        string memory combinedWord = string(abi.encodePacked(first,second,third));\n\n        string memory finalSvg = string(abi.encodePacked(baseSvg, first, second, third, \"&lt;\/text&gt;&lt;\/svg&gt;\"));\n\n        string memory json = Base64.encode(\n            bytes(\n                string(\n                    abi.encodePacked(\n                    '{\"name\": \"',\n                        combinedWord,\n                        '\", \"description\": \"A highly acclaimed collection Eternal Warriors\", \"image\": \"data:image\/svg+xml;base64,',\n                        Base64.encode(bytes(finalSvg)),\n                    '\"}'\n                    )\n                )\n            )\n        );\n\n        string memory finalTokenURI = string(abi.encodePacked(\n            \"data:application\/json;base64,\", json\n        ));\n\n        _safeMint(msg.sender, newItemId);\n        _setTokenURI(newItemId, finalTokenURI);\n\n        _tokenId.increment();\n\n        return newItemId;\n    }\n}\n<\/code><\/pre>\n\n\n\n<p>In this contract, we are inheriting from the&nbsp;<a href=\"https:\/\/github.com\/OpenZeppelin\/openzeppelin-contracts\/blob\/master\/contracts\/token\/ERC721\/extensions\/ERC721URIStorage.sol\" target=\"_blank\" rel=\"noreferrer noopener\">ERC721ERC721URIStorage.sol<\/a>&nbsp;and&nbsp;<a href=\"https:\/\/github.com\/OpenZeppelin\/openzeppelin-contracts\/blob\/master\/contracts\/utils\/Counters.sol\" target=\"_blank\" rel=\"noreferrer noopener\">Counters.sol<\/a>&nbsp;implemented by&nbsp;<a href=\"https:\/\/metaschool.so\/articles\/what-is-openzeppelin\/\" target=\"_blank\" rel=\"noreferrer noopener\">OpenZeppelin<\/a><\/p>\n\n\n\n<p>For the&nbsp;<strong>Base64 library<\/strong>&nbsp;that is inherited by the contract, create a&nbsp;<code>libraries<\/code>&nbsp;folder inside the contracts folder. Inside the libraries, folder create a&nbsp;<code>Base64.sol<\/code>&nbsp;file add the following code:<\/p>\n\n\n\n<p>You can view the gist at&nbsp;<a href=\"https:\/\/gist.github.com\/AbhinavXT\/d5bdf41988214b5e0464cb6cb07e786d\" target=\"_blank\" rel=\"noreferrer noopener\">Base64.sol<\/a><\/p>\n\n\n\n<pre class=\"wp-block-code has-background\" style=\"background-color:#dacde6\"><code>\/**\n *Submitted for verification at Etherscan.io on 2021-09-05\n *\/\n\n\/\/ SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\n\/\/\/ &#91;MIT License]\n\/\/\/ @title Base64\n\/\/\/ @notice Provides a function for encoding some bytes in base64\n\/\/\/ @author Brecht Devos &lt;brecht@loopring.org&gt;\nlibrary Base64 {\n    bytes internal constant TABLE =\n        \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+\/\";\n\n    \/\/\/ @notice Encodes some bytes to the base64 representation\n    function encode(bytes memory data) internal pure returns (string memory) {\n        uint256 len = data.length;\n        if (len == 0) return \"\";\n\n        \/\/ multiply by 4\/3 rounded up\n        uint256 encodedLen = 4 * ((len + 2) \/ 3);\n\n        \/\/ Add some extra buffer at the end\n        bytes memory result = new bytes(encodedLen + 32);\n\n        bytes memory table = TABLE;\n\n        assembly {\n            let tablePtr := add(table, 1)\n            let resultPtr := add(result, 32)\n\n            for {\n                let i := 0\n            } lt(i, len) {\n\n            } {\n                i := add(i, 3)\n                let input := and(mload(add(data, i)), 0xffffff)\n\n                let out := mload(add(tablePtr, and(shr(18, input), 0x3F)))\n                out := shl(8, out)\n                out := add(\n                    out,\n                    and(mload(add(tablePtr, and(shr(12, input), 0x3F))), 0xFF)\n                )\n                out := shl(8, out)\n                out := add(\n                    out,\n                    and(mload(add(tablePtr, and(shr(6, input), 0x3F))), 0xFF)\n                )\n                out := shl(8, out)\n                out := add(\n                    out,\n                    and(mload(add(tablePtr, and(input, 0x3F))), 0xFF)\n                )\n                out := shl(224, out)\n\n                mstore(resultPtr, out)\n\n                resultPtr := add(resultPtr, 4)\n            }\n\n            switch mod(len, 3)\n            case 1 {\n                mstore(sub(resultPtr, 2), shl(240, 0x3d3d))\n            }\n            case 2 {\n                mstore(sub(resultPtr, 1), shl(248, 0x3d))\n            }\n\n            mstore(result, encodedLen)\n        }\n\n        return string(result);\n    }\n}\n<\/code><\/pre>\n\n\n\n<p><strong>Sign up for later<\/strong>: <a href=\"https:\/\/metaschool.so\/courses\/how-does-ethereum-work-a-deepdive?ref=Articles&amp;utm_source=Blog_Organic\" target=\"_blank\" rel=\"noreferrer noopener\">How does Ethereum work? Let&#8217;s take a deep dive<\/a> <\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"heading-testing-the-smart-contracts\"><span class=\"ez-toc-section\" id=\"Testing_the_Smart_Contracts\"><\/span>Testing the Smart Contracts<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>Now the smart contract code and environment are complete and we can try testing it out.<\/p>\n\n\n\n<p>To do so, we can create a local test to run through much of the functionality, like checking for name, symbol, and address of token, minting a token, etc.<\/p>\n\n\n\n<p>To create the test, open test\/sample-test.js and update it with the following code:<\/p>\n\n\n\n<p>You can view the gist at&nbsp;<a href=\"https:\/\/gist.github.com\/AbhinavXT\/2586ffef2501325798636de1c2556b01\" target=\"_blank\" rel=\"noreferrer noopener\">sample-test.js<\/a><\/p>\n\n\n\n<pre class=\"wp-block-code has-background\" style=\"background-color:#dacde6\"><code>const { assert } = require('chai')\n\ndescribe('EternalNFT Contract', async () =&gt; {\n    let nft\n    let nftContractAddress\n    let tokenId\n\n    \/\/ Deploys the EternalNFT contract and the EternalMarket contract before each test\n    beforeEach('Setup Contract', async () =&gt; {\n        const EternalNFT = await ethers.getContractFactory('EternalNFT')\n        nft = await EternalNFT.deploy()\n        await nft.deployed()\n        nftContractAddress = await nft.address\n    })\n\n    \/\/ Tests address for the EternalNFT contract\n    it('Should have an address', async () =&gt; {\n        assert.notEqual(nftContractAddress, 0x0)\n        assert.notEqual(nftContractAddress, '')\n        assert.notEqual(nftContractAddress, null)\n        assert.notEqual(nftContractAddress, undefined)\n    })\n\n    \/\/ Tests name for the token of EternalNFT contract\n    it('Should have a name', async () =&gt; {\n        \/\/ Returns the name of the token\n        const name = await nft.collectionName()\n\n        assert.equal(name, 'EternalNFT')\n    })\n\n    \/\/ Tests symbol for the token of EternalNFT contract\n    it('Should have a symbol', async () =&gt; {\n        \/\/ Returns the symbol of the token\n        const symbol = await nft.collectionSymbol()\n\n        assert.equal(symbol, 'ENFT')\n    })\n\n    \/\/ Tests for NFT minting function of EternalNFT contract using tokenID of the minted NFT\n    it('Should be able to mint NFT', async () =&gt; {\n        \/\/ Mints a NFT\n        let txn = await nft.createEternalNFT()\n        let tx = await txn.wait()\n\n        \/\/ tokenID of the minted NFT\n        let event = tx.events&#91;0]\n        let value = event.args&#91;2]\n        tokenId = value.toNumber()\n\n        assert.equal(tokenId, 0)\n\n        \/\/ Mints another NFT\n        txn = await nft.createEternalNFT()\n        tx = await txn.wait()\n\n        \/\/ tokenID of the minted NFT\n        event = tx.events&#91;0]\n        value = event.args&#91;2]\n        tokenId = value.toNumber()\n\n        assert.equal(tokenId, 1)\n    })\n})\n<\/code><\/pre>\n\n\n\n<p>To run the test, run the following command from your terminal at the root of your project:<\/p>\n\n\n\n<pre class=\"wp-block-code has-background\" style=\"background-color:#dacde6\"><code>npx hardhat test\n<\/code><\/pre>\n\n\n\n<p><strong>Explore:<\/strong> <a href=\"https:\/\/metaschool.so\/articles\/how-to-get-an-ens-domain\/\">How to get ENS Domains \u2013 Everything you need to know<\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"heading-deploying-the-contracts-to-the-rinkeby-network\"><span class=\"ez-toc-section\" id=\"Deploying_the_contracts_to_the_Rinkeby_Network\"><\/span>Deploying the contracts to the Rinkeby Network<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>When we created the project, Hardhat created an example deployment script at&nbsp;<code>scripts\/sample-script.js<\/code>.<\/p>\n\n\n\n<p>To make the purpose of this script clear, delete&nbsp;<code>scripts\/sample-script.js<\/code>&nbsp;and create&nbsp;<code>scripts\/deploy.js<\/code>.<\/p>\n\n\n\n<p>To deploy the contracts add the following code inside&nbsp;<code>deploy.js<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code has-background\" style=\"background-color:#dacde6\"><code>const main = async () =&gt; {\n    const nftContractFactory = await ethers.getContractFactory('EternalNFT')\n    const nftContract = await nftContractFactory.deploy()\n    await nftContract.deployed()\n    console.log('Contract deployed to:', nftContract.address)\n}\n\nconst runMain = async () =&gt; {\n    try {\n        await main()\n        process.exit(0)\n    } catch (error) {\n        console.log(error)\n        process.exit(1)\n    }\n}\n\nrunMain()\n<\/code><\/pre>\n\n\n\n<p>To deploy the contract to the rinkeby network run the following command in your terminal: <\/p>\n\n\n\n<pre class=\"wp-block-code has-background\" style=\"background-color:#dacde6\"><code>npx hardhat run scripts\/deploy.js --network goerli\n<\/code><\/pre>\n\n\n\n<p>This will deploy the contract to the rinkeby network and output the address at which the contract is deployed in the terminal.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"heading-building-the-frontend\"><span class=\"ez-toc-section\" id=\"Building_the_frontend\"><\/span>Building the frontend<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>Now that the smart contract is working and ready to go, we can start building out the UI.<\/p>\n\n\n\n<p>First, we need to connect the frontend to the smart contract, so it can interact with the data from the blockchain using the functions in the smart contracts.<\/p>\n\n\n\n<p>For this we need to do the following:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Create a&nbsp;<code>utils<\/code>&nbsp;folder inside the&nbsp;<code>client<\/code>&nbsp;folder and copy and paste the&nbsp;<code>artifacts\/contracts\/EternalNFT.sol\/EternalNFT.json<\/code>&nbsp;file inside the&nbsp;<code>utils<\/code>&nbsp;folder.<\/li><li>Create a&nbsp;<code>config.js<\/code>&nbsp;file inside the&nbsp;<code>client<\/code>&nbsp;folder and add the following code inside it.<\/li><\/ul>\n\n\n\n<pre class=\"wp-block-code has-background\" style=\"background-color:#dacde6\"><code>export const nftContractAddress = \"DEPLOYED_CONTRACT_ADDRES\"\n<\/code><\/pre>\n\n\n\n<p>Replace the&nbsp;<code>DEPLOYED_CONTRACT_ADDRES<\/code>&nbsp;with the deployed contract address from the terminal when deploying the smart contract.<\/p>\n\n\n\n<p>Next, to set up the frontend go to&nbsp;<code>client\/pages\/index.js<\/code>&nbsp;and update it with the following code:<\/p>\n\n\n\n<p>You can view the gist at&nbsp;<a href=\"https:\/\/gist.github.com\/AbhinavXT\/f56f101bf5bd94bb3b49d189ede3ffe0\" target=\"_blank\" rel=\"noreferrer noopener\">index.js<\/a><\/p>\n\n\n\n<pre class=\"wp-block-code has-background\" style=\"background-color:#dacde6\"><code>import { useState, useEffect } from 'react'\nimport { nftContractAddress } from '..\/config.js'\nimport { ethers } from 'ethers'\nimport axios from 'axios'\n\nimport Loader from 'react-loader-spinner'\n\nimport NFT from '..\/utils\/EternalNFT.json'\n\nconst mint = () =&gt; {\n    const &#91;mintedNFT, setMintedNFT] = useState(null)\n    const &#91;miningStatus, setMiningStatus] = useState(null)\n    const &#91;loadingState, setLoadingState] = useState(0)\n    const &#91;txError, setTxError] = useState(null)\n    const &#91;currentAccount, setCurrentAccount] = useState('')\n    const &#91;correctNetwork, setCorrectNetwork] = useState(false)\n\n    \/\/ Checks if wallet is connected\n    const checkIfWalletIsConnected = async () =&gt; {\n        const { ethereum } = window\n        if (ethereum) {\n            console.log('Got the ethereum obejct: ', ethereum)\n        } else {\n            console.log('No Wallet found. Connect Wallet')\n        }\n\n        const accounts = await ethereum.request({ method: 'eth_accounts' })\n\n        if (accounts.length !== 0) {\n            console.log('Found authorized Account: ', accounts&#91;0])\n            setCurrentAccount(accounts&#91;0])\n        } else {\n            console.log('No authorized account found')\n        }\n    }\n\n    \/\/ Calls Metamask to connect wallet on clicking Connect Wallet button\n    const connectWallet = async () =&gt; {\n        try {\n            const { ethereum } = window\n\n            if (!ethereum) {\n                console.log('Metamask not detected')\n                return\n            }\n            let chainId = await ethereum.request({ method: 'eth_chainId' })\n            console.log('Connected to chain:' + chainId)\n\n            const goerliChainId = '0x5'\n\n            const devChainId = 1337\n            const localhostChainId = `0x${Number(devChainId).toString(16)}`\n\n            if (chainId !== goerliChainId &amp;&amp; chainId !== localhostChainId) {\n                alert('You are not connected to the Goerli Testnet!')\n                return\n            }\n\n            const accounts = await ethereum.request({ method: 'eth_requestAccounts' })\n\n            console.log('Found account', accounts&#91;0])\n            setCurrentAccount(accounts&#91;0])\n        } catch (error) {\n            console.log('Error connecting to metamask', error)\n        }\n    }\n\n    \/\/ Checks if wallet is connected to the correct network\n    const checkCorrectNetwork = async () =&gt; {\n        const { ethereum } = window\n        let chainId = await ethereum.request({ method: 'eth_chainId' })\n        console.log('Connected to chain:' + chainId)\n\n        const goerliChainId = '0x5'\n\n        const devChainId = 1337\n        const localhostChainId = `0x${Number(devChainId).toString(16)}`\n\n        if (chainId !== goerliChainId &amp;&amp; chainId !== localhostChainId) {\n            setCorrectNetwork(false)\n        } else {\n            setCorrectNetwork(true)\n        }\n    }\n\n    useEffect(() =&gt; {\n        checkIfWalletIsConnected()\n        checkCorrectNetwork()\n    }, &#91;])\n\n    \/\/ Creates transaction to mint NFT on clicking Mint Character button\n    const mintCharacter = async () =&gt; {\n        try {\n            const { ethereum } = window\n\n            if (ethereum) {\n                const provider = new ethers.providers.Web3Provider(ethereum)\n                const signer = provider.getSigner()\n                const nftContract = new ethers.Contract(\n                    nftContractAddress,\n                    NFT.abi,\n                    signer\n                )\n\n                let nftTx = await nftContract.createEternalNFT()\n                console.log('Mining....', nftTx.hash)\n                setMiningStatus(0)\n\n                let tx = await nftTx.wait()\n                setLoadingState(1)\n                console.log('Mined!', tx)\n                let event = tx.events&#91;0]\n                let value = event.args&#91;2]\n                let tokenId = value.toNumber()\n\n                console.log(\n                    `Mined, see transaction: https:\/\/rinkeby.etherscan.io\/tx\/${nftTx.hash}`\n                )\n\n                getMintedNFT(tokenId)\n            } else {\n                console.log(\"Ethereum object doesn't exist!\")\n            }\n        } catch (error) {\n            console.log('Error minting character', error)\n            setTxError(error.message)\n        }\n    }\n\n    \/\/ Gets the minted NFT data\n    const getMintedNFT = async (tokenId) =&gt; {\n        try {\n            const { ethereum } = window\n\n            if (ethereum) {\n                const provider = new ethers.providers.Web3Provider(ethereum)\n                const signer = provider.getSigner()\n                const nftContract = new ethers.Contract(\n                    nftContractAddress,\n                    NFT.abi,\n                    signer\n                )\n\n                let tokenUri = await nftContract.tokenURI(tokenId)\n                let data = await axios.get(tokenUri)\n                let meta = data.data\n\n                setMiningStatus(1)\n                setMintedNFT(meta.image)\n            } else {\n                console.log(\"Ethereum object doesn't exist!\")\n            }\n        } catch (error) {\n            console.log(error)\n            setTxError(error.message)\n        }\n    }\n\n    return (\n        &lt;div className='flex flex-col items-center pt-32 bg-&#91;#0B132B] text-&#91;#d3d3d3] min-h-screen'&gt;\n            &lt;div className='trasition hover:rotate-180 hover:scale-105 transition duration-500 ease-in-out'&gt;\n                &lt;svg\n                    xmlns='http:\/\/www.w3.org\/2000\/svg'\n                    width='60'\n                    height='60'\n                    fill='currentColor'\n                    viewBox='0 0 16 16'\n                &gt;\n                    &lt;path d='M8.186 1.113a.5.5 0 0 0-.372 0L1.846 3.5 8 5.961 14.154 3.5 8.186 1.113zM15 4.239l-6.5 2.6v7.922l6.5-2.6V4.24zM7.5 14.762V6.838L1 4.239v7.923l6.5 2.6zM7.443.184a1.5 1.5 0 0 1 1.114 0l7.129 2.852A.5.5 0 0 1 16 3.5v8.662a1 1 0 0 1-.629.928l-7.185 2.874a.5.5 0 0 1-.372 0L.63 13.09a1 1 0 0 1-.63-.928V3.5a.5.5 0 0 1 .314-.464L7.443.184z' \/&gt;\n                &lt;\/svg&gt;\n            &lt;\/div&gt;\n            &lt;h2 className='text-3xl font-bold mb-20 mt-12'&gt;\n                Mint your Eternal Domain NFT!\n            &lt;\/h2&gt;\n            {currentAccount === '' ? (\n                &lt;button\n                    className='text-2xl font-bold py-3 px-12 bg-black shadow-lg shadow-&#91;#6FFFE9] rounded-lg mb-10 hover:scale-105 transition duration-500 ease-in-out'\n                    onClick={connectWallet}\n                &gt;\n                    Connect Wallet\n                &lt;\/button&gt;\n            ) : correctNetwork ? (\n                &lt;button\n                    className='text-2xl font-bold py-3 px-12 bg-black shadow-lg shadow-&#91;#6FFFE9] rounded-lg mb-10 hover:scale-105 transition duration-500 ease-in-out'\n                    onClick={mintCharacter}\n                &gt;\n                    Mint Character\n                &lt;\/button&gt;\n            ) : (\n                &lt;div className='flex flex-col justify-center items-center mb-20 font-bold text-2xl gap-y-3'&gt;\n                    &lt;div&gt;----------------------------------------&lt;\/div&gt;\n                    &lt;div&gt;Please connect to the Rinkeby Testnet&lt;\/div&gt;\n                    &lt;div&gt;and reload the page&lt;\/div&gt;\n                    &lt;div&gt;----------------------------------------&lt;\/div&gt;\n                &lt;\/div&gt;\n            )}\n\n            &lt;div className='text-xl font-semibold mb-20 mt-4'&gt;\n                &lt;a\n                    href={`https:\/\/goerli.rarible.com\/collection\/${nftContractAddress}`}\n                    target='_blank'\n                &gt;\n                    &lt;span className='hover:underline hover:underline-offset-8 '&gt;\n                        View Collection on Rarible\n                    &lt;\/span&gt;\n                &lt;\/a&gt;\n            &lt;\/div&gt;\n            {loadingState === 0 ? (\n                miningStatus === 0 ? (\n                    txError === null ? (\n                        &lt;div className='flex flex-col justify-center items-center'&gt;\n                            &lt;div className='text-lg font-bold'&gt;\n                                Processing your transaction\n                            &lt;\/div&gt;\n                            &lt;Loader\n                                className='flex justify-center items-center pt-12'\n                                type='TailSpin'\n                                color='#d3d3d3'\n                                height={40}\n                                width={40}\n                            \/&gt;\n                        &lt;\/div&gt;\n                    ) : (\n                        &lt;div className='text-lg text-red-600 font-semibold'&gt;{txError}&lt;\/div&gt;\n                    )\n                ) : (\n                    &lt;div&gt;&lt;\/div&gt;\n                )\n            ) : (\n                &lt;div className='flex flex-col justify-center items-center'&gt;\n                    &lt;div className='font-semibold text-lg text-center mb-4'&gt;\n                        Your Eternal Domain Character\n                    &lt;\/div&gt;\n                    &lt;img\n                        src={mintedNFT}\n                        alt=''\n                        className='h-60 w-60 rounded-lg shadow-2xl shadow-&#91;#6FFFE9] hover:scale-105 transition duration-500 ease-in-out'\n                    \/&gt;\n                &lt;\/div&gt;\n            )}\n        &lt;\/div&gt;\n    )\n}\n\nexport default mint\n<\/code><\/pre>\n\n\n\n<p>Let&#8217;s discuss the code we have added to the&nbsp;<code>index.js<\/code>&nbsp;file<\/p>\n\n\n\n<p>The code contains the following functions:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><code>checkIfWalletIsConnected<\/code>: This function checks if the wallet is connected to the dapp when it loads.<\/li><li><code>connectWallet<\/code>: This function connects the wallet to the dapp when the user clicks the&nbsp;<code>Connect Wallet<\/code>&nbsp;button in the frontend.<\/li><li><code>checkCorrectNetwork<\/code>: This function checks if the wallet is connected to the&nbsp;<code>rinkeby<\/code>&nbsp;network. If not the frontend asks the user to connect to the&nbsp;<code>rinkeby<\/code>&nbsp;network and reload the page.<\/li><li><code>mintCharacter<\/code>: This function creates the transaction to mint a new NFT when the user clicks on the&nbsp;<code>Mint Character<\/code>&nbsp;button.<\/li><li><code>getMintedNFT<\/code>: This function retrieves the data of the newly minted NFT to display it in the frontend.<\/li><\/ul>\n\n\n\n<p>To test the <a href=\"https:\/\/metaschool.so\/courses\/build-your-own-web3-twitter-dapp-with-solidity?ref=Articles&amp;utm_source=Blog_Organic\" target=\"_blank\" rel=\"noreferrer noopener\">dapp<\/a> in the browser, run the following command in your terminal:<\/p>\n\n\n\n<pre class=\"wp-block-code has-background\" style=\"background-color:#dacde6\"><code>cd client\n\nnpm run dev\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"heading-next-steps\"><span class=\"ez-toc-section\" id=\"Next_steps\"><\/span>Next steps<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>Congratulations! Here&#8217;s how to build a Full Stack NFT minting Dapp using Hardhat, ethers.js, Next.js and TailwindCSS. You most likely have deployed a full-stack NFT minting dapp to Ethereum by now. <\/p>\n\n\n\n<p>After successfully deploying the dapp, you can host it on services like&nbsp;<a href=\"https:\/\/vercel.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">vercel<\/a>&nbsp;or&nbsp;<a href=\"https:\/\/www.netlify.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">netlify<\/a>.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>Learn more about the Web3 space with exciting and <a href=\"https:\/\/metaschool.so\/courses?ref=Articles&amp;utm_source=Blog_Organic\">free web3 tutorials<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"","protected":false},"author":5,"featured_media":429,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"neve_meta_sidebar":"","neve_meta_container":"","neve_meta_enable_content_width":"","neve_meta_content_width":0,"neve_meta_title_alignment":"","neve_meta_author_avatar":"","neve_post_elements_order":"","neve_meta_disable_header":"","neve_meta_disable_footer":"","neve_meta_disable_title":"","footnotes":""},"categories":[14,17,12],"tags":[36,35,33,31,34],"class_list":["post-419","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-web3","category-blockchain","category-nft","tag-blockchain-applications","tag-dapps","tag-decentralized-app","tag-ethereum-blockchain","tag-mint-nft-dapp"],"_links":{"self":[{"href":"https:\/\/metaschool.so\/articles\/wp-json\/wp\/v2\/posts\/419","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/metaschool.so\/articles\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/metaschool.so\/articles\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/metaschool.so\/articles\/wp-json\/wp\/v2\/users\/5"}],"replies":[{"embeddable":true,"href":"https:\/\/metaschool.so\/articles\/wp-json\/wp\/v2\/comments?post=419"}],"version-history":[{"count":19,"href":"https:\/\/metaschool.so\/articles\/wp-json\/wp\/v2\/posts\/419\/revisions"}],"predecessor-version":[{"id":7608,"href":"https:\/\/metaschool.so\/articles\/wp-json\/wp\/v2\/posts\/419\/revisions\/7608"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/metaschool.so\/articles\/wp-json\/wp\/v2\/media\/429"}],"wp:attachment":[{"href":"https:\/\/metaschool.so\/articles\/wp-json\/wp\/v2\/media?parent=419"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/metaschool.so\/articles\/wp-json\/wp\/v2\/categories?post=419"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/metaschool.so\/articles\/wp-json\/wp\/v2\/tags?post=419"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}