GovernorTimelockCompoundUpgradeable.sol 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. // SPDX-License-Identifier: MIT
  2. // OpenZeppelin Contracts v4.4.1 (governance/extensions/GovernorTimelockCompound.sol)
  3. pragma solidity ^0.8.0;
  4. import "./IGovernorTimelockUpgradeable.sol";
  5. import "../GovernorUpgradeable.sol";
  6. import "../../utils/math/SafeCastUpgradeable.sol";
  7. import "../../proxy/utils/Initializable.sol";
  8. /**
  9. * https://github.com/compound-finance/compound-protocol/blob/master/contracts/Timelock.sol[Compound's timelock] interface
  10. */
  11. interface ICompoundTimelockUpgradeable {
  12. receive() external payable;
  13. // solhint-disable-next-line func-name-mixedcase
  14. function GRACE_PERIOD() external view returns (uint256);
  15. // solhint-disable-next-line func-name-mixedcase
  16. function MINIMUM_DELAY() external view returns (uint256);
  17. // solhint-disable-next-line func-name-mixedcase
  18. function MAXIMUM_DELAY() external view returns (uint256);
  19. function admin() external view returns (address);
  20. function pendingAdmin() external view returns (address);
  21. function delay() external view returns (uint256);
  22. function queuedTransactions(bytes32) external view returns (bool);
  23. function setDelay(uint256) external;
  24. function acceptAdmin() external;
  25. function setPendingAdmin(address) external;
  26. function queueTransaction(
  27. address target,
  28. uint256 value,
  29. string memory signature,
  30. bytes memory data,
  31. uint256 eta
  32. ) external returns (bytes32);
  33. function cancelTransaction(
  34. address target,
  35. uint256 value,
  36. string memory signature,
  37. bytes memory data,
  38. uint256 eta
  39. ) external;
  40. function executeTransaction(
  41. address target,
  42. uint256 value,
  43. string memory signature,
  44. bytes memory data,
  45. uint256 eta
  46. ) external payable returns (bytes memory);
  47. }
  48. /**
  49. * @dev Extension of {Governor} that binds the execution process to a Compound Timelock. This adds a delay, enforced by
  50. * the external timelock to all successful proposal (in addition to the voting duration). The {Governor} needs to be
  51. * the admin of the timelock for any operation to be performed. A public, unrestricted,
  52. * {GovernorTimelockCompound-__acceptAdmin} is available to accept ownership of the timelock.
  53. *
  54. * Using this model means the proposal will be operated by the {TimelockController} and not by the {Governor}. Thus,
  55. * the assets and permissions must be attached to the {TimelockController}. Any asset sent to the {Governor} will be
  56. * inaccessible.
  57. *
  58. * _Available since v4.3._
  59. */
  60. abstract contract GovernorTimelockCompoundUpgradeable is Initializable, IGovernorTimelockUpgradeable, GovernorUpgradeable {
  61. using SafeCastUpgradeable for uint256;
  62. using TimersUpgradeable for TimersUpgradeable.Timestamp;
  63. struct ProposalTimelock {
  64. TimersUpgradeable.Timestamp timer;
  65. }
  66. ICompoundTimelockUpgradeable private _timelock;
  67. mapping(uint256 => ProposalTimelock) private _proposalTimelocks;
  68. /**
  69. * @dev Emitted when the timelock controller used for proposal execution is modified.
  70. */
  71. event TimelockChange(address oldTimelock, address newTimelock);
  72. /**
  73. * @dev Set the timelock.
  74. */
  75. function __GovernorTimelockCompound_init(ICompoundTimelockUpgradeable timelockAddress) internal onlyInitializing {
  76. __Context_init_unchained();
  77. __ERC165_init_unchained();
  78. __IGovernor_init_unchained();
  79. __IGovernorTimelock_init_unchained();
  80. __GovernorTimelockCompound_init_unchained(timelockAddress);
  81. }
  82. function __GovernorTimelockCompound_init_unchained(ICompoundTimelockUpgradeable timelockAddress) internal onlyInitializing {
  83. _updateTimelock(timelockAddress);
  84. }
  85. /**
  86. * @dev See {IERC165-supportsInterface}.
  87. */
  88. function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165Upgradeable, GovernorUpgradeable) returns (bool) {
  89. return interfaceId == type(IGovernorTimelockUpgradeable).interfaceId || super.supportsInterface(interfaceId);
  90. }
  91. /**
  92. * @dev Overriden version of the {Governor-state} function with added support for the `Queued` and `Expired` status.
  93. */
  94. function state(uint256 proposalId) public view virtual override(IGovernorUpgradeable, GovernorUpgradeable) returns (ProposalState) {
  95. ProposalState status = super.state(proposalId);
  96. if (status != ProposalState.Succeeded) {
  97. return status;
  98. }
  99. uint256 eta = proposalEta(proposalId);
  100. if (eta == 0) {
  101. return status;
  102. } else if (block.timestamp >= eta + _timelock.GRACE_PERIOD()) {
  103. return ProposalState.Expired;
  104. } else {
  105. return ProposalState.Queued;
  106. }
  107. }
  108. /**
  109. * @dev Public accessor to check the address of the timelock
  110. */
  111. function timelock() public view virtual override returns (address) {
  112. return address(_timelock);
  113. }
  114. /**
  115. * @dev Public accessor to check the eta of a queued proposal
  116. */
  117. function proposalEta(uint256 proposalId) public view virtual override returns (uint256) {
  118. return _proposalTimelocks[proposalId].timer.getDeadline();
  119. }
  120. /**
  121. * @dev Function to queue a proposal to the timelock.
  122. */
  123. function queue(
  124. address[] memory targets,
  125. uint256[] memory values,
  126. bytes[] memory calldatas,
  127. bytes32 descriptionHash
  128. ) public virtual override returns (uint256) {
  129. uint256 proposalId = hashProposal(targets, values, calldatas, descriptionHash);
  130. require(state(proposalId) == ProposalState.Succeeded, "Governor: proposal not successful");
  131. uint256 eta = block.timestamp + _timelock.delay();
  132. _proposalTimelocks[proposalId].timer.setDeadline(eta.toUint64());
  133. for (uint256 i = 0; i < targets.length; ++i) {
  134. require(
  135. !_timelock.queuedTransactions(keccak256(abi.encode(targets[i], values[i], "", calldatas[i], eta))),
  136. "GovernorTimelockCompound: identical proposal action already queued"
  137. );
  138. _timelock.queueTransaction(targets[i], values[i], "", calldatas[i], eta);
  139. }
  140. emit ProposalQueued(proposalId, eta);
  141. return proposalId;
  142. }
  143. /**
  144. * @dev Overriden execute function that run the already queued proposal through the timelock.
  145. */
  146. function _execute(
  147. uint256 proposalId,
  148. address[] memory targets,
  149. uint256[] memory values,
  150. bytes[] memory calldatas,
  151. bytes32 /*descriptionHash*/
  152. ) internal virtual override {
  153. uint256 eta = proposalEta(proposalId);
  154. require(eta > 0, "GovernorTimelockCompound: proposal not yet queued");
  155. AddressUpgradeable.sendValue(payable(_timelock), msg.value);
  156. for (uint256 i = 0; i < targets.length; ++i) {
  157. _timelock.executeTransaction(targets[i], values[i], "", calldatas[i], eta);
  158. }
  159. }
  160. /**
  161. * @dev Overriden version of the {Governor-_cancel} function to cancel the timelocked proposal if it as already
  162. * been queued.
  163. */
  164. function _cancel(
  165. address[] memory targets,
  166. uint256[] memory values,
  167. bytes[] memory calldatas,
  168. bytes32 descriptionHash
  169. ) internal virtual override returns (uint256) {
  170. uint256 proposalId = super._cancel(targets, values, calldatas, descriptionHash);
  171. uint256 eta = proposalEta(proposalId);
  172. if (eta > 0) {
  173. for (uint256 i = 0; i < targets.length; ++i) {
  174. _timelock.cancelTransaction(targets[i], values[i], "", calldatas[i], eta);
  175. }
  176. _proposalTimelocks[proposalId].timer.reset();
  177. }
  178. return proposalId;
  179. }
  180. /**
  181. * @dev Address through which the governor executes action. In this case, the timelock.
  182. */
  183. function _executor() internal view virtual override returns (address) {
  184. return address(_timelock);
  185. }
  186. /**
  187. * @dev Accept admin right over the timelock.
  188. */
  189. // solhint-disable-next-line private-vars-leading-underscore
  190. function __acceptAdmin() public {
  191. _timelock.acceptAdmin();
  192. }
  193. /**
  194. * @dev Public endpoint to update the underlying timelock instance. Restricted to the timelock itself, so updates
  195. * must be proposed, scheduled and executed using the {Governor} workflow.
  196. *
  197. * For security reason, the timelock must be handed over to another admin before setting up a new one. The two
  198. * operations (hand over the timelock) and do the update can be batched in a single proposal.
  199. *
  200. * Note that if the timelock admin has been handed over in a previous operation, we refuse updates made through the
  201. * timelock if admin of the timelock has already been accepted and the operation is executed outside the scope of
  202. * governance.
  203. */
  204. function updateTimelock(ICompoundTimelockUpgradeable newTimelock) external virtual onlyGovernance {
  205. _updateTimelock(newTimelock);
  206. }
  207. function _updateTimelock(ICompoundTimelockUpgradeable newTimelock) private {
  208. emit TimelockChange(address(_timelock), address(newTimelock));
  209. _timelock = newTimelock;
  210. }
  211. uint256[48] private __gap;
  212. }