initialize clusters mapping

initialize clusters mapping

pragma solidity ^0.4.0;

import "./Math.sol";
import "./abstract/AbstractConcept.sol";
import "./abstract/AbstractConceptRegistry.sol";
import "./abstract/AbstractUser.sol";
import "./abstract/AbstractUserRegistry.sol";

contract Assessment {
  address assessee; //The address of the user being assessed
  address[] assessors;
  address[] finalAssessors; //The assessors who actually give an assessment
  mapping (address => State) assessorState;
  mapping(uint => int[]) clusters; //Initializes mapping to store clusters of scores
  enum State {//The state of the assessors
    Called, //Been called as a potential assessor
    Confirmed, //Confirmed as assessing
    Committed, //Committed a score
    Done, //Completed the assessment processs
    Burned //Entire stake has been burned
  }
  address[] assessorPool; //The addresses of the user's that the assessors are randomly selected from
  address concept;
  address userRegistry;
  address conceptRegistry;
  address math = 0x90B66E80448eb60938FAed4A738dE0D5b630B2Fd;
  uint public startTime;
  uint public size;
  uint cost;
  mapping(address => string[]) public data; //IFFS hashes of data that can be passed between the assessors and the assessee for the assessment to occur
  mapping(address => bytes32) commits;
  mapping(address => uint) stake;
  uint done = 0;
  mapping(address => int8) scores; //could save gas by making this an int8
  mapping(int => bool) inRewardCluster;
  int finalScore;
  event DataSet(address _dataSetter, uint _index);

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

  /*
  @type: modifier
  @name: onlyAssessorAssessee
  @purpose: to only allow the assessors and assessee to call a function to which this modifier is applied
  */
  modifier onlyAssessorAssessee() {
    if(msg.sender != assessee && uint(assessorState[msg.sender]) == 0) {
      throw;
    }
    _;
  }

  // only allow the this contract or the Concept contract that spawned it
  modifier onlyConceptAssessment() {
    if(msg.sender != address(this) && msg.sender != concept) {
      throw;
    }
    _;
  }

  modifier onlyConcept() {
    if(msg.sender != concept) {
      throw;
    }
    _;
  }

  function Assessment(address _assessee, address _userRegistry, address _conceptRegistry, uint _size, uint _cost) {
    assessee = _assessee;
    concept = msg.sender;
    userRegistry = _userRegistry;
    conceptRegistry = _conceptRegistry;
    startTime = block.timestamp;
    size = _size;
    cost = _cost;
    AbstractUser(assessee).notification(concept, 0); //Assessment made
  }

  function cancelAssessment() onlyConceptAssessment() {
    AbstractConcept(concept).setBalance(assessee, AbstractUserRegistry(userRegistry).balances(assessee) + cost*size);
    AbstractUser(assessee).notification(concept, 3); //Assessment Cancled and you have been refunded
    for(uint i = 0; i < assessors.length; i++) {
      AbstractConcept(concept).setBalance(assessors[i], AbstractUserRegistry(userRegistry).balances(assessors[i]) + cost);
      AbstractUser(assessors[i]).notification(concept, 3); //Assessment Cancled and you have been refunded
    }
    suicide(conceptRegistry);
  }

  function addAssessorToPool(address assessor) onlyConcept() returns(bool) {
    if(uint(assessorState[assessor]) == 0) {//Checks if the called assessor hasn't already been called
      AbstractUser(assessor).notification(concept, 1); //Called As A Potential Assessor
      assessorState[assessor] = State.Called; //Sets the state of the assessor as called
      return true;
    }
    else {
      return false; //Returns false if the assessor has already been called
    }
  }

  /*
  @purpose: To recursively set the pool to draw assessors from in the assessment
  @param: uint seed = the seed number for random number generation
  */
  function setAssessorPool(uint seed, address _concept, uint num) onlyConceptAssessment() {
    uint numCalled = 0;
    for(uint k=0; k < num; k++) {
      if(assessorPool.length == size*20){ return; }
      address randomUser = AbstractConcept(_concept).getRandomMember(seed + k);
      if(addAssessorToPool(randomUser)){
        numCalled++;
      }
    }
    uint remaining = num - numCalled;
    if(remaining > 0) {
      for(uint i = 0; i < AbstractConcept(_concept).getParentsLength(); i++) {
          setAssessorPool(seed + assessorPool.length, AbstractConcept(_concept).parents(i), remaining/AbstractConcept(_concept).getParentsLength() + 1);
      }
    }
  }

  function confirmAssessor() {
    if(block.number - startTime <= 15 && assessorState[msg.sender] == State.Called && assessors.length < size && AbstractUserRegistry(userRegistry).balances(msg.sender) >= cost) { //Check if the time to confirm has not passed, that the assessor was actually called, assessors are still needed, and that the assessor has enough of a balance to pay the stake
      assessors.push(msg.sender); //Adds the user that called this function to the array of confirmed assessors
      assessorState[msg.sender] = State.Confirmed; //Sets the assessor's state to confirmed
      stake[msg.sender] = cost; //Sets the current stake value of the assessor to the cost of the assessment
      AbstractConcept(concept).setBalance(msg.sender,AbstractUserRegistry(userRegistry).balances(msg.sender) - cost); //Takes the stake from the assessor
      AbstractUser(msg.sender).notification(concept, 2); //Confirmed for assessing, stake has been taken
    }
    if(assessors.length == size) { //If enough assessors have been called
      notifyStart(); //Assessors and the assessee are notified that the assessmentn has begun
    }
    else if(block.number - startTime > 15 && assessors.length < size){
      cancelAssessment(); //Cancels the assessment if not enough assessors confirm within 15 blocks
    }
  }

  function notifyStart() onlyThis() { //Sends a notification to the assessors and the assessee informing them that the assessment has begun
    for(uint i = 0; i < assessors.length; i++) {
      AbstractUser(assessors[i]).notification(concept, 4); //Assessment Has Started
    }
    AbstractUser(assessee).notification(concept, 4); //Assessment Has Started
  }

  function setData(string _data) onlyAssessorAssessee() { //Allows the assessors and the assessee to publically add data for the purposes of the assessment
    data[msg.sender].push(_data); //Adds the data to an array corresponding to the user that uploaded it
    DataSet(msg.sender, data[msg.sender].length - 1); //Spawns an event that contains the address of the user who just uploaded data and the index number of this piece of data in their corresponding array
  }

  function commit(bytes32 hash) { //Assessors should call this to commit a sha3 hash of their final score and a bytes16
    if(done > size/2) {//If more than half the assessors have committed their score hash
      for(uint i = 0; i < assessors.length; i++) {//Loops through all the assessors
        if(assessorState[assessors[i]] == State.Confirmed) {//Checks if the assessor has not committed  a score yet
          uint r = 38; //Inverse burn rate
          stake[assessors[i]] = cost*2**(-(now-startTime)/r) - 1; //Sets their stake to a lower value based off of how long its been since the first half of the assessors committed
        }
        if(stake[assessors[i]] == 0) {//If an assessor's stake is entirely burned
          assessorState[assessors[i]] = State.Burned; //Sets the assessor's state to Burned
          done++; //Increases done by 1 to help progress to the next assessment stage
        }
      }
    }
    if(done == size) {//If all the assessors have either committed or had their entire stake burned
      for(uint j = 0; j < assessors.length; j++) { //Loops through all assessors
        if(assessorState[assessors[j]] == State.Committed) { //Sends a notification to all the assessors that have committed to reveal their score
          AbstractUser(assessors[j]).notification(concept, 5); //Send in Score
          //NOTE: The front end should receive this notification and then automatically call the reveal function
        }
      }
      startTime = block.number; //Resets the startTime
      done = 0; //Resets the done counter
    }
    if(assessorState[msg.sender] == State.Confirmed) //If the user calling this function is confirmed as an assessor
    {
      commits[msg.sender] = hash; //Maps the score hash to the assessor
      assessorState[msg.sender] == State.Committed; //Sets the assessor's state to Committed
      done++; //Increases done by 1 to help progress to the next assessment stage.

      if(done <= size/2) //If less than or half the assessors have committed
      {
        startTime = block.number; //Sets the startTime to the current block
      }
    }
  }

  function reveal(int8 score, bytes16 salt, address assessor) { //Assessors reveal the components of their hash (which are checked), assessors can reveal other assessors hash components to report them for cheating
    if(block.number - startTime <= 10) { //If less than 10 blocks have passed since the socre commiting stage ended
      bytes32 hash = sha3(score,salt);
      if(commits[assessor] == hash) {
        if(msg.sender == assessor) {
          scores[msg.sender] = score; //That score is mapped to the assessor
          assessorState[assessor] = State.Done;
          done++; //done increases by 1 to help progress to the next assessment stage
        }
        else { //If it was correct and submitted by a user other than the assessor in the parameter
          AbstractConcept(concept).setBalance(msg.sender,AbstractUserRegistry(userRegistry).balances(msg.sender) + stake[assessor]); //The user that called this function gets the assessor's stake
          stake[assessor] = 0;
          assessorState[assessor] = State.Burned; //The assessor's state is set to Burned
          done++; //done increases by 1 to help progress to the next assessment stage
        }
      }
      else if(msg.sender == assessor) { //If the stake was wrong and was provided by the assessor in the parameter
        stake[assessor] = 0; //The assessor's stake is completely burned
        assessorState[assessor] = State.Burned; //The assessor's state is set to Burned
        done++; //done increases by 1 to help progress to the next assessment stage
      }
    }
    else { //If more than 10 blocks have passed
      for(uint i = 0; i < assessors.length; i++) { //Loops through all the assessors
        if(assessorState[assessors[i]] == State.Committed) { //If the assessor has not revealed their score
          stake[assessors[i]] = 0; //The assessor's stake is completely burned
          assessorState[assessors[i]] = State.Burned; //The assessor's state is set to Burned
          done++; //done increases by 1 to help progress to the next assessment stage
        }
      }
    }
    if(done == size) { //If all the assessors have revealed their scored or burned their stakes
      calculateResult(); //The final result is calculated
    }
  }

  function calculateResult() onlyThis() {
    for(uint j = 0; j < size; j++) { //Loops through the assessors
      if(assessorState[assessors[i]] == State.Done) {
        finalAssessors.push(assessors[i]); //Adds all the assessors that completed the assessment process to an array
      }
    }
    int[] memory score = new int[] (finalAssessors.length); //Initializes an array to store scores that is the same length as the number of finalAssessors
    uint largestClusterIndex = 0; //Initializes a uint to store the index of the largest cluster in the clusters mapping
    int averageScore; //Initializes an int to store the average score
    for(uint i = 0; i < finalAssessors.length; i++) {
      score[i] = scores[finalAssessors[i]]; //Puts all the scores in the score array
    }
    int meanAbsoluteDeviation = Math.calculateMAD(score,int(finalAssessors.length)); //Caclulates the MAD of the scores
    for(uint l = 0; l < score.length; l++) { //Find the largest cluster of scores
      for(uint m = 0; m < score.length; m++)
      {
        if(score[l] - score[m] <= meanAbsoluteDeviation) {
          clusters[l].push(score[m]);
        }
      }
      if(clusters[l].length > clusters[largestClusterIndex].length) {
        largestClusterIndex = l;
      }
    }
    for(uint o = 0; o < clusters[largestClusterIndex].length; o++) { //Records which assessors submitted a score that was in the largest cluster
      averageScore += clusters[largestClusterIndex][o];
      inRewardCluster[clusters[largestClusterIndex][o]] = true;
    }
    averageScore /= int(clusters[largestClusterIndex].length); //Calculates the average score from the largest cluster
    finalScore = averageScore; //Sets the final score to the average score
    payout(clusters[largestClusterIndex].length); //Initializes the payout sequence
  }

  function payout(uint largestSize) onlyThis() {
    for(uint i = 0; i < size; i++) //Loops through all the confirmed assessors {
      int score = scores[assessors[i]]; //Gets the score of an assessor
      int scoreDistance = ((score - finalScore)*100)/finalScore; //Calculates the percent difference between the final score the assessors score
      if(scoreDistance < 0) { //Makes negative scoreDistances positive
        scoreDistance *= -1;
      }
      uint payoutValue = 1; //Initializes the payoutValue for the assessor
      if(inRewardCluster[score] == true) { //If the assessor's score was in the largest cluster
        uint q = 1; //Inflation rate factor, WE NEED TO FIGURE THIS OUT AT SOME POINT
        payoutValue = q*cost*((100 - uint(scoreDistance))/100); //The assessor's payout will be some constant times a propotion of their original stake determined by how close to the final score they were
        AbstractConcept(concept).setBalance(assessors[i], AbstractUserRegistry(userRegistry).balances(assessors[i]) + payoutValue); //Pays the user
        AbstractUser(assessors[i]).notification(concept, 15); //You Have Received Payment For Your Assessment
      }
      if(inRewardCluster[score] == false) { //If the assessor's score wasn't in the largest cluster
        payoutValue = stake[assessors[i]]*((200 - uint(scoreDistance))/200); //The assessor's payout will be a propotion of their remaining stake determined by their distance from the final score
        AbstractConcept(concept).setBalance(assessors[i], AbstractUserRegistry(userRegistry).balances(assessors[i]) + payoutValue); //Pays the user
        AbstractUser(assessors[i]).notification(concept, 16); //You Have Received Some of Your Stake Back For Your Assessment
      }
    AbstractConcept(concept).finishAssessment(finalScore, assessee, address(this)); //Sends assessment info to the concept so that it can update its records
  }
}

