Create a web3 front end using React

Introduction

This tutorial will show you how to:

  1. Let users connect their Metamask wallets to the website
  2. Allows users to call a contract function, make a payment, and mint an NFT.

By the end of this tutorial, you will have a fully functional web3 frontend built with React. You'll also get the basics needed to build any generic web3 frontend (except NFT minter).

premise

This tutorial assumes that you have developed and deployed a smart contract to the Rinkeby test network. If you haven't already, we highly recommend you go through this tutorial . In order to continue with this tutorial, you will need the following.

  1. ABI file for the smart contract (found in your project's artifacts folder).
  2. The address of the smart contract.

We also assume you have some experience with React and Javascript. If not, it is strongly recommended that you take a look at the official tutorial on the React website first .

set item

Let's create-react-appstart by creating a React project using . Open a terminal and run the following command:

npx create-react-app nft-collectible-frontend

The installation process will take 2-10 minutes. Once complete, check that everything is working by running the following command.

cd nft-collectible-frontend
npm start

If all goes well, you should see the browser open a new tab at localhost://3000 with the following screen. Pretty standard React content:

Now let's do some cleanup.

To go in public/index.html, modify the site's title and meta description (this step is optional).

Next, go into the src folder and delete the App.test.js, logo.svgand setupTests.jsfiles. In this tutorial, we will not need these files.

Go into App.jsthe file and replace its contents with the following template.

import './App.css';

function App() {
    return (
        <h1>Hello World</h1>
    );
}

export default App;

App.cssAll content deleted at the same time . However, do not delete this file. In later chapters we'll provide some basic styling, which should be good enough for this demo project.

If you go back to localhost, you should see a screen that says Hello World . We now have a basic react project ready to get started.

Get contract ABI and address

In order for our React frontend to connect and communicate with a smart contract, it needs the contract's ABI and address.

ABI (Application Binary Interface) is a JSON file that is automatically generated during contract compilation. We deploy to the blockchain to store smart contracts in the form of bytecode. In order to call a function on it, pass the correct parameters, and parse the return value using a high-level language, we need to specify details about the function and contract (such as name, parameters, type, etc.) to the front end. This is exactly what the ABI file does. In order to learn more about ABI, I suggest you read: How to understand Ethereum ABI .

To find your ABI file, go into your hardhat project and navigate to artifacts/contracts/NFTCollectible.sol/NFTCollectible.json.

We now need to copy the JSON file to the React project. Inside srcthe folder create a contractsnew folder called and paste NFTCollectible.jsonthe files.

You should already have the address of the deployed smart contract. (If you don't, just deploy it to Rinkeby again and get the latest addresses and ABI files).

Our contract address in the previous tutorial was 0x355638a4eCcb777794257f22f50c289d4189F245. We will also use this contract in this tutorial.

Now let's import the contract ABI and App.jsdefine the contract address in the file.

Set template HTML, CSS and JS

The website will be very simple. It will just have a title and a connect wallet button. Once the wallet is connected, the connect wallet button will be replaced by a Mint NFT button.

We're not going to go to the trouble of creating separate component files. Instead, we'll App.jswrite all the HTML and logic in and App.cssall the CSS in .

Copy the contents of the following Github gist into App.jsthe file.

import { useEffect } from 'react';
import './App.css';
import contract from './contracts/NFTCollectible.json';

const contractAddress = "0x355638a4eCcb777794257f22f50c289d4189F245";
const abi = contract.abi;

function App() {

  const checkWalletIsConnected = () => { }

  const connectWalletHandler = () => { }

  const mintNftHandler = () => { }

  const connectWalletButton = () => {
    return (
      <button onClick={connectWalletHandler} className='cta-button connect-wallet-button'>
        Connect Wallet
      </button>
    )
  }

  const mintNftButton = () => {
    return (
      <button onClick={mintNftHandler} className='cta-button mint-nft-button'>
        Mint NFT
      </button>
    )
  }

  useEffect(() => {
    checkWalletIsConnected();
  }, [])

  return (
    <div className='main-app'>
      <h1>Scrappy Squirrels Tutorial</h1>
      <div>
        {connectWalletButton()}
      </div>
    </div>
  )
}

export default App;

(Remember to set the correct contract address on line 5)

Note that several functions are already defined here, which currently have no effect. We'll explain their purpose below and put logic into it.

Below is the corresponding CSS, copy the following into your App.cssfile.

.main-app {
    text-align: center;
    margin: 100px;
}

.cta-button {
    padding: 15px;
    border: none;
    border-radius: 12px;
    min-width: 250px;
    color: white;
    font-size: 18px;
    cursor: pointer;
}

.connect-wallet-button {
    background: rgb(32, 129, 226);
}

.mint-nft-button {
    background: orange;
}

The site should now look like this:

Feel free to customize the look of your site by adding more styles and static elements (images, headers, footers, social media links, etc.).

We've put together most of the base building blocks for this project. We are now in a good position to tackle one of the first main goals of this tutorial: allowing users to connect their wallets to our website.

Connect Metamask wallet

In order for users to be able to call functions from our contracts, they need to be able to connect their wallets to our website. The wallet will enable users to pay the gas and sale price to mint an NFT from our collection.

In this tutorial, we will exclusively use the Metamask wallet and its set of APIs. There are ready-made solutions like Moralis and web3modal that allow you to add support for multiple wallets with very little code. But in this project, we will focus on implementing the connected wallet functionality from scratch. Solutions like Moralis will be covered in a future tutorial.

We assume you already have the Metamask wallet plugin installed in your browser. If you have, Metamask injects an ethereumobject into your browser's global windowobject. We will access window.ethereumto perform most of our functions.

Check if Metamask wallet exists

Users cannot mint NFTs on our website unless they have a Metamask wallet. Let's Appadd checkWalletIsConnecteda function to the component to check if the Metamask wallet exists.

Note that we also define useEffecthooks that check for the presence of Metamask when the App component loads.

Open the console on your application's localhost page. If you already have Metamask installed, you should see a message saying Wallet exists! We're ready to go! (*Wallet exists!* We're ready to go!).

Programmatically connect to Metamask

Just because we have the Metamask plugin installed, doesn't mean Metamask automatically connects to every website we visit. We need to prompt Metamask to ask the user to do so.

This is where the connected wallet feature comes in. It is equivalent to a login button of web3. It allows users to connect through the website and send requests to invoke contract functions.

Metamask makes it easy to connect via the "window.ethereum.request" method.

Let's first App()define a variable in the useState hook to track the user's wallet address. (don't forget to import from React useState)

const [currentAccount, setCurrentAccount] = useState(null);

Now, let's define connectWalletHandlerthe function.

Let's briefly look at what this function does:

  1. Check if Metamask is installed. If not, the website will display a popup asking to install Metamask.
  2. It requests Metamask to provide the user's wallet address.
  3. Once the user agrees to connect with the website, it will fetch the first available wallet address and use it as the value of the currentAccount variable.
  4. If something goes wrong (such as a user refusing to connect), it will fail and print an error message to the console.

Currently, if you open the Metamask plugin on the website, it says Not conntected.

Now comes the moment, click the **Connect Wallet* button on the website. Metamask will prompt you to connect with the website. Once you agree, the plugin interface will look like this:

congratulations! The wallet has been successfully connected to the website.

Once the wallet is connected, we'd better replace the Connect Wallet button with a Mint NFT button . In the App's return value, let's replace the rendering of the Connect Wallet button with a conditional rendering .

{currentAccount ? mintNftButton() : connectWalletButton()}

The site should now look like this:

Let's refresh the page and check the plugin. You will see that Metamask shows that the website is connected (connected), but the website still shows a button to connect to the wallet .

If you're familiar with React, it should be pretty clear why this happens. After all, we only set the "currentAccount" state in the "connectWallet" function.

Ideally, the website should Appcheck to see if the wallet is connected every time the component loads (i.e. every refresh).

Let's plug in checkWalletIsConnectedthe function to check the account as soon as the site loads, and set the currentAccount if the wallet is already connected.

(Note that this function is marked async). A brief explanation of what this function does:

  1. It checks if Metamask is installed and outputs the result to the console.
  2. It tries to request Metamask for the connected account.
  3. If Metamask is already connected, it will do so by giving the function a list of accounts. Returns an empty list if none.
  4. If the list is not empty, the function will select the first account Metamask fetches and set it as the current account.

If you refresh the page now, you'll see that the website does display the Mint NFT button.

Mint NFT from the website

Now let's implement the core functionality of the site. Here's what we want to happen when a user taps the Mint NFT button.

  1. Metamask prompts users to pay the price of NFT + Gas.
  2. Once the user accepts, Metamask calls the mintNFT function in the contract on behalf of the user.
  3. Once the transaction is completed, it notifies the user of the success/failure of the transaction.

To do this, we will need etherslibraries for contract interaction. In your terminal, run the following command:

npm install ethers

Let's App.jsimport this library in:

import { ethers } from 'ethers';

Finally, let's add mintNftHandlerthe function:

(don't forget to mark this function as "async")

As usual, to explain what this function does:

  1. Attempt to access an object injected by Metamask ethereum.
  2. If ethereumthe object exists, it sets Metamask as the RPC provider. This means, the request will be made to the miner using the Metamask wallet.
  3. In order to make a transaction request, users need to sign the transaction with their private key. So get the signer.
  4. A contract instance is then created with the deployed contract's address, contract ABI, and signer.
  5. Call the function on our contract through the above contract object. Call the mintNFT function and ask Metamask to send 0.01 ETH (this is the price we set for the NFT).
  6. Wait for the transaction to be processed, and once processed, output the transaction hash to the console.
  7. If there is any failure (bad function call, wrong parameter passed, <0.01 ETH sent, user rejected transaction, etc.), the error will be printed to the console.

On the website, open your browser's console so you can see the mining status in real time.

Now, tap the Mint NFT button. Metamask will prompt you to pay 0.01 ETH + gas. The transaction will take about 15-20 seconds to process. Once complete, the transaction can be confirmed via a Metamask popup and console output.

You can now also view the NFT on Opensea. Navigate to your account on testnets.opensea.io and you should see your latest NFT.

UX improvements and conclusions

congratulations! You now have a fully functional web3 frontend through which users can mint NFTs.

However, as you may have noticed, the user experience of the site leaves a lot to be desired. Here are some improvements you should consider making.

Make sure users are connected to the correct network

Our website assumes that users are connected to the Rinkeby network when interacting with the website, which may not always be the case.

Can you implement a way to alert the user when he is not connected to Rinkeby (like OpenSea does)? Also, make sure users can't see the Mint NFT button when they're connected to the wrong network .

show transaction status

Currently, our website prints transaction status to the console. In a real project, you can't expect your users to have their consoles open at the same time as they are interacting with the website.

Can you implement tracking transaction status and real-time feedback to users? It should display a loading prompt (loading) while the transaction is being processed, notify the user if the transaction fails, and display the transaction hash (or Opensea link) if the transaction is successful.

Prompt Metamask even if funds are low

If you don't have any ETH in your Metamask wallet, clicking on the Mint NFT will not prompt Metamask at all. In fact, the user will not receive any feedback.

Can you make sure that Metamask is prompted even if the user has insufficient funds? It would be better for Metamask to inform the user how much ETH is needed and how much he/she is short of.

other improvements

Here are some other improvements you might consider:

  1. Users are allowed to mint more than 1 NFT at a time.
  2. Add some samples of artwork from your NFT collection.
  3. Add a link to information about your collection on Opensea.
  4. Add verified smart contract addresses so people can double-check what's really happening behind the scenes.
  5. Add your Twitter, IG and Discord links.

Our NFT sandbox project, Rinkeby Squirrels , implements most of the UX upgrades mentioned here, and you can try minting one.

Final codebase: https://github.com/rounakbanik/nft-collectible-frontend

About Scrappy Squirrels

Scrappy Squirrels is a collection of over 10,000 randomly generated NFTs. Scrappy Squirrels is for buyers, creators, and developers who are completely new to the NFT ecosystem.

This 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 together.

Join our community here: https://discord.gg/8UqJXTX7Kd

Guess you like

Origin blog.csdn.net/smartContractXH/article/details/126704522