Changed lib/Voting.sol behaviour by #11

Changed lib/Voting.sol behaviour by #11

import 'token/Token.sol';
import './AddressList.sol';

/**
 * @dev The library for voting actions.
 *      This data contains stack of voters, its opinion and count of shares.
 */
library Voting {
    /* Voting structure */
    struct Poll {
        /* Stack of all voters */
        AddressList.Data            voters;
        /* Stack of all variants by value */
        AddressList.Data            poll;
        /* Count of shares for given variant */
        mapping(address => uint)    valueOf;
        /* Count of shares for given voter */
        mapping(address => uint)    shareOf;
        /* Poll variant for given voter */
        mapping(address => address) pollOf;
    }

    using AddressList for AddressList.Data;

    /**
     * @dev Current high value poll
     * @param _poll ref to `Poll` structure
     * @return current value
     */
    function current(Poll storage _poll) constant returns (address)
    { return _poll.poll.first(); }

    /**
     * @dev Increase poll shares for given variant
     * @param _poll ref to `Poll` structure
     * @param _variant voter variant value
     * @param _shares token represents vote
     * @param _count how much votes are given
     */
    function up(Poll storage _poll, address _voter, address _variant,
                Token _shares, uint _count) {
        // Try to transfer count of shares from voter to self
        if (!_shares.transferFrom(_voter, this, _count))
            throw;

        // Increase shares and set the poll
        _poll.shareOf[_voter]   += _count;
        _poll.pollOf[_voter]     = _variant;
        _poll.valueOf[_variant] += _count;

        // Append voter if not in list
        if (!_poll.voters.contains(_voter))
            _poll.voters.append(_voter);

        // Append variant if not in list
        if (!_poll.poll.contains(_variant))
            _poll.poll.append(_variant);

        // Shift voter in the stack
        shiftLeft(_poll, _variant);
    }

    /**
     * @dev Decrease poll shares of given voter
     * @param _poll ref to `Poll` structure
     * @param _count how much shares will decreased
     */
    function down(Poll storage _poll, address _voter, Token _shares, uint _count) {
        // So I can refund no more that gives from voter
        var refund = _poll.shareOf[_voter] > _count ? _count : _poll.shareOf[_voter];

        // Transfer shares
        _shares.transfer(_voter, refund);
        _poll.shareOf[_voter]               -= refund;
        _poll.valueOf[_poll.pollOf[_voter]] -= refund;

        // Shift right or drop when no shares
        if (_poll.shareOf[_voter] > 0) {
            shiftRight(_poll, _poll.pollOf[_voter]);
        } else {
            _poll.voters.remove(_voter);
        }
    }

    /*
     * Shifting mechanism
     * Thesys: the stack of variants should be sorted by valueOf value.
     * Solution:
     *  - `up` call: variant shifted left while his valueOf value is large
     *  - `down` call: varian shifted right in the stack while valueOf value is low
     */

    function shiftLeft(Poll storage _poll, address _variant) internal {
        var value = _poll.valueOf[_variant];
        var left  = _poll.poll.prev(_variant);

        while (left != 0 && _poll.valueOf[left] < value) {
            _poll.poll.swap(left, _voter);
            left = _poll.poll.prev(_variant);
        }
    }

    function shiftRight(Poll storage _poll, address _variant) internal {
        var value = _poll.valueOf[_variant];
        var right = _poll.poll.next(_variant);

        while (right != 0 && _poll.valueOf[right] > value) {
            _poll.poll.swap(right, _variant);
            right = _poll.poll.next(_variant);
        }
    }
}

import 'token/Token.sol';
import './AddressList.sol';

/**
 * @dev The library for voting actions.
 *      This data contains stack of voters, its opinion and count of shares.
 */
library Voting {
    /* Voting structure */
    struct Poll {
        /* Stack of all voters by value */
        AddressList.Data            voters;
        /* Count of shares for given voter */
        mapping(address => uint)    shareOf;
        /* Poll variant for given voter */
        mapping(address => address) pollOf;
    }

    using AddressList for AddressList.Data;

    /**
     * @dev Current high value poll
     * @param _poll ref to `Poll` structure
     * @return current value
     */
    function current(Poll storage _poll) constant returns (address)
    { return _poll.pollOf[_poll.voters.first()]; }

    /**
     * @dev Increase poll shares for given variant
     * @param _poll ref to `Poll` structure
     * @param _value voter variant value
     * @param _shares token represents vote
     * @param _count how much votes are given
     */
    function up(Poll storage _poll, address _voter, address _value,
                Token _shares, uint _count) {
        // Try to transfer count of shares from voter to self
        if (!_shares.transferFrom(_voter, this, _count))
            throw;

        // Increase shares and set the poll
        _poll.shareOf[_voter] += _count;
        _poll.pollOf[_voter]   = _value;

        // Append voter if not in list
        if (!_poll.voters.contains(_voter))
            _poll.voters.append(_voter);

        // Shift voter in the stack
        shiftLeft(_poll, _voter);
    }

    /**
     * @dev Decrease poll shares of given voter
     * @param _poll ref to `Poll` structure
     * @param _count how much shares will decreased
     */
    function down(Poll storage _poll, address _voter, Token _shares, uint _count) {
        // So I can refund no more that gives from voter
        var refund = _poll.shareOf[_voter] > _count ? _count : _poll.shareOf[_voter];

        // Transfer shares
        _shares.transfer(_voter, refund);
        _poll.shareOf[_voter] -= refund;

        // Shift right or drop when no shares
        if (_poll.shareOf[_voter] > 0) {
            shiftRight(_poll, _voter);
        } else {
            _poll.voters.remove(_voter);
        }
    }

    /*
     * Shifting mechanism
     * Thesys: the stack of voters should be sorted by shareOf value.
     * Solution:
     *  - `up` call: voter shifted left while his shareOf value is large
     *  - `down` call: voter shifted right in the stack while shareOf value is low
     */

    function shiftLeft(Poll storage _poll, address _voter) internal {
        var value = _poll.shareOf[_voter];
        var left  = _poll.voters.prev(_voter);

        while (left != 0 && _poll.shareOf[left] < value) {
            _poll.voters.swap(left, _voter);
            left = _poll.voters.prev(_voter);
        }
    }

    function shiftRight(Poll storage _poll, address _voter) internal {
        var value = _poll.shareOf[_voter];
        var right = _poll.voters.next(_voter);

        while (right != 0 && _poll.shareOf[right] > value) {
            _poll.voters.swap(right, _voter);
            right = _poll.voters.next(_voter);
        }
    }
}


reduce cost of getWeekday, getSecond, getMinute, and getHour

contract DateTime {
        /*
         *  Date and Time utilities for ethereum contracts
         *
         *  address: 0x1a6184cd4c5bea62b0116de7962ee7315b7bcbce
         */
        struct DateTime {
                uint16 year;
                uint8 month;
                uint8 day;
                uint8 hour;
                uint8 minute;
                uint8 second;
                uint8 weekday;
        }

        uint constant DAY_IN_SECONDS = 86400;
        uint constant YEAR_IN_SECONDS = 31536000;
        uint constant LEAP_YEAR_IN_SECONDS = 31622400;

        uint constant HOUR_IN_SECONDS = 3600;
        uint constant MINUTE_IN_SECONDS = 60;

        uint16 constant ORIGIN_YEAR = 1970;

        function isLeapYear(uint16 year) constant returns (bool) {
                if (year % 4 != 0) {
                        return false;
                }
                if (year % 100 != 0) {
                        return true;
                }
                if (year % 400 != 0) {
                        return false;
                }
                return true;
        }

        function parseTimestamp(uint timestamp) internal returns (DateTime dt) {
                uint secondsAccountedFor = 0;
                uint buf;
                uint8 i;

                dt.year = ORIGIN_YEAR;

                // Year
                while (true) {
                        if (isLeapYear(dt.year)) {
                                buf = LEAP_YEAR_IN_SECONDS;
                        }
                        else {
                                buf = YEAR_IN_SECONDS;
                        }

                        if (secondsAccountedFor + buf > timestamp) {
                                break;
                        }
                        dt.year += 1;
                        secondsAccountedFor += buf;
                }

                // Month
                uint8[12] monthDayCounts;
                monthDayCounts[0] = 31;
                if (isLeapYear(dt.year)) {
                        monthDayCounts[1] = 29;
                }
                else {
                        monthDayCounts[1] = 28;
                }
                monthDayCounts[2] = 31;
                monthDayCounts[3] = 30;
                monthDayCounts[4] = 31;
                monthDayCounts[5] = 30;
                monthDayCounts[6] = 31;
                monthDayCounts[7] = 31;
                monthDayCounts[8] = 30;
                monthDayCounts[9] = 31;
                monthDayCounts[10] = 30;
                monthDayCounts[11] = 31;

                uint secondsInMonth;
                for (i = 0; i < monthDayCounts.length; i++) {
                        secondsInMonth = DAY_IN_SECONDS * monthDayCounts[i];
                        if (secondsInMonth + secondsAccountedFor > timestamp) {
                                dt.month = i + 1;
                                break;
                        }
                        secondsAccountedFor += secondsInMonth;
                }

                // Day
                for (i = 0; i < monthDayCounts[dt.month - 1]; i++) {
                        if (DAY_IN_SECONDS + secondsAccountedFor > timestamp) {
                                dt.day = i + 1;
                                break;
                        }
                        secondsAccountedFor += DAY_IN_SECONDS;
                }

                // Hour
                for (i = 0; i < 24; i++) {
                        if (HOUR_IN_SECONDS + secondsAccountedFor > timestamp) {
                                dt.hour = i;
                                break;
                        }
                        secondsAccountedFor += HOUR_IN_SECONDS;
                }

                // Minute
                for (i = 0; i < 60; i++) {
                        if (MINUTE_IN_SECONDS + secondsAccountedFor > timestamp) {
                                dt.minute = i;
                                break;
                        }
                        secondsAccountedFor += MINUTE_IN_SECONDS;
                }

                if (timestamp - secondsAccountedFor > 60) {
                        __throw();
                }

                // Second
                dt.second = uint8(timestamp - secondsAccountedFor);

                // Day of week.
                buf = timestamp / DAY_IN_SECONDS;
                dt.weekday = uint8((buf + 3) % 7);
        }

        function getYear(uint timestamp) constant returns (uint16) {
                return parseTimestamp(timestamp).year;
        }

        function getMonth(uint timestamp) constant returns (uint16) {
                return parseTimestamp(timestamp).month;
        }

        function getDay(uint timestamp) constant returns (uint16) {
                return parseTimestamp(timestamp).day;
        }

        function getHour(uint timestamp) constant returns (uint16) {
                return uint16((timestamp / 60 / 60) % 24);
        }

        function getMinute(uint timestamp) constant returns (uint16) {
                return uint16((timestamp / 60) % 60);
        }

        function getSecond(uint timestamp) constant returns (uint16) {
                return uint16(timestamp % 60);
        }

        function getWeekday(uint timestamp) constant returns (uint8) {
                return uint8((timestamp / DAY_IN_SECONDS + 3) % 7);
        }

        function toTimestamp(uint16 year, uint8 month, uint8 day) constant returns (uint timestamp) {
                return toTimestamp(year, month, day, 0, 0, 0);
        }

        function toTimestamp(uint16 year, uint8 month, uint8 day, uint8 hour) constant returns (uint timestamp) {
                return toTimestamp(year, month, day, hour, 0, 0);
        }

        function toTimestamp(uint16 year, uint8 month, uint8 day, uint8 hour, uint8 minute) constant returns (uint timestamp) {
                return toTimestamp(year, month, day, hour, minute, 0);
        }

        function toTimestamp(uint16 year, uint8 month, uint8 day, uint8 hour, uint8 minute, uint8 second) constant returns (uint timestamp) {
                uint16 i;

                // Year
                for (i = ORIGIN_YEAR; i < year; i++) {
                        if (isLeapYear(i)) {
                                timestamp += LEAP_YEAR_IN_SECONDS;
                        }
                        else {
                                timestamp += YEAR_IN_SECONDS;
                        }
                }

                // Month
                uint8[12] monthDayCounts;
                monthDayCounts[0] = 31;
                if (isLeapYear(year)) {
                        monthDayCounts[1] = 29;
                }
                else {
                        monthDayCounts[1] = 28;
                }
                monthDayCounts[2] = 31;
                monthDayCounts[3] = 30;
                monthDayCounts[4] = 31;
                monthDayCounts[5] = 30;
                monthDayCounts[6] = 31;
                monthDayCounts[7] = 31;
                monthDayCounts[8] = 30;
                monthDayCounts[9] = 31;
                monthDayCounts[10] = 30;
                monthDayCounts[11] = 31;

                for (i = 1; i < month; i++) {
                        timestamp += DAY_IN_SECONDS * monthDayCounts[i - 1];
                }

                // Day
                timestamp += DAY_IN_SECONDS * (day - 1);

                // Hour
                timestamp += HOUR_IN_SECONDS * (hour);

                // Minute
                timestamp += MINUTE_IN_SECONDS * (minute);

                // Second
                timestamp += second;

                return timestamp;
        }

        function __throw() {
                uint[] arst;
                arst[1];
        }
}

