{"id":2238,"date":"2022-01-25T17:57:38","date_gmt":"2022-01-25T17:57:38","guid":{"rendered":"https:\/\/lvboard.infostore.in.ua\/?p=2238"},"modified":"2022-01-25T17:57:38","modified_gmt":"2022-01-25T17:57:38","slug":"building-a-web3-frontend-with-react","status":"publish","type":"post","link":"https:\/\/lvboard.infostore.in.ua\/?p=2238","title":{"rendered":"Building a web3 frontend with React"},"content":{"rendered":"\n<h2>Introduction<\/h2>\n\n\n\n<p>In a&nbsp;<a href=\"https:\/\/dev.to\/rounakbanik\/writing-an-nft-collectible-smart-contract-2nh8\">previous tutorial<\/a>, we covered how to create and deploy an NFT collectible smart contract from scratch. We also explored how to verify our contract on etherscan and enable yourself as well as your users to call functions directly from the contract\u2019s etherscan page.<\/p>\n\n\n\n<!--more-->\n\n\n\n<p>However, most serious projects tend to deploy their own websites and allow users to mint directly from the website.<\/p>\n\n\n\n<p>This is exactly what we will be covering in this tutorial. More specifically, this tutorial will show you how to:<\/p>\n\n\n\n<ol><li>Let users connect their Metamask wallet to your website<\/li><li>Allow users to call a contract function, make a payment, and mint an NFT from your collection.<\/li><\/ol>\n\n\n\n<p>By the end of this tutorial, you\u2019ll have a fully functioning web3 frontend built with React. You will have also gained the foundational knowledge required to build any general-purpose web3 frontend (beyond an NFT minter).<\/p>\n\n\n\n<h2><a href=\"https:\/\/dev.to\/rounakbanik\/building-a-web3-frontend-with-react-340c#prerequisites\"><\/a>Prerequisites<\/h2>\n\n\n\n<figure class=\"wp-block-image\"><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--kzOBMLAR--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/dev-to-uploads.s3.amazonaws.com\/uploads\/articles\/k5n2m87tq72ncq2zi2ny.png\"><img src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--kzOBMLAR--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/dev-to-uploads.s3.amazonaws.com\/uploads\/articles\/k5n2m87tq72ncq2zi2ny.png\" alt=\"React Tutorial\"\/><\/a><\/figure>\n\n\n\n<p>This tutorial assumes you have already developed and deployed your smart contract to the Rinkeby test network. If you haven\u2019t, we strongly suggest you go through&nbsp;<a href=\"https:\/\/dev.to\/rounakbanik\/writing-an-nft-collectible-smart-contract-2nh8\">this tutorial<\/a>. In order to follow along with this tutorial, you will need the following:<\/p>\n\n\n\n<ol><li>The ABI file for your smart contract (which is available in the&nbsp;<em>artifacts<\/em>&nbsp;folder of your smart contract project).<\/li><li>The address of your smart contract.<\/li><\/ol>\n\n\n\n<p>We also assume that you have experience working with React and Javascript. If not, we strongly suggest you go through the&nbsp;<a href=\"https:\/\/reactjs.org\/tutorial\/tutorial.html\">official tutorial on React\u2019s website<\/a>&nbsp;first.<\/p>\n\n\n\n<h2><a href=\"https:\/\/dev.to\/rounakbanik\/building-a-web3-frontend-with-react-340c#setting-up-the-project\"><\/a>Setting up the project<\/h2>\n\n\n\n<p>Let\u2019s start off by creating a React project using&nbsp;<code>create-react-app<\/code>. Open your terminal and run the following command:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>npx create-react-app nft-collectible-frontend\n<\/code><\/pre>\n\n\n\n<p>The installation process will take anywhere between 2\u201310 minutes. Once its done, check that everything is working by running the following:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>cd nft-collectible-frontend\nnpm start\n<\/code><\/pre>\n\n\n\n<p>If all goes well, you should see your browser open a new tab at&nbsp;<a href=\"http:\/\/localhost:3000\/\">localhost:\/\/3000<\/a>&nbsp;with the following screen. Pretty standard React stuff.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--KzE6TvWC--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/dev-to-uploads.s3.amazonaws.com\/uploads\/articles\/byzvf3q49ybu6awir1f2.png\"><img src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--KzE6TvWC--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/dev-to-uploads.s3.amazonaws.com\/uploads\/articles\/byzvf3q49ybu6awir1f2.png\" alt=\"React starter website\"\/><\/a><\/figure>\n\n\n\n<p>Let\u2019s do a little cleanup now.<\/p>\n\n\n\n<p>Go to&nbsp;<code>public\/index.html<\/code>&nbsp;and change the title and meta description of your website. This step is optional.<\/p>\n\n\n\n<p>Next, go to the src folder and delete the&nbsp;<code>App.test.js<\/code>,&nbsp;<code>logo.svg<\/code>, and&nbsp;<code>setupTests.js<\/code>&nbsp;files. We will not be needing these files for this tutorial.<\/p>\n\n\n\n<p>Go to the&nbsp;<code>App.js<\/code>&nbsp;file and replace its contents with the following boilerplate.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import '.\/App.css';\n\nfunction App() {\n    return (\n        &lt;h1&gt;Hello World&lt;\/h1&gt;\n    );\n}\n\nexport default App;\n<\/code><\/pre>\n\n\n\n<p>Remove all the contents of&nbsp;<code>App.css<\/code>&nbsp;as well. Do not, however, delete this file. In a later section, we will provide you with some basic styling that should be good enough for this demo project.<\/p>\n\n\n\n<p>If you go back to localhost, you should see a screen that says&nbsp;<strong>Hello World<\/strong>. We now have a basic react project set up and good to go.<\/p>\n\n\n\n<h2><a href=\"https:\/\/dev.to\/rounakbanik\/building-a-web3-frontend-with-react-340c#getting-contract-abi-and-address\"><\/a>Getting contract ABI and address<\/h2>\n\n\n\n<p>For our React frontend to be able to connect and communicate with our smart contract, it needs the contract\u2019s ABI and address.<\/p>\n\n\n\n<p>ABI (or Application Binary Interface) is a JSON file that is automatically generated during contract compilation. The blockchain we deploy to stores our smart contract in the form of bytecode. In order to invoke functions on it, pass the correct parameters, and parse return values using a high-level language, we need to specify details about the functions and the contract (such as name, arguments, types, etc.) to our frontend. This is exactly what the ABI file does. In order to learn more about the ABI, we suggest you go through&nbsp;<a href=\"https:\/\/www.quicknode.com\/guides\/solidity\/what-is-an-abi\">this excellent post<\/a>.<\/p>\n\n\n\n<p>To find your ABI file, go to your hardhat project and navigate to&nbsp;<code>artifacts\/contracts\/NFTCollectible.sol\/NFTCollectible.json<\/code>.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--xN-SOV-F--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/dev-to-uploads.s3.amazonaws.com\/uploads\/articles\/ymm08q5ufrxk368ayon3.png\"><img src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--xN-SOV-F--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/dev-to-uploads.s3.amazonaws.com\/uploads\/articles\/ymm08q5ufrxk368ayon3.png\" alt=\"Folder tree\"\/><\/a><\/figure>\n\n\n\n<p>We need to now copy the JSON file to our React project. Create a new folder called&nbsp;<code>contracts<\/code>&nbsp;in the&nbsp;<code>src<\/code>&nbsp;folder and paste the&nbsp;<code>NFTCollectible.json<\/code>&nbsp;file.<\/p>\n\n\n\n<p>You should already have the address of your deployed smart contract. (If you don\u2019t just deploy it to Rinkeby again, and get the latest address and ABI file).<\/p>\n\n\n\n<p>Our contract address from the previous tutorial is 0x355638a4eCcb777794257f22f50c289d4189F245. We will be using this contract in this tutorial too.<\/p>\n\n\n\n<p>Let us now import the contract ABI and define the contract address in the&nbsp;<code>App.js<\/code>&nbsp;file.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--pD7SzVQ5--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/dev-to-uploads.s3.amazonaws.com\/uploads\/articles\/hqetfa7sb4rkslu3df5y.png\"><img src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--pD7SzVQ5--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/dev-to-uploads.s3.amazonaws.com\/uploads\/articles\/hqetfa7sb4rkslu3df5y.png\" alt=\"App.js\"\/><\/a><\/figure>\n\n\n\n<h2><a href=\"https:\/\/dev.to\/rounakbanik\/building-a-web3-frontend-with-react-340c#setting-up-boilerplate-html-css-and-js\"><\/a>Setting up boilerplate HTML, CSS, and JS<\/h2>\n\n\n\n<p>Our website is going to be incredibly simple. All it will have is a heading and a&nbsp;<em>Connect Wallet<\/em>&nbsp;button. Once the wallet is connected, the&nbsp;<em>Connect Wallet<\/em>&nbsp;button will be replaced by a&nbsp;<em>Mint NFT<\/em>&nbsp;button.<\/p>\n\n\n\n<p>We\u2019re not going to bother with creating separate component files. Instead, we will write all our HTML and logic in&nbsp;<code>App.js<\/code>&nbsp;and all our CSS in&nbsp;<code>App.css<\/code><\/p>\n\n\n\n<p>Copy the contents of the following Github gist into your&nbsp;<code>App.js<\/code>&nbsp;file.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import { useEffect } from 'react';\nimport '.\/App.css';\nimport contract from '.\/contracts\/NFTCollectible.json';\n\nconst contractAddress = \"0x355638a4eCcb777794257f22f50c289d4189F245\";\nconst abi = contract.abi;\n\nfunction App() {\n\n  const checkWalletIsConnected = () =&gt; { }\n\n  const connectWalletHandler = () =&gt; { }\n\n  const mintNftHandler = () =&gt; { }\n\n  const connectWalletButton = () =&gt; {\n    return (\n      &lt;button onClick={connectWalletHandler} className='cta-button connect-wallet-button'&gt;\n        Connect Wallet\n      &lt;\/button&gt;\n    )\n  }\n\n  const mintNftButton = () =&gt; {\n    return (\n      &lt;button onClick={mintNftHandler} className='cta-button mint-nft-button'&gt;\n        Mint NFT\n      &lt;\/button&gt;\n    )\n  }\n\n  useEffect(() =&gt; {\n    checkWalletIsConnected();\n  }, &#91;])\n\n  return (\n    &lt;div className='main-app'&gt;\n      &lt;h1&gt;Scrappy Squirrels Tutorial&lt;\/h1&gt;\n      &lt;div&gt;\n        {connectWalletButton()}\n      &lt;\/div&gt;\n    &lt;\/div&gt;\n  )\n}\n\nexport default App;\n<\/code><\/pre>\n\n\n\n<p>(Remember to set the correct contract address on line 5)<\/p>\n\n\n\n<p>Notice that we have defined a few functions for you which do not do a lot at the moment. We will be explaining their purpose and populating them with logic as we proceed with this tutorial.<\/p>\n\n\n\n<p>We have a small amount of CSS for you to use too. Copy the following into your&nbsp;<code>App.css<\/code>&nbsp;file.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>.main-app {\n    text-align: center;\n    margin: 100px;\n}\n\n.cta-button {\n    padding: 15px;\n    border: none;\n    border-radius: 12px;\n    min-width: 250px;\n    color: white;\n    font-size: 18px;\n    cursor: pointer;\n}\n\n.connect-wallet-button {\n    background: rgb(32, 129, 226);\n}\n\n.mint-nft-button {\n    background: orange;\n}\n<\/code><\/pre>\n\n\n\n<p>Your website should now look like this:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--HaNYVeqm--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/dev-to-uploads.s3.amazonaws.com\/uploads\/articles\/fzmmz65rhjqngyjk1tpx.png\"><img src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--HaNYVeqm--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/dev-to-uploads.s3.amazonaws.com\/uploads\/articles\/fzmmz65rhjqngyjk1tpx.png\" alt=\"Frontend\"\/><\/a><\/figure>\n\n\n\n<p>Feel free to customize the look of the website by adding more styles and static elements (images, header, footer, social media links, etc.).<\/p>\n\n\n\n<p>We\u2019ve put together most of the foundational blocks of the project. We are now in a good position to tackle one of the first major objectives of this tutorial: allowing a user to connect their wallet to our website.<\/p>\n\n\n\n<h2><a href=\"https:\/\/dev.to\/rounakbanik\/building-a-web3-frontend-with-react-340c#connecting-metamask-wallet\"><\/a>Connecting Metamask Wallet<\/h2>\n\n\n\n<figure class=\"wp-block-image\"><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--2BKxC6TA--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/dev-to-uploads.s3.amazonaws.com\/uploads\/articles\/oamoap1p2sblkrlbqtoe.png\"><img src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--2BKxC6TA--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/dev-to-uploads.s3.amazonaws.com\/uploads\/articles\/oamoap1p2sblkrlbqtoe.png\" alt=\"Metamask\"\/><\/a><\/figure>\n\n\n\n<p>For a user to call functions from our contract, they need to be able to connect their wallet to our website. The wallet will enable the user to pay gas and the sale price in order to mint an NFT from our collection.<\/p>\n\n\n\n<p>In this tutorial, we will be working exclusively with the Metamask wallet and its suite of APIs. Off-the-shelf solutions like&nbsp;<a href=\"https:\/\/moralis.io\/\">Moralis<\/a>&nbsp;and&nbsp;<a href=\"https:\/\/www.npmjs.com\/package\/web3modal\">web3modal<\/a>&nbsp;exist that allow you to add support for multiple wallets with very few lines of code. But for this project, we will focus on implementing connect wallet functionality from scratch. We will cover solutions like Moralis in a later tutorial.<\/p>\n\n\n\n<p>We assume you already have the Metamask wallet extension installed in your browser. If you do, Metamask injects an&nbsp;<code>ethereum<\/code>&nbsp;object into your browser\u2019s global&nbsp;<code>window<\/code>&nbsp;object. We will be accessing&nbsp;<code>window.ethereum<\/code>&nbsp;to perform the bulk of our functionality.<\/p>\n\n\n\n<h3><a href=\"https:\/\/dev.to\/rounakbanik\/building-a-web3-frontend-with-react-340c#checking-if-metamask-wallet-exists\"><\/a>Checking if Metamask Wallet Exists<\/h3>\n\n\n\n<p>A user cannot mint NFTs on our website unless they have a Metamask wallet. Let\u2019s populate the&nbsp;<code>checkWalletIsConnected<\/code>&nbsp;function within the&nbsp;<code>App<\/code>&nbsp;component that checks if the Metamask wallet exists.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--q2pKDjBM--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/dev-to-uploads.s3.amazonaws.com\/uploads\/articles\/9x3wluw6nofif4bu3z4o.png\"><img src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--q2pKDjBM--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/dev-to-uploads.s3.amazonaws.com\/uploads\/articles\/9x3wluw6nofif4bu3z4o.png\" alt=\"Code\"\/><\/a><\/figure>\n\n\n\n<p>Note that we have also defined the&nbsp;<code>useEffect<\/code>&nbsp;hook that checks Metamask\u2019s existence when the App component loads.<\/p>\n\n\n\n<p>Open the console on your app\u2019s localhost page. If you have Metamask installed, you should see a message that says&nbsp;<em>Wallet exists! We\u2019re ready to go!<\/em><\/p>\n\n\n\n<figure class=\"wp-block-image\"><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--nXK_ZLvR--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/dev-to-uploads.s3.amazonaws.com\/uploads\/articles\/rjglm085ox31okd3gn7r.png\"><img src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--nXK_ZLvR--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/dev-to-uploads.s3.amazonaws.com\/uploads\/articles\/rjglm085ox31okd3gn7r.png\" alt=\"Browser console output\"\/><\/a><\/figure>\n\n\n\n<h3><a href=\"https:\/\/dev.to\/rounakbanik\/building-a-web3-frontend-with-react-340c#connecting-metamask-programmatically\"><\/a>Connecting Metamask Programmatically<\/h3>\n\n\n\n<p>Just because we have the Metamask extension installed doesn\u2019t mean that Metamask will automatically connect to every website we visit. We need to prompt Metamask to ask the user to do so.<\/p>\n\n\n\n<p>This is where the&nbsp;<em>Connect Wallet<\/em>&nbsp;functionality comes in. It is the web3 equivalent of a login button. It allows the user to connect and send contract function call requests through the website frontend.<\/p>\n\n\n\n<p>Metamask makes this process remarkably simple with the&nbsp;<code>window.ethereum.request<\/code>&nbsp;method.<\/p>\n\n\n\n<p>Let\u2019s first define a variable in&nbsp;<code>App()<\/code>&nbsp;with the useState hook that will keep track of the user\u2019s wallet address. (Don\u2019t forget to import&nbsp;<code>useState<\/code>&nbsp;from React!)<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>const &#91;currentAccount, setCurrentAccount] = useState(null);\n<\/code><\/pre>\n\n\n\n<p>Now, let\u2019s define the&nbsp;<code>connectWalletHandler<\/code>&nbsp;function.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--CtNJghcS--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/dev-to-uploads.s3.amazonaws.com\/uploads\/articles\/wtg2cpe30pfp7fqc14a5.png\"><img src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--CtNJghcS--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/dev-to-uploads.s3.amazonaws.com\/uploads\/articles\/wtg2cpe30pfp7fqc14a5.png\" alt=\"Code\"\/><\/a><\/figure>\n\n\n\n<p>Let\u2019s briefly go through what this function does.<\/p>\n\n\n\n<ol><li>It checks if you have Metamask installed. If not, the website displays a pop-up asking you to install Metamask.<\/li><li>It requests Metamask for the user\u2019s wallet addresses.<\/li><li>Once the user has consented to connect with the website, it takes the first wallet address that is available and sets it as the value of the currentAccount variable.<\/li><li>If something goes wrong (such as the user refusing to connect), it fails and prints an error message to the console.<\/li><\/ol>\n\n\n\n<p>At the moment, if you open the Metamask extension on your website, it will tell you that you\u2019re not connected.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--pJYrqNX1--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/dev-to-uploads.s3.amazonaws.com\/uploads\/articles\/6icgk9022dyqtu0pqel5.png\"><img src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--pJYrqNX1--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/dev-to-uploads.s3.amazonaws.com\/uploads\/articles\/6icgk9022dyqtu0pqel5.png\" alt=\"Metamask wallet\"\/><\/a><\/figure>\n\n\n\n<p>It is now time for the moment of truth. Click on the&nbsp;<em>Connect Wallet<\/em>&nbsp;button on your website. Metamask will prompt you to connect with the website. Once you agree to do so, your extension screen will look like this.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--RyGmFruT--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/dev-to-uploads.s3.amazonaws.com\/uploads\/articles\/d3o1csu71wxdsv9rt01u.png\"><img src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--RyGmFruT--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/dev-to-uploads.s3.amazonaws.com\/uploads\/articles\/d3o1csu71wxdsv9rt01u.png\" alt=\"Metamask wallet\"\/><\/a><\/figure>\n\n\n\n<p>Congratulations! We have successfully connected our wallet to our website.<\/p>\n\n\n\n<p>Once the wallet is connected, we should ideally replace the&nbsp;<em>Connect Wallet<\/em>&nbsp;button with a&nbsp;<em>Mint NFT<\/em>&nbsp;button. In the return value of App , let\u2019s replace the render of a&nbsp;<em>Connect Wallet<\/em>&nbsp;button with a conditional render.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>{currentAccount ? mintNftButton() : connectWalletButton()}\n<\/code><\/pre>\n\n\n\n<p>Our website should now look like this:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--AqcyLsa6--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/dev-to-uploads.s3.amazonaws.com\/uploads\/articles\/bqp00nwj98isz0u59w1m.png\"><img src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--AqcyLsa6--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/dev-to-uploads.s3.amazonaws.com\/uploads\/articles\/bqp00nwj98isz0u59w1m.png\" alt=\"Mint NFT\"\/><\/a><\/figure>\n\n\n\n<p>Let\u2019s refresh our page and check our extension. You will see that Metamask tells us that we are still connected to the website but our website still displays a&nbsp;<em>Connect Wallet<\/em>&nbsp;button.<\/p>\n\n\n\n<p>If you\u2019re familiar with React, it should be obvious why this is happening. After all, we are setting the&nbsp;<code>currentAccount<\/code>&nbsp;state only within the&nbsp;<code>connectWallet<\/code>&nbsp;function.<\/p>\n\n\n\n<p>Ideally what should happen is that the website should check if the wallet is connected every time the&nbsp;<code>App<\/code>&nbsp;component is loaded (i.e every time we refresh).<\/p>\n\n\n\n<p>Let us extend the&nbsp;<code>checkWalletIsConnected<\/code>&nbsp;function to check for accounts as soon as the website is loaded and set currentAccount if the wallet has already been connected.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--IMmNlPTi--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/dev-to-uploads.s3.amazonaws.com\/uploads\/articles\/fhy8d4qtxpt6o2v12nmk.png\"><img src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--IMmNlPTi--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/dev-to-uploads.s3.amazonaws.com\/uploads\/articles\/fhy8d4qtxpt6o2v12nmk.png\" alt=\"Code\"\/><\/a><\/figure>\n\n\n\n<p>(Note that we have marked this function async ). Let\u2019s briefly touch upon what this function does:<\/p>\n\n\n\n<ol><li>It checks if Metamask is installed and outputs result to the console.<\/li><li>It attempts to request Metamask for accounts that are connected.<\/li><li>If Metamask is already connected, it obliges by giving the function a list of accounts. If not, an empty list is returned.<\/li><li>If the list is not empty, the function picks the first account sent over by Metamask and sets it as the current account.<\/li><\/ol>\n\n\n\n<p>If you now refresh the page, you will see that the website indeed displays the&nbsp;<em>Mint NFT<\/em>&nbsp;button as it should.<\/p>\n\n\n\n<h2><a href=\"https:\/\/dev.to\/rounakbanik\/building-a-web3-frontend-with-react-340c#mint-nfts-from-the-website\"><\/a>Mint NFTs from the website<\/h2>\n\n\n\n<p>Let us now implement the core functionality of our website. When a user clicks on the&nbsp;<em>Mint NFT<\/em>&nbsp;button, we expect the following to happen:<\/p>\n\n\n\n<ol><li>Metamask prompts the user to pay the NFT\u2019s price + gas.<\/li><li>Once the user accepts, Metamask calls the mintNFT function of our contract on behalf of the user.<\/li><li>It notifies the user about the success\/failure of the transaction once it is complete.<\/li><\/ol>\n\n\n\n<p>To do this, we will require the&nbsp;<code>ethers<\/code>&nbsp;library from our smart contract project. In your terminal, run the following command:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>npm install ethers\n<\/code><\/pre>\n\n\n\n<p>Let us import this library in&nbsp;<code>App.js<\/code>.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import { ethers } from 'ethers';\n<\/code><\/pre>\n\n\n\n<p>Finally, let\u2019s populate the&nbsp;<code>mintNftHandler<\/code>&nbsp;function.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--e8sjM8vG--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/dev-to-uploads.s3.amazonaws.com\/uploads\/articles\/so14774uc0dxqqxyiu53.png\"><img src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--e8sjM8vG--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/dev-to-uploads.s3.amazonaws.com\/uploads\/articles\/so14774uc0dxqqxyiu53.png\" alt=\"Code\"\/><\/a><\/figure>\n\n\n\n<p>(Don\u2019t forget to mark this function as&nbsp;<code>async<\/code>)<\/p>\n\n\n\n<p>As usual, let\u2019s touch upon what this function does.<\/p>\n\n\n\n<ol><li>It tries to access the ethereum object injected by Metamask.<\/li><li>If ethereum exists, it sets Metamask as the RPC provider. This means that you will be issuing requests to the miners using your Metamask wallet.<\/li><li>To issue requests, the user will need to sign transactions using their private key. We access signer for this purpose.<\/li><li>We then initiate an ethers Contract instance using the deployed contract\u2019s address, the contract ABI, and the signer.<\/li><li>We can now call functions on our contract through the aforementioned contract object. We call the mintNFT function and ask Metamask to send 0.01 ETH (which is the price we set for our NFT).<\/li><li>We wait for the transaction to be processed and once it\u2019s done, we output the transaction hash to the console.<\/li><li>If anything fails (the wrong function called, wrong parameters passed, &lt; 0.01 ETH sent, user rejected transaction, etc.), an error is printed to the console.<\/li><\/ol>\n\n\n\n<p>On your website, open your browser\u2019s console so that you are able to view the mining status in real-time.<\/p>\n\n\n\n<p>Now, click on the&nbsp;<em>Mint NFT<\/em>&nbsp;button. Metamask will prompt you to pay 0.01 ETH + gas. The transaction will take approximately 15\u201320 seconds to process. Once it\u2019s done, the transaction will be confirmed both by a Metamask popup and the console output.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--p4EGl3U8--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/dev-to-uploads.s3.amazonaws.com\/uploads\/articles\/mm6i8q7wbxfe8gu23272.png\"><img src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--p4EGl3U8--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/dev-to-uploads.s3.amazonaws.com\/uploads\/articles\/mm6i8q7wbxfe8gu23272.png\" alt=\"Website + Console\"\/><\/a><\/figure>\n\n\n\n<p>You can now view the NFT on Opensea too.&nbsp;<a href=\"https:\/\/testnets.opensea.io\/account\">Navigate to your account on testnets.opensea.io<\/a>&nbsp;and you should be able to see your latest NFT.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--jCRcVXj6--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/dev-to-uploads.s3.amazonaws.com\/uploads\/articles\/fesdcf1u9h7rg96zj06u.png\"><img src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--jCRcVXj6--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/dev-to-uploads.s3.amazonaws.com\/uploads\/articles\/fesdcf1u9h7rg96zj06u.png\" alt=\"Scrappy Squirrel\"\/><\/a><\/figure>\n\n\n\n<h2><a href=\"https:\/\/dev.to\/rounakbanik\/building-a-web3-frontend-with-react-340c#ux-improvements-amp-conclusion\"><\/a>UX Improvements &amp; Conclusion<\/h2>\n\n\n\n<p>Congratulations! You now have a fully functioning web3 frontend that users can mint NFTs from.<\/p>\n\n\n\n<p>However, as you may have noticed, the UX of the website leaves a lot to be desired. Here are a few improvements that you should consider doing.<\/p>\n\n\n\n<h3><a href=\"https:\/\/dev.to\/rounakbanik\/building-a-web3-frontend-with-react-340c#ensure-the-user-is-connected-to-the-right-network\"><\/a>Ensure the user is connected to the right network<\/h3>\n\n\n\n<p>Our website assumes that the user is connected to the Rinkeby Network when interacting with our website. This may not always be the case.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--PlI0inJ1--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/dev-to-uploads.s3.amazonaws.com\/uploads\/articles\/j3u7n2dz3oclm6bmfzkx.png\"><img src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--PlI0inJ1--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/dev-to-uploads.s3.amazonaws.com\/uploads\/articles\/j3u7n2dz3oclm6bmfzkx.png\" alt=\"Change network banner\"\/><\/a><\/figure>\n\n\n\n<p>Can you implement functionality that gently alerts the user if s\/he is not connected to Rinkeby (like OpenSea does)? Also, ensure that the user is not able to see the&nbsp;<em>Mint NFT<\/em>&nbsp;button when connected to the wrong network.<\/p>\n\n\n\n<h3><a href=\"https:\/\/dev.to\/rounakbanik\/building-a-web3-frontend-with-react-340c#show-transaction-status\"><\/a>Show transaction status<\/h3>\n\n\n\n<p>Currently, our website prints the transaction status onto the console. In a real project, you cannot really expect your users to open their console while interacting with the website.<\/p>\n\n\n\n<p>Can you implement state which tracks the transaction status and gives feedback to the user in real-time? It should show a loader when the transaction is processing, notify the user if the transaction has failed, and display the transaction hash\/Opensea link if the transaction has succeeded.<\/p>\n\n\n\n<h3><a href=\"https:\/\/dev.to\/rounakbanik\/building-a-web3-frontend-with-react-340c#prompt-metamask-even-if-funds-are-nonexistent\"><\/a>Prompt Metamask even if funds are non-existent<\/h3>\n\n\n\n<p>If you do not have any ETH in your Metamask wallet, clicking on Mint NFT will not prompt Metamask at all. In fact, the user will receive no feedback.<\/p>\n\n\n\n<p>Can you ensure that Metamask is prompted even when the user has insufficient funds? It should ideally be Metamask that informs the user how much ETH is required and how much s\/he is short by.<\/p>\n\n\n\n<h3><a href=\"https:\/\/dev.to\/rounakbanik\/building-a-web3-frontend-with-react-340c#other-quality-of-life-changes\"><\/a>Other Quality of life changes<\/h3>\n\n\n\n<p>Here are a few other quality of life changes that you can consider.<\/p>\n\n\n\n<ol><li>Allow users to mint more than 1 NFT at a time.<\/li><li>Add a few sample artworks from your NFT collection.<\/li><li>Add a link to your collection on Opensea.<\/li><li>Add the verified smart contract address so people can double-check what\u2019s really happening behind the scenes.<\/li><li>Add links to your Twitter, IG, and Discord.<\/li><\/ol>\n\n\n\n<figure class=\"wp-block-image\"><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--3Q580jZI--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/dev-to-uploads.s3.amazonaws.com\/uploads\/articles\/825l21hl7cy0ms8x8zs7.png\"><img src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--3Q580jZI--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/dev-to-uploads.s3.amazonaws.com\/uploads\/articles\/825l21hl7cy0ms8x8zs7.png\" alt=\"Rinkeby Squirrels\"\/><\/a><\/figure>\n\n\n\n<p>Our NFT sandbox project,&nbsp;<a href=\"https:\/\/medium.com\/scrappy-squirrels\/getting-started-with-nft-collectibles-communities-for-free-24bab021a97\">Rinkeby Squirrels<\/a>, implements a majority of the UX upgrades mentioned here.&nbsp;<a href=\"https:\/\/rsq-frontend.vercel.app\/\">Try and mint one here<\/a>&nbsp;and see if you can notice the difference between it and the website we built.<\/p>\n\n\n\n<p>We will be launching future tutorials showing you how to implement a few of these upgrades. But we really suggest you try doing this yourself. You\u2019ll be one step closer to becoming a web3 frontend master.<\/p>\n\n\n\n<p>If you have any questions or are stuck, reach out to us on our&nbsp;<a href=\"https:\/\/discord.gg\/8UqJXTX7Kd\">Discord<\/a>.<\/p>\n\n\n\n<p>If you don\u2019t have questions, come say hi to us on our&nbsp;<a href=\"https:\/\/discord.gg\/8UqJXTX7Kd\">Discord<\/a>&nbsp;anyway! Also, if you liked our content, we would be super grateful if you tweet about us, follow us(@ScrappyNFTs and @Rounak_Banik), and invite your circle to our Discord. Thank you for your support!<\/p>\n\n\n\n<p>Final code repository:&nbsp;<a href=\"https:\/\/github.com\/rounakbanik\/nft-collectible-frontend\">https:\/\/github.com\/rounakbanik\/nft-collectible-frontend<\/a><\/p>\n\n\n\n<h3><a href=\"https:\/\/dev.to\/rounakbanik\/building-a-web3-frontend-with-react-340c#about-scrappy-squirrels\"><\/a><em>About Scrappy Squirrels<\/em><\/h3>\n\n\n\n<p><a href=\"https:\/\/www.scrappysquirrels.co\/\">Scrappy Squirrels<\/a>&nbsp;is a collection of 10,000+ randomly generated NFTs. Scrappy Squirrels are meant for buyers, creators, and developers who are completely new to the NFT ecosystem.<\/p>\n\n\n\n<p>The community is built around learning about the NFT revolution, exploring its current use cases, discovering new applications, and finding members to collaborate on exciting projects with.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Introduction In a&nbsp;previous tutorial, we covered how to create and deploy an NFT collectible smart contract from scratch. We also explored how to verify our contract on etherscan and enable yourself as well as your users to call functions directly from the contract\u2019s etherscan page.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[178],"tags":[65],"_links":{"self":[{"href":"https:\/\/lvboard.infostore.in.ua\/index.php?rest_route=\/wp\/v2\/posts\/2238"}],"collection":[{"href":"https:\/\/lvboard.infostore.in.ua\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/lvboard.infostore.in.ua\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/lvboard.infostore.in.ua\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/lvboard.infostore.in.ua\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2238"}],"version-history":[{"count":1,"href":"https:\/\/lvboard.infostore.in.ua\/index.php?rest_route=\/wp\/v2\/posts\/2238\/revisions"}],"predecessor-version":[{"id":2239,"href":"https:\/\/lvboard.infostore.in.ua\/index.php?rest_route=\/wp\/v2\/posts\/2238\/revisions\/2239"}],"wp:attachment":[{"href":"https:\/\/lvboard.infostore.in.ua\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2238"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/lvboard.infostore.in.ua\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2238"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/lvboard.infostore.in.ua\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2238"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}