pragma solidity ^0.4.0;

import "./Math.sol";
import "./abstract/AbstractConcept.sol";
import "./abstract/AbstractConceptRegistry.sol";
import "./abstract/AbstractUser.sol";
import "./abstract/AbstractUserRegistry.sol";

contract Assessment {
  address assessee; //The address of the user being assessed
  address[] assessors;
  address[] finalAssessors; //The assessors who actually give an assessment
  mapping (address => State) assessorState;
  enum State {//The state of the assessors
    Called, //Been called as a potential assessor
    Confirmed, //Confirmed as assessing
    Committed, //Committed a score
    Done, //Completed the assessment processs
    Burned //Entire stake has been burned
  }
  address[] assessorPool; //The addresses of the user's that the assessors are randomly selected from
  address concept;
  address userRegistry;
  address conceptRegistry;
  address math = 0x90B66E80448eb60938FAed4A738dE0D5b630B2Fd;
  uint public startTime;
  uint public size;
  uint cost;
  mapping(address => string[]) public data; //IFFS hashes of data that can be passed between the assessors and the assessee for the assessment to occur
  mapping(address => bytes32) commits;
  mapping(address => uint) stake;
  uint done = 0;
  mapping(address => int8) scores; //could save gas by making this an int8
  mapping(int => bool) inRewardCluster;
  int finalScore;
  event DataSet(address _dataSetter, uint _index);

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

  /*
  @type: modifier
  @name: onlyAssessorAssessee
  @purpose: to only allow the assessors and assessee to call a function to which this modifier is applied
  */
  modifier onlyAssessorAssessee() {
    if(msg.sender != assessee && uint(assessorState[msg.sender]) == 0) {
      throw;
    }
    _;
  }

  // only allow the this contract or the Concept contract that spawned it
  modifier onlyConceptAssessment() {
    if(msg.sender != address(this) && msg.sender != concept) {
      throw;
    }
    _;
  }

  modifier onlyConcept() {
    if(msg.sender != concept) {
      throw;
    }
    _;
  }

  function Assessment(address _assessee, address _userRegistry, address _conceptRegistry, uint _size, uint _cost) {
    assessee = _assessee;
    concept = msg.sender;
    userRegistry = _userRegistry;
    conceptRegistry = _conceptRegistry;
    startTime = block.timestamp;
    size = _size;
    cost = _cost;
    AbstractUser(assessee).notification(concept, 0); //Assessment made
  }

  function cancelAssessment() onlyConceptAssessment() {
    AbstractConcept(concept).setBalance(assessee, AbstractUserRegistry(userRegistry).balances(assessee) + cost*size);
    AbstractUser(assessee).notification(concept, 3); //Assessment Cancled and you have been refunded
    for(uint i = 0; i < assessors.length; i++) {
      AbstractConcept(concept).setBalance(assessors[i], AbstractUserRegistry(userRegistry).balances(assessors[i]) + cost);
      AbstractUser(assessors[i]).notification(concept, 3); //Assessment Cancled and you have been refunded
    }
    suicide(conceptRegistry);
  }

  function addAssessorToPool(address assessor) onlyConcept() returns(bool) {
    if(uint(assessorState[assessor]) == 0) {//Checks if the called assessor hasn't already been called
      AbstractUser(assessor).notification(concept, 1); //Called As A Potential Assessor
      assessorState[assessor] = State.Called; //Sets the state of the assessor as called
      return true;
    }
    else {
      return false; //Returns false if the assessor has already been called
    }
  }

  /*
  @purpose: To recursively set the pool to draw assessors from in the assessment
  @param: uint seed = the seed number for random number generation
  */
  function setAssessorPool(uint seed, address _concept, uint num) onlyConceptAssessment() {
    uint numCalled = 0;
    for(uint k=0; k < num; k++) {
      if(assessorPool.length == size*20){ return; }
      address randomUser = AbstractConcept(_concept).getRandomMember(seed + k);
      if(addAssessorToPool(randomUser)){
        numCalled++;
      }
    }
    uint remaining = num - numCalled;
    if(remaining > 0) {
      for(uint i = 0; i < AbstractConcept(_concept).getParentsLength(); i++) {
          setAssessorPool(seed + assessorPool.length, AbstractConcept(_concept).parents(i), remaining/AbstractConcept(_concept).getParentsLength() + 1);
      }
    }
  }

  function confirmAssessor() {
    if(block.number - startTime <= 15 && assessorState[msg.sender] == State.Called && assessors.length < size && AbstractUserRegistry(userRegistry).balances(msg.sender) >= cost) { //Check if the time to confirm has not passed, that the assessor was actually called, assessors are still needed, and that the assessor has enough of a balance to pay the stake
      assessors.push(msg.sender); //Adds the user that called this function to the array of confirmed assessors
      assessorState[msg.sender] = State.Confirmed; //Sets the assessor's state to confirmed
      stake[msg.sender] = cost; //Sets the current stake value of the assessor to the cost of the assessment
      AbstractConcept(concept).setBalance(msg.sender,AbstractUserRegistry(userRegistry).balances(msg.sender) - cost); //Takes the stake from the assessor
      AbstractUser(msg.sender).notification(concept, 2); //Confirmed for assessing, stake has been taken
    }
    if(assessors.length == size) { //If enough assessors have been called
      notifyStart(); //Assessors and the assessee are notified that the assessmentn has begun
    }
    else if(block.number - startTime > 15 && assessors.length < size){
      cancelAssessment(); //Cancels the assessment if not enough assessors confirm within 15 blocks
    }
  }

  function notifyStart() onlyThis() { //Sends a notification to the assessors and the assessee informing them that the assessment has begun
    for(uint i = 0; i < assessors.length; i++) {
      AbstractUser(assessors[i]).notification(concept, 4); //Assessment Has Started
    }
    AbstractUser(assessee).notification(concept, 4); //Assessment Has Started
  }

  function setData(string _data) onlyAssessorAssessee() { //Allows the assessors and the assessee to publically add data for the purposes of the assessment
    data[msg.sender].push(_data); //Adds the data to an array corresponding to the user that uploaded it
    DataSet(msg.sender, data[msg.sender].length - 1); //Spawns an event that contains the address of the user who just uploaded data and the index number of this piece of data in their corresponding array
  }

  function commit(bytes32 hash) { //Assessors should call this to commit a sha3 hash of their final score and a bytes16
    if(done > size/2) {//If more than half the assessors have committed their score hash
      for(uint i = 0; i < assessors.length; i++) {//Loops through all the assessors
        if(assessorState[assessors[i]] == State.Confirmed) {//Checks if the assessor has not committed  a score yet
          uint r = 38; //Inverse burn rate
          stake[assessors[i]] = cost*2**(-(now-startTime)/r) - 1; //Sets their stake to a lower value based off of how long its been since the first half of the assessors committed
        }
        if(stake[assessors[i]] == 0) {//If an assessor's stake is entirely burned
          assessorState[assessors[i]] = State.Burned; //Sets the assessor's state to Burned
          done++; //Increases done by 1 to help progress to the next assessment stage
        }
      }
    }
    if(done == size) {//If all the assessors have either committed or had their entire stake burned
      for(uint j = 0; j < assessors.length; j++) { //Loops through all assessors
        if(assessorState[assessors[j]] == State.Committed) { //Sends a notification to all the assessors that have committed to reveal their score
          AbstractUser(assessors[j]).notification(concept, 5); //Send in Score
          //NOTE: The front end should receive this notification and then automatically call the reveal function
        }
      }
      startTime = block.number; //Resets the startTime
      done = 0; //Resets the done counter
    }
    if(assessorState[msg.sender] == State.Confirmed) //If the user calling this function is confirmed as an assessor
    {
      commits[msg.sender] = hash; //Maps the score hash to the assessor
      assessorState[msg.sender] == State.Committed; //Sets the assessor's state to Committed
      done++; //Increases done by 1 to help progress to the next assessment stage.

      if(done <= size/2) //If less than or half the assessors have committed
      {
        startTime = block.number; //Sets the startTime to the current block
      }
    }
  }

  function reveal(int8 score, bytes16 salt, address assessor) { //Assessors reveal the components of their hash (which are checked), assessors can reveal other assessors hash components to report them for cheating
    if(block.number - startTime <= 10) { //If less than 10 blocks have passed since the socre commiting stage ended
      bytes32 hash = sha3(score,salt);
      if(commits[assessor] == hash) {
        if(msg.sender == assessor) {
          scores[msg.sender] = score; //That score is mapped to the assessor
          assessorState[assessor] = State.Done;
          done++; //done increases by 1 to help progress to the next assessment stage
        }
        else { //If it was correct and submitted by a user other than the assessor in the parameter
          AbstractConcept(concept).setBalance(msg.sender,AbstractUserRegistry(userRegistry).balances(msg.sender) + stake[assessor]); //The user that called this function gets the assessor's stake
          stake[assessor] = 0;
          assessorState[assessor] = State.Burned; //The assessor's state is set to Burned
          done++; //done increases by 1 to help progress to the next assessment stage
        }
      }
      else if(msg.sender == assessor) { //If the stake was wrong and was provided by the assessor in the parameter
        stake[assessor] = 0; //The assessor's stake is completely burned
        assessorState[assessor] = State.Burned; //The assessor's state is set to Burned
        done++; //done increases by 1 to help progress to the next assessment stage
      }
    }
    else { //If more than 10 blocks have passed
      for(uint i = 0; i < assessors.length; i++) { //Loops through all the assessors
        if(assessorState[assessors[i]] == State.Committed) { //If the assessor has not revealed their score
          stake[assessors[i]] = 0; //The assessor's stake is completely burned
          assessorState[assessors[i]] = State.Burned; //The assessor's state is set to Burned
          done++; //done increases by 1 to help progress to the next assessment stage
        }
      }
    }
    if(done == size) { //If all the assessors have revealed their scored or burned their stakes
      calculateResult(); //The final result is calculated
    }
  }

  function calculateResult() onlyThis() {
    mapping(uint => int[]) clusters; //Initializes mapping to store clusters of scores
    for(uint j = 0; j < size; j++) { //Loops through the assessors
      if(assessorState[assessors[i]] == State.Done) {
        finalAssessors.push(assessors[i]); //Adds all the assessors that completed the assessment process to an array
      }
    }
    int[] memory score = new int[] (finalAssessors.length); //Initializes an array to store scores that is the same length as the number of finalAssessors
    uint largestClusterIndex = 0; //Initializes a uint to store the index of the largest cluster in the clusters mapping
    int averageScore; //Initializes an int to store the average score
    for(uint i = 0; i < finalAssessors.length; i++) {
      score[i] = scores[finalAssessors[i]]; //Puts all the scores in the score array
    }
    int meanAbsoluteDeviation = Math.calculateMAD(score,int(finalAssessors.length)); //Caclulates the MAD of the scores
    for(uint l = 0; l < score.length; l++) { //Find the largest cluster of scores
      for(uint m = 0; m < score.length; m++)
      {
        if(score[l] - score[m] <= meanAbsoluteDeviation) {
          clusters[l].push(score[m]);
        }
      }
      if(clusters[l].length > clusters[largestClusterIndex].length) {
        largestClusterIndex = l;
      }
    }
    for(uint o = 0; o < clusters[largestClusterIndex].length; o++) { //Records which assessors submitted a score that was in the largest cluster
      averageScore += clusters[largestClusterIndex][o];
      inRewardCluster[clusters[largestClusterIndex][o]] = true;
    }
    averageScore /= int(clusters[largestClusterIndex].length); //Calculates the average score from the largest cluster
    finalScore = averageScore; //Sets the final score to the average score
    payout(clusters[largestClusterIndex].length); //Initializes the payout sequence
  }

  function payout(uint largestSize) onlyThis() {
    for(uint i = 0; i < size; i++) //Loops through all the confirmed assessors {
      int score = scores[assessors[i]]; //Gets the score of an assessor
      int scoreDistance = ((score - finalScore)*100)/finalScore; //Calculates the percent difference between the final score the assessors score
      if(scoreDistance < 0) { //Makes negative scoreDistances positive
        scoreDistance *= -1;
      }
      uint payoutValue = 1; //Initializes the payoutValue for the assessor
      if(inRewardCluster[score] == true) { //If the assessor's score was in the largest cluster
        uint q = 1; //Inflation rate factor, WE NEED TO FIGURE THIS OUT AT SOME POINT
        payoutValue = q*cost*((100 - uint(scoreDistance))/100); //The assessor's payout will be some constant times a propotion of their original stake determined by how close to the final score they were
        AbstractConcept(concept).setBalance(assessors[i], AbstractUserRegistry(userRegistry).balances(assessors[i]) + payoutValue); //Pays the user
        AbstractUser(assessors[i]).notification(concept, 15); //You Have Received Payment For Your Assessment
      }
      if(inRewardCluster[score] == false) { //If the assessor's score wasn't in the largest cluster
        payoutValue = stake[assessors[i]]*((200 - uint(scoreDistance))/200); //The assessor's payout will be a propotion of their remaining stake determined by their distance from the final score
        AbstractConcept(concept).setBalance(assessors[i], AbstractUserRegistry(userRegistry).balances(assessors[i]) + payoutValue); //Pays the user
        AbstractUser(assessors[i]).notification(concept, 16); //You Have Received Some of Your Stake Back For Your Assessment
      }
    AbstractConcept(concept).finishAssessment(finalScore, assessee, address(this)); //Sends assessment info to the concept so that it can update its records
  }
}


