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

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

Original ERC · ← ERCs