Token-weighted governance over a share contract, from the ethereum.org tutorial
Context
Deployed in December 2015 on the Frontier chain.
Key Facts
Description
The Association from the ethereum.org DAO tutorial. It is bound at construction to a token contract whose balances decide voting power, a minimum share threshold that gates who may act, and a debating period in minutes. A shareholder proposes a beneficiary, an amount of ether, a description and a payload of transaction bytecode; other shareholders vote for or against, weighted by their balance. Once the debating period has elapsed anyone may call executeProposal, which recomputes the hash of the recipient, amount and payload to prove it is the code that was voted on, and only then performs the call. This deployment declares checkProposalCode immediately after the constructor, which is the only thing separating it from the one made the same day.
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 balanceOf; }
contract Association {
uint public minimumQuorum;
uint public debatingPeriodInMinutes;
Proposal[] public proposals;
uint public numProposals;
token public sharesTokenAddress;
event ProposalAdded(uint proposalID, address recipient, uint amount, string description);
event Voted(uint proposalID, bool position, address voter);
event ProposalTallied(uint proposalID, int result, uint quorum, bool active);
struct Proposal {
address recipient;
uint amount;
string description;
uint votingDeadline;
bool openToVote;
bool proposalPassed;
uint numberOfVotes;
bytes32 proposalHash;
Vote[] votes;
mapping (address => bool) voted;
}
struct Vote {
bool inSupport;
address voter;
}
modifier onlyShareholders {
if (sharesTokenAddress.balanceOf(msg.sender) == 0) throw;
_
}
function Association(address sharesAddress, uint minimumSharesForVoting, uint minutesForDebate) {
sharesTokenAddress = token(sharesAddress);
minimumQuorum = minimumSharesForVoting;
debatingPeriodInMinutes = minutesForDebate;
}
function checkProposalCode(uint proposalNumber, address beneficiary, uint etherAmount, bytes transactionBytecode) constant returns (bool codeChecksOut) {
Proposal p = proposals[proposalNumber];
return p.proposalHash == sha3(beneficiary, etherAmount, transactionBytecode);
}
function vote(uint proposalNumber, bool supportsProposal) onlyShareholders returns (uint voteID) {
Proposal p = proposals[proposalNumber];
if (p.voted[msg.sender] == true) throw;
voteID = p.votes.length++;
p.votes[voteID] = Vote({inSupport: supportsProposal, voter: msg.sender});
p.voted[msg.sender] = true;
p.numberOfVotes = voteID + 1;
Voted(proposalNumber, supportsProposal, msg.sender);
}
function executeProposal(uint proposalNumber, bytes transactionBytecode) returns (int result) {
Proposal p = proposals[proposalNumber];
if (now < p.votingDeadline
|| !p.openToVote
|| p.proposalHash != sha3(p.recipient, p.amount, transactionBytecode)) throw;
uint quorum = 0;
uint yea = 0;
uint nay = 0;
for (uint i = 0; i < p.votes.length; ++i) {
Vote v = p.votes[i];
uint voteWeight = sharesTokenAddress.balanceOf(v.voter);
quorum += voteWeight;
if (v.inSupport) {
yea += voteWeight;
} else {
nay += voteWeight;
}
}
if (quorum > minimumQuorum && yea > nay) {
p.recipient.call.value(p.amount * 1000000000000000000)(transactionBytecode);
p.openToVote = false;
p.proposalPassed = true;
} else if (quorum > minimumQuorum && nay > yea) {
p.openToVote = false;
p.proposalPassed = false;
}
ProposalTallied(proposalNumber, result, quorum, p.openToVote);
}
function newProposal(address beneficiary, uint etherAmount, string JobDescription, bytes transactionBytecode) onlyShareholders returns (uint proposalID) {
proposalID = proposals.length++;
Proposal p = proposals[proposalID];
p.recipient = beneficiary;
p.amount = etherAmount;
p.description = JobDescription;
p.proposalHash = sha3(beneficiary, etherAmount, transactionBytecode);
p.votingDeadline = now + debatingPeriodInMinutes * 1 minutes;
p.openToVote = true;
p.proposalPassed = false;
p.numberOfVotes = 0;
ProposalAdded(proposalID, beneficiary, etherAmount, JobDescription);
numProposals = proposalID+1;
}
}External Links
Related contracts
meh token
Same deployerA central minter can issue new units and freeze any account's ability to send.
0xa8a937...257e97December 11, 2015MessageStore
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, 2015CoinFlipper
Same eraA coin flip on the block timestamp that pays double or keeps the stake
0x6c8dda...5ef84eAugust 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, 2015