change to using timestamps not blocks

change to using timestamps not blocks

pragma solidity ^0.4.0;

import "./Math.sol";
import "./Concept.sol";
import "./ConceptRegistry.sol";
import "./UserRegistry.sol";

contract Assessment {
  address assessee;
  address[] assessors;
  address[] finalAssessors;
  mapping (address => State) assessorState;
  mapping(uint => int[]) clusters;
  State public assessmentStage;
  enum State {
    None,
    Called,
    Confirmed,
    Committed,
    Done,
    Burned
  }

  uint public assessorPoolLength;
  address concept;
  address userRegistry;
  address conceptRegistry;
  uint public checkpoint;
  uint public size;
  uint cost;
  mapping(address => string[]) public data;
  mapping(address => bytes32) commits;
  mapping(address => uint) stake;
  uint public done; //counter how many assessors have committed/revealed their score
  mapping(address => int8) scores;
  mapping(int => bool) inRewardCluster;
  int public finalScore;
  event DataSet(address _dataSetter, uint _index);

  modifier onlyAssessorAssessee() {
    if(msg.sender != assessee && uint(assessorState[msg.sender]) == 0) {
      throw;
    }
    _;
  }

  modifier onlyConceptAssessment() {
    if(msg.sender != address(this) && msg.sender != concept) {
      throw;
    }
    _;
  }

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

  modifier onlyInStage(State _stage) {
      if(assessmentStage != _stage){
          throw;
      }
      _;
  }

  function Assessment(address _assessee, address _userRegistry, address _conceptRegistry, uint _size, uint _cost) {
    assessee = _assessee;
    concept = msg.sender;
    userRegistry = _userRegistry;
    conceptRegistry = _conceptRegistry;
    checkpoint = now;
    size = _size;
    cost = _cost;
    UserRegistry(userRegistry).notification(assessee, 0); // assesse has started an assessment
    assessorPoolLength = 0;
    done = 0;
  }

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

  //@purpose: adds a user to the pool eligible to accept an assessment
  function addAssessorToPool(address assessor) onlyConcept() returns(bool) {
    if(assessorState[assessor] == State.None) {
      UserRegistry(userRegistry).notification(assessor, 1); //Called As A Potential Assessor
      assessorState[assessor] = State.Called;
      assessorPoolLength++;
      return true;
    }
    else {
      return false;
    }
  }

  /*
  @purpose: To recursively set the pool to draw assessors from in the assessment
  stops when the pool of potential assessors is 20 times the size of the assessment2
  @param: uint seed = the seed number for random number generation
  @param: address _concept = the concept being called from
  @param: uint num = the number of assessors to be called
  */
  function setAssessorPool(uint seed, address _concept, uint num) onlyConceptAssessment() {
    uint numCalled = 0;
    for (uint k=0; k < num; k++) {
      if (assessorPoolLength == size*20) { return; } //
      address randomUser = Concept(_concept).getRandomMember(seed + k);
      if (addAssessorToPool(randomUser)) {
        numCalled++;
      }
    }
    uint remaining = num - numCalled;
    if (remaining > 0) {
      for (uint i = 0; i < Concept(_concept).getParentsLength(); i++) {
        setAssessorPool(seed + assessorPoolLength, Concept(_concept).parents(i), remaining/Concept(_concept).getParentsLength() + 1); //Calls the remaining users from the parent concepts proportional to their size
      }
    }
    assessmentStage = State.Called;
  }

  /*
    @purpose: To set the pool of assessors when there are so few users in the system that
    assembling them at random is not meaningful. This will use all members of mew instead
  */
  function setAssessorPoolFromMew() onlyConcept() {
    Concept mew = Concept(ConceptRegistry(conceptRegistry).mewAddress()); //TODO: can this be more elegant and/or in one line?
      for (uint i=0; i<mew.getMemberLength(); i++) {
        addAssessorToPool(mew.members(i));
      }
      size = mew.getMemberLength();
      assessmentStage = State.Called;
  }

  //@purpose: called by an assessor to confirm and stake
  function confirmAssessor() onlyInStage(State.Called){
      if (now - checkpoint > 12 hours) {
          cancelAssessment();
          return;
      }
      if (assessorState[msg.sender] == State.Called &&
          assessors.length < size &&
          Concept(concept).subtractBalance(msg.sender, cost)
          ) {
          assessors.push(msg.sender);
          assessorState[msg.sender] = State.Confirmed;
          stake[msg.sender] = cost;
          UserRegistry(userRegistry).notification(msg.sender, 2); //Confirmed for assessing, stake has been taken
      }
      if (assessors.length == size) {
          notifyAssessors(uint(State.Confirmed), 4);
          checkpoint = now;
          UserRegistry(userRegistry).notification(assessee, 4);
          assessmentStage = State.Confirmed;
      }
  }

  function setData(string _data) onlyAssessorAssessee() {
    data[msg.sender].push(_data);
    DataSet(msg.sender, data[msg.sender].length - 1);
  }

  //@purpose: called by an assessor to commit a hash of their score //TODO explain in more detail what's happening
  function commit(bytes32 _hash) onlyInStage(State.Confirmed){
    if(done > size/2) {
        burnStakes();
    }

    if(done == size) {
      notifyAssessors(uint(State.Committed), 5);
      checkpoint = now; //Resets the startTime
      done = 0; //Resets the done counter
      assessmentStage = State.Committed;
    }

    if(assessorState[msg.sender] == State.Confirmed)
    {
        commits[msg.sender] = _hash;
        assessorState[msg.sender] = State.Committed;
        done++; //Increases done by 1 to help progress to the next assessment stage.

        if(done <= size/2) {
            checkpoint = now + (now - checkpoint);
      }
    }
  }

  //@purpose: called by assessors to reveal their own commits or others
  function reveal(int8 score, string salt, address assessor) onlyInStage(State.Committed) {
      if(now - checkpoint > 12 hours) {
          for(uint i = 0; i < assessors.length; i++) {
              if(assessorState[assessors[i]] == State.Committed) { //If the assessor has not revealed their score
                  stake[assessors[i]] = 0;
                  assessorState[assessors[i]] = State.Burned;
                  done++;
              }
          }
      }

      bytes32 hash = sha3(score,salt);
      if(commits[assessor] == hash) {
          if(msg.sender == assessor) {
              scores[msg.sender] = score;
              assessorState[assessor] = State.Done;
              done++; //done increases by 1 to help progress to the next assessment stage
          }
          else {
              Concept(concept).addBalance(msg.sender, stake[assessor]); // give the stake to the caller
              stake[assessor] = 0;
              assessorState[assessor] = State.Burned;
              done++; //done increases by 1 to help progress to the next assessment stage
          }
      }

      if(done == size) { //If all the assessors have revealed their scored or burned their stakes
          assessmentStage = State.Done;
          calculateResult(); //The final result is calculated
      }
  }

  function burnStakes() internal {
      for(uint i = 0; i < assessors.length; i++) {
          if(assessorState[assessors[i]] == State.Confirmed) {
              uint r = 38; //Inverse burn rate
              stake[assessors[i]] = cost*2**(-(now-checkpoint)/r) - 1; //burns stake as a function of how much time has passed since half of the assessors commited
          }
          if(stake[assessors[i]] == 0) {
              assessorState[assessors[i]] = State.Burned;
              done++; //Increases done by 1 to help progress to the next assessment stage
          }
      }
  }

   function notifyAssessors(uint _state, uint _topic) private {
      for(uint i=0; i < assessors.length; i++) {
          if(uint(assessorState[assessors[i]]) == _state) {
              UserRegistry(userRegistry).notification(assessors[i], _topic);
          }
      }
  }

   function calculateResult() onlyInStage(State.Done) private {
    for(uint j = 0; j < size; j++) {
      if(assessorState[assessors[i]] == State.Done) {
        finalAssessors.push(assessors[i]); //Adds all the assessors that completed the assessment process to an array
      }
    }
    int[] memory score = new int[] (finalAssessors.length); //Initializes an array to store scores that is the same length as the number of finalAssessors
    uint largestClusterIndex = 0; //store the index of the largest cluster
    int averageScore;
    for(uint i = 0; i < finalAssessors.length; i++) {
      score[i] = scores[finalAssessors[i]];
    }
    int meanAbsoluteDeviation = Math.calculateMAD(score,int(finalAssessors.length));
    for(uint l = 0; l < score.length; l++) {
      for(uint m = 0; m < score.length; m++)
      {
        if(score[l] - score[m] <= meanAbsoluteDeviation) {
          clusters[l].push(score[m]);
        }
      }
      if(clusters[l].length > clusters[largestClusterIndex].length) {
        largestClusterIndex = l;
      }
    }
    for(uint o = 0; o < clusters[largestClusterIndex].length; o++) {
      averageScore += clusters[largestClusterIndex][o];
      inRewardCluster[clusters[largestClusterIndex][o]] = true;
    }
    averageScore /= int(clusters[largestClusterIndex].length);
    finalScore = averageScore; //Sets the final score to the average score
    payout();
  }

   function payout() onlyInStage(State.Done) private { //TODO order functions according to styleguide
    for(uint i = 0; i < size; i++) {
      int score = scores[assessors[i]];
      int scoreDistance = ((score - finalScore)*100)/finalScore;
      if(scoreDistance < 0) {
        scoreDistance *= -1;
      }
      uint payoutValue = 1; //Initializes the payoutValue for the assessor
      if(inRewardCluster[score] == true) {
        uint q = 1; //Inflation rate factor, WE NEED TO FIGURE THIS OUT AT SOME POINT
        payoutValue = (q*cost*((100 - uint(scoreDistance))/100)) + stake[assessors[i]]; //The assessor's payout will be some constant times a propotion of their original stake determined by how close to the final score they were
        Concept(concept).addBalance(assessors[i], payoutValue);
      }
      if(inRewardCluster[score] == false) {
        payoutValue = stake[assessors[i]]*((200 - uint(scoreDistance))/200); //The assessor's payout will be a propotion of their remaining stake determined by their distance from the final score
        Concept(concept).addBalance(assessors[i], payoutValue);
      }
    Concept(concept).finishAssessment(finalScore, assessee, address(this)); //Sends assessment info to the concept so that it can update its records
    UserRegistry(userRegistry).notification(assessors[i], 6); //You Have Received Payment For Your Assessment
    }
  }
}

