citizen: implement Implement: Defines the main community governance contract
Some checks are pending
CI / build-and-test (push) Waiting to run
CI / slither (push) Waiting to run

This commit is contained in:
sourcebridge_42 2026-04-19 09:09:36 +00:00
parent fab5ccc5f8
commit f0bd7390e6

View File

@ -0,0 +1,136 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import "./interfaces/IGovernance.sol";
import "./VotingContract.sol";
contract GovernanceContract is IGovernance {
struct Proposal {
address proposer;
string description;
bytes32 proposalHash;
uint256 votingStartTime;
uint256 votingEndTime;
ProposalStatus status;
uint256 totalVotesFor;
uint256 totalVotesAgainst;
mapping(address => bool) hasVoted;
}
enum ProposalStatus {
Pending,
Active,
Passed,
Rejected,
Executed
}
VotingContract public votingContract;
mapping(uint256 => Proposal) public proposals;
uint256 public proposalCount;
uint256 public constant VOTING_PERIOD = 7 days;
uint256 public constant QUORUM_PERCENTAGE = 30;
uint256 public constant PASS_THRESHOLD_PERCENTAGE = 50;
event ProposalCreated(
uint256 indexed proposalId,
address indexed proposer,
string description
);
event ProposalVoted(
uint256 indexed proposalId,
address indexed voter,
bool support
);
event ProposalStatusChanged(
uint256 indexed proposalId,
ProposalStatus newStatus
);
constructor(address _votingContractAddress) {
require(_votingContractAddress != address(0), "Invalid voting contract address");
votingContract = VotingContract(_votingContractAddress);
}
function createProposal(string memory _description) external returns (uint256) {
require(bytes(_description).length > 0, "Description cannot be empty");
uint256 proposalId = proposalCount++;
Proposal storage newProposal = proposals[proposalId];
newProposal.proposer = msg.sender;
newProposal.description = _description;
newProposal.proposalHash = keccak256(abi.encodePacked(_description, block.timestamp, msg.sender));
newProposal.votingStartTime = block.timestamp;
newProposal.votingEndTime = block.timestamp + VOTING_PERIOD;
newProposal.status = ProposalStatus.Active;
emit ProposalCreated(proposalId, msg.sender, _description);
return proposalId;
}
function vote(uint256 _proposalId, bool _support) external {
Proposal storage proposal = proposals[_proposalId];
require(proposal.status == ProposalStatus.Active, "Proposal not active");
require(block.timestamp <= proposal.votingEndTime, "Voting period has ended");
require(!proposal.hasVoted[msg.sender], "Already voted");
proposal.hasVoted[msg.sender] = true;
if (_support) {
proposal.totalVotesFor += votingContract.getVotingPower(msg.sender);
} else {
proposal.totalVotesAgainst += votingContract.getVotingPower(msg.sender);
}
emit ProposalVoted(_proposalId, msg.sender, _support);
}
function finalizeProposal(uint256 _proposalId) external {
Proposal storage proposal = proposals[_proposalId];
require(block.timestamp > proposal.votingEndTime, "Voting period not ended");
require(proposal.status == ProposalStatus.Active, "Proposal already finalized");
uint256 totalVotes = proposal.totalVotesFor + proposal.totalVotesAgainst;
uint256 quorumVotes = (votingContract.getTotalVotingPower() * QUORUM_PERCENTAGE) / 100;
if (totalVotes >= quorumVotes) {
uint256 supportPercentage = (proposal.totalVotesFor * 100) / totalVotes;
if (supportPercentage >= PASS_THRESHOLD_PERCENTAGE) {
proposal.status = ProposalStatus.Passed;
} else {
proposal.status = ProposalStatus.Rejected;
}
} else {
proposal.status = ProposalStatus.Rejected;
}
emit ProposalStatusChanged(_proposalId, proposal.status);
}
function getProposalDetails(uint256 _proposalId) external view returns (
address proposer,
string memory description,
uint256 votingStartTime,
uint256 votingEndTime,
ProposalStatus status,
uint256 totalVotesFor,
uint256 totalVotesAgainst
) {
Proposal storage proposal = proposals[_proposalId];
return (
proposal.proposer,
proposal.description,
proposal.votingStartTime,
proposal.votingEndTime,
proposal.status,
proposal.totalVotesFor,
proposal.totalVotesAgainst
);
}
}