Remove warning

Remove warning

pragma solidity ^0.4.11;

import './ConfirmationRepository.sol';
import './zeppelin/ownership/Ownable.sol';
import './zeppelin/lifecycle/Destructible.sol';

contract Conference is Destructible {
	string public name;
	uint256 public deposit;
	uint public limitOfParticipants;
	uint public registered;
	uint public attended;
	bool public ended;
	bool public cancelled;
	uint public endedAt;
	uint public coolingPeriod;
	uint256 public payoutAmount;
	ConfirmationRepository public confirmationRepository;
	string public encryption;

	mapping (address => Participant) public participants;
	mapping (uint => address) public participantsIndex;
	bool paid;

	struct Participant {
		string participantName;
		address addr;
		bool attended;
		bool paid;
	}

	event RegisterEvent(address addr, string participantName, string _encryption);
	event AttendEvent(address addr);
	event PaybackEvent(uint256 _payout);
	event WithdrawEvent(address addr, uint256 _payout);
	event CancelEvent();
	event ClearEvent(address addr, uint256 leftOver);

	/* Modifiers */
	modifier sentDepositOrReturn {
		if (msg.value == deposit) {
			_;
		}else{
			assert(msg.sender.send(msg.value));
		}
	}

	modifier onlyActive {
		if (ended == false) {
			_;
		}
	}

	modifier onlyActiveOrReturn {
		if (ended == false) {
			_;
		}else{
			assert(msg.sender.send(msg.value));
		}
	}

	modifier withinLimitOrReturn {
		if (registered < limitOfParticipants ) {
			_;
		}else{
			assert(msg.sender.send(msg.value));
		}
	}

	modifier isEnded {
		if (ended){
			_;
		}
	}

	modifier onlyAfter(uint _time) {
		if (now > _time){
			_;
		}
	}

	modifier ifConfirmed(bytes32 _code){
		require(confirmationRepository.claim(_code, msg.sender));
		_;
	}

	/* Public functions */

	function Conference(
		string _name,
		uint256 _deposit,
		uint _limitOfParticipants,
		uint _coolingPeriod,
		address _confirmation_repository_address,
		string _encryption
	) {
		if(bytes(_name).length != 0){
			name = _name;
		}else{
			name = 'Test';
		}

		if(_deposit != 0){
			deposit = _deposit;
		}else{
			deposit = 0.05 ether;
		}

		if(_limitOfParticipants !=0){
			limitOfParticipants = _limitOfParticipants;
		}else{
			limitOfParticipants = 20;
		}

		if (_coolingPeriod != 0) {
			coolingPeriod = _coolingPeriod;
		} else {
			coolingPeriod = 1 weeks;
		}

		if (bytes(_encryption).length != 0) {
			encryption = _encryption;
		}

		if (_confirmation_repository_address !=0) {
			confirmationRepository = ConfirmationRepository(_confirmation_repository_address);
		}
	}

	function registerWithEncryption(string _participant, string _encrypted) public payable{
		registerInternal(_participant);
		RegisterEvent(msg.sender, _participant, _encrypted);
	}

	function register(string _participant) public payable{
		registerInternal(_participant);
		RegisterEvent(msg.sender, _participant, '');
	}

	function registerInternal(string _participant) internal sentDepositOrReturn withinLimitOrReturn onlyActiveOrReturn {
		require(!isRegistered(msg.sender));
		registered++;
		participantsIndex[registered] = msg.sender;
		participants[msg.sender] = Participant(_participant, msg.sender, false, false);
	}

	function attendWithConfirmation(bytes32 _confirmation) public ifConfirmed(_confirmation){
		require(isRegistered(msg.sender));
		require(!isAttended(msg.sender));
		participants[msg.sender].attended = true;
		attended++;
		AttendEvent(msg.sender);
	}

	function withdraw() public{
		require(payoutAmount > 0);
		Participant participant = participants[msg.sender];
		require(participant.addr == msg.sender);
		require(cancelled || participant.attended);
		require(participant.paid == false);

		participant.paid = true;
		assert(participant.addr.send(payoutAmount));
		WithdrawEvent(msg.sender, payoutAmount);
	}

	/* Constants */
	function totalBalance() constant returns (uint256){
		return this.balance;
	}

	function confirmation() constant returns (bool){
		return address(confirmationRepository) != address(0);
	}

	function isRegistered(address _addr) constant returns (bool){
		return participants[_addr].addr != address(0);
	}

	function isAttended(address _addr) constant returns (bool){
		return isRegistered(_addr) && participants[_addr].attended;
	}

	function isPaid(address _addr) constant returns (bool){
		return isRegistered(_addr) && participants[_addr].paid;
	}

	function payout() constant returns(uint256){
		if (attended == 0) return 0;
		return uint(totalBalance()) / uint(attended);
	}

	/* Admin only functions */

	function payback() onlyOwner{
		payoutAmount = payout();
		ended = true;
		endedAt = now;
		PaybackEvent(payoutAmount);
	}

	function cancel() onlyOwner onlyActive{
		payoutAmount = deposit;
		cancelled = true;
		ended = true;
		endedAt = now;
		CancelEvent();
	}

	/* return the remaining of balance if there are any unclaimed after cooling period */
	function clear() public onlyOwner isEnded onlyAfter(endedAt + coolingPeriod) {
		var leftOver = totalBalance();
		ClearEvent(owner, leftOver);
		assert(owner.send(leftOver));
	}

	function setLimitOfParticipants(uint _limitOfParticipants) public onlyOwner{
		limitOfParticipants = _limitOfParticipants;
	}

	function attend(address[] _addresses) public onlyOwner onlyActive{
		for(uint i=0;i<_addresses.length;i++){
			var _addr = _addresses[i];
			require(isRegistered(_addr));
			require(!isAttended(_addr));
			AttendEvent(_addr);
			participants[_addr].attended = true;
			attended++;
		}
	}
}