pragma solidity ^0.4.0;

import "./Math.sol";
import "./Concept.sol";
import "./ConceptRegistry.sol";
import "./UserRegistry.sol";

contract Assessment {
  address assessee;
  address[] assessors;
  address[] finalAssessors;
  mapping (address => State) assessorState;
  mapping(uint => int[]) clusters;
  State public assessmentStage;
  enum State {
    None,
    Called,
    Confirmed,
    Committed,
    Done,
    Burned
  }

  uint public assessorPoolLength;
  address concept;
  address userRegistry;
  address conceptRegistry;
  uint public checkpoint;
  uint public size;
  uint cost;
  mapping(address => string[]) public data;
  mapping(address => bytes32) commits;
  mapping(address => uint) stake;
  uint public done; //counter how many assessors have committed/revealed their score
  mapping(address => int8) scores;
  mapping(int => bool) inRewardCluster;
  int public finalScore;
  event DataSet(address _dataSetter, uint _index);

  modifier onlyAssessorAssessee() {
    if(msg.sender != assessee && uint(assessorState[msg.sender]) == 0) {
      throw;
    }
    _;
  }

  modifier onlyConceptAssessment() {
    if(msg.sender != address(this) && msg.sender != concept) {
      throw;
    }
    _;
  }

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

  modifier onlyInStage(State _stage) {
      if(assessmentStage != _stage){
          throw;
      }
      _;
  }

  function Assessment(address _assessee, address _userRegistry, address _conceptRegistry, uint _size, uint _cost) {
    assessee = _assessee;
    concept = msg.sender;
    userRegistry = _userRegistry;
    conceptRegistry = _conceptRegistry;
    checkpoint = block.number;
    size = _size;
    cost = _cost;
    UserRegistry(userRegistry).notification(assessee, 0); // assesse has started an assessment
    assessorPoolLength = 0;
    done = 0;
  }

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

  //@purpose: adds a user to the pool eligible to accept an assessment
  function addAssessorToPool(address assessor) onlyConcept() returns(bool) {
    if(assessorState[assessor] == State.None) {
      UserRegistry(userRegistry).notification(assessor, 1); //Called As A Potential Assessor
      assessorState[assessor] = State.Called;
      assessorPoolLength++;
      return true;
    }
    else {
      return false;
    }
  }

  /*
  @purpose: To recursively set the pool to draw assessors from in the assessment
  stops when the pool of potential assessors is 20 times the size of the assessment2
  @param: uint seed = the seed number for random number generation
  @param: address _concept = the concept being called from
  @param: uint num = the number of assessors to be called
  */
  function setAssessorPool(uint seed, address _concept, uint num) onlyConceptAssessment() {
    uint numCalled = 0;
    for (uint k=0; k < num; k++) {
      if (assessorPoolLength == size*20) { return; } //
      address randomUser = Concept(_concept).getRandomMember(seed + k);
      if (addAssessorToPool(randomUser)) {
        numCalled++;
      }
    }
    uint remaining = num - numCalled;
    if (remaining > 0) {
      for (uint i = 0; i < Concept(_concept).getParentsLength(); i++) {
        setAssessorPool(seed + assessorPoolLength, Concept(_concept).parents(i), remaining/Concept(_concept).getParentsLength() + 1); //Calls the remaining users from the parent concepts proportional to their size
      }
    }
    assessmentStage = State.Called;
  }

  /*
    @purpose: To set the pool of assessors when there are so few users in the system that
    assembling them at random is not meaningful. This will use all members of mew instead
  */
  function setAssessorPoolFromMew() onlyConcept() {
    Concept mew = Concept(ConceptRegistry(conceptRegistry).mewAddress()); //TODO: can this be more elegant and/or in one line?
      for (uint i=0; i<mew.getMemberLength(); i++) {
        addAssessorToPool(mew.members(i));
      }
      size = mew.getMemberLength();
      assessmentStage = State.Called;
  }

  //@purpose: called by an assessor to confirm and stake
  function confirmAssessor() onlyInStage(State.Called){
      if (block.number - checkpoint > 1000) {
          cancelAssessment();
          return;
      }
      if (assessorState[msg.sender] == State.Called &&
          assessors.length < size &&
          Concept(concept).subtractBalance(msg.sender, cost)
          ) {
          assessors.push(msg.sender);
          assessorState[msg.sender] = State.Confirmed;
          stake[msg.sender] = cost;
          UserRegistry(userRegistry).notification(msg.sender, 2); //Confirmed for assessing, stake has been taken
      }
      if (assessors.length == size) {
          notifyAssessors(uint(State.Confirmed), 4);
          checkpoint = block.number;
          UserRegistry(userRegistry).notification(assessee, 4);
          assessmentStage = State.Confirmed;
      }
  }

  function setData(string _data) onlyAssessorAssessee() {
    data[msg.sender].push(_data);
    DataSet(msg.sender, data[msg.sender].length - 1);
  }

  //@purpose: called by an assessor to commit a hash of their score //TODO explain in more detail what's happening
  function commit(bytes32 _hash) onlyInStage(State.Confirmed){
    if(done > size/2) {
        burnStakes();
    }

    if(done == size) {
      notifyAssessors(uint(State.Committed), 5);
      checkpoint = block.number; //Resets the startTime
      done = 0; //Resets the done counter
      assessmentStage = State.Committed;
    }

    if(assessorState[msg.sender] == State.Confirmed)
    {
        commits[msg.sender] = _hash;
        assessorState[msg.sender] = State.Committed;
        done++; //Increases done by 1 to help progress to the next assessment stage.

        if(done <= size/2) {
            checkpoint = block.number + (block.number-checkpoint);
      }
    }
  }

  //@purpose: called by assessors to reveal their own commits or others
  function reveal(int8 score, string salt, address assessor) onlyInStage(State.Committed) {
      if(block.number - checkpoint > 1000) {
          for(uint i = 0; i < assessors.length; i++) {
              if(assessorState[assessors[i]] == State.Committed) { //If the assessor has not revealed their score
                  stake[assessors[i]] = 0;
                  assessorState[assessors[i]] = State.Burned;
                  done++;
              }
          }
      }

      bytes32 hash = sha3(score,salt);
      if(commits[assessor] == hash) {
          if(msg.sender == assessor) {
              scores[msg.sender] = score;
              assessorState[assessor] = State.Done;
              done++; //done increases by 1 to help progress to the next assessment stage
          }
          else {
              Concept(concept).addBalance(msg.sender, stake[assessor]); // give the stake to the caller
              stake[assessor] = 0;
              assessorState[assessor] = State.Burned;
              done++; //done increases by 1 to help progress to the next assessment stage
          }
      }

      if(done == size) { //If all the assessors have revealed their scored or burned their stakes
          assessmentStage = State.Done;
          calculateResult(); //The final result is calculated
      }
  }

  function burnStakes() internal {
      for(uint i = 0; i < assessors.length; i++) {
          if(assessorState[assessors[i]] == State.Confirmed) {
              uint r = 38; //Inverse burn rate
              stake[assessors[i]] = cost*2**(-(now-checkpoint)/r) - 1; //burns stake as a function of how much time has passed since half of the assessors commited
          }
          if(stake[assessors[i]] == 0) {
              assessorState[assessors[i]] = State.Burned;
              done++; //Increases done by 1 to help progress to the next assessment stage
          }
      }
  }

   function notifyAssessors(uint _state, uint _topic) private {
      for(uint i=0; i < assessors.length; i++) {
          if(uint(assessorState[assessors[i]]) == _state) {
              UserRegistry(userRegistry).notification(assessors[i], _topic);
          }
      }
  }

   function calculateResult() onlyInStage(State.Done) private {
    for(uint j = 0; j < size; j++) {
      if(assessorState[assessors[i]] == State.Done) {
        finalAssessors.push(assessors[i]); //Adds all the assessors that completed the assessment process to an array
      }
    }
    int[] memory score = new int[] (finalAssessors.length); //Initializes an array to store scores that is the same length as the number of finalAssessors
    uint largestClusterIndex = 0; //store the index of the largest cluster
    int averageScore;
    for(uint i = 0; i < finalAssessors.length; i++) {
      score[i] = scores[finalAssessors[i]];
    }
    int meanAbsoluteDeviation = Math.calculateMAD(score,int(finalAssessors.length));
    for(uint l = 0; l < score.length; l++) {
      for(uint m = 0; m < score.length; m++)
      {
        if(score[l] - score[m] <= meanAbsoluteDeviation) {
          clusters[l].push(score[m]);
        }
      }
      if(clusters[l].length > clusters[largestClusterIndex].length) {
        largestClusterIndex = l;
      }
    }
    for(uint o = 0; o < clusters[largestClusterIndex].length; o++) {
      averageScore += clusters[largestClusterIndex][o];
      inRewardCluster[clusters[largestClusterIndex][o]] = true;
    }
    averageScore /= int(clusters[largestClusterIndex].length);
    finalScore = averageScore; //Sets the final score to the average score
    payout();
  }

   function payout() onlyInStage(State.Done) private { //TODO order functions according to styleguide
    for(uint i = 0; i < size; i++) {
      int score = scores[assessors[i]];
      int scoreDistance = ((score - finalScore)*100)/finalScore;
      if(scoreDistance < 0) {
        scoreDistance *= -1;
      }
      uint payoutValue = 1; //Initializes the payoutValue for the assessor
      if(inRewardCluster[score] == true) {
        uint q = 1; //Inflation rate factor, WE NEED TO FIGURE THIS OUT AT SOME POINT
        payoutValue = (q*cost*((100 - uint(scoreDistance))/100)) + stake[assessors[i]]; //The assessor's payout will be some constant times a propotion of their original stake determined by how close to the final score they were
        Concept(concept).addBalance(assessors[i], payoutValue);
      }
      if(inRewardCluster[score] == false) {
        payoutValue = stake[assessors[i]]*((200 - uint(scoreDistance))/200); //The assessor's payout will be a propotion of their remaining stake determined by their distance from the final score
        Concept(concept).addBalance(assessors[i], payoutValue);
      }
    Concept(concept).finishAssessment(finalScore, assessee, address(this)); //Sends assessment info to the concept so that it can update its records
    UserRegistry(userRegistry).notification(assessors[i], 6); //You Have Received Payment For Your Assessment
    }
  }
}


