The public counter that sells token weighted governance deployments for a fee
Historical Significance
Part of a 2016 attempt to sell working organisations as deployable parts: a governance contract, a token or a payment splitter bought from a counter for a fee, with the created contract's shape published on chain beside it.
Context
Deployed in the Homestead era, when deploying a contract meant compiling one yourself.
Key Facts
Description
BuilderAssociation is the public facing half of Airalab's DAO toolkit. A caller pays the building fee and gets back a freshly deployed Association, a governing contract that weighs each vote by the caller's token balance, recorded against their address and announced in a Builded event. Deployed on 30 November 2016 by 0x4af013afbadb22d8a88c92d68fc96b033b9ebb8a and recovered from airalab/core. Etherscan cannot verify it: solc writes its link placeholder as the library name in lowercase at this vintage and Etherscan will not resolve that, so this record is the published form.
Source Verified
Heuristic Analysis
The following characteristics were detected through bytecode analysis and may not be accurate.
Spurious Dragon Era
Continued DoS protection. State trie clearing.
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)
pragma solidity ^0.4.4;
/**
* @title Contract for object that have an owner
*/
contract Owned {
/**
* Contract owner address
*/
address public owner;
/**
* @dev Store owner on creation
*/
function Owned() { owner = msg.sender; }
/**
* @dev Delegate contract to another person
* @param _owner is another person address
*/
function delegate(address _owner) onlyOwner
{ owner = _owner; }
/**
* @dev Owner check modifier
*/
modifier onlyOwner { if (msg.sender != owner) throw; _; }
}
pragma solidity ^0.4.4;
/**
* @title Contract for objects that can be morder
*/
contract Mortal is Owned {
/**
* @dev Destroy contract and scrub a data
* @notice Only owner can kill me
*/
function kill() onlyOwner
{ suicide(owner); }
}
pragma solidity ^0.4.4;
// Standard token interface (ERC 20)
// https://github.com/ethereum/EIPs/issues/20
contract ERC20
{
// Functions:
/// @return total amount of tokens
function totalSupply() constant returns (uint256 supply) {}
/// @param _owner The address from which the balance will be retrieved
/// @return The balance
function balanceOf(address _owner) constant returns (uint256 balance) {}
/// @notice send `_value` token to `_to` from `msg.sender`
/// @param _to The address of the recipient
/// @param _value The amount of token to be transferred
/// @return Whether the transfer was successful or not
function transfer(address _to, uint256 _value) returns (bool success) {}
/// @notice send `_value` token to `_to` from `_from` on the condition it is approved by `_from`
/// @param _from The address of the sender
/// @param _to The address of the recipient
/// @param _value The amount of token to be transferred
/// @return Whether the transfer was successful or not
function transferFrom(address _from, address _to, uint256 _value) returns (bool success) {}
/// @notice `msg.sender` approves `_addr` to spend `_value` tokens
/// @param _spender The address of the account able to transfer the tokens
/// @param _value The amount of wei to be approved for transfer
/// @return Whether the approval was successful or not
function approve(address _spender, uint256 _value) returns (bool success) {}
/// @param _owner The address of the account owning tokens
/// @param _spender The address of the account able to transfer the tokens
/// @return Amount of remaining tokens allowed to spent
function allowance(address _owner, address _spender) constant returns (uint256 remaining) {}
// Events:
event Transfer(address indexed _from, address indexed _to, uint256 _value);
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
}
pragma solidity ^0.4.4;
/**
* @title Token contract represents any asset in digital economy
*/
contract Token is Mortal, ERC20 {
/* Short description of token */
string public name;
string public symbol;
/* Total count of tokens exist */
uint public totalSupply;
/* Fixed point position */
uint8 public decimals;
/* Token approvement system */
mapping(address => uint) public balanceOf;
mapping(address => mapping(address => uint)) public allowance;
/**
* @return available balance of `sender` account (self balance)
*/
function getBalance() constant returns (uint)
{ return balanceOf[msg.sender]; }
/**
* @dev This method returns non zero result when sender is approved by
* argument address and target address have non zero self balance
* @param _address target address
* @return available for `sender` balance of given address
*/
function getBalance(address _address) constant returns (uint) {
return allowance[_address][msg.sender]
> balanceOf[_address] ? balanceOf[_address]
: allowance[_address][msg.sender];
}
/* Token constructor */
function Token(string _name, string _symbol, uint8 _decimals, uint _count) {
name = _name;
symbol = _symbol;
decimals = _decimals;
totalSupply = _count;
balanceOf[msg.sender] = _count;
}
/**
* @dev Transfer self tokens to given address
* @param _to destination address
* @param _value amount of token values to send
* @notice `_value` tokens will be sended to `_to`
* @return `true` when transfer done
*/
function transfer(address _to, uint _value) returns (bool) {
if (balanceOf[msg.sender] >= _value) {
balanceOf[msg.sender] -= _value;
balanceOf[_to] += _value;
Transfer(msg.sender, _to, _value);
return true;
}
return false;
}
/**
* @dev Transfer with approvement mechainsm
* @param _from source address, `_value` tokens shold be approved for `sender`
* @param _to destination address
* @param _value amount of token values to send
* @notice from `_from` will be sended `_value` tokens to `_to`
* @return `true` when transfer is done
*/
function transferFrom(address _from, address _to, uint _value) returns (bool) {
var avail = allowance[_from][msg.sender]
> balanceOf[_from] ? balanceOf[_from]
: allowance[_from][msg.sender];
if (avail >= _value) {
allowance[_from][msg.sender] -= _value;
balanceOf[_from] -= _value;
balanceOf[_to] += _value;
Transfer(_from, _to, _value);
return true;
}
return false;
}
/**
* @dev Give to target address ability for self token manipulation without sending
* @param _sender target address (future requester)
* @param _value amount of token values for approving
*/
function approve(address _sender, uint _value) returns (bool) {
allowance[msg.sender][_sender] += _value;
Approval(msg.sender, _sender, _value);
return true;
}
/**
* @dev Reset count of tokens approved for given address
* @param _address target address
*/
function unapprove(address _address)
{ allowance[msg.sender][_address] = 0; }
}
pragma solidity ^0.4.4;
/* The democracy contract itself */
contract Association is Owned {
/* Contract Variables and events */
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);
event ChangeOfRules(uint minimumQuorum, uint debatingPeriodInMinutes, address sharesTokenAddress);
struct Proposal {
address recipient;
uint amount;
string description;
uint votingDeadline;
bool executed;
bool proposalPassed;
uint numberOfVotes;
bytes32 proposalHash;
Vote[] votes;
mapping (address => bool) voted;
}
struct Vote {
bool inSupport;
address voter;
}
/* modifier that allows only shareholders to vote and create new proposals */
modifier onlyShareholders {
if (sharesTokenAddress.balanceOf(msg.sender) == 0) throw;
_;
}
/* First time setup */
function Association(address sharesAddress, uint minimumSharesToPassAVote, uint minutesForDebate) payable {
changeVotingRules(Token(sharesAddress), minimumSharesToPassAVote, minutesForDebate);
}
/*change rules*/
function changeVotingRules(Token sharesAddress, uint minimumSharesToPassAVote, uint minutesForDebate) onlyOwner {
sharesTokenAddress = Token(sharesAddress);
if (minimumSharesToPassAVote == 0 ) minimumSharesToPassAVote = 1;
minimumQuorum = minimumSharesToPassAVote;
debatingPeriodInMinutes = minutesForDebate;
ChangeOfRules(minimumQuorum, debatingPeriodInMinutes, sharesTokenAddress);
}
/* Function to create a new proposal */
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.executed = false;
p.proposalPassed = false;
p.numberOfVotes = 0;
ProposalAdded(proposalID, beneficiary, etherAmount, JobDescription);
numProposals = proposalID+1;
}
/* function to check if a proposal code matches */
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];
/* Check if the proposal can be executed */
if (now < p.votingDeadline /* has the voting deadline arrived? */
|| p.executed /* has it been already executed? */
|| p.proposalHash != sha3(p.recipient, p.amount, transactionBytecode)) /* Does the transaction code match the proposal? */
throw;
/* tally the votes */
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;
}
}
/* execute result */
if (quorum <= minimumQuorum) {
/* Not enough significant voters */
throw;
} else if (yea > nay ) {
/* has quorum and was approved */
p.executed = true;
if (!p.recipient.call.value(p.amount * 1 ether)(transactionBytecode)) {
throw;
}
p.proposalPassed = true;
} else {
p.proposalPassed = false;
}
// Fire Events
ProposalTallied(proposalNumber, result, quorum, p.proposalPassed);
}
}
pragma solidity ^0.4.4;
library CreatorAssociation {
function create(address sharesAddress, uint256 minimumSharesToPassAVote, uint256 minutesForDebate) returns (Association)
{ return new Association(sharesAddress, minimumSharesToPassAVote, minutesForDebate); }
function version() constant returns (string)
{ return "v0.5.0 (6d589277)"; }
function abi() constant returns (string)
{ return '[{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"proposals","outputs":[{"name":"recipient","type":"address"},{"name":"amount","type":"uint256"},{"name":"description","type":"string"},{"name":"votingDeadline","type":"uint256"},{"name":"executed","type":"bool"},{"name":"proposalPassed","type":"bool"},{"name":"numberOfVotes","type":"uint256"},{"name":"proposalHash","type":"bytes32"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"proposalNumber","type":"uint256"},{"name":"transactionBytecode","type":"bytes"}],"name":"executeProposal","outputs":[{"name":"result","type":"int256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"sharesTokenAddress","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"numProposals","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"sharesAddress","type":"address"},{"name":"minimumSharesToPassAVote","type":"uint256"},{"name":"minutesForDebate","type":"uint256"}],"name":"changeVotingRules","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_owner","type":"address"}],"name":"delegate","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"debatingPeriodInMinutes","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"minimumQuorum","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"beneficiary","type":"address"},{"name":"etherAmount","type":"uint256"},{"name":"JobDescription","type":"string"},{"name":"transactionBytecode","type":"bytes"}],"name":"newProposal","outputs":[{"name":"proposalID","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"proposalNumber","type":"uint256"},{"name":"supportsProposal","type":"bool"}],"name":"vote","outputs":[{"name":"voteID","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"proposalNumber","type":"uint256"},{"name":"beneficiary","type":"address"},{"name":"etherAmount","type":"uint256"},{"name":"transactionBytecode","type":"bytes"}],"name":"checkProposalCode","outputs":[{"name":"codeChecksOut","type":"bool"}],"payable":false,"type":"function"},{"inputs":[{"name":"sharesAddress","type":"address"},{"name":"minimumSharesToPassAVote","type":"uint256"},{"name":"minutesForDebate","type":"uint256"}],"type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"name":"proposalID","type":"uint256"},{"indexed":false,"name":"recipient","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"description","type":"string"}],"name":"ProposalAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"proposalID","type":"uint256"},{"indexed":false,"name":"position","type":"bool"},{"indexed":false,"name":"voter","type":"address"}],"name":"Voted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"proposalID","type":"uint256"},{"indexed":false,"name":"result","type":"int256"},{"indexed":false,"name":"quorum","type":"uint256"},{"indexed":false,"name":"active","type":"bool"}],"name":"ProposalTallied","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"minimumQuorum","type":"uint256"},{"indexed":false,"name":"debatingPeriodInMinutes","type":"uint256"},{"indexed":false,"name":"sharesTokenAddress","type":"address"}],"name":"ChangeOfRules","type":"event"}]'; }
}
pragma solidity ^0.4.4;
/**
* @title Builder based contract
*/
contract Builder is Mortal {
/**
* @dev this event emitted for every builded contract
*/
event Builded(address indexed client, address indexed instance);
/* Addresses builded contracts at sender */
mapping(address => address[]) public getContractsOf;
/**
* @dev Get last address
* @return last address contract
*/
function getLastContract() constant returns (address) {
var sender_contracts = getContractsOf[msg.sender];
return sender_contracts[sender_contracts.length - 1];
}
/* Building beneficiary */
address public beneficiary;
/**
* @dev Set beneficiary
* @param _beneficiary is address of beneficiary
*/
function setBeneficiary(address _beneficiary) onlyOwner
{ beneficiary = _beneficiary; }
/* Building cost */
uint public buildingCostWei;
/**
* @dev Set building cost
* @param _buildingCostWei is cost
*/
function setCost(uint _buildingCostWei) onlyOwner
{ buildingCostWei = _buildingCostWei; }
/* Security check report */
string public securityCheckURI;
/**
* @dev Set security check report URI
* @param _uri is an URI to report
*/
function setSecurityCheck(string _uri) onlyOwner
{ securityCheckURI = _uri; }
}
//
// AIRA Builder for Association contract
//
// Ethereum address:
// - Mainnet:
// - Testnet:
//
pragma solidity ^0.4.4;
/**
* @title BuilderAssociation contract
*/
contract BuilderAssociation is Builder {
/**
* @dev Run script creation contract
* @return address new contract
*/
function create(address sharesAddress,
uint256 minimumSharesToPassAVote,
uint256 minutesForDebate,
address _client) payable returns (address) {
if (buildingCostWei > 0 && beneficiary != 0) {
// Too low value
if (msg.value < buildingCostWei) throw;
// Beneficiary send
if (!beneficiary.send(buildingCostWei)) throw;
// Refund
if (msg.value > buildingCostWei) {
if (!msg.sender.send(msg.value - buildingCostWei)) throw;
}
} else {
// Refund all
if (msg.value > 0) {
if (!msg.sender.send(msg.value)) throw;
}
}
if (_client == 0)
_client = msg.sender;
var inst = CreatorAssociation.create(sharesAddress,
minimumSharesToPassAVote,
minutesForDebate);
inst.delegate(_client);
getContractsOf[_client].push(inst);
Builded(_client, inst);
return inst;
}
}External Links
Related contracts
AddressList
Same deployerA doubly linked list of addresses, deployed as a shared library
0xb0af78...dff94bAugust 18, 2016Contract 0x7e62ca...86e943
Same deployerAn address to address map with iteration, deployed as a shared library
0x7e62ca...86e943August 18, 2016CreatorTokenEmission
Same deployerA factory library that deploys mintable and burnable tokens, and hands back their ABI
0x63bfd6...63231eAugust 18, 2016CreatorTokenEther
Same deployerA factory library that deploys tokens backed one for one by ether held in the token
0x01f568...7b8312August 18, 2016AddressList
Same deployerA doubly linked list of addresses, deployed as a shared library
0xb51afd...224574August 25, 2016Contract 0xed6216...c0bce9
Same deployerAn address to address map with iteration, deployed as a shared library
0xed6216...c0bce9August 25, 2016