ERC-1202 On-chain Voting Interface (Voting Interface)
Review · Other · created 2018-07-08
A common interface for creating a vote with a smart contract, casting ballots, and querying and executing results. It lets anyone participate in voting the same way on any compatible contract and leave the results on chain in a standard format.
Why it is needed
Voting is one of the oldest use cases in EVM programming and a core procedure for DAOs (decentralized autonomous organizations) and organizational governance. But without a common standard, every project ends up building its own voting contract from scratch, making it hard to build general-purpose apps or UIs that handle voting across multiple DAOs in one screen, which makes it harder to draw in more participants. If voting results are not recorded on chain in a standard format, it is also hard for other contracts or DAOs to read those results and act on them programmatically. This standard defines a common API for casting votes, viewing results, and setting voting status, aiming to lay the groundwork for general-purpose voting UIs, delegated and automated voting, standardized on-chain recording of results, compatibility with token standards such as ERC-20 and ERC-721, recording voting weight based on token quantity, and setting voting deadlines.
What to implement
function execute(uint256 proposalId, bytes memory extraParams) payable external;: Executes the proposal corresponding to proposal number proposalId.function votingPeriodFor(uint256 proposalId) external view returns (uint256 startPointOfTime, uint256 endPointOfTime);: Reports the start and end time of voting for the given proposal.function eligibleVotingWeight(uint256 proposalId, address voter) external view returns (uint256);: Reports the voting weight a given address can exercise on the given proposal.
In depth
Required interface: IERC1202Core
A contract that follows the standard MUST implement IERC1202Core. castVote casts a vote given a proposal number proposalId, a choice support, a weight weight, a reasonUri holding the reason, and extraParams for additional data. castVoteFrom takes the same information plus a voter address from, and is used to submit a vote on behalf of another address. execute executes the proposal corresponding to proposalId. Once a vote is accepted, a VoteCast event records the voter, proposal number, choice, weight, and reason. All three functions are declared payable, so ether can be sent along with the call.
Multiple-choice voting: IERC1202MultiVote
IERC1202MultiVote is an optional (MAY) implementation, but any contract that wants to support multiple choices, such as ranked-choice voting or voting that splits weight differently across options, MUST implement it. castMultiVote takes an array of choices uint8[] support and an array of weights uint256[] weight, splits a vote across multiple choices in a single call, and records the result with a MultiVoteCast event. The design is such that the core interface alone is sufficient for single-choice voting, and this interface is added only when a more complex voting scheme is needed.
Query interface and ERC-5269
IERC1202Info defines view functions for reading voting information. votingPeriodFor(proposalId) returns the voting start time startPointOfTime and end time endPointOfTime, and eligibleVotingWeight(proposalId, voter) returns the weight a given address can exercise on that proposal. It assumes that weight distribution is determined internally by the contract or set in the constructor. Compatible contracts are also recommended (SHOULD) to implement ERC-5269, which signals interface support.
Deliberately out of scope
This standard deliberately does not address four things. First, delegation is excluded so that it can be handled by a separate EIP. Second, voting eligibility and weight calculation methods are also excluded, such as the snapshot approach used by OpenZeppelin's GovernorBravo implementation or quadratic voting calculations; this standard is designed to be flexible enough to accommodate both current and future weight calculation methods. Third, the content of a proposal is only identified by proposalId, and whether it is on chain or executable is left to separate proposals such as ERC-5247. Fourth, signature aggregation and guarantees, where offline signatures are collected and another account submits the transaction, are also out of scope, as exemplified by ERC-5453.
Design background: vote disclosure and anonymity
The original rationale explains that a view function called ballotOf was created so that a given address's vote can be easily checked. If an implementer does not want voting history disclosed, they can support anonymous voting by rejecting all calls to this function. However, it notes that since all smart contract calls remain in the block record, secrecy is not strongly guaranteed unless cryptographic techniques are used. It also assumes that each address votes on only one decision, and explains that a user who wants to split their voting power across multiple choices can create a new wallet address, move part of their tokens to it, and vote separately from each account.
Backward compatibility and proposal status
The choice field support was set to the uint8 type for backward compatibility with GovernorBravo, a widely used governance contract, and the source notes that this size could be increased in the future. This proposal was created in 2018 and is currently in Review status. Since it has not been finalized and the specification may still change, developers looking to implement it should check the latest state of the source.
Things to watch out for
- The use of the standard interface must be scoped narrowly: This standard is expected to be used in connection with other contracts, such as token distribution, consensus-driven actions, and multisig wallets. The core security consideration is ensuring that the standard interface is used only for performing follow-up actions and receiving vote submissions as input, and future auditing tools are also expected to be built on top of the standard interface.
- The interpretation of duplicate votes is not fixed: This standard was kept deliberately minimal for simplicity. Interpretations such as whether the same person voting multiple times increases weight, votes for multiple choices, or has a later vote override an earlier one may vary by implementation. Extensions or implementations of this standard should be thoroughly audited before use in large-scale, high-value applications.
- Anonymity, randomness, and deadlines are hard to implement: Requirements such as anonymity, randomness, time-based deadlines, and ordering guarantees are known to be difficult to achieve on Ethereum. Applications or organizations that need to enforce such requirements are advised to rely on audited, long-vetted shared libraries.
- Potential for vote buying and conflict-of-interest abuse: Once voting is standardized and put on chain, it becomes possible to build separate contracts that reward people for voting a particular way. This can create bribery and conflict-of-interest abuse problems that were previously hard to implement.