Avoid duplicate attend

Avoid duplicate attend

contract Conference {
	string public name;
	uint256 public balance;
	uint256 public deposit;
	uint public capacity;
	uint public registered;
	uint public attended;
	mapping (address => Participant) public participants;
	mapping (uint => address) public participantsIndex;
	bool paid;
	uint256 _pot;

	struct Participant {
		address addr;
		bool attended;
	}

	event Register(address addr, uint256 balance, uint256 value);
	event Attend(address addr, uint256 balance);
	event Payback(address addr, uint256 _pot, uint256 balance, bool paid);

	function Conference() {
		name = 'CodeUp';
		deposit = 1000000000000000000;		// 1 ETH = 10**18 wai
		balance = 0;
		registered = 0;
		attended = 0;
	}

	function register(){
		Register(msg.sender, msg.sender.balance, msg.value);
		if (msg.value != deposit) throw;
		if (isRegistered()) throw;
		registered++;
		participantsIndex[registered] = msg.sender;
		participants[msg.sender] = Participant(msg.sender, false);
		balance = balance + (deposit * 1);
	}

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

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

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

	function pot() returns(uint256){
		return balance / uint(attended);
	}

	function payback(){
		for(uint i=1;i<=registered;i++)
		{
			if(participants[participantsIndex[i]].attended){
				Payback(participantsIndex[i], pot(), participantsIndex[i].balance,  true);
				participantsIndex[i].send(pot());
			}else{
				Payback(participantsIndex[i], pot(), participantsIndex[i].balance, false);
			}
		}
		balance = 0;
	}
}

contract Conference {
	string public name;
	uint256 public balance;
	uint256 public deposit;
	uint public capacity;
	uint public registered;
	uint public attended;
	mapping (address => Participant) public participants;
	mapping (uint => address) public participantsIndex;
	bool paid;
	uint256 _pot;

	struct Participant {
		address addr;
		bool attended;
	}

	event Register(address addr, uint256 balance, uint256 value);
	event Attend(address addr, uint256 balance);
	event Payback(address addr, uint256 _pot, uint256 balance, bool paid);

	function Conference() {
		name = 'CodeUp';
		deposit = 1000000000000000000;		// 1 ETH = 10**18 wai
		balance = 0;
		registered = 0;
		attended = 0;
	}

	function register(){
		Register(msg.sender, msg.sender.balance, msg.value);
		if (msg.value != deposit) throw;
		if (isRegistered()) throw;
		registered++;
		participantsIndex[registered] = msg.sender;
		participants[msg.sender] = Participant(msg.sender, false);
		balance = balance + (deposit * 1);
	}

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

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

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

	function pot() returns(uint256){
		return balance / uint(attended);
	}

	function payback(){
		for(uint i=1;i<=registered;i++)
		{
			if(participants[participantsIndex[i]].attended){
				Payback(participantsIndex[i], pot(), participantsIndex[i].balance,  true);
				participantsIndex[i].send(pot());
			}else{
				Payback(participantsIndex[i], pot(), participantsIndex[i].balance, false);
			}
		}
		balance = 0;
	}
}


