How to Build an Exciting Blockchain Voting System with React, Solidity, and CometChat
Tags: blockchain, web3, react, solidity
Published: 2022-11-24 12:11:23

What you will be building, see the [**demo**](https://bluevotes-22114.web.app/) on the Goerli test network and [**git repo**](https://github.com/Daltonic/bluevotes) here.

![Blockchain Voting System](https://paper-attachments.dropboxusercontent.com/s_F8CFEC13187B2461ACB3333DD930FBFD0382C2061717C82E7C601E673B7954B4_1669037877969_0.gif)

## Introduction

Now, it's time for you to learn the ultimate trick in building a decentralized voting system. In this tutorial, you will learn how to make a blockchain voting application featuring the use of solidity’s Smart Contracts, React frontend designed with Tailwind CSS, and [CometChat SDK.](https://try.cometchat.com/oj0s7hrm5v78)

By the way, [**Subscribe to my YouTube channel**](https://www.youtube.com/@dappmentors?sub_confirmation=1) to learn how to build a Web3 app from scratch. I also offer private and specialized classes for serious folks who want to learn one-on-one from a mentor. [**Book your Web3 classes here**](https://www.buymeacoffee.com/web3classes/e/74614).

If you are ready to crush this build, then let’s get started.


## Prerequisite

You will need the following tools installed to build along with me:

- NodeJs *(Super important)*
- EthersJs
- Hardhat
- React
- Tailwind CSS
- CometChat SDK
- Metamask
- Yarn 


## Installing Dependencies

Have the starter kit below cloned using the command below:


    git clone https://github.com/Daltonic/tailwind_ethers_starter_kit <PROJECT_NAME>
    cd <PROJECT_NAME>

Now, open the project in VS Code or on your preferred code editor. Locate the `package.json` file and update it with the codes below.


{% gist https://gist.github.com/Daltonic/2e08c04a7f4b9a2aebd405fba6bc2f1f %}


Now, run `**yarn install**` on the terminal to have all the dependencies for this project installed.


## Configuring CometChat SDK

Follow the steps below to configure the [**CometChat SDK**](https://try.cometchat.com/oj0s7hrm5v78); at the end, you must save these keys as an environment variable.

**STEP 1:**
Head to [**CometChat**](https://try.cometchat.com/daltonic) Dashboard and create an account.

![Register a new CometChat account if you do not have one](https://res.cloudinary.com/practicaldev/image/fetch/s--1vLWkScm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://assets-global.website-files.com/5f3c19f18169b62a0d0bf387/61700dac76419b7bac2de69d_s_1988D50EEAEE632A7CEA2F32B0824BC13ED61EA41386BA94E99320DDC4403C74_1633934795404_image.png)


**STEP 2:**
Log in to the [**CometChat**](https://try.cometchat.com/daltonic) dashboard, only after registering.

![Log in to the CometChat Dashboard with your created account](https://paper-attachments.dropboxusercontent.com/s_90B53416B7AA7BC8FEE6FA04488E85316C40786902CF7342257FAAC4A53B3554_1666201371382_screenshoteasy+1.png)


**STEP 3:**
From the dashboard, add a new app called **BlueVotes.**

![Create a new CometChat app - Step 1](https://res.cloudinary.com/practicaldev/image/fetch/s--UbyuK5N3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://assets-global.website-files.com/5f3c19f18169b62a0d0bf387/61700dac7e33a881ced79837_s_1988D50EEAEE632A7CEA2F32B0824BC13ED61EA41386BA94E99320DDC4403C74_1633936628018_image.png)

![Create a new CometChat app - Step 2](https://res.cloudinary.com/practicaldev/image/fetch/s--Eh8m9hoJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://assets-global.website-files.com/5f3c19f18169b62a0d0bf387/618ea496d603ba7ef8cabeb3_s_C05E7B93FFC9B007F6C09747840C5EEC81AFEC86C6C89C570966797151AE7076_1635316586805_VLioyzP2.png)


**STEP 4:**
Select the app you just created from the list.

![Select your created app](https://res.cloudinary.com/practicaldev/image/fetch/s--zEUb15p8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://assets-global.website-files.com/5f3c19f18169b62a0d0bf387/618ea4969bad618548da9ccd_s_C05E7B93FFC9B007F6C09747840C5EEC81AFEC86C6C89C570966797151AE7076_1635316654035_bSCncNJN.png)


**STEP 5:**
From the Quick Start copy the `APP_ID`, `REGION`, and `AUTH_KEY`, to your `.env` file. See the image and code snippet.

![Copy the the APP_ID, REGION, and AUTH_KEY](https://res.cloudinary.com/practicaldev/image/fetch/s--vnJudkph--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://assets-global.website-files.com/5f3c19f18169b62a0d0bf387/618ea4968574a3c1945af0bd_s_C05E7B93FFC9B007F6C09747840C5EEC81AFEC86C6C89C570966797151AE7076_1635316757752_QHRb0reB.png)


Replace the `REACT_COMET_CHAT` placeholder keys with their appropriate values.


    REACT_APP_COMET_CHAT_REGION=**
    REACT_APP_COMET_CHAT_APP_ID=**************
    REACT_APP_COMET_CHAT_AUTH_KEY=******************************

The `**.env**` file should be created at the root of your project.

## Configuring Alchemy App

**STEP 1:** Head to [**Alchemy**](https://www.alchemy.com/pricing/?r=f5ecd4315e80b9d9).

![](https://cdn.hackernoon.com/images/-p093utq.png)


**STEP 2:** [Create an account](https://auth.alchemy.com/?r=f5ecd4315e80b9d9).

![Login to Alchemey](https://res.cloudinary.com/practicaldev/image/fetch/s--H-JnhPrD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropboxusercontent.com/s_90B53416B7AA7BC8FEE6FA04488E85316C40786902CF7342257FAAC4A53B3554_1666201253981_screenshoteasy.png)


**STEP 3:**
From the [**dashboard**](https://dashboard.alchemy.com/?r=f5ecd4315e80b9d9) create a new project.

![Creating a Project](https://res.cloudinary.com/practicaldev/image/fetch/s--MueFRtJH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropboxusercontent.com/s_90B53416B7AA7BC8FEE6FA04488E85316C40786902CF7342257FAAC4A53B3554_1666203189642_screenshoteasy%2B2.png)


**STEP 4:**
Copy the `Goerli` test network WebSocket or HTTPS endpoint URL to your `.env` file.

![Goerli Testnet Key](https://res.cloudinary.com/practicaldev/image/fetch/s--BbbXQWE4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropboxusercontent.com/s_90B53416B7AA7BC8FEE6FA04488E85316C40786902CF7342257FAAC4A53B3554_1666203321015_screenshoteasy%2B3.png)


After that, enter the private key of your preferred Metamask account to the `DEPLOYER_KEY` in your environment variables and save. If you followed the instructions correctly, your environment variables should now look like this.


    ENDPOINT_URL=***************************
    DEPLOYER_KEY=**********************
    
    REACT_APP_COMET_CHAT_REGION=**
    REACT_APP_COMET_CHAT_APP_ID=**************
    REACT_APP_COMET_CHAT_AUTH_KEY=******************************

See the section below if you don't know how to access your private key.

## Extracting Your Metamask Private Key

**STEP 1:**
Make sure **Goerli** is selected as the test network in your Metamask browser extension, ~~Rinkeby~~ and the older test nets have now been depreciated. 

Next, on the preferred account, click the vertical dotted line and choose account details. Please see the image below.

![Step One](https://res.cloudinary.com/practicaldev/image/fetch/s--WduRe5ma--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/practicaldev/image/fetch/s--FXeHUvQp--/c_limit%252Cf_auto%252Cfl_progressive%252Cq_auto%252Cw_880/https://i.ibb.co/NjkWgrf/kpK7sHUA.png)


**STEP 2:**
Enter your password on the field provided and click the confirm button, this will enable you to access your account private key.

![Step Two](https://res.cloudinary.com/practicaldev/image/fetch/s--Hci3cHQo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/practicaldev/image/fetch/s--oYd6FJPm--/c_limit%252Cf_auto%252Cfl_progressive%252Cq_auto%252Cw_880/https://i.ibb.co/Tqrx1RT/S5sWkwuA.png)


**STEP 3:**
Click on **"export private key**" to see your private key. Make sure you never expose your keys on a public page such as `Github`. That is why we are appending it as an environment variable.

![Step Three](https://res.cloudinary.com/practicaldev/image/fetch/s--9wrgKLtc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/practicaldev/image/fetch/s--lo9ufSCF--/c_limit%252Cf_auto%252Cfl_progressive%252Cq_auto%252Cw_880/https://i.ibb.co/0sW24xz/iHVXsxjw.png)


**STEP 4:**
Copy your private key to your `.env` file. See the image and code snippet below:

![Step Four](https://res.cloudinary.com/practicaldev/image/fetch/s--4G4yKwVN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/practicaldev/image/fetch/s--yvdexnsQ--/c_limit%252Cf_auto%252Cfl_progressive%252Cq_auto%252Cw_880/https://i.ibb.co/MCkMvyz/1KEkvmvw.png)

    ENDPOINT_URL=***************************
    DEPLOYER_KEY=**********************
    
    REACT_APP_COMET_CHAT_REGION=**
    REACT_APP_COMET_CHAT_APP_ID=**************
    REACT_APP_COMET_CHAT_AUTH_KEY=******************************


## Configuring the Hardhat script

At the root of this project, open the `hardhat.config.js` file and replace its content with the following settings.


{% gist https://gist.github.com/Daltonic/627b37deca19b3f41b4b018125385e32 %}


The above script instructs hardhat on these three important rules.


- **Networks**: This block contains the configurations for your choice of networks. On deployment, hardhat will require you to specify a network for shipping your smart contracts.


- **Solidity**: This describes the version of the compiler to be used by hardhat for compiling your smart contract codes into `bytecodes` and `abi`.


- **Paths**: This simply informs hardhat of the location of your smart contracts and also a location to dump the output of the compiler which is the abi.


## Configuring the Deployment Script

Navigate to the scripts folder and then to your `deploy.js` file and paste the code below into it. If you can't find a script folder, make one, create a **deploy.js** file, and paste the following code into it.


{% gist https://gist.github.com/Daltonic/129f9d8f713e423a83e2eb579f8a9393 %}


When run as a Hardhat command, the above script will deploy the `**BlueVotes.sol**` smart contract to any network of your choice.

Following the above instructions, open a terminal pointing to this project and run the commands listed below separately on two terminals. You can do this directly from your editor in VS Code. Look at the command below.


    yarn hardhat node # Terminal #1
    yarn hardhat run scripts/deploy.js --network localhost # Terminal #2

If the preceding commands were successfully executed, you should see the following activity on your terminal. Please see the image below.


![Activities of Deployment on the Terminal](https://paper-attachments.dropboxusercontent.com/s_90B53416B7AA7BC8FEE6FA04488E85316C40786902CF7342257FAAC4A53B3554_1666245726239_Screenshot+2022-10-20+at+7.00.39+AM.png)


If you need further help configuring Hardhat or deploying your Fullstack DApp, watch this video.


[![Deploy Fullstack DApp](http://img.youtube.com/vi/hsec2erdLOI/0.jpg)](http://www.youtube.com/watch?v=hsec2erdLOI)


## The Blockchain Service File

Now that we've completed the preceding configurations, let's create the smart contract for this build. Create a new folder called `**contracts**` in your project's `**src**` directory.

Create a new file called `**BlueVotes.sol**` within this contracts folder; this file will contain all of the logic that govern the smart contract's activities. Copy, paste, and save the following codes into the `**BlueVotes.sol**` file. See the complete code below.


{% gist https://gist.github.com/Daltonic/8a4dead153fc0cb2d8cd4f3d6b3fdcd8 %}


Now, let's go over some of the details of what's going on in the smart contract above. We have the following items:

**Structs**

- PollStruct: This describes the content of each poll created in our platform.
- VoterStruct: This models the information of a voter, user, or contestant on the platform.

**State Variables**

- TotalPolls: This keeps track of the number of polls created on the smart contract.
- TotalUsers: This carries the total number of users registered on the platform.

**Mappings**

- Users: This maps users' addresses to their respective data using the VoterStruct.
- Voted: This keeps track of the voting status of each user on different polls.
- Contested: This tells if a contestant has or has not contested for a particular poll.
- ContestantsIn: This holds the data for every contestant in a given poll.
- PollExist: This checks if a specific poll Id exists or not on the platform.

**Events and Modifiers**

- Voted: This emits information about the current user who voted.
- UserOnly: This modifier prevents unregistered users from accessing unauthorized functions.

**Poll Functions**

- CreatePoll: This takes data about a poll from a registered user and creates a poll after validating that the information meets standards.
- UpdatePoll:  This function modifies the content of a specific poll, given that the caller is the poll creator and the poll Id exists.
- DeletePoll: This function enables the poll creator to toggle the deleted key to true, thereby making the poll unavailable for circulation.
- GetPolls: This returns all the polls created by every user on the platform.
- GetPoll: This returns information about a specific poll from our platform.

**User Oriented Functions**

- Register: This function enables a user to sign up with his full name and image avatar.
- Contest: This function gives a registered user the chance to become a contestant on a given poll provided that the poll has not started.
- ListContestants: This function lists out all the contestants who contested for a particular poll.
- Vote: This function enables a user to vote for one contestant per poll within the period stipulated for voting.

Do you want to improve your knowledge of smart contracts? Watch this video to learn how to use Hardhat for smart contract test-driven development.

[![Learn test-driven development](http://img.youtube.com/vi/RadB8dan0Bs/0.jpg)](http://www.youtube.com/watch?v=RadB8dan0Bs)

## Developing the Frontend

Now that we have our smart contract on the network and all of our artifacts (bytecodes and ABI) generated, let's take a step-by-step approach to build the front end with React.

## Components

In the src directory, create a new folder called `**components**` to house all of the React components.

**Header component**

![Header Component](https://paper-attachments.dropboxusercontent.com/s_F8CFEC13187B2461ACB3333DD930FBFD0382C2061717C82E7C601E673B7954B4_1669106827424_screenshoteasy+1.png)


This component clearly displays only two pieces of information, the website's logo, and the connected account button. See the codes below.


{% gist https://gist.github.com/Daltonic/a2bb33585b0d0f0eae03e578bf8cd57e %}


**Hero Component**

![Hero Component](https://paper-attachments.dropboxusercontent.com/s_F8CFEC13187B2461ACB3333DD930FBFD0382C2061717C82E7C601E673B7954B4_1669107486820_screenshoteasy+2.png)


The hero component allows you to launch other components such as the registration and the poll creation components. This component also allows a user to log in to their account if already registered, using the CometChat SDK under the hood. See the codes below.


{% gist https://gist.github.com/Daltonic/08529614f05b41123c569010aba7c5f5 %}


**Polls Component**

![Polls Component](https://paper-attachments.dropboxusercontent.com/s_F8CFEC13187B2461ACB3333DD930FBFD0382C2061717C82E7C601E673B7954B4_1669111083791_screenshoteasy+4.png)


This component grabs all active polls and lists them on our platform. Within this component also lies a single component responsible for rendering each specific poll. See the codes below.


{% gist https://gist.github.com/Daltonic/edf6f135bd8591f73b7cdaba7e3c3040 %}


**CreatePoll Component**

![Create Poll Component](https://paper-attachments.dropboxusercontent.com/s_F8CFEC13187B2461ACB3333DD930FBFD0382C2061717C82E7C601E673B7954B4_1669111930982_screenshoteasy+3.png)


This component is used for creating fresh new polls on our platform. It takes essential information like a poll title, description, image URL, and start and end date to create a poll. See the codes below.


{% gist https://gist.github.com/Daltonic/c641507d847c2f86ee27676ec63ec990 %}


**Update Poll Component**

![Update Component](https://paper-attachments.dropboxusercontent.com/s_F8CFEC13187B2461ACB3333DD930FBFD0382C2061717C82E7C601E673B7954B4_1669113228635_screenshoteasy+6.png)


This component follows the same approach as the create poll component. See the codes below.


{% gist https://gist.github.com/Daltonic/7b61d73bd2090ffe7a1ea9194531ba81 %}


**DeletePoll Component**

![Delete Poll Component](https://paper-attachments.dropboxusercontent.com/s_F8CFEC13187B2461ACB3333DD930FBFD0382C2061717C82E7C601E673B7954B4_1669114202532_screenshoteasy+7.png)


This component simply allows you to delete an existing poll from being listed. After deletion, the poll will be removed from circulation. See the code below.


{% gist https://gist.github.com/Daltonic/bfeced57519d807ad1d274bbbc82ddbc %}


**Messages Component**

![The Message Component](https://paper-attachments.dropboxusercontent.com/s_F8CFEC13187B2461ACB3333DD930FBFD0382C2061717C82E7C601E673B7954B4_1669125754742_screenshoteasy+8.png)


Using the CometChat SDK, this component is in charge of displaying a collection of group chat messages for each poll. Look at the code below.


{% gist 
https://gist.github.com/Daltonic/9f56ec21d5d1e859833074ff8d18aecc %}


**Footer Component**

![Footer Component](https://paper-attachments.dropboxusercontent.com/s_F8CFEC13187B2461ACB3333DD930FBFD0382C2061717C82E7C601E673B7954B4_1669111594205_screenshoteasy+5.png)


This is a simple component that essentially enhances the aesthetics and design of our application. Look at the code below.


{% gist https://gist.github.com/Daltonic/fd5aeb8ce5764a850961d0342cf21541 %}



## Views

On the `**src**` directory, create a new folder called `**views**` and create the following components one after the other inside of it.

**Home Page**

![Home Page](https://paper-attachments.dropboxusercontent.com/s_F8CFEC13187B2461ACB3333DD930FBFD0382C2061717C82E7C601E673B7954B4_1669131405334_BlueVotes+Home.gif)


This page brings together the hero and polls components in one beautiful interface. See the code snippet below.


{% gist https://gist.github.com/Daltonic/7cdca47db9fa06d882ea061f0f5d96ad %}


**Vote Page**

![VotesPage](https://paper-attachments.dropboxusercontent.com/s_F8CFEC13187B2461ACB3333DD930FBFD0382C2061717C82E7C601E673B7954B4_1669131871062_BlueVotes+Vote+Page.gif)


This page contains buttons for launching the edit or delete poll components, and also gives one the opportunity to contest, vote, or chat with other voters. See the codes below.


{% gist https://gist.github.com/Daltonic/95c397db93824ee46da626c1422ef4fb %}

## The App.jsx file

Now, let’s tackle the App.jsx file responsible for bundling all our components and pages, see its codes below.


{% gist 
https://gist.github.com/Daltonic/6bf5fbb00ce5675186b33894de72d46d %}



## Other Essential Services

The services listed below are critical to the smooth operation of our application.

**The Store Service**
We're using the [react-hooks-global-state](https://www.npmjs.com/package/react-hooks-global-state) library to create a centralized storage space in our app that serves as a state management service.

Make a "store" folder in the src folder. Next, within this store folder, create a file called index.jsx and paste and save the following codes into it.


{% gist https://gist.github.com/Daltonic/d1ead6d9b6ce8d32959419dcf86481b8 %}


**The Blockchain Service**
In the src folder, create a file called **Blockchain.services.jsx** and paste and save the file below inside it.


{% gist https://gist.github.com/Daltonic/606e86508e25d498b6c012789f935396 %}


**The Chat Service**
Make a file called "Chat.services.jsx" in the src folder and paste and save the codes below inside it.


{% gist https://gist.github.com/Daltonic/b7b31e30f0e4bed0aed8b4dd7bae37d6 %}


**The Index.jsx file**
Now update the index entry file with the following codes.


{% gist https://gist.github.com/Daltonic/945f0664d794e09d496f56d72c922dbe %}


Lastly, run the following commands on two terminals to spin up the server on your browser, but make sure you already have Metamask installed.


    # Terminal one:
    yarn hardhat node
    # Terminal Two
    yarn hardhat run scripts/deploy.js
    yarn start

Running the above commands as instructed will open your project on your browser. And there you have it for how to build a blockchain voting system with React, Solidity, and [CometChat](https://try.cometchat.com/oj0s7hrm5v78).

If you're confused about web3 development and want visual materials, here's one of my videos that will teach you how to create an NFT marketplace.


[![Build NFT marketplace](http://img.youtube.com/vi/fJIiqeevqoU/0.jpg)](http://www.youtube.com/watch?v=fJIiqeevqoU)

## Conclusion

The decentralized web and the blockchain have come to stay, and building real-life use cases are a sure way to accelerate your web3 development career.

In this tutorial, you have learned how to build a blockchain-based voting system that utilizes smart contracts to ensure that rigging and cheating are prohibited. We also incorporated the awesome CometChat SDK that allows us to have a group chat for each poll.

If you are ready to go deeper into web3 development, [**watch my free videos on my YouTube channel**](https://youtube.com/@dappmentors?sub_confirmation=1). Or [**book your private web3 classes with me**](https://www.buymeacoffee.com/web3classes/e/74614) to speed up your web3 learning process.

That being said, I'll see you next time, and have a wonderful day!


## About the Author

Gospel Darlington is a full-stack blockchain developer with `6+` years of experience in the software development industry.

By combining Software Development, writing, and teaching, he demonstrates how to build decentralized applications on EVM-compatible blockchain networks.

His stacks include `JavaScript`, `React`, `Vue`, `Angular`, `Node`, `React Native`, `NextJs`, `Solidity`, and more.

For more information about him, kindly visit and follow his page on [Twitter](https://twitter.com/idaltonic), [Github](https://github.com/Daltonic), [LinkedIn](https://www.linkedin.com/in/darlington-gospel-aa626b125), or his [website](https://daltonic.github.io/).