Create a transparent and tamper-proof voting system on the blockchain. Learn about access control, vote delegation, time-locked voting periods, and result tabulation.
Create a comprehensive voting system with proposals and vote tracking.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/access/AccessControl.sol";
contract VotingSystem is AccessControl {
bytes32 public constant ADMIN_ROLE = keccak256("ADMIN_ROLE");
struct Proposal {
string title;
string description;
uint256 voteCount;
uint256 startTime;
uint256 endTime;
bool exists;
}
struct Voter {
bool registered;
bool hasVoted;
uint256 votedProposalId;
address delegate;
}
mapping(uint256 => Proposal) public proposals;
mapping(address => Voter) public voters;
uint256 public proposalCount;
event ProposalCreated(uint256 indexed id, string title, uint256 startTime, uint256 endTime);
event VoterRegistered(address indexed voter);
event VoteCast(address indexed voter, uint256 indexed proposalId);
event VoteDelegated(address indexed from, address indexed to);
constructor() {
_grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
_grantRole(ADMIN_ROLE, msg.sender);
}
function createProposal(
string memory _title,
string memory _description,
uint256 _duration
) external onlyRole(ADMIN_ROLE) returns (uint256) {
uint256 proposalId = proposalCount++;
proposals[proposalId] = Proposal({
title: _title,
description: _description,
voteCount: 0,
startTime: block.timestamp,
endTime: block.timestamp + _duration,
exists: true
});
emit ProposalCreated(proposalId, _title, block.timestamp, block.timestamp + _duration);
return proposalId;
}
function registerVoter(address _voter) external onlyRole(ADMIN_ROLE) {
require(!voters[_voter].registered, "Already registered");
voters[_voter].registered = true;
emit VoterRegistered(_voter);
}
function registerVoters(address[] calldata _voters) external onlyRole(ADMIN_ROLE) {
for (uint i = 0; i < _voters.length; i++) {
if (!voters[_voters[i]].registered) {
voters[_voters[i]].registered = true;
emit VoterRegistered(_voters[i]);
}
}
}
function delegate(address _to) external {
Voter storage sender = voters[msg.sender];
require(sender.registered, "Not registered");
require(!sender.hasVoted, "Already voted");
require(_to != msg.sender, "Cannot delegate to self");
sender.delegate = _to;
emit VoteDelegated(msg.sender, _to);
}
function vote(uint256 _proposalId) external {
Voter storage sender = voters[msg.sender];
require(sender.registered, "Not registered");
require(!sender.hasVoted, "Already voted");
Proposal storage proposal = proposals[_proposalId];
require(proposal.exists, "Proposal does not exist");
require(block.timestamp >= proposal.startTime, "Voting not started");
require(block.timestamp <= proposal.endTime, "Voting ended");
sender.hasVoted = true;
sender.votedProposalId = _proposalId;
proposal.voteCount++;
emit VoteCast(msg.sender, _proposalId);
}
function getProposal(uint256 _id) external view returns (
string memory title,
string memory description,
uint256 voteCount,
uint256 startTime,
uint256 endTime,
bool isActive
) {
Proposal storage p = proposals[_id];
require(p.exists, "Proposal does not exist");
return (
p.title,
p.description,
p.voteCount,
p.startTime,
p.endTime,
block.timestamp >= p.startTime && block.timestamp <= p.endTime
);
}
}Sign up to save your progress and earn 180 points upon completion.