explanation of privatized

explanation of privatized

pragma solidity ^0.4.4;

contract Randomized {

    address public owner;

    function Randomized() {
        owner = msg.sender;
    }

    struct Key {
        uint entryBlockNumber;
        bytes publicKey;
    }

    mapping (address => Key) keys;

    function setKey(bytes publicKey) {
        keys[msg.sender].entryBlockNumber = block.number;
        keys[msg.sender].publicKey = publicKey;
    }

    function validate(uint seedBlockNumber, bytes seed, address sender, bytes32 crypted, bytes32 result) constant returns (bool) {
        if (keys[sender].entryBlockNumber >= seedBlockNumber) return false;
        if (keccak256(crypted, seed) != result) return false;
        return keccak256(seed) == this.privatized(crypted, keys[sender].publicKey);
    }

    function privatized(bytes32 crypted, bytes publicKey) constant returns (bytes32) {
        // Waiting for https://github.com/ethereum/EIPs/pull/198
        return 123;
    }

}

pragma solidity ^0.4.4;

contract Randomized {

    address public owner;

    function Randomized() {
        owner = msg.sender;
    }

    struct Key {
        uint entryBlockNumber;
        bytes publicKey;
    }

    mapping (address => Key) keys;

    function setKey(bytes publicKey) {
        keys[msg.sender].entryBlockNumber = block.number;
        keys[msg.sender].publicKey = publicKey;
    }

    function validate(uint seedBlockNumber, bytes seed, address sender, bytes32 crypted, bytes32 result) constant returns (bool) {
        if (keys[sender].entryBlockNumber >= seedBlockNumber) return false;
        if (keccak256(crypted, seed) != result) return false;
        return keccak256(seed) == this.privatized(crypted, keys[sender].publicKey);
    }

    function privatized(bytes32 crypted, bytes publicKey) constant returns (bytes32) {
        return 123;
    }

}


Updated fee

Updated fee

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

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

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

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

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

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

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

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

    address public registrarAddress;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        offerCancelled(_deedAddress, msg.sender);
    }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    address feeAddress;
    uint public fee = 100; // Out of 10000 = 1%
    uint public minimumOfferPrice = 0.01 ether;

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

    address public registrarAddress;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        offerCancelled(_deedAddress, msg.sender);
    }

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

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

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

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

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

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

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

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

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

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

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


set correct function visibility

set correct function visibility

pragma solidity ^0.4.21;

import "contracts/Interface/RequestFactoryInterface.sol";
import "contracts/TransactionRequestCore.sol";
import "contracts/Library/RequestLib.sol";
import "contracts/IterTools.sol";
import "contracts/CloneFactory.sol";
import "contracts/Library/RequestScheduleLib.sol";

/**
 * @title RequestFactory
 * @dev Contract which will produce new TransactionRequests.
 */
contract RequestFactory is RequestFactoryInterface, CloneFactory {
    using IterTools for bool[6];

    TransactionRequestCore public transactionRequestCore;

    uint constant public BLOCKS_BUCKET_SIZE = 240; //~1h
    uint constant public TIMESTAMP_BUCKET_SIZE = 3600; //1h

    function RequestFactory(
        address _transactionRequestCore
    )
        public
    {
        require(_transactionRequestCore != 0x0);

        transactionRequestCore = TransactionRequestCore(_transactionRequestCore);
    }

    /**
     * @dev The lowest level interface for creating a transaction request.
     *
     * @param _addressArgs [0] -  meta.owner
     * @param _addressArgs [1] -  paymentData.feeRecipient
     * @param _addressArgs [2] -  txnData.toAddress
     * @param _uintArgs [0]    -  paymentData.fee
     * @param _uintArgs [1]    -  paymentData.bounty
     * @param _uintArgs [2]    -  schedule.claimWindowSize
     * @param _uintArgs [3]    -  schedule.freezePeriod
     * @param _uintArgs [4]    -  schedule.reservedWindowSize
     * @param _uintArgs [5]    -  schedule.temporalUnit
     * @param _uintArgs [6]    -  schedule.windowSize
     * @param _uintArgs [7]    -  schedule.windowStart
     * @param _uintArgs [8]    -  txnData.callGas
     * @param _uintArgs [9]    -  txnData.callValue
     * @param _uintArgs [10]   -  txnData.gasPrice
     * @param _uintArgs [11]   -  claimData.requiredDeposit
     * @param _callData        -  The call data
     */
    function createRequest(
        address[3]  _addressArgs,
        uint[12]    _uintArgs,
        bytes       _callData
    )
        public payable returns (address)
    {
        // Create a new transaction request clone from transactionRequestCore.
        address transactionRequest = createClone(transactionRequestCore);

        // Call initialize on the transaction request clone.
        TransactionRequestCore(transactionRequest).initialize.value(msg.value)(
            [
                msg.sender,       // Created by
                _addressArgs[0],  // meta.owner
                _addressArgs[1],  // paymentData.feeRecipient
                _addressArgs[2]   // txnData.toAddress
            ],
            _uintArgs,            //uint[12]
            _callData
        );

        // Track the address locally
        requests[transactionRequest] = true;

        // Log the creation.
        emit RequestCreated(
            transactionRequest,
            _addressArgs[0],
            getBucket(_uintArgs[7], RequestScheduleLib.TemporalUnit(_uintArgs[5])),
            _uintArgs
        );

        return transactionRequest;
    }

    /**
     *  The same as createRequest except that it requires validation prior to
     *  creation.
     *
     *  Parameters are the same as `createRequest`
     */
    function createValidatedRequest(
        address[3]  _addressArgs,
        uint[12]    _uintArgs,
        bytes       _callData
    )
        public payable returns (address)
    {
        bool[6] memory isValid = validateRequestParams(
            _addressArgs,
            _uintArgs,
            _callData,
            msg.value
        );

        if (!isValid.all()) {
            if (!isValid[0]) {
                emit ValidationError(uint8(Errors.InsufficientEndowment));
            }
            if (!isValid[1]) {
                emit ValidationError(uint8(Errors.ReservedWindowBiggerThanExecutionWindow));
            }
            if (!isValid[2]) {
                emit ValidationError(uint8(Errors.InvalidTemporalUnit));
            }
            if (!isValid[3]) {
                emit ValidationError(uint8(Errors.ExecutionWindowTooSoon));
            }
            if (!isValid[4]) {
                emit ValidationError(uint8(Errors.CallGasTooHigh));
            }
            if (!isValid[5]) {
                emit ValidationError(uint8(Errors.EmptyToAddress));
            }

            // Try to return the ether sent with the message
            msg.sender.transfer(msg.value);

            return 0x0;
        }

        return createRequest(_addressArgs, _uintArgs, _callData);
    }

    /// ----------------------------
    /// Internal
    /// ----------------------------

    /*
     *  @dev The enum for launching `ValidationError` events and mapping them to an error.
     */
    enum Errors {
        InsufficientEndowment,
        ReservedWindowBiggerThanExecutionWindow,
        InvalidTemporalUnit,
        ExecutionWindowTooSoon,
        CallGasTooHigh,
        EmptyToAddress
    }

    event ValidationError(uint8 error);

    /*
     * @dev Validate the constructor arguments for either `createRequest` or `createValidatedRequest`.
     */
    function validateRequestParams(
        address[3]  _addressArgs,
        uint[12]    _uintArgs,
        bytes       _callData,
        uint        _endowment
    )
        public view returns (bool[6])
    {
        return RequestLib.validate(
            [
                msg.sender,      // meta.createdBy
                _addressArgs[0],  // meta.owner
                _addressArgs[1],  // paymentData.feeRecipient
                _addressArgs[2]   // txnData.toAddress
            ],
            _uintArgs,
            _callData,
            _endowment
        );
    }

    /// Mapping to hold known requests.
    mapping (address => bool) requests;

    function isKnownRequest(address _address)
        public view returns (bool isKnown)
    {
        return requests[_address];
    }

    function getBucket(uint windowStart, RequestScheduleLib.TemporalUnit unit)
        public view returns(int)
    {
        uint bucketSize;
        /* since we want to handle both blocks and timestamps
            and do not want to get into case where buckets overlaps
            block buckets are going to be negative ints
            timestamp buckets are going to be positive ints
            we'll overflow after 2**255-1 blocks instead of 2**256-1 since we encoding this on int256
        */
        int sign;

        if (unit == RequestScheduleLib.TemporalUnit.Blocks) {
            bucketSize = BLOCKS_BUCKET_SIZE;
            sign = -1;
        } else if (unit == RequestScheduleLib.TemporalUnit.Timestamp) {
            bucketSize = TIMESTAMP_BUCKET_SIZE;
            sign = 1;
        } else {
            revert();
        }
        return sign * int(windowStart - (windowStart % bucketSize));
    }
}

