Skip to content

Commit

Permalink
Improve Governor documentation
Browse files Browse the repository at this point in the history
(cherry picked from commit 4ac1070)
  • Loading branch information
frangio committed Aug 17, 2021
1 parent bb2b687 commit e3cbfcd
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 25 deletions.
2 changes: 1 addition & 1 deletion contracts/governance/Governor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import "./IGovernor.sol";
/**
* @dev Core of the governance system, designed to be extended though various modules.
*
* This contract is abstract and requiers several function to be implemented in various modules:
* This contract is abstract and requires several function to be implemented in various modules:
*
* - A counting module must implement {quorum}, {_quorumReached}, {_voteSucceeded} and {_countVote}
* - A voting module must implement {getVotes}
Expand Down
6 changes: 3 additions & 3 deletions contracts/governance/IGovernor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ abstract contract IGovernor is IERC165 {

/**
* @notice module:user-config
* @dev Minimum number of cast voted requiered for a proposal to be successful.
* @dev Minimum number of cast voted required for a proposal to be successful.
*
* Note: The `blockNumber` parameter corresponds to the snaphot used for counting vote. This allows to scale the
* quroum depending on values such as the totalSupply of a token at this block (see {ERC20Votes}).
Expand Down Expand Up @@ -167,12 +167,12 @@ abstract contract IGovernor is IERC165 {
) public virtual returns (uint256 proposalId);

/**
* @dev Execute a successful proposal. This requiers the quorum to be reached, the vote to be successful, and the
* @dev Execute a successful proposal. This requires the quorum to be reached, the vote to be successful, and the
* deadline to be reached.
*
* Emits a {ProposalExecuted} event.
*
* Note: some module can modify the requierements for execution, for example by adding an additional timelock.
* Note: some module can modify the requirements for execution, for example by adding an additional timelock.
*/
function execute(
address[] memory targets,
Expand Down
59 changes: 39 additions & 20 deletions contracts/governance/README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -7,43 +7,56 @@ This directory includes primitives for on-chain governance.

== Governor

The {Governor} contract provides primitive to set an on-chain voting system similar to https://compound.finance/docs/governance[Compound's Governor Alpha & Bravo].
This modular system of Governor contracts allows the deployment on-chain voting protocols similar to https://compound.finance/docs/governance[Compound's Governor Alpha & Bravo] and beyond, through the ability to easily customize multiple aspects of the protocol.

Similarly to our other contracts, it is customizable through inheritance and comes with extensions:
[TIP]
====
For a guided experience, set up your Governor contract using https://wizard.openzeppelin.com/#governor[Contracts Wizard].
* {GovernorTimelockControl}: A {Governor} extension that performs executions through a {TimelockController}. This requires a successful proposal to be queued before then can be executed. The {TimelockController} will enforce a delay between the queueing and the execution. With this module, proposals are executed by the external {TimelockController} contract, which would have to hold the assets that are being governed.
For a written walkthrough, check out our guide on xref:ROOT:governance.adoc[How to set up on-chain governance].
====

* {GovernorTimelockCompound}: A {Governor} extension that performs executions through a compound https://github.com/compound-finance/compound-protocol/blob/master/contracts/Timelock.sol[`Timelock`]. This requires a successful proposal to be queued before then can be executed. The `Timelock` will enforce a delay between the queueing and the execution. With this module, proposals are executed by the external `Timelock` contract, which would have to hold the assets that are being governed.
* {Governor}: The core contract that contains all the logic and primitives. It is abstract and requires choosing one of each of the modules below, or custom ones.

* {GovernorCountingSimple}: A simple voting mechanism for {Governor} with support 3 vote options: Against, For and Abstain.
Votes modules determine the source of voting power, and sometimes quorum number.

* {GovernorVotes}: Binding to extract voting weight from an {ERC20Votes} token.
* {GovernorVotes}: Extracts voting weight from an {ERC20Votes} token.

* {GovernorVotesQuorumFraction}: Binding to extract voting weight from an {ERC20Votes} token and set the quorum as a fraction of the (snapshoted) total token supply.
* {GovernorVotesComp}: Extracts voting weight from a COMP-like or {ERC20VotesComp} token.

* {GovernorVotesComp}: Binding to extract voting weight from a Comp or {ERC20VotesComp} token.
* {GovernorVotesQuorumFraction}: Combines with `GovernorVotes` to set the quorum as a fraction of the total token supply.

In addition to modules, the {Governor} requires a few virtual functions to be implemented to your particular specifications:
Counting modules determine valid voting options.

* <<Governor-votingOffset-,`votingOffset()`>>: Delay (number of blocks), between the proposal, is submitted and the snapshot block used for voting. This can be used to enforce a delay after a proposal is published for users to buy tokens, or delegate their votes (default: 0).
* <<Governor-votingDuration-,`votingDuration()`>>: Delay (in seconds), between the proposal, is submitted and the vote ends.
* <<Governor-quorum-uint256-,`quorum(uint256 blockNumber)`>>: Quorum required for a proposal to be successful. This function includes a `blockNumber` argument so the quorum can adapt through time, for example, to follow a token's `totalSupply`.
* {GovernorCountingSimple}: Simple voting mechanism with 3 voting options: Against, For and Abstain.

Timelock extensions add a delay for governance decisions to be executed. The workflow is extended to require a `queue` step before execution. With these modules, proposals are executed by the external timelock contract, thus it is the timelock that has to hold the assets that are being governed.

* {GovernorTimelockControl}: Connects with an instance of {TimelockController}. Allows multiple proposers and executors, in addition to the Governor itself.

* {GovernorTimelockCompound}: Connects with an instance of Compound's https://github.com/compound-finance/compound-protocol/blob/master/contracts/Timelock.sol[`Timelock`] contract.

Other extensions can customize the behavior or interface in multiple ways.

Note: Function of the {Governor} contract does NOT include access control. If you want to restrict access (for example to require a minimum balance to submit a proposal), you should add these checks by overloading the particular functions. For security reasons, the {Governor-_cancel} method is internal, and you will have to expose it (which the right access control mechanism) yourself if this is a mechanism you need.
* {GovernorCompatibilityBravo}: Extends the interface to be fully `GovernorBravo`-compatible. Note that events are compatible regardless of whether this extension is included or not.

Events emitted by the {Governor} contract are compatible with Compound's `GovernorBravo`. Additionnaly, function compatibility can be added using the {GovernorCompatibilityBravo} compatibility layer. This layer includes a voting system but does not include token bindings. This layer also requiers a timelock module (either {GovernorTimelockControl} or {GovernorTimelockCompound}).
* {GovernorProposalThreshold}: Restricts proposals to delegates with a minimum voting power.

In addition to modules and extensions, the core contract requires a few virtual functions to be implemented to your particular specifications:

* <<Governor-votingDelay-,`votingDelay()`>>: Delay (in number of blocks) since the proposal is submitted until voting power is fixed and voting starts. This can be used to enforce a delay after a proposal is published for users to buy tokens, or delegate their votes.
* <<Governor-votingPeriod-,`votingPeriod()`>>: Delay (in number of blocks) since the proposal starts until voting ends.
* <<Governor-quorum-uint256-,`quorum(uint256 blockNumber)`>>: Quorum required for a proposal to be successful. This function includes a `blockNumber` argument so the quorum can adapt through time, for example, to follow a token's `totalSupply`.

NOTE: Functions of the `Governor` contract do not include access control. If you want to restrict access, you should add these checks by overloading the particular functions. Among these, {Governor-_cancel} is internal by default, and you will have to expose it (which the right access control mechanism) yourself if this function is needed.

=== Core

{{IGovernor}}

{{Governor}}

=== Extensions

{{GovernorTimelockControl}}

{{GovernorTimelockCompound}}
=== Modules

{{GovernorCountingSimple}}

Expand All @@ -53,7 +66,13 @@ Events emitted by the {Governor} contract are compatible with Compound's `Govern

{{GovernorVotesComp}}

=== Compatibility
=== Extensions

{{GovernorTimelockControl}}

{{GovernorTimelockCompound}}

{{GovernorProposalThreshold}}

{{GovernorCompatibilityBravo}}

Expand Down
2 changes: 1 addition & 1 deletion contracts/interfaces/README.adoc
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
= Interfaces

[.readme-notice]
NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/utils
NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/interfaces

== List of standardized interfaces
These interfaces are available as `.sol` files, and also as compiler `.json` ABI files (through the npm package). These
Expand Down
2 changes: 2 additions & 0 deletions docs/modules/ROOT/pages/governance.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

In this guide we will learn how OpenZeppelin’s Govenor contract works, how to set it up, and how to use it to create proposals, vote for them, and execute them, using tools provided by Ethers.js and Tally.

NOTE: Find detailed contract documentation at xref:api:governance.adoc[Governance API].

== Introduction

Decentralized protocols are in constant evolution from the moment they are publicly released. Often, the initial team retains control of this evolution in the first stages, but eventually delegates it to a community of stakeholders. The process by which this community makes decisions is called on-chain governance, and it has become a central component of decentralized protocols, fueling varied decisions such as parameter tweaking, smart contract upgrades, integrations with other protocols, treasury management, grants, etc.
Expand Down

0 comments on commit e3cbfcd

Please sign in to comment.