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
Greeter
Same deployerThe go-ethereum Contract Tutorial greeter, deployed with the greeting: Hello World!
0xb214cb...5cd6f7August 20, 2015greeter
Same deployerThe Frontier-era greeter tutorial contract: returns a constructor-set greeting from greet(), with an owner-only kill() inherited from mortal.
0x252568...5f1ce1August 20, 2015greeter
Same deployerThe Frontier-era greeter tutorial contract: returns a constructor-set greeting from greet(), with an owner-only kill() inherited from mortal.
0x6f5678...693918August 20, 2015Greeter
Same deployerThe go-ethereum Contract Tutorial greeter, deployed with the greeting: Hello World!
0x3d7ed1...246503August 22, 2015greeter
Same deployerThe Frontier-era greeter tutorial contract: returns a constructor-set greeting from greet(), with an owner-only kill() inherited from mortal.
0x1f1058...edaf2bAugust 22, 2015Contract 0x8e6f6a...5d9651
Same deployerA standalone mortal base contract
0x8e6f6a...5d9651August 22, 2015