Skip to content

Commit

Permalink
Automatically merged updates to draft EIP(s) 2767 (ethereum#3114)
Browse files Browse the repository at this point in the history
Hi, I'm a bot! This change was automatically merged because:

 - It only modifies existing Draft or Last Call EIP(s)
 - The PR was approved or written by at least one author of each modified EIP
 - The build is passing
  • Loading branch information
zemse authored Nov 12, 2020
1 parent 81b5302 commit ad9aba7
Showing 1 changed file with 44 additions and 142 deletions.
186 changes: 44 additions & 142 deletions EIPS/eip-2767.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,16 @@ status: Draft
type: Standards Track
category: ERC
created: 2020-07-04
requires: 165, 173, 191
requires: 20, 165, 173
---

## Simple Summary

A standard interface for Governance contracts that administratively decentralize the ownership of smart contracts.
A standard for Governance contracts that holds the administrative ownership of other smart contracts with voting power distributed as `ERC-20` tokens.

## Abstract

The following standard allows for the implementation of a standard API for a Governance smart contract. This standard provides basic functionality for on-chain and off-chain governance inheriting equal or privileged voting rights. Existing `ERC-173` compatible contracts can upgrade from private key wallet ownership to a Governance smart contract. Smart contracts that use a Governance contract are more administratively decentralised and adhering to a standard API enables tools to populate governance information to dApp users.
The following standard defines the implementation of a standard API for a Governance smart contract based on `ERC-20`. Existing `ERC-173` compatible contracts can upgrade from private key wallet ownership to a Governance smart contract. Adhering to a standard API enables general tools to populate governance information of various projects, thus increasing transparency.

## Motivation

Expand All @@ -32,51 +32,33 @@ contract dApp {

Often, such administrative rights for a contract are written for maintenance purpose but users need to trust the owner. Rescue operations by an owner have raised questions on decentralised nature of the projects. Also, there is a possibility of compromise of an owner's private key.

At present, there are various implementation ideas for handling governance. Adhering to a standard API would enable general tools (like EtherScan) to populate governance information, thus increasing transparency to users. This can result in a wide adoption for contract governance.
At present, many governance implementations by ambitious projects need users to visit a specific UI to see governance information about their project. Some examples of live implementations having different API that does the same thing are [Compound Governance](https://github.com/compound-finance/compound-protocol/blob/master/contracts/Governance/GovernorAlpha.sol#L27), [Uniswap Governance](https://github.com/Uniswap/governance/blob/master/contracts/GovernorAlpha.sol#L27) and [Sushiswap Governance](https://github.com/sushiswap/sushiswap/blob/master/contracts/GovernorAlpha.sol#L45). It's just like if the ERC-20 standard wasn't finalized, then token projects would have their own block explorer. Adhering to a standard API would enable general tools (like Etherscan) to populate governance information, thus increasing transparency to users. Using widely popular `ERC-20` token as a governance token, existing tools built to work with `ERC-20` can already display voters. This can result in a wide adoption for contract governance over private key based ownership.

## Specification

#### Notes

- The following specifications use syntax from Solidity 0.6.0 (or above)
- Governor is the board member who has voting right.
- Power represents the voting privilege of a governor.

A contract that is compliant with `ERC-2767` shall implement the following interface:
A Governance contract that is compliant with `ERC-2767` shall implement the following interfaces:

```solidity
/// @title ERC-2767 Governance with Privileged Voting Rights
/// @dev ERC-165 InterfaceID: 0x4fe54581
interface ERC2767 {
/// @dev This emits when governor power changes
event GovernorPowerUpdated(address indexed governor, uint256 power);
/// @notice Gets the consensus power of the governor
/// @param _governor Address of the governor
/// @return The governor's voting power
function powerOf(address _governor) external view returns (uint256);
/// @notice Gets the sum of the power of all governors
/// @return Sum of the power of all governors
function totalPower() external view returns (uint256);
/// @title ERC-2767 Governance
/// @dev ERC-165 InterfaceID: 0xd8b04e0e
interface ERC2767 is ERC165 {
/// @notice Gets number votes required for achieving consensus
/// @return Required number of consensus votes
function required() external view returns (uint256);
/// @notice Updates governor statuses
/// @param _governor Governor address
/// @param _newPower New power for the governor
/// @dev Only Governance can call
function setGovernor(address _governor, uint256 _newPower) external;
/// @dev Should cost less than 30000 gas
/// @return Required number of votes for achieving consensus
function quorumVotes() external view returns (uint256);
/// @notice The address of the Governance ERC20 token
function token() external view returns (address);
}
```

Implementations that require equal governance rights between the governors can simply have equal power values for every governor.
### `ERC-20` Governance Token

An `ERC-2767` Governance Contract should reference an address through `token()` that implements `ERC-20` interface. `token()` is allowed to return self address (`address(this)`), if `ERC-20` functionalities are implemented in the same contract (one can consider checking out Diamond Standard [`ERC-2535`](https://eips.ethereum.org/EIPS/eip-2535) to optimise contract size).

There is a possibility that `totalPower()` changes rapidly due to adding or removing governors. This can result in having a fixed `required()` return value easier or difficult to achieve. Implementations can have custom logic that affect the return value of `required()`. For example the return value of `required()` can be changed by custom logic in order to maintain `51%` of `totalPower()`. So if more governors are added in such implementations, the `required()` return value would automatically take that into account.
Implementations are allowed to have varying `ERC-20`'s `totalSupply()` (through any standard of minting or burning). But having a fixed `quorumVotes()` return value in this case would cause required votes consensus in `%` with respect to `totalSupply()` to change. To automatically account for this, any custom logic under `quorumVotes()` is allowed to return for e.g. `51%` of `totalSupply()`.

### Interface Identification
### `ERC-165` Interface Identification

An `ERC-2767` Governance Contract should also implement `ERC-165`. This helps general tools to identify whether a contract is a `ERC-2767` Governance contract.

Expand All @@ -92,129 +74,49 @@ interface ERC165 {
}
```

### Transaction execution (Optional)

There are two optional interfaces for transaction execution: On-chain and Off-chain. A `ERC-2767` compatible governance contract can optionally implement one of them or both. The contract should specify the interfaceID(s) using `ERC-165`'s `supportsInterface` method.

#### On-chain

```solidity
/// @title ERC-2767 On-chain Governance
/// @dev ERC-165 InterfaceID: 0x947133b4
interface IGovernanceOnchain {
struct Transaction {
address destination;
uint256 value;
bytes data;
bool executed;
uint256 votes;
}
/// @dev Emits when a transaction is proposed
event TransactionCreated(uint256 indexed transactionId);
/// @dev Emits every time a governor confirms a transaction
event TransactionConfirmed(uint256 indexed transactionId);
/// @dev Emits whenever a governor takes back their confirmation
event TransactionRevoked(uint256 indexed transactionId);
/// @dev Emits when a transactions with enough confirmations is executed
event TransactionExecuted(uint256 indexed transactionId);
/// @notice Gets transaction parameters
/// @param _transactionId TransactionID
/// @return ABIV2 encoded Transaction struct
function getTransaction(uint256 _transactionId) external view returns (Transaction memory);
/// @notice Allows an governor to submit and confirm a transaction.
/// @param _destination Transaction target address, the governed contract
/// @param _value Transaction ether value
/// @param _data Transaction data payload
/// @return Returns transaction ID
function createTransaction(
address _destination,
uint256 _value,
bytes memory _data
) external returns (uint256);
/// @notice Allows a governor to confirm a transaction.
/// @param _transactionId Transaction ID
function confirmTransaction(uint256 _transactionId) external;
/// @notice Allows a governor to revoke a confirmation for a transaction
/// @param _transactionId Transaction ID
function revokeConfirmation(uint256 _transactionId) external;
/// @notice Calls the governed contract to perform administrative task
/// @param _transactionId Transaction ID
/// @dev Only Governance can call
function executeTransaction(uint256 _transactionId) external;
}
```

A governor proposes a transaction by calling `createTransaction` passing the parameters. Following this, rest of the governors can choose to confirm the transaction by calling `confirmTransaction`. If at later point of time, a governor wishes to take back their vote, they can call `revokeConfirmation`. Once a transaction reaches enough confirmations, it can be executed by calling `confirmTransaction`. The `confirmTransaction` method can internally call `executeTransaction` after it's primary logic if required votes have been registered.

#### Off-chain

```solidity
/// @title ERC-2767 Off-chain Governance
/// @dev ERC-165 InterfaceID: 0x32542713
interface IGovernanceOffchain {
/// @notice Get the transactions count
/// @dev To be used as nonce
/// @return The transactions count
function transactionsCount() external view returns (uint256);
/// @notice Calls the governed contract to perform an administrative task
/// @param _nonce Serial number of transaction
/// @param _destination Address of contract to make a call to, should be governed contract address
/// @param _data Input data in the transaction
/// @param _signatures Signatures of governors collected off chain
/// @dev The signatures are required to be sorted to prevent duplicates
/// @dev Only Governance can call
function executeTransaction(
uint256 _nonce,
address _destination,
bytes memory _data,
bytes[] memory _signatures
) external payable;
}
```

Anyone can take an initiative to execute a transaction by preparing a `ERC-191` signed data `0x 19 00 <20 bytes address> <32 bytes nonce> <20 bytes to-address> <input data>` and collect signatures from required governors. The contract logic should expect signatures to be sorted, this is to save the expenditure gas to prevent duplicate signatures. If signatures are sorted, valid, and the required number of them (or more), the governance contract will make a call to the governed contract to perform the administrative task.

## Rationale

The goals of this EIP have been the following:

- standardize API of Governance contracts for governed contracts.
- enable existing `ERC-173` ownership smart contracts to become administratively decentralised.
- Standardize API of Governance contracts to make it easy for analysis tools to be built.
- Encourage use of `ERC-20` based weighted governance over existing multi-sig (_generally limited to 50 max owners_) for big projects.
- Encourage existing `ERC-173` ownership smart contracts / projects to move to Governance based ownership by removing the effort needed to host custom UI for their project.
- Encourage availability of publicly audited governance contracts, just like `ERC-20` which anyone can use.
- Make it possible to utilize existing `ERC-20` tools for owners of governance token analysis.
- Make future protocols possible that need to interact with governances of multiple projects.
- Keep this EIP minimal and allow another EIPs to standardize any specific functionalities.

## Backwards Compatibility

Smart contracts that are `ERC-173` compliant can transfer their ownership to a Governance contract. This enables existing contracts to become compatible with `ERC-2767`.
Smart contracts that are `ERC-173` compliant can transfer their ownership to a Governance contract. This enables such contracts to become compatible with `ERC-2767` Governance.

However, there are some existing projects with governance implementations and most of them have custom APIs ([Compound Governance](https://github.com/compound-finance/compound-protocol/blob/master/contracts/Governance/GovernorAlpha.sol#L27), [Uniswap Governance](https://github.com/Uniswap/governance/blob/master/contracts/GovernorAlpha.sol#L27) and [Sushiswap Governance](https://github.com/sushiswap/sushiswap/blob/master/contracts/GovernorAlpha.sol#L45)), since a standard did not exist. Not having an `ERC-2767` compatible governance contract means only that general tools might not be able to populate their governance information without including some special code for the project.

For existing governance contracts to get compatible with `ERC-2767`:

However, there are some existing projects with governance implementations and most of them have custom APIs, since a standard did not exist. Such projects need to deploy a new governance contract and transfer ownership to it to be `ERC-2767` compatible. Not having an `ERC-2767` compatible governance contract means only that general tools might be able to populate their governance information.
1. Projects can deploy a new governance contract and transfer ownership to it to be `ERC-2767` compatible. This is suitable for those who use Multi-sig wallets for Governance.
2. It is understood that redeploying governance contracts would be a troublesome task, and contracts who already have functionality similar to `ERC-20` based (weighted votes) have a bit advanced way to avoid it. Basically, they can create a forwarder contract implements `ERC-2767` and forwards all calls to the actual non-standard methods. Projects can list the forwarder contract to display the information project's governance info without requiring any custom code in analysys tool, but this might have certain limitations depending on the project's existing governance implementation. Specification of forwarder contract is out of scope for this EIP and it may be addressed in another EIP if required.

<!-- ## Test Cases -->

## Implementation

The reference implementations are available in this [repository](https://github.com/zemse/contract-ownership-governance).

1. Governance Onchain with Equal Voting Rights ([Contract](https://github.com/zemse/contract-ownership-governance/blob/master/contracts/GovernanceOnchainEqual.sol), [Tests](https://github.com/zemse/contract-ownership-governance/blob/master/test/suites/OnchainEqual.test.ts))
2. Governance Offchain with Privileged Voting Rights ([Contract](https://github.com/zemse/contract-ownership-governance/blob/master/contracts/GovernanceOffchainPrivileged.sol), [Tests](https://github.com/zemse/contract-ownership-governance/blob/master/test/suites/OffchainPrivileged.test.ts))
The reference implementations are available in this [repository](https://github.com/zemse/contract-ownership-governance). Publicly audited implementations will be included in future.

## Security Considerations

The signatures in off-chain governance implementation should follow recommendations of `ERC-191`.
Implementers are free to choose between On-chain and Off-chain consensus. Exact specification is out of scope for this standard (open for other EIPs to standardize). However, this section mentions points that implementers can consider.

```
0x 19 00 <20 bytes governance address> <32 bytes nonce> <20 bytes to-address> <input data>.
```
#### On-chain

In such implementations, community can create transaction proposals and vote on it by sending on-chain transactions.

- OpenZeppelin Snapshots can be used to prevent double voting.

#### Off-chain

To prevent repeated signatures in the `signatures` array, it is required that caller of `executeTransaction` should sort the signatures based on increasing addresses.
- The signatures in off-chain governance implementation can follow recommendations of `ERC-191` or `ERC-712`.
- To prevent replaying signatures, it'd be best if executer is required to sort the signatures based on increasing addresses.

## Copyright

Expand Down

0 comments on commit ad9aba7

Please sign in to comment.