Voting Example¶
A decentralized voting contract with proposals and weighted votes.
Contract¶
contract Voting {
struct Proposal {
string description;
uint256 voteCount;
uint256 deadline;
bool executed;
mapping(address => bool) hasVoted;
}
struct Voter {
uint256 weight;
bool registered;
}
mapping(uint256 => Proposal) public proposals;
mapping(address => Voter) public voters;
uint256 public proposalCount;
address public admin;
uint256 public totalVoters;
event ProposalCreated(uint256 indexed id, string description, uint256 deadline);
event Voted(uint256 indexed proposalId, address indexed voter, uint256 weight);
event VoterRegistered(address indexed voter, uint256 weight);
event ProposalExecuted(uint256 indexed id);
error NotAdmin();
error NotRegistered();
error AlreadyVoted();
error VotingEnded();
error VotingNotEnded();
error AlreadyExecuted();
error ProposalNotFound();
modifier onlyAdmin() {
if (msg.sender != admin) revert NotAdmin();
_;
}
modifier onlyRegistered() {
if (!voters[msg.sender].registered) revert NotRegistered();
_;
}
constructor() {
admin = msg.sender;
}
function registerVoter(address voter, uint256 weight) public onlyAdmin {
require(weight > 0, "Weight must be positive");
require(!voters[voter].registered, "Already registered");
voters[voter] = Voter({
weight: weight,
registered: true
});
totalVoters++;
emit VoterRegistered(voter, weight);
}
function createProposal(string memory description, uint256 duration) public onlyAdmin returns (uint256) {
proposalCount++;
Proposal storage p = proposals[proposalCount];
p.description = description;
p.voteCount = 0;
p.deadline = block.timestamp + duration;
p.executed = false;
emit ProposalCreated(proposalCount, description, p.deadline);
return proposalCount;
}
function vote(uint256 proposalId) public onlyRegistered {
Proposal storage p = proposals[proposalId];
if (bytes(p.description).length == 0) revert ProposalNotFound();
if (block.timestamp >= p.deadline) revert VotingEnded();
if (p.hasVoted[msg.sender]) revert AlreadyVoted();
p.hasVoted[msg.sender] = true;
p.voteCount += voters[msg.sender].weight;
emit Voted(proposalId, msg.sender, voters[msg.sender].weight);
}
function execute(uint256 proposalId) public onlyAdmin {
Proposal storage p = proposals[proposalId];
if (bytes(p.description).length == 0) revert ProposalNotFound();
if (block.timestamp < p.deadline) revert VotingNotEnded();
if (p.executed) revert AlreadyExecuted();
p.executed = true;
emit ProposalExecuted(proposalId);
// Execute proposal logic here
}
function getProposal(uint256 proposalId) public view returns (
string memory description,
uint256 voteCount,
uint256 deadline,
bool executed
) {
Proposal storage p = proposals[proposalId];
return (p.description, p.voteCount, p.deadline, p.executed);
}
function hasVoted(uint256 proposalId, address voter) public view returns (bool) {
return proposals[proposalId].hasVoted[voter];
}
function getVoter(address voter) public view returns (uint256 weight, bool registered) {
Voter storage v = voters[voter];
return (v.weight, v.registered);
}
function isVotingActive(uint256 proposalId) public view returns (bool) {
Proposal storage p = proposals[proposalId];
return block.timestamp < p.deadline && !p.executed;
}
function getTimeRemaining(uint256 proposalId) public view returns (uint256) {
Proposal storage p = proposals[proposalId];
if (block.timestamp >= p.deadline) return 0;
return p.deadline - block.timestamp;
}
}
Build¶
Usage Flow¶
- Admin registers voters with voting weights
- Admin creates proposals with descriptions and deadlines
- Registered voters vote on active proposals
- After deadline, admin executes successful proposals
Key Features¶
- Weighted voting: Different voters can have different weights
- Time-limited proposals: Voting ends at deadline
- One vote per address: Prevents double voting
- Execution tracking: Proposals can only execute once