GovernorCountingSimple.sol 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  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} 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 => bool) hasVoted;
  22. }
  23. mapping(uint256 => ProposalVote) private _proposalVotes;
  24. /**
  25. * @dev See {IGovernor-COUNTING_MODE}.
  26. */
  27. // solhint-disable-next-line func-name-mixedcase
  28. function COUNTING_MODE() public pure virtual override returns (string memory) {
  29. return "support=bravo&quorum=for,abstain";
  30. }
  31. /**
  32. * @dev See {IGovernor-hasVoted}.
  33. */
  34. function hasVoted(uint256 proposalId, address account) public view virtual override returns (bool) {
  35. return _proposalVotes[proposalId].hasVoted[account];
  36. }
  37. /**
  38. * @dev Accessor to the internal vote counts.
  39. */
  40. function proposalVotes(
  41. uint256 proposalId
  42. ) public view virtual returns (uint256 againstVotes, uint256 forVotes, uint256 abstainVotes) {
  43. ProposalVote storage proposalVote = _proposalVotes[proposalId];
  44. return (proposalVote.againstVotes, proposalVote.forVotes, proposalVote.abstainVotes);
  45. }
  46. /**
  47. * @dev See {Governor-_quorumReached}.
  48. */
  49. function _quorumReached(uint256 proposalId) internal view virtual override returns (bool) {
  50. ProposalVote storage proposalVote = _proposalVotes[proposalId];
  51. return quorum(proposalSnapshot(proposalId)) <= proposalVote.forVotes + proposalVote.abstainVotes;
  52. }
  53. /**
  54. * @dev See {Governor-_voteSucceeded}. In this module, the forVotes must be strictly over the againstVotes.
  55. */
  56. function _voteSucceeded(uint256 proposalId) internal view virtual override returns (bool) {
  57. ProposalVote storage proposalVote = _proposalVotes[proposalId];
  58. return proposalVote.forVotes > proposalVote.againstVotes;
  59. }
  60. /**
  61. * @dev See {Governor-_countVote}. In this module, the support follows the `VoteType` enum (from Governor Bravo).
  62. */
  63. function _countVote(
  64. uint256 proposalId,
  65. address account,
  66. uint8 support,
  67. uint256 weight,
  68. bytes memory // params
  69. ) internal virtual override {
  70. ProposalVote storage proposalVote = _proposalVotes[proposalId];
  71. if (proposalVote.hasVoted[account]) {
  72. revert GovernorAlreadyCastVote(account);
  73. }
  74. proposalVote.hasVoted[account] = true;
  75. if (support == uint8(VoteType.Against)) {
  76. proposalVote.againstVotes += weight;
  77. } else if (support == uint8(VoteType.For)) {
  78. proposalVote.forVotes += weight;
  79. } else if (support == uint8(VoteType.Abstain)) {
  80. proposalVote.abstainVotes += weight;
  81. } else {
  82. revert GovernorInvalidVoteType();
  83. }
  84. }
  85. }