GovernorPreventLateQuorum.sol 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. // SPDX-License-Identifier: MIT
  2. pragma solidity ^0.8.0;
  3. import "../Governor.sol";
  4. import "../../utils/math/Math.sol";
  5. /**
  6. * @dev A module that ensures there is a minimum voting period after quorum is reached. This prevents a large voter from
  7. * swaying a vote and triggering quorum at the last minute, by ensuring there is always time for other voters to react
  8. * and try to oppose the decision.
  9. *
  10. * If a vote causes quorum to be reached, the proposal's voting period may be extended so that it does not end before at
  11. * least a given number of blocks have passed (the "vote extension" parameter). This parameter can be set by the
  12. * governance executor (e.g. through a governance proposal).
  13. *
  14. * _Available since v4.5._
  15. */
  16. abstract contract GovernorPreventLateQuorum is Governor {
  17. using SafeCast for uint256;
  18. using Timers for Timers.BlockNumber;
  19. uint64 private _voteExtension;
  20. mapping(uint256 => Timers.BlockNumber) private _extendedDeadlines;
  21. /// @dev Emitted when a proposal deadline is pushed back due to reaching quorum late in its voting period.
  22. event ProposalExtended(uint256 indexed proposalId, uint64 extendedDeadline);
  23. /// @dev Emitted when the {lateQuorumVoteExtension} parameter is changed.
  24. event LateQuorumVoteExtensionSet(uint64 oldVoteExtension, uint64 newVoteExtension);
  25. /**
  26. * @dev Initializes the vote extension parameter: the number of blocks that are required to pass since a proposal
  27. * reaches quorum until its voting period ends. If necessary the voting period will be extended beyond the one set
  28. * at proposal creation.
  29. */
  30. constructor(uint64 initialVoteExtension) {
  31. _setLateQuorumVoteExtension(initialVoteExtension);
  32. }
  33. /**
  34. * @dev Returns the proposal deadline, which may have been extended beyond that set at proposal creation, if the
  35. * proposal reached quorum late in the voting period. See {Governor-proposalDeadline}.
  36. */
  37. function proposalDeadline(uint256 proposalId) public view virtual override returns (uint256) {
  38. return Math.max(super.proposalDeadline(proposalId), _extendedDeadlines[proposalId].getDeadline());
  39. }
  40. /**
  41. * @dev Casts a vote and detects if it caused quorum to be reached, potentially extending the voting period. See
  42. * {Governor-_castVote}.
  43. *
  44. * May emit a {ProposalExtended} event.
  45. */
  46. function _castVote(
  47. uint256 proposalId,
  48. address account,
  49. uint8 support,
  50. string memory reason
  51. ) internal virtual override returns (uint256) {
  52. uint256 result = super._castVote(proposalId, account, support, reason);
  53. Timers.BlockNumber storage extendedDeadline = _extendedDeadlines[proposalId];
  54. if (extendedDeadline.isUnset() && _quorumReached(proposalId)) {
  55. uint64 extendedDeadlineValue = block.number.toUint64() + lateQuorumVoteExtension();
  56. if (extendedDeadlineValue > proposalDeadline(proposalId)) {
  57. emit ProposalExtended(proposalId, extendedDeadlineValue);
  58. }
  59. extendedDeadline.setDeadline(extendedDeadlineValue);
  60. }
  61. return result;
  62. }
  63. /**
  64. * @dev Returns the current value of the vote extension parameter: the number of blocks that are required to pass
  65. * from the time a proposal reaches quorum until its voting period ends.
  66. */
  67. function lateQuorumVoteExtension() public view virtual returns (uint64) {
  68. return _voteExtension;
  69. }
  70. /**
  71. * @dev Changes the {lateQuorumVoteExtension}. This operation can only be performed by the governance executor,
  72. * generally through a governance proposal.
  73. *
  74. * Emits a {LateQuorumVoteExtensionSet} event.
  75. */
  76. function setLateQuorumVoteExtension(uint64 newVoteExtension) public virtual onlyGovernance {
  77. _setLateQuorumVoteExtension(newVoteExtension);
  78. }
  79. /**
  80. * @dev Changes the {lateQuorumVoteExtension}. This is an internal function that can be exposed in a public function
  81. * like {setLateQuorumVoteExtension} if another access control mechanism is needed.
  82. *
  83. * Emits a {LateQuorumVoteExtensionSet} event.
  84. */
  85. function _setLateQuorumVoteExtension(uint64 newVoteExtension) internal virtual {
  86. emit LateQuorumVoteExtensionSet(_voteExtension, newVoteExtension);
  87. _voteExtension = newVoteExtension;
  88. }
  89. }