improved inline comment about the solidity decoder

pragma solidity ^0.4.0;

import "./Token.sol";

library NettingChannelLibrary {
    struct Lock
    {
        uint64 expiration;
        uint amount;
        bytes32 hashlock;
    }

    struct Participant
    {
        address node_address;
        uint256 balance;
        uint256 netted;
        uint256 transferred_amount;
        uint64 nonce;
        bytes32 locksroot;
        Lock[] unlocked;
    }

    struct Data {
        uint settle_timeout;
        uint opened;
        uint closed;
        uint settled;
        address closing_address;
        Token token;
        Participant[2] participants;
        mapping(address => uint8) participant_index;
        mapping(bytes32 => bool) locks;
        bool updated;
    }

    modifier notSettledButClosed(Data storage self) {
        if (self.settled > 0 || self.closed == 0)
            throw;
        _;
    }

    modifier stillTimeout(Data storage self) {
        if (self.closed + self.settle_timeout < block.number)
            throw;
        _;
    }

    modifier timeoutOver(Data storage self) {
        if (self.closed + self.settle_timeout > block.number)
            throw;
        _;
    }

    modifier isCounterParty(Data storage self, address caller) {
        if (caller == self.closing_address) {
            throw;
        }
        address participant0 = self.participants[0].node_address;
        address participant1 = self.participants[1].node_address;
        if (caller != participant0 && caller != participant1) {
            throw;
        }
        _;
    }

    modifier inNonceRange(Data storage self, bytes message) {
        uint64 nonce;
        nonce = getNonce(message);
        if (nonce < self.opened * (2 ** 32) || nonce >= (self.opened + 1) * (2 ** 32))
            throw;
        _;
    }

    modifier channelSettled(Data storage self) {
        if (self.settled == 0)
            throw;
        _;
    }

    modifier notYetUpdated(Data storage self) {
        if (self.updated)
            throw;
        _;
    }

    /// @notice Deposit amount to channel.
    /// @dev Deposit an amount to the channel. At least one of the participants
    /// must deposit before the channel is opened.
    /// @param caller_address The address of the invoker of the function
    /// @param channel_address The address of the channel
    /// @param amount The amount to be deposited to the address
    /// @return Success if the transfer was successful
    /// @return The new balance of the invoker
    function deposit(
        Data storage self,
        address caller_address,
        address channel_address,
        uint256 amount)
        returns (bool success, uint256 balance)
    {

        if (self.closed != 0) {
            throw;
        }

        if (self.token.balanceOf(caller_address) < amount) {
            throw;
        }

        uint8 index = index_or_throw(self, caller_address);

        Participant storage participant = self.participants[index];

        success = self.token.transferFrom(
            caller_address,
            channel_address,
            amount
        );

        if (success == true) {
            balance = participant.balance;
            balance += amount;
            participant.balance = balance;

            if (self.opened == 0) {
                self.opened = block.number;
            }

            return (true, balance);
        }

        return (false, 0);
    }

    /// @notice Get the partner or other participant of the channel
    /// @dev Get the other participating party of the channel
    /// @return The partner of the calling party
    function partner(Data storage self, address one_address) constant returns (address) {
        Participant[2] storage participants = self.participants;
        Participant storage node1 = participants[0];
        Participant storage node2 = participants[1];

        if (one_address == node1.node_address) {
            return node2.node_address;
        }

        if (one_address == node2.node_address) {
            return node1.node_address;
        }

        return 0x0;
    }

    function transferredAmount(Data storage self, address participant_address)
        constant
        returns (uint)
    {
         uint8 index = index_or_throw(self, participant_address);
         Participant storage participant = self.participants[index];
         return participant.transferred_amount;
    }

    function addressAndBalance(Data storage self)
        constant
        returns(
        address participant1,
        uint balance1,
        address participant2,
        uint balance2)
    {
        Participant[2] participants = self.participants;
        Participant node1 = participants[0];
        Participant node2 = participants[1];

        // return by name
        participant1 = node1.node_address;
        balance1 = node1.balance;
        participant2 = node2.node_address;
        balance2 = node2.balance;
    }

    /// @notice Close a channel between two parties that was used bidirectionally
    /// @param caller_address The address of the participant closing the channel
    /// @param their_transfer The latest known transfer of the other participant
    ///                       to the channel. Can also be empty, in which case
    ///                       we are attempting to close a channel without any
    ///                       transfers.
    function close(
        Data storage self,
        address caller_address,
        bytes their_transfer)
    {
        uint closer_index;
        uint counterparty_index;
        bytes memory transfer_raw;
        uint64 nonce;
        address transfer_address;

        // Already closed
        if (self.closed > 0) {
            throw;
        }

        // Only a participant can call close
        closer_index = index_or_throw(self, caller_address);

        self.closing_address = caller_address;
        self.closed = block.number;

        // Only the closing party can provide a transfer from the counterparty,
        // and only when this function is called, i.e. this value can not be
        // updated afterwards.

        // An empty value means that the closer never received a transfer, or
        // he is intentionally not providing the latest transfer, in which case
        // the closing party is going to lose the tokens that were transferred
        // to him.
        if (their_transfer.length != 0) {

            // only accept messages with a valid nonce
            nonce = getNonce(their_transfer);
            if (nonce < self.opened * (2 ** 32) || nonce >= (self.opened + 1) * (2 ** 32)) {
                throw;
            }

            (transfer_raw, transfer_address) = getTransferRawAddress(their_transfer);
            counterparty_index = index_or_throw(self, transfer_address);

            // only a message from the counter party is valid
            if (closer_index == counterparty_index) {
                throw;
            }

            // update the structure of the counterparty with its data provided
            // by the closing node
            Participant storage counterparty = self.participants[counterparty_index];
            decodeAndAssign(counterparty, transfer_raw);
        }

    }

    function processTransfer(Data storage self, Participant storage node1, Participant storage node2, bytes transfer)
        inNonceRange(self, transfer)
        internal
        returns (address)
    {
        bytes memory transfer_raw;
        address transfer_address;

        if (transfer.length <= 65) {
            throw;
        }

        (transfer_raw, transfer_address) = getTransferRawAddress(transfer);
        if (node1.node_address == transfer_address) {
            Participant storage sender = node1;
        } else if (node2.node_address == transfer_address) {
            sender = node2;
        } else {
            throw;
        }

        decodeAndAssign(sender, transfer_raw);

        return sender.node_address;
    }

    /// @notice Updates (disputes) the state after closing.
    /// @param caller_address The counterparty to the channel. The participant
    ///                       that did not close the channel.
    /// @param their_transfer The transfer the counterparty believes is the
    ///                        valid state for the first participant.
    function updateTransfer(
        Data storage self,
        address caller_address,
        bytes their_transfer
    )
        notSettledButClosed(self)
        stillTimeout(self)
        isCounterParty(self, caller_address)
        notYetUpdated(self)
    {
        Participant[2] storage participants = self.participants;
        Participant storage node1 = participants[0];
        Participant storage node2 = participants[1];

        processTransfer(self, node1, node2, their_transfer);
        self.updated = true;
    }

    /// @notice Unlock a locked transfer
    /// @dev Unlock a locked transfer
    /// @param caller_address The calling address
    /// @param locked_encoded The lock
    /// @param merkle_proof The merkle proof
    /// @param secret The secret
    function unlock(
        Data storage self,
        address caller_address,
        bytes locked_encoded,
        bytes merkle_proof,
        bytes32 secret)
        notSettledButClosed(self)
    {
        uint amount;
        uint partner_id;
        uint64 expiration;
        bytes32 el;
        bytes32 h;
        bytes32 hashlock;

        (expiration, amount, hashlock) = decodeLock(locked_encoded);

        if (self.locks[hashlock]) {
            throw;
        }

        if (expiration < block.number) {
            throw;
        }

        if (hashlock != sha3(secret)) {
            throw;
        }

        //Check if caller_address is a participant and select her partner
        uint8 index = 1 - index_or_throw(self, caller_address);

        Participant storage counterparty = self.participants[index];
        if (counterparty.nonce == 0) {
            throw;
        }

        h = computeMerkleRoot(locked_encoded, merkle_proof);

        if (counterparty.locksroot != h) {
            throw;
        }

        counterparty.unlocked.push(Lock(expiration, amount, hashlock));
        self.locks[hashlock] = true;
    }

    function computeMerkleRoot(bytes lock, bytes merkle_proof)
        private
        constant
        returns (bytes32)
    {
        if (merkle_proof.length % 32 != 0) {
            throw;
        }

        uint i;
        bytes32 h;
        bytes32 el;

        h = sha3(lock);
        for (i = 32; i <= merkle_proof.length; i += 32) {
            assembly {
                el := mload(add(merkle_proof, i))
            }

            if (h < el) {
                h = sha3(h, el);
            } else {
                h = sha3(el, h);
            }
        }

        return h;
    }

    /// @notice Settles the balance between the two parties
    /// @dev Settles the balances of the two parties fo the channel
    /// @return The participants with netted balances
    function settle(Data storage self, address caller_address)
        notSettledButClosed(self)
        timeoutOver(self)
    {
        uint total_deposit;
        uint k;

        Participant[2] storage participants = self.participants;
        Participant storage node1 = participants[0];
        Participant storage node2 = participants[1];

        node1.netted = node1.balance + node2.transferred_amount - node1.transferred_amount;
        node2.netted = node2.balance + node1.transferred_amount - node2.transferred_amount;

        for (k = 0; k < node1.unlocked.length; k++) {
            node1.netted -= node1.unlocked[k].amount;
            node2.netted += node1.unlocked[k].amount;
        }

        for (k = 0; k < node2.unlocked.length; k++) {
            node2.netted -= node2.unlocked[k].amount;
            node1.netted += node2.unlocked[k].amount;
        }

        self.settled = block.number;
        total_deposit = node1.balance + node2.balance;

        Participant memory closing_party;
        Participant memory other_party;

        if (node1.node_address == self.closing_address) {
            closing_party = node1;
            other_party = node2;
        } else {
            closing_party = node2;
            other_party = node1;
        }

        // first pay out to the party that did not close the channel
        uint amount = total_deposit < other_party.netted
            ? total_deposit
            : other_party.netted;
        if (amount > 0) {
            if (!self.token.transfer(other_party.node_address, amount)) {
                throw;
            }
        }
        // then payout whatever can be paid out to the closing party
        amount = total_deposit - other_party.netted;
        if (amount > 0) {
            if (!self.token.transfer(closing_party.node_address, amount)) {
                throw;
            }
        }

        kill(self);
    }

    function getTransferRawAddress(bytes memory signed_transfer) private returns (bytes memory, address) {
        uint signature_start;
        uint length;
        bytes memory signature;
        bytes memory transfer_raw;
        bytes32 transfer_hash;
        address transfer_address;

        length = signed_transfer.length;
        signature_start = length - 65;
        signature = slice(signed_transfer, signature_start, length);
        transfer_raw = slice(signed_transfer, 0, signature_start);

        transfer_hash = sha3(transfer_raw);
        var (r, s, v) = signatureSplit(signature);
        transfer_address = ecrecover(transfer_hash, v, r, s);

        return (transfer_raw, transfer_address);
    }

    function decodeAndAssign(Participant storage sender, bytes transfer_raw) private {
        // all checks must be done by now
        uint cmdid;

        cmdid = uint(transfer_raw[0]);

        if (cmdid == 5) {
            assignDirectTransfer(sender, transfer_raw);
        } else if (cmdid == 7) {
            assignMediatedTransfer(sender, transfer_raw);
        } else if (cmdid == 8) {
            assignRefundTransfer(sender, transfer_raw);
        } else {
            throw;
        }
    }

    // NOTES:
    //
    // - The EVM is a big-endian, byte addressing machine, with 32bytes/256bits
    //   words.
    // - The Ethereum Contract ABI specifies that variable length types have a
    //   32bytes prefix to define the variable size.
    // - Solidity has additional data types that are narrower than 32bytes
    //   (e.g. uint128 uses a half word).
    // - Solidity uses the *least-significant* bits of the word to store the
    //   values of a narrower type.
    //
    // GENERAL APPROACH:
    //
    // Add to the message pointer the number of bytes required to move the
    // address so that the target data is at the end of the 32bytes word.
    //
    // EXAMPLE:
    //
    // To decode the cmdid, consider this initial state:
    //
    //
    //     v- pointer word start
    //     [ 32 bytes length prefix ][ cmdid ] ----
    //                              ^- pointer word end
    //
    //
    // Because the cmdid has 1 byte length the type uint8 is used, the decoder
    // needs to move the pointer so the cmdid is at the end of the pointer
    // word.
    //
    //
    //             v- pointer word start [moved 1byte ahead]
    //     [ 32 bytes length prefix ][ cmdid ] ----
    //                                       ^- pointer word end
    //
    //
    // Now the data of the cmdid can be loaded to the uint8 variable.
    //
    // REFERENCES:
    // - https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI
    // - http://solidity.readthedocs.io/en/develop/assembly.html

    // TODO: use sstore instead of these temporaries

    function assignDirectTransfer(Participant storage participant, bytes memory message) private {
        if (message.length != 124) { // size of the raw message without the signature
            throw;
        }

        uint64 nonce;
        uint256 transferred_amount;
        bytes32 locksroot;

        assembly {
                                                          // [0:1] cmdid
                                                          // [1:4] pad
            nonce := mload(add(message, 12))              // [4:12] nonce
                                                          // [12:20] identifier
                                                          // [20:40] token
                                                          // [40:60] recipient
            transferred_amount := mload(add(message, 92)) // [60:92] transferred_amount
            locksroot := mload(add(message, 124))         // [92:124] optional_locksroot
        }

        participant.nonce = nonce;
        participant.transferred_amount = transferred_amount;
        participant.locksroot = locksroot;
    }

    function assignMediatedTransfer(Participant storage participant, bytes memory message) private {
        if (message.length != 268) { // size of the raw message without the signature
            throw;
        }

        uint64 nonce;
        bytes32 locksroot;
        uint256 transferred_amount;
        uint256 lock_amount;

        assembly {
                                                           // [0:1] cmdid
                                                           // [1:4] pad
            nonce := mload(add(message, 12))               // [4:12] nonce
                                                           // [12:20] identifier
                                                           // [20:28] expiration
                                                           // [28:48] token
                                                           // [48:68] recipient
                                                           // [68:88] target
                                                           // [88:108] initiator
            locksroot := mload(add(message, 140))          // [108:140] locksroot
                                                           // [140:172] hashlock
            transferred_amount := mload(add(message, 204)) // [172:204] transferred_amoun
                                                           // [204:236] amount
                                                           // [236:268] fee
        }

        participant.nonce = nonce;
        participant.locksroot = locksroot;
        participant.transferred_amount = transferred_amount;
    }

    function assignRefundTransfer(Participant storage participant, bytes memory message) private {
        if (message.length != 196) { // size of the raw message without the signature
            throw;
        }

        uint64 nonce;
        bytes32 locksroot;
        uint256 transferred_amount;
        uint256 lock_amount;

        assembly {
                                                            // [0:1] cmdid
                                                            // [1:4] pad
            nonce := mload(add(message, 12))                // [4:12] nonce
                                                            // [12:20] identifier
                                                            // [20:28] expiration
                                                            // [28:48] token
                                                            // [48:68] recipient
            locksroot := mload(add(message, 100))           // [68:100] locksroot
            transferred_amount := mload(add(message, 132))  // [100:132] transferred_amount
                                                            // [132:164] amount
                                                            // [164:196] hashlock
        }

        participant.nonce = nonce;
        participant.locksroot = locksroot;
        participant.transferred_amount = transferred_amount;
    }

    function decodeLock(bytes lock) private returns (uint64 expiration, uint amount, bytes32 hashlock) {
        if (lock.length != 72) {
            throw;
        }

        assembly {
            expiration := mload(add(lock, 8))   // [0:8] expiration
            amount := mload(add(lock, 40))      // [8:40] amont
            hashlock := mload(add(lock, 72))    // [40:72] hashlock

        }
    }

    // Get nonce from a message
    function getNonce(bytes message) private returns (uint64 nonce) {
        // don't care about length of message since nonce is always at a fixed position
        assembly {
            nonce := mload(add(message, 12))
        }
    }

    function signatureSplit(bytes signature) private returns (bytes32 r, bytes32 s, uint8 v) {
        // The signature format is a compact form of:
        //   {bytes32 r}{bytes32 s}{uint8 v}
        // Compact means, uint8 is not padded to 32 bytes.
        assembly {
            r := mload(add(signature, 32))
            s := mload(add(signature, 64))
            // Here we are loading the last 32 bytes, including 31 bytes
            // of 's'. There is no 'mload8' to do this.
            //
            // 'byte' is not working due to the Solidity parser, so lets
            // use the second best option, 'and'
            v := and(mload(add(signature, 65)), 1)
        }
        // old geth sends a `v` value of [0,1], while the new, in line with the YP sends [27,28]
        if(v < 27) v += 27;
    }

    function slice(bytes a, uint start, uint end) private returns (bytes n) {
        if (a.length < end) {
            throw;
        }
        if (start < 0) {
            throw;
        }

        n = new bytes(end - start);
        for (uint i = start; i < end; i++) { //python style slice
            n[i - start] = a[i];
        }
    }

    function index_or_throw(Data storage self, address caller_address) private returns (uint8) {
        uint8 n;
        // Return index of participant, or throw
        n = self.participant_index[caller_address];
        if (n == 0) {
            throw;
        }
        return n - 1;
    }

    function kill(Data storage self) channelSettled(self) {
        selfdestruct(0x00000000000000000000);
    }
}