pragma solidity ^0.4.21;

import "contracts/Interface/RequestFactoryInterface.sol";
import "contracts/TransactionRequestCore.sol";
import "contracts/Library/RequestLib.sol";
import "contracts/IterTools.sol";
import "contracts/CloneFactory.sol";
import "contracts/Library/RequestScheduleLib.sol";

/**
 * @title RequestFactory
 * @dev Contract which will produce new TransactionRequests.
 */
contract RequestFactory is RequestFactoryInterface, CloneFactory {
    using IterTools for bool[6];

    TransactionRequestCore public transactionRequestCore;

    uint constant public BLOCKS_BUCKET_SIZE = 240; //~1h
    uint constant public TIMESTAMP_BUCKET_SIZE = 3600; //1h

    function RequestFactory(
        address _transactionRequestCore
    )
        public
    {
        require(_transactionRequestCore != 0x0);

        transactionRequestCore = TransactionRequestCore(_transactionRequestCore);
    }

    /**
     * @dev The lowest level interface for creating a transaction request.
     *
     * @param _addressArgs [0] -  meta.owner
     * @param _addressArgs [1] -  paymentData.feeRecipient
     * @param _addressArgs [2] -  txnData.toAddress
     * @param _uintArgs [0]    -  paymentData.fee
     * @param _uintArgs [1]    -  paymentData.bounty
     * @param _uintArgs [2]    -  schedule.claimWindowSize
     * @param _uintArgs [3]    -  schedule.freezePeriod
     * @param _uintArgs [4]    -  schedule.reservedWindowSize
     * @param _uintArgs [5]    -  schedule.temporalUnit
     * @param _uintArgs [6]    -  schedule.windowSize
     * @param _uintArgs [7]    -  schedule.windowStart
     * @param _uintArgs [8]    -  txnData.callGas
     * @param _uintArgs [9]    -  txnData.callValue
     * @param _uintArgs [10]   -  txnData.gasPrice
     * @param _uintArgs [11]   -  claimData.requiredDeposit
     * @param _callData        -  The call data
     */
    function createRequest(
        address[3]  _addressArgs,
        uint[12]    _uintArgs,
        bytes       _callData
    )
        public payable returns (address)
    {
        // Create a new transaction request clone from transactionRequestCore.
        address transactionRequest = createClone(transactionRequestCore);

        // Call initialize on the transaction request clone.
        TransactionRequestCore(transactionRequest).initialize.value(msg.value)(
            [
                msg.sender,       // Created by
                _addressArgs[0],  // meta.owner
                _addressArgs[1],  // paymentData.feeRecipient
                _addressArgs[2]   // txnData.toAddress
            ],
            _uintArgs,            //uint[12]
            _callData
        );

        // Track the address locally
        requests[transactionRequest] = true;

        // Log the creation.
        emit RequestCreated(
            transactionRequest,
            _addressArgs[0],
            getBucket(_uintArgs[7], RequestScheduleLib.TemporalUnit(_uintArgs[5])),
            _uintArgs
        );

        return transactionRequest;
    }

    /**
     *  The same as createRequest except that it requires validation prior to
     *  creation.
     *
     *  Parameters are the same as `createRequest`
     */
    function createValidatedRequest(
        address[3]  _addressArgs,
        uint[12]    _uintArgs,
        bytes       _callData
    )
        public payable returns (address)
    {
        bool[6] memory isValid = validateRequestParams(
            _addressArgs,
            _uintArgs,
            _callData,
            msg.value
        );

        if (!isValid.all()) {
            if (!isValid[0]) {
                emit ValidationError(uint8(Errors.InsufficientEndowment));
            }
            if (!isValid[1]) {
                emit ValidationError(uint8(Errors.ReservedWindowBiggerThanExecutionWindow));
            }
            if (!isValid[2]) {
                emit ValidationError(uint8(Errors.InvalidTemporalUnit));
            }
            if (!isValid[3]) {
                emit ValidationError(uint8(Errors.ExecutionWindowTooSoon));
            }
            if (!isValid[4]) {
                emit ValidationError(uint8(Errors.CallGasTooHigh));
            }
            if (!isValid[5]) {
                emit ValidationError(uint8(Errors.EmptyToAddress));
            }

            // Try to return the ether sent with the message
            msg.sender.transfer(msg.value);

            return 0x0;
        }

        return createRequest(_addressArgs, _uintArgs, _callData);
    }

    /// ----------------------------
    /// Internal
    /// ----------------------------

    /*
     *  @dev The enum for launching `ValidationError` events and mapping them to an error.
     */
    enum Errors {
        InsufficientEndowment,
        ReservedWindowBiggerThanExecutionWindow,
        InvalidTemporalUnit,
        ExecutionWindowTooSoon,
        CallGasTooHigh,
        EmptyToAddress
    }

    event ValidationError(uint8 error);

    /*
     * @dev Validate the constructor arguments for either `createRequest` or `createValidatedRequest`.
     */
    function validateRequestParams(
        address[3]  _addressArgs,
        uint[12]    _uintArgs,
        bytes       _callData,
        uint        _endowment
    )
        public view returns (bool[6])
    {
        return RequestLib.validate(
            [
                msg.sender,      // meta.createdBy
                _addressArgs[0],  // meta.owner
                _addressArgs[1],  // paymentData.feeRecipient
                _addressArgs[2]   // txnData.toAddress
            ],
            _uintArgs,
            _callData,
            _endowment
        );
    }

    /// Mapping to hold known requests.
    mapping (address => bool) requests;

    function isKnownRequest(address _address)
        public view returns (bool isKnown)
    {
        return requests[_address];
    }

    function getBucket(uint windowStart, RequestScheduleLib.TemporalUnit unit)
        public pure returns(int)
    {
        uint bucketSize;
        /* since we want to handle both blocks and timestamps
            and do not want to get into case where buckets overlaps
            block buckets are going to be negative ints
            timestamp buckets are going to be positive ints
            we'll overflow after 2**255-1 blocks instead of 2**256-1 since we encoding this on int256
        */
        int sign;

        if (unit == RequestScheduleLib.TemporalUnit.Blocks) {
            bucketSize = BLOCKS_BUCKET_SIZE;
            sign = -1;
        } else if (unit == RequestScheduleLib.TemporalUnit.Timestamp) {
            bucketSize = TIMESTAMP_BUCKET_SIZE;
            sign = 1;
        } else {
            revert();
        }
        return sign * int(windowStart - (windowStart % bucketSize));
    }
}


Update sender_test.sol

Update sender_test.sol

import "remix_tests.sol"; // this import is automatically injected by Remix.
import "remix_accounts.sol";

