Background
I am building a governance system that uses a new ERC20 for voting and delegating and has a timelock on all actions. Our community already has a multisig of trusted stewards, so it would be nice to have the option to give the multisig some extra privileges like canceling a proposal or something, but that's not a must have and not related to the question at hand. I've thoroughly read through the governance docs, the governance contracts and have used the contracts wizard, and it seems obvious that the OS governance contracts, namely GovernorTimelockControl
and TimelockController
, are exactly what I need. However, I'm finding some confusing notes about those contracts in the docs. I have specific questions which you can see below, but it would also be sufficient just to see a complete generic example of how to use GovernorTimelockControl and TimelockController together (including how they are meant to be deployed in tandem and what to pass in for constructor args). It would also be great to see how I could deploy them in a way that allows our multisig to be a kind of admin that can step in when necessary, but again, not the most pressing issue.
Problem
In the docs I see
Setting up the TimelockController to have additional proposers besides the governor is very risky
which I interpret to mean that the GovernorTimelockControl contract should be the only proposer passed into the TimelockController constructor. That implies that the GovernorTimelockControl must be deployed first and TimelockController second. The problem is, the GovernorTimelockControl takes a TimelockController as a constructor arg. Chicken-or-the-egg problem. What's the intended way to deploy these contracts? The TimelockController proposers array seems like it cannot be updated after construction. I do see that GovernorTimelockControl has a function updateTimelock
, but only the current timelock can call it, so I still don't understand what to pass in at first.
-
Do I need to use CREATE2 to preocompute the address of the GovernorTimelockControl contract, deploy TimelockController first with that precomputed address in the proposers array, and finally deploy GovernorTimelockControl passing in the deployed TimelockController address? How else could I possibly deploy these contracts together?
-
I'm also wondering what should be passed in as the
executors
array in addition to theproposers
array, and whether it makes sense to include our multisig as a proposer or executor.
I also saw somewhere in the docs
A common use case is to position this TimelockController as the owner of a smart contract, with a multisig or a DAO as the sole proposer.
I'm surprised that the "common use case" has nothing to do with GovernorTimelockControl (GovernorTimelockControl is not Ownable, and as I said above it's not clear how to deploy them such that it is the sole proposer). I would really appreciate an example and more clear explanation about how the two should relate to each other. They seem like they were literally made for each other, and yet they also seem incompatible.
Can someone please help me make sense of this? Much appreciated!