Finished payout protocols

Finished payout protocols

contract Master
{
  //Initialize master data store
  mapping (address => uint) tokenBalance;
  mapping (address => string) tagName;
  mapping (string => address) tagAddressFromName;
  mapping (address => address[]) achievements;
  mapping (address => bool) availability;
  mapping (address => address) users;

  event TagCreation
  ( string _tagName,
    address _tagAddress,
    address[] _parents);

  function Master()
  {
    tokenBalance[address(this)] = 1;
    address[] memory a;
    uint useless = addTag("account", a, "Initial Account Tag");
  }

  function mapTokenBalance(address user, uint balance)
  {
    if(tagAddressFromName[tagName[msg.sender]] == 0)
    {
      tokenBalance[user] = balance;
    }
  }
  function mapTagName(address tagAddress, string name)
  {
    tagName[tagAddress] = name;
  }
  function mapTagAddressFromName(string name, address tagAddress)
  {
    tagAddressFromName[name] = tagAddress;
  }
  function mapAchievement(address user, address achievment)
  {
    achievements[user].push(achievment);
  }
  function mapAvailability(address user, bool available)
  {
    availability[user] = available;
  }

  function getTokenBalance(address user) returns(uint)
  {
    return tokenBalance[user];
  }
  function getTagName(address tagAddress) returns(string)
  {
    return tagName[tagAddress];
  }
  function getTagAddressFromName(string name) returns(address)
  {
    return tagAddressFromName[name];
  }
  function getAchievement(address user) returns(address[])
  {
    return achievements[user];
  }
  function getNumberOfachievments(address user) returns(uint)
  {
    return achievements[user].length;
  }
  function getAvailability(address user) returns(bool)
  {
    return availability[user];
  }
 function getTagDescription(address tagAddress) returns(string)
  {
    return Tag(tagAddress).getDescription();
  }

  function addUser()
  {
    User newUser = new User(msg.sender, address(this));
    Tag(tagAddressFromName["account"]).startAssessment(address(newUser),5, 600);
  }

  function addTag(string name, address[] parentList, string description) returns(uint) //Creates a new tag contract
  {
    uint response = 0;
    address[] parents;
    if(tokenBalance[msg.sender] < 1)
    {
      response += 1;
    }
    if(tagAddressFromName[name] == 0)
    {
      response += 10;
    }
    if(response==0)
    {
      for(uint i=0; i<= parentList.length; i++) //adds all the given parents
      {
        if(parentList[i]==0)
        {
          response += 100*(10**i);
        }
        else
        {
          parents.push(parentList[i]);
        }
      }
      Tag newTag = new Tag(name, parents, address(this), description);
      address newTagAddress = address(newTag);
      tagName[newTagAddress] = name;
      tagAddressFromName[name] = newTagAddress;
      tokenBalance[msg.sender] -= 1;
      TagCreation(name, newTagAddress, parents);
    }
    return response;
  }
}

//Defines the meta-contract for a Tag
contract Tag
{
  address[] parentTags;
  address master;
  string name;
  string description;
  address[] owners; //Those who have earned the tag
  mapping(address => address[]) assessmentHistory; //All assessments completed
  mapping(address => int) scores; //All assessements scores
  event CompletedAssessment
  ( address _assessee,
    bool _pass,
    int _score,
    address _assessment);

  function Tag(string tagName, address[] parents, address masterAddress, string tagDescription)
  {
    name = tagName;
    parentTags = parents;
    master = masterAddress;
    description = tagDescription;
  }

  function getDescription() returns(string)
  {
    return description;
  }

  function getOwners() returns(address[])
  {
    return owners;
  }

  function getOwnerLength() returns(uint)
  {
    return owners.length;
  }

  function getOwner(uint index) returns(address)
  {
    return owners[index];
  }

  function getParents() returns(address[])
  {
    return parentTags;
  }

  function getParentsLength() returns(uint)
  {
    return parentTags.length;
  }

  function getParent(uint index) returns(address)
  {
      return parentTags[index];
  }

  function setAssessorPool(address tagAddress, address assessment)
  {
    for(uint i = 0; i < Tag(tagAddress).getOwnerLength() && Assessment(assessment).getAssessmentPoolSize() != 0; i++)
    {
      if(Assessment(assessment).getAssessorPoolLength() < Tag(tagAddress).getOwnerLength()/10)
      {
        address random = Tag(tagAddress).getOwner(getRandom(Tag(tagAddress).getOwnerLength()-1));
        if(Master(master).getAvailability(random) == true)
        {
          Assessment(assessment).addToAssessorPool(random);
          Assessment(assessment).setAssessmentPoolSize(Assessment(assessment).getAssessmentPoolSize() -1);
        }
      }
      else
      {
        for(uint j = 0; j < Tag(tagAddress).getParentsLength(); j++)
        {
          setAssessorPool(Tag(tagAddress).getParent(j), assessment);
        }
      }
      if(Assessment(assessment).getAssessmentPoolSize() <= 0)
      {
        Assessment(assessment).setPotentialAssessor();
      }
    }
  }

  function startAssessment(address assessee, uint size, uint timeForSettingTask)
  {
    Assessment newAssessment = new Assessment(assessee, address(this), master, timeForSettingTask);
    newAssessment.setNumberOfAssessors(size);
    newAssessment.setAssessmentPoolSize(size*20);
    setAssessorPool(address(this), address(newAssessment));
  }

  function finishAssessment(bool pass, int score, address assessee, address assessment)
  {
    if(pass == true)
    {
      owners.push(assessee);
      scores[assessee] = score;
      Master(master).mapAchievement(assessee,address(this));
    }
    if(pass == false && address(this) == Master(master).getTagAddressFromName("account"))
    {
      User(assessee).remove();
    }
    assessmentHistory[assessee].push(assessment);
    CompletedAssessment(assessee, pass, score, assessment);
  }
  function getRandom(uint i) returns(uint)
  {
    return 12;
  }
}

