EIP-TBD: Ranked Delegated Voting Standard
Work in ProgressSimple Summary
A standard for ranked delegated voting in DAOs that allows token holders to create ordered delegation lists and point their token votes to these lists. Voting power cascades down the list to the highest-ranked delegate who voted on a specific proposal. This improves voter participation and ensures delegated tokens are actively used without compromising user control.
Abstract
This EIP introduces a mechanism to extend token-based delegation (as in ERC20Votes
) to support ranked fallback delegation. Users can assign a prioritized list of delegates to vote on their behalf. On a per-proposal basis, the system checks if the token holder voted; if not, it checks the delegates in order until it finds one who did vote. The first such delegate receives the token holder's voting power for that proposal.
The voting mechanism is compatible with single-option yes/no proposals and can integrate with ranked-choice voting schemes like Instant-Runoff Voting (IRV). The standard is designed to work with OpenZeppelin's ERC20Votes
and Governor
contracts.
Motivation
In DAOs such as Optimism, a vast majority of voting power is under-utilized:
- ~2.7% of OP tokens are actively delegated
- ~33% of delegates miss proposals
This leads to governance capture and apathy. Traditional delegation is fragile: if your delegate is inactive, your vote is lost. A ranked delegation system ensures votes find the most active trusted representative and reduces vote wastage.
Limitations of Existing Standards
Existing contract standards Governor.sol, Votes.sol, GovernorVotes.sol are incapable of supporting ranked delegation as-is:
- Dynamic vote resolution during voting period
- Multiple delegate storage per account
- Conditional vote power transfer based on delegate activity
- Per-proposal delegation resolution rather than global delegation
These requirements are fundamentally incompatible with the checkpoint-based, pre-calculated voting power model used by OpenZeppelin's Governor system in the following ways:
Specific Blocking Functions
ERC20Votes/Votes.sol:
delegates()
- Returns single delegate, not ranked list_delegate()
- Overwrites delegation, no ranking concept_moveDelegateVotes()
- Immediately transfers powergetVotes()
- Returns pre-calculated power, not dynamic
GovernorVotes.sol:
_getVotes()
- Calls token().getPastVotes() for static lookup- Cannot override without breaking checkpoint system
Governor.sol:
- Vote counting extensions expect fixed voting power
- Proposal lifecycle assumes static delegation
Detailed Limitations
1. Single Delegate Model (Votes.sol)
- Line 38:
mapping(address account => address) private _delegatee;
- Problem: Each account can only delegate to one address
- Impact: Cannot store ranked delegation lists
2. Static Vote Weight Calculation (GovernorVotes.sol)
- Line 62:
return token().getPastVotes(account, timepoint);
- Problem: Voting power is pre-calculated and stored in checkpoints
- Impact: Cannot perform dynamic cascading at vote time
3. Immutable Delegation Storage (Votes.sol)
- Line 169-175:
_delegate()
function overwrites previous delegation - Problem: Delegation is permanent until explicitly changed
- Impact: No concept of "fallback" or "ranked" delegates
4. Checkpoint-Based System (Votes.sol)
- Line 194-213:
_moveDelegateVotes()
immediately transfers voting power - Problem: Voting power is immediately transferred to delegate
- Impact: Cannot hold voting power in escrow for cascading
5. Governor Vote Counting Architecture
- Governor.sol: Expects fixed voting power per account at proposal snapshot
- Problem: Vote counting assumes static delegation at proposal creation
- Impact: Cannot dynamically resolve delegation during voting period
Possible Solutions
There are several delegation strategies that could address the limitations of existing standards:
1. Ranked Delegation
A token holder selects many ranked delegates in priority order. When voting, the system cascades through the list until finding an active delegate who voted.
Example: [Alice, Bob, Carol] → If Alice didn't vote, check Bob → If Bob didn't vote, use Carol's vote
2. Chained Delegation
A token holder selects one delegate, who may select another delegate, creating a delegation chain. Voting power flows through the chain to the final active delegate.
Example: Token Holder → Alice → Bob → Carol (if Carol votes, she gets all the delegated power)
3. Fractional Delegation
A token holder selects a set of delegates and allocates different portions of their tokens to each delegate, allowing for diversified representation.
Example: 40% to Alice, 35% to Bob, 25% to Carol (each delegate receives their allocated portion if they vote)
Optimal Solution
An optimal solution is one that can support all of these strategies or a combination of them, allowing the token issuer to determine which delegation strategies they want to support for their specific project and governance needs.
Specification
WIP
Reference Implementation
See the tab for the complete implementation.
Open Questions
- Should each delegation list exist as a contract that lives at a single address or should a single registry hold all lists?The factory pattern costs approximately 2-3x additional gas per delegation list due to contract deployment overhead. However, it provides the benefit of maintaining ERC20Votes compatibility by giving each delegation list a unique address that can be used with existing delegate(address) functions. Storing all lists as arrays within a single registry contract centralizes management and can be more gas-efficient, but may limit flexibility and upgradability.
- Should delegation list updates use full array overwrite or support incremental add/remove operations?Gas analysis shows full overwrite is more efficient for most scenarios:
- Full overwrite wins for any changes involving 2+ delegates
- Incremental operations only cheaper for single additions at list end (~16k gas savings)
- Position matters significantly: adding at beginning costs ~72k gas vs ~31k at end
- Operation cost scales with list size: 10 delegates = 42k gas, 50 delegates = 99k gas