GovernorPreventLateQuorum.sol 4.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. // SPDX-License-Identifier: MIT
  2. // OpenZeppelin Contracts (last updated v5.4.0-rc.0) (governance/extensions/GovernorPreventLateQuorum.sol)
  3. pragma solidity ^0.8.24;
  4. import {Governor} from "../Governor.sol";
  5. import {Math} from "../../utils/math/Math.sol";
  6. /**
  7. * @dev A module that ensures there is a minimum voting period after quorum is reached. This prevents a large voter from
  8. * swaying a vote and triggering quorum at the last minute, by ensuring there is always time for other voters to react
  9. * and try to oppose the decision.
  10. *
  11. * If a vote causes quorum to be reached, the proposal's voting period may be extended so that it does not end before at
  12. * least a specified time has passed (the "vote extension" parameter). This parameter can be set through a governance
  13. * proposal.
  14. */
  15. abstract contract GovernorPreventLateQuorum is Governor {
  16. uint48 private _voteExtension;
  17. mapping(uint256 proposalId => uint48) private _extendedDeadlines;
  18. /// @dev Emitted when a proposal deadline is pushed back due to reaching quorum late in its voting period.
  19. event ProposalExtended(uint256 indexed proposalId, uint64 extendedDeadline);
  20. /// @dev Emitted when the {lateQuorumVoteExtension} parameter is changed.
  21. event LateQuorumVoteExtensionSet(uint64 oldVoteExtension, uint64 newVoteExtension);
  22. /**
  23. * @dev Initializes the vote extension parameter: the time in either number of blocks or seconds (depending on the
  24. * governor clock mode) that is required to pass since the moment a proposal reaches quorum until its voting period
  25. * ends. If necessary the voting period will be extended beyond the one set during proposal creation.
  26. */
  27. constructor(uint48 initialVoteExtension) {
  28. _setLateQuorumVoteExtension(initialVoteExtension);
  29. }
  30. /**
  31. * @dev Returns the proposal deadline, which may have been extended beyond that set at proposal creation, if the
  32. * proposal reached quorum late in the voting period. See {Governor-proposalDeadline}.
  33. */
  34. function proposalDeadline(uint256 proposalId) public view virtual override returns (uint256) {
  35. return Math.max(super.proposalDeadline(proposalId), _extendedDeadlines[proposalId]);
  36. }
  37. /**
  38. * @dev Vote tally updated and detects if it caused quorum to be reached, potentially extending the voting period.
  39. *
  40. * May emit a {ProposalExtended} event.
  41. */
  42. function _tallyUpdated(uint256 proposalId) internal virtual override {
  43. super._tallyUpdated(proposalId);
  44. if (_extendedDeadlines[proposalId] == 0 && _quorumReached(proposalId)) {
  45. uint48 extendedDeadline = clock() + lateQuorumVoteExtension();
  46. if (extendedDeadline > proposalDeadline(proposalId)) {
  47. emit ProposalExtended(proposalId, extendedDeadline);
  48. }
  49. _extendedDeadlines[proposalId] = extendedDeadline;
  50. }
  51. }
  52. /**
  53. * @dev Returns the current value of the vote extension parameter: the number of blocks that are required to pass
  54. * from the time a proposal reaches quorum until its voting period ends.
  55. */
  56. function lateQuorumVoteExtension() public view virtual returns (uint48) {
  57. return _voteExtension;
  58. }
  59. /**
  60. * @dev Changes the {lateQuorumVoteExtension}. This operation can only be performed by the governance executor,
  61. * generally through a governance proposal.
  62. *
  63. * Emits a {LateQuorumVoteExtensionSet} event.
  64. */
  65. function setLateQuorumVoteExtension(uint48 newVoteExtension) public virtual onlyGovernance {
  66. _setLateQuorumVoteExtension(newVoteExtension);
  67. }
  68. /**
  69. * @dev Changes the {lateQuorumVoteExtension}. This is an internal function that can be exposed in a public function
  70. * like {setLateQuorumVoteExtension} if another access control mechanism is needed.
  71. *
  72. * Emits a {LateQuorumVoteExtensionSet} event.
  73. */
  74. function _setLateQuorumVoteExtension(uint48 newVoteExtension) internal virtual {
  75. emit LateQuorumVoteExtensionSet(_voteExtension, newVoteExtension);
  76. _voteExtension = newVoteExtension;
  77. }
  78. }