//Defines the meta-contract for an assessment
contract Assessment
{
  address assessee; //We need a better word for this
  address[] assessorPool;
  mapping (address => uint) assessors;
  address[] finalAssessors;
  address tag;
  address master;
  uint poolSizeRemaining;
  uint numberOfAssessors;
  mapping(address => string) assessmentTasks; //Given by the assessors as IPFS hashes
  mapping(address => string) assessmentResponses; //Given by the assessee as IPFS hashes
  mapping(address => int) assessmentResults; //Pass/Fail and Score given by assessors
  mapping(int => address) addressFromScore;
  mapping(int => bool) inRewardCluster;
  address currentAssessor;
  int finalScore;
  bool finalResult;
  uint taskCreationTime;
  uint taskCompletionTime;
  uint taskGradingTime;
  uint referenceTime;
  uint numberCancelled;

  function Assessment(address assesseeAddress, address tagAddress, address masterAddress, uint timeForTaskCreation)
  {
    assessee = assesseeAddress;
    tag = tagAddress;
    master = masterAddress;
    referenceTime = block.timestamp;
    taskCreationTime = timeForTaskCreation;
  }

  function getTaskCreationTime() returns(uint)
  {
      return taskCreationTime;
  }

  function getTaskCompletionTime() returns(uint)
  {
      return taskCompletionTime;
  }

  function setNumberOfAssessors(uint number)
  {
    numberOfAssessors = number;
  }

  function getNumberOfAssessors() returns(uint)
  {
    return numberOfAssessors;
  }

  function setAssessmentPoolSize(uint sizeRemaining)
  {
    poolSizeRemaining = sizeRemaining;
  }

  function getAssessmentPoolSize() returns(uint)
  {
    return poolSizeRemaining;
  }

  function addToAssessorPool(address potentialAddress)
  {
    assessorPool.push(potentialAddress);
  }

  function setPotentialAssessor()
  {
    bool potentialAssessorSet = false;
    while(potentialAssessorSet == false)
    {
      address randomAssessor = assessorPool[getRandom(assessorPool.length)];
      if(assessors[randomAssessor] == 0)
      {
        assessors[randomAssessor] = 3;
        currentAssessor = randomAssessor;
        potentialAssessorSet = true;
        User(randomAssessor).notification("Called As A Potential Assessor",tag, 1);
      }
    }
    referenceTime = now;
  }

  function getAssessorPoolLength() returns(uint)
  {
      return assessorPool.length;
  }

  function getRandom(uint i) returns(uint)
  {
    return 12;
  }

  function setTask(string data, uint timeLimit)
  {
    if(numberCancelled >= numberOfAssessors)
    {
      cancelAssessment();
    }
    if(assessors[currentAssessor] == 5 && now - referenceTime <= taskCreationTime)
    {
      assessmentTasks[currentAssessor] = data;
      taskCompletionTime = timeLimit;
      assessors[currentAssessor] = 6;
      User(currentAssessor).notification("Task Data Inputted", tag, 5);
      User(assessee).notification("New Task Available", tag, 7);
      referenceTime = now;
    }
    if(now - referenceTime > taskCreationTime && assessors[currentAssessor]!=5)
    {
      User(currentAssessor).notification("Did Not Submit Task On Time", tag, 6);
      Master(master).mapTokenBalance(currentAssessor, Master(master).getTokenBalance(currentAssessor) - 1);
      User(currentAssessor).setReputation(User(currentAssessor).getReputation() + 1);
      numberCancelled++;
      setPotentialAssessor();
    }
  }

  function cancelAssessment()
  {
    User(assessee).notification("Assessment Cancled", tag, 8);
    for(uint i = 0; i < finalAssessors.length; i++)
    {
      User(finalAssessors[i]).notification("Assessment Cancled", tag, 8);
    }
    suicide(master);
  }

  function getTask(address assessorAddress) returns(string)
  {
    return assessmentTasks[assessorAddress];
  }

  function setResponse(string data)
  {
    if(assessors[currentAssessor] == 6 && now - referenceTime <= taskCompletionTime)
    {
      assessmentResponses[currentAssessor] = data;
      assessors[currentAssessor] = 7;
      User(currentAssessor).notification("Task Response Inputted", tag, 10);
      taskGradingTime = (3*(now - referenceTime))/2;
      referenceTime = now;
    }
    if(now - referenceTime > taskCompletionTime && assessors[currentAssessor]!=6)
    {
      User(assessee).notification("Did Not Submit Task Response On Time", tag, 11);
      Master(master).mapTokenBalance(currentAssessor, Master(master).getTokenBalance(assessee) - 1);
      cancelAssessment();
    }
  }

  function getResponse(address assesseeAddress) returns(string)
  {
    return assessmentResponses[assesseeAddress];
  }

  function setResult(int score)
  {
    if(numberCancelled >= numberOfAssessors)
    {
      cancelAssessment();
    }
    if(assessors[currentAssessor] == 7 && now - referenceTime <= taskGradingTime)
    {
      assessmentResults[currentAssessor] = score;
      addressFromScore[score] = currentAssessor;
      User(assessee).notification("Task Result Inputted", tag, 12);
      finalAssessors.push(currentAssessor);
    }
    if(now - referenceTime <= taskGradingTime && assessors[currentAssessor] != 7)
    {
      User(currentAssessor).notification("Did Not Submit Task Results On Time", tag, 13);
      User(assessee).notification("Assessor Has Not Graded In Time", tag, 14);
      Master(master).mapTokenBalance(currentAssessor, Master(master).getTokenBalance(assessee) - 1);
      User(currentAssessor).setReputation(User(currentAssessor).getReputation() + 1);
      numberCancelled++;
      setPotentialAssessor();
    }
    if(finalAssessors.length == numberOfAssessors)
    {
      calculateResult();
    }
    if(finalAssessors.length < numberOfAssessors)
    {
      setPotentialAssessor;
    }
  }

  function calculateResult()
  {
    int[][] clusters;
    int[] scores;
    int n = 0;
    int meanScore;
    int totalRelativeDistance;
    int meanAbsoluteDeviation;
    uint largestClusterIndex = 0;
    int averageScore;
    for(uint i = 0; i < numberOfAssessors; i++)
    {
      scores.push(assessmentResults[finalAssessors[i]]);
      n++;
    }
    for(uint j = 0; j < scores.length; j++)
    {
      meanScore += scores[j];
      inRewardCluster[score] = false;
    }
    meanScore /= n;
    for(uint k = 0; k < scores.length; k++)
    {
      int distanceFromMean = scores[k] - meanScore;
      if(distanceFromMean < 0)
      {
        distanceFromMean *= -1;
      }
      totalRelativeDistance += distanceFromMean;
    }
    meanAbsoluteDeviation = totalRelativeDistance/n;
    for(uint l = 0; l < scores.length; l++)
    {
      for(uint m = 0; m < scores.length; m++)
      {
        if(scores[l] - scores[m] <= meanAbsoluteDeviation)
        {
          clusters[l].push(scores[m]);
        }
      }
      if(clusters[l].length > clusters[largestClusterIndex].length)
      {
        largestClusterIndex = l;
      }
    }
    for(uint o = 0; o < clusters[largestClusterIndex].length; n++)
    {
      averageScore += clusters[largestClusterIndex][o];
      inRewardCluster[clusters[largestClusterIndex][o]] = true;
    }
    averageScore /= int(clusters[largestClusterIndex].length);
    finalScore = averageScore;
    if(averageScore > 0)
    {
      finalResult = true;
    }
    if(averageScore <= 0)
    {
      finalResult = false;
    }
    payout();
  }

  function confirmAssessor(uint confirm, bool timeKnow)
  {
    if(numberCancelled >= numberOfAssessors)
    {
      cancelAssessment();
    }
    if(assessors[currentAssessor] != 0 && now - referenceTime <= 180)
    {
      assessors[currentAssessor] = confirm;
      if(confirm == 1)
      {
        User(currentAssessor).notification("Confirmed As Potential Assessor", tag, 2);
        referenceTime = now;
      }
      if(confirm == 2 || confirm == 4)
      {
        User(currentAssessor).notification("Confirmed As Not Assessing", tag, 3);
        numberCancelled ++;
        setPotentialAssessor();
      }
      if(confirm == 5)
      {
        User(currentAssessor).notification("Confirmed As Assessing", tag, 9);
        referenceTime = now;
      }
    }
    if(now - referenceTime > 180)
    {
      if(timeKnow == false && assessors[currentAssessor]==3)
      {
      User(currentAssessor).notification("Did Not Respond In Time To Be Assessor", tag, 4);
      Master(master).mapTokenBalance(currentAssessor, Master(master).getTokenBalance(currentAssessor) - 1);
      setPotentialAssessor();
      }
      if(timeKnow == true && assessors[currentAssessor]==1)
      {
        User(currentAssessor).notification("Did Not Respond In Time To Be Assessor", tag, 4);
        setPotentialAssessor();
      }
    }
  }

  function returnResults()
  {
    Tag(tag).finishAssessment(finalResult, finalScore, assessee, address(this));
  }

  function payout()
  {
    for(uint i = 0; i < finalAssessors.length; i++)
    {
      int score = assessmentResults[finalAssessors[i]];
      int scoreDistance = ((score - finalScore)*100)/finalScore;
      if(scoreDistance < 0)
      {
        scoreDistance *= -1;
      }
      uint distance = uint(scoreDistance);
      if(inRewardCluster(score) = true)
      {
        Master(master).setTokenBalance(Master(master).getTokenBalance(finalAssessors[i]) + (500/(100 - scoreDistance)));
        User(finalAssessors[i]).notification("You Have Received Payment For Your Assessment", tag, 15);
      }
      if(inRewardCluster(score) = true)
      {
        Master(master).setTokenBalance(Master(master).getTokenBalance(finalAssessors[i]) - (500/(100 - scoreDistance)));
        User(finalAssessors[i]).notification("You Have Received A Fine For Your Assessment", tag, 16);
      }
    }
  }
}

contract User
{
  address user;
  address master;
  address[] acheivements;
  string userData;
  uint reputation;

  event Notification
  ( string _description,
    address _sender,
    address _user,
    address _tag,
    uint _code);

  function User(address userAddress, address masterAddress)
  {
    user = userAddress;
    master = masterAddress;
    reputation = 1;
  }

  function getReputation() returns(uint)
  {
    return reputation;
  }

  function setReputation(uint newReputation)
  {
    reputation = newReputation;
  }

  function notification(string description, address tag, uint code)
  {
    Notification(description, msg.sender, address(this), tag, code);
  }

  function setUserData(string hash)
  {
    userData = hash;
  }

  function getUserData() returns(string)
  {
    return userData;
  }

  function remove()
  {
    suicide(master);
  }
}

