GovernorCountingSimple.sol 3.3 KB

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