contract DateTime {
        /*
         *  Date and Time utilities for ethereum contracts
         *
         *  address: 0x1a6184cd4c5bea62b0116de7962ee7315b7bcbce
         */
        struct DateTime {
                uint16 year;
                uint8 month;
                uint8 day;
                uint8 hour;
                uint8 minute;
                uint8 second;
                uint8 weekday;
        }

        uint constant DAY_IN_SECONDS = 86400;
        uint constant YEAR_IN_SECONDS = 31536000;
        uint constant LEAP_YEAR_IN_SECONDS = 31622400;

        uint constant HOUR_IN_SECONDS = 3600;
        uint constant MINUTE_IN_SECONDS = 60;

        uint16 constant ORIGIN_YEAR = 1970;

        function isLeapYear(uint16 year) constant returns (bool) {
                if (year % 4 != 0) {
                        return false;
                }
                if (year % 100 != 0) {
                        return true;
                }
                if (year % 400 != 0) {
                        return false;
                }
                return true;
        }

        function parseTimestamp(uint timestamp) internal returns (DateTime dt) {
                uint secondsAccountedFor = 0;
                uint buf;
                uint8 i;

                dt.year = ORIGIN_YEAR;

                // Year
                while (true) {
                        if (isLeapYear(dt.year)) {
                                buf = LEAP_YEAR_IN_SECONDS;
                        }
                        else {
                                buf = YEAR_IN_SECONDS;
                        }

                        if (secondsAccountedFor + buf > timestamp) {
                                break;
                        }
                        dt.year += 1;
                        secondsAccountedFor += buf;
                }

                // Month
                uint8[12] monthDayCounts;
                monthDayCounts[0] = 31;
                if (isLeapYear(dt.year)) {
                        monthDayCounts[1] = 29;
                }
                else {
                        monthDayCounts[1] = 28;
                }
                monthDayCounts[2] = 31;
                monthDayCounts[3] = 30;
                monthDayCounts[4] = 31;
                monthDayCounts[5] = 30;
                monthDayCounts[6] = 31;
                monthDayCounts[7] = 31;
                monthDayCounts[8] = 30;
                monthDayCounts[9] = 31;
                monthDayCounts[10] = 30;
                monthDayCounts[11] = 31;

                uint secondsInMonth;
                for (i = 0; i < monthDayCounts.length; i++) {
                        secondsInMonth = DAY_IN_SECONDS * monthDayCounts[i];
                        if (secondsInMonth + secondsAccountedFor > timestamp) {
                                dt.month = i + 1;
                                break;
                        }
                        secondsAccountedFor += secondsInMonth;
                }

                // Day
                for (i = 0; i < monthDayCounts[dt.month - 1]; i++) {
                        if (DAY_IN_SECONDS + secondsAccountedFor > timestamp) {
                                dt.day = i + 1;
                                break;
                        }
                        secondsAccountedFor += DAY_IN_SECONDS;
                }

                // Hour
                for (i = 0; i < 24; i++) {
                        if (HOUR_IN_SECONDS + secondsAccountedFor > timestamp) {
                                dt.hour = i;
                                break;
                        }
                        secondsAccountedFor += HOUR_IN_SECONDS;
                }

                // Minute
                for (i = 0; i < 60; i++) {
                        if (MINUTE_IN_SECONDS + secondsAccountedFor > timestamp) {
                                dt.minute = i;
                                break;
                        }
                        secondsAccountedFor += MINUTE_IN_SECONDS;
                }

                if (timestamp - secondsAccountedFor > 60) {
                        __throw();
                }

                // Second
                dt.second = uint8(timestamp - secondsAccountedFor);

                // Day of week.
                buf = timestamp / DAY_IN_SECONDS;
                dt.weekday = uint8((buf + 3) % 7);
        }

        function getYear(uint timestamp) constant returns (uint16) {
                return parseTimestamp(timestamp).year;
        }

        function getMonth(uint timestamp) constant returns (uint16) {
                return parseTimestamp(timestamp).month;
        }

        function getDay(uint timestamp) constant returns (uint16) {
                return parseTimestamp(timestamp).day;
        }

        function getHour(uint timestamp) constant returns (uint16) {
                return parseTimestamp(timestamp).hour;
        }

        function getMinute(uint timestamp) constant returns (uint16) {
                return parseTimestamp(timestamp).minute;
        }

        function getSecond(uint timestamp) constant returns (uint16) {
                return parseTimestamp(timestamp).second;
        }

        function getWeekday(uint timestamp) constant returns (uint8) {
                return parseTimestamp(timestamp).weekday;
        }

        function toTimestamp(uint16 year, uint8 month, uint8 day) constant returns (uint timestamp) {
                return toTimestamp(year, month, day, 0, 0, 0);
        }

        function toTimestamp(uint16 year, uint8 month, uint8 day, uint8 hour) constant returns (uint timestamp) {
                return toTimestamp(year, month, day, hour, 0, 0);
        }

        function toTimestamp(uint16 year, uint8 month, uint8 day, uint8 hour, uint8 minute) constant returns (uint timestamp) {
                return toTimestamp(year, month, day, hour, minute, 0);
        }

        function toTimestamp(uint16 year, uint8 month, uint8 day, uint8 hour, uint8 minute, uint8 second) constant returns (uint timestamp) {
                uint16 i;

                // Year
                for (i = ORIGIN_YEAR; i < year; i++) {
                        if (isLeapYear(i)) {
                                timestamp += LEAP_YEAR_IN_SECONDS;
                        }
                        else {
                                timestamp += YEAR_IN_SECONDS;
                        }
                }

                // Month
                uint8[12] monthDayCounts;
                monthDayCounts[0] = 31;
                if (isLeapYear(year)) {
                        monthDayCounts[1] = 29;
                }
                else {
                        monthDayCounts[1] = 28;
                }
                monthDayCounts[2] = 31;
                monthDayCounts[3] = 30;
                monthDayCounts[4] = 31;
                monthDayCounts[5] = 30;
                monthDayCounts[6] = 31;
                monthDayCounts[7] = 31;
                monthDayCounts[8] = 30;
                monthDayCounts[9] = 31;
                monthDayCounts[10] = 30;
                monthDayCounts[11] = 31;

                for (i = 1; i < month; i++) {
                        timestamp += DAY_IN_SECONDS * monthDayCounts[i - 1];
                }

                // Day
                timestamp += DAY_IN_SECONDS * (day - 1);

                // Hour
                timestamp += HOUR_IN_SECONDS * (hour);

                // Minute
                timestamp += MINUTE_IN_SECONDS * (minute);

                // Second
                timestamp += second;

                return timestamp;
        }

        function __throw() {
                uint[] arst;
                arst[1];
        }
}


- Added new attribute called minimumContractAmt for easier calculations

pragma solidity ^0.4.2;

import "./priced.sol";
import "./stateMachine.sol";
import "./accessRestricted.sol";