contract Master
{
  //Initialize master data store
  mapping (address => uint) tokenBalance;
  mapping (address => string) tagName;
  mapping (string => address) tagAddressFromName;
  mapping (address => address[]) achievements;
  mapping (address => bool) availability;
  mapping (address => address) users;

  event TagCreation
  ( string _tagName,
    address _tagAddress,
    address[] _parents);

  function Master()
  {
    tokenBalance[address(this)] = 1;
    address[] memory a;
    uint useless = addTag("account", a, "Initial Account Tag");
  }

  function mapTokenBalance(address user, uint balance)
  {
    if(tagAddressFromName[tagName[msg.sender]] == 0)
    {
      tokenBalance[user] = balance;
    }
  }
  function mapTagName(address tagAddress, string name)
  {
    tagName[tagAddress] = name;
  }
  function mapTagAddressFromName(string name, address tagAddress)
  {
    tagAddressFromName[name] = tagAddress;
  }
  function mapAchievement(address user, address achievment)
  {
    achievements[user].push(achievment);
  }
  function mapAvailability(address user, bool available)
  {
    availability[user] = available;
  }

  function getTokenBalance(address user) returns(uint)
  {
    return tokenBalance[user];
  }
  function getTagName(address tagAddress) returns(string)
  {
    return tagName[tagAddress];
  }
  function getTagAddressFromName(string name) returns(address)
  {
    return tagAddressFromName[name];
  }
  function getAchievement(address user) returns(address[])
  {
    return achievements[user];
  }
  function getNumberOfachievments(address user) returns(uint)
  {
    return achievements[user].length;
  }
  function getAvailability(address user) returns(bool)
  {
    return availability[user];
  }
 function getTagDescription(address tagAddress) returns(string)
  {
    return Tag(tagAddress).getDescription();
  }

  function addUser()
  {
    User newUser = new User(msg.sender, address(this));
    Tag(tagAddressFromName["account"]).startAssessment(address(newUser),5, 600);
  }

  function addTag(string name, address[] parentList, string description) returns(uint) //Creates a new tag contract
  {
    uint response = 0;
    address[] parents;
    if(tokenBalance[msg.sender] < 1)
    {
      response += 1;
    }
    if(tagAddressFromName[name] == 0)
    {
      response += 10;
    }
    if(response==0)
    {
      for(uint i=0; i<= parentList.length; i++) //adds all the given parents
      {
        if(parentList[i]==0)
        {
          response += 100*(10**i);
        }
        else
        {
          parents.push(parentList[i]);
        }
      }
      Tag newTag = new Tag(name, parents, address(this), description);
      address newTagAddress = address(newTag);
      tagName[newTagAddress] = name;
      tagAddressFromName[name] = newTagAddress;
      tokenBalance[msg.sender] -= 1;
      TagCreation(name, newTagAddress, parents);
    }
    return response;
  }
}

//Defines the meta-contract for a Tag
contract Tag
{
  address[] parentTags;
  address master;
  string name;
  string description;
  address[] owners; //Those who have earned the tag
  mapping(address => address[]) assessmentHistory; //All assessments completed
  mapping(address => uint) scores; //All positive assessements scores
  event CompletedAssessment
  ( address _assessee,
    bool _pass,
    uint _score,
    address _assessment);

  function Tag(string tagName, address[] parents, address masterAddress, string tagDescription)
  {
    name = tagName;
    parentTags = parents;
    master = masterAddress;
    description = tagDescription;
  }

  function getDescription() returns(string)
  {
    return description;
  }

  function getOwners() returns(address[])
  {
    return owners;
  }

  function getOwnerLength() returns(uint)
  {
    return owners.length;
  }

  function getOwner(uint index) returns(address)
  {
    return owners[index];
  }

  function getParents() returns(address[])
  {
    return parentTags;
  }

  function getParentsLength() returns(uint)
  {
    return parentTags.length;
  }

  function getParent(uint index) returns(address)
  {
      return parentTags[index];
  }

  function setAssessorPool(address tagAddress, address assessment)
  {
    for(uint i = 0; i < Tag(tagAddress).getOwnerLength() && Assessment(assessment).getAssessmentPoolSize() != 0; i++)
    {
      if(Assessment(assessment).getAssessorPoolLength() < Tag(tagAddress).getOwnerLength()/10)
      {
        address random = Tag(tagAddress).getOwner(getRandom(Tag(tagAddress).getOwnerLength()-1));
        if(Master(master).getAvailability(random) == true)
        {
          Assessment(assessment).addToAssessorPool(random);
          Assessment(assessment).setAssessmentPoolSize(Assessment(assessment).getAssessmentPoolSize() -1);
        }
      }
      else
      {
        for(uint j = 0; j < Tag(tagAddress).getParentsLength(); j++)
        {
          setAssessorPool(Tag(tagAddress).getParent(j), assessment);
        }
      }
      if(Assessment(assessment).getAssessmentPoolSize() <= 0)
      {
        Assessment(assessment).setPotentialAssessor();
      }
    }
  }

  function startAssessment(address assessee, uint size, uint timeForSettingTask)
  {
    Assessment newAssessment = new Assessment(assessee, address(this), master, timeForSettingTask);
    newAssessment.setNumberOfAssessors(size);
    newAssessment.setAssessmentPoolSize(size*20);
    setAssessorPool(address(this), address(newAssessment));
  }

  function finishAssessment(bool pass, uint score, address assessee, address assessment)
  {
    if(pass == true)
    {
      owners.push(assessee);
      scores[assessee] = score;
      Master(master).mapAchievement(assessee,address(this));
    }
    if(pass == false && address(this) == Master(master).getTagAddressFromName("account"))
    {
      User(assessee).remove();
    }
    assessmentHistory[assessee].push(assessment);
    CompletedAssessment(assessee, pass, score, assessment);
  }
  function getRandom(uint i) returns(uint)
  {
    return 12;
  }
}

