How to Sell Coupons on ETH? Web3.js and Connect Frontend with Metamask (3/4)

How to Sell Coupons on ETH? Creating your own sample dApp in four parts:


Welcome to the front-end journey for the Finxter coupon Dapp.

πŸ›‘ Note: This is just a training “fun” dApp that shows you how to use React, Truffle, and Solidity. It is not a real dApp with real functionality!

Imaginary Scenario: Finxter academy has recently announced that it will launch some coupons with a 25% discount for its new premium membership, and the coupons will be distributed through a decentralized blockchain.

In this part, We will bring our codes into visualization with the help of React and Tailwind CSS.

Install React & Tailwind CSS

First, I am creating a directory coupon_frontend where all our React code will lie.

Let’s move to the coupon_dapp directory through the command prompt and type

npx create-react-app coupon_frontend

npx will create a react app for you, but we need to install tailwind CSS before initializing the app. Move to the app directory and command

cd coupon_frontend
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p

All the peer dependencies will be installed inside the tailwind.config.js file in the VS Code. To configure the template paths, enter the tailwind.config.js file and change the content section inside the β€˜module.exports’.

module.exports = {
  content: [
    "./src/**/*.{js,jsx,ts,tsx}",
  ],
}

Now open the index.css folder inside the source file and copy the directives to finish the tailwind setup process.

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

Now back to the command prompt and initialize React

npm start

You are doing fine if you see the React logo running on port 3000 of your browser. Move to the app.js file inside the source folder and remove the code inside the return function. We will write new code here.

Create a Navbar for the Dapp

Let’s make a components folder where we will create different functional components inside the folder.

We need a navbar to make our web page looks nice. So create a navbar component inside the components folder, name it navbar.js and to style the navbar, we need navbar.css.

Let’s create a simple navbar. Type some code inside the return function.

return (
    <div className=" bg-slate-800 my-0 py-2">
      <nav className="2xl:container 2xl:mx-auto sm:py-6 sm:px-7 py-5 px-4">
        <h1 className=" font-extrabold font-sans text-teal-400 text-5xl text-center leading-6 text-gray-800">
          FINXTER PREMIUM
        </h1>
      </nav>
    </div>
  );

We must import this navbar component to the app.js to display it on the user interface.

import Navbar from "./components/navbar/Navbar";

Initialize web3.js

To connect our front end with Metamask, we need to install web3.js that provides us with many inbuilt methods that help us connect with Metamask or any Ethereum-based blockchain.

To the terminal, command

npm install --save web3

To confirm if the dependencies are installed correctly, visit the “package.json” file, where you can see the version number of web3.

Then import web3 to the app.js file

import Web3 from "web3";

We will create a connect button that will allow us to connect to Metamask when clicked.

We need to import the JSON format of the contract to get the account address and access the methods from the ABI.

To show the account address to the UI, we need to bring the JSON file inside the source folder of React.

We can do it in several ways. I am following the simplest way; I am just bringing a copy of the Coupons.json file from the build/contract folder to the source folder.

Now import the configuration file on app.js

import configuration from "../../Coupons.json";

Now, as we imported an instance of our contract, we can get the address and the ABI from that, also.

const contractAddress = configuration.networks["5777"].address;
const contractABI = configuration.abi;

By default, the truffle will target its own network that we can run locally.

But as we have decided to use another local network like Ganache, we can configure it by adding it to the configuration file’s networks section. 5777 is the network id of the ganache network.

You may not get the correct contract address if connected to another network.

Let’s initialize a web3 instance.

const web3 = new Web3(Web3.givenProvider || "http://127.0.0.1:7545");

We are basically setting up a web3 connection with the local host or using the given provider if there is one.

We can use our web3 now to connect to the contract.

const contract = new web3.eth.Contract(contractABI, contractAddress);

Web3.eth.contract object helps us to interact with the smart contracts on the Ethereum blockchain. It will take the ABI and address from the JSON interface, and auto-convert all calls into low-level ABI calls over Remote Procedure Calls (RPC).

🌍 Reference: Web3js

Now we will be able to call our required methods from the contract. Soon we will see it.

Connect User interface to Metamask

Before moving forward, we need to know about some crucial functionalities of Metamask.

This Metamask extension automatically injects some methods called “window.Ethereum” on the browser. If our application uses web3-related libraries, we can easily access those methods and further build on them.

We will see the application soon. So don’t worry.

