Check that only counter party can update

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;
        uint256 amount;
        bytes merkle_proof;
        bytes32 hashlock;
        bytes32 secret;
        uint256 expiration;
        uint64 nonce;
        address token;
        address recipient;
        bytes32 locksroot;
        Lock[] unlocked;
    }

    struct Data {
        uint settle_timeout;
        uint opened;
        uint closed;
        uint settled;
        address closing_address;
        Token token;
        Participant[2] participants;
        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) {
        Participant storage participant = self.participants[0];
        if (participant.node_address != self.closing_address) {
            participant = self.participants[1];
            if (participant.node_address != caller) {
                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)
    {
        uint index;

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

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

        Participant storage participant = self.participants[0];
        if (participant.node_address != caller_address) {
            participant = self.participants[1];
            if (participant.node_address != caller_address) {
                throw;
            }
        }

        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)
    {
        Participant[2] participants = self.participants;
        Participant node1 = participants[0];
        Participant node2 = participants[1];

        if (node1.node_address == participant_address) {
            return node1.transferred_amount;
        } else if (node2.node_address == participant_address) {
            return node2.transferred_amount;
        }
        // invalid address
        throw;
    }

    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)
    {
        // the channel can't be closed multiple times
        if (self.settled > 0 || self.closed > 0) {
            throw;
        }

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

        //only a channel participant can close the channel
        if (node1.node_address != caller_address && node2.node_address != caller_address) {
            throw;
        }

        // keep the information of the closing party
        self.closing_address = caller_address;
        self.closed = block.number;
        // if no transfer from the other participant was given then we are
        // attempting to close a channel without a transfer
        if (their_transfer.length == 0) {
            return;
        }

        // else we are closing a channel that has received transfers
        their_sender = processTransfer(self, node1, node2, their_transfer);
        if (their_sender == caller_address) {
            // the sender of "their" transaction can't be ourselves
            throw;
        }
    }

    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;

        // TODO check if tampered and penalize
        // TODO check if outdated and penalize
    }

    /// @notice Unlock a locked transfer
    /// @dev Unlock a locked transfer
    /// @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 partner_id;
        uint64 expiration;
        uint amount;
        bytes32 hashlock;
        bytes32 h;
        bytes32 el;

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

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

        if (expiration < block.number)
            throw;

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

        Participant[2] storage participants = self.participants;
        Participant storage participant = participants[0];
        if (participant.node_address == caller_address) {
            participant = participants[1];
            if (participant.node_address != caller_address) {
                throw;
            }
        }

        if (participant.nonce == 0) {
            throw;
        }

        h = sha3(locked_encoded);
        for (uint 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);
            }
        }

        if (participant.locksroot != h)
            throw;

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

    /// @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 = closing_party.netted < self.token.balanceOf(address(this))
            ? closing_party.netted
            : self.token.balanceOf(address(this));
        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 != 156) {  // raw message size (without signature)
            throw;
        }

        uint64 nonce;
        address token;
        address recipient;
        uint256 transferred_amount;
        bytes32 locksroot;
        bytes32 secret;

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

        participant.nonce = nonce;
        participant.token = token;
        participant.recipient = recipient;
        participant.transferred_amount = transferred_amount;
        participant.locksroot = locksroot;
        participant.secret = secret;
    }

    function assignMediatedTransfer(Participant storage participant, bytes memory message) private {
        if (message.length != 268) {
            throw;
        }

        uint64 nonce;
        uint64 expiration;
        address token;
        address recipient;
        bytes32 locksroot;
        bytes32 hashlock;
        uint256 transferred_amount;
        uint256 lock_amount;

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

        participant.nonce = nonce;
        participant.expiration = expiration;
        participant.token = token;
        participant.recipient = recipient;
        participant.locksroot = locksroot;
        participant.hashlock = hashlock;
        participant.transferred_amount = transferred_amount;
        participant.amount = lock_amount;
    }

    function assignRefundTransfer(Participant storage participant, bytes memory message) private {
        if (message.length != 196) {
            throw;
        }

        uint64 nonce;
        uint64 expiration;
        address token;
        address recipient;
        bytes32 locksroot;
        uint256 transferred_amount;
        uint256 lock_amount;
        bytes32 hashlock;

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

        participant.nonce = nonce;
        participant.expiration = expiration;
        participant.token = token;
        participant.recipient = recipient;
        participant.locksroot = locksroot;
        participant.transferred_amount = transferred_amount;
        participant.amount = lock_amount;
        participant.hashlock = hashlock;
    }

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

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

        }
    }

    // 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 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;
        uint256 amount;
        bytes merkle_proof;
        bytes32 hashlock;
        bytes32 secret;
        uint256 expiration;
        uint64 nonce;
        address token;
        address recipient;
        bytes32 locksroot;
        Lock[] unlocked;
    }

    struct Data {
        uint settle_timeout;
        uint opened;
        uint closed;
        uint settled;
        address closing_address;
        Token token;
        Participant[2] participants;
        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 notClosingAddress(Data storage self, address caller) {
        if (caller == self.closing_address)
            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)
    {
        uint index;

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

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

        Participant storage participant = self.participants[0];
        if (participant.node_address != caller_address) {
            participant = self.participants[1];
            if (participant.node_address != caller_address) {
                throw;
            }
        }

        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)
    {
        Participant[2] participants = self.participants;
        Participant node1 = participants[0];
        Participant node2 = participants[1];

        if (node1.node_address == participant_address) {
            return node1.transferred_amount;
        } else if (node2.node_address == participant_address) {
            return node2.transferred_amount;
        }
        // invalid address
        throw;
    }

    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)
    {
        // the channel can't be closed multiple times
        if (self.settled > 0 || self.closed > 0) {
            throw;
        }

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

        //only a channel participant can close the channel
        if (node1.node_address != caller_address && node2.node_address != caller_address) {
            throw;
        }

        // keep the information of the closing party
        self.closing_address = caller_address;
        self.closed = block.number;
        // if no transfer from the other participant was given then we are
        // attempting to close a channel without a transfer
        if (their_transfer.length == 0) {
            return;
        }

        // else we are closing a channel that has received transfers
        their_sender = processTransfer(self, node1, node2, their_transfer);
        if (their_sender == caller_address) {
            // the sender of "their" transaction can't be ourselves
            throw;
        }
    }

    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)
        notClosingAddress(self, caller_address)
        notYetUpdated(self)
    {
        // transfer address must be from counter party
        if (self.closing_address == caller_address) {
            throw;
        }

        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;

        // TODO check if tampered and penalize
        // TODO check if outdated and penalize
    }

    /// @notice Unlock a locked transfer
    /// @dev Unlock a locked transfer
    /// @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 partner_id;
        uint64 expiration;
        uint amount;
        bytes32 hashlock;
        bytes32 h;
        bytes32 el;

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

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

        if (expiration < block.number)
            throw;

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

        Participant[2] storage participants = self.participants;
        Participant storage participant = participants[0];
        if (participant.node_address == caller_address) {
            participant = participants[1];
            if (participant.node_address != caller_address) {
                throw;
            }
        }

        if (participant.nonce == 0) {
            throw;
        }

        h = sha3(locked_encoded);
        for (uint 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);
            }
        }

        if (participant.locksroot != h)
            throw;

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

    /// @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 = closing_party.netted < self.token.balanceOf(address(this))
            ? closing_party.netted
            : self.token.balanceOf(address(this));
        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 != 156) {  // raw message size (without signature)
            throw;
        }

        uint64 nonce;
        address token;
        address recipient;
        uint256 transferred_amount;
        bytes32 locksroot;
        bytes32 secret;

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

        participant.nonce = nonce;
        participant.token = token;
        participant.recipient = recipient;
        participant.transferred_amount = transferred_amount;
        participant.locksroot = locksroot;
        participant.secret = secret;
    }

    function assignMediatedTransfer(Participant storage participant, bytes memory message) private {
        if (message.length != 268) {
            throw;
        }

        uint64 nonce;
        uint64 expiration;
        address token;
        address recipient;
        bytes32 locksroot;
        bytes32 hashlock;
        uint256 transferred_amount;
        uint256 lock_amount;

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

        participant.nonce = nonce;
        participant.expiration = expiration;
        participant.token = token;
        participant.recipient = recipient;
        participant.locksroot = locksroot;
        participant.hashlock = hashlock;
        participant.transferred_amount = transferred_amount;
        participant.amount = lock_amount;
    }

    function assignRefundTransfer(Participant storage participant, bytes memory message) private {
        if (message.length != 196) {
            throw;
        }

        uint64 nonce;
        uint64 expiration;
        address token;
        address recipient;
        bytes32 locksroot;
        uint256 transferred_amount;
        uint256 lock_amount;
        bytes32 hashlock;

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

        participant.nonce = nonce;
        participant.expiration = expiration;
        participant.token = token;
        participant.recipient = recipient;
        participant.locksroot = locksroot;
        participant.transferred_amount = transferred_amount;
        participant.amount = lock_amount;
        participant.hashlock = hashlock;
    }

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

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

        }
    }

    // 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 kill(Data storage self) channelSettled(self) {
        selfdestruct(0x00000000000000000000);
    }
}


