DAO Voting from Layer 2 with Flexible Voting
August 21, 2023 / Alex Keating
DAO voting with Governance tokens on Ethereum mainnet is expensive. Gas costs can be prohibitive for small to medium sized holders, or delegates who have received voting power but don't have a strong incentive to vote on a given proposal.
Enabling governance voting to take place on Layer 2 networks, such as Optimism and Arbitrum, is one solution to this issue. Gas on these networks is often orders of magnitudes below mainnet costs. But this poses another problem: how can holders express their vote on Layer 2 when the "real" tokens are locked in Layer 1 bridge contracts?
ScopeLift created Flexible Voting to solve this and similar issues. We received a grant from the Ethereum Foundation to build a proof-of-concept that enables trust minimized Layer 2 voting for DAOs deployed on mainnet. We will walk you through our solution, the difficulties we faced building for cross chain use cases, and potential future improvements to this initial implementation.
Our design has 3 cross chain interactions:
- Bridging the L1 token to unlock an L2 voting token and vice versa
- Making the L1 governance proposal metadata available on L2
Collecting L2 votes and sending them to the L1 Governor contract
Let's review each part of this architecture individually.
Theoretically, networks like Optimism and Arbitrum could include infrastructure for cross chain voting in their native bridges. Unsurprisingly, this functionality was not included out of the gate. While we hope networks might consider adding such functionality in the future, we opted to build our own simple bridging contracts for the proof-of-concept. To do this, we leveraged Wormhole's automatic relayer service, which makes it easy to pass cross chain messages between smart contracts without custom offchain infrastructure.
When a user deposits their token on the L1, a message is sent to the L2 minting an ERC20 token. Unlike generic tokens minted by standard bridges, the token we provide for the user on L2 includes the delegation and checkpointing functionality needed for governance voting. This means the token holder is ready to cast votes on L2 immediately.
Similarly, if a holder of the Layer 2 voting token wants to reclaim their native token on mainnet, our contracts allow them to burn the token on Layer 2 and sends a message to release the token on Layer 1.
Governance proposals are a sequence of actions the governance contracts will execute, along with metadata, such as the proposal description, identifier, start block and end block. To allow for voting on Layer 2, we need some of this metadata available. In particular, we need the start block and end block for a given proposal identifier to validate the voting window is still open.
In theory, it might be possible to get this data using a storage proof or another technique. For the sake of this proof-of concept, we went the simplest route, using an L1 contract to read and send this proposal metadata to the L2 using Wormhole's message passing capabilities. Clients can initiate this process when a proposal is created.
Vote Collection and Casting
On Layer 2, users cast their votes through a custom aggregator contract that acts like a Governor. As already covered, this aggregator contract pulls its proposal information from the bridged metadata. The user experience for a voter on Layer 2 is similar to voting on Layer 1 but with dramatically lower gas fees.
Voting on the L2 ends 4 hours before the L1 to prevent situations where a vote is cast on the L2, but is not received by the L1 in time to be counted. Once again, we use Wormhole's automatic relayers to pass the message across chains.
Bridging aggregated votes from L2 to L1 can be initiated by anyone. In a production deployment, this action might be executed by a bot and subsidized by the DAO itself. Future versions could even collect a tiny fee from each L2 voter to incentivize third parties to execute this cross chain transaction.
On Layer 1, our bridge contract receives the vote totals and passes them on to the mainnet Governor contract by leveraging the Flexible Voting extension.
Building Cross Chain
Adding additional systems to an application's architecture increases the complexity in a nonlinear fashion. Building smart contract systems that function cross chain is significantly more complex than single chain dapps.
When dealing with Layer 2 rollups, the biggest questions we had centered around latency and correctness of the L2 state. Leveraging Wormhole's automatic relayers allowed us to get to a proof-of-concept quickly, but there are further considerations relevant for future versions.
One consideration that is unlikely to matter in the short term, but becomes a bigger issue if cross chain voting becomes widely adopted, has to do with censorship or invalid state attacks. For a high value governance proposal that might be swayed by the inclusion of votes recorded on other chains, the incentive to attack or bribe bridge operators to censor or lie about votes can be high.
In theory, this could avoided by using censorship resistant native bridges, but both Arbitrum and Optimism have an approximately one week delay in delivering a messages from L2 to L1. This challenge period prevents an incorrect transaction result from being finalized. For our use case, this is an unacceptable delay, because many DAOs have voting periods less than one week.
Leveraging Wormhole allows us to bypass the 7 day challenge period, but shifts our security model to rely on their validator set. We believe their security model is more than sufficient for a proof-of-concept, and potentially well beyond this. Still, it's important to architect solutions that minimize such attack vectors.
Another challenge we encountered was how we would read L1 proposal metadata on L2. One option is to get the L1 proposal metadata via a proof, while another is to send a message with the L1 state to the L2. As covered, we chose the simpler option: sending a message from L1 to the L2. This is another area where improvement is possible in the future.
The last major challenge we ran into was what clock mode to use in the L2 token. We considered using the latest L1 block number on L2 or the current L2 block number. Both Optimism and Arbitrum have ways of getting the last seen L1 block number. Relying on L1 blocks adds some latency on Optimism, where L1 block data is delayed 2 block confirmations, and Arbitrum advises treating block numbers as correct on the order of hours.
Layer 2 voting is one of many possible use cases for Flexible Voting. We've been building these out over the last several months, as well as working with DAOs to upgrade to Flexible Voting compatible Governors. We're excited to share that Gitcoin, PoolTogether, and Frax have all adopted Flexible Voting. This means in the near future, it will be possible to move proof-of-concepts like this one into production for real users of real DAOs.
We hope to continue pushing Layer 2 voting forward after this proof-of-concept. Hardening and generalizing the contracts, and building out interfaces for users to interact with them, are two obvious areas we hope to advance soon. In the long run, we hope that governance token holders will be able seamlessly participate in governance, regardless of where their tokens are held or what they're doing with them. There's much work left to do to get there, but we're grateful to the Ethereum Foundation for supporting this step forward.
To see what we've built so far, and follow along with future work, check out the GitHub repo, where all the code is available under an open source license.