Now, we need to create a button in the UI that will connect us to Metamask. Let’s create a <div> under the navbar. Now create a button and a container for the account address of the buyer’s account. The wallet’s address will be shown in the UI when connected to the wallet.

Let’s apply some styles also at the same time when we proceed. As I am not an expert on front-end design, I always take shortcuts with some tailwind UI kit.

Flowbite is one of the open-source UI libraries that will help us to build a front-end design faster.

Choose a button from their UI components and name the button as

<div className="text-center">
          <button
            type="button"
            onClick={connectWalletHandler}
            className="text-white text-xl bg-gradient-to-r from-teal-400 via-teal-500 to-teal-600 hover:bg-gradient-to-br focus:ring-4 focus:outline-none focus:ring-teal-300 dark:focus:ring-teal-800 font-medium rounded-lg text-sm px-5 py-2.5 text-center mr-2 mb-2"
          >
            Connect to Metamask
          </button>
          <div className="items-center mt-5 py-3 px-4 text-sm font-medium text-center text-white bg-red-500 rounded-lg hover:bg-red-500 focus:ring-4 focus:outline-none focus:ring-blue-300">
            <h3 className="text-2xl">Address: {activeAccount}</h3>
          </div>
        </div>

I have selected a teal colour button from flowbite and added an onclick event handler called connectWalletHandler. When this button gets clicked, the connectWalletHandler function will help us connect to the Metamask.

Below this button, I have created another div that will allow us to show the account address that we are connected to. The address will be displayed on the UI whenever a connection is established with an account.

Our button is visible in the UI, and we need to add some functionalities to the connectWalletHandler event handler to make it work.

const connectWalletHandler = async () => {
    if (window.Ethereum) {
      var web3 = new Web3(window.Ethereum);
      await window.Ethereum.request({ method: "eth_requestAccounts" });
      var accounts = await web3.eth.getAccounts();
      const myAccount = accounts[0];
      setActiveAccount(myAccount);
    } else {
      console.log("Need to install MetaMask");
      setErrorMessage("Please install MetaMask browser extension to interact");
    }
  };

We have created a fat arrow function with async await functionalities. We established an if else condition inside this connectWallethandler. It makes sure that the front end is connected to the Metamask.

If the Metamask is connected, then the event handler will perform certain operations; if it is not connected, it will throw an error message to the viewer.

We are instructing the event handler that if the Metamask is connected to the front end, you create an instance of web3 and establish a connection to the account with the ‘eth_requestAccounts’ method.

The recommended way to connect to MetaMask is with “Ethereum.request()” method. The function takes an object with a JSON-RPC method (like eth_requestAccounts) and returns a Promise.

🌍 Reference: Stackexchange

We Created an accounts variable that will gather all the accounts of the Ganache with “web3.eth.getAccounts()” method.

The myAccount variable will take the first account of the Ganache.

We need to declare a state variable outside the event handler to show our account address to the UI. useState hook of React would be helpful here.

Import useState from React.

import React, { useState } from "react";

Now create a state variable to store the value of the active account address.

const [activeAccount, setActiveAccount] = useState(null);

Inside the connectWalletHandler event handler, we set the active account as our myAccount. We have already created a dynamic variable inside the h3 heading to show this active account address to the UI.

We will create another state variable to store the error message.

const [errorMessage, setErrorMessage] = useState(null);

If the event handler fails to connect to Metamask, it will throw an error message. We have already set the error message inside the connectWalletHandler.

If everything works fine, whenever you click on the connect to Metamask button, you will get the account address of the active wallet address on the UI. Make sure the ganache app runs in the background and the local host ganache is connected to Metamask. Otherwise, you will encounter some error message.

Metamask extension will pop up only once if the Metamask is not connected to the UI. Once the connection is established, the Metamask extension will no longer pop up if you click the connect to Metamask button again.

To verify if we are getting the correct account address, let’s copy the private key of any account from Ganache. Create a new account with this private key by clicking on the import account button of the Metamask extension. Make sure this account is connected to the UI. If the address shown in the UI matches the newly imported account, it proves that our app is working perfectly fine.

Part 3 Done!

It concludes the 3rd part of the series. We have successfully connected the Metamask with our front-end. In the next part, you will see how the smart contract interacts with the front end. Thanks for being with me.

You can get the code from GitHub.

Here are all links to this 4-part code project to create a sample dApp on ETH for selling virtualized coupon codes: