A factory library that deploys mintable tokens with a list of authorised minters
Historical Significance
Contract creation offered as a service by a library, with the created contract's ABI published on chain beside it. The library reports its own toolkit release and git commit through a version function, which is how it was traced back to its source.
Context
Deployed in the Homestead era, when a dapp that wanted to create a contract had to ship a compiler or a hardcoded blob.
Key Facts
Description
CreatorTokenEmissionACL is one of the factory libraries in Airalab's DAO toolkit. Its create function deploys a token that can mint and burn like the plain emission token, but gates minting behind an access control list rather than a single owner, so a group of accounts can be authorised to issue. Two further functions make it self describing on chain, version returning the toolkit release it was built from and interface returning the full ABI of the token it creates as a JSON string. Deployed on 30 November 2016 by 0x4af013afbadb22d8a88c92d68fc96b033b9ebb8a and recovered from airalab/core.
Spurious Dragon Era
Continued DoS protection. State trie clearing.
Bytecode Overview
Verified Source Available
This contract has verified source code on Etherscan.
Show 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
uint256 public totalSupply;
/// @param _owner The address from which the balance will be retrieved
/// @return The balance
function balanceOf(address _owner) constant returns (uint256);
/// @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);
/// @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);
/// @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);
/// @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);
// 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) balances;
mapping(address => mapping(address => uint)) allowances;
/**
* @dev Get balance of plain address
* @param _owner is a target address
* @return amount of tokens on balance
*/
function balanceOf(address _owner) constant returns (uint256)
{ return balances[_owner]; }
/**
* @dev Take allowed tokens
* @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)
{ return allowances[_owner][_spender]; }
/* Token constructor */
function Token(string _name, string _symbol, uint8 _decimals, uint _count) {
name = _name;
symbol = _symbol;
decimals = _decimals;
totalSupply = _count;
balances[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 (balances[msg.sender] >= _value) {
balances[msg.sender] -= _value;
balances[_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, uint256 _value) returns (bool) {
var avail = allowances[_from][msg.sender]
> balances[_from] ? balances[_from]
: allowances[_from][msg.sender];
if (avail >= _value) {
allowances[_from][msg.sender] -= _value;
balances[_from] -= _value;
balances[_to] += _value;
Transfer(_from, _to, _value);
return true;
}
return false;
}
/**
* @dev Give to target address ability for self token manipulation without sending
* @param _spender target address (future requester)
* @param _value amount of token values for approving
*/
function approve(address _spender, uint256 _value) returns (bool) {
allowances[msg.sender][_spender] += _value;
Approval(msg.sender, _spender, _value);
return true;
}
/**
* @dev Reset count of tokens approved for given address
* @param _spender target address (future requester)
*/
function unapprove(address _spender)
{ allowances[msg.sender][_spender] = 0; }
}
pragma solidity ^0.4.4;
contract TokenEmission is Token {
function TokenEmission(string _name, string _symbol, uint8 _decimals,
uint _start_count)
Token(_name, _symbol, _decimals, _start_count)
{}
/**
* @dev Token emission
* @param _value amount of token values to emit
* @notice owner balance will be increased by `_value`
*/
function emission(uint _value) onlyOwner {
// Overflow check
if (_value + totalSupply < totalSupply) throw;
totalSupply += _value;
balances[owner] += _value;
}
/**
* @dev Burn the token values from sender balance and from total
* @param _value amount of token values for burn
* @notice sender balance will be decreased by `_value`
*/
function burn(uint _value) {
if (balances[msg.sender] >= _value) {
balances[msg.sender] -= _value;
totalSupply -= _value;
}
}
}
pragma solidity ^0.4.4;
/**
* @dev Double linked list with address items
*/
library AddressList {
struct Data {
address head;
address tail;
uint length;
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;
++_data.length;
}
/**
* @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;
++_data.length;
}
/**
* @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;
--_data.length;
}
/**
* @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);
}
}
}
pragma solidity ^0.4.4;
/**
* @title ACL storage contract
* @dev this contract used for store and manage access groups and its members
*/
contract ACLStorage is Owned {
// Group list
string[] public group;
/**
* @dev Size of group array
*/
function groupLength() constant returns (uint)
{ return group.length; }
// Group members list by SHA3 of group name
mapping(bytes32 => AddressList.Data) members;
using AddressList for AddressList.Data;
/**
* @dev Group members iteration start
* @param _group is a group name
* @return first member address
*/
function memberFirst(string _group) constant returns (address)
{ return members[sha3(_group)].first(); }
/**
* @dev Group members iteration
* @param _group is a group name
* @param _current is a current iteration address
* @return next iteration address
*/
function memberNext(string _group, address _current) constant returns (address)
{ return members[sha3(_group)].next(_current); }
/**
* @dev Check for `_member` address is member of `_groupName`
* @param _group is a group name for check
* @param _member is a address for member checking
* @return `true` when address is member of group
*/
function isMemberOf(string _group, address _member) constant returns (bool)
{ return members[sha3(_group)].contains(_member); }
/**
* @dev Create access group
* @param _name is a group name
* @param _firstMember is a first member address, group should not be empty
*/
function createGroup(string _name, address _firstMember) onlyOwner {
var mems = members[sha3(_name)];
if (mems.first() == 0) {
group[group.length++] = _name;
mems.append(_firstMember);
}
}
/**
* @dev Add new member into group
* @param _group is a group name
* @param _member is a new member address
*/
function addMember(string _group, address _member) onlyOwner
{ members[sha3(_group)].append(_member); }
/**
* @dev Remove member from group
* @param _group is a group name
* @param _member is a address for remove
*/
function removeMember(string _group, address _member) onlyOwner
{ members[sha3(_group)].remove(_member); }
}
pragma solidity ^0.4.4;
/**
* @title Access Control List contract
*/
contract ACL {
ACLStorage public acl;
modifier onlyGroup(string _name) {
if (!acl.isMemberOf(_name, msg.sender)) throw;
_;
}
}
pragma solidity ^0.4.4;
contract TokenEmissionACL is TokenEmission, ACL {
function TokenEmissionACL(string _name, string _symbol, uint8 _decimals,
uint _start_count,
address _acl_storage, string _emitent_group)
TokenEmission(_name, _symbol, _decimals, _start_count) {
acl = ACLStorage(_acl_storage);
emitentGroup = _emitent_group;
}
string public emitentGroup;
/**
* @dev Token emission
* @param _value amount of token values to emit
* @notice owner balance will be increased by `_value`
*/
function emission(uint _value) onlyGroup(emitentGroup) {
// Overflow check
if (_value + totalSupply < totalSupply) throw;
totalSupply += _value;
balances[msg.sender] += _value;
}
}
pragma solidity ^0.4.2;
library CreatorTokenEmissionACL {
function create(string _name, string _symbol, uint8 _decimals, uint256 _start_count, address _acl_storage, string _emitent_group) returns (TokenEmissionACL)
{ return new TokenEmissionACL(_name, _symbol, _decimals, _start_count, _acl_storage, _emitent_group); }
function version() constant returns (string)
{ return "v0.5.0 (041be4cf)"; }
function abi() constant returns (string)
{ return '[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_address","type":"address"},{"name":"_value","type":"uint256"}],"name":"approve","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"getBalance","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"kill","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_value","type":"uint256"}],"name":"burn","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_value","type":"uint256"}],"name":"emission","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_owner","type":"address"}],"name":"delegate","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"emitentGroup","outputs":[{"name":"","type":"string"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"acl","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_address","type":"address"}],"name":"getBalance","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_address","type":"address"}],"name":"unapprove","outputs":[],"payable":false,"type":"function"},{"inputs":[{"name":"_name","type":"string"},{"name":"_symbol","type":"string"},{"name":"_decimals","type":"uint8"},{"name":"_start_count","type":"uint256"},{"name":"_acl_storage","type":"address"},{"name":"_emitent_group","type":"string"}],"type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_from","type":"address"},{"indexed":true,"name":"_to","type":"address"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_owner","type":"address"},{"indexed":true,"name":"_spender","type":"address"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Approval","type":"event"}]'; }
}
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