citizen: implement Implement: Defines the main community governance contract
This commit is contained in:
parent
fab5ccc5f8
commit
f0bd7390e6
136
contracts/GovernanceContract.sol
Normal file
136
contracts/GovernanceContract.sol
Normal 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
|
||||
);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user