The workshop was recorded on the 12th August 2021 and led by Nami Shah, Ethereum Developer at OpenZeppelin.
The workshop covers the following:
- The need for timelocks
- Setting up and deploying a timelock
- Create and execute a time-locked proposal
- The risks of timelocks
You can watch the video, view the slides, and learn how to use OpenZeppelin’s Defender to set up and deploy timelocks.
This workshop focuses on implementing timelocks via Defender Admin’s contract administration interface. A timelock is a smart contract that delays function calls of another smart contract after a predetermined amount of time has passed. Timelocks are mostly used in the context of governance to add a delay of administrative actions and are generally considered a strong indicator that a project is legitimate and demonstrates commitment to the project by project owners.
There are more than a few good reasons to implement a timelock:
- Project owners give up control to provide more guarantees to the community
- Timelocks allow investors to exit the protocol in time if necessary
- Project admins required to be transparent with stakeholders/investors
The diagram below represents a potentially malicious action where the owner of a contract can directly call a critical function with no accountability to their community. A classic example of this would be where a founder mints more tokens than agreed upon therefore devaluing the asset while getting rich in the process.
The next diagram shows timelock governance in play where stakeholders have given up ownership of the target contract to the timelock. As the timelock is in control of the contract, the contract creators can only act as a proposer, securing future changes. We explain timelock roles further in our Defender docs page.
ERC20 Creation and Deployment
To best demonstrate how timelocks can delay potentially malicious actions like minting in Defender, we begin by creating a fresh ERC20 token with specific properties. Quickly and easily build an ERC20 token with Contracts Wizard, our lighting-fast contract creation tool leveraging OpenZeppelin Contracts. Make sure the mintable feature is enabled and access control is set to ownable. This ensures that the owner of the contract is the only party able to call the mint function. To keep things simple, we set the premint value to 0. The ERC20 contract is then compiled and deployed using Remix and MetaMask.
Timelock Creation Inside Defender
Once the contract is deployed (Rinkby network was used for this workshop), we confirm the transaction on Etherscan and add the contract address into Defender Admin. If the contract is not verified on Etherscan, the ABI needs to be copied over manually.
By adding a multisig wallet to your timelock you can avoid the situation where a rouge developer is the only proposer in a protocol. As the proposal threshold will be greater than one requiring another signatory, we prevent this circumstance while adding an additional assurance to the community.
To create a multisig inside of Defender, click “Add Contract” then select the “Create Gnosis Safe” option. Add your owners and make sure that the threshold value, the number of owners needed to approve a transaction, is set to the appropriate value. In this workshop we added two owners and set the threshold value of two, meaning that all owners have to approve the proposal before it is executed.
To create a timelock inside of Defender, click “Add Contract” then select the “Create Timelock” option. For the proposer field, add the multisig address that we just created. In the executors field, we can either add individual addresses as executors or allow anyone to execute a proposal. In this workshop we allowed anyone to execute a proposal for simplicity’s sake. The administrator role is automatically assigned to the deployer and the timelock itself. Finally, a minimum delay period between a proposal being approved and executed must be specified.
Once the timelock is created we head over to the timelock admin action page and check that all roles are correct. To verify that all roles are correctly setup, we use the “query other functions” tool to run the
hasRole function on the assigned addresses. Once all roles are verified we use the timelock “new admin action” interface to remove the deployer role as an administrator so the timelock is the sole administrator. To do this we use the
renounceRole function selecting the admin role and our account. Because we as the deployer are still an administrator at this point, we can use the EOA execution strategy to execute this action. Finally make sure to name and describe the action before executing the admin action. At this point, the timelock is now self-governed and the only administrator.
Inside our timelock console, we can see a list of all proposals, their dates, and status. Our renouncement proposal should be the only item listed at this point. Once the proposal has executed, we use the “query other functions” tool to run the
hasRole function confirming that the administrator role was renounced. Next, we navigate to the ERC20 token contract, and again, using the “new admin action” interface we will run the
transferOwnership function to transfer the ownership of the token contract to the timelock.
This timelock is the only administrator and owner of the contract and is thus self-governed. We can test this by running the
mint function from our address which should result in an error. Now we change the execution strategy to “Timelock”, remove the EOA, add the multisig address, which is now a proposer on the timelock, and once again run the
mint function. As two approvals are needed for the timelock, we need to switch metamask accounts to run the approvals and confirm the proposal. After your specified delay passes, the
mint function will run and you will have executed a proposal using timelock governance! Defender will track the process between approval and execution within the timelock’s proposal feed.
Still there are risks associated with timelocks:
- All timelock contracts can be improperly setup
- A timelock contract may be controlled by a single administrator
- There can be a short delay between the transaction and its execution
- It is crucial to have make sure that there is at least one proposer and one executor to prevent the timelock contract from being locked down
- A contract controlled by a single proposer has all the power over the timelock and can submit whichever transaction they like
- Therefore, it is crucial for there to be multiple community-trusted proposers (in the form of a multisig is even better)
- A timelock doesn’t stop transactions from being confirmed, it simply broadcasts the action prior to its execution
- Malicious proposals, if not carefully monitored by the community, can still be executed after the delay
- Therefore, it’s also important for the delay between a proposal and its execution to be long enough for users to react. A typical delay would be between one and three days
We discuss these risks and more in our blog post Bypassing Smart Contract Timelocks.
Presentation slides available here.
Learn more about OpenZeppelin Wizard: https://wizard.openzeppelin.com
See the documentation: docs.openzeppelin.com/contracts
Sign up for a free OpenZeppelin Defender account: defender.openzeppelin.com