Remove variable declaration hack

Remove variable declaration hack

pragma solidity >=0.8.4;

import "./ENS.sol";
import "../root/Ownable.sol";
import "../root/Controllable.sol";

abstract contract NameResolver {
    function setName(bytes32 node, string memory name) public virtual;
}

bytes32 constant lookup = 0x3031323334353637383961626364656600000000000000000000000000000000;

contract ReverseRegistrar is Ownable, Controllable {
    // namehash('addr.reverse')
    bytes32 public constant ADDR_REVERSE_NODE =
        0x91d1777781884d03a6757a803996e38de2a42967fb37eeaca72729271025a9e2;

    ENS public ens;
    NameResolver public defaultResolver;

    /**
     * @dev Constructor
     * @param ensAddr The address of the ENS registry.
     * @param resolverAddr The address of the default reverse resolver.
     */
    constructor(ENS ensAddr, NameResolver resolverAddr) public {
        ens = ensAddr;
        defaultResolver = resolverAddr;

        // Assign ownership of the reverse record to our deployer
        ReverseRegistrar oldRegistrar = ReverseRegistrar(
            ens.owner(ADDR_REVERSE_NODE)
        );
        if (address(oldRegistrar) != address(0x0)) {
            oldRegistrar.claim(msg.sender);
        }
    }

    /**
     * @dev Transfers ownership of the reverse ENS record associated with the
     *      calling account.
     * @param owner The address to set as the owner of the reverse record in ENS.
     * @return The ENS node hash of the reverse record.
     */
    function claim(address owner) public returns (bytes32) {
        return claimWithResolver(owner, address(0x0));
    }

    /**
     * @dev Transfers ownership of the reverse ENS record associated with the
     *      calling account.
     * @param owner The address to set as the owner of the reverse record in ENS.
     * @param resolver The address of the resolver to set; 0 to leave unchanged.
     * @return The ENS node hash of the reverse record.
     */
    function claimWithResolver(address owner, address resolver)
        public
        returns (bytes32)
    {
        return _claimWithResolver(msg.sender, owner, resolver);
    }

    /**
     * @dev Sets the `name()` record for the reverse ENS record associated with
     * the calling account. First updates the resolver to the default reverse
     * resolver if necessary.
     * @param name The name to set for this address.
     * @return The ENS node hash of the reverse record.
     */
    function setName(string memory name) public returns (bytes32) {
        bytes32 node = claimWithResolver(
            address(this),
            address(defaultResolver)
        );
        defaultResolver.setName(node, name);
        return node;
    }

    /**
     * @dev Sets the `name()` record for the reverse ENS record associated with
     * the account provided. First updates the resolver to the default reverse
     * resolver if necessary.
     * Only callable by controllers
     * @param name The name to set for this address.
     * @return The ENS node hash of the reverse record.
     */
    function setNameWithController(address addr, string memory name)
        public
        onlyController
        returns (bytes32)
    {
        bytes32 node = _claimWithResolver(
            addr,
            address(this),
            address(defaultResolver)
        );
        defaultResolver.setName(node, name);
        return node;
    }

    /**
     * @dev Returns the node hash for a given account's reverse records.
     * @param addr The address to hash
     * @return The ENS node hash.
     */
    function node(address addr) public pure returns (bytes32) {
        return
            keccak256(
                abi.encodePacked(ADDR_REVERSE_NODE, sha3HexAddress(addr))
            );
    }

    /**
     * @dev An optimised function to compute the sha3 of the lower-case
     *      hexadecimal representation of an Ethereum address.
     * @param addr The address to hash
     * @return ret The SHA3 hash of the lower-case hexadecimal encoding of the
     *         input address.
     */
    function sha3HexAddress(address addr) private pure returns (bytes32 ret) {
        assembly {
            for {
                let i := 40
            } gt(i, 0) {

            } {
                i := sub(i, 1)
                mstore8(i, byte(and(addr, 0xf), lookup))
                addr := div(addr, 0x10)
                i := sub(i, 1)
                mstore8(i, byte(and(addr, 0xf), lookup))
                addr := div(addr, 0x10)
            }

            ret := keccak256(0, 40)
        }
    }

    /**
     * @dev Transfers ownership of the reverse ENS record associated with the
     *      calling account.
     * @param owner The address to set as the owner of the reverse record in ENS.
     * @param resolver The address of the resolver to set; 0 to leave unchanged.
     * @return The ENS node hash of the reverse record.
     */
    function _claimWithResolver(
        address addr,
        address owner,
        address resolver
    ) internal returns (bytes32) {
        bytes32 label = sha3HexAddress(addr);
        bytes32 node = keccak256(abi.encodePacked(ADDR_REVERSE_NODE, label));
        address currentOwner = ens.owner(node);

        // Update the resolver if required
        if (resolver != address(0x0) && resolver != ens.resolver(node)) {
            // Transfer the name to us first if it's not already
            if (currentOwner != address(this)) {
                ens.setSubnodeOwner(ADDR_REVERSE_NODE, label, address(this));
                currentOwner = address(this);
            }
            ens.setResolver(node, resolver);
        }

        // Update the owner if required
        if (currentOwner != owner) {
            ens.setSubnodeOwner(ADDR_REVERSE_NODE, label, owner);
        }

        return node;
    }
}