//Defines the meta-contract for an assessment
contract Assessment
{
  address assessee; //We need a better word for this
  address[] assessorPool;
  mapping (address => uint) assessors;
  address[] finalAssessors;
  address tag;
  address master;
  uint poolSizeRemaining;
  uint numberOfAssessors;
  mapping(address => string) assessmentTasks; //Given by the assessors as IPFS hashes
  mapping(address => string) assessmentResponses; //Given by the assessee as IPFS hashes
  mapping(address => int) assessmentResults; //Pass/Fail and Score given by assessors
  mapping(int => address) addressFromScore;
  address currentAssessor;
  int finalScore;
  bool finalResult;
  uint taskCreationTime;
  uint taskCompletionTime;
  uint taskGradingTime;
  uint referenceTime;
  uint numberCancelled;

  function Assessment(address assesseeAddress, address tagAddress, address masterAddress, uint timeForTaskCreation)
  {
    assessee = assesseeAddress;
    tag = tagAddress;
    master = masterAddress;
    referenceTime = block.timestamp;
    taskCreationTime = timeForTaskCreation;
  }

  function getTaskCreationTime() returns(uint)
  {
      return taskCreationTime;
  }

  function getTaskCompletionTime() returns(uint)
  {
      return taskCompletionTime;
  }

  function setNumberOfAssessors(uint number)
  {
    numberOfAssessors = number;
  }

  function getNumberOfAssessors() returns(uint)
  {
    return numberOfAssessors;
  }

  function setAssessmentPoolSize(uint sizeRemaining)
  {
    poolSizeRemaining = sizeRemaining;
  }

  function getAssessmentPoolSize() returns(uint)
  {
    return poolSizeRemaining;
  }

  function addToAssessorPool(address potentialAddress)
  {
    assessorPool.push(potentialAddress);
  }

  function setPotentialAssessor()
  {
    bool potentialAssessorSet = false;
    while(potentialAssessorSet == false)
    {
      address randomAssessor = assessorPool[getRandom(assessorPool.length)];
      if(assessors[randomAssessor] == 0)
      {
        assessors[randomAssessor] = 3;
        currentAssessor = randomAssessor;
        potentialAssessorSet = true;
        User(randomAssessor).notification("Called As A Potential Assessor",tag, 1);
      }
    }
    referenceTime = now;
  }

  function getAssessorPoolLength() returns(uint)
  {
      return assessorPool.length;
  }

  function getRandom(uint i) returns(uint)
  {
    return 12;
  }

  function setTask(string data, uint timeLimit)
  {
    if(numberCancelled >= numberOfAssessors)
    {
      cancelAssessment();
    }
    if(assessors[currentAssessor] == 5 && now - referenceTime <= taskCreationTime)
    {
      assessmentTasks[currentAssessor] = data;
      taskCompletionTime = timeLimit;
      assessors[currentAssessor] = 6;
      User(currentAssessor).notification("Task Data Inputted", tag, 5);
      User(assessee).notification("New Task Available", tag, 7);
      referenceTime = now;
    }
    if(now - referenceTime > taskCreationTime && assessors[currentAssessor]!=5)
    {
      User(currentAssessor).notification("Did Not Submit Task On Time", tag, 6);
      Master(master).mapTokenBalance(currentAssessor, Master(master).getTokenBalance(currentAssessor) - 1);
      User(currentAssessor).setReputation(User(currentAssessor).getReputation() + 1);
      numberCancelled++;
      setPotentialAssessor();
    }
  }

  function cancelAssessment()
  {
    User(assessee).notification("Assessment Cancled", tag, 8);
    for(uint i = 0; i < finalAssessors.length; i++)
    {
      User(finalAssessors[i]).notification("Assessment Cancled", tag, 8);
    }
    suicide(master);
  }

  function getTask(address assessorAddress) returns(string)
  {
    return assessmentTasks[assessorAddress];
  }

  function setResponse(string data)
  {
    if(assessors[currentAssessor] == 6 && now - referenceTime <= taskCompletionTime)
    {
      assessmentResponses[currentAssessor] = data;
      assessors[currentAssessor] = 7;
      User(currentAssessor).notification("Task Response Inputted", tag, 10);
      taskGradingTime = (3*(now - referenceTime))/2;
      referenceTime = now;
    }
    if(now - referenceTime > taskCompletionTime && assessors[currentAssessor]!=6)
    {
      User(assessee).notification("Did Not Submit Task Response On Time", tag, 11);
      Master(master).mapTokenBalance(currentAssessor, Master(master).getTokenBalance(assessee) - 1);
      cancelAssessment();
    }
  }

  function getResponse(address assesseeAddress) returns(string)
  {
    return assessmentResponses[assesseeAddress];
  }

  function setResult(int score)
  {
    if(numberCancelled >= numberOfAssessors)
    {
      cancelAssessment();
    }
    if(assessors[currentAssessor] == 7 && now - referenceTime <= taskGradingTime)
    {
      assessmentResults[currentAssessor] = score;
      User(assessee).notification("Task Result Inputted", tag, 12);
      finalAssessors.push(currentAssessor);
    }
    if(now - referenceTime <= taskGradingTime && assessors[currentAssessor] != 7)
    {
      User(currentAssessor).notification("Did Not Submit Task Results On Time", tag, 13);
      User(assessee).notification("Assessor Has Not Graded In Time", tag, 14);
      Master(master).mapTokenBalance(currentAssessor, Master(master).getTokenBalance(assessee) - 1);
      User(currentAssessor).setReputation(User(currentAssessor).getReputation() + 1);
      numberCancelled++;
      setPotentialAssessor();
    }
    if(finalAssessors.length == numberOfAssessors)
    {
      calculateResult();
    }
    if(finalAssessors.length < numberOfAssessors)
    {
      setPotentialAssessor;
    }
  }

  function calculateResult()
  {
    int[][] clusters;
    int[] scores;
    int n = 0;
    int meanScore;
    int totalRelativeDistance;
    int meanAbsoluteDeviation;
    uint largestClusterIndex = 0;
    int averageScore;
    for(uint i = 0; i < numberOfAssessors; i++)
    {
      scores.push(assessmentResults[finalAssessors[i]]);
      n++;
    }
    for(uint j = 0; j < scores.length; j++)
    {
      meanScore += scores[j];
    }
    meanScore /= n;
    for(uint k = 0; k < scores.length; k++)
    {
      int distanceFromMean = scores[k] - meanScore;
      if(distanceFromMean < 0)
      {
        distanceFromMean *= -1;
      }
      totalRelativeDistance += distanceFromMean;
    }
    meanAbsoluteDeviation = totalRelativeDistance/n;
    for(uint l = 0; l < scores.length; l++)
    {
      for(uint m = 0; m < scores.length; m++)
      {
        if(scores[l] - scores[m] <= meanAbsoluteDeviation)
        {
          clusters[l].push(scores[m]);
        }
      }
      if(clusters[l].length > clusters[largestClusterIndex].length)
      {
        largestClusterIndex = l;
      }
    }
    for(uint n = 0; n < clusters[largestClusterIndex].length; n++)
    {
      averageScore += clusters[largestClusterIndex];
    }
    averageScore /= clusters[largestClusterIndex].length;
    finalScore = averageScore;
    if(averageScore > 0)
    {
      finalResult = true;
    }
    if(averageScore <= 0)
    {
      finalResult = false;
    }
    payout();
  }

  function confirmAssessor(uint confirm, bool timeKnow)
  {
    if(numberCancelled >= numberOfAssessors)
    {
      cancelAssessment();
    }
    if(assessors[currentAssessor] != 0 && now - referenceTime <= 180)
    {
      assessors[currentAssessor] = confirm;
      if(confirm == 1)
      {
        User(currentAssessor).notification("Confirmed As Potential Assessor", tag, 2);
        referenceTime = now;
      }
      if(confirm == 2 || confirm == 4)
      {
        User(currentAssessor).notification("Confirmed As Not Assessing", tag, 3);
        numberCancelled ++;
        setPotentialAssessor();
      }
      if(confirm == 5)
      {
        User(currentAssessor).notification("Confirmed As Assessing", tag, 9);
        referenceTime = now;
      }
    }
    if(now - referenceTime > 180)
    {
      if(timeKnow == false && assessors[currentAssessor]==3)
      {
      User(currentAssessor).notification("Did Not Respond In Time To Be Assessor", tag, 4);
      Master(master).mapTokenBalance(currentAssessor, Master(master).getTokenBalance(currentAssessor) - 1);
      setPotentialAssessor();
      }
      if(timeKnow == true && assessors[currentAssessor]==1)
      {
        User(currentAssessor).notification("Did Not Respond In Time To Be Assessor", tag, 4);
        setPotentialAssessor();
      }
    }
  }

  function returnResults()
  {
    Tag(tag).finishAssessment(finalResult, finalScore, assessee, address(this));
  }

  function cashout()
  {

  }
}

contract User
{
  address user;
  address master;
  address[] acheivements;
  string userData;
  uint reputation;

  event Notification
  ( string _description,
    address _sender,
    address _user,
    address _tag,
    uint _code);

  function User(address userAddress, address masterAddress)
  {
    user = userAddress;
    master = masterAddress;
    reputation = 1;
  }

  function getReputation() returns(uint)
  {
    return reputation;
  }

  function setReputation(uint newReputation)
  {
    reputation = newReputation;
  }

  function notification(string description, address tag, uint code)
  {
    Notification(description, msg.sender, address(this), tag, code);
  }

  function setUserData(string hash)
  {
    userData = hash;
  }

  function getUserData() returns(string)
  {
    return userData;
  }

  function remove()
  {
    suicide(master);
  }
}


initial commit

initial commit