pragma solidity ^0.4.0;

import "./Token.sol";

library NettingChannelLibrary {
    struct Lock
    {
        uint64 expiration;
        uint amount;
        bytes32 hashlock;
    }

    struct Participant
    {
        address node_address;
        uint256 balance;
        uint256 netted;
        uint256 transferred_amount;
        uint64 nonce;
        bytes32 locksroot;
        Lock[] unlocked;
    }

    struct Data {
        uint settle_timeout;
        uint opened;
        uint closed;
        uint settled;
        address closing_address;
        Token token;
        Participant[2] participants;
        mapping(address => uint8) participant_index;
        mapping(bytes32 => bool) locks;
        bool updated;
    }

    modifier notSettledButClosed(Data storage self) {
        if (self.settled > 0 || self.closed == 0)
            throw;
        _;
    }

    modifier stillTimeout(Data storage self) {
        if (self.closed + self.settle_timeout < block.number)
            throw;
        _;
    }

    modifier timeoutOver(Data storage self) {
        if (self.closed + self.settle_timeout > block.number)
            throw;
        _;
    }

    modifier isCounterParty(Data storage self, address caller) {
        if (caller == self.closing_address) {
            throw;
        }
        address participant0 = self.participants[0].node_address;
        address participant1 = self.participants[1].node_address;
        if (caller != participant0 && caller != participant1) {
            throw;
        }
        _;
    }

    modifier inNonceRange(Data storage self, bytes message) {
        uint64 nonce;
        nonce = getNonce(message);
        if (nonce < self.opened * (2 ** 32) || nonce >= (self.opened + 1) * (2 ** 32))
            throw;
        _;
    }

    modifier channelSettled(Data storage self) {
        if (self.settled == 0)
            throw;
        _;
    }

    modifier notYetUpdated(Data storage self) {
        if (self.updated)
            throw;
        _;
    }

    /// @notice Deposit amount to channel.
    /// @dev Deposit an amount to the channel. At least one of the participants
    /// must deposit before the channel is opened.
    /// @param caller_address The address of the invoker of the function
    /// @param channel_address The address of the channel
    /// @param amount The amount to be deposited to the address
    /// @return Success if the transfer was successful
    /// @return The new balance of the invoker
    function deposit(
        Data storage self,
        address caller_address,
        address channel_address,
        uint256 amount)
        returns (bool success, uint256 balance)
    {

        if (self.closed != 0) {
            throw;
        }

        if (self.token.balanceOf(caller_address) < amount) {
            throw;
        }

        uint8 index = index_or_throw(self, caller_address);

        Participant storage participant = self.participants[index];

        success = self.token.transferFrom(
            caller_address,
            channel_address,
            amount
        );

        if (success == true) {
            balance = participant.balance;
            balance += amount;
            participant.balance = balance;

            if (self.opened == 0) {
                self.opened = block.number;
            }

            return (true, balance);
        }

        return (false, 0);
    }

    /// @notice Get the partner or other participant of the channel
    /// @dev Get the other participating party of the channel
    /// @return The partner of the calling party
    function partner(Data storage self, address one_address) constant returns (address) {
        Participant[2] storage participants = self.participants;
        Participant storage node1 = participants[0];
        Participant storage node2 = participants[1];

        if (one_address == node1.node_address) {
            return node2.node_address;
        }

        if (one_address == node2.node_address) {
            return node1.node_address;
        }

        return 0x0;
    }

    function transferredAmount(Data storage self, address participant_address)
        constant
        returns (uint)
    {
         uint8 index = index_or_throw(self, participant_address);
         Participant storage participant = self.participants[index];
         return participant.transferred_amount;
    }

    function addressAndBalance(Data storage self)
        constant
        returns(
        address participant1,
        uint balance1,
        address participant2,
        uint balance2)
    {
        Participant[2] participants = self.participants;
        Participant node1 = participants[0];
        Participant node2 = participants[1];

        // return by name
        participant1 = node1.node_address;
        balance1 = node1.balance;
        participant2 = node2.node_address;
        balance2 = node2.balance;
    }

    /// @notice Close a channel between two parties that was used bidirectionally
    /// @param caller_address The address of the participant closing the channel
    /// @param their_transfer The latest known transfer of the other participant
    ///                       to the channel. Can also be empty, in which case
    ///                       we are attempting to close a channel without any
    ///                       transfers.
    function close(
        Data storage self,
        address caller_address,
        bytes their_transfer)
    {
        uint closer_index;
        uint counterparty_index;
        bytes memory transfer_raw;
        uint64 nonce;
        address transfer_address;

        // Already closed
        if (self.closed > 0) {
            throw;
        }

        // Only a participant can call close
        closer_index = index_or_throw(self, caller_address);

        self.closing_address = caller_address;
        self.closed = block.number;

        // Only the closing party can provide a transfer from the counterparty,
        // and only when this function is called, i.e. this value can not be
        // updated afterwards.

        // An empty value means that the closer never received a transfer, or
        // he is intentionally not providing the latest transfer, in which case
        // the closing party is going to lose the tokens that were transferred
        // to him.
        if (their_transfer.length != 0) {

            // only accept messages with a valid nonce
            nonce = getNonce(their_transfer);
            if (nonce < self.opened * (2 ** 32) || nonce >= (self.opened + 1) * (2 ** 32)) {
                throw;
            }

            (transfer_raw, transfer_address) = getTransferRawAddress(their_transfer);
            counterparty_index = index_or_throw(self, transfer_address);

            // only a message from the counter party is valid
            if (closer_index == counterparty_index) {
                throw;
            }

            // update the structure of the counterparty with its data provided
            // by the closing node
            Participant storage counterparty = self.participants[counterparty_index];
            decodeAndAssign(counterparty, transfer_raw);
        }

    }

    function processTransfer(Data storage self, Participant storage node1, Participant storage node2, bytes transfer)
        inNonceRange(self, transfer)
        internal
        returns (address)
    {
        bytes memory transfer_raw;
        address transfer_address;

        if (transfer.length <= 65) {
            throw;
        }

        (transfer_raw, transfer_address) = getTransferRawAddress(transfer);
        if (node1.node_address == transfer_address) {
            Participant storage sender = node1;
        } else if (node2.node_address == transfer_address) {
            sender = node2;
        } else {
            throw;
        }

        decodeAndAssign(sender, transfer_raw);

        return sender.node_address;
    }

    /// @notice Updates (disputes) the state after closing.
    /// @param caller_address The counterparty to the channel. The participant
    ///                       that did not close the channel.
    /// @param their_transfer The transfer the counterparty believes is the
    ///                        valid state for the first participant.
    function updateTransfer(
        Data storage self,
        address caller_address,
        bytes their_transfer
    )
        notSettledButClosed(self)
        stillTimeout(self)
        isCounterParty(self, caller_address)
        notYetUpdated(self)
    {
        Participant[2] storage participants = self.participants;
        Participant storage node1 = participants[0];
        Participant storage node2 = participants[1];

        processTransfer(self, node1, node2, their_transfer);
        self.updated = true;
    }

    /// @notice Unlock a locked transfer
    /// @dev Unlock a locked transfer
    /// @param caller_address The calling address
    /// @param locked_encoded The lock
    /// @param merkle_proof The merkle proof
    /// @param secret The secret
    function unlock(
        Data storage self,
        address caller_address,
        bytes locked_encoded,
        bytes merkle_proof,
        bytes32 secret)
        notSettledButClosed(self)
    {
        uint amount;
        uint partner_id;
        uint64 expiration;
        bytes32 el;
        bytes32 h;
        bytes32 hashlock;

        (expiration, amount, hashlock) = decodeLock(locked_encoded);

        if (self.locks[hashlock]) {
            throw;
        }

        if (expiration < block.number) {
            throw;
        }

        if (hashlock != sha3(secret)) {
            throw;
        }

        //Check if caller_address is a participant and select her partner
        uint8 index = 1 - index_or_throw(self, caller_address);

        Participant storage counterparty = self.participants[index];
        if (counterparty.nonce == 0) {
            throw;
        }

        h = computeMerkleRoot(locked_encoded, merkle_proof);

        if (counterparty.locksroot != h) {
            throw;
        }

        counterparty.unlocked.push(Lock(expiration, amount, hashlock));
        self.locks[hashlock] = true;
    }

    function computeMerkleRoot(bytes lock, bytes merkle_proof)
        private
        constant
        returns (bytes32)
    {
        if (merkle_proof.length % 32 != 0) {
            throw;
        }

        uint i;
        bytes32 h;
        bytes32 el;

        h = sha3(lock);
        for (i = 32; i <= merkle_proof.length; i += 32) {
            assembly {
                el := mload(add(merkle_proof, i))
            }

            if (h < el) {
                h = sha3(h, el);
            } else {
                h = sha3(el, h);
            }
        }

        return h;
    }

    /// @notice Settles the balance between the two parties
    /// @dev Settles the balances of the two parties fo the channel
    /// @return The participants with netted balances
    function settle(Data storage self, address caller_address)
        notSettledButClosed(self)
        timeoutOver(self)
    {
        uint total_deposit;
        uint k;

        Participant[2] storage participants = self.participants;
        Participant storage node1 = participants[0];
        Participant storage node2 = participants[1];

        node1.netted = node1.balance + node2.transferred_amount - node1.transferred_amount;
        node2.netted = node2.balance + node1.transferred_amount - node2.transferred_amount;

        for (k = 0; k < node1.unlocked.length; k++) {
            node1.netted -= node1.unlocked[k].amount;
            node2.netted += node1.unlocked[k].amount;
        }

        for (k = 0; k < node2.unlocked.length; k++) {
            node2.netted -= node2.unlocked[k].amount;
            node1.netted += node2.unlocked[k].amount;
        }

        self.settled = block.number;
        total_deposit = node1.balance + node2.balance;

        Participant memory closing_party;
        Participant memory other_party;

        if (node1.node_address == self.closing_address) {
            closing_party = node1;
            other_party = node2;
        } else {
            closing_party = node2;
            other_party = node1;
        }

        // first pay out to the party that did not close the channel
        uint amount = total_deposit < other_party.netted
            ? total_deposit
            : other_party.netted;
        if (amount > 0) {
            if (!self.token.transfer(other_party.node_address, amount)) {
                throw;
            }
        }
        // then payout whatever can be paid out to the closing party
        amount = total_deposit - other_party.netted;
        if (amount > 0) {
            if (!self.token.transfer(closing_party.node_address, amount)) {
                throw;
            }
        }

        kill(self);
    }

    function getTransferRawAddress(bytes memory signed_transfer) private returns (bytes memory, address) {
        uint signature_start;
        uint length;
        bytes memory signature;
        bytes memory transfer_raw;
        bytes32 transfer_hash;
        address transfer_address;

        length = signed_transfer.length;
        signature_start = length - 65;
        signature = slice(signed_transfer, signature_start, length);
        transfer_raw = slice(signed_transfer, 0, signature_start);

        transfer_hash = sha3(transfer_raw);
        var (r, s, v) = signatureSplit(signature);
        transfer_address = ecrecover(transfer_hash, v, r, s);

        return (transfer_raw, transfer_address);
    }

    function decodeAndAssign(Participant storage sender, bytes transfer_raw) private {
        // all checks must be done by now
        uint cmdid;

        cmdid = uint(transfer_raw[0]);

        if (cmdid == 5) {
            assignDirectTransfer(sender, transfer_raw);
        } else if (cmdid == 7) {
            assignMediatedTransfer(sender, transfer_raw);
        } else if (cmdid == 8) {
            assignRefundTransfer(sender, transfer_raw);
        } else {
            throw;
        }
    }

    // NOTES about the length of variable types:
    // - variable length types start with a size-prefix of 32bytes (uint256)
    // - bytes is a variable length type
    // - a variable with a bytes type will contain the address of the first data element
    // - solidity starts indexing at 0 (so the 32th byte is at the offset 31)
    //  ref: https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI

    // TODO: use sstore instead of these temporaries

    function assignDirectTransfer(Participant storage participant, bytes memory message) private {
        if (message.length != 124) { // size of the raw message without the signature
            throw;
        }

        uint64 nonce;
        uint256 transferred_amount;
        bytes32 locksroot;

        assembly {
                                                          // [0:1] cmdid
                                                          // [1:4] pad
            nonce := mload(add(message, 12))              // [4:12] nonce
                                                          // [12:20] identifier
                                                          // [20:40] token
                                                          // [40:60] recipient
            transferred_amount := mload(add(message, 92)) // [60:92] transferred_amount
            locksroot := mload(add(message, 124))         // [92:124] optional_locksroot
        }

        participant.nonce = nonce;
        participant.transferred_amount = transferred_amount;
        participant.locksroot = locksroot;
    }

    function assignMediatedTransfer(Participant storage participant, bytes memory message) private {
        if (message.length != 268) { // size of the raw message without the signature
            throw;
        }

        uint64 nonce;
        bytes32 locksroot;
        uint256 transferred_amount;
        uint256 lock_amount;

        assembly {
                                                           // [0:1] cmdid
                                                           // [1:4] pad
            nonce := mload(add(message, 12))               // [4:12] nonce
                                                           // [12:20] identifier
                                                           // [20:28] expiration
                                                           // [28:48] token
                                                           // [48:68] recipient
                                                           // [68:88] target
                                                           // [88:108] initiator
            locksroot := mload(add(message, 140))          // [108:140] locksroot
                                                           // [140:172] hashlock
            transferred_amount := mload(add(message, 204)) // [172:204] transferred_amoun
                                                           // [204:236] amount
                                                           // [236:268] fee
        }

        participant.nonce = nonce;
        participant.locksroot = locksroot;
        participant.transferred_amount = transferred_amount;
    }

    function assignRefundTransfer(Participant storage participant, bytes memory message) private {
        if (message.length != 196) { // size of the raw message without the signature
            throw;
        }

        uint64 nonce;
        bytes32 locksroot;
        uint256 transferred_amount;
        uint256 lock_amount;

        assembly {
                                                            // [0:1] cmdid
                                                            // [1:4] pad
            nonce := mload(add(message, 12))                // [4:12] nonce
                                                            // [12:20] identifier
                                                            // [20:28] expiration
                                                            // [28:48] token
                                                            // [48:68] recipient
            locksroot := mload(add(message, 100))           // [68:100] locksroot
            transferred_amount := mload(add(message, 132))  // [100:132] transferred_amount
                                                            // [132:164] amount
                                                            // [164:196] hashlock
        }

        participant.nonce = nonce;
        participant.locksroot = locksroot;
        participant.transferred_amount = transferred_amount;
    }

    function decodeLock(bytes lock) private returns (uint64 expiration, uint amount, bytes32 hashlock) {
        if (lock.length != 72) {
            throw;
        }

        assembly {
            expiration := mload(add(lock, 8))   // [0:8] expiration
            amount := mload(add(lock, 40))      // [8:40] amont
            hashlock := mload(add(lock, 72))    // [40:72] hashlock

        }
    }

    // Get nonce from a message
    function getNonce(bytes message) private returns (uint64 nonce) {
        // don't care about length of message since nonce is always at a fixed position
        assembly {
            nonce := mload(add(message, 12))
        }
    }

    function signatureSplit(bytes signature) private returns (bytes32 r, bytes32 s, uint8 v) {
        // The signature format is a compact form of:
        //   {bytes32 r}{bytes32 s}{uint8 v}
        // Compact means, uint8 is not padded to 32 bytes.
        assembly {
            r := mload(add(signature, 32))
            s := mload(add(signature, 64))
            // Here we are loading the last 32 bytes, including 31 bytes
            // of 's'. There is no 'mload8' to do this.
            //
            // 'byte' is not working due to the Solidity parser, so lets
            // use the second best option, 'and'
            v := and(mload(add(signature, 65)), 1)
        }
        // old geth sends a `v` value of [0,1], while the new, in line with the YP sends [27,28]
        if(v < 27) v += 27;
    }

    function slice(bytes a, uint start, uint end) private returns (bytes n) {
        if (a.length < end) {
            throw;
        }
        if (start < 0) {
            throw;
        }

        n = new bytes(end - start);
        for (uint i = start; i < end; i++) { //python style slice
            n[i - start] = a[i];
        }
    }

    function index_or_throw(Data storage self, address caller_address) private returns (uint8) {
        uint8 n;
        // Return index of participant, or throw
        n = self.participant_index[caller_address];
        if (n == 0) {
            throw;
        }
        return n - 1;
    }

    function kill(Data storage self) channelSettled(self) {
        selfdestruct(0x00000000000000000000);
    }
}


Change how allowances are paid

Change how allowances are paid

pragma solidity ^0.4.4;

contract FamilyWallet {
  // TYPES

  // Still Debating using mappings/array - or both for adult/children.
  // Right now using both.
  address _wallet = this;
  mapping (address => Adult) _adults;
  mapping (address => Child) _children;
  Adult[] _listOfAdults;
  Child[] _listOfChildren;
  uint _allowance;
  uint _allowancePeriodStart;
  uint _allowancePeriodEnd;
  uint _duration;

  // TODO: Add _requireTasksForAllowance
  // This would require "tasksCompleted" in Child Object to be true before allowance can be paid
  // bool _requireTasksForAllowance;

  struct Child {
    uint allowance;
    address addr;
    uint allowanceDue;
    //bool tasksCompleted (will be added when  _requireTasksForAllowance is added)
  }

  struct Adult {
    address addr;
    bool approveRefund;
    uint256 balanceOf;
  }

  // EVENTS
  event MoneyReceived(uint payment, address sender);
  event AllowancePaid(uint allowance, address receiver);

  // MODIFIERS

  // Adult Confirmation modifier
  // Confirmation that message sender is an adult
  modifier isAdult() {
    for (uint i = 0; i < _listOfAdults.length; i++) {
      if (msg.sender == _listOfAdults[i].addr) _;
    }
  }

  // Child Confirmation modifier
  // Confirmation that message sender is a child
  modifier isChild() {
    for (uint i = 0; i < _listOfChildren.length; i++) {
      if (msg.sender == _listOfChildren[i].addr) _;
    }
  }

  // Refundable Modifier
  // Confirmation that each ADULT has approved the ability to withdraw
  // funds from the contract.
  modifier refundable() {
    for (uint i = 0; i < _listOfAdults.length; i++) {
        address adultAddress = _listOfAdults[i].addr;
        if(!_adults[adultAddress].approveRefund) throw;
     }
     _;
  }
  // METHODS

  // Constructor Method Initialize when contract is created
  function FamilyWallet(
    address[] adults,
    address[] children,
    uint durationInDays
  ) {
    // Loop through adult array and include address in mapping and array
    for (uint j = 0; j < adults.length; j++) {
      Adult memory adult;
      adult.addr = adults[j];
      _listOfAdults.push(adult);
      _adults[adult.addr] = adult;
    }
    // Loop through children array and include address in mapping and array
    for (uint i = 0; i < children.length; i++) {
      Child memory child;
      child.addr = children[i];
      _listOfChildren.push(child);
      _children[child.addr] = child;
    }

    // Set Durations
    _allowancePeriodStart = now;
    _duration = durationInDays * 1 days;
    _allowancePeriodEnd = now + _duration;
  }

  // Make payment on allowance start,or when user calls getAllowance?
  // Right now child must call get allowance to receive alowance
  function nextAllowancePeriod() {
    if(now < _allowancePeriodEnd) throw;
    _allowancePeriodStart = _allowancePeriodEnd;
    _allowancePeriodEnd = _allowancePeriodEnd + _duration;
    for (uint i = 0; i < _listOfChildren.length; i++) {
      _listOfChildren[i].allowanceDue +=  _listOfChildren[i].allowance;
    }
  }

  function getAllowance() isChild {
    Child memory child = _children[msg.sender];
    if(child.allowanceDue == 0) throw;
    if(child.addr.send(child.allowanceDue)) throw;
    child.allowanceDue = 0;
    AllowancePaid(child.allowanceDue, msg.sender);
  }
  function approveRefund() isAdult {
    for (uint i = 0; i < _listOfAdults.length; i++) {
        if(msg.sender == _listOfAdults[i].addr) _listOfAdults[i].approveRefund = true;
     }
  }

  // Sends wallet balance to message sender
  // TODO:  Amount refunded should be same weighted average as amount deposited
  //        Rather that first person takes all.
  function refundBalance(address addr) isAdult refundable {
     if(_adults[msg.sender].addr.send(_wallet.balance)) throw;
  }

  function getChild() returns (address)  {
    return _listOfChildren[0].addr;
  }

  // Fallback method, send event once mony is paid
  function() payable {
    _adults[msg.sender].balanceOf += msg.value;
    MoneyReceived(msg.value, msg.sender);
  }
// TODO:    Allow Removal of Childen/Adult
// REASON:  In case of mental/physical inability of adult
//          to withdraw funds on his own behalf (Lost Private Key/Death)
//          Allow Remove of his account in order to be able to let other
//          adults withdraw funds. Contributions will be evenly split among
//          Other adults.
// NOTES:   Must allow a "checkin" method of some sort, if adult does not
//          check in after a period of time - allow other to vote him out
//          Otherwise if a user is checked in, there is no way he can be
//          voted out of the family.

}

