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;
}
How it works:
-
Constructor accepts a list of candidate names and initializes the
candidates
array. - 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.- getCandidate() returns a candidateβs name and vote count.
- 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 returntrue
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)