ETH Price: $2,153.28 (-0.51%)
Gas: 0.04 Gwei

Transaction Decoder

Block:
5276237 at Mar-18-2018 08:15:20 AM +UTC
Transaction Fee:
0.00034442 ETH $0.74
Gas Used:
86,105 Gas / 4 Gwei

Emitted Events:

Account State Difference:

  Address   Before After State Difference Code
0x00eEE5f9...0cEbA141f
29.9319552279375 Eth
Nonce: 126177
29.9316108079375 Eth
Nonce: 126178
0.00034442
(DwarfPool)
519.370707131363438761 Eth519.371051551363438761 Eth0.00034442
0xB64ef51C...fBC0Ab8aC
0xeA5Ab833...D1703288A

Execution Trace

Issuer.issue( benefactor=0x3ef3348AcFBa8A26f331B52E3AE42b8c6920EB56, amount=184911810 )
  • CentrallyIssuedToken.transferFrom( _from=0xDa0131319B5d8fAA0F405d6c7cD2E629ceb35AC0, _to=0x3ef3348AcFBa8A26f331B52E3AE42b8c6920EB56, _value=184911810 ) => ( success=True )
    File 1 of 3: Issuer
    /*
     * ERC20 interface
     * see https://github.com/ethereum/EIPs/issues/20
     */
    contract ERC20 {
      uint public totalSupply;
      function balanceOf(address who) constant returns (uint);
      function allowance(address owner, address spender) constant returns (uint);
    
      function transfer(address to, uint value) returns (bool ok);
      function transferFrom(address from, address to, uint value) returns (bool ok);
      function approve(address spender, uint value) returns (bool ok);
      event Transfer(address indexed from, address indexed to, uint value);
      event Approval(address indexed owner, address indexed spender, uint value);
    }
    
    
    
    /**
     * Math operations with safety checks
     */
    contract SafeMath {
      function safeMul(uint a, uint b) internal returns (uint) {
        uint c = a * b;
        assert(a == 0 || c / a == b);
        return c;
      }
    
      function safeDiv(uint a, uint b) internal returns (uint) {
        assert(b > 0);
        uint c = a / b;
        assert(a == b * c + a % b);
        return c;
      }
    
      function safeSub(uint a, uint b) internal returns (uint) {
        assert(b <= a);
        return a - b;
      }
    
      function safeAdd(uint a, uint b) internal returns (uint) {
        uint c = a + b;
        assert(c>=a && c>=b);
        return c;
      }
    
      function max64(uint64 a, uint64 b) internal constant returns (uint64) {
        return a >= b ? a : b;
      }
    
      function min64(uint64 a, uint64 b) internal constant returns (uint64) {
        return a < b ? a : b;
      }
    
      function max256(uint256 a, uint256 b) internal constant returns (uint256) {
        return a >= b ? a : b;
      }
    
      function min256(uint256 a, uint256 b) internal constant returns (uint256) {
        return a < b ? a : b;
      }
    
      function assert(bool assertion) internal {
        if (!assertion) {
          throw;
        }
      }
    }
    
    
    
    /**
     * Standard ERC20 token with Short Hand Attack and approve() race condition mitigation.
     *
     * Based on code by FirstBlood:
     * https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol
     */
    contract StandardToken is ERC20, SafeMath {
    
      mapping(address => uint) balances;
      mapping (address => mapping (address => uint)) allowed;
    
      // Interface marker
      bool public constant isToken = true;
    
      /**
       *
       * Fix for the ERC20 short address attack
       *
       * http://vessenes.com/the-erc20-short-address-attack-explained/
       */
      modifier onlyPayloadSize(uint size) {
         if(msg.data.length < size + 4) {
           throw;
         }
         _;
      }
    
      function transfer(address _to, uint _value) onlyPayloadSize(2 * 32) returns (bool success) {
        balances[msg.sender] = safeSub(balances[msg.sender], _value);
        balances[_to] = safeAdd(balances[_to], _value);
        Transfer(msg.sender, _to, _value);
        return true;
      }
    
      function transferFrom(address _from, address _to, uint _value)  returns (bool success) {
        var _allowance = allowed[_from][msg.sender];
    
        // Check is not needed because safeSub(_allowance, _value) will already throw if this condition is not met
        // if (_value > _allowance) throw;
    
        balances[_to] = safeAdd(balances[_to], _value);
        balances[_from] = safeSub(balances[_from], _value);
        allowed[_from][msg.sender] = safeSub(_allowance, _value);
        Transfer(_from, _to, _value);
        return true;
      }
    
      function balanceOf(address _owner) constant returns (uint balance) {
        return balances[_owner];
      }
    
      function approve(address _spender, uint _value) returns (bool success) {
    
        // To change the approve amount you first have to reduce the addresses`
        //  allowance to zero by calling `approve(_spender, 0)` if it is not
        //  already 0 to mitigate the race condition described here:
        //  https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
        if ((_value != 0) && (allowed[msg.sender][_spender] != 0)) throw;
    
        allowed[msg.sender][_spender] = _value;
        Approval(msg.sender, _spender, _value);
        return true;
      }
    
      function allowance(address _owner, address _spender) constant returns (uint remaining) {
        return allowed[_owner][_spender];
      }
    
    }
    
    
    
    /*
     * Ownable
     *
     * Base contract with an owner.
     * Provides onlyOwner modifier, which prevents function from running if it is called by anyone other than the owner.
     */
    contract Ownable {
      address public owner;
    
      function Ownable() {
        owner = msg.sender;
      }
    
      modifier onlyOwner() {
        if (msg.sender != owner) {
          throw;
        }
        _;
      }
    
      function transferOwnership(address newOwner) onlyOwner {
        if (newOwner != address(0)) {
          owner = newOwner;
        }
      }
    
    }
    
    
    
    /**
     * Issuer manages token distribution after the crowdsale.
     *
     * This contract is fed a CSV file with Ethereum addresses and their
     * issued token balances.
     *
     * Issuer act as a gate keeper to ensure there is no double issuance
     * per address, in the case we need to do several issuance batches,
     * there is a race condition or there is a fat finger error.
     *
     * Issuer contract gets allowance from the team multisig to distribute tokens.
     *
     */
    contract Issuer is Ownable, SafeMath {
    
      /** Map addresses whose tokens we have already issued. */
      mapping(address => bool) public issued;
    
      /** Centrally issued token we are distributing to our contributors */
      StandardToken public token;
    
      /** Party (team multisig) who is in the control of the token pool. Note that this will be different from the owner address (scripted) that calls this contract. */
      address public masterTokenBalanceHolder;
    
      /** How many addresses have received their tokens. */
      uint public issuedCount;
    
      /**
       *
       * @param _issuerDeploymentAccount Ethereun account that controls the issuance process and pays the gas fee
       * @param _token Token contract address
       * @param _masterTokenBalanceHolder Multisig address that does StandardToken.approve() to give allowance for this contract
       */
      function Issuer(address _issuerDeploymentAccount, address _masterTokenBalanceHolder, StandardToken _token) {
        owner = _issuerDeploymentAccount;
        masterTokenBalanceHolder = _masterTokenBalanceHolder;
        token = _token;
      }
    
      function issue(address benefactor, uint amount) onlyOwner {
        if(issued[benefactor]) throw;
        token.transferFrom(masterTokenBalanceHolder, benefactor, amount);
        issued[benefactor] = true;
        issuedCount = safeAdd(amount, issuedCount);
      }
    
      /**
       * How many tokens we have left in our approval pool.
       */
      function getApprovedTokenCount() public constant returns(uint tokens) {
        return token.allowance(masterTokenBalanceHolder, address(this));
      }
    
    }

    File 2 of 3: MultiSigWalletWithDailyLimit
    pragma solidity 0.4.4;
    
    
    /// @title Multisignature wallet - Allows multiple parties to agree on transactions before execution.
    /// @author Stefan George - <stefan.george@consensys.net>
    contract MultiSigWallet {
    
        uint constant public MAX_OWNER_COUNT = 50;
    
        event Confirmation(address indexed sender, uint indexed transactionId);
        event Revocation(address indexed sender, uint indexed transactionId);
        event Submission(uint indexed transactionId);
        event Execution(uint indexed transactionId);
        event ExecutionFailure(uint indexed transactionId);
        event Deposit(address indexed sender, uint value);
        event OwnerAddition(address indexed owner);
        event OwnerRemoval(address indexed owner);
        event RequirementChange(uint required);
    
        mapping (uint => Transaction) public transactions;
        mapping (uint => mapping (address => bool)) public confirmations;
        mapping (address => bool) public isOwner;
        address[] public owners;
        uint public required;
        uint public transactionCount;
    
        struct Transaction {
            address destination;
            uint value;
            bytes data;
            bool executed;
        }
    
        modifier onlyWallet() {
            if (msg.sender != address(this))
                throw;
            _;
        }
    
        modifier ownerDoesNotExist(address owner) {
            if (isOwner[owner])
                throw;
            _;
        }
    
        modifier ownerExists(address owner) {
            if (!isOwner[owner])
                throw;
            _;
        }
    
        modifier transactionExists(uint transactionId) {
            if (transactions[transactionId].destination == 0)
                throw;
            _;
        }
    
        modifier confirmed(uint transactionId, address owner) {
            if (!confirmations[transactionId][owner])
                throw;
            _;
        }
    
        modifier notConfirmed(uint transactionId, address owner) {
            if (confirmations[transactionId][owner])
                throw;
            _;
        }
    
        modifier notExecuted(uint transactionId) {
            if (transactions[transactionId].executed)
                throw;
            _;
        }
    
        modifier notNull(address _address) {
            if (_address == 0)
                throw;
            _;
        }
    
        modifier validRequirement(uint ownerCount, uint _required) {
            if (   ownerCount > MAX_OWNER_COUNT
                || _required > ownerCount
                || _required == 0
                || ownerCount == 0)
                throw;
            _;
        }
    
        /// @dev Fallback function allows to deposit ether.
        function()
            payable
        {
            if (msg.value > 0)
                Deposit(msg.sender, msg.value);
        }
    
        /*
         * Public functions
         */
        /// @dev Contract constructor sets initial owners and required number of confirmations.
        /// @param _owners List of initial owners.
        /// @param _required Number of required confirmations.
        function MultiSigWallet(address[] _owners, uint _required)
            public
            validRequirement(_owners.length, _required)
        {
            for (uint i=0; i<_owners.length; i++) {
                if (isOwner[_owners[i]] || _owners[i] == 0)
                    throw;
                isOwner[_owners[i]] = true;
            }
            owners = _owners;
            required = _required;
        }
    
        /// @dev Allows to add a new owner. Transaction has to be sent by wallet.
        /// @param owner Address of new owner.
        function addOwner(address owner)
            public
            onlyWallet
            ownerDoesNotExist(owner)
            notNull(owner)
            validRequirement(owners.length + 1, required)
        {
            isOwner[owner] = true;
            owners.push(owner);
            OwnerAddition(owner);
        }
    
        /// @dev Allows to remove an owner. Transaction has to be sent by wallet.
        /// @param owner Address of owner.
        function removeOwner(address owner)
            public
            onlyWallet
            ownerExists(owner)
        {
            isOwner[owner] = false;
            for (uint i=0; i<owners.length - 1; i++)
                if (owners[i] == owner) {
                    owners[i] = owners[owners.length - 1];
                    break;
                }
            owners.length -= 1;
            if (required > owners.length)
                changeRequirement(owners.length);
            OwnerRemoval(owner);
        }
    
        /// @dev Allows to replace an owner with a new owner. Transaction has to be sent by wallet.
        /// @param owner Address of owner to be replaced.
        /// @param owner Address of new owner.
        function replaceOwner(address owner, address newOwner)
            public
            onlyWallet
            ownerExists(owner)
            ownerDoesNotExist(newOwner)
        {
            for (uint i=0; i<owners.length; i++)
                if (owners[i] == owner) {
                    owners[i] = newOwner;
                    break;
                }
            isOwner[owner] = false;
            isOwner[newOwner] = true;
            OwnerRemoval(owner);
            OwnerAddition(newOwner);
        }
    
        /// @dev Allows to change the number of required confirmations. Transaction has to be sent by wallet.
        /// @param _required Number of required confirmations.
        function changeRequirement(uint _required)
            public
            onlyWallet
            validRequirement(owners.length, _required)
        {
            required = _required;
            RequirementChange(_required);
        }
    
        /// @dev Allows an owner to submit and confirm a transaction.
        /// @param destination Transaction target address.
        /// @param value Transaction ether value.
        /// @param data Transaction data payload.
        /// @return Returns transaction ID.
        function submitTransaction(address destination, uint value, bytes data)
            public
            returns (uint transactionId)
        {
            transactionId = addTransaction(destination, value, data);
            confirmTransaction(transactionId);
        }
    
        /// @dev Allows an owner to confirm a transaction.
        /// @param transactionId Transaction ID.
        function confirmTransaction(uint transactionId)
            public
            ownerExists(msg.sender)
            transactionExists(transactionId)
            notConfirmed(transactionId, msg.sender)
        {
            confirmations[transactionId][msg.sender] = true;
            Confirmation(msg.sender, transactionId);
            executeTransaction(transactionId);
        }
    
        /// @dev Allows an owner to revoke a confirmation for a transaction.
        /// @param transactionId Transaction ID.
        function revokeConfirmation(uint transactionId)
            public
            ownerExists(msg.sender)
            confirmed(transactionId, msg.sender)
            notExecuted(transactionId)
        {
            confirmations[transactionId][msg.sender] = false;
            Revocation(msg.sender, transactionId);
        }
    
        /// @dev Allows anyone to execute a confirmed transaction.
        /// @param transactionId Transaction ID.
        function executeTransaction(uint transactionId)
            public
            notExecuted(transactionId)
        {
            if (isConfirmed(transactionId)) {
                Transaction tx = transactions[transactionId];
                tx.executed = true;
                if (tx.destination.call.value(tx.value)(tx.data))
                    Execution(transactionId);
                else {
                    ExecutionFailure(transactionId);
                    tx.executed = false;
                }
            }
        }
    
        /// @dev Returns the confirmation status of a transaction.
        /// @param transactionId Transaction ID.
        /// @return Confirmation status.
        function isConfirmed(uint transactionId)
            public
            constant
            returns (bool)
        {
            uint count = 0;
            for (uint i=0; i<owners.length; i++) {
                if (confirmations[transactionId][owners[i]])
                    count += 1;
                if (count == required)
                    return true;
            }
        }
    
        /*
         * Internal functions
         */
        /// @dev Adds a new transaction to the transaction mapping, if transaction does not exist yet.
        /// @param destination Transaction target address.
        /// @param value Transaction ether value.
        /// @param data Transaction data payload.
        /// @return Returns transaction ID.
        function addTransaction(address destination, uint value, bytes data)
            internal
            notNull(destination)
            returns (uint transactionId)
        {
            transactionId = transactionCount;
            transactions[transactionId] = Transaction({
                destination: destination,
                value: value,
                data: data,
                executed: false
            });
            transactionCount += 1;
            Submission(transactionId);
        }
    
        /*
         * Web3 call functions
         */
        /// @dev Returns number of confirmations of a transaction.
        /// @param transactionId Transaction ID.
        /// @return Number of confirmations.
        function getConfirmationCount(uint transactionId)
            public
            constant
            returns (uint count)
        {
            for (uint i=0; i<owners.length; i++)
                if (confirmations[transactionId][owners[i]])
                    count += 1;
        }
    
        /// @dev Returns total number of transactions after filers are applied.
        /// @param pending Include pending transactions.
        /// @param executed Include executed transactions.
        /// @return Total number of transactions after filters are applied.
        function getTransactionCount(bool pending, bool executed)
            public
            constant
            returns (uint count)
        {
            for (uint i=0; i<transactionCount; i++)
                if (   pending && !transactions[i].executed
                    || executed && transactions[i].executed)
                    count += 1;
        }
    
        /// @dev Returns list of owners.
        /// @return List of owner addresses.
        function getOwners()
            public
            constant
            returns (address[])
        {
            return owners;
        }
    
        /// @dev Returns array with owner addresses, which confirmed transaction.
        /// @param transactionId Transaction ID.
        /// @return Returns array of owner addresses.
        function getConfirmations(uint transactionId)
            public
            constant
            returns (address[] _confirmations)
        {
            address[] memory confirmationsTemp = new address[](owners.length);
            uint count = 0;
            uint i;
            for (i=0; i<owners.length; i++)
                if (confirmations[transactionId][owners[i]]) {
                    confirmationsTemp[count] = owners[i];
                    count += 1;
                }
            _confirmations = new address[](count);
            for (i=0; i<count; i++)
                _confirmations[i] = confirmationsTemp[i];
        }
    
        /// @dev Returns list of transaction IDs in defined range.
        /// @param from Index start position of transaction array.
        /// @param to Index end position of transaction array.
        /// @param pending Include pending transactions.
        /// @param executed Include executed transactions.
        /// @return Returns array of transaction IDs.
        function getTransactionIds(uint from, uint to, bool pending, bool executed)
            public
            constant
            returns (uint[] _transactionIds)
        {
            uint[] memory transactionIdsTemp = new uint[](transactionCount);
            uint count = 0;
            uint i;
            for (i=0; i<transactionCount; i++)
                if (   pending && !transactions[i].executed
                    || executed && transactions[i].executed)
                {
                    transactionIdsTemp[count] = i;
                    count += 1;
                }
            _transactionIds = new uint[](to - from);
            for (i=from; i<to; i++)
                _transactionIds[i - from] = transactionIdsTemp[i];
        }
    }
    
    
    /// @title Multisignature wallet with daily limit - Allows an owner to withdraw a daily limit without multisig.
    /// @author Stefan George - <stefan.george@consensys.net>
    contract MultiSigWalletWithDailyLimit is MultiSigWallet {
    
        event DailyLimitChange(uint dailyLimit);
    
        uint public dailyLimit;
        uint public lastDay;
        uint public spentToday;
    
        /*
         * Public functions
         */
        /// @dev Contract constructor sets initial owners, required number of confirmations and daily withdraw limit.
        /// @param _owners List of initial owners.
        /// @param _required Number of required confirmations.
        /// @param _dailyLimit Amount in wei, which can be withdrawn without confirmations on a daily basis.
        function MultiSigWalletWithDailyLimit(address[] _owners, uint _required, uint _dailyLimit)
            public
            MultiSigWallet(_owners, _required)
        {
            dailyLimit = _dailyLimit;
        }
    
        /// @dev Allows to change the daily limit. Transaction has to be sent by wallet.
        /// @param _dailyLimit Amount in wei.
        function changeDailyLimit(uint _dailyLimit)
            public
            onlyWallet
        {
            dailyLimit = _dailyLimit;
            DailyLimitChange(_dailyLimit);
        }
    
        /// @dev Allows anyone to execute a confirmed transaction or ether withdraws until daily limit is reached.
        /// @param transactionId Transaction ID.
        function executeTransaction(uint transactionId)
            public
            notExecuted(transactionId)
        {
            Transaction tx = transactions[transactionId];
            bool confirmed = isConfirmed(transactionId);
            if (confirmed || tx.data.length == 0 && isUnderLimit(tx.value)) {
                tx.executed = true;
                if (!confirmed)
                    spentToday += tx.value;
                if (tx.destination.call.value(tx.value)(tx.data))
                    Execution(transactionId);
                else {
                    ExecutionFailure(transactionId);
                    tx.executed = false;
                    if (!confirmed)
                        spentToday -= tx.value;
                }
            }
        }
    
        /*
         * Internal functions
         */
        /// @dev Returns if amount is within daily limit and resets spentToday after one day.
        /// @param amount Amount to withdraw.
        /// @return Returns if amount is under daily limit.
        function isUnderLimit(uint amount)
            internal
            returns (bool)
        {
            if (now > lastDay + 24 hours) {
                lastDay = now;
                spentToday = 0;
            }
            if (spentToday + amount > dailyLimit || spentToday + amount < spentToday)
                return false;
            return true;
        }
    
        /*
         * Web3 call functions
         */
        /// @dev Returns maximum withdraw amount.
        /// @return Returns amount.
        function calcMaxWithdraw()
            public
            constant
            returns (uint)
        {
            if (now > lastDay + 24 hours)
                return dailyLimit;
            if (dailyLimit < spentToday)
                return 0;
            return dailyLimit - spentToday;
        }
    }

    File 3 of 3: CentrallyIssuedToken
    /*
     * ERC20 interface
     * see https://github.com/ethereum/EIPs/issues/20
     */
    contract ERC20 {
      uint public totalSupply;
      function balanceOf(address who) constant returns (uint);
      function allowance(address owner, address spender) constant returns (uint);
    
      function transfer(address to, uint value) returns (bool ok);
      function transferFrom(address from, address to, uint value) returns (bool ok);
      function approve(address spender, uint value) returns (bool ok);
      event Transfer(address indexed from, address indexed to, uint value);
      event Approval(address indexed owner, address indexed spender, uint value);
    }
    
    
    
    /**
     * Math operations with safety checks
     */
    contract SafeMath {
      function safeMul(uint a, uint b) internal returns (uint) {
        uint c = a * b;
        assert(a == 0 || c / a == b);
        return c;
      }
    
      function safeDiv(uint a, uint b) internal returns (uint) {
        assert(b > 0);
        uint c = a / b;
        assert(a == b * c + a % b);
        return c;
      }
    
      function safeSub(uint a, uint b) internal returns (uint) {
        assert(b <= a);
        return a - b;
      }
    
      function safeAdd(uint a, uint b) internal returns (uint) {
        uint c = a + b;
        assert(c>=a && c>=b);
        return c;
      }
    
      function max64(uint64 a, uint64 b) internal constant returns (uint64) {
        return a >= b ? a : b;
      }
    
      function min64(uint64 a, uint64 b) internal constant returns (uint64) {
        return a < b ? a : b;
      }
    
      function max256(uint256 a, uint256 b) internal constant returns (uint256) {
        return a >= b ? a : b;
      }
    
      function min256(uint256 a, uint256 b) internal constant returns (uint256) {
        return a < b ? a : b;
      }
    
      function assert(bool assertion) internal {
        if (!assertion) {
          throw;
        }
      }
    }
    
    
    
    /**
     * Standard ERC20 token with Short Hand Attack and approve() race condition mitigation.
     *
     * Based on code by FirstBlood:
     * https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol
     */
    contract StandardToken is ERC20, SafeMath {
    
      mapping(address => uint) balances;
      mapping (address => mapping (address => uint)) allowed;
    
      // Interface marker
      bool public constant isToken = true;
    
      /**
       *
       * Fix for the ERC20 short address attack
       *
       * http://vessenes.com/the-erc20-short-address-attack-explained/
       */
      modifier onlyPayloadSize(uint size) {
         if(msg.data.length < size + 4) {
           throw;
         }
         _;
      }
    
      function transfer(address _to, uint _value) onlyPayloadSize(2 * 32) returns (bool success) {
        balances[msg.sender] = safeSub(balances[msg.sender], _value);
        balances[_to] = safeAdd(balances[_to], _value);
        Transfer(msg.sender, _to, _value);
        return true;
      }
    
      function transferFrom(address _from, address _to, uint _value)  returns (bool success) {
        var _allowance = allowed[_from][msg.sender];
    
        // Check is not needed because safeSub(_allowance, _value) will already throw if this condition is not met
        // if (_value > _allowance) throw;
    
        balances[_to] = safeAdd(balances[_to], _value);
        balances[_from] = safeSub(balances[_from], _value);
        allowed[_from][msg.sender] = safeSub(_allowance, _value);
        Transfer(_from, _to, _value);
        return true;
      }
    
      function balanceOf(address _owner) constant returns (uint balance) {
        return balances[_owner];
      }
    
      function approve(address _spender, uint _value) returns (bool success) {
    
        // To change the approve amount you first have to reduce the addresses`
        //  allowance to zero by calling `approve(_spender, 0)` if it is not
        //  already 0 to mitigate the race condition described here:
        //  https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
        if ((_value != 0) && (allowed[msg.sender][_spender] != 0)) throw;
    
        allowed[msg.sender][_spender] = _value;
        Approval(msg.sender, _spender, _value);
        return true;
      }
    
      function allowance(address _owner, address _spender) constant returns (uint remaining) {
        return allowed[_owner][_spender];
      }
    
    }
    
    
    
    /**
     * A trait that allows any token owner to decrease the token supply.
     *
     * We add a Burned event to differentiate from normal transfers.
     * However, we still try to support some legacy Ethereum ecocsystem,
     * as ERC-20 has not standardized on the burn event yet.
     *
     */
    contract BurnableToken is StandardToken {
    
      address public constant BURN_ADDRESS = 0;
    
      /** How many tokens we burned */
      event Burned(address burner, uint burnedAmount);
    
      /**
       * Burn extra tokens from a balance.
       *
       */
      function burn(uint burnAmount) {
        address burner = msg.sender;
        balances[burner] = safeSub(balances[burner], burnAmount);
        totalSupply = safeSub(totalSupply, burnAmount);
        Burned(burner, burnAmount);
    
        // Keep token balance tracking services happy by sending the burned amount to
        // "burn address", so that it will show up as a ERC-20 transaction
        // in etherscan, etc. as there is no standarized burn event yet
        Transfer(burner, BURN_ADDRESS, burnAmount);
      }
    }
    
    
    
    
    /**
     * Upgrade agent interface inspired by Lunyr.
     *
     * Upgrade agent transfers tokens to a new contract.
     * Upgrade agent itself can be the token contract, or just a middle man contract doing the heavy lifting.
     */
    contract UpgradeAgent {
    
      uint public originalSupply;
    
      /** Interface marker */
      function isUpgradeAgent() public constant returns (bool) {
        return true;
      }
    
      function upgradeFrom(address _from, uint256 _value) public;
    
    }
    
    
    /**
     * A token upgrade mechanism where users can opt-in amount of tokens to the next smart contract revision.
     *
     * First envisioned by Golem and Lunyr projects.
     */
    contract UpgradeableToken is StandardToken {
    
      /** Contract / person who can set the upgrade path. This can be the same as team multisig wallet, as what it is with its default value. */
      address public upgradeMaster;
    
      /** The next contract where the tokens will be migrated. */
      UpgradeAgent public upgradeAgent;
    
      /** How many tokens we have upgraded by now. */
      uint256 public totalUpgraded;
    
      /**
       * Upgrade states.
       *
       * - NotAllowed: The child contract has not reached a condition where the upgrade can bgun
       * - WaitingForAgent: Token allows upgrade, but we don't have a new agent yet
       * - ReadyToUpgrade: The agent is set, but not a single token has been upgraded yet
       * - Upgrading: Upgrade agent is set and the balance holders can upgrade their tokens
       *
       */
      enum UpgradeState {Unknown, NotAllowed, WaitingForAgent, ReadyToUpgrade, Upgrading}
    
      /**
       * Somebody has upgraded some of his tokens.
       */
      event Upgrade(address indexed _from, address indexed _to, uint256 _value);
    
      /**
       * New upgrade agent available.
       */
      event UpgradeAgentSet(address agent);
    
      /**
       * Do not allow construction without upgrade master set.
       */
      function UpgradeableToken(address _upgradeMaster) {
        upgradeMaster = _upgradeMaster;
      }
    
      /**
       * Allow the token holder to upgrade some of their tokens to a new contract.
       */
      function upgrade(uint256 value) public {
    
          UpgradeState state = getUpgradeState();
          if(!(state == UpgradeState.ReadyToUpgrade || state == UpgradeState.Upgrading)) {
            // Called in a bad state
            throw;
          }
    
          // Validate input value.
          if (value == 0) throw;
    
          balances[msg.sender] = safeSub(balances[msg.sender], value);
    
          // Take tokens out from circulation
          totalSupply = safeSub(totalSupply, value);
          totalUpgraded = safeAdd(totalUpgraded, value);
    
          // Upgrade agent reissues the tokens
          upgradeAgent.upgradeFrom(msg.sender, value);
          Upgrade(msg.sender, upgradeAgent, value);
      }
    
      /**
       * Set an upgrade agent that handles
       */
      function setUpgradeAgent(address agent) external {
    
          if(!canUpgrade()) {
            // The token is not yet in a state that we could think upgrading
            throw;
          }
    
          if (agent == 0x0) throw;
          // Only a master can designate the next agent
          if (msg.sender != upgradeMaster) throw;
          // Upgrade has already begun for an agent
          if (getUpgradeState() == UpgradeState.Upgrading) throw;
    
          upgradeAgent = UpgradeAgent(agent);
    
          // Bad interface
          if(!upgradeAgent.isUpgradeAgent()) throw;
          // Make sure that token supplies match in source and target
          if (upgradeAgent.originalSupply() != totalSupply) throw;
    
          UpgradeAgentSet(upgradeAgent);
      }
    
      /**
       * Get the state of the token upgrade.
       */
      function getUpgradeState() public constant returns(UpgradeState) {
        if(!canUpgrade()) return UpgradeState.NotAllowed;
        else if(address(upgradeAgent) == 0x00) return UpgradeState.WaitingForAgent;
        else if(totalUpgraded == 0) return UpgradeState.ReadyToUpgrade;
        else return UpgradeState.Upgrading;
      }
    
      /**
       * Change the upgrade master.
       *
       * This allows us to set a new owner for the upgrade mechanism.
       */
      function setUpgradeMaster(address master) public {
          if (master == 0x0) throw;
          if (msg.sender != upgradeMaster) throw;
          upgradeMaster = master;
      }
    
      /**
       * Child contract can enable to provide the condition when the upgrade can begun.
       */
      function canUpgrade() public constant returns(bool) {
         return true;
      }
    
    }
    
    
    
    /**
     * Centrally issued Ethereum token.
     *
     * We mix in burnable and upgradeable traits.
     *
     * Token supply is created in the token contract creation and allocated to owner.
     * The owner can then transfer from its supply to crowdsale participants.
     * The owner, or anybody, can burn any excessive tokens they are holding.
     *
     */
    contract CentrallyIssuedToken is BurnableToken, UpgradeableToken {
    
      string public name;
      string public symbol;
      uint public decimals;
    
      function CentrallyIssuedToken(address _owner, string _name, string _symbol, uint _totalSupply, uint _decimals)  UpgradeableToken(_owner) {
        name = _name;
        symbol = _symbol;
        totalSupply = _totalSupply;
        decimals = _decimals;
    
        // Allocate initial balance to the owner
        balances[_owner] = _totalSupply;
      }
    }