pragma solidity ^0.4.4;

contract FamilyWallet {
  // TYPES

  // Still Debating using mappings/array - or both for adult/children.
  // Right now using both.
  address _wallet = this;
  mapping (address => Adult) _adults;
  mapping (address => Child) _children;
  Adult[] _listOfAdults;
  Child[] _listOfChildren;
  uint _allowance;
  uint _allowancePeriodStart;
  uint _allowancePeriodEnd;
  uint _duration;

  // TODO: Add _requireTasksForAllowance
  // This would require "tasksCompleted" in Child Object to be true before allowance can be paid
  // bool _requireTasksForAllowance;

  struct Child {
    uint allowance;
    address addr;
    bool allowanceReceived;
    //bool tasksCompleted (will be added when  _requireTasksForAllowance is added)
  }

  struct Adult {
    address addr;
    bool approveRefund;
    uint256 balanceOf;
  }

  // EVENTS
  event MoneyReceived(uint payment, address sender);
  event AllowancePaid(uint allowance, address receiver);

  // MODIFIERS

  // Adult Confirmation modifier
  // Confirmation that message sender is an adult
  modifier isAdult() {
    for (uint i = 0; i < _listOfAdults.length; i++) {
      if (msg.sender == _listOfAdults[i].addr) _;
    }
  }

  // Child Confirmation modifier
  // Confirmation that message sender is a child
  modifier isChild() {
    for (uint i = 0; i < _listOfChildren.length; i++) {
      if (msg.sender == _listOfChildren[i].addr) _;
    }
  }

  // Refundable Modifier
  // Confirmation that each ADULT has approved the ability to withdraw
  // funds from the contract.
  modifier refundable() {
    for (uint i = 0; i < _listOfAdults.length; i++) {
        address adultAddress = _listOfAdults[i].addr;
        if(!_adults[adultAddress].approveRefund) throw;
     }
     _;
  }
  // METHODS

  // Constructor Method Initialize when contract is created
  function FamilyWallet(
    address[] adults,
    address[] children,
    uint durationInDays
  ) {
    // Loop through adult array and include address in mapping and array
    for (uint j = 0; j < adults.length; j++) {
      Adult memory adult;
      adult.addr = adults[j];
      _listOfAdults.push(adult);
      _adults[adult.addr] = adult;
    }
    // Loop through children array and include address in mapping and array
    for (uint i = 0; i < children.length; i++) {
      Child memory child;
      child.addr = children[i];
      _listOfChildren.push(child);
      _children[child.addr] = child;
    }

    // Set Durations
    _allowancePeriodStart = now;
    _duration = durationInDays * 1 days;
    _allowancePeriodEnd = now + _duration;
  }

  // Make payment on allowance start,or when user calls getAllowance?
  // Right now child must call get allowance to receive alowance
  function nextAllowancePeriod() {
    if(now < _allowancePeriodEnd) throw;
    _allowancePeriodStart = _allowancePeriodEnd;
    _allowancePeriodEnd = _allowancePeriodEnd + _duration;
    for (uint i = 0; i < _listOfChildren.length; i++) {
      _listOfChildren[i].allowanceReceived = false;
    }
  }

  function getAllowance() isChild {
    Child memory child = _children[msg.sender];
    if(child.allowanceReceived == false) {
      if(child.addr.send(child.allowance)) throw;
    }
  }
  function approveRefund() isAdult {
    for (uint i = 0; i < _listOfAdults.length; i++) {
        if(msg.sender == _listOfAdults[i].addr) _listOfAdults[i].approveRefund = true;
     }
  }

  // Sends wallet balance to message sender
  // TODO:  Amount refunded should be same weighted average as amount deposited
  //        Rather that first person takes all.
  function refundBalance(address addr) isAdult refundable {
     if(_adults[msg.sender].addr.send(_wallet.balance)) throw;
  }

  function getChild() returns (address)  {
    return _listOfChildren[0].addr;
  }

  // Fallback method, send event once mony is paid
  function() payable {
    _adults[msg.sender].balanceOf += msg.value;
    MoneyReceived(msg.value, msg.sender);
  }
// TODO:    Allow Removal of Childen/Adult
// REASON:  In case of mental/physical inability of adult
//          to withdraw funds on his own behalf (Lost Private Key/Death)
//          Allow Remove of his account in order to be able to let other
//          adults withdraw funds. Contributions will be evenly split among
//          Other adults.
// NOTES:   Must allow a "checkin" method of some sort, if adult does not
//          check in after a period of time - allow other to vote him out
//          Otherwise if a user is checked in, there is no way he can be
//          voted out of the family.

}