contract SenderTest {

    function beforeAll () public {}

    /// 1
    function checkSenderIs1 () public {
        Assert.equal(msg.sender, TestsAccounts.getAccount(1), "wrong sender in checkSenderIs1");
    }

    /// 0
    function checkSenderIs0 () public {
        Assert.equal(msg.sender, TestsAccounts.getAccount(0), "wrong sender in checkSenderIs0");
    }

    /// 1
    function checkSenderIsNt0 () public {
        Assert.notEqual(msg.sender, TestsAccounts.getAccount(0), "wrong sender in checkSenderIsNot0");
    }

    /// 2
    function checkSenderIsnt2 () public {
        Assert.notEqual(msg.sender, TestsAccounts.getAccount(1), "wrong sender in checkSenderIsnt2");
    }
}

import "remix_tests.sol"; // this import is automatically injected by Remix.
import "remix_accounts.sol";

contract SenderTest {

    function beforeAll () {}

    /// 1
    function checkSenderIs1 () public {
        Assert.equal(msg.sender, TestsAccounts.getAccount(1), "wrong sender in checkSenderIs1");
    }

    /// 0
    function checkSenderIs0 () public {
        Assert.equal(msg.sender, TestsAccounts.getAccount(0), "wrong sender in checkSenderIs0");
    }

    /// 1
    function checkSenderIsNt0 () public {
        Assert.notEqual(msg.sender, TestsAccounts.getAccount(0), "wrong sender in checkSenderIsNot0");
    }

    /// 2
    function checkSenderIsnt2 () public {
        Assert.notEqual(msg.sender, TestsAccounts.getAccount(1), "wrong sender in checkSenderIsnt2");
    }
}


Use transfer() rather than send()

Use transfer() rather than send()

pragma solidity ^0.4.2;

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import "../../wealdtech-solidity/contracts/ens/ENSReverseRegister.sol";

// Interesting parts of the ENS deed
contract Deed {
    address public owner;
    address public previousOwner;
}

// Interesting parts of the ENS registry
contract Registry {
    function owner(bytes32 _hash) constant returns (address);
}

// Interesting parts of the ENS registrar
contract Registrar {
    function transfer(bytes32 _hash, address newOwner);
    function entries(bytes32 _hash) constant returns (uint, Deed, uint, uint, uint);
}

contract DomainSale is ENSReverseRegister {
    Registrar public registrar;
    mapping (string => Sale) private sales;
    mapping (address => uint256) private balances;

    // Auction parameters
    uint256 private constant AUCTION_DURATION = 24 hours;
    uint256 private constant HIGH_BID_KICKIN = 7 days;
    uint256 private constant NORMAL_BID_INCREASE_PERCENTAGE = 10;
    uint256 private constant HIGH_BID_INCREASE_PERCENTAGE = 50;

    // Distribution of the sale funds
    uint256 private constant SELLER_SALE_PERCENTAGE = 90;
    uint256 private constant START_REFERRER_SALE_PERCENTAGE = 5;
    uint256 private constant BID_REFERRER_SALE_PERCENTAGE = 5;

    // ENS
    string private constant CONTRACT_ENS = "domainsale.eth";
    // Hex is namehash("eth")
    bytes32 private constant NAMEHASH_ETH = 0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae;

    struct Sale {
        // The lowest direct purchase price that will be accepted
        uint256 price;
        // The lowest auction bid that will be accepted
        uint256 reserve;
        // The last bid on the auction.  0 if no bid has been made
        uint256 lastBid;
        // The address of the last bider on the auction.  0 if no bid has been made
        address lastBidder;
        // The timestamp when this auction started
        uint256 auctionStarted;
        // The timestamp at which this auction ends
        uint256 auctionEnds;
        // The address of the referrer who started the sale
        address startReferrer;
        // The address of the referrer who supplied the winning bid
        address bidReferrer;
    }

    //
    // Events
    //

    // Sent when a name is offered (can occur multiple times if the seller
    // changes their prices)
    event Offer(address indexed seller, string name, uint256 price, uint256 reserve);
    // Sent when a bid is placed for a name
    event Bid(address indexed bidder, string name, uint256 bid);
    // Sent when a name is transferred to a new owner
    event Transfer(address indexed seller, address indexed buyer, string name, uint256 value);
    // Sent when a sale for a name is cancelled
    event Cancel(string name);

    //
    // Modifiers
    //

    // Actions that can only be undertaken by the seller of the name.
    // The owner of the name is this contract, so we use the previous
    // owner from the deed
    modifier onlyNameSeller(string _name) {
        Deed deed;
        (,deed,,,) = registrar.entries(sha3(_name));
        require(deed.owner() == address(this));
        require(deed.previousOwner() == msg.sender);
        _;
    }

    // It is possible for a name to be invalidated, in which case the
    // owner will be reset
    modifier deedValid(string _name) {
        address deed;
        (,deed,,,) = registrar.entries(sha3(_name));
        require(deed != 0);
        _;
    }

    // Actions that can only be undertaken if the name sale has attracted
    // no bids.
    modifier auctionNotStarted(string _name) {
        require(sales[_name].auctionStarted == 0);
        _;
    }

    // Allow if the name can be bid upon
    modifier canBid(string _name) {
        require(sales[_name].reserve != 0);
        _;
    }

    // Allow if the name can be purchased
    modifier canBuy(string _name) {
        require(sales[_name].price != 0);
        _;
    }

    /**
     * @dev Constructor takes the address of the ENS registry
     */
    function DomainSale(address _registry) ENSReverseRegister(_registry, CONTRACT_ENS) {
        registrar = Registrar(Registry(_registry).owner(NAMEHASH_ETH));
    }

    //
    // Accessors for sales struct
    //

    /**
     * @dev return useful information from the sale structure in one go
     */
    function sale(string _name) public constant returns (uint256, uint256, uint256, address, uint256, uint256) {
        Sale storage s = sales[_name];
        return (s.price, s.reserve, s.lastBid, s.lastBidder, s.auctionStarted, s.auctionEnds);
    }

    /**
     * @dev a flag set if this name can be purchased through auction
     */
    function isAuction(string _name) public constant returns (bool) {
        return sales[_name].reserve != 0;
    }

    /**
     * @dev a flag set if this name can be purchased outright
     */
    function isBuyable(string _name) public constant returns (bool) {
        return sales[_name].price != 0;
    }

    /**
     * @dev a flag set if the auction has started
     */
    function auctionStarted(string _name) public constant returns (bool) {
        return sales[_name].lastBid != 0;
    }

    /**
     * @dev the time at which the auction ends
     */
    function auctionEnds(string _name) public constant returns (uint256) {
        return sales[_name].auctionEnds;
    }

    /**
     * @dev minimumBid is the greater of the minimum bid or the last bid + 10%.
     *      If an auction has been going longer than 7 days then it is the last
     *      bid + 50%.
     *      Throws if this sale does not accept bids
     */
    function minimumBid(string _name) public constant returns (uint256) {
        Sale storage s = sales[_name];

        if (s.auctionStarted == 0) {
            return s.reserve;
        } else if (s.auctionStarted + HIGH_BID_KICKIN > now) {
            return s.lastBid + s.lastBid * NORMAL_BID_INCREASE_PERCENTAGE / 100;
        } else {
            return s.lastBid + s.lastBid * HIGH_BID_INCREASE_PERCENTAGE / 100;
        }
    }

    /**
     * @dev price is the instant purchase price.
     *      Throws if this sale does not accept an instant purchase
     */
    function price(string _name) public constant returns (uint256) {
        Sale storage s = sales[_name];

        return s.price;
    }

    /**
     * @dev The balance available for withdrawal
     */
    function balance() public constant returns (uint256) {
        return balances[msg.sender];
    }

    //
    // Operations
    //

    /**
     * @dev offer a domain for sale.
     *      The price is the price at which a domain can be purchased directly.
     *      The reserve is the initial lowest price for which a bid can be made.
     */
    function offer(string _name, uint256 _price, uint256 reserve, address referrer) onlyNameSeller(_name) auctionNotStarted(_name) deedValid(_name) public {
        require(_price == 0 || _price > reserve);
        require(_price != 0 || reserve != 0);
        Sale storage s = sales[_name];
        s.reserve = reserve;
        s.price = _price;
        s.startReferrer = referrer;
        Offer(msg.sender, _name, _price, reserve);
    }

    /**
     * @dev cancel a sale for a domain.
     *      This can only happen if there have been no bids for the name.
     */
    function cancel(string _name) onlyNameSeller(_name) auctionNotStarted(_name) deedValid(_name) public {
        registrar.transfer(sha3(_name), msg.sender);
        Cancel(_name);

        // Tidy up
        clearStorage(_name);
    }

    /**
     * @dev buy a domain directly
     */
    function buy(string _name, address bidReferrer) canBuy(_name) deedValid(_name) public payable {
        Sale storage s = sales[_name];
        require(msg.value >= s.price);
        require(s.auctionStarted == 0);

        // As we're here, return any funds that the sender is owed
        withdraw();

        // Obtain the previous owner from the deed
        Deed deed;
        (,deed,,,) = registrar.entries(sha3(_name));
        address previousOwner = deed.previousOwner();

        // Transfer the name
        registrar.transfer(sha3(_name), msg.sender);
        Transfer(previousOwner, msg.sender, _name, msg.value);

        // Distribute funds to referrers
        transferFunds(msg.value, previousOwner, s.startReferrer, bidReferrer);

        // Tidy up
        clearStorage(_name);
    }

    /**
     * @dev bid for a domain
     */
    function bid(string _name, address bidReferrer) canBid(_name) deedValid(_name) public payable {
        require(msg.value >= minimumBid(_name));

        Sale storage s = sales[_name];
        require(s.auctionStarted == 0 || now < s.auctionEnds);

        // Update the balance for the outbid bidder
        balances[s.lastBidder] += s.lastBid;

        // As we're here, return any funds that the sender is owed
        withdraw();

        if (s.auctionStarted == 0) {
          // First bid; set the auction start
          s.auctionStarted = now;
        }
        s.lastBidder = msg.sender;
        s.lastBid = msg.value;
        s.auctionEnds = now + AUCTION_DURATION;
        s.bidReferrer = bidReferrer;
        Bid(msg.sender, _name, msg.value);
    }

    /**
     * @dev finish an auction
     */
    function finish(string _name) deedValid(_name) public {
        Sale storage s = sales[_name];
        require(now > s.auctionEnds);

        // Obtain the previous owner from the deed
        Deed deed;
        (,deed,,,) = registrar.entries(sha3(_name));

        address previousOwner = deed.previousOwner();
        registrar.transfer(sha3(_name), s.lastBidder);
        Transfer(previousOwner, s.lastBidder, _name, s.lastBid);

        // Distribute funds to referrers
        transferFunds(s.lastBid, previousOwner, s.startReferrer, s.bidReferrer);
        clearStorage(_name);
    }

    /**
     * @dev withdraw any owned balance
     */
    function withdraw() public {
        uint256 withdrawalAmount = balances[msg.sender];
        if (withdrawalAmount > 0) {
            balances[msg.sender] = 0;
            msg.sender.transfer(withdrawalAmount);
        }
    }

    /**
     * @dev Invalidate an auction if the deed is no longer active
     */
    function invalidate(string _name) public {
        // Ensure the deed has been invalidated
        address deed;
        (,deed,,,) = registrar.entries(sha3(_name));
        require(deed == 0);

        Sale storage s = sales[_name];

        // Update the balance for the winning bidder
        balances[s.lastBidder] += s.lastBid;

        // As we're here, return any funds that the sender is owed
        withdraw();

        // Cancel the auction
        Cancel(_name);

        // Tidy up
        clearStorage(_name);
    }

    //
    // Internal functions
    //

    /**
     * @dev Transfer funds for a sale to the relevant parties
     */
    function transferFunds(uint256 amount, address seller, address startReferrer, address bidReferrer) internal {
        seller.transfer(amount * SELLER_SALE_PERCENTAGE / 100);
        startReferrer.transfer(amount * START_REFERRER_SALE_PERCENTAGE / 100);
        bidReferrer.transfer(amount * BID_REFERRER_SALE_PERCENTAGE / 100);
    }

    /**
     * @dev Clear the storage for a name
     */
    function clearStorage(string _name) internal {
        // Clear name records
        sales[_name] = Sale({
            reserve: 0,
            price: 0,
            lastBid:0,
            lastBidder:0,
            auctionStarted:0,
            auctionEnds:0,
            startReferrer: 0,
            bidReferrer: 0
        });
    }
}

