A Flexible Voting Money Market on Compound V3
July 12, 2023 / Ben DiFrancesco
This post will explain how we added flexible voting support to Comet, as well as some of the abstractions we created to make this kind of work easier for smart contract devs of the future. It will also cover some of the other work we're doing to help the DAO governance ecosystem benefit from flexible voting.
Flexible VotingFlexible voting is a novel extension to Compound-style governance systems. It was originally developed with funding from Uniswap Grants. It allows delegates to split their voting weight across For/Against/Abstain options, rather than having to put all of it behind one.
Enabling flex voting for protocols like Compound—which hold voting tokens for depositors—allows them to participate in Governance while earning yield. This benefits the Compound ecosystem by making it more attractive for Governance token holders to deposit them into the lending market. To learn more of the details related to these benefits, read our earlier summary.
While valuable, enabling flex voting for a protocol can be difficult. One of the main challenges is that flex voting clients require being able to compare past balances for users at arbitrary blocks. This is necessary to determine how much of the protocol's aggregate voting weight a depositor should have control over.
A significant difference between Comet and previous versions of Compound is Comet's use of rebasing tokens—i.e a token whose balance changes programmatically over time.
For example, if you have 100 cUSDCv3 today, at an interest rate of 2% APY, you will have 102 cUSDCv3 in a year from now, without even interacting with the protocol. The increase in your token balance is built into the Comet contract.
Comet's usage of a rebasing token design means our Flexible Voting implementation ends up looking similar to the approach we've used for integrating other protocols. That approach involves checkpointing a user's balances each time they changed.
Helpfully, Comet has a single function,
updateBasePrincipal, that writes said balances to storage. So adding flex voting to Compound v3 required inheriting from Comet and extending
updateBasePrincipal to checkpoint balances as they changed. The result can be seen here. Pretty neat!
Implementing Flexible Voting for another rebasing token gave us the opportunity to abstract the behavior shared by similar implementations. Doing so made the implementation easier to read, test, and reason about. It will also make it easier for others to add flex voting to other protocols in the future.
FlexVotingClient contract. We created it to encapsulate all of the logic necessary to add flex voting to contracts that custody voting tokens. Those contracts need only inherit from
FlexVotingClient to enjoy all of the benefits of flex voting. And the beauty of it is that it works for non-rebasing tokens just as well as rebasing tokens.
Key to the
FlexVotingClient is the concept of a user's raw balance. A raw balance is the system's internal representation of a user's claim on the governance tokens that it custodies. Since different systems might represent such claims in different ways, the FlexVotingClient leaves the implementation of its
_rawBalanceOf function to the child contract.
The simplest such representation would be to directly store the cumulative balance of governance tokens that the user had deposited. In such a system, the amount that the user has claim to is just the amount that the user has deposited. If the user has claim to
1e18 governance tokens, the internal representation is just
In many systems, however, the raw balance will not be equivalent to the amount of governance tokens the user has claim to. This is the case for rebasing systems like Comet. In Comet, deposit amounts are scaled down by an ever-increasing index that represents the cumulative amount of interest earned over the lifetime of deposits. The "raw balance" of a user in Comet's case is this scaled down amount, since it is the value that represents the user's claim on deposits. Thus for Comet, a user's raw balance will always be less than the actual amount they have claim to.
The only requirement for
FlexVotingClient to be added to a contract is that it be possible to define a user's raw balance. If the raw balance can be identified and defined for a system, and
_rawBalanceOf can be implemented for it, then this contract will take care of the rest.
The adoption of flexible voting across the ecosystem has two primary components:
- DAOs launching or upgrading to flexible voting compatible contracts
- More use cases being built on top of flexible voting for those DAOs to use While we anticipate some big announcements on the first point in the near future, the work we've done for this grant falls into the second category. It is another great usecase for those DAOs that do eventually upgrade to flexible voting. In particular, our Comet compatible contracts mean it will be easier for DAOs that choose flexible voting to enable voting-while-earning yield via Compound in the future.
There's still some work to do to make this come to fruition. For one, we see an opportunity to build Flexible Voting compatible contracts for the other side of the Compound market. That is, we want to make it possible to participate in governance when depositing your tokens as collateral, rather than to earn yield. We also want to reduce the contract sizes, do some gas optimization, and increase test coverage for what we've already built.
This grant enabled us to get huge start on making it possible for token holders to continue participating in governance when depositing their tokens in the Compound ecosystem. Thank you again to the Compound Grants Program for their generous support. Stay tuned for more updates on flexible voting coming soon!