adjusted soft cap

adjusted soft cap

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: 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 = 1505682000 + MSK2UTC_DELTA;

    /// @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: 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 = 1000 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 = 1505682000 + MSK2UTC_DELTA;

    /// @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;
}


fixed comments

fixed comments

import "lib/random.sol";
import "tag.sol";
import "assessment.sol";
import "user.sol";
import "tagMaster.sol";

/*
@type: contract
@name: UserMaster
@purpose: To store data about users for easy and secure access
*/
contract UserMaster
{
  address tagMasterAddress; //The address of the tagMaster contract
  mapping (address => int)  tokenBalance; //Maps the addresses of users to their token balances
  mapping (address => address[])  history; //Maps the addresses of users to an array of addresses that contain the addresses of their assessments
  mapping (address => bool)  availability; //Maps the addresses of users to their availability status for whether or not they can currently assess someone
  mapping (address => address)  users; //Maps the addresses of the users to their account
  bool firstUserMade = false; //Keeps track of whether or not the first user has been made yet
  event UserCreation(address _userAddress); //address of the created user contract

  /*
  @type: modifier
  @name: onlyTag
  @purpose: to only allow the Tag contract to call a function to which this modifier is applied
  */
  modifier onlyTag()
  {
    if(TagMaster(tagMasterAddress).checkTag(msg.sender) == false) //checks if the address calling the function is not a tag
    {
      throw; //throws out the fucntion call
    }
    _;
  }

  /*
  @type: modifier
  @name: onlyThis
  @purpose: to only allow the this contract to call a function to which this modifier is applied
  */
  modifier onlyThis()
  {
    if(msg.sender != address(this)) //Checks if msg.sender is this contract
    {
      throw; //Throws out the function call if it isn't
    }
    _;
  }

  /*
  @type: constructor function
  @purpose: To initialize the userMaster contract
  @param: address creator = the address of the creator contract
  @returns: nothing
  */
  function UserMaster(address tagMaster)
  {
    tagMasterAddress = tagMaster; //Sets the address of the tagMaster contract
  }

  /*
  @type: function
  @purpose: To get the address of the Tag Master
  @returns: The address of the Tag Master
  */
  function getTagMasterAddress() returns(address)
  {
    return tagMasterAddress;
  }

  /*
  @type: function
  @purpose: To create a user contract
  @param: address userAddress = the address of the user's wallet
  @param: address masterAddress = the address of the master contract that stores this user's address
  @returns: nothing
  */
  function addUser(address userAddress)
  {
    User newUser = new User(userAddress, address(this), tagMasterAddress); //Makes a new user that represents the address from userAddress and uses the master from masterAddress as its datastore
    Tag(TagMaster(tagMasterAddress).getMew()).addUser(address(newUser));
    UserCreation(address(newUser)); //Makes a new UserCreation event with the address of the newly created user
  }

  function firstUser(address userAddress)
  {
    if(firstUserMade == false)
    {
      User newUser = new User(userAddress, address(this), tagMasterAddress); //Makes a new user that represents the address from userAddress and uses the master from masterAddress as its datastore
      Tag(TagMaster(tagMasterAddress).getMew()).addUser(address(newUser));
      UserCreation(address(newUser)); //Makes a new UserCreation event with the address of the newly created user
      tokenBalance[address(newUser)] = 1000;
    }
  }

  /*
  @type: function
  @purpose: To map the address of a user to the address of the tag that the user has just passed
  @param: address user = the address of the user
  @param: address assessment = the address of the assessment completed
  @returns: nothing
  */
  function mapHistory(address user, address assessment) onlyTag()
  {
    history[user].push(assessment); //adds the address of the tag to the end of the array that is mapped to the user
  }

  /*
  @type: function
  @purpose: To map the user's availability to assess to the user's address
  @param: address user = the address of the user
  @param: bool available = the availa status of the user to assess
  @returns: nothing
  */
  function mapAvailability(bool available)
  {
    availability[msg.sender] = available; //sets the availability of the user specified in the parameter to the availability specified in the parameter
  }

  /*
  @type: function
  @purpose: To set a new token balance for a user
  @param: address user = the address of the user whose token balance is to be mapped
  @param: uint balance = the new token balance for the user
  @returns: nothing
  */
  function mapTokenBalance(address user, int balance) onlyTag()
  {
    tokenBalance[user] = balance; //sets the token balance of the user
  }

  /*
  @type: function
  @purpose: To get the user's token balance
  @param: address user = the address of the user
  @returns: The token balance in the form of a uint
  */
  function getTokenBalance(address user) constant returns(int)
  {
    return tokenBalance[user];
  }

  /*
  @type: function
  @purpose: To get the addresses of the assessments that the user has completed
  @param: address user = the address of the user
  @returns: The addresses of the assessments that the user has completed in the form of an array of addresses
  */
  function getHistory(address user) constant returns(address[])
  {
    return history[user];
  }

  /*
  @type: function
  @purpose: To get the number of assessments completed by a user
  @param: address user = the address of the user
  @returns: The number of assessments that a user has completed in the form of a uint
  */
  function getNumberOfHistory(address user) constant returns(uint)
  {
    return history[user].length;
  }

  /*
  @type: function
  @purpose: To get the availability of a user to assess
  @param: address user = the address of the user
  @returns: The availability of a user to assess in the form of a bool
  */
  function getAvailability(address user) constant returns(bool)
  {
    return availability[user];
  }

  function transferTokens(address user, int amount) returns(bool)
  {
    if(amount > 0 && tokenBalance[msg.sender] > amount)
    {
      tokenBalance[msg.sender] -= amount;
      tokenBalance[user] += amount;
      return true;
    }
    else
    {
      return false;
    }
  }

  /*
  @type: function
  @purpose: to remove this contract
  @param: address receiver = the address of the wallet that will receive of the ether
  @returns: nothing
  */
  function remove(address reciever) onlyThis()
  {
    suicide(reciever);
  }
}