contract mixer {

    struct anon_registeration{
        address sender;
        uint value;
        bool valid;
    }

    struct public_user{
        uint deposit;
        address addr;
        bool valid;
        uint revealed_deposit;
        anon_registeration[] registrations; // used only if there is violation
    }

    struct mixing_deal{
        uint start_time;
        public_user[] users; // must hold array to iterate them
        mapping (address=>uint) user_to_index_mapping;
        anon_registeration[] registrations;
        mapping (address=>uint) registration_to_index_mapping;

        uint32 min_num_participants;
        uint   registration_deposit_size_in_wei;
        uint   phase_time_in_secs;

        uint   deposit_sum;
        uint   registration_sum;
        bool   violated;
    }

    mixing_deal[] deals;

    enum deal_state{
        invalid,

        initial_deposit,
        anonymous_registration,
        anonymous_withdraw,

        anonymous_revealing,
        public_withdraw_not_enough_parties,
        public_withdraw_violation
    }

    modifier non_payable {
        if (msg.value > 0 )
            throw;
        _
    }
    function mixer(){
        deals.length = 0;
    }

    function not_after_phase(mixing_deal deal, uint phase) constant private returns(bool){
        return deal.start_time + deal.phase_time_in_secs * phase >= now;
    }

    function get_deal_state(uint deal_id) constant returns(deal_state){
        if( deals.length >= deal_id ) return deal_state.invalid;
        mixing_deal deal = deals[ deal_id ];
        if( not_after_phase(deal, 1) ) return deal_state.initial_deposit;

        if( deal.users.length < deal.min_num_participants ) return deal_state.public_withdraw_not_enough_parties;

        if( not_after_phase(deal, 2) ) return deal_state.anonymous_registration;

        if( deal.violated ){
            if( not_after_phase(deal, 3) ) return deal_state.anonymous_revealing;
            // else - phase 4
            return deal_state.public_withdraw_violation;
        }
        else{
            return deal_state.anonymous_withdraw;
        }
    }

    function create_new_deal(uint32 _min_num_participants,
                             uint   _registration_deposit_size_in_wei,
                             uint32 _phase_time_in_hours ) non_payable returns (uint) {
        uint deal_id = deals.length;
        deals.length += 1;

        deals[ deal_id ].start_time = now;
        deals[ deal_id ].min_num_participants = _min_num_participants;
        deals[ deal_id ].registration_deposit_size_in_wei = _registration_deposit_size_in_wei;
        deals[ deal_id ].phase_time_in_secs = _phase_time_in_hours * 1 hours;

        deals[ deal_id ].deposit_sum = 0;
        deals[ deal_id ].registration_sum = 0;
        deals[ deal_id ].violated = false;

        return deal_id;
    }

    function make_initial_deposit( uint deal_id ){
        if( get_deal_state( deal_id ) != deal_state.initial_deposit ) throw;

        mixing_deal deal = deals[ deal_id ];
        uint user_index = deal.users.length;
        deal.users.length += 1;

        deal.users[ user_index ].deposit = msg.value;
        deal.users[ user_index ].addr = msg.sender;
        deal.users[ user_index ].revealed_deposit = 0;
        deal.users[ user_index ].valid = true;

        deal.user_to_index_mapping[ msg.sender ] = user_index;

        deal.deposit_sum += msg.value;
    }

    function make_anonymous_registration( uint deal_id, uint amount_in_wei ){
        if( get_deal_state( deal_id ) != deal_state.anonymous_registration ) throw;
        if( amount_in_wei > 1024 * 1024 * 1024 ether ) throw; // prevent possible overflows

        mixing_deal deal = deals[ deal_id ];

        if( msg.value != deal.registration_deposit_size_in_wei ) throw;

        uint reg_id = deal.registrations.length;
        deal.registrations.length += 1;

        deal.registrations[ reg_id ].sender = msg.sender;
        deal.registrations[ reg_id ].value = amount_in_wei;
        deal.registrations[ reg_id ].valid = true;

        deal.registration_to_index_mapping[ msg.sender ] = reg_id;

        deals[ deal_id ].registration_sum += amount_in_wei;

        if( deals[ deal_id ].registration_sum > deal.deposit_sum ) deals[ deal_id ].violated = true;
    }

    function make_anonymous_withdraw(uint deal_id) non_payable{
        if( get_deal_state( deal_id ) != deal_state.anonymous_withdraw ) throw;
        uint reg_index = deals[ deal_id ].registration_to_index_mapping[ msg.sender ];
        anon_registeration reg = deals[ deal_id ].registrations[ reg_index ];
        if( ! reg.valid ) throw;

        // invalidate for next time
        reg.valid = false;

        uint value = reg.value + deals[ deal_id ].deposit_sum;

        if( ! reg.sender.send( value ) ) throw;
    }

    function reveal_registration( uint deal_id, address public_address ) non_payable{
        if( get_deal_state( deal_id ) != deal_state.anonymous_revealing ) throw;

        mixing_deal deal = deals[ deal_id ];

        // get registration
        uint reg_index = deal.registration_to_index_mapping[ msg.sender ];
        anon_registeration reg = deal.registrations[ reg_index ];
        if( ! reg.valid ) throw;

        // get user
        uint user_index = deal.user_to_index_mapping[ public_address ];
        public_user user = deal.users[ user_index ];
        if( ! user.valid ) throw;

        // assume no overflows
        if( user.deposit >= user.revealed_deposit + reg.value ){
            user.registrations.length += 1;
            user.registrations[ user.registrations.length - 1 ] = reg;
            user.revealed_deposit += reg.value;
            return;
        }

        // else - replace with maximal value deposit
        uint max_index = 0;
        uint max_value = user.registrations[ 0 ].value;
        for ( uint index = 1; index < user.registrations.length; index += 1 ){
            if( user.registrations[ index ].value > max_value ){
                max_index = index;
                max_value = user.registrations[ index ].value;
            }
        }
        if( max_value > reg.value ) return; // ignore this registration
        // else - replace max with new reg
        user.registrations[ max_index ] = reg;
        user.revealed_deposit = user.revealed_deposit + reg.value - max_value;
    }

    function public_withdraw( uint deal_id ) non_payable{
        if( ( get_deal_state( deal_id ) != deal_state.public_withdraw_not_enough_parties ) &&
            ( get_deal_state( deal_id ) != deal_state.public_withdraw_violation ) ) throw;

        mixing_deal deal = deals[ deal_id ];
        uint user_index = deal.user_to_index_mapping[ msg.sender ];
        public_user user = deal.users[ user_index ];
        if( ! user.valid ) throw;

        uint value = user.deposit;

        if( get_deal_state( deal_id ) == deal_state.public_withdraw_violation ){
            value += user.registrations.length * deal.registration_deposit_size_in_wei;
        }

        user.valid = false;

        if( ! user.addr.send( value ) ) throw;
    }

}

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


implement installation deadline and re-funding before voting

pragma solidity ^0.4.13;

