This guide focuses on showcasing battle-tested practices and recommended patterns to implement safer and more robust on-chain governance smart contracts. This content was originally part of a workshop recorded on the 16th of September 2021 and led by Martin Abbatemarco, Security Researcher at OpenZeppelin. It is the fourth workshop in a series that covers multiple topics around secure development of smart contracts.
In these guidelines, we cover the following:
- The need for on-chain governance.
- Common use cases and battle-tested mechanics in governance systems.
- Relevant security pitfalls in the governance of smart contracts.
- Must-follow development practices to implement safe on-chain governance mechanisms.
Governance in smart contracts
In the journey towards unstoppable decentralized applications, more projects are looking to integrate governance modules into their smart contract systems. Security is paramount for this type of contracts as you do not want governance powers falling in the wrong hands.
In general, governance modules are a set of smart contracts that allow a community to influence an on-chain governance system. Some initial questions a smart contract auditor may ask to better understand a governance module could include:
- Who participates in the decision-making process?
- How do they participate?
- What kind of actions can they take?
- What components of the system can be impacted by governance decisions?
- Are these decisions binding?
- Do they take place immediately?
- How are governance powers distributed among participants? Are there any roles?
- Are there privileged accounts with enough powers to overrule governance decisions? Could they bypass the governance process altogether?
- What are the relevant off-chain processes that participants should follow?
It is likely that each mainnet project would have different answers to these questions. Governance comes in multiple flavors, and each implementation can have particular value propositions worth exploring. At the end of the day, a system should be free to self-determine how it wants to be governed.
Still, if we consider the matter from a more neutral security standpoint, there are relevant practices worth following to mitigate security risks and learnings to integrate from past mistakes.
The reality today is that most projects are just starting to figure out how to do on-chain governance. You can find an overview of the governance features that the community is currently experimenting with in Balancer’s documentation.
Features and practices in on-chain governance modules are rapidly evolving and mutating as projects figure out their community’s needs. This is not only true for specific technicalities of smart contract implementations, but also for more high-level matters around tooling, processes, and risks. Hence it’s not straightforward to provide fundamental and evergreen security guidelines that will apply to all projects in the space.
Nonetheless, a recurring idea throughout this series is “learning from others”. Of course, in governance too we can learn from others by taking a look at some of the most popular and battle-tested projects in Ethereum and extracting insights, learnings, and recommendations from their practices. Note that our analysis does not aim to be exhaustive, we will not cover every single feature of each governance module. On top of that, some features or security-related practices are repeated across projects – in those cases we won’t highlight the practice multiple times.
Moreover, the article will not teach you the specific mechanics to participate in these governance systems. You can refer to the official docs for that. Instead, we are going to cover topics that from a security standpoint make sense to highlight. We want the guidelines to be agnostistic to implementation details so we will approach ideas from a high-level view referring to off-chain processes, documentation, roles and threats. Still, some specific implementations will be linked when necessary.
As a final remark, remember that these systems tend to evolve and change quickly over time. In fact, probably none of the examples we will showcase here started out as we will show them. They have evolved, matured, and learned over multiple iterations and will continue doing so. Therefore, many of the details we are about to describe might become outdated some time after the date of publication. Make sure to always check each protocol’s documentation for the latest information on this topic.
The mechanics for governance are implemented in a handful of contracts: the COMP token, Governor Bravo (with its proxy and implementation), and the Timelock. If you are interested in the specifics of the implementation, you can refer to the open-source code available at https://github.com/compound-finance/compound-protocol. Here, we will highlight some aspects of this architecture:
- Upgrades: The Governor Bravo contract implements the core mechanics of this governance module. It’s an upgradeable contract following the usual proxy-based pattern. This provides the needed flexibility for an ever-evolving governance contract that will be able to adapt to future community needs (or fixing bugs). Being able to perform upgrades without having to change the address of the contract can be a helpful feature, so as to avoid potentially breaking integrations with the growing landscape of community governance tools.
- Administrative powers: Secure access controls play a significant role in the security of governance modules, usually having sensitive parameters. In the case of Compound’s implementation of the Governor Bravo contract, it allows an administrator account to change a number of sensitive parameters: the voting period, the proposal threshold, and the voting delay. Note that the administrator account is currently the Timelock contract, so changes to governance itself are time-delayed. Moreover, these powers can be transferred using the offer–accept pattern.
- Flash-loan protections: To prevent flash-loans of governance tokens to negatively affect governance dynamics, the Governor contract measures voting power at previous blocks – never at the current block (see here and here and here). By now this has become a common practice that you’ll notice in many other similar implementations of governance modules.
- Delegation of voting power: A feature that is becoming increasingly mainstream in governance modules is the ability to delegating voting power. In the case of the Compound Protocol, you will find this implemented in the COMP token. This feature allows less engaged users to transfer the power of their governance tokens to trusted stakeholders that are more involved in the day-to-day governance process, without losing exposure to the actual tokens.
There are two additional features worth highlighting. For that, let us introduce two new components into the previous diagram: the community multisig (deployed here) and whitelisted proposers.
- Community multisig: Some changes over the Compound Protocol do not go through governance. Instead, they are executed by a multisig wallet. This is limited to a set of specific sensitive changes in the Compound protocol, which could be applied rapidly without needing to rely on the formal governance processes. As we will see, this is not the only protocol that allows a set of trusted actors to overrule governance in certain aspects.
- Whitelisted proposers: It was recently decided to allow a set of accounts to propose changes without requiring them to delegate their COMP tokens in advance. On the one hand, this feature should reduce barriers to entry and foster the participation of developers willing to advance the governed protocol, avoiding scenarios where the protocol becomes stagnated. On the other hand, it grants additional powers to trusted actors that if rogue, could spam the governance system.
For more information on the Compound Protocol’s governance, please refer to the official documentation.
UNI is the governance token behind the Uniswap protocol. At the moment of writing, Uniswap’s governance architecture may resemble that of the Compound Protocol. It was recently migrated from the Governor Alpha contract to the Bravo version, following in the Compound Protocol’s footsteps. Several of the previous points (use of timelocks, delegation of voting power, flash-loan protection, upgrades) apply here as well, so we will not repeat them. Do note that in this case, there are no community multisigs nor whitelisted proposers (at the time of publication).
One interesting point that we should highlight about Uniswap is their use of external documentation to present “adversarial circumstances”. In the documentation, the community can find different scenarios that could potentially put Uniswap’s governance at risk and how the team understands mitigation of the stated risks. If you are curious to know more about how a governance module can react to proposals with exploitable vulnerabilities and attempts of governance takeover attacks, give their documentation a careful read and think about whether any of these scenarios could apply to your system. This is a great example of how projects can be honest and transparent with their community, sharing concerns, and laying out scenarios related to security risks that are highly relevant to everyone.
For more information on Uniswap’s governance, please refer to the official documentation.
SNX is the governance token behind the Synthetix protocol. Synthetix is today a fairly complex protocol. For this brief analysis we won’t dive into the details of its inner workings. However, we certainly encourage you to go read more about it in their thorough and extensive documentation linked at the end of this section.
Synthetix’s governance can be seen from at least two angles: the artifacts and the governing bodies. Already these simple ideas mark a fundamental difference with the protocols we’ve just covered. As your governance system matures, they will become more and more relevant to better define responsibilities and have clear separation of concerns within your formalized processes.
- Governance artifacts: There are differences between a change to a core part of the protocol, and a tweak in a single parameter. In more general terms, not every change in a system is to be treated the same. While some are fairly trivial and therefore may be executed quickly, others are so fundamental to the mechanics of the protocol itself that demand deeper and more thorough analysis from specialists. That’s why Synthetix uses different artifacts to document and proceed with changes. Each artifact demands different levels of involvement from the governing bodies, which further helps encapsulate responsibilities, ensuring all changes go through the most appropriate actors.
- Governance bodies: Synthetix heavily relies on different DAOs to ensure governance runs smoothly. They have different levels of responsibilities, and to different extents they can be seen as autonomous entities that rely and control each other. This separation in multiple bodies should help encapsulate concerns and limit powers of the participants, which is particularly relevant when a protocol grows to the size and complexity of Synthetix. Nonetheless, if you’re just starting out, this level of formality and complexity might be counter-productive if you want to do it from day one. It may be better to start with simpler processes, and slowly mature and formalize them as your community grows and you decentralize your system.
Additional practices in Synthetix governance that stand out and can serve as guidelines:
- Use of multisigs: Most governance bodies work with battle-tested implementations of multisigs from Gnosis Safe. It serves as a reminder that sometimes you might reduce complexity by just using a multisig instead of a full-fledged Governor-like contract.
- Documentation for transparency and security: Off-chain processes should always be well documented to ensure all participants can have the necessary information. This not only fosters community participation. It also contributes to the security of the system when processes for every protocol change are clearly laid out and followed. This is becoming a key feature of governance systems in Ethereum and Synthetix appears to be a good example for further study.
- Use of off-chain voting: Synthetix, as with many other projects in the ecosystem, relies on off-chain voting tools to smooth voting processes that might be expensive or inefficient on-chain. The chosen one in this case is snapshot.org, a spin-off of a tool created by Balancer. Integrating this or other similar tools will likely be relevant to foster participation in a cost-efficient, safe, and reliable way.
For more information on Synthetix’s governance, please refer to the official documentation.
BAL is the governance token of the Balancer protocol. At first glance, the architecture of the governance module is fairly straightforward although there are some key aspects that we can highlight as guidelines.
At the moment of writing, the main account controlling the governed contracts in Balancer is a multisig wallet (specifically, an implementation of a Gnosis Safe multisig). The owners of this multisig wallet are expected to enact the results from off-chain voting events happening at Balancer’s space in snapshot.org. One could argue that there is a good amount of trust deposited into these owners, and to some extent this might be true. Yet as one dives deeper into Balancer’s documentation, there are some interesting points that must be stressed to paint the whole picture.
- Powers, limitations and responsibilities: It is fundamental for any governance system to clearly state all roles involved and their responsibilities. Balancer’s documentation is transparent and honest in this regard. It states the existence of the multisig, its purpose and powers over the system.
- Publicly known owners: The fact that the owners of the multisig are publicly known and can be linked to specific individuals in the community is a good tactic to ensure that they behave as expected. Their one and only role is to enact on-chain the decisions of the community. It is seen as good practice to explicitly say what their exact duties are.
- Rationale behind decisions and roadmaps: Favoring transparency is also the fact that the documentation explains why the decision of having a single multisig was made. Considering that some users might not fully agree with systems that are solely governed by one multisig (in fear of scenarios where owners are compromised or go rogue), explaining decision rationale may alleviate concerns. To further support the point, if needed, you can expand on the expected governance’s roadmap where it may transition to a more decentralized on-chain implementation in future versions.
- Designing for rogue owners: If you’ve implemented safety features to limit the powers of rogue owners, your external documentation is the perfect place to highlight it. Similar to the “adversarial circumstances” case we described in Uniswap, you can do the same for risky scenarios of rogue owners in the multisig, and explain how the protocol behaves in such cases. For Balancer, their documentation states that “[…] even if the multisig goes rogue, all the liquidity is safe and can be withdrawn by their rightful owners”.
Balancer’s approach to governance can serve as an example for those that want to start out with simpler and more straightforward governance mechanisms. It is likely that smaller communities that might not want to (or not be ready to) implement full-featured Governor-like contracts such as Compound or Uniswap, or structured and multi-layered governance hierarchies such as in Synthetix.
For more information on Balancer’s governance, please refer to the official documentation.
At the center of governance lives a contract with similar features to those usually seen in Governor-like contracts. Despite it not being upgradeable, it includes a key mechanism that can be used to change some of its internal mechanics. More specifically, the governance contract uses a “strategy” contract. This contract encapsulates the logic related to voting power for proposing changes and casting votes. By changing the strategy, AAVE’s governance can effectively change how voting power is used within governance, without having to implement a proxy pattern for upgradeability (and thus avoiding some complexity and related security risks).
Another key point to highlight for AAVE is the use of multiple timelocks. This pattern allows for different delays for different actions, depending on their type (protocol or governance changes). This is a pattern that further stresses the importance of considering governance actions depending on their potential impact in the protocol. Not all governance actions are the same, and they might require different processes to be reviewed and enacted – an idea that we have surfaced several times already throughout these guidelines. Nonetheless, if you are considering following this path, bear in mind that using multiple timelocks and delays might add overhead to management and maintenance. Discuss with your team whether the benefits of the added complexity outweigh the costs.
Finally, we must also mention an important role in AAVE’s governance: the guardian. Implemented using a multisig, this role has the power to cancel proposals that make it into the governance process (before they’re executed). The guardian can be seen as a safeguard to prevent malicious proposals that may negatively impact the protocol. Its powers are well documented and highlighted in AAVE’s documentation, which favors transparency, and serves to raise awareness in the community about powerful roles in the system.
For more information on AAVE’s governance, please refer to the official documentation.
Now’s the turn to talk about one of the most well known governance systems in the Ethereum ecosystem: MakerDAO. MKR is its governance token. Before jumping into some key practices implemented in this system, let’s first do an overview of its architecture and mechanics.
First and foremost, it should be noted that the voting process is quite different from other systems we’ve seen so far. Because MakerDAO implements an approval voting scheme.
One of their most important contracts is the Chief. In short, this is where users lock their governance tokens and vote for proposals. That is why you will see that the Chief usually has lots of MKR in balance.
Changes to the protocol come via governance proposals, also known as Spells (such as this one). Spells are smart contracts that include a set of well defined encapsulated actions that can affect how the protocol works. This approach can be helpful to better understand and review governance actions if you are more used to reading Solidity code than transactions’ calldata (as in the case of Governor-like contracts).
Once a proposal gathers enough support in the Chief, it can be enacted. At this point the proposal is chosen as “the hat” of the Chief, and therefore can be queued and later executed via the Pause (a timelock essentially).
Even though this is a simplified version of the mechanics of this governance system, with these basic explanations we can take some interesting learnings:
- Use of delays: Similar to what we have seen in other governance systems, we can highlight the use of time-delayed actions via timelock contracts. This allows the community to better understand and review changes in the protocol before they take place.
- Approval voting: As a key difference with other governance systems explored in these guidelines, MakerDAO implements an approval voting mechanism. It is likely one of the most popular implementations in the ecosystem for this mechanism, and has been around for quite some time already. If you are looking for a battle-tested approval voting scheme, MakerDAO might be a good place to start.
- Sources of error and failure mode: If there’s anything that stands out from MakerDAO’s governance documentation, it is the fact that sources of user error and failure modes are explicitly and clearly laid out. This kind of information, similar to what we discussed for the adversarial circumstances in Uniswap, can be extremely helpful for third-party developers, auditors and users alike. Understanding if and how a system can fail is fundamental to understanding the safest ways to interact with it.
- Emergency shutdown: To mitigate the impact of governance takeover, or critical security incidents that may put user funds at risk, MKR holders can trigger a shutdown. It acts as a mechanism of last resort to keep users’ funds safe even under critical conditions. While worth including in governance, remember that these kinds of sensitive mechanisms usually involve tradeoffs and nuance. Not only related to implementation details, but also (and perhaps more importantly) to economic design decisions and game theory. Thus, it is important to first study and analyse these critical scenarios in depth, and then flesh them out with user-friendly documentation to raise awareness in your community.
We encourage readers to specifically take a look at the sources of user error and failure modes of the Chief, the Pause, the Spells, and the Emergency Shutdown module to learn more about specific best practices and risks when using these contracts. It is likely that some of these can serve as examples for you to follow in your own governance system.
For more information on MakerDAO’s governance, please refer to the official documentation.
Additional security recommendations
Beyond these example practices implemented in the wild for quite some time already, there are additional security recommendations we can make. These come from security issues that we have spotted during audits and actual vulnerabilities disclosed or exploited in mainnet.
- Protocol-specific issues: Regardless of any general guidelines we share here, always remember that you are coding software with a specific business logic. Whether you are coding a governance module or executing changes in your system via a governance module, all logic can have flaws. Those flaws may or may not result in security vulnerabilities that put the system at risk. As an example of the former, you can read our disclosure of a critical vulnerability in MakerDAO. As an example of the latter, recently a severe issue was introduced in the Compound Protocol due to a flawed community proposal approved by the protocol’s governance.
Therefore, following secure development practices of thorough testing, peer-reviews, and security assessments to ensure your code is safe and sound are always a must.
- Risks of low-level calls: In most, if not all, cases of governance implementations we have seen use low-level calls to arbitrary contracts with arbitrary data. That is obviously by design, as it provides the much needed flexibility of a generalized governance contract. Still, low-level calls are risky. So treat them carefully, and always:
- Check the success conditions of the calls and handle the returned data if necessary. Utilities in the Address library of OpenZeppelin Contracts may come in handy.
- Be mindful of the differences of executing low-level calls against EOAs or accounts with code.
- Beware of reentrancy attack vectors, which you can protect against using the ReentrancyGuard contract.
- Use of ETH: We have noticed a number of cases of governance-related contracts mishandling ETH. Although these are fairly simple recommendations, consider this when it comes to handling ETH:
- Flash-loans of governance tokens: We have covered this previously, but it is important to reinforce this idea. Unless you really know what you are doing, you most likely do not want to measure voting power at the current block – otherwise a flash-loan of the governance token can put at risk the entire governance system and the governed protocol. The usual mechanism is measuring voting power using special ERC20 tokens with additional features to snapshot balances.
- Governance takeovers: Even if your smart contract code is flawless, there are ways in which malicious users may try to take over your governance. Therefore, always monitor the market of your governance token, and adjust thresholds accordingly. Additionally, you can use delays to allow for some time to react should anything go badly. This and this discussion may be relevant for you.
In the same line of thought, depending on the level of decentralization you are aiming for, having guardians with powers to veto proposals or the ability to trigger sensitive actions on governance might be a sensible decision.
- Migrations and upgrades: We have seen issues arising from the way migrations and upgrades of governance systems themselves are handled. As an example, you can read more about an issue during Uniswap’s migration to Governor Bravo, where a flawed initialization of the contract led to temporarily bricking some governance actions.
You must pay special attention to these kinds of changes. Even if your contracts are considered battle-tested (or even audited), issues can arise during migrations and initialization stages. Always require security assessments from peer developers, bug hunters and security auditors. Moreover, document processes, include checklists and have off-chain validations. Testing and post-deployment scripts should greatly contribute in this area. Not everyone in your community will be technically proficient to understand all risks and impact of a simple change in your governance module. Therefore, you want to have processes in place to ensure all steps to a safe upgrade are closely followed, and the right stakeholders are involved.
As a final thought on governance risks, there’s an insightful article from Vitalik Buterin on coin voting governance that clarifies the pitfalls of some current governance schemes, and potential future mitigations. There are also additional articles referenced in the blog relevant to the guidelines discussed above.
- Use well-known contracts already available in the community (Governor contracts, ERC20 tokens for voting, Gnosis Safe multisig wallets).
- Consider including mechanisms for upgrades in governance logic (either via proxies, or strategies).
- Protect against flash-loans of governance tokens.
- Consider whether mechanisms for delegation of voting power can serve as a way to foster participation of key stakeholders that are more familiar with the day-to-day governance process of your protocol.
- Having different delays and thresholds for different actions can be a sensible choice, though beware of the tradeoffs with emergency response.
- In some scenarios, it might become relevant to have guardians via multisigs with reputable members of the community that can enact certain changes quickly.
- To favor efficiency, explore tooling for off-chain voting such as snapshot.org.
- Remember to always have user-friendly documentation to highlight powers, limitations, responsibilities and processes.
- Always perform audits and peer-reviews for modifications in your system. This applies both for changes to the governed contracts, or to the governance contracts themselves.
A Note From the Author
If you’re involved in the development of any of the governance modules mentioned in this guide and would like to provide feedback, further clarify, or improve the accuracy of the statements and information provided in this workshop, please reach out to tincho <at> openzeppelin <dot> com. I’d be happy to chat and continue improving our understanding of governance systems together.
- References and developer documentation highlighted throughout the workshop.
- Public security audits of governance systems.
- Moving beyond coin voting governance by Vitalik Buterin
Click here to view the slides from the workshop.