import "lib/random.sol";
import "tag.sol";
import "assessment.sol";
import "user.sol";
import "tagMaster.sol";

/*
@type: contract
@name: UserMaster
@purpose: To store data about users for easy and secure access
*/
contract UserMaster
{
  address tagMasterAddress; //The address of the tagMaster contract
  mapping (address => int)  tokenBalance; //Maps the addresses of users to their token balances
  mapping (address => address[])  history; //Maps the addresses of users to an array of addresses that contain the addresses of their assessments
  mapping (address => bool)  availability; //Maps the addresses of users to their availability status for whether or not they can currently assess someone
  mapping (address => address)  users; //Maps the addresses of the users to their actual location of the blockchain
  bool firstUserMade = false; //Keeps track of whether or not the first user has been made yet
  event UserCreation(address _userAddress); //address of the created user contract

  /*
  @type: modifier
  @name: onlyTag
  @purpose: to only allow the Tag contract to call a function to which this modifier is applied
  */
  modifier onlyTag()
  {
    if(TagMaster(tagMasterAddress).checkTag(msg.sender) == false) //checks if the address calling the function is not a tag
    {
      throw; //throws out the fucntion call
    }
    _;
  }

  /*
  @type: modifier
  @name: onlyThis
  @purpose: to only allow the this contract to call a function to which this modifier is applied
  */
  modifier onlyThis()
  {
    if(msg.sender != address(this)) //Checks if msg.sender is this contract
    {
      throw; //Throws out the function call if it isn't
    }
    _;
  }

  /*
  @type: constructor function
  @purpose: To initialize the userMaster contract
  @param: address creator = the address of the creator contract
  @returns: nothing
  */
  function UserMaster(address tagMaster)
  {
    tagMasterAddress = tagMaster; //Sets the address of the tagMaster contract
  }

  /*
  @type: function
  @purpose: To get the address of the Tag Master
  @returns: The address of the Tag Master
  */
  function getTagMasterAddress() returns(address)
  {
    return tagMasterAddress;
  }

  /*
  @type: function
  @purpose: To create a user contract
  @param: address userAddress = the address of the user's wallet
  @param: address masterAddress = the address of the master contract that stores this user's address
  @returns: nothing
  */
  function addUser(address userAddress)
  {
    User newUser = new User(userAddress, address(this), tagMasterAddress); //Makes a new user that represents the address from userAddress and uses the master from masterAddress as its datastore
    Tag(TagMaster(tagMasterAddress).getMew()).addUser(address(newUser));
    UserCreation(address(newUser)); //Makes a new UserCreation event with the address of the newly created user
  }

  function firstUser(address userAddress)
  {
    if(firstUserMade == false)
    {
      User newUser = new User(userAddress, address(this), tagMasterAddress); //Makes a new user that represents the address from userAddress and uses the master from masterAddress as its datastore
      Tag(TagMaster(tagMasterAddress).getMew()).addUser(address(newUser));
      UserCreation(address(newUser)); //Makes a new UserCreation event with the address of the newly created user
      tokenBalance[address(newUser)] = 1000;
    }
  }

  /*
  @type: function
  @purpose: To map the address of a user to the address of the tag that the user has just passed
  @param: address user = the address of the user
  @param: address assessment = the address of the assessment completed
  @returns: nothing
  */
  function mapHistory(address user, address assessment) onlyTag()
  {
    history[user].push(assessment); //adds the address of the tag to the end of the array that is mapped to the user
  }

  /*
  @type: function
  @purpose: To map the user's availability to assess to the user's address
  @param: address user = the address of the user
  @param: bool available = the availa status of the user to assess
  @returns: nothing
  */
  function mapAvailability(bool available)
  {
    availability[msg.sender] = available; //sets the availability of the user specified in the parameter to the availability specified in the parameter
  }

  /*
  @type: function
  @purpose: To set a new token balance for a user
  @param: address user = the address of the user whose token balance is to be mapped
  @param: uint balance = the new token balance for the user
  @returns: nothing
  */
  function mapTokenBalance(address user, int balance) onlyTag()
  {
    tokenBalance[user] = balance; //sets the token balance of the user
  }

  /*
  @type: function
  @purpose: To get the user's token balance
  @param: address user = the address of the user
  @returns: The token balance in the form of a uint
  */
  function getTokenBalance(address user) constant returns(int)
  {
    return tokenBalance[user];
  }

  /*
  @type: function
  @purpose: To get the addresses of the assessments that the user has completed
  @param: address user = the address of the user
  @returns: The addresses of the assessments that the user has completed in the form of an array of addresses
  */
  function getHistory(address user) constant returns(address[])
  {
    return history[user];
  }

  /*
  @type: function
  @purpose: To get the number of assessments completed by a user
  @param: address user = the address of the user
  @returns: The number of assessments that a user has completed in the form of a uint
  */
  function getNumberOfHistory(address user) constant returns(uint)
  {
    return history[user].length;
  }

  /*
  @type: function
  @purpose: To get the availability of a user to assess
  @param: address user = the address of the user
  @returns: The availability of a user to assess in the form of a bool
  */
  function getAvailability(address user) constant returns(bool)
  {
    return availability[user];
  }

  function transferTokens(address user, int amount) returns(bool)
  {
    if(amount > 0 && tokenBalance[msg.sender] > amount)
    {
      tokenBalance[msg.sender] -= amount;
      tokenBalance[user] += amount;
      return true;
    }
    else
    {
      return false;
    }
  }

  /*
  @type: function
  @purpose: to remove this contract
  @param: address receiver = the address of the wallet that will receive of the ether
  @returns: nothing
  */
  function remove(address reciever) onlyThis()
  {
    suicide(reciever);
  }
}