136 lines
4.5 KiB
Solidity
136 lines
4.5 KiB
Solidity
// 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
|
|
);
|
|
}
|
|
} |