contract Voting {

    enum Role { OWNER, COMPANY, RESIDENT, AUDITOR }
    enum State { INITIAL, FUNDED, OPEN, APPROVED, INSTALLING, AUDITED, CLOSED, FAILED }

    mapping (address => Role) roles;
    State public state;

    event Funded(address addr, uint amount);
    event VotingOpened(uint threshold);
    event Approved(address addr, uint total);
    event VotingClosedSuccess(uint total);
    event VotingFailed();
    event Withdrawn(address addr, uint amount);
    event Audited();
    event InstallationFailed();
    event Closed();

    mapping (address => bool) approved;

    uint numRoles = 4;
    uint numApproved;   // number of residents who approved
    uint threshold;     // required support in persent (1 to 100)
    uint firstWithdrawalShare = 50;     // share that company withdraws before installation
    uint votingDeadline;
    uint defaultVotingDuration = 1 minutes;
    uint installationDeadline;
    uint defaultInstallationDuration = 1 minutes;

	// Addresses generated from seed.txt
    address[] private testAddresses;

    function assignTestAddresses(bool isRpc) internal {
        if (isRpc) {
    		testAddresses.push(0x0120fe6e3aa2c936e6d2f88062b266c46c408f98);
    		testAddresses.push(0xa8fc189694dc8ba03c027d470b77c09b7d13471e);
    		testAddresses.push(0xdbf73038f3e4a5d27e38004c36dc6ce82165794f);
    		testAddresses.push(0x692b50dc6d0021a73ec50fcd3ad78d3c121be360);
    		testAddresses.push(0xc396dfc357c849c5e4fbbe1f130eb469675af895);
    		testAddresses.push(0x07efc80760137f58a43e44a9bede15da8053d730);
    		testAddresses.push(0xfe8699b505180f51966e56f118e66544dea311bd);
    		testAddresses.push(0x276ae02aa2710bebc571f3647d64d9b440f998d6);
    		testAddresses.push(0x43882f2be5ccf7ba1cf848e202683385d5fb93bb);
    		testAddresses.push(0x76c780eb591481c086e1a0574b16c4f52e5aa352);
        } else {
            testAddresses.push(0xca35b7d915458ef540ade6068dfe2f44e8fa733c);
            testAddresses.push(0x14723a09acff6d2a60dcdf7aa4aff308fddc160c);
            testAddresses.push(0x4b0897b0513fdc7c541b6d9d7e929c4e5364d2db);
            testAddresses.push(0x583031d1113ad414f02576bd6afabfb302140225);
            testAddresses.push(0xdd870fa1b7c4700f2bd7f44238821c26f7392148);
        }
    }

	function assignRoles() internal {
	    require(msg.sender == testAddresses[0]);
	    require(testAddresses.length >= numRoles);
		roles[testAddresses[0]] = Role.OWNER;
		roles[testAddresses[1]] = Role.COMPANY;
		roles[testAddresses[2]] = Role.AUDITOR;
		for (uint i = numRoles-1; i < testAddresses.length; i++) {
		    roles[testAddresses[i]] = Role.RESIDENT;
		}
	}

	function Voting(bool isRpc) {
	    assignTestAddresses(isRpc);
	    assignRoles();
	    state = State.INITIAL;
	}

	function () payable {
	    require(roles[msg.sender] == Role.OWNER);
	    require(state == State.INITIAL || state == State.FUNDED);
	    state = State.FUNDED;
	    Funded(msg.sender, msg.value);
	}

	// owner can deposit and withdraw ether before voting starts
	function withdrawBeforeVoting(uint _amount) {
	    require(state == State.FUNDED);
	    require(roles[msg.sender] == Role.OWNER);
	    withdraw(_amount);
	}

	function startVoting(uint _thresholdPercent) {
	    require(roles[msg.sender] == Role.OWNER);
	    require(_thresholdPercent > 0 && _thresholdPercent <= 100);
	    require(state == State.FUNDED);
	    votingDeadline = now + defaultVotingDuration;
	    threshold = (_thresholdPercent * (testAddresses.length - numRoles + 1) / 100);
	    state = State.OPEN;
	    VotingOpened(threshold);
	}

	function approve() {
	    require(now < votingDeadline);
	    require(roles[msg.sender] == Role.RESIDENT);
	    require(state == State.OPEN);
	    approved[msg.sender] = true;
	    numApproved += 1;
	    Approved(msg.sender, numApproved);
	    if (numApproved >= threshold) {
	        state = State.APPROVED;
	        installationDeadline = now + defaultInstallationDuration;
	        VotingClosedSuccess(numApproved);
	    }
	}

	function closeFailedVotingAndWithdraw() {
	    require(now >= votingDeadline);    // voting deadline passed
	    require(state == State.OPEN);      // but voting still "opened"
	    require(roles[msg.sender] == Role.OWNER);
	    state = State.FAILED;
	    VotingFailed();
	    withdraw(this.balance);
	}

	function closeFailedInstallationAndWithdraw() {
	    require(now >= installationDeadline);   // installation deadline passed
	    require(state == State.APPROVED || state == State.INSTALLING);      // but nothing was installed
	    require(roles[msg.sender] == Role.OWNER);
	    state = State.FAILED;
	    InstallationFailed();
	    withdraw(this.balance);
	}

	function withdraw(uint amount) internal {
	    msg.sender.transfer(amount);
	    Withdrawn(msg.sender, amount);
	}

	function withdrawFirst() {
	    require(now < installationDeadline);
	    require(roles[msg.sender] == Role.COMPANY);
	    require(state == State.APPROVED);
	    withdraw(this.balance * firstWithdrawalShare / 100);
	    state = State.INSTALLING;
	}

	function auditConfirm() {
	    require(now < installationDeadline);
	    require(roles[msg.sender] == Role.AUDITOR);
	    require(state == State.INSTALLING);
	    state = State.AUDITED;
	    Audited();
	}

	function withdrawSecond() {
	    require(roles[msg.sender] == Role.COMPANY);
	    require(state == State.AUDITED);
	    withdraw(this.balance);
	    state = State.CLOSED;
	    Closed();
	}

	//// HELPERS ////

	function getState() constant returns (uint) {
	    return uint(state);
	}

}

pragma solidity ^0.4.13;

contract Voting {

    enum Role { OWNER, COMPANY, RESIDENT, AUDITOR }
    enum State { INITIAL, FUNDED, OPEN, APPROVED, INSTALLIING, AUDITED, CLOSED, FAILED }

    mapping (address => Role) roles;
    State public state;

    event Funded(address addr, uint amount);
    event VotingOpened(uint threshold);
    event Approved(address addr, uint total);
    event VotingClosedSuccess(uint total);
    event VotingClosedFailure();
    event Withdrawn(address addr, uint amount);
    event Audited();
    event Closed();

    mapping (address => bool) approved;

    uint numRoles = 4;
    uint numApproved;   // number of residents who approved
    uint threshold;     // required support in persent (1 to 100)
    uint firstWithdrawalShare = 50;     // share that company withdraws before installation
    uint votingDeadline;
    uint defaultVotingDuration = 1 minutes;

	// Addresses generated from seed.txt
    address[] private testAddresses;

    function assignTestAddresses(bool isRpc) internal {
        if (isRpc) {
    		testAddresses.push(0x0120fe6e3aa2c936e6d2f88062b266c46c408f98);
    		testAddresses.push(0xa8fc189694dc8ba03c027d470b77c09b7d13471e);
    		testAddresses.push(0xdbf73038f3e4a5d27e38004c36dc6ce82165794f);
    		testAddresses.push(0x692b50dc6d0021a73ec50fcd3ad78d3c121be360);
    		testAddresses.push(0xc396dfc357c849c5e4fbbe1f130eb469675af895);
    		testAddresses.push(0x07efc80760137f58a43e44a9bede15da8053d730);
    		testAddresses.push(0xfe8699b505180f51966e56f118e66544dea311bd);
    		testAddresses.push(0x276ae02aa2710bebc571f3647d64d9b440f998d6);
    		testAddresses.push(0x43882f2be5ccf7ba1cf848e202683385d5fb93bb);
    		testAddresses.push(0x76c780eb591481c086e1a0574b16c4f52e5aa352);
        } else {
            testAddresses.push(0xca35b7d915458ef540ade6068dfe2f44e8fa733c);
            testAddresses.push(0x14723a09acff6d2a60dcdf7aa4aff308fddc160c);
            testAddresses.push(0x4b0897b0513fdc7c541b6d9d7e929c4e5364d2db);
            testAddresses.push(0x583031d1113ad414f02576bd6afabfb302140225);
            testAddresses.push(0xdd870fa1b7c4700f2bd7f44238821c26f7392148);
        }
    }

	function assignRoles() internal {
	    require(msg.sender == testAddresses[0]);
	    require(testAddresses.length >= numRoles);
		roles[testAddresses[0]] = Role.OWNER;
		roles[testAddresses[1]] = Role.COMPANY;
		roles[testAddresses[2]] = Role.AUDITOR;
		for (uint i = numRoles-1; i < testAddresses.length; i++) {
		    roles[testAddresses[i]] = Role.RESIDENT;
		}
	}

	function Voting(bool isRpc) {
	    assignTestAddresses(isRpc);
	    assignRoles();
	    state = State.INITIAL;
	}

	function () payable {
	    require(roles[msg.sender] == Role.OWNER);
	    require(state == State.INITIAL || state == State.FUNDED);
	    state = State.FUNDED;
	    Funded(msg.sender, msg.value);
	}

	function startVoting(uint _thresholdPercent) {
	    require(roles[msg.sender] == Role.OWNER);
	    require(_thresholdPercent > 0 && _thresholdPercent <= 100);
	    require(state == State.FUNDED);
	    votingDeadline = now + defaultVotingDuration;
	    threshold = (_thresholdPercent * (testAddresses.length - numRoles + 1) / 100);
	    state = State.OPEN;
	    VotingOpened(threshold);
	}

	function approve() {
	    require(now < votingDeadline);
	    require(roles[msg.sender] == Role.RESIDENT);
	    require(state == State.OPEN);
	    approved[msg.sender] = true;
	    numApproved += 1;
	    Approved(msg.sender, numApproved);
	    if (numApproved >= threshold) {
	        state = State.APPROVED;
	        VotingClosedSuccess(numApproved);
	    }
	}

	function closeFailedVotingAndWithdraw() {
	    require(now >= votingDeadline);    // voting deadline passed
	    require(state == State.OPEN);      // but voting still "opened"
	    require(roles[msg.sender] == Role.OWNER);
	    state = State.FAILED;
	    VotingClosedFailure();
	    withdraw(this.balance);
	}

	function withdraw(uint amount) internal {
	    require(now >= votingDeadline);
	    msg.sender.transfer(amount);
	    Withdrawn(msg.sender, amount);
	}

	function withdrawFirst() {
	    require(roles[msg.sender] == Role.COMPANY);
	    require(state == State.APPROVED);
	    withdraw(this.balance * firstWithdrawalShare / 100);
	    state = State.INSTALLIING;
	}

	function auditConfirm() {
	    require(now >= votingDeadline);
	    require(roles[msg.sender] == Role.AUDITOR);
	    require(state == State.INSTALLIING);
	    state = State.AUDITED;
	    Audited();
	}

	function withdrawSecond() {
	    require(roles[msg.sender] == Role.COMPANY);
	    require(state == State.AUDITED);
	    withdraw(this.balance);
	    state = State.CLOSED;
	    Closed();
	}

}


