How to Sell Coupons on ETH? Creating your own sample dApp in four parts:
- Part 1: A Sample Solidity dApp with React and Truffle
- Part 2: Build, Deploy and Test the Smart Contract
- π Part 3: Web3.js and Connect Frontend with Metamask
- Part 4: Integrate Frontend with Smart Contract
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.contrac
t 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: