DEV Community

Cover image for Day 3 of 30 Days of Solidity Challenge – Build a Simple Polling Station πŸ—³οΈ
Saurav Kumar
Saurav Kumar

Posted on

Day 3 of 30 Days of Solidity Challenge – Build a Simple Polling Station πŸ—³οΈ

Hello Web3 devs πŸ‘‹,

Welcome to Day 3 of my 30 Days of Solidity Challenge! For this day, I created a polling station smart contract that allows users to vote for their favorite candidates. Through this project, I deepened my understanding of arrays, mappings, and structs in Solidity by building a simplified digital voting system.


πŸ“Œ Task Overview

The goal of this project was to design a smart contract that can:

  • Store candidate data (name and vote count) using an array of structs
  • Keep track of whether an address has already voted using a mapping
  • Prevent double voting
  • Allow anyone to check candidate details and votes

πŸ› οΈ The Smart Contract (Key Snippets & Explanation)

Here’s a breakdown of the main logic:

struct Candidate {
    string name;
    uint voteCount;
}

Candidate[] public candidates;
mapping(address => bool) public hasVoted;
event Voted(address indexed voter, uint candidateIndex);

constructor(string[] memory _candidateNames) {
    for (uint i = 0; i < _candidateNames.length; i++) {
        candidates.push(Candidate({ name: _candidateNames[i], voteCount: 0 }));
    }
}

function vote(uint _candidateIndex) public {
    require(!hasVoted[msg.sender], "You have already voted!");
    require(_candidateIndex < candidates.length, "Invalid candidate!");

    hasVoted[msg.sender] = true;
    candidates[_candidateIndex].voteCount++;
    emit Voted(msg.sender, _candidateIndex);
}

function getCandidate(uint _index) public view returns (string memory, uint) {
    require(_index < candidates.length, "Invalid candidate index!");
    Candidate memory c = candidates[_index];
    return (c.name, c.voteCount);
}

function getTotalCandidates() public view returns (uint) {
    return candidates.length;
}
Enter fullscreen mode Exit fullscreen mode

How it works:

  1. Constructor accepts a list of candidate names and initializes the candidates array.
  2. vote():
  • Checks if the sender has already voted (via hasVoted mapping).
  • Ensures the candidate index is valid.
  • Marks the address as having voted.
  • Increments the vote count for that candidate.
  • Emits a Voted event for transparency.
    1. getCandidate() returns a candidate’s name and vote count.
    2. getTotalCandidates() returns the number of candidates.

πŸš€ Testing & Seeing Output

I used Remix IDE for testing, which is simple and interactive:

  • Deploy the contract with a list of names, e.g. ["Alice", "Bob", "Charlie"].
  • Call vote(0) to vote for Alice.
  • Then call getCandidate(0) β†’ It should return ("Alice", 1).
  • Try hasVoted(yourAddress) β†’ It should return true after you vote.
  • You can check the Deployed Contracts section in Remix to see all outputs and state changes.

This approach gives instant visual feedback, which is helpful while learning.


πŸ“š Key Learnings from Day 3

  • Arrays + Structs let you structure and store complex data.
  • Mappings help track individual user actions (like whether they’ve voted).
  • Events provide an on-chain log of actions, improving transparency.
  • Composing these elements enables you to build real-world logic (like voting) on-chain.

πŸ“‚ Repo & Code

You can find the full source code and all my day-wise submissions here:

πŸ”— Repo: 30-Days-of-Solidity Submissions

Feel free to check it out, clone it, and experiment with enhancements!


Thanks for reading πŸŽ‰
On to Day 4 β€” more Solidity magic awaits!

Top comments (0)