added FundTransfer event (#5)

added FundTransfer event (#5)

* using multiowned from ethereum/dapp-bin as a base for multi-signature actions

* multiowned: comments, improvements, defencive checks

* multiowned: fixes, tests

* multiowned: grouping confirmation-related functions together

* multiowned: defencive checks, tests

* multiowned: refactoring: removed some copy-paste

* multiowned: refactoring: using correct data type for addresses

* multiowned: refactoring: not polluting namespace with private members

* multiowned: ctor: no more implied owners!

* multiowned: have to call clearPending from time to time; minor improvements

* forgotten comment

* multiowned: indexing some args of the events

* SimpleMultiSigWallet: basic demonstration of multi-owned entity

* removing previous version

* Apache license

* crowdsale & token - WIP

* introduced registry of funds sent by investors

* added payment

* finishing ICO logic

* automatic check for unaccounted withdrawals

* added support for token emissions

* STQCrowdsale deployment hitting block gas limit: have to restructure

* caps updated

* test for FixedTimeBonuses

* test for FundsRegistry

* detaching crowdsale from funds and token when its time

* storing actual values for some events

* test for detachController()

* fix and extensive tests for MintableMultiownedToken

* MintableMultiownedToken: transferFrom test

* the beginning of STQCrowdsale tests

* fix for CirculatingToken; STQCrowdsale tests WIP

* fix for assert; STQCrowdsale tests WIP

* its better to be nonReentrant right from the beginning

* auto-pause improvement; STQCrowdsale tests WIP

* done with tests

* introduced minimum investment value

* disabling minting after ICO

* implicitly finishing ICO in case its time

* improvements

* improvements

* couple of notes

* deploying

* fix

* deploying SimpleMultiSigWallet as an automatic bug bounty

* doc update

* preparations for mainnet deployment

* adjusted soft cap

* 16 sep

* added FundTransfer event

pragma solidity 0.4.15;

import './ownership/multiowned.sol';
import './crowdsale/FixedTimeBonuses.sol';
import './crowdsale/FundsRegistry.sol';
import './STQToken.sol';
import 'zeppelin-solidity/contracts/ReentrancyGuard.sol';
import 'zeppelin-solidity/contracts/math/Math.sol';
import 'zeppelin-solidity/contracts/math/SafeMath.sol';

/// @title Storiqa ICO contract
contract STQCrowdsale is multiowned, ReentrancyGuard {
    using Math for uint256;
    using SafeMath for uint256;
    using FixedTimeBonuses for FixedTimeBonuses.Data;

    uint internal constant MSK2UTC_DELTA = 3600 * 3;

    enum IcoState { INIT, ICO, PAUSED, FAILED, SUCCEEDED }

    event StateChanged(IcoState _state);
    event FundTransfer(address backer, uint amount, bool isContribution);

    modifier requiresState(IcoState _state) {
        require(m_state == _state);
        _;
    }

    /// @dev triggers some state changes based on current time
    /// note: function body could be skipped!
    modifier timedStateChange() {
        if (IcoState.INIT == m_state && getCurrentTime() >= getStartTime())
            changeState(IcoState.ICO);

        if (IcoState.ICO == m_state && getCurrentTime() > getEndTime()) {
            finishICO();

            if (msg.value > 0)
                msg.sender.transfer(msg.value);
            // note that execution of further (but not preceding!) modifiers and functions ends here
        } else {
            _;
        }
    }

    /// @dev automatic check for unaccounted withdrawals
    modifier fundsChecker() {
        assert(m_state == IcoState.ICO);

        uint atTheBeginning = m_funds.balance;
        if (atTheBeginning < m_lastFundsAmount) {
            changeState(IcoState.PAUSED);
            if (msg.value > 0)
                msg.sender.transfer(msg.value); // we cant throw (have to save state), so refunding this way
            // note that execution of further (but not preceding!) modifiers and functions ends here
        } else {
            _;

            if (m_funds.balance < atTheBeginning) {
                changeState(IcoState.PAUSED);
            } else {
                m_lastFundsAmount = m_funds.balance;
            }
        }
    }

    // PUBLIC interface

    function STQCrowdsale(address[] _owners, address _token, address _funds)
        multiowned(_owners, 2)
    {
        require(3 == _owners.length);
        require(address(0) != address(_token) && address(0) != address(_funds));

        m_token = STQToken(_token);
        m_funds = FundsRegistry(_funds);

        m_bonuses.bonuses.push(FixedTimeBonuses.Bonus({endTime: 1505681999 + MSK2UTC_DELTA, bonus: 50}));
        m_bonuses.bonuses.push(FixedTimeBonuses.Bonus({endTime: 1505768399 + MSK2UTC_DELTA, bonus: 25}));
        m_bonuses.bonuses.push(FixedTimeBonuses.Bonus({endTime: 1505941199 + MSK2UTC_DELTA, bonus: 20}));
        m_bonuses.bonuses.push(FixedTimeBonuses.Bonus({endTime: 1506200399 + MSK2UTC_DELTA, bonus: 15}));
        m_bonuses.bonuses.push(FixedTimeBonuses.Bonus({endTime: 1506545999 + MSK2UTC_DELTA, bonus: 10}));
        m_bonuses.bonuses.push(FixedTimeBonuses.Bonus({endTime: 1506891599 + MSK2UTC_DELTA, bonus: 5}));
        m_bonuses.bonuses.push(FixedTimeBonuses.Bonus({endTime: 1508360399 + MSK2UTC_DELTA, bonus: 0}));
        m_bonuses.validate(true);
    }

    // PUBLIC interface: payments

    // fallback function as a shortcut
    function() payable {
        buy();  // only internal call here!
    }

    /// @notice ICO participation
    /// @return number of STQ tokens bought (with all decimal symbols)
    function buy()
        public
        payable
        nonReentrant
        timedStateChange
        requiresState(IcoState.ICO)
        fundsChecker
        returns (uint)
    {
        address investor = msg.sender;
        uint256 payment = msg.value;
        require(payment >= c_MinInvestment);

        uint startingInvariant = this.balance.add(m_funds.balance);

        // checking for max cap
        uint fundsAllowed = getMaximumFunds().sub(m_funds.totalInvested());
        assert(0 != fundsAllowed);  // in this case state must not be IcoState.ICO
        payment = fundsAllowed.min256(payment);
        uint256 change = msg.value.sub(payment);

        // issue tokens
        uint stq = calcSTQAmount(payment);
        m_token.mint(investor, stq);

        // record payment
        m_funds.invested.value(payment)(investor);
        FundTransfer(investor, payment, true);

        // check if ICO must be closed early
        if (change > 0)
        {
            assert(getMaximumFunds() == m_funds.totalInvested());
            finishICO();

            // send change
            investor.transfer(change);
            assert(startingInvariant == this.balance.add(m_funds.balance).add(change));
        }
        else
            assert(startingInvariant == this.balance.add(m_funds.balance));

        return stq;
    }

    // PUBLIC interface: owners: maintenance

    /// @notice pauses ICO
    function pause()
        external
        timedStateChange
        requiresState(IcoState.ICO)
        onlyowner
    {
        changeState(IcoState.PAUSED);
    }

    /// @notice resume paused ICO
    function unpause()
        external
        timedStateChange
        requiresState(IcoState.PAUSED)
        onlymanyowners(sha3(msg.data))
    {
        changeState(IcoState.ICO);
        checkTime();
    }

    /// @notice consider paused ICO as failed
    function fail()
        external
        timedStateChange
        requiresState(IcoState.PAUSED)
        onlymanyowners(sha3(msg.data))
    {
        changeState(IcoState.FAILED);
    }

    /// @notice In case we need to attach to existent token
    function setToken(address _token)
        external
        timedStateChange
        requiresState(IcoState.PAUSED)
        onlymanyowners(sha3(msg.data))
    {
        require(address(0) != _token);
        m_token = STQToken(_token);
    }

    /// @notice In case we need to attach to existent funds
    function setFundsRegistry(address _funds)
        external
        timedStateChange
        requiresState(IcoState.PAUSED)
        onlymanyowners(sha3(msg.data))
    {
        require(address(0) != _funds);
        m_funds = FundsRegistry(_funds);
    }

    /// @notice explicit trigger for timed state changes
    function checkTime()
        public
        timedStateChange
        onlyowner
    {
    }

    // INTERNAL functions

    function finishICO() private {
        if (m_funds.totalInvested() < getMinFunds())
            changeState(IcoState.FAILED);
        else
            changeState(IcoState.SUCCEEDED);
    }

    /// @dev performs only allowed state transitions
    function changeState(IcoState _newState) private {
        assert(m_state != _newState);

        if (IcoState.INIT == m_state) {        assert(IcoState.ICO == _newState); }
        else if (IcoState.ICO == m_state) {    assert(IcoState.PAUSED == _newState || IcoState.FAILED == _newState || IcoState.SUCCEEDED == _newState); }
        else if (IcoState.PAUSED == m_state) { assert(IcoState.ICO == _newState || IcoState.FAILED == _newState); }
        else assert(false);

        m_state = _newState;
        StateChanged(m_state);

        // this should be tightly linked
        if (IcoState.SUCCEEDED == m_state) {
            onSuccess();
        } else if (IcoState.FAILED == m_state) {
            onFailure();
        }
    }

    function onSuccess() private {
        // mint tokens for owners
        uint tokensPerOwner = m_token.totalSupply().mul(4).div(m_numOwners);
        for (uint i = 0; i < m_numOwners; i++)
            m_token.mint(getOwner(i), tokensPerOwner);

        m_funds.changeState(FundsRegistry.State.SUCCEEDED);
        m_funds.detachController();

        m_token.disableMinting();
        m_token.startCirculation();
        m_token.detachController();
    }

    function onFailure() private {
        m_funds.changeState(FundsRegistry.State.REFUNDING);
        m_funds.detachController();
    }

    /// @dev calculates amount of STQ to which payer of _wei is entitled
    function calcSTQAmount(uint _wei) private constant returns (uint) {
        uint stq = _wei.mul(c_STQperETH);

        // apply bonus
        stq = stq.mul(m_bonuses.getBonus(getCurrentTime()).add(100)).div(100);

        return stq;
    }

    /// @dev start time of the ICO, inclusive
    function getStartTime() private constant returns (uint) {
        return c_startTime;
    }

    /// @dev end time of the ICO, inclusive
    function getEndTime() private constant returns (uint) {
        return m_bonuses.getLastTime();
    }

    /// @dev to be overridden in tests
    function getCurrentTime() internal constant returns (uint) {
        return now;
    }

    /// @dev to be overridden in tests
    function getMinFunds() internal constant returns (uint) {
        return c_MinFunds;
    }

    /// @dev to be overridden in tests
    function getMaximumFunds() internal constant returns (uint) {
        return c_MaximumFunds;
    }

    // FIELDS

    /// @notice starting exchange rate of STQ
    uint public constant c_STQperETH = 100;

    /// @notice minimum investment
    uint public constant c_MinInvestment = 10 finney;

    /// @notice minimum investments to consider ICO as a success
    uint public constant c_MinFunds = 5000 ether;

    /// @notice maximum investments to be accepted during ICO
    uint public constant c_MaximumFunds = 500000 ether;

    /// @notice start time of the ICO
    uint public constant c_startTime = 1505541600;

    /// @notice timed bonuses
    FixedTimeBonuses.Data m_bonuses;

    /// @dev state of the ICO
    IcoState public m_state = IcoState.INIT;

    /// @dev contract responsible for token accounting
    STQToken public m_token;

    /// @dev contract responsible for investments accounting
    FundsRegistry public m_funds;

    /// @dev last recorded funds
    uint256 public m_lastFundsAmount;
}

pragma solidity 0.4.15;

import './ownership/multiowned.sol';
import './crowdsale/FixedTimeBonuses.sol';
import './crowdsale/FundsRegistry.sol';
import './STQToken.sol';
import 'zeppelin-solidity/contracts/ReentrancyGuard.sol';
import 'zeppelin-solidity/contracts/math/Math.sol';
import 'zeppelin-solidity/contracts/math/SafeMath.sol';

/// @title Storiqa ICO contract
contract STQCrowdsale is multiowned, ReentrancyGuard {
    using Math for uint256;
    using SafeMath for uint256;
    using FixedTimeBonuses for FixedTimeBonuses.Data;

    uint internal constant MSK2UTC_DELTA = 3600 * 3;

    enum IcoState { INIT, ICO, PAUSED, FAILED, SUCCEEDED }

    event StateChanged(IcoState _state);

    modifier requiresState(IcoState _state) {
        require(m_state == _state);
        _;
    }

    /// @dev triggers some state changes based on current time
    /// note: function body could be skipped!
    modifier timedStateChange() {
        if (IcoState.INIT == m_state && getCurrentTime() >= getStartTime())
            changeState(IcoState.ICO);

        if (IcoState.ICO == m_state && getCurrentTime() > getEndTime()) {
            finishICO();

            if (msg.value > 0)
                msg.sender.transfer(msg.value);
            // note that execution of further (but not preceding!) modifiers and functions ends here
        } else {
            _;
        }
    }

    /// @dev automatic check for unaccounted withdrawals
    modifier fundsChecker() {
        assert(m_state == IcoState.ICO);

        uint atTheBeginning = m_funds.balance;
        if (atTheBeginning < m_lastFundsAmount) {
            changeState(IcoState.PAUSED);
            if (msg.value > 0)
                msg.sender.transfer(msg.value); // we cant throw (have to save state), so refunding this way
            // note that execution of further (but not preceding!) modifiers and functions ends here
        } else {
            _;

            if (m_funds.balance < atTheBeginning) {
                changeState(IcoState.PAUSED);
            } else {
                m_lastFundsAmount = m_funds.balance;
            }
        }
    }

    // PUBLIC interface

    function STQCrowdsale(address[] _owners, address _token, address _funds)
        multiowned(_owners, 2)
    {
        require(3 == _owners.length);
        require(address(0) != address(_token) && address(0) != address(_funds));

        m_token = STQToken(_token);
        m_funds = FundsRegistry(_funds);

        m_bonuses.bonuses.push(FixedTimeBonuses.Bonus({endTime: 1505681999 + MSK2UTC_DELTA, bonus: 50}));
        m_bonuses.bonuses.push(FixedTimeBonuses.Bonus({endTime: 1505768399 + MSK2UTC_DELTA, bonus: 25}));
        m_bonuses.bonuses.push(FixedTimeBonuses.Bonus({endTime: 1505941199 + MSK2UTC_DELTA, bonus: 20}));
        m_bonuses.bonuses.push(FixedTimeBonuses.Bonus({endTime: 1506200399 + MSK2UTC_DELTA, bonus: 15}));
        m_bonuses.bonuses.push(FixedTimeBonuses.Bonus({endTime: 1506545999 + MSK2UTC_DELTA, bonus: 10}));
        m_bonuses.bonuses.push(FixedTimeBonuses.Bonus({endTime: 1506891599 + MSK2UTC_DELTA, bonus: 5}));
        m_bonuses.bonuses.push(FixedTimeBonuses.Bonus({endTime: 1508360399 + MSK2UTC_DELTA, bonus: 0}));
        m_bonuses.validate(true);
    }

    // PUBLIC interface: payments

    // fallback function as a shortcut
    function() payable {
        buy();  // only internal call here!
    }

    /// @notice ICO participation
    /// @return number of STQ tokens bought (with all decimal symbols)
    function buy()
        public
        payable
        nonReentrant
        timedStateChange
        requiresState(IcoState.ICO)
        fundsChecker
        returns (uint)
    {
        address investor = msg.sender;
        uint256 payment = msg.value;
        require(payment >= c_MinInvestment);

        uint startingInvariant = this.balance.add(m_funds.balance);

        // checking for max cap
        uint fundsAllowed = getMaximumFunds().sub(m_funds.totalInvested());
        assert(0 != fundsAllowed);  // in this case state must not be IcoState.ICO
        payment = fundsAllowed.min256(payment);
        uint256 change = msg.value.sub(payment);

        // issue tokens
        uint stq = calcSTQAmount(payment);
        m_token.mint(investor, stq);

        // record payment
        m_funds.invested.value(payment)(investor);

        // check if ICO must be closed early
        if (change > 0)
        {
            assert(getMaximumFunds() == m_funds.totalInvested());
            finishICO();

            // send change
            investor.transfer(change);
            assert(startingInvariant == this.balance.add(m_funds.balance).add(change));
        }
        else
            assert(startingInvariant == this.balance.add(m_funds.balance));

        return stq;
    }

    // PUBLIC interface: owners: maintenance

    /// @notice pauses ICO
    function pause()
        external
        timedStateChange
        requiresState(IcoState.ICO)
        onlyowner
    {
        changeState(IcoState.PAUSED);
    }

    /// @notice resume paused ICO
    function unpause()
        external
        timedStateChange
        requiresState(IcoState.PAUSED)
        onlymanyowners(sha3(msg.data))
    {
        changeState(IcoState.ICO);
        checkTime();
    }

    /// @notice consider paused ICO as failed
    function fail()
        external
        timedStateChange
        requiresState(IcoState.PAUSED)
        onlymanyowners(sha3(msg.data))
    {
        changeState(IcoState.FAILED);
    }

    /// @notice In case we need to attach to existent token
    function setToken(address _token)
        external
        timedStateChange
        requiresState(IcoState.PAUSED)
        onlymanyowners(sha3(msg.data))
    {
        require(address(0) != _token);
        m_token = STQToken(_token);
    }

    /// @notice In case we need to attach to existent funds
    function setFundsRegistry(address _funds)
        external
        timedStateChange
        requiresState(IcoState.PAUSED)
        onlymanyowners(sha3(msg.data))
    {
        require(address(0) != _funds);
        m_funds = FundsRegistry(_funds);
    }

    /// @notice explicit trigger for timed state changes
    function checkTime()
        public
        timedStateChange
        onlyowner
    {
    }

    // INTERNAL functions

    function finishICO() private {
        if (m_funds.totalInvested() < getMinFunds())
            changeState(IcoState.FAILED);
        else
            changeState(IcoState.SUCCEEDED);
    }

    /// @dev performs only allowed state transitions
    function changeState(IcoState _newState) private {
        assert(m_state != _newState);

        if (IcoState.INIT == m_state) {        assert(IcoState.ICO == _newState); }
        else if (IcoState.ICO == m_state) {    assert(IcoState.PAUSED == _newState || IcoState.FAILED == _newState || IcoState.SUCCEEDED == _newState); }
        else if (IcoState.PAUSED == m_state) { assert(IcoState.ICO == _newState || IcoState.FAILED == _newState); }
        else assert(false);

        m_state = _newState;
        StateChanged(m_state);

        // this should be tightly linked
        if (IcoState.SUCCEEDED == m_state) {
            onSuccess();
        } else if (IcoState.FAILED == m_state) {
            onFailure();
        }
    }

    function onSuccess() private {
        // mint tokens for owners
        uint tokensPerOwner = m_token.totalSupply().mul(4).div(m_numOwners);
        for (uint i = 0; i < m_numOwners; i++)
            m_token.mint(getOwner(i), tokensPerOwner);

        m_funds.changeState(FundsRegistry.State.SUCCEEDED);
        m_funds.detachController();

        m_token.disableMinting();
        m_token.startCirculation();
        m_token.detachController();
    }

    function onFailure() private {
        m_funds.changeState(FundsRegistry.State.REFUNDING);
        m_funds.detachController();
    }

    /// @dev calculates amount of STQ to which payer of _wei is entitled
    function calcSTQAmount(uint _wei) private constant returns (uint) {
        uint stq = _wei.mul(c_STQperETH);

        // apply bonus
        stq = stq.mul(m_bonuses.getBonus(getCurrentTime()).add(100)).div(100);

        return stq;
    }

    /// @dev start time of the ICO, inclusive
    function getStartTime() private constant returns (uint) {
        return c_startTime;
    }

    /// @dev end time of the ICO, inclusive
    function getEndTime() private constant returns (uint) {
        return m_bonuses.getLastTime();
    }

    /// @dev to be overridden in tests
    function getCurrentTime() internal constant returns (uint) {
        return now;
    }

    /// @dev to be overridden in tests
    function getMinFunds() internal constant returns (uint) {
        return c_MinFunds;
    }

    /// @dev to be overridden in tests
    function getMaximumFunds() internal constant returns (uint) {
        return c_MaximumFunds;
    }

    // FIELDS

    /// @notice starting exchange rate of STQ
    uint public constant c_STQperETH = 100;

    /// @notice minimum investment
    uint public constant c_MinInvestment = 10 finney;

    /// @notice minimum investments to consider ICO as a success
    uint public constant c_MinFunds = 5000 ether;

    /// @notice maximum investments to be accepted during ICO
    uint public constant c_MaximumFunds = 500000 ether;

    /// @notice start time of the ICO
    uint public constant c_startTime = 1505541600;

    /// @notice timed bonuses
    FixedTimeBonuses.Data m_bonuses;

    /// @dev state of the ICO
    IcoState public m_state = IcoState.INIT;

    /// @dev contract responsible for token accounting
    STQToken public m_token;

    /// @dev contract responsible for investments accounting
    FundsRegistry public m_funds;

    /// @dev last recorded funds
    uint256 public m_lastFundsAmount;
}


Fix unfreeze bug

Fix unfreeze bug

Previously, there was no way to ensure that a state could be revoked
before being frozen. After this change, you can now revoke the state
before the contract becomes frozen.

/**
 * This contract ensures that the latest signed state between some parties is
 * revealed. This solves the data availability contest problem.
 */
contract Adjudicator {

	// The maximum integer value that can be stored in an uint256 (uint)
	uint public constant UINT_MAX = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;

	// Whether the state has been frozen or not
	bool public frozen = false;

	// The current nonce of the state
	uint nonce = 0;

	// The timestamp of the last state sent
	uint lastTimestamp = 0;

	// The address of the owner of this contract
	address owner;

	// The timeout period before this contract can be frozen
	uint timeout;

	// The last hash of the latest state
	bytes32 public stateHash;

	modifier onlyOwner {
		if (msg.sender == owner) {
			_
		} else {
			throw;
		}
	}

	modifier notFrozen {
		if (frozen) {
			throw;
		} else {
			_
		}
	}

	/**
	 * Creates a new Adjudicator contract.
	 *
	 * _owner: The owner of this contract
	 * _timeout: The timeout period before this contract can be frozen
	 */
	function Adjudicator(address _owner, uint _timeout) {
		owner = _owner;
		timeout = _timeout;
	}

	/**
	 * Submits a potential hash of state into this contract.
	 *
	 * _newNonce: The nonce of the new state
	 * _stateHash: The hash of the latest state
	 *
	 * returns: `true` if sucessful, otherwise `false`
	 */
	function submit(uint _newNonce, bytes32 _stateHash)
		external
		onlyOwner
		notFrozen
		returns (bool)
	{
		if (_newNonce > nonce) {
			nonce = _newNonce;
			stateHash = _stateHash;
			return true;
		} else {
			return false;
		}
	}

	/**
	 * Unfreezes the contract and prevents last sent state from being frozen.
	 *
	 * returns: `true` if successful, otherwise `false`
	 */
	function unfreeze() external onlyOwner returns (bool) {
		if (nonce != UINT_MAX) {
			lastTimestamp = 0;
			frozen = false;
			return true;
		} else {
			return false;
		}
	}

	/**
	 * Freezes the contract if the nonce is final or if the timeout period has
	 * been reached.
	 *
	 * returns: `true` if successful, otherwise `false`
	 */
	function finalize() external notFrozen returns (bool) {
		if (nonce == UINT_MAX || (lastTimestamp != 0 && now > lastTimestamp + timeout)) {
			frozen = true;
			return true;
		} else {
			return false;
		}
	}

	/**
	 * Kills the current contract.
	 *
	 * _recipient: The recipient of funds from the `selfdestruct` call
	 */
	function kill(address _recipient) external onlyOwner {
		selfdestruct(_recipient);
	}
}

/**
 * This contract ensures that the latest signed state between some parties is
 * revealed. This solves the data availability contest problem.
 */
contract Adjudicator {

	// The maximum integer value that can be stored in an uint256 (uint)
	uint public constant UINT_MAX = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;

	// Whether the state has been frozen or not
	bool public frozen = false;

	// The current nonce of the state
	uint nonce = 0;

	// The timestamp of the last state sent
	uint lastTimestamp = 0;

	// The address of the owner of this contract
	address owner;

	// The timeout period before this contract can be frozen
	uint timeout;

	// The last hash of the latest state
	bytes32 public stateHash;

	modifier onlyOwner {
		if (msg.sender == owner) {
			_
		} else {
			throw;
		}
	}

	modifier notFrozen {
		if (frozen) {
			throw;
		} else {
			_
		}
	}

	/**
	 * Creates a new Adjudicator contract.
	 *
	 * _owner: The owner of this contract
	 * _timeout: The timeout period before this contract can be frozen
	 */
	function Adjudicator(address _owner, uint _timeout) {
		owner = _owner;
		timeout = _timeout;
	}

	/**
	 * Submits a potential hash of state into this contract.
	 *
	 * _newNonce: The nonce of the new state
	 * _stateHash: The hash of the latest state
	 *
	 * returns: `true` if sucessful, otherwise `false`
	 */
	function submit(uint _newNonce, bytes32 _stateHash)
		external
		onlyOwner
		notFrozen
		returns (bool)
	{
		if (_newNonce > nonce) {
			nonce = _newNonce;
			stateHash = _stateHash;
			return true;
		} else {
			return false;
		}
	}

	/**
	 * Unfreezes the contract only if the the contract is frozen.
	 *
	 * returns: `true` if successful, otherwise `false`
	 */
	function unfreeze() external onlyOwner returns (bool) {
		if (frozen && nonce != UINT_MAX) {
			lastTimestamp = 0;
			frozen = false;
			return true;
		} else {
			return false;
		}
	}

	/**
	 * Freezes the contract if the nonce is final or if the timeout period has
	 * been reached.
	 *
	 * returns: `true` if successful, otherwise `false`
	 */
	function finalize() external notFrozen returns (bool) {
		if (nonce == UINT_MAX || (lastTimestamp != 0 && now > lastTimestamp + timeout)) {
			frozen = true;
			return true;
		} else {
			return false;
		}
	}

	/**
	 * Kills the current contract.
	 *
	 * _recipient: The recipient of funds from the `selfdestruct` call
	 */
	function kill(address _recipient) external onlyOwner {
		selfdestruct(_recipient);
	}
}


events documentation

events documentation

import {User} from "./User.sol";
import {Participant} from "./Participant.sol";
import {ParticipantAuthority} from "./ParticipantAuthority.sol";
import {UserState} from "./UserState.sol";

contract Certificate {

    address public constant owner = msg.sender;
    address public kpcs;

    enum State {
        /*
        Created: certificate has been created, but awaiting addition of parsels
        Pending: parsels added, awaiting signatures from issuer and either importer or exporter
        Issued: all signatures received, certificate is valid.
        Completed: shipment validated upon border crossing
        Expired: shipment has expired without receiving a 'completed' Event
        */
        Created, Pending, Issued, Completed, Expired
    }
    State private state = State.Created;

    struct Dates {
        //date the certificate is created + requested
        uint created;

        //date the certificate is signed by all parties and is officially issued
        uint issued;

        //date the shipment is certified by the importing authority
        uint completed;

        //default expiration date of the certificate, exercised only if shipment never verified by importing authority
        uint expired;
    }
    Dates public dates = Dates(now, 0, 0, 0);

    //Participants in the KP: member countries of source and destination
    struct Participants {
        address[] origins; //the declared origin of the goods
        address source; //the country we are exporting from
        address destination; //the country we are importing to
    }
    Participants private participants;

    //the parties to the transaction: importer and exporter
    struct Parties {
        address exporter;
        address importer;
    }
    Parties public parties;

    struct Signature {
        uint date;
        address owner;
    }

    struct Signatures {
        Signature exporter;
        Signature importer;
        Signature importerOnReceipt;
        Signature exporterAuthority;
        Signature importerAuthority;
        Signature importerAuthorityOnReceipt;
    }
    Signatures private signatures;

    struct Parsel {
        uint carats;
        uint value;
        address[] origins;
    }
    Parsel[] public parsels;

    //expire this certificate 30 days in the future
    uint private constant expirationDateFromNow = now + (60 * 60 * 24 * 30);

    //when the certificate is created by the exporting party
    event Created(address indexed certificate);

    //when the parsels have been added, and the certificate is awaiting signing by parties and authorities
    event Pending(address indexed certificate,
        address exporter,
        address importer,
        address participantSource,
        address participantDestination);

    //when all required parties and authorities have signed the certificate
    event Issued(address indexed certificate);

    //when a certificate has been signed by a party of authority's agent
    event Signed(address from, string name);

    event Expired(address indexed certificate);

    //when a certificate completes transit of an international border,
    //and is marked as received by the improting authority
    event Complete(address from, string name);

    /*
    Certificates should be created by the exporter: the party in possession of the goods.
    params:
    - importer - importing Party
    - exporter - exporting Party
    - participantOrigin - KPCS Participant (member country) the goods were sourced _from_
      ... likely the country of geological origin
    - participantSource - KPCS Participant (member country) the goods are being sent from
    - participantDestination - KPCS Participant (member country) the goods are being sent to
    */
    function Certificate(address _kpcs,
        address _exporter,
        address _importer,
        address _participantSource,
        address _participantDestination) {
            kpcs = _kpcs;
            parties = Parties(_exporter, _importer);
            if(User(parties.exporter).getState() == UserState.Accepted()) {
                participants = Participants(new address[](0x0), _participantSource, _participantDestination);
                signatures = Signatures(
                    Signature(now, _exporter),
                    Signature(0,0x0),
                    Signature(0,0x0),
                    Signature(0,0x0),
                    Signature(0,0x0),
                    Signature(0,0x0));
                dates = Dates(now, 0, 0, expirationDateFromNow);
                Created(this);
            }
    }

    function kill() {
        if (msg.sender == owner && state == State.Pending) {
            suicide(owner);
        }
    }

    function getNumberOfParticipantsOrigins() constant returns (uint) {
        return participants.origins.length;
    }

    function getParticipantOriginWithIndex(uint index) constant returns (address) {
        return participants.origins[index];
    }

    function getParticipantSource() constant returns (address) {
        return participants.source;
    }

    function getParticipantDestination() constant returns (address) {
        return participants.destination;
    }

    function getParticipants() constant returns (address[]) {
        address[] memory allParticipants = new address[](participants.origins.length + 2);
        allParticipants[0] = (participants.source);
        allParticipants[1] = participants.destination;
        uint origins = participants.origins.length;
        for(uint i = 0; i<origins; i++) {
            allParticipants[i + 2] = participants.origins[i];
        }
        return allParticipants;
    }

    function addParsel(uint carats, uint value, address[] origins) {
        if(msg.sender != owner || state != State.Created) {
            return;
        }
        parsels.push(Parsel(carats, value, origins));
        for(uint index = 0; index < origins.length; index++) {
            participants.origins.push(origins[index]);
        }
    }

    function completedAddingParsels() {
        if(msg.sender != owner || state != State.Created) {
            return;
        }
        state = State.Pending;
        Pending(this, parties.exporter, parties.importer, participants.source, participants.destination);
    }

    function getImportingParty() returns (address) {
        return User(parties.importer);
    }

    function getExportingParty() returns (address) {
        return User(parties.exporter);
    }

    function getSignatures() returns (uint[4]) {
        return [signatures.exporter.date,
            signatures.importer.date,
            signatures.exporterAuthority.date,
            signatures.importerAuthority.date
        ];
    }

    function canSign() returns (bool) {
        if(state != State.Pending) {
            return false;
        }

        if(ParticipantAuthority(Participant(participants.source).getExportingAuthority()).isSenderRegisteredAgent(msg.sender)) {
            if(signatures.exporterAuthority.date > 0) {
                return false;
            }
            if(Participant(participants.source).getState() != UserState.Accepted()) {
                return false;
            }
            return true;
        } else if(ParticipantAuthority(Participant(participants.destination).getImportingAuthority()).isSenderRegisteredAgent(msg.sender)) {
            if(signatures.importerAuthority.date > 0) {
                return false;
            }
            if(Participant(participants.destination).getState() != UserState.Accepted()) {
                return false;
            }
            return true;
        } else if(msg.sender == User(parties.importer).getOwner()) {
            if(signatures.importer.date > 0 || User(parties.importer).getState() != UserState.Accepted()) {
                return false;
            }
            return true;
        }
        return false;
    }

    function sign() {
        if(state != State.Pending) {
            return;
        }

        if(ParticipantAuthority(Participant(participants.source).getExportingAuthority()).isSenderRegisteredAgent(msg.sender)) {
            if(signatures.exporterAuthority.date > 0) {
                return;
            }
            if(Participant(participants.source).getState() != UserState.Accepted()) {
                return;
            }
            Signed(msg.sender, "Exporting Authority");
            signatures.exporterAuthority = Signature(now, msg.sender);
        } else if(ParticipantAuthority(Participant(participants.destination).getImportingAuthority()).isSenderRegisteredAgent(msg.sender)) {
            if(signatures.importerAuthority.date > 0) {
                return;
            }
            if(Participant(participants.destination).getState() != UserState.Accepted()) {
                return;
            }
            Signed(msg.sender, "Importing Authority");
            signatures.importerAuthority = Signature(now, msg.sender);
        } else if(msg.sender == User(parties.importer).getOwner()) {
            if(signatures.importer.date > 0 || User(parties.importer).getState() != UserState.Accepted()) {
                return;
            }
            Signed(msg.sender, "Importing Party");
            signatures.importer = Signature(now, msg.sender);
        } else {
            return;
        }

        if(hasRequiredSignaturesToValidate()) {
            state = State.Issued;
            dates.issued = now;
            Issued(this);
        }
    }

    function markAsReceived() {
        if(ParticipantAuthority(Participant(participants.destination).getImportingAuthority()).isSenderRegisteredAgent(msg.sender)) {
            if(signatures.importerAuthorityOnReceipt.date > 0) {
                return;
            }
            dates.completed = now;
            signatures.importerAuthorityOnReceipt = Signature(now, msg.sender);
            state = State.Completed;
            Complete(msg.sender, "Importing Authority - On Receipt");
        } else if(msg.sender == User(parties.importer).getOwner()) {
            if(signatures.importerOnReceipt.date > 0) {
                return;
            }
            signatures.importerOnReceipt = Signature(now, msg.sender);
            state = State.Completed;
            Complete(msg.sender, "Importing Party - On Receipt");
        }
    }

    function hasRequiredSignaturesToValidate() returns (bool isComplete) {
        return (signatures.importerAuthority.date > 0 && signatures.exporterAuthority.date > 0 && signatures.importer.date > 0 && signatures.exporter.date > 0);
    }

    function expireIfNecessary() {
        if(now >= dates.expired && state == State.Issued) {
            state = State.Expired;
        }
        Expired(this);
    }

    function isExpired() returns (bool) {
        return (state == State.Expired);
    }

    function isComplete() returns (bool) {
        return (state == State.Completed);
    }

    function isValid() returns (bool) {
        return (state == State.Issued && now < dates.expired);
    }
}

import {User} from "./User.sol";
import {Participant} from "./Participant.sol";
import {ParticipantAuthority} from "./ParticipantAuthority.sol";
import {UserState} from "./UserState.sol";

contract Certificate {

    address public constant owner = msg.sender;
    address public kpcs;

    enum State {
        /*
        Pending: certificate has been created, but awaiting signatures from issuer and either importer or exporter
        Issued: all signatures received, certificate is valid.
        Completed: shipment validated upon border crossing
        Expired: shipment has expired without receiving a 'completed' Event
        */
        Created, Pending, Issued, Completed, Expired
    }
    State private state = State.Created;

    struct Dates {
        //date the certificate is created + requested
        uint created;

        //date the certificate is signed by all parties and is officially issued
        uint issued;

        //date the shipment is certified by the importing authority
        uint completed;

        //default expiration date of the certificate, exercised only if shipment never verified by importing authority
        uint expired;
    }
    Dates public dates = Dates(now, 0, 0, 0);

    //Participants in the KP: member countries of source and destination
    struct Participants {
        address[] origins; //the declared origin of the goods
        address source; //the country we are exporting from
        address destination; //the country we are importing to
    }
    Participants private participants;

    //the parties to the transaction: importer and exporter
    struct Parties {
        address exporter;
        address importer;
    }
    Parties public parties;

    struct Signature {
        uint date;
        address owner;
    }

    struct Signatures {
        Signature exporter;
        Signature importer;
        Signature importerOnReceipt;
        Signature exporterAuthority;
        Signature importerAuthority;
        Signature importerAuthorityOnReceipt;
    }
    Signatures private signatures;

    struct Parsel {
        uint carats;
        uint value;
        address[] origins;
    }
    Parsel[] public parsels;

    //expire this certificate 30 days in the future
    uint private constant expirationDateFromNow = now + (60 * 60 * 24 * 30);

    //when the certificate is created by the exporting party
    event Created(address indexed certificate);

    //when the parsels have been added, and the certificate is awaiting signing by parties and authorities
    event Pending(address indexed certificate,
        address exporter,
        address importer,
        address participantSource,
        address participantDestination);

    //when all required parties and authorities have signed the certificate
    event Issued(address indexed certificate);

    //when a certificate has been signed by a party of authority's agent
    event Signed(address from, string name);

    event Expired(address indexed certificate);

    //when a certificate completes transit of an international border,
    //and is marked as received by the improting authority
    event Complete(address from, string name);

    /*
    Certificates should be created by the exporter: the party in possession of the goods.
    params:
    - importer - importing Party
    - exporter - exporting Party
    - participantOrigin - KPCS Participant (member country) the goods were sourced _from_
      ... likely the country of geological origin
    - participantSource - KPCS Participant (member country) the goods are being sent from
    - participantDestination - KPCS Participant (member country) the goods are being sent to
    */
    function Certificate(address _kpcs,
        address _exporter,
        address _importer,
        address _participantSource,
        address _participantDestination) {
            kpcs = _kpcs;
            parties = Parties(_exporter, _importer);
            if(User(parties.exporter).getState() == UserState.Accepted()) {
                participants = Participants(new address[](0x0), _participantSource, _participantDestination);
                signatures = Signatures(
                    Signature(now, _exporter),
                    Signature(0,0x0),
                    Signature(0,0x0),
                    Signature(0,0x0),
                    Signature(0,0x0),
                    Signature(0,0x0));
                dates = Dates(now, 0, 0, expirationDateFromNow);
                Created(this);
            }
    }

    function kill() {
        if (msg.sender == owner && state == State.Pending) {
            suicide(owner);
        }
    }

    function getNumberOfParticipantsOrigins() constant returns (uint) {
        return participants.origins.length;
    }

    function getParticipantOriginWithIndex(uint index) constant returns (address) {
        return participants.origins[index];
    }

    function getParticipantSource() constant returns (address) {
        return participants.source;
    }

    function getParticipantDestination() constant returns (address) {
        return participants.destination;
    }

    function getParticipants() constant returns (address[]) {
        address[] memory allParticipants = new address[](participants.origins.length + 2);
        allParticipants[0] = (participants.source);
        allParticipants[1] = participants.destination;
        uint origins = participants.origins.length;
        for(uint i = 0; i<origins; i++) {
            allParticipants[i + 2] = participants.origins[i];
        }
        return allParticipants;
    }

    function addParsel(uint carats, uint value, address[] origins) {
        if(msg.sender != owner || state != State.Created) {
            return;
        }
        parsels.push(Parsel(carats, value, origins));
        for(uint index = 0; index < origins.length; index++) {
            participants.origins.push(origins[index]);
        }
    }

    function completedAddingParsels() {
        if(msg.sender != owner || state != State.Created) {
            return;
        }
        state = State.Pending;
        Pending(this, parties.exporter, parties.importer, participants.source, participants.destination);
    }

    function getImportingParty() returns (address) {
        return User(parties.importer);
    }

    function getExportingParty() returns (address) {
        return User(parties.exporter);
    }

    function getSignatures() returns (uint[4]) {
        return [signatures.exporter.date,
            signatures.importer.date,
            signatures.exporterAuthority.date,
            signatures.importerAuthority.date
        ];
    }

    function canSign() returns (bool) {
        if(state != State.Pending) {
            return false;
        }

        if(ParticipantAuthority(Participant(participants.source).getExportingAuthority()).isSenderRegisteredAgent(msg.sender)) {
            if(signatures.exporterAuthority.date > 0) {
                return false;
            }
            if(Participant(participants.source).getState() != UserState.Accepted()) {
                return false;
            }
            return true;
        } else if(ParticipantAuthority(Participant(participants.destination).getImportingAuthority()).isSenderRegisteredAgent(msg.sender)) {
            if(signatures.importerAuthority.date > 0) {
                return false;
            }
            if(Participant(participants.destination).getState() != UserState.Accepted()) {
                return false;
            }
            return true;
        } else if(msg.sender == User(parties.importer).getOwner()) {
            if(signatures.importer.date > 0 || User(parties.importer).getState() != UserState.Accepted()) {
                return false;
            }
            return true;
        }
        return false;
    }

    function sign() {
        if(state != State.Pending) {
            return;
        }

        if(ParticipantAuthority(Participant(participants.source).getExportingAuthority()).isSenderRegisteredAgent(msg.sender)) {
            if(signatures.exporterAuthority.date > 0) {
                return;
            }
            if(Participant(participants.source).getState() != UserState.Accepted()) {
                return;
            }
            Signed(msg.sender, "Exporting Authority");
            signatures.exporterAuthority = Signature(now, msg.sender);
        } else if(ParticipantAuthority(Participant(participants.destination).getImportingAuthority()).isSenderRegisteredAgent(msg.sender)) {
            if(signatures.importerAuthority.date > 0) {
                return;
            }
            if(Participant(participants.destination).getState() != UserState.Accepted()) {
                return;
            }
            Signed(msg.sender, "Importing Authority");
            signatures.importerAuthority = Signature(now, msg.sender);
        } else if(msg.sender == User(parties.importer).getOwner()) {
            if(signatures.importer.date > 0 || User(parties.importer).getState() != UserState.Accepted()) {
                return;
            }
            Signed(msg.sender, "Importing Party");
            signatures.importer = Signature(now, msg.sender);
        } else {
            return;
        }

        if(hasRequiredSignaturesToValidate()) {
            state = State.Issued;
            dates.issued = now;
            Issued(this);
        }
    }

    function markAsReceived() {
        if(ParticipantAuthority(Participant(participants.destination).getImportingAuthority()).isSenderRegisteredAgent(msg.sender)) {
            if(signatures.importerAuthorityOnReceipt.date > 0) {
                return;
            }
            dates.completed = now;
            signatures.importerAuthorityOnReceipt = Signature(now, msg.sender);
            state = State.Completed;
            Complete(msg.sender, "Importing Authority - On Receipt");
        } else if(msg.sender == User(parties.importer).getOwner()) {
            if(signatures.importerOnReceipt.date > 0) {
                return;
            }
            signatures.importerOnReceipt = Signature(now, msg.sender);
            state = State.Completed;
            Complete(msg.sender, "Importing Party - On Receipt");
        }
    }

    function hasRequiredSignaturesToValidate() returns (bool isComplete) {
        return (signatures.importerAuthority.date > 0 && signatures.exporterAuthority.date > 0 && signatures.importer.date > 0 && signatures.exporter.date > 0);
    }

    function expireIfNecessary() {
        if(now >= dates.expired && state == State.Issued) {
            state = State.Expired;
        }
        Expired(this);
    }

    function isExpired() returns (bool) {
        return (state == State.Expired);
    }

    function isComplete() returns (bool) {
        return (state == State.Completed);
    }

    function isValid() returns (bool) {
        return (state == State.Issued && now < dates.expired);
    }
}


The original REP TokenTraderFactory

The original REP TokenTraderFactory

Published by https://www.reddit.com/user/JonnyLatte at https://etherscan.io/address/0x3398080b81a1cff1429af347ce2b17fc28de3937#code . Note that no licence is specified.

pragma solidity ^0.4.0;

//https://github.com/nexusdev/erc20/blob/master/contracts/erc20.sol

contract ERC20Constant {
    function totalSupply() constant returns (uint supply);
    function balanceOf( address who ) constant returns (uint value);
    function allowance(address owner, address spender) constant returns (uint _allowance);
}
contract ERC20Stateful {
    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);
}
contract ERC20Events {
    event Transfer(address indexed from, address indexed to, uint value);
    event Approval( address indexed owner, address indexed spender, uint value);
}
contract ERC20 is ERC20Constant, ERC20Stateful, ERC20Events {}

contract owned {
    address public owner;

    function owned() {
        owner = msg.sender;
    }

    modifier onlyOwner {
        if (msg.sender != owner) throw;
        _;
    }

    function transferOwnership(address newOwner) onlyOwner {
        owner = newOwner;
    }
}

// contract can buy or sell tokens for ETH
// prices are in amount of wei per batch of token units

contract TokenTrader is owned {

    address public asset;       // address of token
    uint256 public buyPrice;   // contact buys lots of token at this price
    uint256 public sellPrice;  // contract sells lots at this price
    uint256 public units;       // lot size (token-wei)

    bool public sellsTokens;    // is contract selling
    bool public buysTokens;     // is contract buying

    event ActivatedEvent(bool sells, bool buys);
    event UpdateEvent();

    function TokenTrader (
        address _asset,
        uint256 _buyPrice,
        uint256 _sellPrice,
        uint256 _units,
        bool    _sellsTokens,
        bool    _buysTokens
        )
    {
          asset         = _asset;
          buyPrice     = _buyPrice;
          sellPrice    = _sellPrice;
          units         = _units;
          sellsTokens   = _sellsTokens;
          buysTokens    = _buysTokens;

          ActivatedEvent(sellsTokens,buysTokens);
    }

    // modify trading behavior
    function activate (
        bool    _sellsTokens,
        bool    _buysTokens
        ) onlyOwner
    {
          sellsTokens   = _sellsTokens;
          buysTokens    = _buysTokens;

          ActivatedEvent(sellsTokens,buysTokens);
    }

    // allows owner to deposit ETH
    // deposit tokens by sending them directly to contract
    // buyers must not send tokens to the contract, use: sell(...)
    function deposit() payable onlyOwner {
        UpdateEvent();
    }

    // allow owner to remove trade token
    function withdrawAsset(uint256 _value) onlyOwner returns (bool ok)
    {
        return ERC20(asset).transfer(owner,_value);
        UpdateEvent();
    }

    // allow owner to remove arbitrary tokens
    // included just in case contract receives wrong token
    function withdrawToken(address _token, uint256 _value) onlyOwner returns (bool ok)
    {
        return ERC20(_token).transfer(owner,_value);
        UpdateEvent();
    }

    // allow owner to remove ETH
    function withdraw(uint256 _value) onlyOwner returns (bool ok)
    {
        if(this.balance >= _value) {
            return owner.send(_value);
        }
        UpdateEvent();
    }

    //user buys token with ETH
    function buy() payable {
        if(sellsTokens || msg.sender == owner)
        {
            uint order   = msg.value / sellPrice;
            uint can_sell = ERC20(asset).balanceOf(address(this)) / units;

            if(order > can_sell)
            {
                uint256 change = msg.value - (can_sell * sellPrice);
                order = can_sell;
                if(!msg.sender.send(change)) throw;
            }

            if(order > 0) {
                if(!ERC20(asset).transfer(msg.sender,order * units)) throw;
            }
            UpdateEvent();
        }
        else if(!msg.sender.send(msg.value)) throw;  // return user funds if the contract is not selling
    }

    // user sells token for ETH
    // user must set allowance for this contract before calling
    function sell(uint256 amount) {
        if (buysTokens || msg.sender == owner) {
            uint256 can_buy = this.balance / buyPrice;  // token lots contract can buy
            uint256 order = amount / units;             // token lots available

            if(order > can_buy) order = can_buy;        // adjust order for funds

            if (order > 0)
            {
                // extract user tokens
                if(!ERC20(asset).transferFrom(msg.sender, address(this), amount)) throw;

                // pay user
                if(!msg.sender.send(order * buyPrice)) throw;
            }
            UpdateEvent();
        }
    }

    // sending ETH to contract sells ETH to user
    function () payable {
        buy();
    }
}

// This contract deploys TokenTrader contracts and logs the event
// trade pairs are identified with sha3(asset,units)

contract TokenTraderFactory {

    event TradeListing(bytes32 bookid, address owner, address addr);
    event NewBook(bytes32 bookid, address asset, uint256 units);

    mapping( address => bool ) _verify;
    mapping( bytes32 => bool ) pairExits;

    function verify(address tradeContract)  constant returns (
        bool valid,
        address asset,
        uint256 buyPrice,
        uint256 sellPrice,
        uint256 units,
        bool    sellsTokens,
        bool    buysTokens
        ) {

            valid = _verify[tradeContract];

            if(valid) {
                TokenTrader t = TokenTrader(tradeContract);

                asset = t.asset();
                buyPrice =t.buyPrice();
                sellPrice = t.sellPrice();
                units = t.units();
                sellsTokens = t.sellsTokens();
                buysTokens = t.buysTokens();
            }

    }

    function createTradeContract(
        address _asset,
        uint256 _buyPrice,
        uint256 _sellPrice,
        uint256 _units,
        bool    _sellsTokens,
        bool    _buysTokens
        ) returns (address)
    {
        if(_buyPrice > _sellPrice) throw; // must make profit on spread
        if(_units == 0) throw;              // can't sell zero units

        address trader = new TokenTrader (
                     _asset,
                     _buyPrice,
                     _sellPrice,
                     _units,
                     _sellsTokens,
                     _buysTokens);

        var bookid = sha3(_asset,_units);

        _verify[trader] = true; // record that this factory created the trader

        TokenTrader(trader).transferOwnership(msg.sender); // set the owner to whoever called the function

        if(pairExits[bookid] == false) {
            pairExits[bookid] = true;
            NewBook(bookid, _asset, _units);
        }

        TradeListing(bookid,msg.sender,trader);
    }

    function () {
        throw;     // Prevents accidental sending of ether to the factory
    }
}

error: pathspec 'contracts/TokenTraderFactory.sol' did not match any file(s) known to git


Migrated some addresses

Migrated some addresses

pragma solidity ^0.4.15;

import './SafeMath.sol';
import './Ownable.sol';
import './TokenHolder.sol';
import './KinToken.sol';
import './VestingTrustee.sol';

/// @title Kin token sale contract.
contract KinTokenSale is Ownable, TokenHolder {
    using SafeMath for uint256;

    // External parties:

    // KIN token contract.
    KinToken public kin;

    // Vesting contract for pre-sale participants.
    VestingTrustee public trustee;

    // Received funds are forwarded to this address.
    address public fundingRecipient;

    // Kin token decimals.
    // Using same decimal value as ETH (makes ETH-KIN conversion much easier).
    // This is the same as in Kin token contract.
    uint256 public constant TOKEN_DECIMALS = 10 ** 18;

    // Maximum number of tokens in circulation: 10 trillion.
    uint256 public constant MAX_TOKENS = 10 ** 13 * TOKEN_DECIMALS;

    // Maximum tokens offered in the sale.
    uint256 public constant MAX_TOKENS_SOLD = 512192121951 * TOKEN_DECIMALS;

    // Wei to 1 USD ratio.
    //
    // TODO update to the real ETH price before sale launch.
    uint256 public constant WEI_PER_USD = uint256(1 ether) / 360;

    // KIN to 1 USD ratio,
    // such MAX_TOKENS_SOLD * KIN_PER_USD is the $75M cap.
    uint256 public constant KIN_PER_USD = 6829 * TOKEN_DECIMALS;

    // KIN to 1 wei ratio.
    uint256 public constant KIN_PER_WEI = KIN_PER_USD / WEI_PER_USD;

    // Sale start, end blocks (time ranges)
    uint256 public constant SALE_DURATION = 14 days;
    uint256 public startTime;
    uint256 public endTime;

    // Amount of tokens sold until now in the sale.
    uint256 public tokensSold = 0;

    // Participation caps, according to KYC tiers.
    uint256 public constant TIER_1_CAP = 100000 * WEI_PER_USD;
    uint256 public constant TIER_2_CAP = uint256(-1); // Maximum uint256 value

    // Accumulated amount each participant have contributed so far.
    mapping (address => uint256) public participationHistory;

    // Maximum amount that each particular is allowed to contribute (in WEI).
    mapping (address => uint256) public participationCaps;

    // Maximum amount ANYBODY is currently allowed to contribute.
    uint256 public hardParticipationCap = 5000 * WEI_PER_USD;

    // Vesting information for special addresses:
    struct TokenGrant {
        uint256 value;
        uint256 startOffset;
        uint256 cliffOffset;
        uint256 endOffset;
        uint256 installmentLength;
        uint8 percentVested;
    }

    address[] public tokenGrantees;
    mapping (address => TokenGrant) public tokenGrants;
    uint256 public lastGrantedIndex = 0;
    uint256 public constant GRANT_BATCH_SIZE = 10;

    // Post-TDE multisig addresses.
    address public constant KIN_FOUNDATION_ADDRESS = 0xa8F769B88d6D74FB2Bd3912F6793F75625228baF;
    address public constant KIK_ADDRESS = 0x7a029DC995f87B5cA060975b9A8A1b4bdB33cDC5;

    event TokensIssued(address indexed _to, uint256 _tokens);

    /// @dev Reverts if called when not during sale.
    modifier onlyDuringSale() {
        if (tokensSold >= MAX_TOKENS_SOLD || now < startTime || now >= endTime) {
            revert();
        }

        _;
    }

    /// @dev Reverts if called before sale ends.
    modifier onlyAfterSale() {
        if (!(tokensSold >= MAX_TOKENS_SOLD || now >= endTime)) {
            revert();
        }

        _;
    }

    /// @dev Constructor that initializes the sale conditions.
    /// @param _fundingRecipient address The address of the funding recipient.
    /// @param _startTime uint256 The start time of the token sale.
    function KinTokenSale(address _fundingRecipient, uint256 _startTime) {
        require(_fundingRecipient != address(0));
        require(_startTime > now);

        // Deploy new KinToken contract.
        kin = new KinToken();

        // Deploy new VestingTrustee contract.
        trustee = new VestingTrustee(kin);

        fundingRecipient = _fundingRecipient;
        startTime = _startTime;
        endTime = startTime + SALE_DURATION;

        // Initialize special vesting grants.
        initTokenGrants();
    }

    /// @dev Initialize token grants.
    ///
    // TODO add real values here.
    function initTokenGrants() private onlyOwner {
        // Issue the remaining 60% to Kin Foundation's multisig wallet. A few days, after the token sale is finalized,
        // these tokens will be loaded into the KinVestingTrustee smart contract, according to the white paper. Please
        // note, that this is implied by setting a 0% vesting percent.
        tokenGrantees.push(KIN_FOUNDATION_ADDRESS);
        tokenGrants[KIN_FOUNDATION_ADDRESS] = TokenGrant(60 * 100000000000 * TOKEN_DECIMALS, 0, 0, 3 years, 1 days, 0);

        // Kik, 30%
        tokenGrantees.push(KIK_ADDRESS);
        tokenGrants[KIK_ADDRESS] = TokenGrant(30 * 100000000000 * TOKEN_DECIMALS, 0, 0, 120 weeks, 12 weeks, 100);
    }

    /// @dev Adds a Kin token vesting grant.
    /// @param _grantee address The address of the token grantee. Can be granted only once.
    /// @param _value uint256 The value of the grant.
    function addTokenGrant(address _grantee, uint256 _value) external onlyOwner {
        require(_grantee != address(0));
        require(_value > 0);

        // Verify the grant doesn't already exist.
        require(tokenGrants[_grantee].value == 0);
        for (uint i = 0; i < tokenGrantees.length; i++) {
            require(tokenGrantees[i] != _grantee);
        }

        // Add grant and add to grantee list.
        tokenGrantees.push(_grantee);
        tokenGrants[_grantee] = TokenGrant(_value, 0, 1 years, 1 years, 1 days, 50);
    }

    /// @dev Deletes a Kin token grant.
    /// @param _grantee address The address of the token grantee.
    function deleteTokenGrant(address _grantee) external onlyOwner {
        require(_grantee != address(0));

        // Delete the grant from the keys array.
        for (uint i = 0; i < tokenGrantees.length; i++) {
            if (tokenGrantees[i] == _grantee) {
                delete tokenGrantees[i];

                break;
            }
        }

        // Delete the grant from the mapping.
        delete tokenGrants[_grantee];
    }

    /// @dev Add a list of participants to a capped participation tier.
    /// @param _participants address[] The list of participant addresses.
    /// @param _cap uint256 The cap amount (in ETH).
    function setParticipationCap(address[] _participants, uint256 _cap) private onlyOwner {
        for (uint i = 0; i < _participants.length; i++) {
            participationCaps[_participants[i]] = _cap;
        }
    }

    /// @dev Add a list of participants to cap tier #1.
    /// @param _participants address[] The list of participant addresses.
    function setTier1Participants(address[] _participants) external onlyOwner {
        setParticipationCap(_participants, TIER_1_CAP);
    }

    /// @dev Add a list of participants to tier #2.
    /// @param _participants address[] The list of participant addresses.
    function setTier2Participants(address[] _participants) external onlyOwner {
        setParticipationCap(_participants, TIER_2_CAP);
    }

    /// @dev Set hard participation cap for all participants.
    /// @param _cap uint256 The hard cap amount.
    function setHardParticipationCap(uint256 _cap) external onlyOwner {
        require(_cap > 0);

        hardParticipationCap = _cap;
    }

    /// @dev Fallback function that will delegate the request to create().
    function () external payable onlyDuringSale {
        create(msg.sender);
    }

    /// @dev Create and sell tokens to the caller.
    /// @param _recipient address The address of the recipient receiving the tokens.
    function create(address _recipient) public payable onlyDuringSale {
        require(_recipient != address(0));

        // Enforce participation cap (in Wei received).
        uint256 weiAlreadyParticipated = participationHistory[msg.sender];
        uint256 participationCap = SafeMath.min256(participationCaps[msg.sender], hardParticipationCap);
        uint256 cappedWeiReceived = SafeMath.min256(msg.value, participationCap.sub(weiAlreadyParticipated));
        require(cappedWeiReceived > 0);

        // Accept funds and transfer to funding recipient.
        uint256 weiLeftInSale = MAX_TOKENS_SOLD.sub(tokensSold).div(KIN_PER_WEI);
        uint256 weiToParticipate = SafeMath.min256(cappedWeiReceived, weiLeftInSale);
        participationHistory[msg.sender] = weiAlreadyParticipated.add(weiToParticipate);
        fundingRecipient.transfer(weiToParticipate);

        // Issue tokens and transfer to recipient.
        uint256 tokensLeftInSale = MAX_TOKENS_SOLD.sub(tokensSold);
        uint256 tokensToIssue = weiToParticipate.mul(KIN_PER_WEI);
        if (tokensLeftInSale.sub(tokensToIssue) < KIN_PER_WEI) {
            // If purchase would cause less than KIN_PER_WEI tokens left then nobody could ever buy them.
            // So, gift them to the last buyer.
            tokensToIssue = tokensLeftInSale;
        }
        tokensSold = tokensSold.add(tokensToIssue);
        issueTokens(_recipient, tokensToIssue);

        // Partial refund if full participation not possible
        // e.g. due to cap being reached.
        uint256 refund = msg.value.sub(weiToParticipate);
        if (refund > 0) {
            msg.sender.transfer(refund);
        }
    }

    /// @dev Finalizes the token sale event, by stopping token minting.
    function finalize() external onlyAfterSale onlyOwner {
        if (!kin.isMinting()) {
            revert();
        }

        require(lastGrantedIndex == tokenGrantees.length);

        // Finish minting.
        kin.endMinting();
    }

    /// @dev Grants pre-configured token grants in batches. When the method is called, it'll resume from the last grant,
    /// from its previous run, and will finish either after granting GRANT_BATCH_SIZE grants or finishing the whole list
    /// of grants.
    function grantTokens() external onlyAfterSale onlyOwner {
        uint endIndex = SafeMath.min256(tokenGrantees.length, lastGrantedIndex + GRANT_BATCH_SIZE);
        for (uint i = lastGrantedIndex; i < endIndex; i++) {
            address grantee = tokenGrantees[i];

            // Calculate how many tokens have been granted, vested, and issued
            // such that: granted = vested + issued
            TokenGrant memory tokenGrant = tokenGrants[grantee];
            uint256 tokensGranted = tokenGrant.value.mul(tokensSold).div(MAX_TOKENS_SOLD);
            uint256 tokensVested = tokensGranted.mul(tokenGrant.percentVested).div(100);
            uint256 tokensIssued = tokensGranted.sub(tokensVested);

            // Transfer issued tokens that have yet to be transferred to grantee.
            if (tokensIssued > 0) {
                issueTokens(grantee, tokensIssued);
            }

            // Transfer vested tokens that have yet to be transferred to vesting trustee,
            // and initialize grant.
            if (tokensVested > 0) {
                issueTokens(trustee, tokensVested);
                trustee.grant(grantee, tokensVested, now.add(tokenGrant.startOffset), now.add(tokenGrant.cliffOffset),
                    now.add(tokenGrant.endOffset), tokenGrant.installmentLength, true);
            }

            lastGrantedIndex++;
        }
    }

    /// @dev Issues tokens for the recipient.
    /// @param _recipient address The address of the recipient.
    /// @param _tokens uint256 The amount of tokens to issue.
    function issueTokens(address _recipient, uint256 _tokens) private {
        // Request Kin token contract to mint the requested tokens for the buyer.
        kin.mint(_recipient, _tokens);

        TokensIssued(_recipient, _tokens);
    }

    /// @dev Requests to transfer control of the Kin token contract to a new owner.
    /// @param _newOwnerCandidate address The address to transfer ownership to.
    ///
    /// NOTE:
    ///   1. The new owner will need to call Kin token contract's acceptOwnership directly in order to accept the ownership.
    ///   2. Calling this method during the token sale will prevent the token sale to continue, since only the owner of
    ///      the Kin token contract can issue new tokens.
    function requestKinTokenOwnershipTransfer(address _newOwnerCandidate) external onlyOwner {
        kin.requestOwnershipTransfer(_newOwnerCandidate);
    }

    /// @dev Accepts new ownership on behalf of the Kin token contract.
    // This can be used by the sale contract itself to claim back ownership of the Kin token contract.
    function acceptKinTokenOwnership() external onlyOwner {
        kin.acceptOwnership();
    }

    /// @dev Requests to transfer control of the VestingTrustee contract to a new owner.
    /// @param _newOwnerCandidate address The address to transfer ownership to.
    ///
    /// NOTE:
    ///   1. The new owner will need to call VestingTrustee's acceptOwnership directly in order to accept the ownership.
    ///   2. Calling this method during the token sale will prevent the token sale from finalizaing, since only the owner
    ///      of the VestingTrustee contract can issue new token grants.
    function requestVestingTrusteeOwnershipTransfer(address _newOwnerCandidate) external onlyOwner {
        trustee.requestOwnershipTransfer(_newOwnerCandidate);
    }

    /// @dev Accepts new ownership on behalf of the VestingTrustee contract.
    /// This can be used by the token sale contract itself to claim back ownership of the VestingTrustee contract.
    function acceptVestingTrusteeOwnership() external onlyOwner {
        trustee.acceptOwnership();
    }
}

pragma solidity ^0.4.15;

import './SafeMath.sol';
import './Ownable.sol';
import './TokenHolder.sol';
import './KinToken.sol';
import './VestingTrustee.sol';

/// @title Kin token sale contract.
contract KinTokenSale is Ownable, TokenHolder {
    using SafeMath for uint256;

    // External parties:

    // KIN token contract.
    KinToken public kin;

    // Vesting contract for pre-sale participants.
    VestingTrustee public trustee;

    // Received funds are forwarded to this address.
    address public fundingRecipient;

    // Kin token decimals.
    // Using same decimal value as ETH (makes ETH-KIN conversion much easier).
    // This is the same as in Kin token contract.
    uint256 public constant TOKEN_DECIMALS = 10 ** 18;

    // Maximum number of tokens in circulation: 10 trillion.
    uint256 public constant MAX_TOKENS = 10 ** 13 * TOKEN_DECIMALS;

    // Maximum tokens offered in the sale.
    uint256 public constant MAX_TOKENS_SOLD = 512192121951 * TOKEN_DECIMALS;

    // Wei to 1 USD ratio.
    //
    // TODO update to the real ETH price before sale launch.
    uint256 public constant WEI_PER_USD = uint256(1 ether) / 360;

    // KIN to 1 USD ratio,
    // such MAX_TOKENS_SOLD * KIN_PER_USD is the $75M cap.
    uint256 public constant KIN_PER_USD = 6829 * TOKEN_DECIMALS;

    // KIN to 1 wei ratio.
    uint256 public constant KIN_PER_WEI = KIN_PER_USD / WEI_PER_USD;

    // Sale start, end blocks (time ranges)
    uint256 public constant SALE_DURATION = 14 days;
    uint256 public startTime;
    uint256 public endTime;

    // Amount of tokens sold until now in the sale.
    uint256 public tokensSold = 0;

    // Participation caps, according to KYC tiers.
    uint256 public constant TIER_1_CAP = 100000 * WEI_PER_USD;
    uint256 public constant TIER_2_CAP = uint256(-1); // Maximum uint256 value

    // Accumulated amount each participant have contributed so far.
    mapping (address => uint256) public participationHistory;

    // Maximum amount that each particular is allowed to contribute (in WEI).
    mapping (address => uint256) public participationCaps;

    // Maximum amount ANYBODY is currently allowed to contribute.
    uint256 public hardParticipationCap = 5000 * WEI_PER_USD;

    // Vesting information for special addresses:
    //  - Kin Foundation
    //  - Kik
    struct TokenGrant {
        uint256 value;
        uint256 startOffset;
        uint256 cliffOffset;
        uint256 endOffset;
        uint256 installmentLength;
        uint8 percentVested;
    }

    address[] public tokenGrantees;
    mapping (address => TokenGrant) public tokenGrants;
    uint256 public lastGrantedIndex = 0;
    uint256 public constant GRANT_BATCH_SIZE = 10;

    event TokensIssued(address indexed _to, uint256 _tokens);

    /// @dev Reverts if called when not during sale.
    modifier onlyDuringSale() {
        if (tokensSold >= MAX_TOKENS_SOLD || now < startTime || now >= endTime) {
            revert();
        }

        _;
    }

    /// @dev Reverts if called before sale ends.
    modifier onlyAfterSale() {
        if (!(tokensSold >= MAX_TOKENS_SOLD || now >= endTime)) {
            revert();
        }

        _;
    }

    /// @dev Constructor that initializes the sale conditions.
    /// @param _fundingRecipient address The address of the funding recipient.
    /// @param _startTime uint256 The start time of the token sale.
    function KinTokenSale(address _fundingRecipient, uint256 _startTime) {
        require(_fundingRecipient != address(0));
        require(_startTime > now);

        // Deploy new KinToken contract.
        kin = new KinToken();

        // Deploy new VestingTrustee contract.
        trustee = new VestingTrustee(kin);

        fundingRecipient = _fundingRecipient;
        startTime = _startTime;
        endTime = startTime + SALE_DURATION;

        // Initialize special vesting grants.
        initTokenGrants();
    }

    /// @dev Initialize token grants.
    ///
    // TODO add real values here.
    function initTokenGrants() private onlyOwner {
        // Issue the remaining 60% to Kin Foundation's multisig wallet. A few days, after the token sale is finalized,
        // these tokens will be loaded into the KinVestingTrustee smart contract, according to the white paper. Please
        // note, that this is implied by setting a 0% vesting percent.
        tokenGrantees.push(0xa8F769B88d6D74FB2Bd3912F6793F75625228baF);
        tokenGrants[0xa8F769B88d6D74FB2Bd3912F6793F75625228baF] = TokenGrant(60 * 100000000000 * TOKEN_DECIMALS, 0, 0,
            3 years, 1 days, 0);

        // Kik, 30%
        tokenGrantees.push(0x7a029DC995f87B5cA060975b9A8A1b4bdB33cDC5);
        tokenGrants[0x7a029DC995f87B5cA060975b9A8A1b4bdB33cDC5] = TokenGrant(30 * 100000000000 * TOKEN_DECIMALS, 0, 0,
            120 weeks, 12 weeks, 100);
    }

    /// @dev Adds a Kin token vesting grant.
    /// @param _grantee address The address of the token grantee. Can be granted only once.
    /// @param _value uint256 The value of the grant.
    function addTokenGrant(address _grantee, uint256 _value) external onlyOwner {
        require(_grantee != address(0));
        require(_value > 0);

        // Verify the grant doesn't already exist.
        require(tokenGrants[_grantee].value == 0);
        for (uint i = 0; i < tokenGrantees.length; i++) {
            require(tokenGrantees[i] != _grantee);
        }

        // Add grant and add to grantee list.
        tokenGrantees.push(_grantee);
        tokenGrants[_grantee] = TokenGrant(_value, 0, 1 years, 1 years, 1 days, 50);
    }

    /// @dev Deletes a Kin token grant.
    /// @param _grantee address The address of the token grantee.
    function deleteTokenGrant(address _grantee) external onlyOwner {
        require(_grantee != address(0));

        // Delete the grant from the keys array.
        for (uint i = 0; i < tokenGrantees.length; i++) {
            if (tokenGrantees[i] == _grantee) {
                delete tokenGrantees[i];

                break;
            }
        }

        // Delete the grant from the mapping.
        delete tokenGrants[_grantee];
    }

    /// @dev Add a list of participants to a capped participation tier.
    /// @param _participants address[] The list of participant addresses.
    /// @param _cap uint256 The cap amount (in ETH).
    function setParticipationCap(address[] _participants, uint256 _cap) private onlyOwner {
        for (uint i = 0; i < _participants.length; i++) {
            participationCaps[_participants[i]] = _cap;
        }
    }

    /// @dev Add a list of participants to cap tier #1.
    /// @param _participants address[] The list of participant addresses.
    function setTier1Participants(address[] _participants) external onlyOwner {
        setParticipationCap(_participants, TIER_1_CAP);
    }

    /// @dev Add a list of participants to tier #2.
    /// @param _participants address[] The list of participant addresses.
    function setTier2Participants(address[] _participants) external onlyOwner {
        setParticipationCap(_participants, TIER_2_CAP);
    }

    /// @dev Set hard participation cap for all participants.
    /// @param _cap uint256 The hard cap amount.
    function setHardParticipationCap(uint256 _cap) external onlyOwner {
        require(_cap > 0);

        hardParticipationCap = _cap;
    }

    /// @dev Fallback function that will delegate the request to create().
    function () external payable onlyDuringSale {
        create(msg.sender);
    }

    /// @dev Create and sell tokens to the caller.
    /// @param _recipient address The address of the recipient receiving the tokens.
    function create(address _recipient) public payable onlyDuringSale {
        require(_recipient != address(0));

        // Enforce participation cap (in Wei received).
        uint256 weiAlreadyParticipated = participationHistory[msg.sender];
        uint256 participationCap = SafeMath.min256(participationCaps[msg.sender], hardParticipationCap);
        uint256 cappedWeiReceived = SafeMath.min256(msg.value, participationCap.sub(weiAlreadyParticipated));
        require(cappedWeiReceived > 0);

        // Accept funds and transfer to funding recipient.
        uint256 weiLeftInSale = MAX_TOKENS_SOLD.sub(tokensSold).div(KIN_PER_WEI);
        uint256 weiToParticipate = SafeMath.min256(cappedWeiReceived, weiLeftInSale);
        participationHistory[msg.sender] = weiAlreadyParticipated.add(weiToParticipate);
        fundingRecipient.transfer(weiToParticipate);

        // Issue tokens and transfer to recipient.
        uint256 tokensLeftInSale = MAX_TOKENS_SOLD.sub(tokensSold);
        uint256 tokensToIssue = weiToParticipate.mul(KIN_PER_WEI);
        if (tokensLeftInSale.sub(tokensToIssue) < KIN_PER_WEI) {
            // If purchase would cause less than KIN_PER_WEI tokens left then nobody could ever buy them.
            // So, gift them to the last buyer.
            tokensToIssue = tokensLeftInSale;
        }
        tokensSold = tokensSold.add(tokensToIssue);
        issueTokens(_recipient, tokensToIssue);

        // Partial refund if full participation not possible
        // e.g. due to cap being reached.
        uint256 refund = msg.value.sub(weiToParticipate);
        if (refund > 0) {
            msg.sender.transfer(refund);
        }
    }

    /// @dev Finalizes the token sale event, by stopping token minting.
    function finalize() external onlyAfterSale onlyOwner {
        if (!kin.isMinting()) {
            revert();
        }

        require(lastGrantedIndex == tokenGrantees.length);

        // Finish minting.
        kin.endMinting();
    }

    /// @dev Grants pre-configured token grants in batches. When the method is called, it'll resume from the last grant,
    /// from its previous run, and will finish either after granting GRANT_BATCH_SIZE grants or finishing the whole list
    /// of grants.
    function grantTokens() external onlyAfterSale onlyOwner {
        uint endIndex = SafeMath.min256(tokenGrantees.length, lastGrantedIndex + GRANT_BATCH_SIZE);
        for (uint i = lastGrantedIndex; i < endIndex; i++) {
            address grantee = tokenGrantees[i];

            // Calculate how many tokens have been granted, vested, and issued
            // such that: granted = vested + issued
            TokenGrant memory tokenGrant = tokenGrants[grantee];
            uint256 tokensGranted = tokenGrant.value.mul(tokensSold).div(MAX_TOKENS_SOLD);
            uint256 tokensVested = tokensGranted.mul(tokenGrant.percentVested).div(100);
            uint256 tokensIssued = tokensGranted.sub(tokensVested);

            // Transfer issued tokens that have yet to be transferred to grantee.
            if (tokensIssued > 0) {
                issueTokens(grantee, tokensIssued);
            }

            // Transfer vested tokens that have yet to be transferred to vesting trustee,
            // and initialize grant.
            if (tokensVested > 0) {
                issueTokens(trustee, tokensVested);
                trustee.grant(grantee, tokensVested, now.add(tokenGrant.startOffset), now.add(tokenGrant.cliffOffset),
                    now.add(tokenGrant.endOffset), tokenGrant.installmentLength, true);
            }

            lastGrantedIndex++;
        }
    }

    /// @dev Issues tokens for the recipient.
    /// @param _recipient address The address of the recipient.
    /// @param _tokens uint256 The amount of tokens to issue.
    function issueTokens(address _recipient, uint256 _tokens) private {
        // Request Kin token contract to mint the requested tokens for the buyer.
        kin.mint(_recipient, _tokens);

        TokensIssued(_recipient, _tokens);
    }

    /// @dev Requests to transfer control of the Kin token contract to a new owner.
    /// @param _newOwnerCandidate address The address to transfer ownership to.
    ///
    /// NOTE:
    ///   1. The new owner will need to call Kin token contract's acceptOwnership directly in order to accept the ownership.
    ///   2. Calling this method during the token sale will prevent the token sale to continue, since only the owner of
    ///      the Kin token contract can issue new tokens.
    function requestKinTokenOwnershipTransfer(address _newOwnerCandidate) external onlyOwner {
        kin.requestOwnershipTransfer(_newOwnerCandidate);
    }

    /// @dev Accepts new ownership on behalf of the Kin token contract.
    // This can be used by the sale contract itself to claim back ownership of the Kin token contract.
    function acceptKinTokenOwnership() external onlyOwner {
        kin.acceptOwnership();
    }

    /// @dev Requests to transfer control of the VestingTrustee contract to a new owner.
    /// @param _newOwnerCandidate address The address to transfer ownership to.
    ///
    /// NOTE:
    ///   1. The new owner will need to call VestingTrustee's acceptOwnership directly in order to accept the ownership.
    ///   2. Calling this method during the token sale will prevent the token sale from finalizaing, since only the owner
    ///      of the VestingTrustee contract can issue new token grants.
    function requestVestingTrusteeOwnershipTransfer(address _newOwnerCandidate) external onlyOwner {
        trustee.requestOwnershipTransfer(_newOwnerCandidate);
    }

    /// @dev Accepts new ownership on behalf of the VestingTrustee contract.
    /// This can be used by the token sale contract itself to claim back ownership of the VestingTrustee contract.
    function acceptVestingTrusteeOwnership() external onlyOwner {
        trustee.acceptOwnership();
    }
}