pragma solidity ^0.4.11;

import './ConfirmationRepository.sol';
import './zeppelin/ownership/Ownable.sol';
import './zeppelin/lifecycle/Destructible.sol';

contract Conference is Destructible {
	string public name;
	uint256 public deposit;
	uint public limitOfParticipants;
	uint public registered;
	uint public attended;
	bool public ended;
	bool public cancelled;
	uint public endedAt;
	uint public coolingPeriod;
	uint256 public payoutAmount;
	ConfirmationRepository public confirmationRepository;
	string public encryption;

	mapping (address => Participant) public participants;
	mapping (uint => address) public participantsIndex;
	bool paid;
	uint256 _payout;

	struct Participant {
		string participantName;
		address addr;
		bool attended;
		bool paid;
	}

	event RegisterEvent(address addr, string participantName, string encryption);
	event AttendEvent(address addr);
	event PaybackEvent(uint256 _payout);
	event WithdrawEvent(address addr, uint256 _payout);
	event CancelEvent();
	event ClearEvent(address addr, uint256 leftOver);

	/* Modifiers */
	modifier sentDepositOrReturn {
		if (msg.value == deposit) {
			_;
		}else{
			assert(msg.sender.send(msg.value));
		}
	}

	modifier onlyActive {
		if (ended == false) {
			_;
		}
	}

	modifier onlyActiveOrReturn {
		if (ended == false) {
			_;
		}else{
			assert(msg.sender.send(msg.value));
		}
	}

	modifier withinLimitOrReturn {
		if (registered < limitOfParticipants ) {
			_;
		}else{
			assert(msg.sender.send(msg.value));
		}
	}

	modifier isEnded {
		if (ended){
			_;
		}
	}

	modifier onlyAfter(uint _time) {
		if (now > _time){
			_;
		}
	}

	modifier ifConfirmed(bytes32 _code){
		require(confirmationRepository.claim(_code, msg.sender));
		_;
	}

	/* Public functions */

	function Conference(
		string _name,
		uint256 _deposit,
		uint _limitOfParticipants,
		uint _coolingPeriod,
		address _confirmation_repository_address,
		string _encryption
	) {
		if(bytes(_name).length != 0){
			name = _name;
		}else{
			name = 'Test';
		}

		if(_deposit != 0){
			deposit = _deposit;
		}else{
			deposit = 0.05 ether;
		}

		if(_limitOfParticipants !=0){
			limitOfParticipants = _limitOfParticipants;
		}else{
			limitOfParticipants = 20;
		}

		if (_coolingPeriod != 0) {
			coolingPeriod = _coolingPeriod;
		} else {
			coolingPeriod = 1 weeks;
		}

		if (bytes(_encryption).length != 0) {
			encryption = _encryption;
		}

		if (_confirmation_repository_address !=0) {
			confirmationRepository = ConfirmationRepository(_confirmation_repository_address);
		}
	}

	function registerWithEncryption(string _participant, string _encrypted) public payable{
		registerInternal(_participant);
		RegisterEvent(msg.sender, _participant, _encrypted);
	}

	function register(string _participant) public payable{
		registerInternal(_participant);
		RegisterEvent(msg.sender, _participant, '');
	}

	function registerInternal(string _participant) internal sentDepositOrReturn withinLimitOrReturn onlyActiveOrReturn {
		require(!isRegistered(msg.sender));
		registered++;
		participantsIndex[registered] = msg.sender;
		participants[msg.sender] = Participant(_participant, msg.sender, false, false);
	}

	function attendWithConfirmation(bytes32 _confirmation) public ifConfirmed(_confirmation){
		require(isRegistered(msg.sender));
		require(!isAttended(msg.sender));
		participants[msg.sender].attended = true;
		attended++;
		AttendEvent(msg.sender);
	}

	function withdraw() public{
		require(payoutAmount > 0);
		Participant participant = participants[msg.sender];
		require(participant.addr == msg.sender);
		require(cancelled || participant.attended);
		require(participant.paid == false);

		participant.paid = true;
		assert(participant.addr.send(payoutAmount));
		WithdrawEvent(msg.sender, payoutAmount);
	}

	/* Constants */
	function totalBalance() constant returns (uint256){
		return this.balance;
	}

	function confirmation() constant returns (bool){
		return address(confirmationRepository) != address(0);
	}

	function isRegistered(address _addr) constant returns (bool){
		return participants[_addr].addr != address(0);
	}

	function isAttended(address _addr) constant returns (bool){
		return isRegistered(_addr) && participants[_addr].attended;
	}

	function isPaid(address _addr) constant returns (bool){
		return isRegistered(_addr) && participants[_addr].paid;
	}

	function payout() constant returns(uint256){
		if (attended == 0) return 0;
		return uint(totalBalance()) / uint(attended);
	}

	/* Admin only functions */

	function payback() onlyOwner{
		payoutAmount = payout();
		ended = true;
		endedAt = now;
		PaybackEvent(payoutAmount);
	}

	function cancel() onlyOwner onlyActive{
		payoutAmount = deposit;
		cancelled = true;
		ended = true;
		endedAt = now;
		CancelEvent();
	}

	/* return the remaining of balance if there are any unclaimed after cooling period */
	function clear() public onlyOwner isEnded onlyAfter(endedAt + coolingPeriod) {
		var leftOver = totalBalance();
		ClearEvent(owner, leftOver);
		assert(owner.send(leftOver));
	}

	function setLimitOfParticipants(uint _limitOfParticipants) public onlyOwner{
		limitOfParticipants = _limitOfParticipants;
	}

	function attend(address[] _addresses) public onlyOwner onlyActive{
		for(uint i=0;i<_addresses.length;i++){
			var _addr = _addresses[i];
			require(isRegistered(_addr));
			require(!isAttended(_addr));
			AttendEvent(_addr);
			participants[_addr].attended = true;
			attended++;
		}
	}
}


