A decentralized blockchain-based voting application built using Solidity, Foundry, React, Ethers.js, and MetaMask. The system allows an administrator to create elections, register candidates, assign candidates to elections, and enables users to cast secure on-chain votes through their wallets.
- React
- React Router DOM
- Ethers.js
- Context API
- CSS
- Solidity
- Foundry
- MetaMask
- MetaMask Wallet Authentication
- Decentralized On-Chain Voting
- Election Creation
- Candidate Registration
- Candidate Reusability Across Elections
- Election Candidate Assignment
- One Vote Per Wallet Per Election
- Election Scheduling Using Blockchain Timestamps
- Live Election Results
- Role-Based Admin Controls
- Smart Contract Events
- Fully Decentralized Architecture
Blockchain-Voting-Network/
│
├── frontend/
│ ├── src/
│ │ ├── abi/
│ │ ├── components/
│ │ ├── config/
│ │ ├── context/
│ │ ├── pages/
│ │ ├── styles/
│ │ ├── App.jsx
│ │ └── main.jsx
│ │
│ └── package.json
│
├── smart-contract/
│ ├── src/
│ │ └── Voting.sol
│ │
│ ├── script/
│ │ ├── VotingDeploy.s.sol
│ │ └── Interactions.s.sol
│ │
│ ├── test/
│ │ └── Voting.t.sol
│ │
│ ├── foundry.toml
│ └── package.json
│
└── README.mdThe contract owner can:
- Create elections
- Define election start time
- Define election end time
- Assign existing candidates to elections
The contract owner can:
- Create candidates
- Reuse candidates across multiple elections
- Manage election participation
Example:
Alice
├── Election 1
└── Election 2
Bob
└── Election 1
Charlie
└── Election 2
Users vote directly through their wallets.
Voting rules:
- One vote per wallet per election
- Users may vote in multiple elections
- Votes are stored permanently on-chain
- Election participation is validated before voting
uint256 private sElectionCount;
uint256 private sCandidateCount;
mapping(uint256 => Election) private sElections;
mapping(uint256 => Candidate) private sCandidates;
mapping(uint256 => uint256[]) private sElectionIdToCandidateIds;
mapping(uint256 => mapping(uint256 => bool)) private sElectionIdToCandidateIdToIsParticipating;
mapping(uint256 => mapping(uint256 => uint256)) private sElectionIdToCandidateIdToVoteCount;
mapping(uint256 => mapping(address => bool)) private sElectionIdToVoterToHasVoted;Admin Creates Candidate
↓
Admin Creates Election
↓
Admin Assigns Candidates
↓
Election Starts
↓
User Connects MetaMask
↓
User Casts Vote
↓
Vote Stored On Chain
↓
Results Updated
| Function | Description |
|---|---|
| createElection() | Create new election |
| getElectionById() | Get election details |
| getElectionCount() | Get total elections |
| getElectionCandidateIds() | Get assigned candidates |
| Function | Description |
|---|---|
| createCandidate() | Create candidate |
| getCandidateById() | Get candidate details |
| getCandidateCount() | Get total candidates |
| addCandidateToElection() | Assign candidate to election |
| Function | Description |
|---|---|
| vote() | Cast vote |
| userHasVoted() | Check voter status |
| Function | Description |
|---|---|
| getVoteCount() | Get candidate vote count |
| getElectionResults() | Get election results |
| getOwner() | Get contract owner |
Global wallet state is managed using:
WalletContext
Stores:
provider
signer
account
contract
isConnected
isOwner
The frontend determines ownership using:
getOwner()Only owners can:
- Create candidates
- Create elections
- Assign candidates
/
│
├── /elections
│
├── /elections/:id
│
├── /results/:id
│
├── /admin/candidates
│
└── /admin/create-election
git clone https://github.com/Aniket-Roy22/ElectaNet.gitFrontend:
cd client
npm installSmart Contract:
cd contracts
forge installforge buildStart local blockchain:
anvilDeploy:
forge script script/VotingDeploy.s.sol \
--rpc-url http://127.0.0.1:8545 \
--private-key <PRIVATE_KEY> \
--broadcastcd frontend
npm run devFrontend runs on:
http://localhost:5173