pragma solidity >=0.8.4;

import "./ENS.sol";
import "../root/Ownable.sol";
import "../root/Controllable.sol";

abstract contract NameResolver {
    function setName(bytes32 node, string memory name) public virtual;
}

bytes32 constant lookup = 0x3031323334353637383961626364656600000000000000000000000000000000;

contract ReverseRegistrar is Ownable, Controllable {
    // namehash('addr.reverse')
    bytes32 public constant ADDR_REVERSE_NODE =
        0x91d1777781884d03a6757a803996e38de2a42967fb37eeaca72729271025a9e2;

    ENS public ens;
    NameResolver public defaultResolver;

    /**
     * @dev Constructor
     * @param ensAddr The address of the ENS registry.
     * @param resolverAddr The address of the default reverse resolver.
     */
    constructor(ENS ensAddr, NameResolver resolverAddr) public {
        ens = ensAddr;
        defaultResolver = resolverAddr;

        // Assign ownership of the reverse record to our deployer
        ReverseRegistrar oldRegistrar = ReverseRegistrar(
            ens.owner(ADDR_REVERSE_NODE)
        );
        if (address(oldRegistrar) != address(0x0)) {
            oldRegistrar.claim(msg.sender);
        }
    }

    /**
     * @dev Transfers ownership of the reverse ENS record associated with the
     *      calling account.
     * @param owner The address to set as the owner of the reverse record in ENS.
     * @return The ENS node hash of the reverse record.
     */
    function claim(address owner) public returns (bytes32) {
        return claimWithResolver(owner, address(0x0));
    }

    /**
     * @dev Transfers ownership of the reverse ENS record associated with the
     *      calling account.
     * @param owner The address to set as the owner of the reverse record in ENS.
     * @param resolver The address of the resolver to set; 0 to leave unchanged.
     * @return The ENS node hash of the reverse record.
     */
    function claimWithResolver(address owner, address resolver)
        public
        returns (bytes32)
    {
        return _claimWithResolver(msg.sender, owner, resolver);
    }

    /**
     * @dev Sets the `name()` record for the reverse ENS record associated with
     * the calling account. First updates the resolver to the default reverse
     * resolver if necessary.
     * @param name The name to set for this address.
     * @return The ENS node hash of the reverse record.
     */
    function setName(string memory name) public returns (bytes32) {
        bytes32 node = claimWithResolver(
            address(this),
            address(defaultResolver)
        );
        defaultResolver.setName(node, name);
        return node;
    }

    /**
     * @dev Sets the `name()` record for the reverse ENS record associated with
     * the account provided. First updates the resolver to the default reverse
     * resolver if necessary.
     * Only callable by controllers
     * @param name The name to set for this address.
     * @return The ENS node hash of the reverse record.
     */
    function setNameWithController(address addr, string memory name)
        public
        onlyController
        returns (bytes32)
    {
        bytes32 node = _claimWithResolver(
            addr,
            address(this),
            address(defaultResolver)
        );
        defaultResolver.setName(node, name);
        return node;
    }

    /**
     * @dev Returns the node hash for a given account's reverse records.
     * @param addr The address to hash
     * @return The ENS node hash.
     */
    function node(address addr) public pure returns (bytes32) {
        return
            keccak256(
                abi.encodePacked(ADDR_REVERSE_NODE, sha3HexAddress(addr))
            );
    }

    /**
     * @dev An optimised function to compute the sha3 of the lower-case
     *      hexadecimal representation of an Ethereum address.
     * @param addr The address to hash
     * @return ret The SHA3 hash of the lower-case hexadecimal encoding of the
     *         input address.
     */
    function sha3HexAddress(address addr) private pure returns (bytes32 ret) {
        addr;
        ret; // Stop warning us about unused variables
        assembly {
            for {
                let i := 40
            } gt(i, 0) {

            } {
                i := sub(i, 1)
                mstore8(i, byte(and(addr, 0xf), lookup))
                addr := div(addr, 0x10)
                i := sub(i, 1)
                mstore8(i, byte(and(addr, 0xf), lookup))
                addr := div(addr, 0x10)
            }

            ret := keccak256(0, 40)
        }
    }

    /**
     * @dev Transfers ownership of the reverse ENS record associated with the
     *      calling account.
     * @param owner The address to set as the owner of the reverse record in ENS.
     * @param resolver The address of the resolver to set; 0 to leave unchanged.
     * @return The ENS node hash of the reverse record.
     */
    function _claimWithResolver(
        address addr,
        address owner,
        address resolver
    ) internal returns (bytes32) {
        bytes32 label = sha3HexAddress(addr);
        bytes32 node = keccak256(abi.encodePacked(ADDR_REVERSE_NODE, label));
        address currentOwner = ens.owner(node);

        // Update the resolver if required
        if (resolver != address(0x0) && resolver != ens.resolver(node)) {
            // Transfer the name to us first if it's not already
            if (currentOwner != address(this)) {
                ens.setSubnodeOwner(ADDR_REVERSE_NODE, label, address(this));
                currentOwner = address(this);
            }
            ens.setResolver(node, resolver);
        }

        // Update the owner if required
        if (currentOwner != owner) {
            ens.setSubnodeOwner(ADDR_REVERSE_NODE, label, owner);
        }

        return node;
    }
}