add basic ballot

add basic ballot

pragma solidity ^0.4.11;
// We have to specify what version of compiler this code will compile with

contract Ballot {

    struct Voter {
        uint weight;
        bool voted;
    }

    struct Candidate {
        bytes32 name;
    }

    Candidate[] public candidateList;
    mapping(address => Voter) public votersList;
    mapping (bytes32 => uint8) public votesForCandidates;

  function Ballot(bytes32[] candidateNames, address[] voterAddresses) {
      for (uint i = 0; i < candidateNames.length; i++) {
          candidateList[i] = Candidate({name: candidateNames[i]});
      }

    for (uint j = 0; j < voterAddresses.length; j++) {
        votersList[voterAddresses[j]] = Voter({weight: 1, voted: false});
    }
  }

  function totalVotesFor(bytes32 candidate) returns (uint8) {
    if (validCandidate(candidate) == false) throw;
    return votesForCandidates[candidate];
  }

  function vote(bytes32 candidate) {
    if (votersList[msg.sender].weight != 1 || votersList[msg.sender].voted) return;
    if (validCandidate(candidate) == false) throw;
    votesForCandidates[candidate] += 1;
    votersList[msg.sender].voted = true;
  }

  function validCandidate(bytes32 candidate) returns (bool) {
    for(uint i = 0; i < candidateList.length; i++) {
      if (candidateList[i].name == candidate) {
        return true;
      }
    }
    return false;
  }

  function getWinner() returns (bytes32) {
      uint maxVotes = 0;
      bytes32 winner = "";

      for (uint i = 0; i < candidateList.length; i++) {
          if (votesForCandidates[candidateList[i].name] > maxVotes) {
              maxVotes = votesForCandidates[candidateList[i].name];
              winner = candidateList[i].name;
          }
      }

      return winner;
  }
}

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


add comment making explicit that SafeMath.sub can throw

pragma solidity ^0.4.11;

import './ERC20Basic.sol';
import '../math/SafeMath.sol';

/**
 * @title Basic token
 * @dev Basic version of StandardToken, with no allowances.
 */
