ETH Price: $2,147.40 (-0.35%)

Transaction Decoder

Block:
9847358 at Apr-10-2020 11:01:31 PM +UTC
Transaction Fee:
0.0007241900224 ETH $1.56
Gas Used:
138,944 Gas / 5.2121 Gwei

Emitted Events:

187 CrowdsaleToken.Transfer( from=[Receiver] CommunityProduct, to=0xF7c5c790Dd34154177C1b7A0D0603f095996C48E, value=2111121733676600486 )

Account State Difference:

  Address   Before After State Difference Code
0x0Cf0Ee63...E122cC023
0x3F2dA479...B965fe987
(Swash: Deployer)
0.873591682302752132 Eth
Nonce: 764
0.872867492280352132 Eth
Nonce: 765
0.0007241900224
(Spark Pool)
4.22559965138848464 Eth4.22632384141088464 Eth0.0007241900224
0xF24197f7...f7C91FD23
(Swash: Contract)

Execution Trace

CommunityProduct.withdrawAllFor( )
  • CrowdsaleToken.balanceOf( _owner=0xF24197f71fC9b2F4F4c24ecE461fB0Ff7C91FD23 ) => ( balance=679483304631454331442 )
  • CrowdsaleToken.transfer( _to=0xF7c5c790Dd34154177C1b7A0D0603f095996C48E, _value=2111121733676600486 ) => ( success=True )
    File 1 of 2: CommunityProduct
    pragma solidity ^0.4.24;
    
    /**
     * @title SafeMath
     * @dev Math operations with safety checks that revert on error
     */
    library SafeMath {
    
      /**
      * @dev Multiplies two numbers, reverts on overflow.
      */
      function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
        if (a == 0) {
          return 0;
        }
    
        uint256 c = a * b;
        require(c / a == b);
    
        return c;
      }
    
      /**
      * @dev Integer division of two numbers truncating the quotient, reverts on division by zero.
      */
      function div(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b > 0); // Solidity only automatically asserts when dividing by 0
        uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold
    
        return c;
      }
    
      /**
      * @dev Subtracts two numbers, reverts on overflow (i.e. if subtrahend is greater than minuend).
      */
      function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b <= a);
        uint256 c = a - b;
    
        return c;
      }
    
      /**
      * @dev Adds two numbers, reverts on overflow.
      */
      function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a);
    
        return c;
      }
    
      /**
      * @dev Divides two numbers and returns the remainder (unsigned integer modulo),
      * reverts when dividing by zero.
      */
      function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b != 0);
        return a % b;
      }
    }
    
    
    /**
     * @title ERC20 interface
     * @dev see https://github.com/ethereum/EIPs/issues/20
     */
    interface IERC20 {
      function totalSupply() external view returns (uint256);
    
      function balanceOf(address who) external view returns (uint256);
    
      function allowance(address owner, address spender)
        external view returns (uint256);
    
      function transfer(address to, uint256 value) external returns (bool);
    
      function approve(address spender, uint256 value)
        external returns (bool);
    
      function transferFrom(address from, address to, uint256 value)
        external returns (bool);
    
      event Transfer(
        address indexed from,
        address indexed to,
        uint256 value
      );
    
      event Approval(
        address indexed owner,
        address indexed spender,
        uint256 value
      );
    }
    
    
    /**
     * Abstract contract, requires implementation to specify who can commit blocks and what
     *   happens when a successful proof is presented
     * Verifies Merkle-tree inclusion proofs that show that certain address has
     *   certain earnings balance, according to hash published ("signed") by a
     *   sidechain operator or similar authority
     *
     * ABOUT Merkle-tree inclusion proof: Merkle-tree inclusion proof is an algorithm to prove memebership
     * in a set using minimal [ie log(N)] inputs. The hashes of the items are arranged by hash value in a binary Merkle tree where 
     * each node contains a hash of the hashes of nodes below. The root node (ie "root hash") contains hash information 
     * about the entire set, and that is the data that BalanceVerifier posts to the blockchain. To prove membership, you walk up the 
     * tree from the node in question, and use the supplied hashes (the "proof") to fill in the hashes from the adjacent nodes. The proof  
     * succeeds iff you end up with the known root hash when you get to the top of the tree. 
     * See https://medium.com/crypto-0-nite/merkle-proofs-explained-6dd429623dc5
     *
     * Merkle-tree inclusion proof is a RELATED concept to the blockchain Merkle tree, but a somewhat DIFFERENT application. 
     * BalanceVerifier posts the root hash of the CURRENT ledger only, and this does NOT depend on the hash of previous ledgers.
     * This is different from the blockchain, where each block contains the hash of the previous block. 
     *
     * TODO: see if it could be turned into a library, so many contracts could use it
     */
    contract BalanceVerifier {
        event BlockCreated(uint blockNumber, bytes32 rootHash, string ipfsHash);
    
        /**
         * Sidechain "blocks" are simply root hashes of merkle-trees constructed from its balances
         * @param uint root-chain block number after which the balances were recorded
         * @return bytes32 root of the balances merkle-tree at that time
         */
        mapping (uint => bytes32) public blockHash;
    
        /**
         * Handler for proof of sidechain balances
         * It is up to the implementing contract to actually distribute out the balances
         * @param blockNumber the block whose hash was used for verification
         * @param account whose balances were successfully verified
         * @param balance the side-chain account balance
         */
        function onVerifySuccess(uint blockNumber, address account, uint balance) internal;
    
        /**
         * Implementing contract should should do access checks for committing
         */
        function onCommit(uint blockNumber, bytes32 rootHash, string ipfsHash) internal;
    
        /**
         * Side-chain operator submits commitments to main chain. These
         * For convenience, also publish the ipfsHash of the balance book JSON object
         * @param blockNumber the block after which the balances were recorded
         * @param rootHash root of the balances merkle-tree
         * @param ipfsHash where the whole balances object can be retrieved in JSON format
         */
        function commit(uint blockNumber, bytes32 rootHash, string ipfsHash) external {
            require(blockHash[blockNumber] == 0, "error_overwrite");
            string memory _hash = ipfsHash;
            onCommit(blockNumber, rootHash, _hash);
            blockHash[blockNumber] = rootHash;
            emit BlockCreated(blockNumber, rootHash, _hash);
        }
    
        /**
         * Proving can be used to record the sidechain balances permanently into root chain
         * @param blockNumber the block after which the balances were recorded
         * @param account whose balances will be verified
         * @param balance side-chain account balance
         * @param proof list of hashes to prove the totalEarnings
         */
        function prove(uint blockNumber, address account, uint balance, bytes32[] memory proof) public {
            require(proofIsCorrect(blockNumber, account, balance, proof), "error_proof");
            onVerifySuccess(blockNumber, account, balance);
        }
    
        /**
         * Check the merkle proof of balance in the given side-chain block for given account
         */
        function proofIsCorrect(uint blockNumber, address account, uint balance, bytes32[] memory proof) public view returns(bool) {
            bytes32 hash = keccak256(abi.encodePacked(account, balance));
            bytes32 rootHash = blockHash[blockNumber];
            require(rootHash != 0x0, "error_blockNotFound");
            return rootHash == calculateRootHash(hash, proof);
        }
    
        /**
         * Calculate root hash of a Merkle tree, given
         * @param hash of the leaf to verify
         * @param others list of hashes of "other" branches
         */
        function calculateRootHash(bytes32 hash, bytes32[] memory others) public pure returns (bytes32 root) {
            root = hash;
            for (uint8 i = 0; i < others.length; i++) {
                bytes32 other = others[i];
                if (other == 0x0) continue;     // odd branch, no need to hash
                if (root < other) {
                    root = keccak256(abi.encodePacked(root, other));
                } else {
                    root = keccak256(abi.encodePacked(other, root));
                }
            }
        }
    }
    
    /**
     * @title Ownable
     * @dev The Ownable contract has an owner address, and provides basic authorization control
     * functions, this simplifies the implementation of "user permissions".
     */
    contract Ownable {
        address public owner;
        address public pendingOwner;
    
        event OwnershipTransferred(
            address indexed previousOwner,
            address indexed newOwner
        );
    
        /**
         * @dev The Ownable constructor sets the original `owner` of the contract to the sender
         * account.
         */
        constructor() public {
            owner = msg.sender;
        }
    
        /**
         * @dev Throws if called by any account other than the owner.
         */
        modifier onlyOwner() {
            require(msg.sender == owner, "onlyOwner");
            _;
        }
    
        /**
         * @dev Allows the current owner to set the pendingOwner address.
         * @param newOwner The address to transfer ownership to.
         */
        function transferOwnership(address newOwner) public onlyOwner {
            pendingOwner = newOwner;
        }
    
        /**
         * @dev Allows the pendingOwner address to finalize the transfer.
         */
        function claimOwnership() public {
            require(msg.sender == pendingOwner, "onlyPendingOwner");
            emit OwnershipTransferred(owner, pendingOwner);
            owner = pendingOwner;
            pendingOwner = address(0);
        }
    }
    
    
    
    
    /**
     * Monoplasma that is managed by an owner, likely the side-chain operator
     * Owner can add and remove recipients.
     */
    contract Monoplasma is BalanceVerifier, Ownable {
        using SafeMath for uint256;
    
        event OperatorChanged(address indexed newOperator);
        event AdminFeeChanged(uint adminFee);
        /**
         * Freeze period during which all side-chain participants should be able to
         *   acquire the whole balance book from IPFS (or HTTP server, or elsewhere)
         *   and validate that the published rootHash is correct
         * In case of incorrect rootHash, all members should issue withdrawals from the
         *   latest block they have validated (that is older than blockFreezeSeconds)
         * So: too short freeze period + bad availability => ether (needlessly) spent withdrawing earnings
         *     long freeze period == lag between purchase and withdrawal => bad UX
         * Blocks older than blockFreezeSeconds can be used to withdraw funds
         */
        uint public blockFreezeSeconds;
    
        /**
         * Block number => timestamp
         * Publish time of a block, where the block freeze period starts from.
         * Note that block number points to the block after which the root hash is calculated,
         *   not the block where BlockCreated was emitted (event must come later)
         */
        mapping (uint => uint) public blockTimestamp;
    
        address public operator;
    
        //fee fraction = adminFee/10^18
        uint public adminFee;
    
        IERC20 public token;
    
        mapping (address => uint) public earnings;
        mapping (address => uint) public withdrawn;
        uint public totalWithdrawn;
        uint public totalProven;
    
        constructor(address tokenAddress, uint blockFreezePeriodSeconds, uint _adminFee) public {
            blockFreezeSeconds = blockFreezePeriodSeconds;
            token = IERC20(tokenAddress);
            operator = msg.sender;
            setAdminFee(_adminFee);
        }
    
        function setOperator(address newOperator) public onlyOwner {
            operator = newOperator;
            emit OperatorChanged(newOperator);
        }
    
        /**
         * Admin fee as a fraction of revenue
         * Fixed-point decimal in the same way as ether: 50% === 0.5 ether
         * Smart contract doesn't use it, it's here just for storing purposes
         */
        function setAdminFee(uint _adminFee) public onlyOwner {
            require(adminFee <= 1 ether, "Admin fee cannot be greater than 1");
            adminFee = _adminFee;
            emit AdminFeeChanged(_adminFee);
        }
    
        /**
         * Operator creates the side-chain blocks
         */
        function onCommit(uint blockNumber, bytes32, string) internal {
            require(msg.sender == operator, "error_notPermitted");
            blockTimestamp[blockNumber] = now;
        }
    
        /**
         * Called from BalanceVerifier.prove
         * Prove can be called directly to withdraw less than the whole share,
         *   or just "cement" the earnings so far into root chain even without withdrawing
         */
        function onVerifySuccess(uint blockNumber, address account, uint newEarnings) internal {
            uint blockFreezeStart = blockTimestamp[blockNumber];
            require(now > blockFreezeStart + blockFreezeSeconds, "error_frozen");
            require(earnings[account] < newEarnings, "error_oldEarnings");
            totalProven = totalProven.add(newEarnings).sub(earnings[account]);
            require(totalProven.sub(totalWithdrawn) <= token.balanceOf(this), "error_missingBalance");
            earnings[account] = newEarnings;
        }
    
        /**
         * Prove and withdraw the whole revenue share from sidechain in one transaction
         * @param blockNumber of the leaf to verify
         * @param totalEarnings in the side-chain
         * @param proof list of hashes to prove the totalEarnings
         */
        function withdrawAll(uint blockNumber, uint totalEarnings, bytes32[] proof) external {
            withdrawAllFor(msg.sender, blockNumber, totalEarnings, proof);
        }
    
        /**
         * Prove and withdraw the whole revenue share for someone else
         * Validator needs to exit those it's watching out for, in case
         *   it detects Operator malfunctioning
         * @param recipient the address we're proving and withdrawing
         * @param blockNumber of the leaf to verify
         * @param totalEarnings in the side-chain
         * @param proof list of hashes to prove the totalEarnings
         */
        function withdrawAllFor(address recipient, uint blockNumber, uint totalEarnings, bytes32[] proof) public {
            prove(blockNumber, recipient, totalEarnings, proof);
            uint withdrawable = totalEarnings.sub(withdrawn[recipient]);
            withdrawTo(recipient, recipient, withdrawable);
        }
    
        /**
         * "Donate withdraw" function that allows you to prove and transfer
         *   your earnings to a another address in one transaction
         * @param recipient the address the tokens will be sent to (instead of msg.sender)
         * @param blockNumber of the leaf to verify
         * @param totalEarnings in the side-chain
         * @param proof list of hashes to prove the totalEarnings
         */
        function withdrawAllTo(address recipient, uint blockNumber, uint totalEarnings, bytes32[] proof) external {
            prove(blockNumber, msg.sender, totalEarnings, proof);
            uint withdrawable = totalEarnings.sub(withdrawn[msg.sender]);
            withdrawTo(recipient, msg.sender, withdrawable);
        }
    
        /**
         * Withdraw a specified amount of your own proven earnings (see `function prove`)
         */
        function withdraw(uint amount) public {
            withdrawTo(msg.sender, msg.sender, amount);
        }
    
        /**
         * Do the withdrawal on behalf of someone else
         * Validator needs to exit those it's watching out for, in case
         *   it detects Operator malfunctioning
         */
        function withdrawFor(address recipient, uint amount) public {
            withdrawTo(recipient, recipient, amount);
        }
    
        /**
         * Execute token withdrawal into specified recipient address from specified member account
         * @dev It is up to the sidechain implementation to make sure
         * @dev  always token balance >= sum of earnings - sum of withdrawn
         */
        function withdrawTo(address recipient, address account, uint amount) public {
            require(amount > 0, "error_zeroWithdraw");
            uint w = withdrawn[account].add(amount);
            require(w <= earnings[account], "error_overdraft");
            withdrawn[account] = w;
            totalWithdrawn = totalWithdrawn.add(amount);
            require(token.transfer(recipient, amount), "error_transfer");
        }
    }
    
    
    contract CommunityProduct is Monoplasma {
    
        string public joinPartStream;
    
        constructor(address operator, string joinPartStreamId, address tokenAddress, uint blockFreezePeriodSeconds, uint adminFeeFraction)
        Monoplasma(tokenAddress, blockFreezePeriodSeconds, adminFeeFraction) public {
            setOperator(operator);
            joinPartStream = joinPartStreamId;
        }
    }

    File 2 of 2: CrowdsaleToken
    /*
     * 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 {
    
      /* Token supply got increased and a new owner received these tokens */
      event Minted(address receiver, uint amount);
    
      /* Actual balances of token holders */
      mapping(address => uint) balances;
    
      /* approve() allowances */
      mapping (address => mapping (address => uint)) allowed;
    
      /* Interface declaration */
      function isToken() public constant returns (bool weAre) {
        return true;
      }
    
      function transfer(address _to, uint _value) 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) {
        uint _allowance = allowed[_from][msg.sender];
    
        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];
      }
    
    }
    
    
    
    
    
    /**
     * 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;
      }
    
    }
    
    
    
    
    /*
     * 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;
        }
      }
    
    }
    
    
    
    
    /**
     * Define interface for releasing the token transfer after a successful crowdsale.
     */
    contract ReleasableToken is ERC20, Ownable {
    
      /* The finalizer contract that allows unlift the transfer limits on this token */
      address public releaseAgent;
    
      /** A crowdsale contract can release us to the wild if ICO success. If false we are are in transfer lock up period.*/
      bool public released = false;
    
      /** Map of agents that are allowed to transfer tokens regardless of the lock down period. These are crowdsale contracts and possible the team multisig itself. */
      mapping (address => bool) public transferAgents;
    
      /**
       * Limit token transfer until the crowdsale is over.
       *
       */
      modifier canTransfer(address _sender) {
    
        if(!released) {
            if(!transferAgents[_sender]) {
                throw;
            }
        }
    
        _;
      }
    
      /**
       * Set the contract that can call release and make the token transferable.
       *
       * Design choice. Allow reset the release agent to fix fat finger mistakes.
       */
      function setReleaseAgent(address addr) onlyOwner inReleaseState(false) public {
    
        // We don't do interface check here as we might want to a normal wallet address to act as a release agent
        releaseAgent = addr;
      }
    
      /**
       * Owner can allow a particular address (a crowdsale contract) to transfer tokens despite the lock up period.
       */
      function setTransferAgent(address addr, bool state) onlyOwner inReleaseState(false) public {
        transferAgents[addr] = state;
      }
    
      /**
       * One way function to release the tokens to the wild.
       *
       * Can be called only from the release agent that is the final ICO contract. It is only called if the crowdsale has been success (first milestone reached).
       */
      function releaseTokenTransfer() public onlyReleaseAgent {
        released = true;
      }
    
      /** The function can be called only before or after the tokens have been releasesd */
      modifier inReleaseState(bool releaseState) {
        if(releaseState != released) {
            throw;
        }
        _;
      }
    
      /** The function can be called only by a whitelisted release agent. */
      modifier onlyReleaseAgent() {
        if(msg.sender != releaseAgent) {
            throw;
        }
        _;
      }
    
      function transfer(address _to, uint _value) canTransfer(msg.sender) returns (bool success) {
        // Call StandardToken.transfer()
       return super.transfer(_to, _value);
      }
    
      function transferFrom(address _from, address _to, uint _value) canTransfer(_from) returns (bool success) {
        // Call StandardToken.transferForm()
        return super.transferFrom(_from, _to, _value);
      }
    
    }
    
    
    
    
    
    /**
     * Safe unsigned safe math.
     *
     * https://blog.aragon.one/library-driven-development-in-solidity-2bebcaf88736#.750gwtwli
     *
     * Originally from https://raw.githubusercontent.com/AragonOne/zeppelin-solidity/master/contracts/SafeMathLib.sol
     *
     * Maintained here until merged to mainline zeppelin-solidity.
     *
     */
    library SafeMathLib {
    
      function times(uint a, uint b) returns (uint) {
        uint c = a * b;
        assert(a == 0 || c / a == b);
        return c;
      }
    
      function minus(uint a, uint b) returns (uint) {
        assert(b <= a);
        return a - b;
      }
    
      function plus(uint a, uint b) returns (uint) {
        uint c = a + b;
        assert(c>=a);
        return c;
      }
    
      function assert(bool assertion) private {
        if (!assertion) throw;
      }
    }
    
    
    
    /**
     * A token that can increase its supply by another contract.
     *
     * This allows uncapped crowdsale by dynamically increasing the supply when money pours in.
     * Only mint agents, contracts whitelisted by owner, can mint new tokens.
     *
     */
    contract MintableToken is StandardToken, Ownable {
    
      using SafeMathLib for uint;
    
      bool public mintingFinished = false;
    
      /** List of agents that are allowed to create new tokens */
      mapping (address => bool) public mintAgents;
    
      event MintingAgentChanged(address addr, bool state  );
    
      /**
       * Create new tokens and allocate them to an address..
       *
       * Only callably by a crowdsale contract (mint agent).
       */
      function mint(address receiver, uint amount) onlyMintAgent canMint public {
        totalSupply = totalSupply.plus(amount);
        balances[receiver] = balances[receiver].plus(amount);
    
        // This will make the mint transaction apper in EtherScan.io
        // We can remove this after there is a standardized minting event
        Transfer(0, receiver, amount);
      }
    
      /**
       * Owner can allow a crowdsale contract to mint new tokens.
       */
      function setMintAgent(address addr, bool state) onlyOwner canMint public {
        mintAgents[addr] = state;
        MintingAgentChanged(addr, state);
      }
    
      modifier onlyMintAgent() {
        // Only crowdsale contracts are allowed to mint new tokens
        if(!mintAgents[msg.sender]) {
            throw;
        }
        _;
      }
    
      /** Make sure we are not done yet. */
      modifier canMint() {
        if(mintingFinished) throw;
        _;
      }
    }
    
    
    
    /**
     * A crowdsaled token.
     *
     * An ERC-20 token designed specifically for crowdsales with investor protection and further development path.
     *
     * - The token transfer() is disabled until the crowdsale is over
     * - The token contract gives an opt-in upgrade path to a new contract
     * - The same token can be part of several crowdsales through approve() mechanism
     * - The token can be capped (supply set in the constructor) or uncapped (crowdsale contract can mint new tokens)
     *
     */
    contract CrowdsaleToken is ReleasableToken, MintableToken, UpgradeableToken {
    
      /** Name and symbol were updated. */
      event UpdatedTokenInformation(string newName, string newSymbol);
    
      string public name;
    
      string public symbol;
    
      uint public decimals;
    
      /**
       * Construct the token.
       *
       * This token must be created through a team multisig wallet, so that it is owned by that wallet.
       *
       * @param _name Token name
       * @param _symbol Token symbol - should be all caps
       * @param _initialSupply How many tokens we start with
       * @param _decimals Number of decimal places
       * @param _mintable Are new tokens created over the crowdsale or do we distribute only the initial supply? Note that when the token becomes transferable the minting always ends.
       */
      function CrowdsaleToken(string _name, string _symbol, uint _initialSupply, uint _decimals, bool _mintable)
        UpgradeableToken(msg.sender) {
    
        // Create any address, can be transferred
        // to team multisig via changeOwner(),
        // also remember to call setUpgradeMaster()
        owner = msg.sender;
    
        name = _name;
        symbol = _symbol;
    
        totalSupply = _initialSupply;
    
        decimals = _decimals;
    
        // Create initially all balance on the team multisig
        balances[owner] = totalSupply;
    
        if(totalSupply > 0) {
          Minted(owner, totalSupply);
        }
    
        // No more new supply allowed after the token creation
        if(!_mintable) {
          mintingFinished = true;
          if(totalSupply == 0) {
            throw; // Cannot create a token without supply and no minting
          }
        }
      }
    
      /**
       * When token is released to be transferable, enforce no new tokens can be created.
       */
      function releaseTokenTransfer() public onlyReleaseAgent {
        mintingFinished = true;
        super.releaseTokenTransfer();
      }
    
      /**
       * Allow upgrade agent functionality kick in only if the crowdsale was success.
       */
      function canUpgrade() public constant returns(bool) {
        return released && super.canUpgrade();
      }
    
      /**
       * Owner can update token information here.
       *
       * It is often useful to conceal the actual token association, until
       * the token operations, like central issuance or reissuance have been completed.
       *
       * This function allows the token owner to rename the token after the operations
       * have been completed and then point the audience to use the token contract.
       */
      function setTokenInformation(string _name, string _symbol) onlyOwner {
        name = _name;
        symbol = _symbol;
    
        UpdatedTokenInformation(name, symbol);
      }
    
    }