sourcebridge_42-contract-lab/contracts/VotingContract.sol
sourcebridge_42 3250fae876
Some checks are pending
CI / build-and-test (push) Waiting to run
CI / slither (push) Waiting to run
citizen: implement Implement: Handles voting logic for the governance contract
2026-04-19 09:08:00 +00:00

130 lines
3.8 KiB
Solidity

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import "./interfaces/IGovernance.sol";
contract VotingContract {
struct Proposal {
uint256 id;
address proposer;
string description;
uint256 startTime;
uint256 endTime;
uint256 votesFor;
uint256 votesAgainst;
mapping(address => bool) hasVoted;
ProposalStatus status;
}
enum ProposalStatus {
Pending,
Active,
Passed,
Rejected,
Executed
}
uint256 public constant VOTING_PERIOD = 7 days;
uint256 public constant QUORUM_PERCENTAGE = 20;
uint256 public constant MIN_VOTING_THRESHOLD = 100 ether;
mapping(uint256 => Proposal) public proposals;
uint256 public proposalCount;
event ProposalCreated(
uint256 indexed proposalId,
address indexed proposer,
string description
);
event VoteCast(
uint256 indexed proposalId,
address indexed voter,
bool support
);
event ProposalStatusChanged(
uint256 indexed proposalId,
ProposalStatus newStatus
);
modifier validProposal(uint256 proposalId) {
require(proposalId < proposalCount, "Invalid proposal ID");
_;
}
function createProposal(string memory description) external payable returns (uint256) {
require(msg.value >= MIN_VOTING_THRESHOLD, "Insufficient proposal stake");
uint256 proposalId = proposalCount++;
Proposal storage newProposal = proposals[proposalId];
newProposal.id = proposalId;
newProposal.proposer = msg.sender;
newProposal.description = description;
newProposal.startTime = block.timestamp;
newProposal.endTime = block.timestamp + VOTING_PERIOD;
newProposal.status = ProposalStatus.Active;
emit ProposalCreated(proposalId, msg.sender, description);
return proposalId;
}
function castVote(uint256 proposalId, bool support) external validProposal(proposalId) {
Proposal storage proposal = proposals[proposalId];
require(block.timestamp >= proposal.startTime && block.timestamp <= proposal.endTime,
"Voting is not active for this proposal");
require(!proposal.hasVoted[msg.sender], "Already voted");
proposal.hasVoted[msg.sender] = true;
if (support) {
proposal.votesFor++;
} else {
proposal.votesAgainst++;
}
emit VoteCast(proposalId, msg.sender, support);
}
function finalizeProposal(uint256 proposalId) external validProposal(proposalId) {
Proposal storage proposal = proposals[proposalId];
require(block.timestamp > proposal.endTime, "Voting period not ended");
require(proposal.status == ProposalStatus.Active, "Proposal already finalized");
uint256 totalVotes = proposal.votesFor + proposal.votesAgainst;
uint256 quorumVotes = (totalVotes * 100) / QUORUM_PERCENTAGE;
if (proposal.votesFor > proposal.votesAgainst && totalVotes >= quorumVotes) {
proposal.status = ProposalStatus.Passed;
} else {
proposal.status = ProposalStatus.Rejected;
}
emit ProposalStatusChanged(proposalId, proposal.status);
}
function getProposalDetails(uint256 proposalId)
external
view
validProposal(proposalId)
returns (
address proposer,
string memory description,
uint256 votesFor,
uint256 votesAgainst,
ProposalStatus status
)
{
Proposal storage proposal = proposals[proposalId];
return (
proposal.proposer,
proposal.description,
proposal.votesFor,
proposal.votesAgainst,
proposal.status
);
}
}