This EIP defines an API for implementing voting with smart contracts. This standard provides functionality for voting, viewing vote results, and setting voting status.
Voting is one of the earliest examples of EVM programming and is also a key part of DAO and organizational governance processes. We expect many DAOs will ultimately need to leverage voting as an important part of their governance. By creating a voting standard for smart contracts and tokens, we can have the following benefits:
proposalId, but the information included in a proposal, whether it is on-chain or off-chain, and whether it is executable are all left out of this proposal. A separate EIP could be proposed to address this particular use case. See one such proposal: ERC-5247.IERC1202Core belowinterface IERC1202Core {
event VoteCast(
address indexed voter,
uint256 indexed proposalId,
uint8 support,
uint256 weight,
string reason,
bytes extraParams
);
function castVote(
uint256 proposalId,
uint8 support,
uint256 weight,
string calldata reasonUri,
bytes calldata extraParams
) external payable returns;
function castVoteFrom(
address from,
uint256 proposalId,
uint8 support,
uint256 weight,
string calldata reasonUri,
bytes calldata extraParams
) external payable returns;
function execute(uint256 proposalId, bytes memory extraParams) payable external;
}
IERC1202MultiVote Interface. If the intention is for multi-options to be supported, e.g. for ranked-choices
or variant weights voting, Compliant contracts MUST implement IERC1202MultiVote Interface.interface IERC1202MultiVote {
event MultiVoteCast(
address indexed voter,
uint256 indexed proposalId,
uint8[] support,
uint256[] weight,
string reason,
bytes extraParams
);
function castMultiVote(
uint256 proposalId,
uint8[] support,
uint256[] weight,
string calldata reasonUri,
bytes calldata extraParams
) external payable;
}
interface IERC1202Info {
function votingPeriodFor(uint256 proposalId) external view returns (uint256 startPointOfTime, uint256 endPointOfTime);
function eligibleVotingWeight(uint256 proposalId, address voter) external view returns (uint256);
}
We made the following design decisions, and here are the rationales.
We created a view function, ballotOf, primarily to make it easier for people to check the vote from a certain address. This has the following assumptions:
It is possible to check someone's vote directly given an address. If implementers do not want to make this so easy, they can simply reject all calls to this function. We want to make sure that we support both anonymous and non-anonymous voting. However, since all calls to a smart contract are logged in block history, there is not much secrecy unless cryptographic techniques are used. I am not sufficiently cryptography-savvy to comment on that possibility. Please see "Second Feedback Questions 2018" for a related topic.
It assumes that each individual address can vote for only one decision. Users can distribute their available voting power at a more granular level. If implementers want to allow this, they can ask the user to create another wallet address and grant that new address a certain amount of power. For example, in token-based voting where voting weight is determined by the amount of tokens held by a voter, a voter who wants to distribute their voting power across two different options (or option sets) can transfer some of the tokens to the new account and cast votes from both accounts.
We assume votes have weight, which can be checked by calling eligibleVotingWeight(proposalId, address voter), and that the weight distribution is either determined internally or set by the constructor.
support options are chosen to be uint8 for the purpose of being backward-compatible with GovernorBravo. This can be increased in the future.We expect the voting standard to be used in connection with other contracts such as token distributions, actions conducted by consensus or on behalf of an entity, multi-signature wallets, and similar systems.
The major security consideration is ensuring that the standard interface is used only for performing downstream actions or receiving upstream input (vote casting). We expect future audit tools to be based on standard interfaces.
It is also important to note, as discussed in this standard, that for the sake of simplicity this EIP is kept in a very basic form. It can be extended to support many different implementation variations. Such variations might contain different assumptions about the behavior and interpretation of actions. One example is: what does it mean if someone votes multiple times through vote?
Because of the flexible nature of voting, we expect that many subsequent standards will need to be created as extensions of this EIP. We suggest that any extension or implementation of this standard be thoroughly audited before being included in large-scale or high-asset-volume applications.
The third consideration is non-triviality. Some voting applications assume anonymity, randomness, time-based deadline, ordering, etc. These requirements are known to be non-trivial to achieve on Ethereum. We suggest that any applications or organizations rely on audited and time-proven shared libraries when these requirements need to be enforced in their applications.
The fourth consideration is potential abuse. When voting is standardized and put on-chain, it is possible to write another contract that rewards a voter for voting in a certain way. This creates potential issues of bribery and conflict-of-interest abuse that were previously hard to implement.
Copyright and related rights waived via CC0.