separate  set functions in thesaurusAdmin contract

contract thesaurus {
	string public name;
	string public desc;
	address public owner;

	modifier ownerCheck { if (msg.sender == owner) _ }

	struct Prop {
		string itemprop;
		string itemtype;
		string desc;
		string dataType;
	}

	Prop[] public propList;
	mapping (bytes32 => uint) public itempropOf;
	mapping (bytes32 => bool) public itempropExistOf;

	struct Enum {
		uint propListID;
	}

	struct Metadata {
		string itemscope;
		Enum[]  enumPropList;
		uint numProp;
	}

	Metadata[] schemaorgList;
	/* Help you find itemscope proplist*/
	mapping (bytes32 => uint) public itemscopeOf;
	mapping (bytes32 => bool) public itemscopeExistOf;

	function thesaurus(string _name, string _desc) {
		name = _name;
		desc = _desc;
		owner = msg.sender;
	}

	function getPropID(string _itemprop) returns(bool result, uint propID){
		if(!itempropExistOf[sha3(_itemprop)]) break;
		result = true;
		propID = itempropOf[sha3(_itemprop)];
		return(result, propID);
	}

	function getProp(uint _propID) returns(string itemprop, string itemtype, string desc, string dataType){
		Prop p = propList[_propID];
		return(p.itemprop, p.itemtype, p.desc, p.dataType);
	}

	function getMetadataID(string _itemscope) returns(bool result, uint metadataID){
		if(!itemscopeExistOf[sha3(_itemscope)]) break;
		result = true;
		metadataID = itemscopeOf[sha3(_itemscope)];
		return(result, metadataID);
	}

	function getMetadataNumProp(uint _itemscopeID) returns(string itemscope, uint numProp){
		Metadata m = schemaorgList[_itemscopeID];
		return(m.itemscope, m.numProp);
	}
}

contract thesaurusAdmin is thesaurus{

	function setProp(string _itemprop, string _itemtype, string _desc, string _dataType) ownerCheck returns(uint propID) {
		propID = propList.length++;
        Prop p = propList[propID];
        p.itemprop = _itemprop;
        p.itemtype = _itemtype;
        p.desc = _desc;
        p.dataType = _dataType;
        itempropExistOf[sha3(p.itemprop)] = true;
        itempropOf[sha3(p.itemprop)] = propID;
        return propID;
	}

	function setMetadata(string _itemscope, uint _propID) ownerCheck returns(uint enumPropListID) {
		uint metadataID;
		if(!itemscopeExistOf[sha3(_itemscope)]) {
			metadataID = schemaorgList.length++;
        	itemscopeExistOf[sha3(m.itemscope)] = true;
        	itemscopeOf[sha3(m.itemscope)] = metadataID;
    	} else {
    		metadataID = itemscopeOf[sha3(_itemscope)];
    	}

    	Metadata m = schemaorgList[metadataID];
        m.itemscope = _itemscope;

        enumPropListID = m.enumPropList.length++;
       	Enum e = m.enumPropList[enumPropListID];
        e.propListID = _propID;
        m.numProp +=1;
    	return enumPropListID;
	}
}

contract thesaurus {
	string public name;
	string public desc;
	address public owner;

	modifier ownerCheck { if (msg.sender == owner) _ }

	struct Prop {
		string itemprop;
		string itemtype;
		string desc;
		string dataType;
	}

	Prop[] public propList;
	mapping (bytes32 => uint) public itempropOf;
	mapping (bytes32 => bool) public itempropExistOf;

	struct Enum {
		uint propListID;
	}

	struct Metadata {
		string itemscope;
		Enum[]  enumPropList;
		uint numProp;
	}

	Metadata[] schemaorgList;
	/* Help you find itemscope proplist*/
	mapping (bytes32 => uint) public itemscopeOf;
	mapping (bytes32 => bool) public itemscopeExistOf;

	function thesaurus(string _name, string _desc) {
		name = _name;
		desc = _desc;
		owner = msg.sender;
	}

	function setProp(string _itemprop, string _itemtype, string _desc, string _dataType) ownerCheck returns(uint propID) {
		propID = propList.length++;
        Prop p = propList[propID];
        p.itemprop = _itemprop;
        p.itemtype = _itemtype;
        p.desc = _desc;
        p.dataType = _dataType;
        itempropExistOf[sha3(p.itemprop)] = true;
        itempropOf[sha3(p.itemprop)] = propID;
        return propID;
	}

	function getPropID(string _itemprop) returns(bool result, uint propID){
		if(!itempropExistOf[sha3(_itemprop)]) break;
		result = true;
		propID = itempropOf[sha3(_itemprop)];
		return(result, propID);
	}

	function getProp(uint _propID) returns(string itemprop, string itemtype, string desc, string dataType){
		Prop p = propList[_propID];
		return(p.itemprop, p.itemtype, p.desc, p.dataType);
	}

	function setMetadata(string _itemscope, uint _propID) ownerCheck returns(uint enumPropListID) {
		uint metadataID;
		if(!itemscopeExistOf[sha3(_itemscope)]) {
			metadataID = schemaorgList.length++;
        	itemscopeExistOf[sha3(m.itemscope)] = true;
        	itemscopeOf[sha3(m.itemscope)] = metadataID;
    	} else {
    		metadataID = itemscopeOf[sha3(_itemscope)];
    	}

    	Metadata m = schemaorgList[metadataID];
        m.itemscope = _itemscope;

        enumPropListID = m.enumPropList.length++;
       	Enum e = m.enumPropList[enumPropListID];
        e.propListID = _propID;
        m.numProp +=1;
    	return enumPropListID;
	}

	function getMetadataID(string _itemscope) returns(bool result, uint metadataID){
		if(!itemscopeExistOf[sha3(_itemscope)]) break;
		result = true;
		metadataID = itemscopeOf[sha3(_itemscope)];
		return(result, metadataID);
	}

	function getMetadataNumProp(uint _itemscopeID) returns(string itemscope, uint numProp){
		Metadata m = schemaorgList[_itemscopeID];
		return(m.itemscope, m.numProp);
	}

}


