A factory library that deploys simple majority voting contracts
Historical Significance
Governance offered as a deployable component in August 2016, two months after The DAO failed, from a toolkit that treated a vote as something you create rather than something you write.
Context
Deployed in the Homestead era, when a DAO toolkit had to build its own data structures because Solidity shipped none.
Key Facts
Description
CreatorVoting51 is one of the factory libraries in Airalab's DAO toolkit. Its create function deploys a Voting51 contract, a poll that carries a list of options, records one vote per address and resolves when an option passes fifty one percent. Like the other creators it also reports the toolkit release it was built from and returns the full ABI of the contract it creates as a JSON string, so a dapp can call the new poll without being told its shape out of band. Deployed on 25 August 2016 by 0x4af013afbadb22d8a88c92d68fc96b033b9ebb8a and recovered from airalab/core.
DAO Fork Era
The controversial fork to recover funds from The DAO hack.
Bytecode Overview
Verified Source Available
This contract has verified source code on Etherscan.
Show source code (Solidity)
// Submitted by EthereumHistory (ethereumhistory.com)
/**
* @title The root contract
* @dev This contract is used as base of all contracts,
* e.g. it change default behaviour of fallback function
*/
contract Object {
/**
* @dev Default fallback behaviour will throw sended ethers
*/
function() { throw; }
}
/**
* @title Contract for object that have an owner
*/
contract Owned is Object {
/**
* 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; _ }
}
/**
* @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); }
}
/**
* @title Owned contract modificator
* @dev It's abstract contract is a way to make some actions with `Owned` contract delayed.
* The use case typically have three steps:
* - create modify contract with owned target
* - (optional) setup `Modify` contract
* - delegate owned contract to `Modify` and `run()` modification
*/
contract Modify is Mortal {
Owned public target;
/**
* @dev Contract constructor
* @param _target is a owned target of modification
*/
function Modify(Owned _target)
{ target = _target; }
/**
* @dev Modification runner
* @notice the `target` should be delegated to this first
*/
function run() onlyOwner {
if (target.owner() != address(this)) throw;
modify();
target.delegate(msg.sender);
}
function modify() internal;
}
/**
* @dev Double linked list with address items
*/
library AddressList {
struct Data {
address head;
address tail;
mapping(address => bool) isContain;
mapping(address => address) nextOf;
mapping(address => address) prevOf;
}
function first(Data storage _data) constant returns (address)
{ return _data.head; }
function last(Data storage _data) constant returns (address)
{ return _data.tail; }
/**
* @dev Chec list for element
* @param _data is list storage ref
* @param _item is an element
* @return `true` when element in list
*/
function contains(Data storage _data, address _item) constant returns (bool)
{ return _data.isContain[_item]; }
/**
* @dev Next element of list
* @param _data is list storage ref
* @param _item is current element of list
* @return next elemen of list
*/
function next(Data storage _data, address _item) constant returns (address)
{ return _data.nextOf[_item]; }
/**
* @dev Previous element of list
* @param _data is list storage ref
* @param _item is current element of list
* @return previous element of list
*/
function prev(Data storage _data, address _item) constant returns (address)
{ return _data.prevOf[_item]; }
/**
* @dev Append element to end of list
* @param _data is list storage ref
* @param _item is a new list element
*/
function append(Data storage _data, address _item)
{ append(_data, _item, _data.tail); }
/**
* @dev Append element to end of element
* @param _data is list storage ref
* @param _item is a new list element
* @param _to is a item element before new
* @notice gas usage < 100000
*/
function append(Data storage _data, address _item, address _to) {
// Unable to contain double element
if (_data.isContain[_item]) throw;
// Empty list
if (_data.head == 0) {
_data.head = _data.tail = _item;
} else {
if (!_data.isContain[_to]) throw;
var nextTo = _data.nextOf[_to];
if (nextTo != 0) {
_data.prevOf[nextTo] = _item;
} else {
_data.tail = _item;
}
_data.nextOf[_to] = _item;
_data.prevOf[_item] = _to;
_data.nextOf[_item] = nextTo;
}
_data.isContain[_item] = true;
}
/**
* @dev Prepend element to begin of list
* @param _data is list storage ref
* @param _item is a new list element
*/
function prepend(Data storage _data, address _item)
{ prepend(_data, _item, _data.head); }
/**
* @dev Prepend element to element of list
* @param _data is list storage ref
* @param _item is a new list element
* @param _to is a item element before new
*/
function prepend(Data storage _data, address _item, address _to) {
// Unable to contain double element
if (_data.isContain[_item]) throw;
// Empty list
if (_data.head == 0) {
_data.head = _data.tail = _item;
} else {
if (!_data.isContain[_to]) throw;
var prevTo = _data.prevOf[_to];
if (prevTo != 0) {
_data.nextOf[prevTo] = _item;
} else {
_data.head = _item;
}
_data.prevOf[_item] = prevTo;
_data.nextOf[_item] = _to;
_data.prevOf[_to] = _item;
}
_data.isContain[_item] = true;
}
/**
* @dev Remove element from list
* @param _data is list storage ref
* @param _item is a removed list element
*/
function remove(Data storage _data, address _item) {
if (!_data.isContain[_item]) throw;
var elemPrev = _data.prevOf[_item];
var elemNext = _data.nextOf[_item];
if (elemPrev != 0) {
_data.nextOf[elemPrev] = elemNext;
} else {
_data.head = elemNext;
}
if (elemNext != 0) {
_data.prevOf[elemNext] = elemPrev;
} else {
_data.tail = elemPrev;
}
_data.isContain[_item] = false;
}
/**
* @dev Replace element on list
* @param _data is list storage ref
* @param _from is old element
* @param _to is a new element
*/
function replace(Data storage _data, address _from, address _to) {
if (!_data.isContain[_from]) throw;
var elemPrev = _data.prevOf[_from];
var elemNext = _data.nextOf[_from];
if (elemPrev != 0) {
_data.nextOf[elemPrev] = _to;
} else {
_data.head = _to;
}
if (elemNext != 0) {
_data.prevOf[elemNext] = _to;
} else {
_data.tail = _to;
}
_data.prevOf[_to] = elemPrev;
_data.nextOf[_to] = elemNext;
_data.isContain[_from] = false;
}
/**
* @dev Swap two elements of list
* @param _data is list storage ref
* @param _a is a first element
* @param _b is a second element
*/
function swap(Data storage _data, address _a, address _b) {
if (!_data.isContain[_a] || !_data.isContain[_b]) throw;
var prevA = _data.prevOf[_a];
remove(_data, _a);
replace(_data, _b, _a);
if (prevA == 0) {
prepend(_data, _b);
} else {
append(_data, _b, prevA);
}
}
}
/**
* @dev Iterable by index (string => address) mapping structure
* with reverse resolve and fast element remove
*/
library AddressMap {
struct Data {
mapping(bytes32 => address) valueOf;
mapping(address => string) keyOf;
AddressList.Data items;
}
using AddressList for AddressList.Data;
/**
* @dev Get element by name
* @param _data is an map storage ref
* @param _key is a item key
* @return item value
*/
function get(Data storage _data, string _key) constant returns (address)
{ return _data.valueOf[sha3(_key)]; }
/** Get key of element
* @param _data is an map storage ref
* @param _item is a item
* @return item key
*/
function getKey(Data storage _data, address _item) constant returns (string)
{ return _data.keyOf[_item]; }
/**
* @dev Set element value for given key
* @param _data is an map storage ref
* @param _key is a item key
* @param _value is a item value
* @notice by design you can't set different keys with same value
*/
function set(Data storage _data, string _key, address _value) {
var replaced = get(_data, _key);
if (replaced != 0)
_data.items.replace(replaced, _value);
else
_data.items.append(_value);
_data.valueOf[sha3(_key)] = _value;
_data.keyOf[_value] = _key;
}
/**
* @dev Remove item from map by key
* @param _data is an map storage ref
* @param _key is and item key
*/
function remove(Data storage _data, string _key) {
var value = get(_data, _key);
_data.items.remove(value);
_data.valueOf[sha3(_key)] = 0;
_data.keyOf[value] = "";
}
}
/**
* @title The DAO core contract basicaly describe the organisation and contain:
* agent storage,
* infrastructure nodes,
* contract templates
*/
contract Core is Mortal {
/* Short description */
string public name;
string public description;
address public founder;
/* Modules map */
AddressMap.Data modules;
/* Module constant mapping */
mapping(bytes32 => bool) is_constant;
/**
* @dev Interface storage
* the contract interface contains source URI
*/
mapping(address => string) public interfaceOf;
/* Using libraries */
using AddressList for AddressList.Data;
using AddressMap for AddressMap.Data;
/**
* @dev DAO constructor
* @param _name is a DAO name
* @param _description is a short DAO description
*/
function Core(string _name, string _description) {
name = _name;
description = _description;
founder = msg.sender;
}
/**
* @dev Fast module exist check
* @param _module is a module address
* @return `true` wnen core contains module
*/
function contains(address _module) constant returns (bool)
{ return modules.items.contains(_module); }
/**
* @dev Check for module have permanent name
* @param _name is a module name
* @return `true` when module have permanent name
*/
function isConstant(string _name) constant returns (bool)
{ return is_constant[sha3(_name)]; }
/**
* @dev Get module by name
* @param _name is module name
* @return module address
*/
function getModule(string _name) constant returns (address)
{ return modules.get(_name); }
/**
* @dev Get module name by address
* @param _module is a module address
* @return module name
*/
function getModuleName(address _module) constant returns (string)
{ return modules.keyOf[_module]; }
/**
* @dev Get first module
* @return first address
*/
function firstModule() constant returns (address)
{ return modules.items.head; }
/**
* @dev Get next module
* @param _current is an current address
* @return next address
*/
function nextModule(address _current) constant returns (address)
{ return modules.items.next(_current); }
/**
* @dev Set new module for given name
* @param _name infrastructure node name
* @param _module infrastructure node address
* @param _interface node interface URI
* @param _constant have a `true` value when you create permanent name of module
*/
function setModule(string _name, address _module, string _interface, bool _constant) onlyOwner {
if (isConstant(_name)) throw;
// Set module in the map
modules.set(_name, _module);
// Register node interface
interfaceOf[_module] = _interface;
// Register constant module
is_constant[sha3(_name)] = _constant;
}
/**
* @dev Remove module by name
* @param _name module name
*/
function removeModule(string _name) onlyOwner {
if (isConstant(_name)) throw;
// Remove module
modules.remove(_name);
}
}
/**
* @title DAO Core modificator
* @dev It's contract can modify core by set/remove modules
*/
contract CoreModify is Modify {
function CoreModify(address _target) Modify(Owned(_target)) {}
enum ModifyType {
SetModule,
RemoveModule
}
struct ModuleParams {
string name;
address module;
string interface;
bool isConstant;
}
ModuleParams modParams;
ModifyType modType;
function modify() internal {
if (modType == ModifyType.SetModule) {
Core(target).setModule(modParams.name,
modParams.module,
modParams.interface,
modParams.isConstant);
} else {
Core(target).removeModule(modParams.name);
}
}
/**
* @dev Set core module
* @param _name is a module name
* @param _module is a module address
* @param _interface is a module interface
* @param _constant is a flag for set module constant
*/
function setModule(string _name, address _module,
string _interface, bool _constant) onlyOwner {
modParams = ModuleParams(_name, _module, _interface, _constant);
modType = ModifyType.SetModule;
}
/**
* @dev Remove module from core register
* @param _name is a module name
*/
function removeModule(string _name) onlyOwner {
modParams.name = _name;
modType = ModifyType.RemoveModule;
}
}
library CreatorCoreModify {
function create(address _target) returns (CoreModify)
{ return new CoreModify(_target); }
function version() constant returns (string)
{ return "v0.4.9 (922689d1)"; }
function interface() constant returns (string)
{ return '[{"constant":false,"inputs":[],"name":"kill","outputs":[],"type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"string"}],"name":"removeModule","outputs":[],"type":"function"},{"constant":false,"inputs":[{"name":"_owner","type":"address"}],"name":"delegate","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"type":"function"},{"constant":false,"inputs":[],"name":"run","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"target","outputs":[{"name":"","type":"address"}],"type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"string"},{"name":"_module","type":"address"},{"name":"_interface","type":"string"},{"name":"_constant","type":"bool"}],"name":"setModule","outputs":[],"type":"function"},{"inputs":[{"name":"_target","type":"address"}],"type":"constructor"}]'; }
}
/**
* @title Token contract represents any asset in digital economy
*/
contract Token is Owned {
event Transfer(address indexed _from, address indexed _to, uint256 _value);
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
/* 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 _address target address
* @param _value amount of token values for approving
*/
function approve(address _address, uint _value) {
allowance[msg.sender][_address] += _value;
Approval(msg.sender, _address, _value);
}
/**
* @dev Reset count of tokens approved for given address
* @param _address target address
*/
function unapprove(address _address)
{ allowance[msg.sender][_address] = 0; }
}
contract ProposalDoneReceiver {
function proposalDone(uint _index);
}
/**
* @dev The 51% voting
*/
contract Voting51 is Owned {
Token public voting_token;
ProposalDoneReceiver public receiver;
address[] public proposal_target;
mapping(uint => uint) public start_time;
mapping(uint => uint) public end_time;
mapping(uint => string) public description;
mapping(uint => uint) public total_value;
mapping(uint => mapping(address => uint)) public voter_value;
uint public current_proposal = 0;
event ProposalDone(uint indexed index);
event ProposalNew(uint indexed index);
/**
* @dev Create voting contract for given voting token
* @param _voting_token is a token used for voting actions
* @param _receiver is a receiver for proposal done actions
*/
function Voting51(address _voting_token, address _receiver) {
voting_token = Token(_voting_token);
receiver = ProposalDoneReceiver(_receiver);
}
/**
* @dev Append new proposal for voting
* @param _target is a proposal target
* @param _description is a proposal description
* @param _start_time is a start time of voting
* @param _duration_sec is a duration of voting
* @notice only voters (accounts with positive voting token balance) can call it
*/
function proposal(address _target, string _description,
uint _start_time, uint _duration_sec) onlyOwner {
description[proposal_target.length] = _description;
start_time[proposal_target.length] = _start_time;
end_time[proposal_target.length] = _start_time + _duration_sec;
proposal_target.push(_target);
ProposalNew(proposal_target.length-1);
}
/**
* @dev Voting for current proposal
* @param _count is how amount of `voting_token` used
* @notice `voting_token` should be approved for voting
*/
function vote(uint _count) {
// Check for no proposal exist
if (proposal_target[current_proposal] == 0
|| now < start_time[current_proposal]) throw;
// Check for end of voting time
if (now > end_time[current_proposal]) {
++current_proposal;
return;
}
// Thransfer token
if (!voting_token.transferFrom(msg.sender, this, _count)) throw;
// Increment values
total_value[current_proposal] += _count;
voter_value[current_proposal][msg.sender] += _count;
var voting_limit = voting_token.totalSupply() / 2; // 50%
// Check vote done
if (total_value[current_proposal] > voting_limit) {
ProposalDone(current_proposal);
receiver.proposalDone(current_proposal++);
}
}
/**
* @dev Refund voting tokens
* @param _proposal is a proposal id
* @param _count is how amount of tokens should be refunded
*/
function refund(uint _proposal, uint _count) {
if (voter_value[_proposal][msg.sender] < _count) throw;
if (!voting_token.transfer(msg.sender, _count)) throw;
voter_value[_proposal][msg.sender] -= _count;
}
}
library CreatorVoting51 {
function create(address _voting_token, address _receiver) returns (Voting51)
{ return new Voting51(_voting_token, _receiver); }
function version() constant returns (string)
{ return "v0.4.9 (468afc69)"; }
function interface() constant returns (string)
{ return '[{"constant":true,"inputs":[],"name":"current_proposal","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[{"name":"_count","type":"uint256"}],"name":"vote","outputs":[],"type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"},{"name":"","type":"address"}],"name":"voter_value","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"description","outputs":[{"name":"","type":"string"}],"type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"end_time","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[{"name":"_proposal","type":"uint256"},{"name":"_count","type":"uint256"}],"name":"refund","outputs":[],"type":"function"},{"constant":false,"inputs":[{"name":"_owner","type":"address"}],"name":"delegate","outputs":[],"type":"function"},{"constant":false,"inputs":[{"name":"_target","type":"address"},{"name":"_description","type":"string"},{"name":"_start_time","type":"uint256"},{"name":"_duration_sec","type":"uint256"}],"name":"proposal","outputs":[],"type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"start_time","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"proposal_target","outputs":[{"name":"","type":"address"}],"type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"total_value","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":true,"inputs":[],"name":"voting_token","outputs":[{"name":"","type":"address"}],"type":"function"},{"constant":true,"inputs":[],"name":"receiver","outputs":[{"name":"","type":"address"}],"type":"function"},{"inputs":[{"name":"_voting_token","type":"address"},{"name":"_receiver","type":"address"}],"type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"index","type":"uint256"}],"name":"ProposalDone","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"index","type":"uint256"}],"name":"ProposalNew","type":"event"}]'; }
}
/**
* @dev The library for multiuser singletoken regulation.
* This data contains stack of variants sorted by value on its internal balance,
* any account(voter) can increase variant balance by self balance from given token,
* and any voter can decrease balance of variant but no more that given.
* The variant with high balance placed on top of voting pool and return by `current()`.
*/
library Voting {
/* Voting structure */
struct Poll {
/* Stack of all voters */
AddressList.Data voters;
/* Stack of all variants by value */
AddressList.Data variants;
/* Count of shares for given variant */
mapping(address => uint) valueOf;
/* Count of shares for given voter */
mapping(address => uint) shareOf;
/* Poll variant for given voter */
mapping(address => address) pollOf;
}
using AddressList for AddressList.Data;
/**
* @dev Current high value poll
* @param _poll ref to `Poll` structure
* @return current value
*/
function current(Poll storage _poll) constant returns (address)
{ return _poll.variants.first(); }
/**
* @dev Increase poll shares for given variant
* @param _poll ref to `Poll` structure
* @param _variant voter variant value
* @param _shares token represents vote
* @param _count how much votes are given
*/
function up(Poll storage _poll, address _voter, address _variant,
Token _shares, uint _count) {
// Check for already voting for any variant
if (_poll.pollOf[_voter] != 0 && _poll.pollOf[_voter] != _variant)
throw;
// Try to transfer count of shares from voter to self
if (!_shares.transferFrom(_voter, this, _count))
throw;
// Increase shares and set the poll
_poll.shareOf[_voter] += _count;
_poll.pollOf[_voter] = _variant;
_poll.valueOf[_variant] += _count;
// Append voter if not in list
if (!_poll.voters.contains(_voter))
_poll.voters.append(_voter);
// Append variant if not in list
if (!_poll.variants.contains(_variant))
_poll.variants.append(_variant);
// Shift variant in the stack
shiftLeft(_poll, _variant);
}
/**
* @dev Decrease poll shares of given voter
* @param _poll ref to `Poll` structure
* @param _count how much shares will decreased
*/
function down(Poll storage _poll, address _voter, Token _shares, uint _count) {
// So I can refund no more that gives from voter
var refund = _poll.shareOf[_voter] > _count ? _count : _poll.shareOf[_voter];
var variant = _poll.pollOf[_voter];
// Transfer shares
_shares.transfer(_voter, refund);
_poll.shareOf[_voter] -= refund;
_poll.valueOf[variant] -= refund;
// Clean voter poll
if (_poll.shareOf[_voter] == 0)
_poll.pollOf[_voter] = 0;
// Shift right or drop when no shares
if (_poll.valueOf[variant] > 0) {
shiftRight(_poll, _poll.pollOf[_voter]);
} else {
_poll.variants.remove(variant);
}
}
/*
* Shifting mechanism
* Thesys: the stack of variants should be sorted by valueOf value.
* Solution:
* - `up` call: variant shifted left while his valueOf value is large
* - `down` call: varian shifted right in the stack while valueOf value is low
*/
function shiftLeft(Poll storage _poll, address _variant) internal {
var value = _poll.valueOf[_variant];
var left = _poll.variants.prevOf[_variant];
/* XXX: possible DoS by block gas limit
when a lot of same value variants */
while (left != 0 && _poll.valueOf[left] < value)
left = _poll.variants.prevOf[_variant];
_poll.variants.remove(_variant);
_poll.variants.append(_variant, left);
}
function shiftRight(Poll storage _poll, address _variant) internal {
var value = _poll.valueOf[_variant];
var right = _poll.variants.nextOf[_variant];
/* XXX: possible DoS by block gas limit
when a lot of same value variants */
while (right != 0 && _poll.valueOf[right] > value)
right = _poll.variants.nextOf[_variant];
_poll.variants.remove(_variant);
_poll.variants.prepend(_variant, right);
}
}
contract BoardOfDirectorsFund {
address public target;
uint public value;
function BoardOfDirectorsFund(address _target, uint _value) {
target = _target;
value = _value;
}
}
contract BoardOfDirectors is Owned, ProposalDoneReceiver {
Core public dao_core;
Token public shares;
Token public credits;
Voting51 public voting;
Voting.Poll voting_token;
using Voting for Voting.Poll;
using AddressList for AddressList.Data;
event VotingTokenChanged(address indexed new_token);
/**
* @dev Board of directors constructor
* @param _dao_core is a DAO core register
* @param _shares is a share holders token
* @param _credits is a fund token
*/
function BoardOfDirectors(address _dao_core, address _shares, address _credits) {
dao_core = Core(_dao_core);
shares = Token(_shares);
credits = Token(_credits);
}
modifier onlyDirectors {
if (address(voting) != 0 && voting.voting_token().balanceOf(msg.sender) > 0) _
}
enum ProposalType {
CoreModify,
Fund
}
mapping(address => ProposalType) typeOf;
/**
* @dev Make a proposal for remove module from DAO register
* @param _name is a module name
* @param _description is a proposal description
* @param _start_time is start time of voting
* @param _duration_sec is duration of voting
*/
function removeCoreModule(string _name, string _description,
uint _start_time, uint _duration_sec) onlyDirectors {
if (address(voting) == 0) throw;
var mod = CreatorCoreModify.create(dao_core);
typeOf[mod] = ProposalType.CoreModify;
mod.removeModule(_name);
voting.proposal(mod, _description, _start_time, _duration_sec);
}
/**
* @dev Make a proposal for set new module for the DAO register
* @param _name is a module name
* @param _module is a module address
* @param _interface is a link for module interface
* @param _constant is a flag for constant modules
* @param _description is a proposal description
* @param _start_time is start time of voting
* @param _duration_sec is duration of voting
*/
function setCoreModule(string _name, address _module,
string _interface, bool _constant,
string _description,
uint _start_time, uint _duration_sec) onlyDirectors {
if (address(voting) == 0) throw;
var mod = CreatorCoreModify.create(dao_core);
typeOf[mod] = ProposalType.CoreModify;
mod.setModule(_name, _module, _interface, _constant);
voting.proposal(mod, _description, _start_time, _duration_sec);
}
/**
* @dev Make a proposal for funding address
* @param _target is a target of fund
* @param _value is a value of fund
* @param _description is a proposal description
* @param _start_time is start time of voting
* @param _duration_sec is duration of voting
*/
function fund(address _target, uint _value,
string _description, uint _start_time, uint _duration_sec) onlyDirectors {
if (address(voting) == 0) throw;
var bod_fund = new BoardOfDirectorsFund(_target, _value);
typeOf[bod_fund] = ProposalType.Fund;
voting.proposal(bod_fund, _description, _start_time, _duration_sec);
}
/**
* @dev Service callback function for proposal done tracking
*/
function proposalDone(uint _index) {
if (msg.sender != address(voting)) throw;
var proposal = voting.proposal_target(_index);
if (typeOf[proposal] == ProposalType.CoreModify) {
dao_core.delegate(proposal);
Modify(proposal).run();
} else {
if (typeOf[proposal] == ProposalType.Fund) {
var bod_fund = BoardOfDirectorsFund(proposal);
if (!credits.transfer(bod_fund.target(), bod_fund.value()))
throw;
}
}
}
/**
* @dev Voting DoS protection
* @return minimal count of shares to voting for new token
*/
function minVotingShares() constant returns (uint)
{ return shares.totalSupply() / 100; }
/**
* @dev Vote for the new directors token
* @param _new_voting is a new voting token
* @param _count is a count of shares
* @notice shares should be approved for this contract
*/
function pollUp(Token _new_voting, uint _count) {
// Voting DoS protection
if (!voting_token.variants.contains(_new_voting)
&& _count < minVotingShares()) throw;
// Voting
voting_token.up(msg.sender, _new_voting, shares, _count);
checkVotingToken();
}
/**
* @dev Refund shares
* @param _count is a count of refunded shares
*/
function pollDown(uint _count) {
voting_token.down(msg.sender, shares, _count);
checkVotingToken();
}
function checkVotingToken() private {
if (address(voting) == 0) throw;
if ( voting.voting_token() != voting_token.current()
&& voting_token.valueOf[voting_token.current()] > shares.totalSupply() / 2) {
voting = CreatorVoting51.create(Token(voting_token.current()), this);
VotingTokenChanged(voting_token.current());
}
}
}
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