Token-weighted voting on proposals that execute a call when they pass
Historical Significance
A DAO from the ethereum.org tutorial. Proposals name a recipient, an amount of ether, a data payload and a description, and anyone holding a balance in the token contract passed to the constructor may raise one or vote on it with a position of minus one, zero or one. Votes are weighted by the voter's token balance at the moment the proposal is tallied, not at the moment of voting. Once the debating period has elapsed anyone may call executeProposal, which sums the weighted positions and, if the quorum is met and the result is positive, performs the recipient call with the proposal's ether and data. A tallied proposal is marked inactive so it cannot run twice.
Context
Deployed in August 2015, in the first month of the Frontier chain, and compiled with solc v0.1.1. The deployer dropped the tutorial's default quorum and changed its debating period from minutes to seconds.
Key Facts
Description
A DAO from the ethereum.org tutorial. Proposals name a recipient, an amount of ether, a data payload and a description, and anyone holding a balance in the token contract passed to the constructor may raise one or vote on it with a position of minus one, zero or one. Votes are weighted by the voter's token balance at the moment the proposal is tallied, not at the moment of voting. Once the debating period has elapsed anyone may call executeProposal, which sums the weighted positions and, if the quorum is met and the result is positive, performs the recipient call with the proposal's ether and data. A tallied proposal is marked inactive so it cannot run twice.
Source Verified
Heuristic Analysis
The following characteristics were detected through bytecode analysis and may not be accurate.
Frontier Era
The initial release of Ethereum. A bare-bones implementation for technical users.
Bytecode Overview
Verified Source Available
Source verified through compiler archaeology and exact bytecode matching.
View Verification ProofShow source code (Solidity)
// Submitted by EthereumHistory (ethereumhistory.com)
contract token {
mapping (address => uint) public coinBalanceOf;
event CoinTransfer(address sender, address receiver, uint amount);
/* Initializes contract with initial supply tokens to the creator of the contract */
function token(uint supply) {
coinBalanceOf[msg.sender] = (supply || 10000);
}
/* Very simple trade function */
function sendCoin(address receiver, uint amount) returns(bool sufficient) {
if (coinBalanceOf[msg.sender] < amount) return false;
coinBalanceOf[msg.sender] -= amount;
coinBalanceOf[receiver] += amount;
CoinTransfer(msg.sender, receiver, amount);
return true;
}
}
contract Democracy {
uint public minimumQuorum;
uint public debatingPeriod;
token public voterShare;
address public founder;
Proposal[] public proposals;
uint public numProposals;
event ProposalAdded(uint proposalID, address recipient, uint amount, bytes32 data, string description);
event Voted(uint proposalID, int position, address voter);
event ProposalTallied(uint proposalID, int result, uint quorum, bool active);
struct Proposal {
address recipient;
uint amount;
bytes32 data;
string description;
uint creationDate;
bool active;
Vote[] votes;
mapping (address => bool) voted;
}
struct Vote {
int position;
address voter;
}
function Democracy(token _voterShareAddress, uint _minimumQuorum, uint _debatingPeriod) {
founder = msg.sender;
voterShare = token(_voterShareAddress);
minimumQuorum = _minimumQuorum;
debatingPeriod = _debatingPeriod * 1 seconds;
}
function newProposal(address _recipient, uint _amount, bytes32 _data, string _description) returns (uint proposalID) {
if (voterShare.coinBalanceOf(msg.sender)>0) {
proposalID = proposals.length++;
Proposal p = proposals[proposalID];
p.recipient = _recipient;
p.amount = _amount;
p.data = _data;
p.description = _description;
p.creationDate = now;
p.active = true;
ProposalAdded(proposalID, _recipient, _amount, _data, _description);
numProposals = proposalID+1;
}
}
function vote(uint _proposalID, int _position) returns (uint voteID){
if (voterShare.coinBalanceOf(msg.sender)>0 && (_position >= -1 || _position <= 1 )) {
Proposal p = proposals[_proposalID];
if (p.voted[msg.sender] == true) return;
voteID = p.votes.length++;
p.votes[voteID] = Vote({position: _position, voter: msg.sender});
p.voted[msg.sender] = true;
Voted(_proposalID, _position, msg.sender);
}
}
function executeProposal(uint _proposalID) returns (int result) {
Proposal p = proposals[_proposalID];
/* Check if debating period is over */
if (now > (p.creationDate + debatingPeriod) && p.active){
uint quorum = 0;
/* tally the votes */
for (uint i = 0; i < p.votes.length; ++i) {
Vote v = p.votes[i];
uint voteWeight = voterShare.coinBalanceOf(v.voter);
quorum += voteWeight;
result += int(voteWeight) * v.position;
}
/* execute result */
if (quorum > minimumQuorum && result > 0 ) {
p.recipient.call.value(p.amount)(p.data);
p.active = false;
} else if (quorum > minimumQuorum && result < 0) {
p.active = false;
}
ProposalTallied(_proposalID, result, quorum, p.active);
}
}
}External Links
Related contracts
MessageStore
Same eraA 6-line contract storing a single public string, deployed Day 9 of Ethereum by a prolific early experimenter who shipped 18 contracts in one week.
0xd2eccd...ff3d6bAugust 8, 2015Contract 0xa85146...9bbf06
Same erago-ethereum's built-in hash registrar, mapping a key to a content hash
0xa85146...9bbf06August 10, 2015Ballot
Same eraDelegated voting with a proposal count fixed at deployment
0x3cf26c...b6a8e1August 18, 2015Ballot
Same eraDelegated voting with a proposal count fixed at deployment
0x56ce77...b44745August 18, 2015Ballot
Same eraDelegated voting over five proposals, with the chairperson handing out voting rights
0x640fa6...b57e8aAugust 25, 2015Lotto
Same eraEtherPot with rounds ten blocks long, deployed to exercise the payout path
0x396864...d0edb7August 27, 2015