Test retractLatestRevision()

Test retractLatestRevision()

pragma solidity ^0.4.2;

import "dapple/test.sol";
import "blobstore.sol";
import "blobstore_flags.sol";

/**
 * @title BlobStoreTest
 * @author Jonathan Brown <jbrown@bluedroplet.com>
 */
contract BlobStoreTest is Test, BlobStoreFlags {

    BlobStoreRegistry blobStoreRegistry;
    BlobStore blobStore;

    function setUp() {
        blobStoreRegistry = new BlobStoreRegistry();
        blobStore = new BlobStore(blobStoreRegistry);
    }

    function testThrowRegisterContractAgain() {
        blobStoreRegistry.register(blobStore.getContractId());
    }

    function testThrowBlobStoreNotRegistered() {
        blobStoreRegistry.getBlobStore(0);
    }

    function testBlobStoreRegistered() {
        assertEq(blobStoreRegistry.getBlobStore(blobStore.getContractId()), blobStore);
    }

    function testThrowCreateExistingNonce() {
        blobStore.create(0, hex"00");
        blobStore.create(0, hex"00");
    }

    function testCreate() {
        bytes20 blobId0 = blobStore.create(0, hex"00");
        assertTrue(blobStore.getExists(blobId0));
        assertEq(blobStore.getOwner(blobId0), this);
        assertEq(blobStore.getRevisionCount(blobId0), 1);
        assertFalse(blobStore.getUpdatable(blobId0));
        assertFalse(blobStore.getEnforceRevisions(blobId0));
        assertFalse(blobStore.getRetractable(blobId0));
        assertFalse(blobStore.getTransferable(blobId0));

        bytes20 blobId1 = blobStore.create(FLAG_UPDATABLE | FLAG_ENFORCE_REVISIONS | FLAG_RETRACTABLE | FLAG_TRANSFERABLE | FLAG_ANONYMOUS, hex"00");
        assertTrue(blobStore.getExists(blobId1));
        assertEq(blobStore.getOwner(blobId1), 0);
        assertEq(blobStore.getRevisionCount(blobId1), 1);
        assertTrue(blobStore.getUpdatable(blobId1));
        assertTrue(blobStore.getEnforceRevisions(blobId1));
        assertTrue(blobStore.getRetractable(blobId1));
        assertTrue(blobStore.getTransferable(blobId1));

        assertFalse(blobId0 == blobId1);
    }

    function testThrowsCreateNewRevisionNotUpdatable() {
        bytes20 blobId = blobStore.create(0, hex"00");
        blobStore.createNewRevision(blobId, hex"00");
    }

    function testCreateNewRevision() {
        bytes20 blobId = blobStore.create(FLAG_UPDATABLE, hex"00");
        uint revisionId = blobStore.createNewRevision(blobId, hex"00");
        assertEq(revisionId, 1);
        assertEq(blobStore.getRevisionCount(blobId), 2);
    }

    function testThrowsUpdateLatestRevisionNotUpdatable() {
        bytes20 blobId = blobStore.create(0, hex"00");
        blobStore.updateLatestRevision(blobId, hex"00");
    }

    function testThrowsUpdateLatestRevisionEnforceRevisions() {
        bytes20 blobId = blobStore.create(FLAG_UPDATABLE | FLAG_ENFORCE_REVISIONS, hex"00");
        blobStore.updateLatestRevision(blobId, hex"00");
    }

    function testUpdateLatestRevision() {
        bytes20 blobId = blobStore.create(FLAG_UPDATABLE, hex"00");
        blobStore.updateLatestRevision(blobId, hex"00");
        assertEq(blobStore.getRevisionCount(blobId), 1);
    }

    function testThrowsRetractLatestRevisionNotUpdatable() {
        bytes20 blobId = blobStore.create(FLAG_UPDATABLE, hex"00");
        blobStore.createNewRevision(blobId, hex"00");
        blobStore.setNotUpdatable(blobId);
        blobStore.retractLatestRevision(blobId);
    }

    function testThrowsRetractLatestRevisionEnforceRevisions() {
        bytes20 blobId = blobStore.create(FLAG_UPDATABLE | FLAG_ENFORCE_REVISIONS, hex"00");
        blobStore.createNewRevision(blobId, hex"00");
        blobStore.retractLatestRevision(blobId);
    }

    function testThrowsRetractLatestRevisionDoesntHaveAdditionalRevisions() {
        bytes20 blobId = blobStore.create(FLAG_UPDATABLE, hex"00");
        blobStore.retractLatestRevision(blobId);
    }

    function testRetractLatestRevision() {
        bytes20 blobId = blobStore.create(FLAG_UPDATABLE, hex"00");
        uint revisionId = blobStore.createNewRevision(blobId, hex"00");
        assertEq(revisionId, 1);
        assertEq(blobStore.getRevisionCount(blobId), 2);
        blobStore.retractLatestRevision(blobId);
        assertEq(blobStore.getRevisionCount(blobId), 1);
    }

}

pragma solidity ^0.4.2;

import "dapple/test.sol";
import "blobstore.sol";
import "blobstore_flags.sol";

/**
 * @title BlobStoreTest
 * @author Jonathan Brown <jbrown@bluedroplet.com>
 */
