GovernorCountingSimple.sol 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. // SPDX-License-Identifier: MIT
  2. // OpenZeppelin Contracts (last updated v5.1.0) (governance/extensions/GovernorCountingSimple.sol)
  3. pragma solidity ^0.8.20;
  4. import {IGovernor, Governor} from "../Governor.sol";
  5. /**
  6. * @dev Extension of {Governor} for simple, 3 options, vote counting.
  7. */
  8. abstract contract GovernorCountingSimple is Governor {
  9. /**
  10. * @dev Supported vote types. Matches Governor Bravo ordering.
  11. */
  12. enum VoteType {
  13. Against,
  14. For,
  15. Abstain
  16. }
  17. struct ProposalVote {
  18. uint256 againstVotes;
  19. uint256 forVotes;
  20. uint256 abstainVotes;
  21. mapping(address voter => bool) hasVoted;
  22. }
  23. mapping(uint256 proposalId => ProposalVote) private _proposalVotes;
  24. /// @inheritdoc IGovernor
  25. // solhint-disable-next-line func-name-mixedcase
  26. function COUNTING_MODE() public pure virtual override returns (string memory) {
  27. return "support=bravo&quorum=for,abstain";
  28. }
  29. /// @inheritdoc IGovernor
  30. function hasVoted(uint256 proposalId, address account) public view virtual override returns (bool) {
  31. return _proposalVotes[proposalId].hasVoted[account];
  32. }
  33. /**
  34. * @dev Accessor to the internal vote counts.
  35. */
  36. function proposalVotes(
  37. uint256 proposalId
  38. ) public view virtual returns (uint256 againstVotes, uint256 forVotes, uint256 abstainVotes) {
  39. ProposalVote storage proposalVote = _proposalVotes[proposalId];
  40. return (proposalVote.againstVotes, proposalVote.forVotes, proposalVote.abstainVotes);
  41. }
  42. /// @inheritdoc Governor
  43. function _quorumReached(uint256 proposalId) internal view virtual override returns (bool) {
  44. ProposalVote storage proposalVote = _proposalVotes[proposalId];
  45. return quorum(proposalSnapshot(proposalId)) <= proposalVote.forVotes + proposalVote.abstainVotes;
  46. }
  47. /**
  48. * @dev See {Governor-_voteSucceeded}. In this module, the forVotes must be strictly over the againstVotes.
  49. */
  50. function _voteSucceeded(uint256 proposalId) internal view virtual override returns (bool) {
  51. ProposalVote storage proposalVote = _proposalVotes[proposalId];
  52. return proposalVote.forVotes > proposalVote.againstVotes;
  53. }
  54. /**
  55. * @dev See {Governor-_countVote}. In this module, the support follows the `VoteType` enum (from Governor Bravo).
  56. */
  57. function _countVote(
  58. uint256 proposalId,
  59. address account,
  60. uint8 support,
  61. uint256 totalWeight,
  62. bytes memory // params
  63. ) internal virtual override returns (uint256) {
  64. ProposalVote storage proposalVote = _proposalVotes[proposalId];
  65. if (proposalVote.hasVoted[account]) {
  66. revert GovernorAlreadyCastVote(account);
  67. }
  68. proposalVote.hasVoted[account] = true;
  69. if (support == uint8(VoteType.Against)) {
  70. proposalVote.againstVotes += totalWeight;
  71. } else if (support == uint8(VoteType.For)) {
  72. proposalVote.forVotes += totalWeight;
  73. } else if (support == uint8(VoteType.Abstain)) {
  74. proposalVote.abstainVotes += totalWeight;
  75. } else {
  76. revert GovernorInvalidVoteType();
  77. }
  78. return totalWeight;
  79. }
  80. }