/// @title Brehon Contract
contract BrehonContract is
    priced,
    stateMachine,
    accessRestricted {

  struct Party {
    address addr;
    uint deposit;
    bool contractAccepted;
  }

  struct Brehon {
    address addr;
    bool contractAccepted;
    uint fixedFee;
    uint disputeFee;
  }

  struct Resolution {
    address proposerAddr;
    uint awardPartyA;
    uint awardPartyB;
    bool partyAAccepted;
    bool partyBAccepted;
  }

  int8 public appealLevel;
  uint public transactionAmount;
  uint public minimumContractAmount;
  bytes32 public contractTermsHash;
  Party public partyA;
  Party public partyB;
  Brehon public primaryBrehon;
  Brehon public secondaryBrehon;
  Brehon public tertiaryBrehon;
  Brehon public activeBrehon;

  mapping (address => uint) awards;
  Resolution public proposedSettlement;

  uint appealPeriodInDays = 5;
  uint public appealPeriodStartTime;

  event ExecutionStarted(address _caller, uint _totalDeposits);
  event ContractDisputed(address _disputingParty, address _activeBrehon);
  event AppealPeriodStarted(int8 _appealLevel, uint _startTime, address _activeBrehon, uint _awardPartyA, uint _awardPartyB);
  //TODO: Provide the information about the party which appaled
  event AppealRaised(int8 _appealLevel, address _activeBrehon);
  event SettlementProposed(address _proposingParty, uint _awardPartyA, uint _awardPartyB);
  event DisputeResolved(uint _awardPartyA, uint _awardPartyB);

  modifier eitherByParty(Party _party1, Party _party2)
  {
    if (msg.sender != _party1.addr &&
        msg.sender != _party2.addr)
        throw;
    _;
  }

  modifier afterContractStarts()
  {
    if(stage != Stages.Execution &&
       stage != Stages.Dispute &&
       stage != Stages.AppealPeriod &&
       stage != Stages.Appeal)
        throw;
    _;
  }

  modifier eitherByBrehon(Brehon _brehon1, Brehon _brehon2, Brehon _brehon3)
  {
    if (msg.sender != _brehon1.addr ||
        msg.sender != _brehon2.addr ||
        msg.sender != _brehon3.addr)
        throw;
    _;
  }

  modifier onlyByBrehon(Brehon _brehon) {
    if (msg.sender != _brehon.addr)
        throw;
    _;
  }

  function BrehonContract(
      address _partyA,
      address _partyB,
      uint _transactionAmount,
      bytes32 _contractTermsHash,
      address _primaryBrehon,
      uint _primaryBrehonFixedFee,
      uint _primaryBrehonDisputeFee,
      address _secondaryBrehon,
      uint _secondaryBrehonFixedFee,
      uint _secondaryBrehonDisputeFee,
      address _tertiaryBrehon,
      uint _tertiaryBrehonFixedFee,
      uint _tertiaryBrehonDisputeFee
  ) {
    partyA.addr = _partyA;
    transactionAmount = _transactionAmount;
    contractTermsHash = _contractTermsHash;

    partyB.addr = _partyB;

    primaryBrehon.addr = _primaryBrehon;
    primaryBrehon.fixedFee = _primaryBrehonFixedFee;
    primaryBrehon.disputeFee = _primaryBrehonDisputeFee;

    secondaryBrehon.addr = _secondaryBrehon;
    secondaryBrehon.fixedFee = _secondaryBrehonFixedFee;
    secondaryBrehon.disputeFee = _secondaryBrehonDisputeFee;

    tertiaryBrehon.addr = _tertiaryBrehon;
    tertiaryBrehon.fixedFee = _tertiaryBrehonFixedFee;
    tertiaryBrehon.disputeFee = _tertiaryBrehonDisputeFee;

    minimumContractAmount = primaryBrehon.fixedFee + primaryBrehon.disputeFee +
        secondaryBrehon.fixedFee + secondaryBrehon.disputeFee +
        tertiaryBrehon.fixedFee + tertiaryBrehon.disputeFee +
        transactionAmount;

    //Defaults
    stage = Stages.Negotiation;
    appealLevel = -1;
    partyA.contractAccepted = false;
    partyA.deposit = 0;

    partyB.contractAccepted = false;
    partyB.deposit = 0;

    primaryBrehon.contractAccepted = false;
    secondaryBrehon.contractAccepted = false;
    tertiaryBrehon.contractAccepted = false;
  }

  function acceptContract()
    atStage(Stages.Negotiation)
  {
      if (msg.sender == partyA.addr) {
          partyA.contractAccepted = true;
      } else if (msg.sender == partyB.addr) {
          partyB.contractAccepted = true;
      } else if(msg.sender == primaryBrehon.addr) {
          primaryBrehon.contractAccepted = true;
      } else if(msg.sender == secondaryBrehon.addr) {
          secondaryBrehon.contractAccepted = true;
      } else if(msg.sender == tertiaryBrehon.addr) {
          tertiaryBrehon.contractAccepted = true;
      } else throw;
  }

  function deposit()
    payable
  {
      if(msg.sender == partyA.addr) {
          partyA.deposit += msg.value;
      } else if (msg.sender == partyB.addr) {
          partyB.deposit += msg.value;
      } else throw;
  }

  function startContract()
    atStage(Stages.Negotiation)
    eitherByParty(partyA, partyB)
  {
      if(!partyA.contractAccepted ||
         !partyB.contractAccepted ||
         !primaryBrehon.contractAccepted ||
         !secondaryBrehon.contractAccepted ||
         !tertiaryBrehon.contractAccepted) throw;

      if ((partyA.deposit + partyB.deposit) >=
          minimumContractAmount) {
             ExecutionStarted(msg.sender, partyA.deposit + partyB.deposit);
             stage = Stages.Execution;
      } else throw;
  }

  function raiseDispute()
    atStage(Stages.Execution)
    eitherByParty(partyA, partyB)
  {
    stage = Stages.Dispute;
    appealLevel = 0;
    activeBrehon = primaryBrehon;
    ContractDisputed(msg.sender, primaryBrehon.addr);
  }

  function adjudicate(uint _awardPartyA, uint _awardPartyB)
    atStage(Stages.Dispute)
    onlyByBrehon(activeBrehon)
  {
    if((_awardPartyA + _awardPartyB) > (partyA.deposit + partyB.deposit)) throw;

    stage = Stages.AppealPeriod;
    appealPeriodStartTime = now;

    awards[partyA.addr] = _awardPartyA;
    awards[partyB.addr] = _awardPartyB;

    AppealPeriodStarted(appealLevel, appealPeriodInDays, activeBrehon.addr, _awardPartyA, _awardPartyB);
  }

  function getActiveJudgmentByParty(address _partyAddress)
    returns (uint)
  {
      if(_partyAddress != partyA.addr &&
         _partyAddress != partyB.addr) throw;
    return awards[_partyAddress];
  }

  function claimFunds()
    timedTransition(appealPeriodStartTime, appealPeriodInDays, Stages.AppealPeriod, Stages.Completed)
    atStage(Stages.Completed)
    eitherByParty(partyA, partyB)
    returns (bool)
  {
    uint amount = awards[msg.sender];
    awards[msg.sender] = 0;
    if(msg.sender.send(amount)) {
      return true;
    } else {
      awards[msg.sender] = amount;
      return false;
    }
  }

  function raiseAppeal()
    atStage(Stages.AppealPeriod)
    eitherByParty(partyA, partyB)
  {
    stage = Stages.Dispute;
    appealLevel = 1;

    activeBrehon = secondaryBrehon;

    AppealRaised(appealLevel, activeBrehon.addr);
  }

  function raise2ndAppeal()
    atStage(Stages.AppealPeriod)
    eitherByParty(partyA, partyB)
  {
    stage = Stages.Dispute;
    appealLevel = 2;

    activeBrehon = tertiaryBrehon;

    AppealRaised(appealLevel, activeBrehon.addr);
  }

  function proposeSettlement(uint _awardPartyA, uint _awardPartyB)
    afterContractStarts()
    eitherByParty(partyA, partyB)
  {
      proposedSettlement.proposerAddr = msg.sender;
      proposedSettlement.awardPartyA = _awardPartyA;
      proposedSettlement.awardPartyB = _awardPartyB;
      if (msg.sender == partyA.addr) {
          proposedSettlement.partyAAccepted = true;
          proposedSettlement.partyBAccepted = false;
      } else if (msg.sender == partyB.addr) {
          proposedSettlement.partyAAccepted = false;
          proposedSettlement.partyBAccepted = true;
      }

      SettlementProposed(msg.sender, _awardPartyA, _awardPartyB);
  }

  function acceptSettlement(uint _awardPartyA, uint _awardPartyB)
    afterContractStarts()
    eitherByParty(partyA, partyB)
  {
      if((proposedSettlement.awardPartyA != _awardPartyA) ||
         (proposedSettlement.awardPartyB != _awardPartyB))
          throw;

      if(msg.sender == partyA.addr) {
        proposedSettlement.partyAAccepted = true;
      }

      if(msg.sender == partyB.addr) {
        proposedSettlement.partyBAccepted = true;
      }

      if(proposedSettlement.partyAAccepted && proposedSettlement.partyBAccepted) {
        stage = Stages.Completed;
        DisputeResolved(_awardPartyA, _awardPartyB);
      }
  }
}

pragma solidity ^0.4.2;

import "./priced.sol";
import "./stateMachine.sol";
import "./accessRestricted.sol";

