Actual script for governance deployment (#696)

* Renounce deployer timelock roles

* Add readme

* Remove obsoleted import

---------

Co-authored-by: elenadimitrova <elena@arenabg.com>
This commit is contained in:
duncancmt 2023-04-06 12:01:43 -04:00 committed by GitHub
parent 4e0b671bd8
commit 70590e3e56
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 82 additions and 12787 deletions

View File

@ -0,0 +1,74 @@
## Governance
This package contains contracts for the ZeroEx governance of 0x Protocol and Treasury.
## Production deployment
`ZRXWrappedToken` 0xfcfaf7834f134f5146dbb3274bab9bed4bafa917
`ZeroExVotesProxy` 0x9c766e51b46cbc1fa4f8b6718ed4a60ac9d591fb
`ZeroExVotes` 0x8d208c5514b98c5b9ceed650b02df2aeb1c73e6f
Protocol `ZeroExTimelock` 0xb6a1f58c5df9f13312639cddda0d128bf28cdd87
`ZeroExProtocolGovernor` 0xc256035fe8533f9ce362012a6ae0aefed4df30f4
Treasury `ZeroExTimelock` 0x0dcfb77a581bc8fe432e904643a5480cc183f38d
`ZeroExTreasuryGovernor` 0x4822cfc1e7699bdb9551bdfd3a838ee414bc2008
Security council 0x979BDb496e5f0A00af078b7a45F1E9E6bcff170F
## Design
This implementation fully decentralises governance of 0x Protocol and Treasury. This is enabled via a wrapped ZRX token and a Compound-like governors design. There are two separate governors for Protocol - `ZeroExProtocolGovernor` and Treasury - `ZeroExTreasuryGovernor` respectively working with two separate Timelock instances of the same contract implementation - `ZeroExTimelock`.
### Upgradability
`ZRXWrappedToken` , `ZeroExProtocolGovernor` and `ZeroExTreasuryGovernor` governors are non-upgradable by design. However the voting implementation the governors use - `ZeroExVotes` is upgradable and using the OZ `ERC1967Proxy`.
### Wrapped ZRX
wZRX will be issued 1-to-1 for ZRX. No locking/vesting mechanisms will exist between wZRX and ZRX and the two will be freely interchangeable. The ZRX token is non-upgradable and same will be valid for its wrapped equivalent.
The token supports delegation which allows a user to delegate their entire voting power to another account (which doesn't necessarily need to be a token holder). This is modelled on the standard OpenZeppelin `ERC20Votes` implementation. We have added logic for block number stamping delegators' balance changes stored in the `DelegateInfo.balanceLastUpdated` property. This block number information is sent in calls to `ZeroExVotes.moveVotingPower` in order to provide support for future upgrades to the vote power calculation.
Note that for consistency `block.number` is used for the governor settings, voting checkpoints and this delegators' balance last updated property while timelock logic for the governor uses block.timestamp.
### Governors' settings
Changing governors' settings for `votingDelay`, `votingPeriod` and `proposalThreshold` can be done via the normal proposal mechanism. Governors are deployed with the following initial settings:
| | voting delay | voting period | proposal threshold |
|-------------------|--------------|---------------|--------------------|
| Protocol governor | 2 days | 7 days | 1000000e18 |
| Treasury governor | 2 days | 7 days | 250000e18 |
This is using standard openzeppelin `GovernorSettings` implementation.
### Quorum
Quorum for Protocol is fixed at 10m (10000000e18) while for Treasury this is calculated as 10% of voting power of the total supply (see voting strategies below for quadratic voting power implementation specifics). The quorum calculations for Treasury are using OpenZeppelin's `GovernorVotesQuorumFraction`.
Note that in-place updates to the quorum are not supported and will need to go through a governance upgrade. Reasoning behind this can be found in this discussion https://forum.openzeppelin.com/t/quorum-default-behaviour-on-governors/34560.
### Voting strategies
The voting strategy will be linear 1-token-1-vote for Protocol and quadratic with threshold of 1000000e18 for Treasury (i.e. voting weight is linear up to 1m tokens and balance above that threshold is quadratic).
Worth noting is the `Checkpoint` struct design. For packing every `Checkpoint` into a single storage slot we are using the minimum uint type size for `votes` and `quadraticVotes` members, e.g.
```
struct Checkpoint {
uint32 fromBlock;
uint96 votes;
uint96 quadraticVotes;
}
```
since the maximum token supply is 1bn we can have maximum value for:
`votes` : 1bn *10^18 => can be stored in 90 bits
`quadraticVotes` : due to the likelihood of threshold changing and potentially bringing it closer to a linear vote, we are preemptively keeping this to the same size as linear votes slot.
### Time locks
Governance proposals are subject to a 3 days delay for Protocol and 2 days for Treasury. This delay allows Security Council time to review passed proposals and take action where needed.
### Security Council
The concept of a Security council is introduced which allows a multisig of security council members to cancel a proposal on the treasury or protocol governors and also rollback the protocol to an earlier version.
When no security council is assigned the following apply:
- ongoing proposals can still be voted on
- new proposals cannot be created - except assignSecurityCouncil
- expired proposals that are successful cannot be queued - excepted assignSecurityCouncil
There is a provision for the governors to have different security council set although initially these are the same.

File diff suppressed because one or more lines are too long

View File

@ -14,20 +14,20 @@ import "../src/ZeroExProtocolGovernor.sol";
import "../src/ZeroExTreasuryGovernor.sol"; import "../src/ZeroExTreasuryGovernor.sol";
contract Deploy is Script { contract Deploy is Script {
address internal constant DEPLOYER = 0xEf37aD2BACD70119F141140f7B5E46Cd53a65fc4;
address internal constant ZRX_TOKEN = 0xE41d2489571d322189246DaFA5ebDe1F4699F498; address internal constant ZRX_TOKEN = 0xE41d2489571d322189246DaFA5ebDe1F4699F498;
address internal constant TREASURY = 0x0bB1810061C2f5b2088054eE184E6C79e1591101; address internal constant TREASURY = 0x0bB1810061C2f5b2088054eE184E6C79e1591101;
address internal constant EXCHANGE = 0xDef1C0ded9bec7F1a1670819833240f027b25EfF; address internal constant EXCHANGE = 0xDef1C0ded9bec7F1a1670819833240f027b25EfF;
address payable internal constant SECURITY_COUNCIL = payable(DEPLOYER); address payable internal constant SECURITY_COUNCIL = payable(0x979BDb496e5f0A00af078b7a45F1E9E6bcff170F);
uint256 internal constant QUADRATIC_THRESHOLD = 1000000e18; uint256 internal constant QUADRATIC_THRESHOLD = 1000000e18;
function setUp() public {} function setUp() public {}
function run() external { function run() external {
vm.startBroadcast(vm.envAddress("DEPLOYER")); address deployer = vm.envAddress("DEPLOYER");
vm.startBroadcast(deployer);
console2.log("Zrx Token", ZRX_TOKEN); console2.log("Zrx Token", ZRX_TOKEN);
address wTokenPrediction = predict(DEPLOYER, vm.getNonce(DEPLOYER) + 2); address wTokenPrediction = predict(deployer, vm.getNonce(deployer) + 2);
ZeroExVotes votesImpl = new ZeroExVotes(wTokenPrediction, QUADRATIC_THRESHOLD); ZeroExVotes votesImpl = new ZeroExVotes(wTokenPrediction, QUADRATIC_THRESHOLD);
ERC1967Proxy votesProxy = new ERC1967Proxy(address(votesImpl), abi.encodeCall(votesImpl.initialize, ())); ERC1967Proxy votesProxy = new ERC1967Proxy(address(votesImpl), abi.encodeCall(votesImpl.initialize, ()));
ZRXWrappedToken wToken = new ZRXWrappedToken(IERC20(ZRX_TOKEN), ZeroExVotes(address(votesProxy))); ZRXWrappedToken wToken = new ZRXWrappedToken(IERC20(ZRX_TOKEN), ZeroExVotes(address(votesProxy)));
@ -41,7 +41,7 @@ contract Deploy is Script {
address[] memory proposers = new address[](0); address[] memory proposers = new address[](0);
address[] memory executors = new address[](0); address[] memory executors = new address[](0);
ZeroExTimelock protocolTimelock = new ZeroExTimelock(3 days, proposers, executors, DEPLOYER); ZeroExTimelock protocolTimelock = new ZeroExTimelock(3 days, proposers, executors, deployer);
console2.log("Protocol timelock", address(protocolTimelock)); console2.log("Protocol timelock", address(protocolTimelock));
ZeroExProtocolGovernor protocolGovernor = new ZeroExProtocolGovernor( ZeroExProtocolGovernor protocolGovernor = new ZeroExProtocolGovernor(
@ -52,9 +52,10 @@ contract Deploy is Script {
protocolTimelock.grantRole(protocolTimelock.PROPOSER_ROLE(), address(protocolGovernor)); protocolTimelock.grantRole(protocolTimelock.PROPOSER_ROLE(), address(protocolGovernor));
protocolTimelock.grantRole(protocolTimelock.EXECUTOR_ROLE(), address(protocolGovernor)); protocolTimelock.grantRole(protocolTimelock.EXECUTOR_ROLE(), address(protocolGovernor));
protocolTimelock.grantRole(protocolTimelock.CANCELLER_ROLE(), address(protocolGovernor)); protocolTimelock.grantRole(protocolTimelock.CANCELLER_ROLE(), address(protocolGovernor));
protocolTimelock.renounceRole(protocolTimelock.TIMELOCK_ADMIN_ROLE(), deployer);
console2.log("Protocol governor", address(protocolGovernor)); console2.log("Protocol governor", address(protocolGovernor));
ZeroExTimelock treasuryTimelock = new ZeroExTimelock(2 days, proposers, executors, DEPLOYER); ZeroExTimelock treasuryTimelock = new ZeroExTimelock(2 days, proposers, executors, deployer);
console2.log("Treasury timelock", address(treasuryTimelock)); console2.log("Treasury timelock", address(treasuryTimelock));
ZeroExTreasuryGovernor treasuryGovernor = new ZeroExTreasuryGovernor( ZeroExTreasuryGovernor treasuryGovernor = new ZeroExTreasuryGovernor(
@ -66,6 +67,7 @@ contract Deploy is Script {
treasuryTimelock.grantRole(treasuryTimelock.PROPOSER_ROLE(), address(treasuryGovernor)); treasuryTimelock.grantRole(treasuryTimelock.PROPOSER_ROLE(), address(treasuryGovernor));
treasuryTimelock.grantRole(treasuryTimelock.EXECUTOR_ROLE(), address(treasuryGovernor)); treasuryTimelock.grantRole(treasuryTimelock.EXECUTOR_ROLE(), address(treasuryGovernor));
treasuryTimelock.grantRole(treasuryTimelock.CANCELLER_ROLE(), address(treasuryGovernor)); treasuryTimelock.grantRole(treasuryTimelock.CANCELLER_ROLE(), address(treasuryGovernor));
treasuryTimelock.renounceRole(treasuryTimelock.TIMELOCK_ADMIN_ROLE(), deployer);
console2.log("Treasury governor", address(treasuryGovernor)); console2.log("Treasury governor", address(treasuryGovernor));
console2.log(unicode"0x governance deployed successfully 🎉"); console2.log(unicode"0x governance deployed successfully 🎉");
vm.stopBroadcast(); vm.stopBroadcast();