removing dublicate line

removing dublicate line

pragma solidity ^0.4.0;

import "./Token.sol";

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

    struct Participant
    {
        address node_address;
        uint256 balance;
        uint256 netted;
        uint256 transferred_amount;
        uint256 amount;
        bytes merkle_proof;
        bytes32 hashlock;
        bytes32 secret;
        uint256 expiration;
        uint64 nonce;
        address asset;
        address recipient;
        bytes32 locksroot;
        Lock[] unlocked;
    }

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

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

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

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

    modifier notClosingAddress(Data storage self, address caller) {
        if (caller == self.closing_address)
            throw;
        _;
    }

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

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

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

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

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

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

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

            return (true, balance);
        }

        return (false, 0);
    }

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

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

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

        return 0x0;
    }

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

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

    function closeSingleTransfer(Data storage self, address caller_address, bytes signed_transfer) {
        bytes memory transfer_raw;
        address transfer_address;

        if (self.settled > 0 || self.closed > 0) {
            throw;
        }

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

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

        if (caller_address != node1.node_address && caller_address != node2.node_address) {
            throw;
        }

        (transfer_raw, transfer_address) = getTransferRawAddress(signed_transfer);

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

        decodeAndAssign(sender, transfer_raw);

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

    /// @notice close(bytes, bytes) to close a channel between to parties
    /// @dev Close the channel between two parties
    /// @param first_encoded (bytes) the last sent transfer of the msg.sender
    /// @param second_encoded (bytes) the last sent transfer of the msg.sender
    function close(
        Data storage self,
        address caller_address,
        bytes first_encoded,
        bytes second_encoded)
    {
        bytes memory first_raw;
        bytes memory second_raw;
        address first_address;
        address second_address;
        bytes32 transfer_sender;

        if (self.settled > 0 || self.closed > 0) {
            throw;
        }

        if (first_encoded.length <= 65 || second_encoded.length <= 65) {
            throw;
        }

        (first_raw, first_address) = getTransferRawAddress(first_encoded);
        (second_raw, second_address) = getTransferRawAddress(second_encoded);

        if (first_address == second_address) {
            throw;
        }

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

        if (caller_address != node1.node_address && caller_address != node2.node_address) {
            throw;
        }

        if (node1.node_address == first_address) {
            Participant storage first_sender = node1;
        } else if (node2.node_address == first_address) {
            first_sender = node2;
        } else {
            throw;
        }

        if (node1.node_address == second_address) {
            Participant storage second_sender = node1;
        } else if (node2.node_address == second_address) {
            second_sender = node2;
        } else {
            throw;
        }

        decodeAndAssign(first_sender, first_raw);
        decodeAndAssign(second_sender, second_raw);

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

    /// @notice updateTransfer(bytes) to update last known transfer
    /// @dev Allow the partner to update the last known transfer
    function updateTransfer(Data storage self, address caller_address, bytes signed_transfer)
        notSettledButClosed(self)
        stillTimeout(self)
        notClosingAddress(self, caller_address)
    {
        uint64 nonce;
        bytes memory transfer_raw;
        address transfer_address;

        (transfer_raw, transfer_address) = getTransferRawAddress(signed_transfer);

        // transfer address must be from counter party
        if (self.closing_address != transfer_address) {
            throw;
        }

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

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

        assembly {
            nonce := mload(add(transfer_raw, 12))  // skip cmdid and padding
        }

        if (nonce < sender.nonce || nonce == sender.nonce) {
            throw;
        }

        decodeAndAssign(sender, transfer_raw);

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

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

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

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

        if (expiration < block.number)
            throw;

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

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

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

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

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

        if (participant.locksroot != h)
            throw;

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

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

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

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

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

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

        self.settled = block.number;

        total_netted = node1.netted + node2.netted;
        total_deposit = node1.balance + node2.balance;

        if (total_netted != total_deposit) {
            throw;
        }

        if (!self.token.transfer(node1.node_address, node1.netted)) {
            throw;
        }
        if (!self.token.transfer(node2.node_address, node2.netted)) {
            throw;
        }
    }

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

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

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

        return (transfer_raw, transfer_address);
    }

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

        cmdid = uint(transfer_raw[0]);

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

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

    // TODO: use sstore instead of these temporaries

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        }
    }

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

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

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

pragma solidity ^0.4.0;

import "./Token.sol";

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

    struct Participant
    {
        address node_address;
        uint256 balance;
        uint256 netted;
        uint256 transferred_amount;
        uint256 amount;
        bytes merkle_proof;
        bytes32 hashlock;
        bytes32 secret;
        uint256 expiration;
        uint64 nonce;
        address asset;
        address recipient;
        bytes32 locksroot;
        Lock[] unlocked;
    }

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

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

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

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

    modifier notClosingAddress(Data storage self, address caller) {
        if (caller == self.closing_address)
            throw;
        _;
    }

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

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

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

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

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

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

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

            return (true, balance);
        }

        return (false, 0);
    }

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

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

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

        return 0x0;
    }

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

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

    function closeSingleTransfer(Data storage self, address caller_address, bytes signed_transfer) {
        bytes memory transfer_raw;
        address transfer_address;

        if (self.settled > 0 || self.closed > 0) {
            throw;
        }

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

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

        if (caller_address != node1.node_address && caller_address != node2.node_address) {
            throw;
        }

        (transfer_raw, transfer_address) = getTransferRawAddress(signed_transfer);

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

        decodeAndAssign(sender, transfer_raw);

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

    /// @notice close(bytes, bytes) to close a channel between to parties
    /// @dev Close the channel between two parties
    /// @param first_encoded (bytes) the last sent transfer of the msg.sender
    /// @param second_encoded (bytes) the last sent transfer of the msg.sender
    function close(
        Data storage self,
        address caller_address,
        bytes first_encoded,
        bytes second_encoded)
    {
        bytes memory first_raw;
        bytes memory second_raw;
        address first_address;
        address second_address;
        bytes32 transfer_sender;

        if (self.settled > 0 || self.closed > 0) {
            throw;
        }

        if (first_encoded.length <= 65 || second_encoded.length <= 65) {
            throw;
        }

        (first_raw, first_address) = getTransferRawAddress(first_encoded);
        (second_raw, second_address) = getTransferRawAddress(second_encoded);

        if (first_address == second_address) {
            throw;
        }

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

        if (caller_address != node1.node_address && caller_address != node2.node_address) {
            throw;
        }

        if (node1.node_address == first_address) {
            Participant storage first_sender = node1;
        } else if (node2.node_address == first_address) {
            first_sender = node2;
        } else {
            throw;
        }

        if (node1.node_address == second_address) {
            Participant storage second_sender = node1;
        } else if (node2.node_address == second_address) {
            second_sender = node2;
        } else {
            throw;
        }

        decodeAndAssign(first_sender, first_raw);
        decodeAndAssign(second_sender, second_raw);

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

    /// @notice updateTransfer(bytes) to update last known transfer
    /// @dev Allow the partner to update the last known transfer
    function updateTransfer(Data storage self, address caller_address, bytes signed_transfer)
        notSettledButClosed(self)
        stillTimeout(self)
        notClosingAddress(self, caller_address)
    {
        uint64 nonce;
        bytes memory transfer_raw;
        address transfer_address;

        (transfer_raw, transfer_address) = getTransferRawAddress(signed_transfer);

        // transfer address must be from counter party
        if (self.closing_address != transfer_address) {
            throw;
        }

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

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

        assembly {
            nonce := mload(add(transfer_raw, 12))  // skip cmdid and padding
        }

        if (nonce < sender.nonce || nonce == sender.nonce) {
            throw;
        }

        decodeAndAssign(sender, transfer_raw);

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

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

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

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

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

        if (expiration < block.number)
            throw;

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

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

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

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

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

        if (participant.locksroot != h)
            throw;

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

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

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

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

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

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

        self.settled = block.number;

        total_netted = node1.netted + node2.netted;
        total_deposit = node1.balance + node2.balance;

        if (total_netted != total_deposit) {
            throw;
        }

        if (!self.token.transfer(node1.node_address, node1.netted)) {
            throw;
        }
        if (!self.token.transfer(node2.node_address, node2.netted)) {
            throw;
        }
    }

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

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

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

        return (transfer_raw, transfer_address);
    }

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

        cmdid = uint(transfer_raw[0]);

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

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

    // TODO: use sstore instead of these temporaries

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        }
    }

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

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

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