pragma solidity ^0.4.2;

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import "../../wealdtech-solidity/contracts/ens/ENSReverseRegister.sol";

// Interesting parts of the ENS deed
contract Deed {
    address public owner;
    address public previousOwner;
}

// Interesting parts of the ENS registry
contract Registry {
    function owner(bytes32 _hash) constant returns (address);
}

// Interesting parts of the ENS registrar
contract Registrar {
    function transfer(bytes32 _hash, address newOwner);
    function entries(bytes32 _hash) constant returns (uint, Deed, uint, uint, uint);
}

contract DomainSale is ENSReverseRegister {
    Registrar public registrar;
    mapping (string => Sale) private sales;
    mapping (address => uint256) private balances;

    // Auction parameters
    uint256 private constant AUCTION_DURATION = 24 hours;
    uint256 private constant HIGH_BID_KICKIN = 7 days;
    uint256 private constant NORMAL_BID_INCREASE_PERCENTAGE = 10;
    uint256 private constant HIGH_BID_INCREASE_PERCENTAGE = 50;

    // Distribution of the sale funds
    uint256 private constant SELLER_SALE_PERCENTAGE = 90;
    uint256 private constant START_REFERRER_SALE_PERCENTAGE = 5;
    uint256 private constant BID_REFERRER_SALE_PERCENTAGE = 5;

    // ENS
    string private constant CONTRACT_ENS = "domainsale.eth";
    // Hex is namehash("eth")
    bytes32 private constant NAMEHASH_ETH = 0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae;

    struct Sale {
        // The lowest direct purchase price that will be accepted
        uint256 price;
        // The lowest auction bid that will be accepted
        uint256 reserve;
        // The last bid on the auction.  0 if no bid has been made
        uint256 lastBid;
        // The address of the last bider on the auction.  0 if no bid has been made
        address lastBidder;
        // The timestamp when this auction started
        uint256 auctionStarted;
        // The timestamp at which this auction ends
        uint256 auctionEnds;
        // The address of the referrer who started the sale
        address startReferrer;
        // The address of the referrer who supplied the winning bid
        address bidReferrer;
    }

    //
    // Events
    //

    // Sent when a name is offered (can occur multiple times if the seller
    // changes their prices)
    event Offer(address indexed seller, string name, uint256 price, uint256 reserve);
    // Sent when a bid is placed for a name
    event Bid(address indexed bidder, string name, uint256 bid);
    // Sent when a name is transferred to a new owner
    event Transfer(address indexed seller, address indexed buyer, string name, uint256 value);
    // Sent when a sale for a name is cancelled
    event Cancel(string name);

    //
    // Modifiers
    //

    // Actions that can only be undertaken by the seller of the name.
    // The owner of the name is this contract, so we use the previous
    // owner from the deed
    modifier onlyNameSeller(string _name) {
        Deed deed;
        (,deed,,,) = registrar.entries(sha3(_name));
        require(deed.owner() == address(this));
        require(deed.previousOwner() == msg.sender);
        _;
    }

    // It is possible for a name to be invalidated, in which case the
    // owner will be reset
    modifier deedValid(string _name) {
        address deed;
        (,deed,,,) = registrar.entries(sha3(_name));
        require(deed != 0);
        _;
    }

    // Actions that can only be undertaken if the name sale has attracted
    // no bids.
    modifier auctionNotStarted(string _name) {
        require(sales[_name].auctionStarted == 0);
        _;
    }

    // Allow if the name can be bid upon
    modifier canBid(string _name) {
        require(sales[_name].reserve != 0);
        _;
    }

    // Allow if the name can be purchased
    modifier canBuy(string _name) {
        require(sales[_name].price != 0);
        _;
    }

    /**
     * @dev Constructor takes the address of the ENS registry
     */
    function DomainSale(address _registry) ENSReverseRegister(_registry, CONTRACT_ENS) {
        registrar = Registrar(Registry(_registry).owner(NAMEHASH_ETH));
    }

    //
    // Accessors for sales struct
    //

    /**
     * @dev return useful information from the sale structure in one go
     */
    function sale(string _name) public constant returns (uint256, uint256, uint256, address, uint256, uint256) {
        Sale storage s = sales[_name];
        return (s.price, s.reserve, s.lastBid, s.lastBidder, s.auctionStarted, s.auctionEnds);
    }

    /**
     * @dev a flag set if this name can be purchased through auction
     */
    function isAuction(string _name) public constant returns (bool) {
        return sales[_name].reserve != 0;
    }

    /**
     * @dev a flag set if this name can be purchased outright
     */
    function isBuyable(string _name) public constant returns (bool) {
        return sales[_name].price != 0;
    }

    /**
     * @dev a flag set if the auction has started
     */
    function auctionStarted(string _name) public constant returns (bool) {
        return sales[_name].lastBid != 0;
    }

    /**
     * @dev the time at which the auction ends
     */
    function auctionEnds(string _name) public constant returns (uint256) {
        return sales[_name].auctionEnds;
    }

    /**
     * @dev minimumBid is the greater of the minimum bid or the last bid + 10%.
     *      If an auction has been going longer than 7 days then it is the last
     *      bid + 50%.
     *      Throws if this sale does not accept bids
     */
    function minimumBid(string _name) public constant returns (uint256) {
        Sale storage s = sales[_name];

        if (s.auctionStarted == 0) {
            return s.reserve;
        } else if (s.auctionStarted + HIGH_BID_KICKIN > now) {
            return s.lastBid + s.lastBid * NORMAL_BID_INCREASE_PERCENTAGE / 100;
        } else {
            return s.lastBid + s.lastBid * HIGH_BID_INCREASE_PERCENTAGE / 100;
        }
    }

    /**
     * @dev price is the instant purchase price.
     *      Throws if this sale does not accept an instant purchase
     */
    function price(string _name) public constant returns (uint256) {
        Sale storage s = sales[_name];

        return s.price;
    }

    /**
     * @dev The balance available for withdrawal
     */
    function balance() public constant returns (uint256) {
        return balances[msg.sender];
    }

    //
    // Operations
    //

    /**
     * @dev offer a domain for sale.
     *      The price is the price at which a domain can be purchased directly.
     *      The reserve is the initial lowest price for which a bid can be made.
     */
    function offer(string _name, uint256 _price, uint256 reserve, address referrer) onlyNameSeller(_name) auctionNotStarted(_name) deedValid(_name) public {
        require(_price == 0 || _price > reserve);
        require(_price != 0 || reserve != 0);
        Sale storage s = sales[_name];
        s.reserve = reserve;
        s.price = _price;
        s.startReferrer = referrer;
        Offer(msg.sender, _name, _price, reserve);
    }

    /**
     * @dev cancel a sale for a domain.
     *      This can only happen if there have been no bids for the name.
     */
    function cancel(string _name) onlyNameSeller(_name) auctionNotStarted(_name) deedValid(_name) public {
        registrar.transfer(sha3(_name), msg.sender);
        Cancel(_name);

        // Tidy up
        clearStorage(_name);
    }

    /**
     * @dev buy a domain directly
     */
    function buy(string _name, address bidReferrer) canBuy(_name) deedValid(_name) public payable {
        Sale storage s = sales[_name];
        require(msg.value >= s.price);
        require(s.auctionStarted == 0);

        // As we're here, return any funds that the sender is owed
        withdraw();

        // Obtain the previous owner from the deed
        Deed deed;
        (,deed,,,) = registrar.entries(sha3(_name));
        address previousOwner = deed.previousOwner();

        // Transfer the name
        registrar.transfer(sha3(_name), msg.sender);
        Transfer(previousOwner, msg.sender, _name, msg.value);

        // Distribute funds to referrers
        transferFunds(msg.value, previousOwner, s.startReferrer, bidReferrer);

        // Tidy up
        clearStorage(_name);
    }

    /**
     * @dev bid for a domain
     */
    function bid(string _name, address bidReferrer) canBid(_name) deedValid(_name) public payable {
        require(msg.value >= minimumBid(_name));

        Sale storage s = sales[_name];
        require(s.auctionStarted == 0 || now < s.auctionEnds);

        // Update the balance for the outbid bidder
        balances[s.lastBidder] += s.lastBid;

        // As we're here, return any funds that the sender is owed
        withdraw();

        if (s.auctionStarted == 0) {
          // First bid; set the auction start
          s.auctionStarted = now;
        }
        s.lastBidder = msg.sender;
        s.lastBid = msg.value;
        s.auctionEnds = now + AUCTION_DURATION;
        s.bidReferrer = bidReferrer;
        Bid(msg.sender, _name, msg.value);
    }

    /**
     * @dev finish an auction
     */
    function finish(string _name) deedValid(_name) public {
        Sale storage s = sales[_name];
        require(now > s.auctionEnds);

        // Obtain the previous owner from the deed
        Deed deed;
        (,deed,,,) = registrar.entries(sha3(_name));

        address previousOwner = deed.previousOwner();
        registrar.transfer(sha3(_name), s.lastBidder);
        Transfer(previousOwner, s.lastBidder, _name, s.lastBid);

        // Distribute funds to referrers
        transferFunds(s.lastBid, previousOwner, s.startReferrer, s.bidReferrer);
        clearStorage(_name);
    }

    /**
     * @dev withdraw any owned balance
     */
    function withdraw() public {
        uint256 withdrawalAmount = balances[msg.sender];
        balances[msg.sender] = 0;
        // Attempt a withdrawal
        if (withdrawalAmount > 0 && !msg.sender.send(withdrawalAmount)) {
            // Withdrawal failed; revert the balance
            balances[msg.sender] = withdrawalAmount;
        }
    }

    /**
     * @dev Invalidate an auction if the deed is no longer active
     */
    function invalidate(string _name) public {
        // Ensure the deed has been invalidated
        address deed;
        (,deed,,,) = registrar.entries(sha3(_name));
        require(deed == 0);

        Sale storage s = sales[_name];

        // Update the balance for the winning bidder
        balances[s.lastBidder] += s.lastBid;

        // As we're here, return any funds that the sender is owed
        withdraw();

        // Cancel the auction
        Cancel(_name);

        // Tidy up
        clearStorage(_name);
    }

    //
    // Internal functions
    //

    /**
     * @dev Transfer funds for a sale to the relevant parties
     */
    function transferFunds(uint256 amount, address seller, address startReferrer, address bidReferrer) internal {
        seller.transfer(amount * SELLER_SALE_PERCENTAGE / 100);
        startReferrer.transfer(amount * START_REFERRER_SALE_PERCENTAGE / 100);
        bidReferrer.transfer(amount * BID_REFERRER_SALE_PERCENTAGE / 100);
    }

    /**
     * @dev Clear the storage for a name
     */
    function clearStorage(string _name) internal {
        // Clear name records
        sales[_name] = Sale({
            reserve: 0,
            price: 0,
            lastBid:0,
            lastBidder:0,
            auctionStarted:0,
            auctionEnds:0,
            startReferrer: 0,
            bidReferrer: 0
        });
    }
}