contract BasicToken is ERC20Basic {
  using SafeMath for uint256;

  mapping(address => uint256) balances;

  /**
  * @dev transfer token for a specified address
  * @param _to The address to transfer to.
  * @param _value The amount to be transferred.
  */
  function transfer(address _to, uint256 _value) returns (bool) {
    require(_to != address(0));

    // SafeMath.sub will throw if there is not enough balance.
    balances[msg.sender] = balances[msg.sender].sub(_value);
    balances[_to] = balances[_to].add(_value);
    Transfer(msg.sender, _to, _value);
    return true;
  }

  /**
  * @dev Gets the balance of the specified address.
  * @param _owner The address to query the the balance of.
  * @return An uint256 representing the amount owned by the passed address.
  */
  function balanceOf(address _owner) constant returns (uint256 balance) {
    return balances[_owner];
  }

}

pragma solidity ^0.4.11;

import './ERC20Basic.sol';
import '../math/SafeMath.sol';

/**
 * @title Basic token
 * @dev Basic version of StandardToken, with no allowances.
 */
contract BasicToken is ERC20Basic {
  using SafeMath for uint256;

  mapping(address => uint256) balances;

  /**
  * @dev transfer token for a specified address
  * @param _to The address to transfer to.
  * @param _value The amount to be transferred.
  */
  function transfer(address _to, uint256 _value) returns (bool) {
    require(_to != address(0));

    balances[msg.sender] = balances[msg.sender].sub(_value);
    balances[_to] = balances[_to].add(_value);
    Transfer(msg.sender, _to, _value);
    return true;
  }

  /**
  * @dev Gets the balance of the specified address.
  * @param _owner The address to query the the balance of.
  * @return An uint256 representing the amount owned by the passed address.
  */
  function balanceOf(address _owner) constant returns (uint256 balance) {
    return balances[_owner];
  }

}


Fixes issues #1 and #2

Fixes issues #1 and #2

pragma solidity ^0.4.10;
contract Registrar {
    function entries(bytes32 _hash) constant returns (uint, address, uint, uint, uint);
}

contract Deed {
    address public registrar;
    function getCreationDate() constant returns(uint);
    uint public creationDate;
    address public owner;
    address public previousOwner;
    uint public value;
    function Deed(address _owner);
    function setOwner(address newOwner);
    function setRegistrar(address newRegistrar);
    function setBalance(uint newValue, bool throwOnFailure);
    function closeDeed(uint refundRatio);
    function destroyDeed();
}

contract ENSTrade {
    struct Record {
        string name;
        bool listed;
        uint buyPrice;
        address nextRecord;
        address previousRecord;
        string message;
    }

    struct RecordOffers {
        address lastOffer;
        uint totalOfferCount;
        uint totalOfferValue;
    }

    struct Offer {
        address nextOffer;
        address previousOffer;
        uint value;
        string message;
    }

    event TradeComplete(address indexed deedAddress, address from, address to, uint value);
    event OfferCreated(address indexed deedAddress, address from, uint value);
    event OfferCancelled(address indexed deedAddress, address from);
    event ListingCreated(address indexed deedAddress, address from, uint buyPrice);
    event ListingRemoved(address indexed deedAddress, address from);
    event RecordReclaimed(address indexed deedAddress, address to);

    address feeAddress;
    uint public fee = 0; // Out of 10000 (0% for alpha)
    uint public minimumOfferPrice = 0.01 ether;

    uint public recordsCurrentlyListed;
    uint public totalRecordsTraded;
    uint public totalValueTraded;

    Registrar public registrarAddress;

    mapping (address => Record) records;
    mapping (address => mapping (address => Offer)) offers;
    mapping (address => RecordOffers) recordOffers;
    address public lastRecord;

    modifier onlyOwner(address _deedAddress) {
        // Check who owns the name using the previousOwner() function, as ens.trade should currently own it.
        Deed d = Deed(_deedAddress);
        if (d.owner() != address(this)) throw;
        if (d.previousOwner() != msg.sender) throw;
        _;
    }

    modifier onlyFeeAddress {
        if (msg.sender != feeAddress) throw;
        _;
    }

    function ENSTrade(Registrar _registrarAddress) {
        feeAddress = msg.sender;
        registrarAddress = _registrarAddress;
    }
    function setFeeAddress(address _feeAddress) onlyFeeAddress {
        feeAddress = _feeAddress;
    }
    function setMinimumOfferPrice(uint _minimumOfferPrice) onlyFeeAddress {
        minimumOfferPrice = _minimumOfferPrice;
    }
    function setFee(uint _fee) onlyFeeAddress {
        if (_fee > 500) throw; // Maximum 5%
        fee = _fee;
    }

    function sha(string _string) constant returns(bytes32) {
        return sha3(_string);
    }

    function newListing(string _name, uint _buyPrice, string _message) {
        // Hashes the name and checks that the sender previously owned it
        Registrar registrar = Registrar(registrarAddress);
        bytes32 hash = sha3(_name);
        var (,_deedAddress,,,) = registrar.entries(hash);
        Deed d = Deed(_deedAddress);
        if (d.owner() != address(this)) throw;
        if (d.previousOwner() != msg.sender) throw;
        if (_buyPrice == 0 || _buyPrice < minimumOfferPrice) throw; // For extra security

        Record r = records[_deedAddress];
        if (lastRecord != 0x0) {
            records[lastRecord].nextRecord = _deedAddress;
        }
        r.previousRecord = lastRecord;
        r.listed = true;
        r.name = _name;
        r.buyPrice = _buyPrice;
        r.message = _message;
        lastRecord = _deedAddress;
        recordsCurrentlyListed++;

        ListingCreated(_deedAddress, msg.sender, _buyPrice);
    }

    function deList(address _deedAddress) onlyOwner(_deedAddress) {
        Record r = records[_deedAddress];
        if (r.listed) {
            deleteRecord(_deedAddress);
            ListingRemoved(_deedAddress, msg.sender);
        }
    }

    function reclaim(address _deedAddress) onlyOwner(_deedAddress) {
        Record r = records[_deedAddress];
        Deed d = Deed(_deedAddress);
        d.setOwner(msg.sender);
        if (r.listed) {
            deleteRecord(_deedAddress);
            ListingRemoved(_deedAddress, msg.sender);
        }
        RecordReclaimed(_deedAddress, msg.sender);
    }

    function deleteRecord(address _deedAddress) internal {
        Record r = records[_deedAddress];
        records[r.previousRecord].nextRecord = r.nextRecord;
        if (_deedAddress == lastRecord) {
            lastRecord = r.previousRecord;
        }
        delete records[_deedAddress];
        recordsCurrentlyListed--;
    }

    function newOffer(address _deedAddress, string _message) payable {
        if (msg.value == 0) throw;
        Offer o = offers[_deedAddress][msg.sender];
        if (o.value > 0) throw; // Offer exists
        Record r = records[_deedAddress];
        if (msg.value >= r.buyPrice && r.buyPrice != 0) {
            // Offer is above asking price, finish trade
            transferRecord(_deedAddress, msg.sender, msg.value);
            return;
        }
        if (msg.value < minimumOfferPrice) throw;
        o.value = msg.value;
        o.message = _message;

        RecordOffers ro = recordOffers[_deedAddress];
        if (ro.lastOffer != 0x0) {
            offers[_deedAddress][ro.lastOffer].nextOffer = msg.sender;
        }
        o.previousOffer = ro.lastOffer;
        ro.lastOffer = msg.sender;
        ro.totalOfferCount++;
        ro.totalOfferValue += msg.value;

        OfferCreated(_deedAddress, msg.sender, msg.value);
    }

    function cancelOffer(address _deedAddress) {
        Offer o = offers[_deedAddress][msg.sender];
        if (o.value == 0) throw;
        uint valueToSend = o.value;
        deleteOffer(_deedAddress, msg.sender);
        msg.sender.transfer(valueToSend);

        OfferCancelled(_deedAddress, msg.sender);
    }

    function acceptOffer(address _deedAddress, address _offerAddress, uint _offerValue) onlyOwner(_deedAddress) {
        Offer o = offers[_deedAddress][_offerAddress];
        if (o.value != _offerValue || o.value == 0) throw; // For extra security and race conditions

        Record r = records[_deedAddress];
        if (!r.listed) throw;

        transferRecord(_deedAddress, _offerAddress, o.value);
        deleteOffer(_deedAddress, _offerAddress);
    }

    function deleteOffer(address _deedAddress, address _offerAddress) internal {
        RecordOffers ro = recordOffers[_deedAddress];
        Offer o = offers[_deedAddress][_offerAddress];
        offers[_deedAddress][o.previousOffer].nextOffer = o.nextOffer;
        if (ro.lastOffer == _offerAddress) {
            ro.lastOffer = o.previousOffer;
        }
        ro.totalOfferCount--;
        ro.totalOfferValue -= offers[_deedAddress][_offerAddress].value;
        delete offers[_deedAddress][_offerAddress];
    }

    function transferRecord(address _deedAddress, address _toAddress, uint _value) internal {
        uint _fee = _value * fee / 10000;
        Deed d = Deed(_deedAddress);
        totalRecordsTraded++;
        totalValueTraded += _value;

        d.setOwner(_toAddress);
        deleteRecord(_deedAddress);

        d.previousOwner().transfer(_value - _fee);
        feeAddress.transfer(_fee);

        TradeComplete(_deedAddress, d.previousOwner(), _toAddress, _value);
    }

    function getRecord(address _deedAddress) constant returns(bool, string, uint, address, address, string) {
        Record r = records[_deedAddress];
        return (r.listed, r.name, r.buyPrice, r.nextRecord, r.previousRecord, r.message);
    }

    function getRecordOffers(address _deedAddress) constant returns(address, uint, uint) {
        RecordOffers ro = recordOffers[_deedAddress];
        return (ro.lastOffer, ro.totalOfferCount, ro.totalOfferValue);
    }

    function getOffer(address _deedAddress, address _offerAddress) constant returns(address, address, uint, string) {
        Offer o = offers[_deedAddress][_offerAddress];
        return (o.nextOffer, o.previousOffer, o.value, o.message);
    }
}

