Token-weighted governance over a share contract, from the ethereum.org tutorial
Context
Deployed in December 2015 on the Frontier chain, and reproduced only once its five functions are put back in the order they were written.
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.
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 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;
}
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);
}
}External Links
Related contracts
Multiply7
Same deployerThe canonical Solidity 'multiply by 7' tutorial contract from the Frontier documentation.
0xa18d71...418761August 10, 2015Ballot
Same deployerDelegated voting over five proposals, with the chairperson handing out voting rights
0x640fa6...b57e8aAugust 25, 2015exchange
Same deployerThe exchange example from the ethereum dapp-bin standardized contract APIs, whose deleteOrder lets anyone cancel anyone else's order.
0xb34555...5f06b4September 8, 2015currency
Same deployerAn early Frontier-era token contract implementing a pre-ERC-20 interface, deployed on September 8, 2015 by an address associated with the ENS name collectibletr
0x8494f7...634fd3September 8, 2015MyToken
Same deployerA MyToken template deployment by collectibletrust.eth on November 3, 2015, linking the same deployer responsible for the pre-ERC-20 currency contract from Septe
0x5f100e...12a9e0November 3, 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, 2015