/// @title Brehon Contract
contract BrehonContract is
    priced,
    stateMachine,
    accessRestricted {

  struct Party {
    address addr;
    uint deposit;
    bool contractAccepted;
  }

  struct Brehon {
    address addr;
    bool contractAccepted;
    uint fixedFee;
    uint disputeFee;
  }

  struct Resolution {
    address proposerAddr;
    uint awardPartyA;
    uint awardPartyB;
    bool partyAAccepted;
    bool partyBAccepted;
  }

  int8 public appealLevel;
  uint public transactionAmount;
  bytes32 public contractTermsHash;
  Party public partyA;
  Party public partyB;
  Brehon public primaryBrehon;
  Brehon public secondaryBrehon;
  Brehon public tertiaryBrehon;
  Brehon public activeBrehon;

  mapping (address => uint) awards;
  Resolution public proposedSettlement;

  uint appealPeriodInDays = 5;
  uint public appealPeriodStartTime;

  event ExecutionStarted(address _caller, uint _totalDeposits);
  event ContractDisputed(address _disputingParty, address _activeBrehon);
  event AppealPeriodStarted(int8 _appealLevel, uint _startTime, address _activeBrehon, uint _awardPartyA, uint _awardPartyB);
  //TODO: Provide the information about the party which appaled
  event AppealRaised(int8 _appealLevel, address _activeBrehon);
  event SettlementProposed(address _proposingParty, uint _awardPartyA, uint _awardPartyB);
  event DisputeResolved(uint _awardPartyA, uint _awardPartyB);

  modifier eitherByParty(Party _party1, Party _party2)
  {
    if (msg.sender != _party1.addr &&
        msg.sender != _party2.addr)
        throw;
    _;
  }

  modifier afterContractStarts()
  {
    if(stage != Stages.Execution &&
       stage != Stages.Dispute &&
       stage != Stages.AppealPeriod &&
       stage != Stages.Appeal)
        throw;
    _;
  }

  modifier eitherByBrehon(Brehon _brehon1, Brehon _brehon2, Brehon _brehon3)
  {
    if (msg.sender != _brehon1.addr ||
        msg.sender != _brehon2.addr ||
        msg.sender != _brehon3.addr)
        throw;
    _;
  }

  modifier onlyByBrehon(Brehon _brehon) {
    if (msg.sender != _brehon.addr)
        throw;
    _;
  }

  function BrehonContract(
      address _partyA,
      address _partyB,
      uint _transactionAmount,
      bytes32 _contractTermsHash,
      address _primaryBrehon,
      uint _primaryBrehonFixedFee,
      uint _primaryBrehonDisputeFee,
      address _secondaryBrehon,
      uint _secondaryBrehonFixedFee,
      uint _secondaryBrehonDisputeFee,
      address _tertiaryBrehon,
      uint _tertiaryBrehonFixedFee,
      uint _tertiaryBrehonDisputeFee
  ) {
    partyA.addr = _partyA;
    transactionAmount = _transactionAmount;
    contractTermsHash = _contractTermsHash;

    partyB.addr = _partyB;

    primaryBrehon.addr = _primaryBrehon;
    primaryBrehon.fixedFee = _primaryBrehonFixedFee;
    primaryBrehon.disputeFee = _primaryBrehonDisputeFee;

    secondaryBrehon.addr = _secondaryBrehon;
    secondaryBrehon.fixedFee = _secondaryBrehonFixedFee;
    secondaryBrehon.disputeFee = _secondaryBrehonDisputeFee;

    tertiaryBrehon.addr = _tertiaryBrehon;
    tertiaryBrehon.fixedFee = _tertiaryBrehonFixedFee;
    tertiaryBrehon.disputeFee = _tertiaryBrehonDisputeFee;

    //Defaults
    stage = Stages.Negotiation;
    appealLevel = -1;
    partyA.contractAccepted = false;
    partyA.deposit = 0;

    partyB.contractAccepted = false;
    partyB.deposit = 0;

    primaryBrehon.contractAccepted = false;
    secondaryBrehon.contractAccepted = false;
    tertiaryBrehon.contractAccepted = false;
  }

  function acceptContract()
    atStage(Stages.Negotiation)
  {
      if (msg.sender == partyA.addr) {
          partyA.contractAccepted = true;
      } else if (msg.sender == partyB.addr) {
          partyB.contractAccepted = true;
      } else if(msg.sender == primaryBrehon.addr) {
          primaryBrehon.contractAccepted = true;
      } else if(msg.sender == secondaryBrehon.addr) {
          secondaryBrehon.contractAccepted = true;
      } else if(msg.sender == tertiaryBrehon.addr) {
          tertiaryBrehon.contractAccepted = true;
      } else throw;
  }

  function deposit()
    payable
  {
      if(msg.sender == partyA.addr) {
          partyA.deposit += msg.value;
      } else if (msg.sender == partyB.addr) {
          partyB.deposit += msg.value;
      } else throw;
  }

  function startContract()
    atStage(Stages.Negotiation)
    eitherByParty(partyA, partyB)
  {
      if(!partyA.contractAccepted ||
         !partyB.contractAccepted ||
         !primaryBrehon.contractAccepted ||
         !secondaryBrehon.contractAccepted ||
         !tertiaryBrehon.contractAccepted) throw;

      if ((partyA.deposit + partyB.deposit) >=
          (primaryBrehon.fixedFee + primaryBrehon.disputeFee +
          secondaryBrehon.fixedFee + secondaryBrehon.disputeFee +
          tertiaryBrehon.fixedFee + tertiaryBrehon.disputeFee +
          transactionAmount)
         ) {
             ExecutionStarted(msg.sender, partyA.deposit + partyB.deposit);
             stage = Stages.Execution;
      } else throw;
  }

  function raiseDispute()
    atStage(Stages.Execution)
    eitherByParty(partyA, partyB)
  {
    stage = Stages.Dispute;
    appealLevel = 0;
    activeBrehon = primaryBrehon;
    ContractDisputed(msg.sender, primaryBrehon.addr);
  }

  function adjudicate(uint _awardPartyA, uint _awardPartyB)
    atStage(Stages.Dispute)
    onlyByBrehon(activeBrehon)
  {
    if((_awardPartyA + _awardPartyB) > (partyA.deposit + partyB.deposit)) throw;

    stage = Stages.AppealPeriod;
    appealPeriodStartTime = now;

    awards[partyA.addr] = _awardPartyA;
    awards[partyB.addr] = _awardPartyB;

    AppealPeriodStarted(appealLevel, appealPeriodInDays, activeBrehon.addr, _awardPartyA, _awardPartyB);
  }

  function getActiveJudgmentByParty(address _partyAddress)
    returns (uint)
  {
      if(_partyAddress != partyA.addr &&
         _partyAddress != partyB.addr) throw;
    return awards[_partyAddress];
  }

  function claimFunds()
    timedTransition(appealPeriodStartTime, appealPeriodInDays, Stages.AppealPeriod, Stages.Completed)
    atStage(Stages.Completed)
    eitherByParty(partyA, partyB)
    returns (bool)
  {
    uint amount = awards[msg.sender];
    awards[msg.sender] = 0;
    if(msg.sender.send(amount)) {
      return true;
    } else {
      awards[msg.sender] = amount;
      return false;
    }
  }

  function raiseAppeal()
    atStage(Stages.AppealPeriod)
    eitherByParty(partyA, partyB)
  {
    stage = Stages.Dispute;
    appealLevel = 1;

    activeBrehon = secondaryBrehon;

    AppealRaised(appealLevel, activeBrehon.addr);
  }

  function raise2ndAppeal()
    atStage(Stages.AppealPeriod)
    eitherByParty(partyA, partyB)
  {
    stage = Stages.Dispute;
    appealLevel = 2;

    activeBrehon = tertiaryBrehon;

    AppealRaised(appealLevel, activeBrehon.addr);
  }

  function proposeSettlement(uint _awardPartyA, uint _awardPartyB)
    afterContractStarts()
    eitherByParty(partyA, partyB)
  {
      proposedSettlement.proposerAddr = msg.sender;
      proposedSettlement.awardPartyA = _awardPartyA;
      proposedSettlement.awardPartyB = _awardPartyB;
      if (msg.sender == partyA.addr) {
          proposedSettlement.partyAAccepted = true;
          proposedSettlement.partyBAccepted = false;
      } else if (msg.sender == partyB.addr) {
          proposedSettlement.partyAAccepted = false;
          proposedSettlement.partyBAccepted = true;
      }

      SettlementProposed(msg.sender, _awardPartyA, _awardPartyB);
  }

  function acceptSettlement(uint _awardPartyA, uint _awardPartyB)
    afterContractStarts()
    eitherByParty(partyA, partyB)
  {
      if((proposedSettlement.awardPartyA != _awardPartyA) ||
         (proposedSettlement.awardPartyB != _awardPartyB))
          throw;

      if(msg.sender == partyA.addr) {
        proposedSettlement.partyAAccepted = true;
      }

      if(msg.sender == partyB.addr) {
        proposedSettlement.partyBAccepted = true;
      }

      if(proposedSettlement.partyAAccepted && proposedSettlement.partyBAccepted) {
        stage = Stages.Completed;
        DisputeResolved(_awardPartyA, _awardPartyB);
      }
  }
}


stubbing out a few more public methods

stubbing out a few more public methods

/*
    Copyright 2017 Phillip A. Elsasser

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
*/

pragma solidity 0.4.18;

import "./Creatable.sol";
import "./oraclize/oraclizeAPI.sol";
import "./libraries/MathLib.sol";
import "./libraries/HashLib.sol";
import "zeppelin-solidity/contracts/token/ERC20.sol";
import "zeppelin-solidity/contracts/token/SafeERC20.sol";

//TODO: fix style issues
//      add failsafe for pool distribution.
//      push as much into library as possible
//      create mappings for deposit tokens and balance of collateral pool
//      think about circuit breaker in case of issues
//      do we want to use ETH or WETH for ETH based contract?