contract BlobStoreTest is Test, BlobStoreFlags {

    BlobStoreRegistry blobStoreRegistry;
    BlobStore blobStore;

    function setUp() {
        blobStoreRegistry = new BlobStoreRegistry();
        blobStore = new BlobStore(blobStoreRegistry);
    }

    function testThrowRegisterContractAgain() {
        blobStoreRegistry.register(blobStore.getContractId());
    }

    function testThrowBlobStoreNotRegistered() {
        blobStoreRegistry.getBlobStore(0);
    }

    function testBlobStoreRegistered() {
        assertEq(blobStoreRegistry.getBlobStore(blobStore.getContractId()), blobStore);
    }

    function testThrowCreateExistingNonce() {
        blobStore.create(0, hex"00");
        blobStore.create(0, hex"00");
    }

    function testCreate() {
        bytes20 blobId0 = blobStore.create(0, hex"00");
        assertTrue(blobStore.getExists(blobId0));
        assertEq(blobStore.getOwner(blobId0), this);
        assertEq(blobStore.getRevisionCount(blobId0), 1);
        assertFalse(blobStore.getUpdatable(blobId0));
        assertFalse(blobStore.getEnforceRevisions(blobId0));
        assertFalse(blobStore.getRetractable(blobId0));
        assertFalse(blobStore.getTransferable(blobId0));

        bytes20 blobId1 = blobStore.create(FLAG_UPDATABLE | FLAG_ENFORCE_REVISIONS | FLAG_RETRACTABLE | FLAG_TRANSFERABLE | FLAG_ANONYMOUS, hex"00");
        assertTrue(blobStore.getExists(blobId1));
        assertEq(blobStore.getOwner(blobId1), 0);
        assertEq(blobStore.getRevisionCount(blobId1), 1);
        assertTrue(blobStore.getUpdatable(blobId1));
        assertTrue(blobStore.getEnforceRevisions(blobId1));
        assertTrue(blobStore.getRetractable(blobId1));
        assertTrue(blobStore.getTransferable(blobId1));

        assertFalse(blobId0 == blobId1);
    }

    function testThrowsCreateNewRevisionNotUpdatable() {
        bytes20 blobId = blobStore.create(0, hex"00");
        blobStore.createNewRevision(blobId, hex"00");
    }

    function testCreateNewRevision() {
        bytes20 blobId = blobStore.create(FLAG_UPDATABLE, hex"00");
        uint revisionId = blobStore.createNewRevision(blobId, hex"00");
        assertEq(revisionId, 1);
        assertEq(blobStore.getRevisionCount(blobId), 2);
    }

    function testThrowsUpdateLatestRevisionNotUpdatable() {
        bytes20 blobId = blobStore.create(0, hex"00");
        blobStore.updateLatestRevision(blobId, hex"00");
    }

    function testThrowsUpdateLatestRevisionEnforceRevisions() {
        bytes20 blobId = blobStore.create(FLAG_UPDATABLE | FLAG_ENFORCE_REVISIONS, hex"00");
        blobStore.updateLatestRevision(blobId, hex"00");
    }

    function testUpdateLatestRevision() {
        bytes20 blobId = blobStore.create(FLAG_UPDATABLE, hex"00");
        blobStore.updateLatestRevision(blobId, hex"00");
        assertEq(blobStore.getRevisionCount(blobId), 1);
    }

}


up contract

up contract

/* Part of this contract is from the solidity documentation
TODO: Set a license.
*/

pragma solidity ^0.4.8;

/// @title Fund for donations.
contract AbieFund {

    uint public membershipFee = 0.1 ether;
    uint public nbMembers;
    uint public registrationTime = 1 years;
    uint[2] public voteLength = [1 weeks, 1 weeks];
    uint MAX_DELEGATION_DEPTH=1000;
    address NOT_COUNTED=0;
    address COUNTED=1;

    event Donated(address donor, uint amount);

    enum ProposalType {AddMember,FundProject} // Different types of proposals.
    enum VoteType {Abstain,Yes,No} // Different value of a vote.

    struct Proposal
    {
        bytes32 name;       // short name (up to 32 bytes).
        uint voteYes;     // number of YES votes.
        uint voteNo;     // number of abstention. Number of No can be deduced.
        address recipient;     // address the funds will be sent.
        uint value;         // quantity of wei to be sent.
        bytes32 data;       // data of the transaction.
        ProposalType proposalType;  // type of the proposal.
        uint endDate; // when the vote will be closed.
        address lastMemberCounted; // last one who was counted or NOT_COUNTED (if the count has not started) or COUNTED (if all the votes has been counted);
        bool executed; // True if the proposal have been executed.
        mapping (address => VoteType) vote; // vote of the party.
    }

    // Is also a node list.
    struct Member
    {
        uint registration;  // date of registration, if 0 the member does not exist.
        address[2] delegate; // delegate[proposalType] gives the delegate for the type.
        address prev;
        address succ; // This should not be deleted even when the member is.
        uint proposalStoppedOnHim; // Number of proposals stopped on him.
    }

    mapping (address => Member) public members;

    // Double chained list.
    struct DoubleChainedList
    {
        address first;
        address last;
    }

    // Chain containing all members to iterate on.
    DoubleChainedList memberList;

    Proposal[] public proposals;

    /// Require at least price to be paid.
    modifier costs(uint price) {
        if (msg.value<price)
            throw;
        _;
    }

    /// Require the caller to be a member.
    modifier isMember() {
        if(!isValidMember(msg.sender))
            throw;
        _;
    }

    /// @param initialMembers First members of the organization.
    function AbieFund(address[] initialMembers) {
        for (uint i;i<initialMembers.length;++i){
            Member member=members[initialMembers[i]];
            member.registration=now;
            if (i==0) { // initialize the list with the first member
                memberList.first=initialMembers[0];
                memberList.last=initialMembers[0];
            } else { // add members
                addMember(initialMembers[i]);
            }
        }
        nbMembers=initialMembers.length;
    }

    // Add the member m to the member list.
    // Assume that there is at least 1 member registrated.
    function addMember(address m) private {
        members[memberList.last].succ=m;
        members[m].prev=memberList.last;
        memberList.last=m;
    }

    /** Choose a delegate.
      * @param proposalType 0 for AddMember, 1 for FundProject.
      * @param target account to delegate to.
      */
    function setDelegate(uint8 proposalType, address target)
    {
        members[msg.sender].delegate[proposalType] = target;
    }

    /// Receive funds.
    function () payable {
        Donated(msg.sender, msg.value);
    }

    /// Ask membership of the fund.
    function askMembership () payable costs(membershipFee) {
        Donated(msg.sender,msg.value); // Register the donation.

        // Create a proposal to add the member.
        proposals.push(Proposal({
        name: 0x0,
        voteYes: 0,
        voteNo: 0,
        recipient: msg.sender,
        value: 0x0,
        data: 0x0,
        proposalType: ProposalType.AddMember,
        endDate: now + voteLength[uint256(ProposalType.AddMember)],
        lastMemberCounted: 0,
        executed: false
        }));
    }

    /** Vote for a proposal.
     *  @param proposalID ID of the proposal to count votes from.
     *  @param voteType Yes or No.
     */
    function vote (uint proposalID, VoteType voteType) isMember {
        Proposal proposal = proposals[proposalID];
        if (proposal.vote[msg.sender] != VoteType.Abstain) // Has already voted.
            throw;
        if (proposal.endDate < now) // Vote is over.
            throw;

        proposals[proposalID].vote[msg.sender] = voteType;
    }

    /** Count all the votes. You can call this function if gas limit is not an issue.
     *  @param proposalID ID of the proposal to count votes from.
     */
    function countAllVotes (uint proposalID) {
        countVotes (proposalID,uint(-1));
    }

    /** Count up to max of the votes.
     *  You may have to call this function multiple times if counting once reach the gas limit.
     *  This function is necessary to count in multiple times if counting reach gas limit.
     *  We just count the number of Yes and Abstention, so we will deduce the number of No.
     *  @param proposalID ID of the proposal to count votes from.
     *  @param max maximum to count.
     */
    function countVotes (uint proposalID, uint max) {
        Proposal proposal = proposals[proposalID];
        address current;
        if (proposal.endDate > now) // You can't count while the vote is not over.
            throw;
        if (proposal.lastMemberCounted == COUNTED) // The count is already over
            throw;

        if (proposal.lastMemberCounted == NOT_COUNTED)
            current = memberList.first;
        else
            current = proposal.lastMemberCounted;

        while (max-- != 0) {
            Member member=members[current];
            address delegate=current;
            if(isValidMember(current)) {
                uint depth=0;
                // Seach the final vote.
                while (true){
                    VoteType vote=proposal.vote[delegate];
                    if (vote==VoteType.Abstain) { // Look at the delegate
                        depth+=1;
                        delegate=members[delegate].delegate[uint(proposal.proposalType)]; // Find the delegate.
                        if (delegate==current // The delegation chain forms a circle.
                            || delegate==0  // Has not set a delegate.
                            || depth>MAX_DELEGATION_DEPTH) { // Too much depth, we must limit it in order to avoid some circle of delegation made to consume too much gaz.
                           break;
                        }
                    }
                    if (vote==VoteType.Yes) {
                        proposal.voteYes+=1;
                        break;
                    } else if (vote==VoteType.No) {
                        proposal.voteNo+=1;
                        break;
                    }
                }
            } else {
                // TODO: Delete the members if they are expired.
            }

            current=member.succ; // In next iteration start from the next node.
            if (current==0) { // We reached the last member.
                proposal.lastMemberCounted=COUNTED;
                break;
            }

        }

    }

    function executeAddMemberProposal(uint proposalID) {
        Proposal proposal = proposals[proposalID];
        if (proposal.proposalType != ProposalType.AddMember) // Not a proposal to add a member.
            throw;
        if (!isExecutable(proposalID)) // Proposal was not approved.
            throw;
        proposal.executed=true; // The proposal will be executed.
        addMember(proposal.recipient);
    }

    /// CONSTANTS ///

    /** Return the delegate.
     *  @param member member to get the delegate from.
     *  @param proposalType 0 for AddMember, 1 for FundProject.
     */
    function getDelegate(address member, uint8 proposalType) constant returns (address){
        return members[member].delegate[proposalType];
    }

    /** Return true if the proposal is validated, false otherwise.
     *  @param proposalID ID of the proposal to count votes from.
     */
    function isExecutable(uint proposalID) constant returns (bool) {
        Proposal proposal = proposals[proposalID];

        if (proposal.lastMemberCounted != COUNTED) // Not counted yet.
            return false;
        if (proposal.executed) // The proposal has already been executed.
            return false;
        if (proposal.value>this.balance) // Not enough to execute it.
            return false;

        return (proposal.voteYes>proposal.voteNo);
    }

    function isValidMember(address m) constant returns(bool) {
        if (members[m].registration==0) // Not a member.
            return false;
        if (members[m].registration+registrationTime<now) // Has expired.
            return false;
        return true;
    }

}