pragma solidity ^0.4.10;
contract Registrar {
    function entries(bytes32 _hash) constant returns (uint, address, uint, uint, uint);
}

contract Deed {
    address public registrar;
    function getCreationDate() constant returns(uint);
    uint public creationDate;
    address public owner;
    address public previousOwner;
    uint public value;
    function Deed(address _owner);
    function setOwner(address newOwner);
    function setRegistrar(address newRegistrar);
    function setBalance(uint newValue, bool throwOnFailure);
    function closeDeed(uint refundRatio);
    function destroyDeed();
}

contract ENSTrade {
    struct Record {
        string name;
        bool listed;
        uint buyPrice;
        address nextRecord;
        address previousRecord;
        string message;
    }

    struct RecordOffers {
        address lastOffer;
        uint totalOfferCount;
        uint totalOfferValue;
    }

    struct Offer {
        address nextOffer;
        address previousOffer;
        uint value;
        string message;
    }

    event tradeComplete(address indexed deedAddress, address from, address to, uint value);
    event offerCreated(address indexed deedAddress, address from, uint value);
    event offerCancelled(address indexed deedAddress, address from);
    event listingCreated(address indexed deedAddress, address from, uint buyPrice);
    event listingRemoved(address indexed deedAddress, address from);
    event recordReclaimed(address indexed deedAddress, address to);

    address feeAddress;
    uint public fee = 0; // Out of 10000 (0% for alpha)
    uint public minimumOfferPrice = 0.01 ether;

    uint public recordsCurrentlyListed;
    uint public totalRecordsTraded;
    uint public totalValueTraded;

    address public registrarAddress;

    mapping (address => Record) records;
    mapping (address => mapping (address => Offer)) offers;
    mapping (address => RecordOffers) recordOffers;
    address public lastRecord;

    modifier onlyOwner(address _deedAddress) {
        // Check who owns the name using the previousOwner() function, as ens.trade should currently owns it.
        Deed d = Deed(_deedAddress);
        if (d.owner() != address(this)) throw;
        if (d.previousOwner() != msg.sender) throw;
        _;
    }

    modifier onlyFeeAddress {
        if (msg.sender != feeAddress) throw;
        _;
    }

    function ENSTrade(address _registrarAddress) {
        feeAddress = msg.sender;
        registrarAddress = _registrarAddress;
    }
    function setFeeAddress(address _feeAddress) onlyFeeAddress {
        feeAddress = _feeAddress;
    }
    function setMinimumOfferPrice(uint _minimumOfferPrice) onlyFeeAddress {
        minimumOfferPrice = _minimumOfferPrice;
    }
    function setFee(uint _fee) onlyFeeAddress {
        if (_fee > 500) throw; // Maximum 5%
        fee = _fee;
    }

    function sha(string _string) constant returns(bytes32) {
        return sha3(_string);
    }

    function newListing(string _name, uint _buyPrice, string _message) {
        // Hashes the name and checks that the sender previously owned it
        Registrar registrar = Registrar(registrarAddress);
        bytes32 hash = sha3(_name);
        var (,_deedAddress,,,) = registrar.entries(hash);
        Deed d = Deed(_deedAddress);
        if (d.owner() != address(this)) throw;
        if (d.previousOwner() != msg.sender) throw;
        if (_buyPrice == 0 || _buyPrice < minimumOfferPrice) throw; // For extra security

        Record r = records[_deedAddress];
        if (lastRecord != 0x0) {
            records[lastRecord].nextRecord = _deedAddress;
        }
        r.previousRecord = lastRecord;
        r.listed = true;
        r.name = _name;
        r.buyPrice = _buyPrice;
        r.message = _message;
        lastRecord = _deedAddress;
        recordsCurrentlyListed++;

        listingCreated(_deedAddress, msg.sender, _buyPrice);
    }

    function deList(address _deedAddress) onlyOwner(_deedAddress) {
        Record r = records[_deedAddress];
        if (r.listed) {
            deleteRecord(_deedAddress);
            listingRemoved(_deedAddress, msg.sender);
        }
    }

    function reclaim(address _deedAddress) onlyOwner(_deedAddress) {
        Record r = records[_deedAddress];
        Deed d = Deed(_deedAddress);
        d.setOwner(msg.sender);
        if (r.listed) {
            deleteRecord(_deedAddress);
            listingRemoved(_deedAddress, msg.sender);
        }
        recordReclaimed(_deedAddress, msg.sender);
    }

    function deleteRecord(address _deedAddress) internal {
        Record r = records[_deedAddress];
        records[r.previousRecord].nextRecord = r.nextRecord;
        if (_deedAddress == lastRecord) {
            lastRecord = r.previousRecord;
        }
        delete records[_deedAddress];
        recordsCurrentlyListed--;
    }

    function newOffer(address _deedAddress, string _message) payable {
        if (msg.value == 0) throw;
        Offer o = offers[_deedAddress][msg.sender];
        if (o.value > 0) throw; // Offer exists
        Record r = records[_deedAddress];
        if (msg.value >= r.buyPrice && r.buyPrice != 0) {
            // Offer is above asking price, finish trade
            transferRecord(_deedAddress, msg.sender, msg.value);
            return;
        }
        if (msg.value < minimumOfferPrice) throw;
        o.value = msg.value;
        o.message = _message;

        RecordOffers ro = recordOffers[_deedAddress];
        if (ro.lastOffer != 0x0) {
            offers[_deedAddress][ro.lastOffer].nextOffer = msg.sender;
        }
        o.previousOffer = ro.lastOffer;
        ro.lastOffer = msg.sender;
        ro.totalOfferCount++;
        ro.totalOfferValue += msg.value;

        offerCreated(_deedAddress, msg.sender, msg.value);
    }

    function cancelOffer(address _deedAddress) {
        Offer o = offers[_deedAddress][msg.sender];
        if (o.value == 0) throw;
        uint valueToSend = o.value;
        deleteOffer(_deedAddress, msg.sender);
        msg.sender.transfer(valueToSend);

        offerCancelled(_deedAddress, msg.sender);
    }

    function acceptOffer(address _deedAddress, address _offerAddress, uint _offerValue) onlyOwner(_deedAddress) {
        Offer o = offers[_deedAddress][_offerAddress];
        if (o.value != _offerValue || o.value == 0) throw; // For extra security and race conditions

        Record r = records[_deedAddress];
        if (!r.listed) throw;

        transferRecord(_deedAddress, _offerAddress, o.value);
        deleteOffer(_deedAddress, _offerAddress);
    }

    function deleteOffer(address _deedAddress, address _offerAddress) internal {
        RecordOffers ro = recordOffers[_deedAddress];
        Offer o = offers[_deedAddress][_offerAddress];
        offers[_deedAddress][o.previousOffer].nextOffer = o.nextOffer;
        if (ro.lastOffer == _offerAddress) {
            ro.lastOffer = o.previousOffer;
        }
        ro.totalOfferCount--;
        ro.totalOfferValue -= offers[_deedAddress][_offerAddress].value;
        delete offers[_deedAddress][_offerAddress];
    }

    function transferRecord(address _deedAddress, address _toAddress, uint _value) internal {
        uint _fee = _value * fee / 10000;
        Deed d = Deed(_deedAddress);
        totalRecordsTraded++;
        totalValueTraded += _value;

        d.setOwner(_toAddress);
        deleteRecord(_deedAddress);

        d.previousOwner().transfer(_value - _fee);
        feeAddress.transfer(_fee);

        tradeComplete(_deedAddress, d.previousOwner(), _toAddress, _value);
    }

    function getRecord(address _deedAddress) constant returns(bool, string, uint, address, address, string) {
        Record r = records[_deedAddress];
        return (r.listed, r.name, r.buyPrice, r.nextRecord, r.previousRecord, r.message);
    }

    function getRecordOffers(address _deedAddress) constant returns(address, uint, uint) {
        RecordOffers ro = recordOffers[_deedAddress];
        return (ro.lastOffer, ro.totalOfferCount, ro.totalOfferValue);
    }

    function getOffer(address _deedAddress, address _offerAddress) constant returns(address, address, uint, string) {
        Offer o = offers[_deedAddress][_offerAddress];
        return (o.nextOffer, o.previousOffer, o.value, o.message);
    }
}