/// @title MarketContract first example of a MarketProtocol contract using Oraclize services
/// @author Phil Elsasser <phil@marketprotcol.io>
contract MarketContract is Creatable, usingOraclize  {
    using MathLib for uint256;
    using MathLib for int;
    using HashLib for address;
    using SafeERC20 for ERC20;

    struct UserNetPosition {
        address userAddress;
        Position[] positions;   // all open positions (lifo upon exit - allows us to not reindex array!)
        int netPosition;        // net position across all prices / executions
    }

    struct Position {
        uint price;
        int qty;
    }

    struct Order {
        address maker;
        address taker;
        address feeRecipient;
        uint makerFee;
        uint takerFee;
        uint qty;
        uint price;
        uint8 makerSide;            // 0=Buy 1=Sell
        uint expirationTimeStamp;
        bytes32 orderHash;
    }

    // constants
    string public CONTRACT_NAME;
    address public BASE_TOKEN_ADDRESS;
    ERC20 public BASE_TOKEN;
    uint public PRICE_CAP;
    uint public PRICE_FLOOR;
    uint public PRICE_DECIMAL_PLACES;   // how to convert the pricing from decimal format (if valid) to integer
    uint public QTY_DECIMAL_PLACES;     // how many tradeable units make up a whole pricing increment
    uint public EXPIRATION;
    string public ORACLE_DATA_SOURCE;
    string public ORACLE_QUERY;
    uint public ORACLE_QUERY_REPEAT;
    uint8 constant public BUY_SIDE = 0;
    uint8 constant public SELL_SIDE = 1;
    uint constant public COST_PER_QUERY = 2 finney;    // leave static for now, price of first query from oraclize is 0
    uint constant public QUERY_CALLBACK_GAS = 300000;

    // state variables
    string public lastPriceQueryResult;
    uint public lastPrice;
    bool public isSettled;
    mapping(bytes32 => bool) validQueryIDs;

    // accounting
    mapping(address => UserNetPosition) addressToUserPosition;
    mapping(address => uint) userAddressToAccountBalance;   // stores account balances allowed to be allocated to orders
    mapping (bytes32 => int) public filledOrderQty;
    mapping (bytes32 => int) public cancelledOrderQty;
    uint collateralPoolBalance = 0;                         // current balance of all collateral committed

    // events
    event OracleQuerySuccess();
    event OracleQueryFailed();
    event UpdatedLastPrice(string price);
    event ContractSettled();
    event UpdatedUserBalance(address user, uint balance);
    event UpdatedPoolBalance(uint balance);

    /// @param contractName viewable name of this contract (BTC/ETH, LTC/ETH, etc)
    /// @param baseTokenAddress address of the ERC20 token that will be used for collateral and pricing
    /// @param oracleDataSource a data-source such as "URL", "WolframAlpha", "IPFS"
    /// see http://docs.oraclize.it/#ethereum-quick-start-simple-query
    /// @param oracleQuery see http://docs.oraclize.it/#ethereum-quick-start-simple-query for examples
    /// @param oracleQueryRepeatSeconds how often to repeat this callback to check for settlement, more frequent
    /// queries require more gas and may not be needed.
    /// @param floorPrice minimum tradeable price of this contract, contract enters settlement if breached
    /// @param capPrice maximum tradeable price of this contract, contract enters settlement if breached
    /// @param priceDecimalPlaces number of decimal places to convert our queried price from a floating point to
    /// an integer
    /// @param qtyDecimalPlaces decimal places to multiply traded qty by.
    /// @param secondsToExpiration - second from now that this contract expires and enters settlement
    function MarketContract(
        string contractName,
        address baseTokenAddress,
        string oracleDataSource,
        string oracleQuery,
        uint oracleQueryRepeatSeconds,
        uint floorPrice,
        uint capPrice,
        uint priceDecimalPlaces,
        uint qtyDecimalPlaces,
        uint secondsToExpiration
    ) public payable {

        require(capPrice > floorPrice);
        oraclize_setProof(proofType_TLSNotary | proofStorage_IPFS);
        CONTRACT_NAME = contractName;
        BASE_TOKEN_ADDRESS = baseTokenAddress;
        BASE_TOKEN = ERC20(baseTokenAddress);
        PRICE_CAP = capPrice;
        PRICE_FLOOR = floorPrice;
        EXPIRATION = now + secondsToExpiration;
        ORACLE_DATA_SOURCE = oracleDataSource;
        ORACLE_QUERY = oracleQuery;
        ORACLE_QUERY_REPEAT = oracleQueryRepeatSeconds;
        PRICE_DECIMAL_PLACES = priceDecimalPlaces;
        QTY_DECIMAL_PLACES = qtyDecimalPlaces;
        require(checkSufficientStartingBalance(secondsToExpiration));
        queryOracle();  // schedules recursive calls to oracle
    }

    /*
    // EXTERNAL METHODS
   */

    // @param userAddress address to return position for
    // @return the users current open position.
    function getUserPosition(address userAddress) external view returns (int)  {
        return addressToUserPosition[userAddress].netPosition;
    }

    function depositEtherForTrading() external payable {
        // should we allow ether or force users to use WETH?
    }

    /// @notice deposits tokens to the smart contract to fund the user account and provide needed tokens for collateral
    /// pool upon trade matching.
    /// @param depositAmount qty of ERC20 tokens to deposit to the smart contract to cover open orders and collateral
    function depositTokensForTrading(uint256 depositAmount) external {
        // user must call approve!
        BASE_TOKEN.safeTransferFrom(msg.sender, this, depositAmount);
        uint256 balanceAfterDeposit = userAddressToAccountBalance[msg.sender].add(depositAmount);
        userAddressToAccountBalance[msg.sender] = balanceAfterDeposit;
        UpdatedUserBalance(msg.sender, balanceAfterDeposit);
    }

    /// @notice removes token from users trading account
    /// @param withdrawAmount qty of token to attempt to withdraw
    function withdrawTokens(uint256 withdrawAmount) external {
        require(userAddressToAccountBalance[msg.sender] >= withdrawAmount);   // ensure sufficient balance
        uint256 balanceAfterWithdrawal = userAddressToAccountBalance[msg.sender].subtract(withdrawAmount);
        userAddressToAccountBalance[msg.sender] = balanceAfterWithdrawal;   // update balance before external call!
        BASE_TOKEN.safeTransfer(msg.sender, withdrawAmount);
        UpdatedUserBalance(msg.sender, balanceAfterWithdrawal);
    }

    // @notice called by a participant wanting to trade a specific order
    /// @param maker address of the maker of this order
    /// @param taker address of the designated taker or address(0) if publicly available to be traded
    /// @param feeRecipient address of a fee recipient, optional
    /// @param makerFee amount of MKT token for maker fee
    /// @param takerFee amount of MKT token for taker fee
    /// @param price of the order
    /// @param orderQty quantity of the order
    /// @param qtyToFill quantity taker is willing to fill (max)
    /// @param expirationTimeStamp last valid timestamp of the order (seconds since epoch)
    /// @param v order signature
    /// @param r order signature
    /// @param s order signature
    function tradeOrder(
        address maker,
        address taker,
        address feeRecipient,
        uint makerFee,
        uint takerFee,
        uint price,
        int orderQty,
        int qtyToFill,
        uint expirationTimeStamp,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external {
        require(taker == address(0) || taker == msg.sender);// taker can be anyone, or specifically the caller!
        require(maker != address(0) && maker != taker);     // do not allow self trade
        require(orderQty != 0 && qtyToFill != 0);           // no zero trades

        bytes32 orderHash = address(this).createOrderHash(maker, feeRecipient,
                                makerFee, takerFee, orderQty, price, expirationTimeStamp);

        require(maker.isValidSignature(orderHash, v, r, s));

        if(now >= expirationTimeStamp) {
            // TODO: order is expired, no trade - log this
            return;
        }
        // TODO finish build out

    }

    // @notice called by the maker of an order to attempt to cancel the order before its expiration time stamp
    /// @param maker address of the maker of this order
    /// @param taker address of the designated taker or address(0) if publicly available to be traded
    /// @param feeRecipient address of a fee recipient, optional
    /// @param makerFee amount of MKT token for maker fee
    /// @param takerFee amount of MKT token for taker fee
    /// @param price of the order
    /// @param orderQty quantity of the order
    /// @param qtyToCancel quantity maker is attempting to cancel
    /// @param expirationTimeStamp last valid timestamp of the order (seconds since epoch)
    function cancelOrder(
        address maker,
        address taker,
        address feeRecipient,
        uint makerFee,
        uint takerFee,
        uint price,
        int orderQty,
        int qtyToCancel,
        uint expirationTimeStamp
    ) external {
        require(maker == msg.sender);                                       // only maker can cancel standing order
        require(qtyToCancel != 0 && qtyToCancel.isSameSign(orderQty));      // cannot cancel 0 and signs must match

        if(now >= expirationTimeStamp) {
            // TODO: order is expired, no need to cancel - log this
            return;
        }

        bytes32 orderHash = address(this).createOrderHash(maker, feeRecipient,
                                makerFee, takerFee, orderQty, price, expirationTimeStamp);
        // TODO: check to see if order is fully filled order cancelled
        //
        cancelledOrderQty[orderHash] = cancelledOrderQty[orderHash].add(qtyToCancel);
        // TODO: log
    }

    // @notice called by a user after settlement has occured.  This function will finalize all accounting around any
    // outstanding positions and return all remaining collateral to the caller. This should only be called after
    // settlement has occurred
    function settleAndClose() external {
        require(isSettled);
        // check to see if user has an positions that need to be marked to the settlement price and then closed
        // return all collateral
    }

    /*
    // PUBLIC METHODS
   */

    /// @param queryID of the returning query, this should match our own internal mapping
    /// @param result query to be processed
    /// @param proof result proof
    function __callback(bytes32 queryID, string result, bytes proof) public {
        require(validQueryIDs[queryID]);
        require(msg.sender == oraclize_cbAddress());
        lastPriceQueryResult = result;
        lastPrice = parseInt(result, PRICE_DECIMAL_PLACES);
        UpdatedLastPrice(result);
        delete validQueryIDs[queryID];
        checkSettlement();
        if (!isSettled) {
            queryOracle();  // set up our next query
        }
    }

    /// @notice returns the qty that is no longer available to trade for a given order
    /// @param orderHash hash of order to find filled and cancelled qty
    /// @return int quantity that is no longer able to filled from the supplied order hash
    function getQtyFilledOrCancelledFromOrder(bytes32 orderHash) public view returns (int) {
        return filledOrderQty[orderHash].add(cancelledOrderQty[orderHash]);
    }

    /*
    // PRIVATE METHODS
    */

    /// @param maker address of the maker in the trade
    /// @param taker address of the taker in the trade
    /// @param qty quantity transacted between parties
    /// @param price agreed price of the matched trade.
    function updatePositions(address maker, address taker, int qty, uint price) private {
        updatePosition(maker, qty, price);
        // continue process for taker, but qty is opposite sign for taker
        updatePosition(taker, qty * -1, price);

    }

    /// @param userAddress storage struct containing position information for this user
    /// @param qty signed quantity this users position is changing by, + for buy and - for sell
    /// @param price transacted price of the new position / trade
    function updatePosition(address userAddress, int qty, uint price) private {
        UserNetPosition storage userNetPosition = addressToUserPosition[userAddress];
        if(userNetPosition.netPosition == 0 ||  userNetPosition.netPosition.isSameSign(qty)) {
            // new position or adding to open pos, no collateral returned
            userNetPosition.positions.push(Position(price, qty)); //append array with new position
        }
        else {
            // opposite side from open position, reduce, flattened, or flipped.
            if(userNetPosition.netPosition >= qty * -1) { // pos is reduced of flattened
                reduceUserNetPosition(userNetPosition, qty, price);
            } else {    // pos is flipped, reduce and then create new open pos!
                reduceUserNetPosition(userNetPosition, userNetPosition.netPosition * -1, price); // flatten completely
                int newNetPos = userNetPosition.netPosition + qty;            // the portion remaining after flattening
                userNetPosition.positions.push(Position(price, newNetPos));   // append array with new position
            }
        }
        userNetPosition.netPosition.add(qty);
    }

    /// @dev calculates the needed collateral for a new position and commits it to the pool removing it from the
    /// users account
    /// @param userAddress address of user entering into the position
    /// @param qty signed quantity of the trade
    /// @param price agreed price of trade
    function addUserNetPosition(address userAddress, int qty, uint price) private {
        uint maxLoss;
        if(qty > 0) { // this person is long, calculate max loss from entry price to floor
            maxLoss = price.subtract(PRICE_FLOOR);
        } else { // this person is short, calculate max loss from entry price to ceiling;
            maxLoss = price.subtract(PRICE_CAP);
        }
        uint neededCollateral = maxLoss * qty.abs() * QTY_DECIMAL_PLACES;
        commitCollateralToPool(userAddress, neededCollateral);
    }

    /// @param userNetPos storage struct for this users position
    /// @param qty signed quantity of the qty to reduce this users position by
    /// @param price transacted price
    function reduceUserNetPosition(UserNetPosition storage userNetPos, int qty, uint price) private {
        int qtyToReduce = qty;
        assert(userNetPos.positions.length != 0);  // sanity check
        while(qtyToReduce != 0) {   //TODO: ensure we dont run out of gas here!
            Position storage position = userNetPos.positions[userNetPos.positions.length - 1];  // get the last pos (LIFO)
            if(position.qty.abs() <= qtyToReduce.abs()) { // this position is completely consumed!
                qtyToReduce = qtyToReduce.add(position.qty);
                // TODO: work on refunding correct amount of collateral.
                userNetPos.positions.length--;  // remove this position from our array.
            }
            else {  // this position stays, just reduce the qty.
                position.qty = position.qty.add(qtyToReduce);
                // TODO: return collateral
                //qtyToReduce = 0; // completely reduced now!
                break;
            }
        }
    }

    /// @notice moves collateral from a user's account to the pool upon trade execution.
    /// @param fromAddress address of user entering trade
    /// @param collateralAmount amount of collateral to transfer from user account to collateral pool
    function commitCollateralToPool(address fromAddress, uint collateralAmount) private {
        require(userAddressToAccountBalance[fromAddress] >= collateralAmount);   // ensure sufficient balance
        uint newBalance = userAddressToAccountBalance[fromAddress].subtract(collateralAmount);
        userAddressToAccountBalance[fromAddress] = newBalance;
        collateralPoolBalance = collateralPoolBalance.add(collateralAmount);
        UpdatedUserBalance(fromAddress, newBalance);
        UpdatedPoolBalance(collateralPoolBalance);
    }

    /// @notice withdraws collateral from pool to a user account upon exit or trade settlement
    /// @param toAddress address of user
    /// @param collateralAmount amount to transfer from pool to user.
    function withdrawCollateralFromPool(address toAddress, uint collateralAmount) private {
        require(collateralPoolBalance >= collateralAmount); // ensure sufficient balance
        uint newBalance = userAddressToAccountBalance[toAddress].add(collateralAmount);
        userAddressToAccountBalance[toAddress] = newBalance;
        collateralPoolBalance = collateralPoolBalance.subtract(collateralAmount);
        UpdatedUserBalance(toAddress, newBalance);
        UpdatedPoolBalance(collateralPoolBalance);
    }

    function queryOracle() private {
        if (oraclize_getPrice(ORACLE_DATA_SOURCE) > this.balance) {
            OracleQueryFailed();
            lastPriceQueryResult = "FAILED"; //TODO: failsafe
        } else {
            OracleQuerySuccess();
            bytes32 queryId = oraclize_query(ORACLE_QUERY_REPEAT, ORACLE_DATA_SOURCE, ORACLE_QUERY, QUERY_CALLBACK_GAS);
            validQueryIDs[queryId] = true;
        }
    }

    function checkSettlement() private {
        if(isSettled)   // already settled.
            return;

        if(now > EXPIRATION) {  // note: miners can cheat this by small increments of time (minutes, not hours)
            isSettled = true;   // time based expiration has occurred.
        } else if(lastPrice >= PRICE_CAP || lastPrice <= PRICE_FLOOR) {
            isSettled = true;   // we have breached/touched our pricing bands
        }

        if(isSettled) {
            settleContract();
        }
    }

    function settleContract() private {
        // TODO: set final settlement price, and allow users at this point to call settleAndClose()
        ContractSettled();
    }

    // for now lets require alot of padding for the settlement,
    function checkSufficientStartingBalance(uint secondsToExpiration) private view returns (bool isSufficient) {
        //uint costPerQuery = oraclize_getPrice(ORACLE_DATA_SOURCE); this doesn't work prior to first query(its free)
        uint expectedNoOfQueries = secondsToExpiration / ORACLE_QUERY_REPEAT;
        uint approxGasRequired = COST_PER_QUERY * expectedNoOfQueries;
        return this.balance > (approxGasRequired * 2);
    }
}

/*
    Copyright 2017 Phillip A. Elsasser

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
*/

pragma solidity 0.4.18;

import "./Creatable.sol";
import "./oraclize/oraclizeAPI.sol";
import "./libraries/MathLib.sol";
import "./libraries/HashLib.sol";
import "zeppelin-solidity/contracts/token/ERC20.sol";
import "zeppelin-solidity/contracts/token/SafeERC20.sol";

//TODO: fix style issues
//      add failsafe for pool distribution.
//      push as much into library as possible
//      create mappings for deposit tokens and balance of collateral pool
//      think about circuit breaker in case of issues
//      do we want to use ETH or WETH for ETH based contract?

/// @title MarketContract first example of a MarketProtocol contract using Oraclize services
/// @author Phil Elsasser <phil@marketprotcol.io>
contract MarketContract is Creatable, usingOraclize  {
    using MathLib for uint256;
    using MathLib for int;
    using HashLib for address;
    using SafeERC20 for ERC20;

    struct UserNetPosition {
        address userAddress;
        Position[] positions;   // all open positions (lifo upon exit - allows us to not reindex array!)
        int netPosition;        // net position across all prices / executions
    }

    struct Position {
        uint price;
        int qty;
    }

    struct Order {
        address maker;
        address taker;
        address feeRecipient;
        uint makerFee;
        uint takerFee;
        uint qty;
        uint price;
        uint8 makerSide;            // 0=Buy 1=Sell
        uint expirationTimeStamp;
        bytes32 orderHash;
    }

    // constants
    string public CONTRACT_NAME;
    address public BASE_TOKEN_ADDRESS;
    ERC20 public BASE_TOKEN;
    uint public PRICE_CAP;
    uint public PRICE_FLOOR;
    uint public PRICE_DECIMAL_PLACES;   // how to convert the pricing from decimal format (if valid) to integer
    uint public QTY_DECIMAL_PLACES;     // how many tradeable units make up a whole pricing increment
    uint public EXPIRATION;
    string public ORACLE_DATA_SOURCE;
    string public ORACLE_QUERY;
    uint public ORACLE_QUERY_REPEAT;
    uint8 constant public BUY_SIDE = 0;
    uint8 constant public SELL_SIDE = 1;
    uint constant public COST_PER_QUERY = 2 finney;    // leave static for now, price of first query from oraclize is 0
    uint constant public QUERY_CALLBACK_GAS = 300000;

    // state variables
    string public lastPriceQueryResult;
    uint public lastPrice;
    bool public isSettled;
    mapping(bytes32 => bool) validQueryIDs;

    // accounting
    mapping(address => UserNetPosition) addressToUserPosition;
    mapping(address => uint) userAddressToAccountBalance;   // stores account balances allowed to be allocated to orders
    uint collateralPoolBalance = 0;                         // current balance of all collateral committed

    // events
    event OracleQuerySuccess();
    event OracleQueryFailed();
    event UpdatedLastPrice(string price);
    event ContractSettled();
    event UpdatedUserBalance(address user, uint balance);
    event UpdatedPoolBalance(uint balance);

    /// @param contractName viewable name of this contract (BTC/ETH, LTC/ETH, etc)
    /// @param baseTokenAddress address of the ERC20 token that will be used for collateral and pricing
    /// @param oracleDataSource a data-source such as "URL", "WolframAlpha", "IPFS"
    /// see http://docs.oraclize.it/#ethereum-quick-start-simple-query
    /// @param oracleQuery see http://docs.oraclize.it/#ethereum-quick-start-simple-query for examples
    /// @param oracleQueryRepeatSeconds how often to repeat this callback to check for settlement, more frequent
    /// queries require more gas and may not be needed.
    /// @param floorPrice minimum tradeable price of this contract, contract enters settlement if breached
    /// @param capPrice maximum tradeable price of this contract, contract enters settlement if breached
    /// @param priceDecimalPlaces number of decimal places to convert our queried price from a floating point to
    /// an integer
    /// @param qtyDecimalPlaces decimal places to multiply traded qty by.
    /// @param secondsToExpiration - second from now that this contract expires and enters settlement
    function MarketContract(
        string contractName,
        address baseTokenAddress,
        string oracleDataSource,
        string oracleQuery,
        uint oracleQueryRepeatSeconds,
        uint floorPrice,
        uint capPrice,
        uint priceDecimalPlaces,
        uint qtyDecimalPlaces,
        uint secondsToExpiration
    ) public payable {

        require(capPrice > floorPrice);
        oraclize_setProof(proofType_TLSNotary | proofStorage_IPFS);
        CONTRACT_NAME = contractName;
        BASE_TOKEN_ADDRESS = baseTokenAddress;
        BASE_TOKEN = ERC20(baseTokenAddress);
        PRICE_CAP = capPrice;
        PRICE_FLOOR = floorPrice;
        EXPIRATION = now + secondsToExpiration;
        ORACLE_DATA_SOURCE = oracleDataSource;
        ORACLE_QUERY = oracleQuery;
        ORACLE_QUERY_REPEAT = oracleQueryRepeatSeconds;
        PRICE_DECIMAL_PLACES = priceDecimalPlaces;
        QTY_DECIMAL_PLACES = qtyDecimalPlaces;
        require(checkSufficientStartingBalance(secondsToExpiration));
        queryOracle();  // schedules recursive calls to oracle
    }

    /*
    // EXTERNAL METHODS
   */

    // @param userAddress address to return position for
    // @return the users current open position.
    function getUserPosition(address userAddress) external view returns (int)  {
        return addressToUserPosition[userAddress].netPosition;
    }

    function depositEtherForTrading() external payable {
        // should we allow ether or force users to use WETH?
    }

    /// @notice deposits tokens to the smart contract to fund the user account and provide needed tokens for collateral
    /// pool upon trade matching.
    /// @param depositAmount qty of ERC20 tokens to deposit to the smart contract to cover open orders and collateral
    function depositTokensForTrading(uint256 depositAmount) external {
        // user must call approve!
        BASE_TOKEN.safeTransferFrom(msg.sender, this, depositAmount);
        uint256 balanceAfterDeposit = userAddressToAccountBalance[msg.sender].add(depositAmount);
        userAddressToAccountBalance[msg.sender] = balanceAfterDeposit;
        UpdatedUserBalance(msg.sender, balanceAfterDeposit);
    }

    /// @notice removes token from users trading account
    /// @param withdrawAmount qty of token to attempt to withdraw
    function withdrawTokens(uint256 withdrawAmount) external {
        require(userAddressToAccountBalance[msg.sender] >= withdrawAmount);   // ensure sufficient balance
        uint256 balanceAfterWithdrawal = userAddressToAccountBalance[msg.sender].subtract(withdrawAmount);
        userAddressToAccountBalance[msg.sender] = balanceAfterWithdrawal;   // update balance before external call!
        BASE_TOKEN.safeTransfer(msg.sender, withdrawAmount);
        UpdatedUserBalance(msg.sender, balanceAfterWithdrawal);
    }

    function trade(address maker, address taker) external {
        require(maker != address(0) && maker != taker);     // do not allow self trade
        // TODO validate orders, etc
    }

    // @notice called by a user after settlement has occured.  This function will finalize all accounting around any
    // outstanding positions and return all remaining collateral to the caller. This should only be called after
    // settlement has occurred
    function settleAndClose() external {
        require(isSettled);
        // check to see if user has an positions that need to be marked to the settlement price and then closed
        // return all collateral
    }

    /*
    // PUBLIC METHODS
   */

    /// @param queryID of the returning query, this should match our own internal mapping
    /// @param result query to be processed
    /// @param proof result proof
    function __callback(bytes32 queryID, string result, bytes proof) public {
        require(validQueryIDs[queryID]);
        require(msg.sender == oraclize_cbAddress());
        lastPriceQueryResult = result;
        lastPrice = parseInt(result, PRICE_DECIMAL_PLACES);
        UpdatedLastPrice(result);
        delete validQueryIDs[queryID];
        checkSettlement();
        if (!isSettled) {
            queryOracle();  // set up our next query
        }
    }

    /*
    // PRIVATE METHODS
    */

    /// @param maker address of the maker in the trade
    /// @param taker address of the taker in the trade
    /// @param qty quantity transacted between parties
    /// @param price agreed price of the matched trade.
    function updatePositions(address maker, address taker, int qty, uint price) private {
        updatePosition(maker, qty, price);
        // continue process for taker, but qty is opposite sign for taker
        updatePosition(taker, qty * -1, price);

    }

    /// @param userAddress storage struct containing position information for this user
    /// @param qty signed quantity this users position is changing by, + for buy and - for sell
    /// @param price transacted price of the new position / trade
    function updatePosition(address userAddress, int qty, uint price) private {
        UserNetPosition storage userNetPosition = addressToUserPosition[userAddress];
        if(userNetPosition.netPosition == 0 ||  userNetPosition.netPosition.isSameSign(qty)) {
            // new position or adding to open pos, no collateral returned
            userNetPosition.positions.push(Position(price, qty)); //append array with new position
        }
        else {
            // opposite side from open position, reduce, flattened, or flipped.
            if(userNetPosition.netPosition >= qty * -1) { // pos is reduced of flattened
                reduceUserNetPosition(userNetPosition, qty, price);
            } else {    // pos is flipped, reduce and then create new open pos!
                reduceUserNetPosition(userNetPosition, userNetPosition.netPosition * -1, price); // flatten completely
                int newNetPos = userNetPosition.netPosition + qty;            // the portion remaining after flattening
                userNetPosition.positions.push(Position(price, newNetPos));   // append array with new position
            }
        }
        userNetPosition.netPosition.add(qty);
    }

    /// @dev calculates the needed collateral for a new position and commits it to the pool removing it from the
    /// users account
    /// @param userAddress address of user entering into the position
    /// @param qty signed quantity of the trade
    /// @param price agreed price of trade
    function addUserNetPosition(address userAddress, int qty, uint price) private {
        uint maxLoss;
        if(qty > 0) { // this person is long, calculate max loss from entry price to floor
            maxLoss = price.subtract(PRICE_FLOOR);
        } else { // this person is short, calculate max loss from entry price to ceiling;
            maxLoss = price.subtract(PRICE_CAP);
        }
        uint neededCollateral = maxLoss * qty.abs() * QTY_DECIMAL_PLACES;
        commitCollateralToPool(userAddress, neededCollateral);
    }

    /// @param userNetPos storage struct for this users position
    /// @param qty signed quantity of the qty to reduce this users position by
    /// @param price transacted price
    function reduceUserNetPosition(UserNetPosition storage userNetPos, int qty, uint price) private {
        int qtyToReduce = qty;
        assert(userNetPos.positions.length != 0);  // sanity check
        while(qtyToReduce != 0) {   //TODO: ensure we dont run out of gas here!
            Position storage position = userNetPos.positions[userNetPos.positions.length - 1];  // get the last pos (LIFO)
            if(position.qty.abs() <= qtyToReduce.abs()) { // this position is completely consumed!
                qtyToReduce = qtyToReduce.add(position.qty);
                // TODO: work on refunding correct amount of collateral.
                userNetPos.positions.length--;  // remove this position from our array.
            }
            else {  // this position stays, just reduce the qty.
                position.qty = position.qty.add(qtyToReduce);
                // TODO: return collateral
                //qtyToReduce = 0; // completely reduced now!
                break;
            }
        }
    }

    /// @notice moves collateral from a user's account to the pool upon trade execution.
    /// @param fromAddress address of user entering trade
    /// @param collateralAmount amount of collateral to transfer from user account to collateral pool
    function commitCollateralToPool(address fromAddress, uint collateralAmount) private {
        require(userAddressToAccountBalance[fromAddress] >= collateralAmount);   // ensure sufficient balance
        uint newBalance = userAddressToAccountBalance[fromAddress].subtract(collateralAmount);
        userAddressToAccountBalance[fromAddress] = newBalance;
        collateralPoolBalance = collateralPoolBalance.add(collateralAmount);
        UpdatedUserBalance(fromAddress, newBalance);
        UpdatedPoolBalance(collateralPoolBalance);
    }

    /// @notice withdraws collateral from pool to a user account upon exit or trade settlement
    /// @param toAddress address of user
    /// @param collateralAmount amount to transfer from pool to user.
    function withdrawCollateralFromPool(address toAddress, uint collateralAmount) private {
        require(collateralPoolBalance >= collateralAmount); // ensure sufficient balance
        uint newBalance = userAddressToAccountBalance[toAddress].add(collateralAmount);
        userAddressToAccountBalance[toAddress] = newBalance;
        collateralPoolBalance = collateralPoolBalance.subtract(collateralAmount);
        UpdatedUserBalance(toAddress, newBalance);
        UpdatedPoolBalance(collateralPoolBalance);
    }

    function queryOracle() private {
        if (oraclize_getPrice(ORACLE_DATA_SOURCE) > this.balance) {
            OracleQueryFailed();
            lastPriceQueryResult = "FAILED"; //TODO: failsafe
        } else {
            OracleQuerySuccess();
            bytes32 queryId = oraclize_query(ORACLE_QUERY_REPEAT, ORACLE_DATA_SOURCE, ORACLE_QUERY, QUERY_CALLBACK_GAS);
            validQueryIDs[queryId] = true;
        }
    }

    function checkSettlement() private {
        if(isSettled)   // already settled.
            return;

        if(now > EXPIRATION) {  // note: miners can cheat this by small increments of time (minutes, not hours)
            isSettled = true;   // time based expiration has occurred.
        } else if(lastPrice >= PRICE_CAP || lastPrice <= PRICE_FLOOR) {
            isSettled = true;   // we have breached/touched our pricing bands
        }

        if(isSettled) {
            settleContract();
        }
    }

    function settleContract() private {
        // TODO: set final settlement price, and allow users at this point to call settleAndClose()
        ContractSettled();
    }

    // for now lets require alot of padding for the settlement,
    function checkSufficientStartingBalance(uint secondsToExpiration) private view returns (bool isSufficient) {
        //uint costPerQuery = oraclize_getPrice(ORACLE_DATA_SOURCE); this doesn't work prior to first query(its free)
        uint expectedNoOfQueries = secondsToExpiration / ORACLE_QUERY_REPEAT;
        uint approxGasRequired = COST_PER_QUERY * expectedNoOfQueries;
        return this.balance > (approxGasRequired * 2);
    }
}


adding position getter method

adding position getter method

/*
    Copyright 2017 Phillip A. Elsasser

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
*/

pragma solidity ^0.4.0;

import "./Creatable.sol";
import "./oraclize/oraclizeAPI.sol";
import "./libraries/MathLib.sol";
import "./libraries/HashLib.sol";

//TODO: fix style issues
//      add accounting for users and positions
//      add failsafe for pool distribution.
//      push as much into library as possible
contract MarketContract is Creatable, usingOraclize  {
    using MathLib for uint256;
    using MathLib for int;
    using HashLib for address;

    struct UserNetPosition {
        address userAddress;
        Position[] positions;   // all open positions (lifo upon exit - allows us to not reindex array!)
        int netPosition;        // net position across all prices / executions
    }

    struct Position {
        uint price;
        int qty;
    }

    struct Order {
        address maker;
        address taker;
        address feeRecipient;
        uint makerFee;
        uint takerFee;
        uint qty;
        uint price;
        uint8 makerSide;            // 0=Buy 1=Sell
        uint expirationTimeStamp;
        bytes32 orderHash;
    }

    // constants
    string public CONTRACT_NAME;
    address public BASE_TOKEN;
    uint public PRICE_CAP;
    uint public PRICE_FLOOR;
    uint public PRICE_DECIMAL_PLACES;   // how to convert the pricing from decimal format (if valid) to integer
    uint public EXPIRATION;
    string public ORACLE_DATA_SOURCE;
    string public ORACLE_QUERY;
    uint public ORACLE_QUERY_REPEAT;
    uint8 constant public BUY_SIDE = 0;
    uint8 constant public SELL_SIDE = 1;
    uint constant public COST_PER_QUERY = 2 finney;    // leave static for now, price of first query from oraclize is 0
    uint constant public QUERY_CALLBACK_GAS = 300000;

    // state variables
    string public lastPriceQueryResult;
    uint public lastPrice;
    bool public isExpired;
    mapping(bytes32 => bool) validQueryIDs;

    // accounting
    mapping(address => UserNetPosition) addressToUserPosition;

    // events
    event OracleQuerySuccess();
    event OracleQueryFailed();
    event UpdatedLastPrice(string price);
    event ContractSettled();

    function MarketContract(
        string contractName,
        address baseToken,
        string oracleDataSource,
        string oracleQuery,
        uint oracleQueryRepeatSeconds,
        uint floorPrice,
        uint capPrice,
        uint priceDecimalPlaces,
        uint secondsToExpiration
    ) payable {

        require(capPrice > floorPrice);
        oraclize_setProof(proofType_TLSNotary | proofStorage_IPFS);
        CONTRACT_NAME = contractName;
        BASE_TOKEN = baseToken;
        PRICE_CAP = capPrice;
        PRICE_FLOOR = floorPrice;
        EXPIRATION = now + secondsToExpiration;
        ORACLE_DATA_SOURCE = oracleDataSource;
        ORACLE_QUERY = oracleQuery;
        ORACLE_QUERY_REPEAT = oracleQueryRepeatSeconds;
        PRICE_DECIMAL_PLACES = priceDecimalPlaces;
        require(checkSufficientStartingBalance(secondsToExpiration));
        queryOracle();  // schedules recursive calls to oracle
    }

    function __callback(bytes32 queryID, string result, bytes proof) {
        require(validQueryIDs[queryID]);
        require(msg.sender == oraclize_cbAddress());
        lastPriceQueryResult = result;
        lastPrice = parseInt(result, PRICE_DECIMAL_PLACES);
        UpdatedLastPrice(result);
        delete validQueryIDs[queryID];
        checkSettlement();
        if (!isExpired) {
            queryOracle();  // set up our next query
        }
    }

    function getUserPosition(address userAddress) public view returns (int)  {
        return addressToUserPosition[userAddress].netPosition;
    }

    function trade(address maker, address taker) {
        require(maker != address(0) && maker != taker);     // do not allow self trade
        // TODO validate orders, etc
    }

    function updatePositions(address maker, address taker, int qty, uint price) private {
        updatePosition(addressToUserPosition[maker], qty, price);
        // continue process for taker, but qty is opposite sign for taker
        updatePosition(addressToUserPosition[taker], qty * -1, price);
    }

    function updatePosition(UserNetPosition storage userNetPosition, int qty, uint price) private {
        if(userNetPosition.netPosition == 0 ||  userNetPosition.netPosition.isSameSign(qty)) {
            // new position or adding to open pos, no collateral returned
            userNetPosition.positions.push(Position(price, newNetPos)); //append array with new position
        }
        else {
            // opposite side from open position, reduce, flattened, or flipped.
            if(userNetPosition.netPosition >= qty * -1) { // pos is reduced of flattened
                reduceUserNetPosition(userNetPosition, qty, price);
            } else {    // pos is flipped, reduce and then create new open pos!
                reduceUserNetPosition(userNetPosition, userNetPosition.netPosition * -1, price); // flatten completely
                int newNetPos = userNetPosition.netPosition + qty;            // the portion remaining after flattening
                userNetPosition.positions.push(Position(price, newNetPos));   // append array with new position
            }
        }
        userNetPosition.netPosition += qty;
    }

    function reduceUserNetPosition(UserNetPosition storage userNetPos, int qty, uint price) private {
        int qtyToReduce = qty;
        assert(userNetPos.positions.length != 0);  // sanity check
        while(qtyToReduce != 0) {
            Position storage position = userNetPos.positions[userNetPos.positions.length - 1];  // get the last pos (LIFO)
            if(position.qty.abs() <= qtyToReduce.abs()) { // this position is completely consumed!
                qtyToReduce = qtyToReduce + position.qty;
                // TODO: work on refunding correct amount of collateral.
                userNetPos.positions.length--;  // remove this position from our array.
            }
            else {  // this position stays, just reduce the qty.
                position.qty += qtyToReduce;
                // TODO: return collateral
                //qtyToReduce = 0; // completely reduced now!
                break;
            }
        }
    }

    function commitCollateralToPool(address fromAddress, uint collateralAmount) private {

    }

    function withdrawCollateralFromPool(address toAddress, uint collateralAmount) private {

    }

    function queryOracle() private
    {
        if (oraclize_getPrice(ORACLE_DATA_SOURCE) > this.balance) {
            OracleQueryFailed();
            lastPriceQueryResult = "FAILED"; //TODO: failsafe
        } else {
            OracleQuerySuccess();
            bytes32 queryId = oraclize_query(ORACLE_QUERY_REPEAT, ORACLE_DATA_SOURCE, ORACLE_QUERY, QUERY_CALLBACK_GAS);
            validQueryIDs[queryId] = true;
        }
    }

    function checkSettlement() private
    {
        if(isExpired)   // already expired.
            return;

        if(now > EXPIRATION) {
            isExpired = true;   // time based expiration has occurred.
        } else if(lastPrice >= PRICE_CAP || lastPrice <= PRICE_FLOOR) {
            isExpired = true;   // we have breached/touched our pricing bands
        }

        if(isExpired) {
            settleContract();
        }
    }

    function settleContract() private
    {
        // TODO: build mechanism for distribution of collateral
        ContractSettled();
    }

    // for now lets require alot of padding for the settlement,
    function checkSufficientStartingBalance(uint secondsToExpiration) private returns (bool isSufficient) {
        //uint costPerQuery = oraclize_getPrice(ORACLE_DATA_SOURCE); this doesn't work prior to first query(its free)
        uint expectedNoOfQueries = secondsToExpiration / ORACLE_QUERY_REPEAT;
        uint approxGasRequired = COST_PER_QUERY * expectedNoOfQueries;
        return this.balance > (approxGasRequired * 2);
    }
}

/*
    Copyright 2017 Phillip A. Elsasser

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
*/

pragma solidity ^0.4.0;

import "./Creatable.sol";
import "./oraclize/oraclizeAPI.sol";
import "./libraries/MathLib.sol";
import "./libraries/HashLib.sol";

//TODO: fix style issues
//      add accounting for users and positions
//      add failsafe for pool distribution.
//      push as much into library as possible
contract MarketContract is Creatable, usingOraclize  {
    using MathLib for uint256;
    using MathLib for int;
    using HashLib for address;

    struct UserNetPosition {
        address userAddress;
        Position[] positions;   // all open positions (lifo upon exit - allows us to not reindex array!)
        int netPosition;        // net position across all prices / executions
    }

    struct Position {
        uint price;
        int qty;
    }

    struct Order {
        address maker;
        address taker;
        address feeRecipient;
        uint makerFee;
        uint takerFee;
        uint qty;
        uint price;
        uint8 makerSide;            // 0=Buy 1=Sell
        uint expirationTimeStamp;
        bytes32 orderHash;
    }

    // constants
    string public CONTRACT_NAME;
    address public BASE_TOKEN;
    uint public PRICE_CAP;
    uint public PRICE_FLOOR;
    uint public PRICE_DECIMAL_PLACES;   // how to convert the pricing from decimal format (if valid) to integer
    uint public EXPIRATION;
    string public ORACLE_DATA_SOURCE;
    string public ORACLE_QUERY;
    uint public ORACLE_QUERY_REPEAT;
    uint8 constant public BUY_SIDE = 0;
    uint8 constant public SELL_SIDE = 1;
    uint constant public COST_PER_QUERY = 2 finney;    // leave static for now, price of first query from oraclize is 0
    uint constant public QUERY_CALLBACK_GAS = 300000;

    // state variables
    string public lastPriceQueryResult;
    uint public lastPrice;
    bool public isExpired;
    mapping(bytes32 => bool) validQueryIDs;

    // accounting
    mapping(address => UserNetPosition) addressToUserPosition;

    // events
    event OracleQuerySuccess();
    event OracleQueryFailed();
    event UpdatedLastPrice(string price);
    event ContractSettled();

    function MarketContract(
        string contractName,
        address baseToken,
        string oracleDataSource,
        string oracleQuery,
        uint oracleQueryRepeatSeconds,
        uint floorPrice,
        uint capPrice,
        uint priceDecimalPlaces,
        uint secondsToExpiration
    ) payable {

        require(capPrice > floorPrice);
        oraclize_setProof(proofType_TLSNotary | proofStorage_IPFS);
        CONTRACT_NAME = contractName;
        BASE_TOKEN = baseToken;
        PRICE_CAP = capPrice;
        PRICE_FLOOR = floorPrice;
        EXPIRATION = now + secondsToExpiration;
        ORACLE_DATA_SOURCE = oracleDataSource;
        ORACLE_QUERY = oracleQuery;
        ORACLE_QUERY_REPEAT = oracleQueryRepeatSeconds;
        PRICE_DECIMAL_PLACES = priceDecimalPlaces;
        require(checkSufficientStartingBalance(secondsToExpiration));
        queryOracle();  // schedules recursive calls to oracle
    }

    function __callback(bytes32 queryID, string result, bytes proof) {
        require(validQueryIDs[queryID]);
        require(msg.sender == oraclize_cbAddress());
        lastPriceQueryResult = result;
        lastPrice = parseInt(result, PRICE_DECIMAL_PLACES);
        UpdatedLastPrice(result);
        delete validQueryIDs[queryID];
        checkSettlement();
        if (!isExpired) {
            queryOracle();  // set up our next query
        }
    }

    function trade(address maker, address taker) {
        require(maker != address(0) && maker != taker);     // do not allow self trade
        // TODO validate orders, etc
    }

    function updatePositions(address maker, address taker, int qty, uint price) private {
        updatePosition(addressToUserPosition[maker], qty, price);
        // continue process for taker, but qty is opposite sign for taker
        updatePosition(addressToUserPosition[taker], qty * -1, price);
    }

    function updatePosition(UserNetPosition storage userNetPosition, int qty, uint price) private {
        if(userNetPosition.netPosition == 0 ||  userNetPosition.netPosition.isSameSign(qty)) {
            // new position or adding to open pos, no collateral returned
            userNetPosition.positions.push(Position(price, newNetPos)); //append array with new position
        }
        else {
            // opposite side from open position, reduce, flattened, or flipped.
            if(userNetPosition.netPosition >= qty * -1) { // pos is reduced of flattened
                reduceUserNetPosition(userNetPosition, qty, price);
            } else {    // pos is flipped, reduce and then create new open pos!
                reduceUserNetPosition(userNetPosition, userNetPosition.netPosition * -1, price); // flatten completely
                int newNetPos = userNetPosition.netPosition + qty;            // the portion remaining after flattening
                userNetPosition.positions.push(Position(price, newNetPos));   // append array with new position
            }
        }
        userNetPosition.netPosition += qty;
    }

    function reduceUserNetPosition(UserNetPosition storage userNetPos, int qty, uint price) private {
        int qtyToReduce = qty;
        assert(userNetPos.positions.length != 0);  // sanity check
        while(qtyToReduce != 0) {
            Position storage position = userNetPos.positions[userNetPos.positions.length - 1];  // get the last pos (LIFO)
            if(position.qty.abs() <= qtyToReduce.abs()) { // this position is completely consumed!
                qtyToReduce = qtyToReduce + position.qty;
                // TODO: work on refunding correct amount of collateral.
                userNetPos.positions.length--;  // remove this position from our array.
            }
            else {  // this position stays, just reduce the qty.
                position.qty += qtyToReduce;
                // TODO: return collateral
                //qtyToReduce = 0; // completely reduced now!
                break;
            }
        }
    }

    function commitCollateralToPool(address fromAddress, uint collateralAmount) private
    {

    }

    function withdrawCollateralFromPool(address toAddress, uint collateralAmount) private
    {

    }

    function queryOracle() private
    {
        if (oraclize_getPrice(ORACLE_DATA_SOURCE) > this.balance) {
            OracleQueryFailed();
            lastPriceQueryResult = "FAILED"; //TODO: failsafe
        } else {
            OracleQuerySuccess();
            bytes32 queryId = oraclize_query(ORACLE_QUERY_REPEAT, ORACLE_DATA_SOURCE, ORACLE_QUERY, QUERY_CALLBACK_GAS);
            validQueryIDs[queryId] = true;
        }
    }

    function checkSettlement() private
    {
        if(isExpired)   // already expired.
            return;

        if(now > EXPIRATION) {
            isExpired = true;   // time based expiration has occurred.
        } else if(lastPrice >= PRICE_CAP || lastPrice <= PRICE_FLOOR) {
            isExpired = true;   // we have breached/touched our pricing bands
        }

        if(isExpired) {
            settleContract();
        }
    }

    function settleContract() private
    {
        // TODO: build mechanism for distribution of collateral
        ContractSettled();
    }

    // for now lets require alot of padding for the settlement,
    function checkSufficientStartingBalance(uint secondsToExpiration) private returns (bool isSufficient) {
        //uint costPerQuery = oraclize_getPrice(ORACLE_DATA_SOURCE); this doesn't work prior to first query(its free)
        uint expectedNoOfQueries = secondsToExpiration / ORACLE_QUERY_REPEAT;
        uint approxGasRequired = COST_PER_QUERY * expectedNoOfQueries;
        return this.balance > (approxGasRequired * 2);
    }
}


Fix typo in comment

Fix typo in comment

pragma solidity ^0.4.8;

import "./Ownable.sol";

/// @title Contracts that should not own Ether
/// @author Remco Bloemen <remco@2π.com>
///
/// This tries to block incoming ether to prevent accidental
/// loss of Ether. Should Ether end up in the contrat, it will
/// allow the owner to reclaim this ether.
///
/// @notice Ether can still be send to this contract by:
///  * calling functions labeled `payable`
///  * `selfdestruct(contract_address)`
///  * mining directly to the contract address
contract HasNoEther is Ownable {

  /// Constructor that rejects incoming Ether
  /// @dev The flag `payable` is added so we can access `msg.value`
  ///      without compiler warning. If we leave out payable, then
  ///      Solidity will allow inheriting contracts to implement a
  ///      payable constructor. By doing it this way we prevent a
  ///      payable constructor from working.
  ///      Alternatively we could use assembly to access msg.value.
  function HasNoEther() payable {
    if(msg.value > 0) {
      throw;
    }
  }

  /// Disallow direct send by settings a default function without `payable`
  function() external {
  }

  /// Transfer all Ether owned by the contract to the owner
  /// @dev What if owner is itself a contract marked HasNoEther?
  function reclaimEther() external onlyOwner {
    if(!owner.send(this.balance)) {
      throw;
    }
  }
}

pragma solidity ^0.4.8;

import "./Ownable.sol";

/// @title Contracts that should not own Ether
/// @author Remco Bloemen <remco@2π.com>
///
/// This tries to block incoming ether to prevent accidental
/// loss of Ether. Should Ether end up in the contrat, it will
/// allow the owner to reclaim this ether.
///
/// @notice Ether can still be send to this contract by:
///  * calling functions labeled `payable`
///  * `selfdestruct(contract_address)`
///  * mining directly to the contract address
contract HasNoEther is Ownable {

  /// Constructor that rejects incoming Ether
  /// @dev The flag `payabe` is added so we can access `msg.value`
  ///      without compiler warning. If we leave out payable, then
  ///      Solidity will allow inheriting contracts to implement a
  ///      payable constructor. By doing it this way we prevent a
  ///      payable constructor from working.
  ///      Alternatively we could use assembly to access msg.value.
  function HasNoEther() payable {
    if(msg.value > 0) {
      throw;
    }
  }

  /// Disallow direct send by settings a default function without `payable`
  function() external {
  }

  /// Transfer all Ether owned by the contract to the owner
  /// @dev What if owner is itself a contract marked HasNoEther?
  function reclaimEther() external onlyOwner {
    if(!owner.send(this.balance)) {
      throw;
    }
  }
}


Fix doxygen.

Fix doxygen.

/**
 * @title BlobStore
 * @author Jonathan Brown <jbrown@bluedroplet.com>
 */
contract BlobStore {

    mapping (bytes32 => uint) blobBlock;

    event logBlob(bytes32 indexed hash, bytes blob) anonymous;

    /**
     * @dev Gets the block that a blob is logged in.
     * @param hash sha3 of the blob.
     * @return blockNumber Number of the block that the blob is logged in.
     */
    function getBlobBlock(bytes32 hash) constant returns (uint blockNumber) {
        blockNumber = blobBlock[hash];
    }

    /**
     * @dev Stores a blob in the transaction log.
     * @param blob Blob that should be stored.
     * @return hash sha3 of the blob.
     */
    function storeBlob(bytes blob) returns (bytes32 hash) {
        hash = sha3(blob);
        if (blobBlock[hash] == 0) {
            blobBlock[hash] = block.number;
            logBlob(hash, blob);
        }
    }

}

/**
 * @title BlobStore
 * @author Jonathan Brown <jbrown@bluedroplet.com>
 */
contract BlobStore {

    mapping (bytes32 => uint) blobBlock;

    event logBlob(bytes32 indexed hash, bytes blob) anonymous;

    /**
     * @dev Gets the block that a blob is logged in.
     * @param hash sha3 of the blob.
     * @return Block number.
     */
    function getBlobBlock(bytes32 hash) constant returns (uint blockNumber) {
        blockNumber = blobBlock[hash];
    }

    /**
     * @dev Stores a blob in the transaction log.
     * @param blob Blob that should be stored.
     * @return hash sha3 of the blob.
     */
    function storeBlob(bytes blob) returns (bytes32 hash) {
        hash = sha3(blob);
        if (blobBlock[hash] == 0) {
            blobBlock[hash] = block.number;
            logBlob(hash, blob);
        }
    }

}