/* Part of this contract is from the solidity documentation
TODO: Set a license.
*/

pragma solidity ^0.4.8;

/// @title Fund for donations.
contract AbieFund {

    uint membershipFee = 0.1 ether;
    uint nbMembers;
    uint registrationTime = 1 years;
    uint[2] voteLength = [1 weeks, 1 weeks];

    event Donated(address donor, uint amount);

    enum ProposalType {AddMember,FundProject} // Different types of proposals.
    enum VoteType {Abstain,Yes,No} // Different value of a vote.

    struct Proposal
    {
        bytes32 name;       // short name (up to 32 bytes).
        uint voteYes;     // number of YES votes.
        uint voteAbstain;     // number of abstention. Number of No can be deduced.
        address recipient;     // address the funds will be sent.
        uint value;         // quantity of wei to be sent.
        bytes32 data;       // data of the transaction.
        ProposalType proposalType;  // type of the proposal.
        uint endDate; // when the vote will be closed.
        mapping (address => VoteType) vote; // vote of the party.
        mapping (address => bool) voteCounted; // has the vote been counted yet?
    }

    // Is also a node list.
    struct Member
    {
        uint registration;  // date of registration, if 0 the member does not exist.
        address[2] delegate; // delegate[proposalType] gives the delegate for the type.
        address prev;
        address succ;
    }

    mapping (address => Member) public members;

    // Double chained list.
    struct DoubleChainedList
    {
        address first;
        address last;
    }

    // Chain containing all members to iterate on.
    DoubleChainedList memberList;

    Proposal[] public proposals;

    /// Require at least price to be paid.
    modifier costs(uint price) {
        if (msg.value<price)
            throw;
        _;
    }

    /// Require the caller to be a member.
    modifier isMember() {

        if (members[msg.sender].registration==0) // Not a member.
            throw;
        if (members[msg.sender].registration+registrationTime<now) // Has expired.
            throw;
        _;
    }

/*
function insertEnd(List list, Node newNode)
     if list.lastNode == null
         insertBeginning(list, newNode)
     else
         insertAfter(list, list.lastNode, newNode)
*/

    /// @param initialMembers First members of the organization.
    function AbieFund(address[] initialMembers) {
        for (uint i;i<initialMembers.length;++i){
            Member member=members[initialMembers[i]];
            member.registration=now;
            if (i==0) { // initialize the list with the first member
                memberList.first=initialMembers[0];
                memberList.last=initialMembers[0];
            } else { // add members
                addMember(initialMembers[i]);
            }
        }
        nbMembers=initialMembers.length;
    }

    // Add the member m to the member list.
    // Assume that there is at least 1 member registrated.
    function addMember(address m) private {
        members[memberList.last].succ=m;
        members[m].prev=memberList.last;
        memberList.last=m;
    }

    /** Choose a delegate.
      * @param proposalType 0 for AddMember, 1 for FundProject.
      * @param target account to delegate to.
      */
    function setDelegate(uint8 proposalType, address target) isMember
    {
        members[msg.sender].delegate[proposalType] = target;
    }

    /// Receive funds.
    function () payable {
        Donated(msg.sender, msg.value);
    }

    /// Ask membership of the fund.
    function askMembership () payable costs(membershipFee) {
        Donated(msg.sender,msg.value); // Register the donation.
        // Create a proposal to add the member.
        proposals.push(Proposal({
        name: 0x0,
        voteYes: 0,
        voteAbstain: 0,
        recipient: msg.sender,
        value: 0x0,
        data: 0x0,
        proposalType: ProposalType.AddMember,
        endDate: now + voteLength[uint256(ProposalType.AddMember)]
        }));
    }

    /** Vote for a proposal.
     *  @param proposalID ID of the proposal to count votes from.
     *  @param voteType Yes or No.
     */
    function vote (uint proposalID, VoteType voteType) isMember {
        Proposal proposal = proposals[proposalID];
        if (proposal.vote[msg.sender] != VoteType.Abstain) // Has already voted.
            throw;
        if (proposal.endDate < now) // Vote is over.
            throw;
        proposals[proposalID].vote[msg.sender] = voteType;
    }

    /** Count all the votes of a proposal.
     *  @param proposalID ID of the proposal to count votes from.
     */
    function countAllVotes (uint proposalID) {
        countVotes (proposalID, memberList.first, 0);
    }

    /** Count the votes from start to end.
     *  This function is necessary to count in multiple times if counting reach gas limit.
     *  We just count the number of Yes and Abstention, so we will deduce the number of No.
     *  @param proposalID ID of the proposal to count votes from.
     *  @param start First member to count from.
     *  @param end   Count votes of all members before this one (end is not included), put to 0 to count till the end.
     */
    function countVotes (uint proposalID, address start, address end) {
        Proposal proposal = proposals[proposalID];

        while (start != end) {
            Member member=members[start];
            if (proposal.voteCounted[start]==false) { // Verify the vote has not been counted yet.
                proposal.voteCounted[start]=true; // The vote will be counted.

                address delegate=start;
                // Seach the final vote.
                while (true){
                    VoteType vote=proposal.vote[delegate];
                    if (vote==VoteType.Abstain) { // Look at the delegate
                        delegate=members[delegate].delegate[uint(proposal.proposalType)]; // Find the delegate.
                        if (delegate==start || delegate==0) { // Back to the start of the loop or failed to name a delegate.
                           proposal.voteAbstain+=1;
                           break;
                        }
                    }
                    if (vote==VoteType.Yes) {
                        proposal.voteYes+=1;
                        break;
                    }
                    // Else voted No, so we don't count.
                }

            }
            start=member.succ; // In next iteration start from the next node.

            // TODO: Delete the members if they are expired.
        }

    }

    /// CONSTANTS ///

    /** Return the delegate.
     *  @param member member to get the delegate from.
     *  @param proposalType 0 for AddMember, 1 for FundProject.
     */
    function getDelegate(address member, uint8 proposalType) constant returns (address){
        return members[member].delegate[proposalType];
    }

    /** Return true if the proposal is validated, false otherwise.
     *  @param proposalID ID of the proposal to count votes from.
     */
    function isValidated(uint proposalID) returns (bool) {
        Proposal proposal = proposals[proposalID];
        if (proposal.endDate > now)
            return false;

        // Deduce the number of votes No by discounting the number of abstentions and votes Yes.
        uint voteNo=nbMembers;
        if (voteNo-proposal.voteYes>voteNo) // Overflow somewhere.
            return false;
        else
            voteNo-=proposal.voteYes;

        if (voteNo-proposal.voteAbstain>voteNo) // Overflow somewhere.
            return false;
        else
            voteNo-=proposal.voteAbstain;

        return (proposal.voteYes>voteNo);
    }

}