revert some changes made to contract

revert some changes made to contract

pragma solidity ^0.4.25;

contract SimpleStorage {
  uint public storedData;
  address public registar;
  address owner;
  event EventOnSet2(bool passed, string message);

  constructor(uint initialValue) public {
    storedData = initialValue;
    owner = msg.sender;
  }

  function set(uint x) public {
    storedData = x;
    //require(msg.sender == owner);
    //require(msg.sender == 0x0);
    //storedData = x + 2;
  }

  function set2(uint x) public {
    storedData = x;
    emit EventOnSet2(true, "hi");
  }

  function get() public view returns (uint retVal) {
    return storedData;
  }

  function getS() public pure returns (string d) {
    return "hello";
  }

  function setRegistar(address x) public {
    registar = x;
  }

}

pragma solidity ^0.4.25;

contract SimpleStorage {
  uint public storedData;
  address owner;

  constructor(uint initialValue) public {
    storedData = initialValue;
    owner = msg.sender;
  }

  function set(uint x) public {
    storedData = x;
    require(msg.sender == owner);
    //require(msg.sender == 0x0);
    storedData = x + 2;
  }

  function get() public view returns (uint retVal) {
    return storedData;
  }

}


Reorganise function orders

Reorganise function orders

import './zeppelin/Rejector.sol';
import './zeppelin/Ownable.sol';
import './zeppelin/Killable.sol';

contract Conference is Rejector, Killable {
	string public name;
	uint256 public totalBalance;
	uint256 public deposit;
	uint public limitOfParticipants;
	uint public registered;
	uint public attended;
	bool public ended;
	uint public endedAt;
	uint public coolingPeriod;

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

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

	event Register(string participantName, address addr, uint256 balance, uint256 value);
	event Attend(address addr, uint256 balance);
	event Payback(address addr, uint256 _payout, uint256 balance, bool paid);

	/* Modifiers */
	modifier sentDepositOrReturn {
		if (msg.value == deposit) {
			_
		}else{
			if(msg.sender.send(msg.value)){/* not much you can do */}
		}
	}

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

	modifier onlyActiveOrReturn {
		if (ended == false) {
			_
		}else{
			if(msg.sender.send(msg.value)){/*not much you can do*/}
		}
	}

	modifier withinLimitOrReturn {
		if (registered < limitOfParticipants ) {
			_
		}else{
			if(msg.sender.send(msg.value)){/* not much you can do */}
		}
	}

	modifier isEnded {
		if (ended){
			_
		}
	}

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

	modifier onlyPayable {
		Participant participant = participants[msg.sender];
		if (participant.payout > 0){
			_
		}
	}

	modifier notPaid {
		Participant participant = participants[msg.sender];
		if (participant.paid == false){
			_
		}
	}

	/* Public functions */

	function Conference(uint _coolingPeriod) {
		name = 'Edcon Post conference lunch';
		deposit = 1 ether;
		totalBalance = 0;
		registered = 0;
		attended = 0;
		limitOfParticipants = 10;
		ended = false;
		if (_coolingPeriod != 0) {
			coolingPeriod = _coolingPeriod;
		} else {
			coolingPeriod = 1 weeks;
		}
	}

	function register(string _participant) public sentDepositOrReturn withinLimitOrReturn onlyActiveOrReturn{
		Register(_participant, msg.sender, msg.sender.balance, msg.value);
		if (isRegistered(msg.sender)) throw;
		registered++;
		participantsIndex[registered] = msg.sender;
		participants[msg.sender] = Participant(_participant, msg.sender, false, 0, false);
		totalBalance = totalBalance + (deposit * 1);
	}

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

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

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

	function withdraw() public onlyPayable notPaid {
		Participant participant = participants[msg.sender];
		if (msg.sender.send(participant.payout)) {
			participant.paid = true;
			totalBalance -= participant.payout;
		}
	}

	/* Admin only functions */

	function payback() onlyOwner{
		for(uint i=1;i<=registered;i++){
			if(participants[participantsIndex[i]].attended){
				participants[participantsIndex[i]].payout = payout();
			}
		}
		ended = true;
		endedAt = now;
	}

	function cancel() onlyOwner onlyActive{
		for(uint i=1;i<=registered;i++){
			participants[participantsIndex[i]].payout = deposit;
		}
		ended = true;
		endedAt = now;
	}

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

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

	function attend(address _addr) public onlyOwner{
		if (isRegistered(_addr) != true) throw;
		if (isAttended(_addr)) throw;
		Attend(_addr, msg.sender.balance);
		participants[_addr].attended = true;
		attended++;
	}

	/* Private functions */
	function payout() private returns(uint256){
		return totalBalance / uint(attended);
	}
}

import './zeppelin/Rejector.sol';
import './zeppelin/Ownable.sol';
import './zeppelin/Killable.sol';

contract Conference is Rejector, Killable {
	string public name;
	uint256 public totalBalance;
	uint256 public deposit;
	uint public limitOfParticipants;
	uint public registered;
	uint public attended;
	bool public ended;
	uint public endedAt;
	uint public coolingPeriod;

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

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

	event Register(string participantName, address addr, uint256 balance, uint256 value);
	event Attend(address addr, uint256 balance);
	event Payback(address addr, uint256 _payout, uint256 balance, bool paid);

	function Conference(uint _coolingPeriod) {
		name = 'Edcon Post conference lunch';
		deposit = 1 ether;
		totalBalance = 0;
		registered = 0;
		attended = 0;
		limitOfParticipants = 10;
		ended = false;
		if (_coolingPeriod != 0) {
			coolingPeriod = _coolingPeriod;
		} else {
			coolingPeriod = 1 weeks;
		}
	}

	modifier sentDepositOrReturn {
		if (msg.value == deposit) {
			_
		}else{
			if(msg.sender.send(msg.value)){/* not much you can do */}
		}
	}

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

	modifier onlyActiveOrReturn {
		if (ended == false) {
			_
		}else{
			if(msg.sender.send(msg.value)){/*not much you can do*/}
		}
	}

	modifier withinLimitOrReturn {
		if (registered < limitOfParticipants ) {
			_
		}else{
			if(msg.sender.send(msg.value)){/* not much you can do */}
		}
	}

	function register(string _participant) sentDepositOrReturn withinLimitOrReturn onlyActiveOrReturn{
		Register(_participant, msg.sender, msg.sender.balance, msg.value);
		if (isRegistered(msg.sender)) throw;
		registered++;
		participantsIndex[registered] = msg.sender;
		participants[msg.sender] = Participant(_participant, msg.sender, false, 0, false);
		totalBalance = totalBalance + (deposit * 1);
	}

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

	function attend(address _addr) onlyOwner{
		if (isRegistered(_addr) != true) throw;
		if (isAttended(_addr)) throw;
		Attend(_addr, msg.sender.balance);
		participants[_addr].attended = true;
		attended++;
	}

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

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

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

	function payout() returns(uint256){
		return totalBalance / uint(attended);
	}

	function payback() onlyOwner{
		for(uint i=1;i<=registered;i++){
			if(participants[participantsIndex[i]].attended){
				participants[participantsIndex[i]].payout = payout();
			}
		}
		ended = true;
		endedAt = now;
	}

	function cancel() onlyOwner onlyActive{
		for(uint i=1;i<=registered;i++){
			participants[participantsIndex[i]].payout = deposit;
		}
		ended = true;
		endedAt = now;
	}

	modifier onlyPayable {
		Participant participant = participants[msg.sender];
		if (participant.payout > 0){
			_
		}
	}

	modifier notPaid {
		Participant participant = participants[msg.sender];
		if (participant.paid == false){
			_
		}
	}

	function withdraw() onlyPayable notPaid {
		Participant participant = participants[msg.sender];
		if (msg.sender.send(participant.payout)) {
			participant.paid = true;
			totalBalance -= participant.payout;
		}
	}

	modifier isEnded {
		if (ended){
			_
		}
	}

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

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