DEV Community

Cover image for Building our first blockchain project: A blockchain voting contract
feranmiodugbemi
feranmiodugbemi

Posted on

Building our first blockchain project: A blockchain voting contract

We've all heard about the last election done in Nigeria, how there seem to be claims of tampering with election votes, mistakes in counting votes, and so many other excuses, well, that was my motive for building this project๐Ÿ˜‚๐Ÿ˜‚. So, I thought๐Ÿค” "How would it feel like if our Nigerian voting system was blockchain-based", then I decided to build the project.

WHY A BLOCKCHAIN VOTING SYSTEM?
In case you're wondering how a blockchain-based voting system solves the problems in our traditional voting system, Let me answer your curious questions. First of all, the blockchain is trustless and decentralized, so no individual has the power to control or manipulate the votes and secondly I just love the idea๐Ÿ˜‚๐Ÿ˜‚.

WHAT WILL I LEARN FROM THIS PROJECT?
You will gain practical experience on how a smart contract works and how it's deployed. You will also implement the knowledge you gained from my last tutorial about solidity keywords.

LFG๐Ÿš€๐Ÿš€๐Ÿš€

BUILDING OUR SMART CONTRACT

First of all, head over to remix. Remix is an online IDE for writing and deploying smart contracts. Create a new file named "Voting.sol" inside the contracts directory
Voting.sol

The blockchain system

The beginning of a new chapter๐Ÿ˜Œ

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;

contract VotingSystem{
   //The rest of the code goes in here
}
Enter fullscreen mode Exit fullscreen mode

We are initializing a new contract named VotingSystem that runs on solidity compiler versions of 0.8.9 and above.

Creating our candidates

We will be using the three musketeers of the 2023 Nigerian election๐Ÿ˜‚๐Ÿ˜‚, Atiku, Obi and Tinubu๐Ÿ™Œ.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;

contract VotingSystem{
   struct Candidate{
        string name;
        uint numberOfVotes;
    }
   mapping(uint => Candidate) candidates;
   constructor(){
        candidates[0] = Candidate("Tinubu", 0);
        candidates[1] = Candidate("Atiku", 0);
        candidates[2] = Candidate("Obi", 0);
    }
}
Enter fullscreen mode Exit fullscreen mode

Here, we created a Candidate struct to hold the name and numberOfVotes of each candidate. We are mapping a uint to our Candidate to keep track of the number of candidates we have and automatically set their number of votes to be 0.

Voting logic

Let's solve the problem of double voting and vote manipulation

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;

contract VotingSystem{
   struct Candidate{
        string name;
        uint numberOfVotes;
    }
   mapping (address => bool) voterVoted;
   mapping(address => uint) votesPerVoter;
   mapping(uint => Candidate) candidates;
   constructor(){
        candidates[0] = Candidate("Tinubu", 0);
        candidates[1] = Candidate("Atiku", 0);
        candidates[2] = Candidate("Obi", 0);
        voterVoted[msg.sender] = false;
    }
   modifier notVoted {
        require(!voterVoted[msg.sender] || votesPerVoter[msg.sender] == 0, "You have already voted");
        _;
    }
}
Enter fullscreen mode Exit fullscreen mode

We created two mappings, voterVoted is to check if an address has already voted for a candidate before and returns a boolean while votesPerVoter ensures that an address is given just 1 chance to vote. The modifier is used for implementing all the logic and will be used in a Vote function.

Vote function

Let's vote for the right candidate

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;

contract VotingSystem{
   // The code we've written earlier
   function vote(string memory _nameofCandidate) public notVoted returns (string memory) {
        bytes32 nameHash = keccak256(abi.encodePacked(_nameofCandidate));
        bytes32 tinubuHash = keccak256(abi.encodePacked("Tinubu"));
        bytes32 atikuHash = keccak256(abi.encodePacked("Atiku"));
        bytes32 obiHash = keccak256(abi.encodePacked("Obi"));
        if (nameHash == tinubuHash){
            candidates[0].numberOfVotes++;
        } else if(nameHash == atikuHash){
            candidates[1].numberOfVotes++;
        } else if(nameHash == obiHash){
            candidates[2].numberOfVotes++;
        }else {
        revert("Invalid candidate name");
        }
        voterVoted[msg.sender] = true;
        string memory Text = "You have already casted your vote";
        votesPerVoter[msg.sender]++;
        return Text;
    }
}
Enter fullscreen mode Exit fullscreen mode

This is our vote function which is used for casting votes, it takes in the nameOfCandidate that the address is voting for. Since Solidity cannot compare two strings together so we generated a hash of our Candidate's name and the _nameofCandidate using the keccak256 algorithm and compares them, so whichever Candidate's name matches the _nameofCandidate their vote count is increased by one else it reverts to Invalid candidate name.

Getting our candidate's votes

After voting, we want to make sure that the right candidate is leading๐Ÿ™ˆ.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;

contract VotingSystem{
   // Earlier written code
   function getVotes() public view returns( Candidate[] memory){
        Candidate[] memory candidateList = new Candidate[](3);
        candidateList[0] = candidates[0];
        candidateList[1] = candidates[1];
        candidateList[2] = candidates[2];
        return candidateList;
    }
}
Enter fullscreen mode Exit fullscreen mode

This function allows anyone to retrieve the vote counts for all Candidates and returns it in an array format.

Deploying our contract

It's time to unleash our project to the world๐Ÿ˜Œ
Voting2
Go ahead and click on that compile button to compile the solidity smart contract on the solidity compiler page
Voting3
So, remix gives us 15 addresses with 100 fake ETH to test our smart contracts on different Ethereum test networks. Now, we will be deploying our contract to one of those addresses. Click on the Deploy button to deploy our contract. The address after AT is called the contract address, We can use it to interact with our contract using a client library like web3.js, ethers.js, web3.py, etc.

Conclusion

In conclusion, our journey through the development of a blockchain-based voting system has been both informative and entertaining. We embarked on this project with the aim of addressing the challenges and concerns surrounding traditional voting systems, particularly in Nigeria. The issues of vote tampering, counting errors, and other excuses that have plagued past elections served as the catalyst for this endeavor ๐Ÿ˜‚๐Ÿ˜‚.

By creating a blockchain voting system, we have introduced a trustless and decentralized approach, where no single entity can manipulate or control the votes. This not only provides transparency but also safeguards the integrity of the electoral process. And let's not forget, we did it because, well, we just love the idea ๐Ÿ˜‚๐Ÿ˜‚.

Throughout this journey, you've had the opportunity to gain practical experience in working with smart contracts and deploying them. You've also applied the knowledge from our previous tutorial on Solidity keywords, further enhancing your blockchain development skills.

So, as we wrap up this adventure, I hope you've not only enjoyed the journey but also gained valuable insights into building your first blockchain project and deploying it successfully. With your newfound skills, you're well-equipped to explore more exciting possibilities in the world of blockchain technology. Until next time, happy coding! ๐Ÿ˜Œ๐Ÿš€๐Ÿ”—

Top comments (3)

Collapse
 
victor_ajibua profile image
Victor Ajibua

Interesting.

Collapse
 
maisiegrady profile image
Maisie

Hey

Collapse
 
feranmiodugbemi profile image
feranmiodugbemi

Hello๐Ÿ‘‹