Updated

Updated

contract NewPoll {

  //defines the poll
  struct Poll {
    address owner;
    string title;
    uint votelimit;
    string options;
    uint deadline;
    bool status;
    uint numVotes;
  }

  // event tracking of all votes
  event NewVote(string votechoice);

  // declare a public poll called p
  Poll public p;

  //initiator function that stores the necessary poll information
  function NewPoll(string _options, string _title, uint _votelimit, uint _deadline) {
    p.owner = msg.sender;
    p.options = _options;
    p.title = _title;
    p.votelimit = _votelimit;
    p.deadline = _deadline;
    p.status = true;
    p.numVotes = 0;
  }

  //function for user vote. input is a string choice
  function vote(string choice) returns (bool) {
    if (msg.sender != p.owner || p.status != true) {
      return false;
    }

    p.numVotes += 1;
    NewVote(choice);

    // if votelimit reached, end poll
    if (p.votelimit > 0) {
      if (p.numVotes >= p.votelimit) {
        endPoll();
      }
    }
    return true;
  }

  //when time or vote limit is reached, set the poll status to false
  function endPoll() returns (bool) {
    if (msg.sender != p.owner) {
      return false;
    }
    p.status = false;
    return true;
  }
}

contract NewPoll {

  //defines the poll
  struct Poll {
    address owner;
    string title;
    uint votelimit;
    string options;
    uint deadline;
    bool status;
    uint numVotes;
  }

  bytes32[] public votes;
  Poll public p;

  //initiator function that stores the necessary poll information
  function NewPoll(string _options, string _title, uint _votelimit, uint _deadline) {
    p.owner = msg.sender;
    p.options = _options;
    p.title = _title;
    p.votelimit = _votelimit;
    p.deadline = _deadline;
    p.status = true;
    p.numVotes = 0;
  }

  //function for user vote. input is a string choice
  function vote(bytes32 choice) returns (bool) {
    if (msg.sender != p.owner || p.status != true) {
      return false;
    }
    votes[votes.length++] = choice;
    p.numVotes += 1;
    if (p.votelimit > 0) {
        if (p.numVotes >= p.votelimit) {
          endPoll();
        }
    }
    return true;
  }

  //when time or vote limit is reached, set the poll status to false
  function endPoll() returns (bool) {
    if (msg.sender != p.owner) {
      return false;
    }
    p.status = false;
    return true;
  }
}