Removed ip from WA.

Removed ip from WA.

contract WorkAgreement {
    address client;
    address worker;
    mapping (address => bool) testers;
    uint public price;
    uint public end;
    // port for docker transfer
    uint dtport;
    // port for hosting
    uint public port;

    function WorkAgreement(address _client, address _worker, uint _price,
                           uint length) {
        client = _client;
        worker = _worker;
        price = _price;
        end = length;
    }

    function addTester(address tester) {
        testers[tester] = true;
    }

    function setWorkerDtPort(uint _dtport) {
        if (msg.sender == worker) {
            dtport = _dtport;
        }
    }

    function setWorkerPort(uint _port) {
        if (msg.sender == worker) {
            port = _port;
        }
    }
}

contract WorkerDispatcher {
    struct Worker {
        bytes32 name;
        bytes32 ip;
        uint maxLength;
        uint price;
        address agreement;
    }
    mapping (address => Worker) public workersInfo;
    uint public numWorkers;
    mapping (uint => address) public workerList;

    function buyContract(address worker, uint redundancy, uint length)
                returns (address addr) {
        if (msg.value < length * workersInfo[worker].price &&
            workersInfo[worker].name == "" &&
            workersInfo[worker].maxLength < length) return msg.sender;
        WorkAgreement wa = new WorkAgreement(msg.sender, worker,
                                             workersInfo[worker].price,
                                             length);
        workersInfo[worker].agreement = wa;
        // TODO - create better way to asign testers
        /*
        for (uint i = 1; i < 3; i++) {
            uint n = uint(block.blockhash(block.number - i)) % numWorkers;
            if (workerList[n] == worker) continue;
            wa.addTester(workerList[n]);
        }*/
        return wa;
    }

    function registerWorker(uint maxLength, uint price,
                            bytes32 name, bytes32 ip) {
        if (workersInfo[msg.sender].name == "") {
            workerList[numWorkers++] = msg.sender;
        }
        Worker w = workersInfo[msg.sender];
        w.name = name;
        w.ip = ip;
        w.maxLength = maxLength;
        w.price = price;
        w.agreement = 0;
    }

    function changeWorkerPrice(uint newPrice) {
        workersInfo[msg.sender].price = newPrice;
    }
}

contract WorkAgreement {
    address client;
    address worker;
    mapping (address => bool) testers;
    uint public price;
    uint public end;
    // ip of worker
    bytes32 public ip;
    // port for docker transfer
    uint dtport;
    // port for hosting
    uint public port;

    function WorkAgreement(address _client, address _worker, uint _price,
                           uint length) {
        client = _client;
        worker = _worker;
        price = _price;
        end = length;
    }

    function addTester(address tester) {
        testers[tester] = true;
    }

    function setWorkerDtPort(uint _dtport) {
        if (msg.sender == worker) {
            dtport = _dtport;
        }
    }

    function setWorkerPort(uint _port) {
        if (msg.sender == worker) {
            port = _port;
        }
    }
}

contract WorkerDispatcher {
    struct Worker {
        bytes32 name;
        bytes32 ip;
        uint maxLength;
        uint price;
        address agreement;
    }
    mapping (address => Worker) public workersInfo;
    uint public numWorkers;
    mapping (uint => address) public workerList;

    function buyContract(address worker, uint redundancy, uint length)
                returns (address addr) {
        if (msg.value < length * workersInfo[worker].price &&
            workersInfo[worker].name == "" &&
            workersInfo[worker].maxLength < length) return msg.sender;
        WorkAgreement wa = new WorkAgreement(msg.sender, worker,
                                             workersInfo[worker].price,
                                             length);
        workersInfo[worker].agreement = wa;
        // TODO - create better way to asign testers
        /*
        for (uint i = 1; i < 3; i++) {
            uint n = uint(block.blockhash(block.number - i)) % numWorkers;
            if (workerList[n] == worker) continue;
            wa.addTester(workerList[n]);
        }*/
        return wa;
    }

    function registerWorker(uint maxLength, uint price,
                            bytes32 name, bytes32 ip) {
        if (workersInfo[msg.sender].name == "") {
            workerList[numWorkers++] = msg.sender;
        }
        Worker w = workersInfo[msg.sender];
        w.name = name;
        w.ip = ip;
        w.maxLength = maxLength;
        w.price = price;
        w.agreement = 0;
    }

    function changeWorkerPrice(uint newPrice) {
        workersInfo[msg.sender].price = newPrice;
    }
}


Commented LockedState.sol

Commented LockedState.sol

import "Owned.sol";

/**
 * LockedState
 *
 * Abstract contract in which all externally modifiable state should be stored.
 * Should be initialised by some Adjudicator contract.
 */
contract LockedState is Owned {

    // an abstract method to check if the final state is valid
    function checkState(bytes state) constant returns (bool);

    // broadcasts the final state to the blockchain
    // it is onlyOwner because this contract should be initialised and controlled by an Adjudicator
    function broadcastState(bytes state) external onlyOwner returns (bool);

    // kills the contract
    function kill() external onlyOwner {
        selfdestruct(owner);
    }
}

import "Owned.sol";

contract LockedState is Owned {

    function checkState(bytes state) constant returns (bool);
    function broadcastState(bytes state) external onlyOwner returns (bool);

    function kill() external onlyOwner {
        selfdestruct(owner);
    }
}


build out of more accounting methods to and from pool

/*
    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 isExpired;
    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
    }

    /// @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 (!isExpired) {
            queryOracle();  // set up our next query
        }
    }

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

    /// @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(isExpired)   // already expired.
            return;

        if(now > EXPIRATION) {  // note: miners can cheat this by small increments of time (minutes, not hours)
            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 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
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 isExpired;
    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 DepositReceived(address user, uint depositAmount, uint totalBalance);
    event WithdrawCompleted(address user, uint withdrawAmount, uint totalBalance);

    /// @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 //TODO explain this better once qty code is in place
    /// @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
    }

    /// @param queryID of the returning query, this should match our own internal mapping
    /// @param result query to be processed
    /// @param 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 (!isExpired) {
            queryOracle();  // set up our next query
        }
    }

    // @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;
        DepositReceived(msg.sender, depositAmount, 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);
        WithdrawCompleted(msg.sender, withdrawAmount, balanceAfterWithdrawal);
    }

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

    /// @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(addressToUserPosition[maker], qty, price);
        // continue process for taker, but qty is opposite sign for taker
        updatePosition(addressToUserPosition[taker], qty * -1, price);
    }

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

    /// @param userNetPos storage struct for this users position
    /// @param qty signed quantity of the qty to reduce this users position by
    /// @param uint 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 + 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 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);
    }
}