Remove redundant modifiers from safeTransferFrom (#1029) (#1030)

pragma solidity ^0.4.24;

import "./ERC721Basic.sol";
import "./ERC721Receiver.sol";
import "../../math/SafeMath.sol";
import "../../AddressUtils.sol";
import "../../introspection/SupportsInterfaceWithLookup.sol";

/**
 * @title ERC721 Non-Fungible Token Standard basic implementation
 * @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
 */
contract ERC721BasicToken is SupportsInterfaceWithLookup, ERC721Basic {

  using SafeMath for uint256;
  using AddressUtils for address;

  // Equals to `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
  // which can be also obtained as `ERC721Receiver(0).onERC721Received.selector`
  bytes4 private constant ERC721_RECEIVED = 0x150b7a02;

  // Mapping from token ID to owner
  mapping (uint256 => address) internal tokenOwner;

  // Mapping from token ID to approved address
  mapping (uint256 => address) internal tokenApprovals;

  // Mapping from owner to number of owned token
  mapping (address => uint256) internal ownedTokensCount;

  // Mapping from owner to operator approvals
  mapping (address => mapping (address => bool)) internal operatorApprovals;

  constructor()
    public
  {
    // register the supported interfaces to conform to ERC721 via ERC165
    _registerInterface(InterfaceId_ERC721);
    _registerInterface(InterfaceId_ERC721Exists);
  }

  /**
   * @dev Gets the balance of the specified address
   * @param _owner address to query the balance of
   * @return uint256 representing the amount owned by the passed address
   */
  function balanceOf(address _owner) public view returns (uint256) {
    require(_owner != address(0));
    return ownedTokensCount[_owner];
  }

  /**
   * @dev Gets the owner of the specified token ID
   * @param _tokenId uint256 ID of the token to query the owner of
   * @return owner address currently marked as the owner of the given token ID
   */
  function ownerOf(uint256 _tokenId) public view returns (address) {
    address owner = tokenOwner[_tokenId];
    require(owner != address(0));
    return owner;
  }

  /**
   * @dev Returns whether the specified token exists
   * @param _tokenId uint256 ID of the token to query the existence of
   * @return whether the token exists
   */
  function exists(uint256 _tokenId) public view returns (bool) {
    address owner = tokenOwner[_tokenId];
    return owner != address(0);
  }

  /**
   * @dev Approves another address to transfer the given token ID
   * The zero address indicates there is no approved address.
   * There can only be one approved address per token at a given time.
   * Can only be called by the token owner or an approved operator.
   * @param _to address to be approved for the given token ID
   * @param _tokenId uint256 ID of the token to be approved
   */
  function approve(address _to, uint256 _tokenId) public {
    address owner = ownerOf(_tokenId);
    require(_to != owner);
    require(msg.sender == owner || isApprovedForAll(owner, msg.sender));

    tokenApprovals[_tokenId] = _to;
    emit Approval(owner, _to, _tokenId);
  }

  /**
   * @dev Gets the approved address for a token ID, or zero if no address set
   * @param _tokenId uint256 ID of the token to query the approval of
   * @return address currently approved for the given token ID
   */
  function getApproved(uint256 _tokenId) public view returns (address) {
    return tokenApprovals[_tokenId];
  }

  /**
   * @dev Sets or unsets the approval of a given operator
   * An operator is allowed to transfer all tokens of the sender on their behalf
   * @param _to operator address to set the approval
   * @param _approved representing the status of the approval to be set
   */
  function setApprovalForAll(address _to, bool _approved) public {
    require(_to != msg.sender);
    operatorApprovals[msg.sender][_to] = _approved;
    emit ApprovalForAll(msg.sender, _to, _approved);
  }

  /**
   * @dev Tells whether an operator is approved by a given owner
   * @param _owner owner address which you want to query the approval of
   * @param _operator operator address which you want to query the approval of
   * @return bool whether the given operator is approved by the given owner
   */
  function isApprovedForAll(
    address _owner,
    address _operator
  )
    public
    view
    returns (bool)
  {
    return operatorApprovals[_owner][_operator];
  }

  /**
   * @dev Transfers the ownership of a given token ID to another address
   * Usage of this method is discouraged, use `safeTransferFrom` whenever possible
   * Requires the msg sender to be the owner, approved, or operator
   * @param _from current owner of the token
   * @param _to address to receive the ownership of the given token ID
   * @param _tokenId uint256 ID of the token to be transferred
  */
  function transferFrom(
    address _from,
    address _to,
    uint256 _tokenId
  )
    public
  {
    require(isApprovedOrOwner(msg.sender, _tokenId));
    require(_from != address(0));
    require(_to != address(0));

    clearApproval(_from, _tokenId);
    removeTokenFrom(_from, _tokenId);
    addTokenTo(_to, _tokenId);

    emit Transfer(_from, _to, _tokenId);
  }

  /**
   * @dev Safely transfers the ownership of a given token ID to another address
   * If the target address is a contract, it must implement `onERC721Received`,
   * which is called upon a safe transfer, and return the magic value
   * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise,
   * the transfer is reverted.
   *
   * Requires the msg sender to be the owner, approved, or operator
   * @param _from current owner of the token
   * @param _to address to receive the ownership of the given token ID
   * @param _tokenId uint256 ID of the token to be transferred
  */
  function safeTransferFrom(
    address _from,
    address _to,
    uint256 _tokenId
  )
    public
  {
    // solium-disable-next-line arg-overflow
    safeTransferFrom(_from, _to, _tokenId, "");
  }

  /**
   * @dev Safely transfers the ownership of a given token ID to another address
   * If the target address is a contract, it must implement `onERC721Received`,
   * which is called upon a safe transfer, and return the magic value
   * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise,
   * the transfer is reverted.
   * Requires the msg sender to be the owner, approved, or operator
   * @param _from current owner of the token
   * @param _to address to receive the ownership of the given token ID
   * @param _tokenId uint256 ID of the token to be transferred
   * @param _data bytes data to send along with a safe transfer check
   */
  function safeTransferFrom(
    address _from,
    address _to,
    uint256 _tokenId,
    bytes _data
  )
    public
  {
    transferFrom(_from, _to, _tokenId);
    // solium-disable-next-line arg-overflow
    require(checkAndCallSafeTransfer(_from, _to, _tokenId, _data));
  }

  /**
   * @dev Returns whether the given spender can transfer a given token ID
   * @param _spender address of the spender to query
   * @param _tokenId uint256 ID of the token to be transferred
   * @return bool whether the msg.sender is approved for the given token ID,
   *  is an operator of the owner, or is the owner of the token
   */
  function isApprovedOrOwner(
    address _spender,
    uint256 _tokenId
  )
    internal
    view
    returns (bool)
  {
    address owner = ownerOf(_tokenId);
    // Disable solium check because of
    // https://github.com/duaraghav8/Solium/issues/175
    // solium-disable-next-line operator-whitespace
    return (
      _spender == owner ||
      getApproved(_tokenId) == _spender ||
      isApprovedForAll(owner, _spender)
    );
  }

  /**
   * @dev Internal function to mint a new token
   * Reverts if the given token ID already exists
   * @param _to The address that will own the minted token
   * @param _tokenId uint256 ID of the token to be minted by the msg.sender
   */
  function _mint(address _to, uint256 _tokenId) internal {
    require(_to != address(0));
    addTokenTo(_to, _tokenId);
    emit Transfer(address(0), _to, _tokenId);
  }

  /**
   * @dev Internal function to burn a specific token
   * Reverts if the token does not exist
   * @param _tokenId uint256 ID of the token being burned by the msg.sender
   */
  function _burn(address _owner, uint256 _tokenId) internal {
    clearApproval(_owner, _tokenId);
    removeTokenFrom(_owner, _tokenId);
    emit Transfer(_owner, address(0), _tokenId);
  }

  /**
   * @dev Internal function to clear current approval of a given token ID
   * Reverts if the given address is not indeed the owner of the token
   * @param _owner owner of the token
   * @param _tokenId uint256 ID of the token to be transferred
   */
  function clearApproval(address _owner, uint256 _tokenId) internal {
    require(ownerOf(_tokenId) == _owner);
    if (tokenApprovals[_tokenId] != address(0)) {
      tokenApprovals[_tokenId] = address(0);
    }
  }

  /**
   * @dev Internal function to add a token ID to the list of a given address
   * @param _to address representing the new owner of the given token ID
   * @param _tokenId uint256 ID of the token to be added to the tokens list of the given address
   */
  function addTokenTo(address _to, uint256 _tokenId) internal {
    require(tokenOwner[_tokenId] == address(0));
    tokenOwner[_tokenId] = _to;
    ownedTokensCount[_to] = ownedTokensCount[_to].add(1);
  }

  /**
   * @dev Internal function to remove a token ID from the list of a given address
   * @param _from address representing the previous owner of the given token ID
   * @param _tokenId uint256 ID of the token to be removed from the tokens list of the given address
   */
  function removeTokenFrom(address _from, uint256 _tokenId) internal {
    require(ownerOf(_tokenId) == _from);
    ownedTokensCount[_from] = ownedTokensCount[_from].sub(1);
    tokenOwner[_tokenId] = address(0);
  }

  /**
   * @dev Internal function to invoke `onERC721Received` on a target address
   * The call is not executed if the target address is not a contract
   * @param _from address representing the previous owner of the given token ID
   * @param _to target address that will receive the tokens
   * @param _tokenId uint256 ID of the token to be transferred
   * @param _data bytes optional data to send along with the call
   * @return whether the call correctly returned the expected magic value
   */
  function checkAndCallSafeTransfer(
    address _from,
    address _to,
    uint256 _tokenId,
    bytes _data
  )
    internal
    returns (bool)
  {
    if (!_to.isContract()) {
      return true;
    }
    bytes4 retval = ERC721Receiver(_to).onERC721Received(
      msg.sender, _from, _tokenId, _data);
    return (retval == ERC721_RECEIVED);
  }
}

pragma solidity ^0.4.24;

import "./ERC721Basic.sol";
import "./ERC721Receiver.sol";
import "../../math/SafeMath.sol";
import "../../AddressUtils.sol";
import "../../introspection/SupportsInterfaceWithLookup.sol";

/**
 * @title ERC721 Non-Fungible Token Standard basic implementation
 * @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
 */
contract ERC721BasicToken is SupportsInterfaceWithLookup, ERC721Basic {

  using SafeMath for uint256;
  using AddressUtils for address;

  // Equals to `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
  // which can be also obtained as `ERC721Receiver(0).onERC721Received.selector`
  bytes4 private constant ERC721_RECEIVED = 0x150b7a02;

  // Mapping from token ID to owner
  mapping (uint256 => address) internal tokenOwner;

  // Mapping from token ID to approved address
  mapping (uint256 => address) internal tokenApprovals;

  // Mapping from owner to number of owned token
  mapping (address => uint256) internal ownedTokensCount;

  // Mapping from owner to operator approvals
  mapping (address => mapping (address => bool)) internal operatorApprovals;

  /**
   * @dev Guarantees msg.sender is owner of the given token
   * @param _tokenId uint256 ID of the token to validate its ownership belongs to msg.sender
   */
  modifier onlyOwnerOf(uint256 _tokenId) {
    require(ownerOf(_tokenId) == msg.sender);
    _;
  }

  /**
   * @dev Checks msg.sender can transfer a token, by being owner, approved, or operator
   * @param _tokenId uint256 ID of the token to validate
   */
  modifier canTransfer(uint256 _tokenId) {
    require(isApprovedOrOwner(msg.sender, _tokenId));
    _;
  }

  constructor()
    public
  {
    // register the supported interfaces to conform to ERC721 via ERC165
    _registerInterface(InterfaceId_ERC721);
    _registerInterface(InterfaceId_ERC721Exists);
  }

  /**
   * @dev Gets the balance of the specified address
   * @param _owner address to query the balance of
   * @return uint256 representing the amount owned by the passed address
   */
  function balanceOf(address _owner) public view returns (uint256) {
    require(_owner != address(0));
    return ownedTokensCount[_owner];
  }

  /**
   * @dev Gets the owner of the specified token ID
   * @param _tokenId uint256 ID of the token to query the owner of
   * @return owner address currently marked as the owner of the given token ID
   */
  function ownerOf(uint256 _tokenId) public view returns (address) {
    address owner = tokenOwner[_tokenId];
    require(owner != address(0));
    return owner;
  }

  /**
   * @dev Returns whether the specified token exists
   * @param _tokenId uint256 ID of the token to query the existence of
   * @return whether the token exists
   */
  function exists(uint256 _tokenId) public view returns (bool) {
    address owner = tokenOwner[_tokenId];
    return owner != address(0);
  }

  /**
   * @dev Approves another address to transfer the given token ID
   * The zero address indicates there is no approved address.
   * There can only be one approved address per token at a given time.
   * Can only be called by the token owner or an approved operator.
   * @param _to address to be approved for the given token ID
   * @param _tokenId uint256 ID of the token to be approved
   */
  function approve(address _to, uint256 _tokenId) public {
    address owner = ownerOf(_tokenId);
    require(_to != owner);
    require(msg.sender == owner || isApprovedForAll(owner, msg.sender));

    tokenApprovals[_tokenId] = _to;
    emit Approval(owner, _to, _tokenId);
  }

  /**
   * @dev Gets the approved address for a token ID, or zero if no address set
   * @param _tokenId uint256 ID of the token to query the approval of
   * @return address currently approved for the given token ID
   */
  function getApproved(uint256 _tokenId) public view returns (address) {
    return tokenApprovals[_tokenId];
  }

  /**
   * @dev Sets or unsets the approval of a given operator
   * An operator is allowed to transfer all tokens of the sender on their behalf
   * @param _to operator address to set the approval
   * @param _approved representing the status of the approval to be set
   */
  function setApprovalForAll(address _to, bool _approved) public {
    require(_to != msg.sender);
    operatorApprovals[msg.sender][_to] = _approved;
    emit ApprovalForAll(msg.sender, _to, _approved);
  }

  /**
   * @dev Tells whether an operator is approved by a given owner
   * @param _owner owner address which you want to query the approval of
   * @param _operator operator address which you want to query the approval of
   * @return bool whether the given operator is approved by the given owner
   */
  function isApprovedForAll(
    address _owner,
    address _operator
  )
    public
    view
    returns (bool)
  {
    return operatorApprovals[_owner][_operator];
  }

  /**
   * @dev Transfers the ownership of a given token ID to another address
   * Usage of this method is discouraged, use `safeTransferFrom` whenever possible
   * Requires the msg sender to be the owner, approved, or operator
   * @param _from current owner of the token
   * @param _to address to receive the ownership of the given token ID
   * @param _tokenId uint256 ID of the token to be transferred
  */
  function transferFrom(
    address _from,
    address _to,
    uint256 _tokenId
  )
    public
    canTransfer(_tokenId)
  {
    require(_from != address(0));
    require(_to != address(0));

    clearApproval(_from, _tokenId);
    removeTokenFrom(_from, _tokenId);
    addTokenTo(_to, _tokenId);

    emit Transfer(_from, _to, _tokenId);
  }

  /**
   * @dev Safely transfers the ownership of a given token ID to another address
   * If the target address is a contract, it must implement `onERC721Received`,
   * which is called upon a safe transfer, and return the magic value
   * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise,
   * the transfer is reverted.
   *
   * Requires the msg sender to be the owner, approved, or operator
   * @param _from current owner of the token
   * @param _to address to receive the ownership of the given token ID
   * @param _tokenId uint256 ID of the token to be transferred
  */
  function safeTransferFrom(
    address _from,
    address _to,
    uint256 _tokenId
  )
    public
    canTransfer(_tokenId)
  {
    // solium-disable-next-line arg-overflow
    safeTransferFrom(_from, _to, _tokenId, "");
  }

  /**
   * @dev Safely transfers the ownership of a given token ID to another address
   * If the target address is a contract, it must implement `onERC721Received`,
   * which is called upon a safe transfer, and return the magic value
   * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise,
   * the transfer is reverted.
   * Requires the msg sender to be the owner, approved, or operator
   * @param _from current owner of the token
   * @param _to address to receive the ownership of the given token ID
   * @param _tokenId uint256 ID of the token to be transferred
   * @param _data bytes data to send along with a safe transfer check
   */
  function safeTransferFrom(
    address _from,
    address _to,
    uint256 _tokenId,
    bytes _data
  )
    public
    canTransfer(_tokenId)
  {
    transferFrom(_from, _to, _tokenId);
    // solium-disable-next-line arg-overflow
    require(checkAndCallSafeTransfer(_from, _to, _tokenId, _data));
  }

  /**
   * @dev Returns whether the given spender can transfer a given token ID
   * @param _spender address of the spender to query
   * @param _tokenId uint256 ID of the token to be transferred
   * @return bool whether the msg.sender is approved for the given token ID,
   *  is an operator of the owner, or is the owner of the token
   */
  function isApprovedOrOwner(
    address _spender,
    uint256 _tokenId
  )
    internal
    view
    returns (bool)
  {
    address owner = ownerOf(_tokenId);
    // Disable solium check because of
    // https://github.com/duaraghav8/Solium/issues/175
    // solium-disable-next-line operator-whitespace
    return (
      _spender == owner ||
      getApproved(_tokenId) == _spender ||
      isApprovedForAll(owner, _spender)
    );
  }

  /**
   * @dev Internal function to mint a new token
   * Reverts if the given token ID already exists
   * @param _to The address that will own the minted token
   * @param _tokenId uint256 ID of the token to be minted by the msg.sender
   */
  function _mint(address _to, uint256 _tokenId) internal {
    require(_to != address(0));
    addTokenTo(_to, _tokenId);
    emit Transfer(address(0), _to, _tokenId);
  }

  /**
   * @dev Internal function to burn a specific token
   * Reverts if the token does not exist
   * @param _tokenId uint256 ID of the token being burned by the msg.sender
   */
  function _burn(address _owner, uint256 _tokenId) internal {
    clearApproval(_owner, _tokenId);
    removeTokenFrom(_owner, _tokenId);
    emit Transfer(_owner, address(0), _tokenId);
  }

  /**
   * @dev Internal function to clear current approval of a given token ID
   * Reverts if the given address is not indeed the owner of the token
   * @param _owner owner of the token
   * @param _tokenId uint256 ID of the token to be transferred
   */
  function clearApproval(address _owner, uint256 _tokenId) internal {
    require(ownerOf(_tokenId) == _owner);
    if (tokenApprovals[_tokenId] != address(0)) {
      tokenApprovals[_tokenId] = address(0);
    }
  }

  /**
   * @dev Internal function to add a token ID to the list of a given address
   * @param _to address representing the new owner of the given token ID
   * @param _tokenId uint256 ID of the token to be added to the tokens list of the given address
   */
  function addTokenTo(address _to, uint256 _tokenId) internal {
    require(tokenOwner[_tokenId] == address(0));
    tokenOwner[_tokenId] = _to;
    ownedTokensCount[_to] = ownedTokensCount[_to].add(1);
  }

  /**
   * @dev Internal function to remove a token ID from the list of a given address
   * @param _from address representing the previous owner of the given token ID
   * @param _tokenId uint256 ID of the token to be removed from the tokens list of the given address
   */
  function removeTokenFrom(address _from, uint256 _tokenId) internal {
    require(ownerOf(_tokenId) == _from);
    ownedTokensCount[_from] = ownedTokensCount[_from].sub(1);
    tokenOwner[_tokenId] = address(0);
  }

  /**
   * @dev Internal function to invoke `onERC721Received` on a target address
   * The call is not executed if the target address is not a contract
   * @param _from address representing the previous owner of the given token ID
   * @param _to target address that will receive the tokens
   * @param _tokenId uint256 ID of the token to be transferred
   * @param _data bytes optional data to send along with the call
   * @return whether the call correctly returned the expected magic value
   */
  function checkAndCallSafeTransfer(
    address _from,
    address _to,
    uint256 _tokenId,
    bytes _data
  )
    internal
    returns (bool)
  {
    if (!_to.isContract()) {
      return true;
    }
    bytes4 retval = ERC721Receiver(_to).onERC721Received(
      msg.sender, _from, _tokenId, _data);
    return (retval == ERC721_RECEIVED);
  }
}


add 1 to burnRate calculation

add 1 to burnRate calculation

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; //marks creation of assessment / start of commit phase / start of reveal phase (time in seconds)
  uint burnRate;
  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*assessors.length);
    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){
      // cancel if the assessment is older than 12 hours
      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; // reset checkpoint to mark start of actual assessment phase
          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);
  }
  event fb(uint x);
  //@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(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 the boundary assessor
        if( done*10 >= 10*size/2 &&
            (done - 1)*10 < 10*size/2) {
            burnRate = (cost / (now - checkpoint)) + 1;
            checkpoint = now + (now - checkpoint);
        }
    }
    if(done == size) {
        notifyAssessors(uint(State.Committed), 5);
        checkpoint = now; //reset checkpoint to mark start of reveal phase
        done = 0; //Resets the done counter
        assessmentStage = State.Committed;
    }

  }

  //@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;
                  size--;
              }
          }
          return;
      }

      bytes32 hash = sha3(score,salt);
      if (assessorState[assessor] == State.Committed) {
              if(commits[assessor] == hash){
          // log in score and increase done
          if(msg.sender == assessor) {
              scores[msg.sender] = score;
              assessorState[assessor] = State.Done;
              done++;
          }
          else {
            // give the stake to the caller and burn assessor
            Concept(concept).addBalance(msg.sender, stake[assessor]);
            stake[assessor] = 0;
            assessorState[assessor] = State.Burned;
            size--;
          }
      }
      }
      //If all the assessors have revealed their scored or burned their stakes
      if(done == size) {
          assessmentStage = State.Done;
          calculateResult(); //The final result is calculated
      }
  }
  event fb(uint x);
  event b(string s);
  //@purpose: burns stakes as a function of how much time has passed since half of the assessors commited
  function burnStakes() internal {
      if(now-checkpoint > now) { //-> underflows if now before the end of the grace period
          return;
      }
      for(uint i = 0; i < assessors.length; i++) {
          if(assessorState[assessors[i]] == State.Confirmed) {
              stake[assessors[i]] = cost - (burnRate * (now - checkpoint));
              if (stake[assessors[i]] == 0 ||
                  stake[assessors[i]] > cost){
                    assessorState[assessors[i]] = State.Burned;
                    stake[assessors[i]] = 0;
                    size--; //decrease size 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 < assessors.length; j++) {
           if(assessorState[assessors[j]] == State.Done) {
               finalAssessors.push(assessors[j]); //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 < assessors.length; i++) {
           if (assessorState[assessors[i]] == State.Done){
               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
                   //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
                   payoutValue = (q*cost*((100 - uint(scoreDistance))/100)) + stake[assessors[i]];
                   Concept(concept).addBalance(assessors[i], payoutValue);
               }
               if(inRewardCluster[score] == false) {
                   //The assessor's payout will be a propotion of their remaining stake determined by their distance from the final score
                   payoutValue = stake[assessors[i]]*((200 - uint(scoreDistance))/200);
                   Concept(concept).addBalance(assessors[i], payoutValue);
               }
               //Sends assessment info to the concept so that it can update its records
               Concept(concept).finishAssessment(finalScore, assessee, address(this));
               UserRegistry(userRegistry).notification(assessors[i], 6); //You  got paid!
           }
       }
   }
}

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; //marks creation of assessment / start of commit phase / start of reveal phase (time in seconds)
  uint burnRate;
  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*assessors.length);
    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){
      // cancel if the assessment is older than 12 hours
      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; // reset checkpoint to mark start of actual assessment phase
          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);
  }
  event fb(uint x);
  //@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(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 the boundary assessor
        if( done*10 >= 10*size/2 &&
            (done - 1)*10 < 10*size/2) {
            burnRate = cost / (now - checkpoint);
            checkpoint = now + (now - checkpoint);
        }
    }
    if(done == size) {
        notifyAssessors(uint(State.Committed), 5);
        checkpoint = now; //reset checkpoint to mark start of reveal phase
        done = 0; //Resets the done counter
        assessmentStage = State.Committed;
    }

  }

  //@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;
                  size--;
              }
          }
          return;
      }

      bytes32 hash = sha3(score,salt);
      if (assessorState[assessor] == State.Committed) {
              if(commits[assessor] == hash){
          // log in score and increase done
          if(msg.sender == assessor) {
              scores[msg.sender] = score;
              assessorState[assessor] = State.Done;
              done++;
          }
          else {
            // give the stake to the caller and burn assessor
            Concept(concept).addBalance(msg.sender, stake[assessor]);
            stake[assessor] = 0;
            assessorState[assessor] = State.Burned;
            size--;
          }
      }
      }
      //If all the assessors have revealed their scored or burned their stakes
      if(done == size) {
          assessmentStage = State.Done;
          calculateResult(); //The final result is calculated
      }
  }
  event fb(uint x);
  event b(string s);
  //@purpose: burns stakes as a function of how much time has passed since half of the assessors commited
  function burnStakes() internal {
      if(now-checkpoint > now) { //-> underflows if now before the end of the grace period
          return;
      }
      for(uint i = 0; i < assessors.length; i++) {
          if(assessorState[assessors[i]] == State.Confirmed) {
              stake[assessors[i]] = cost - (burnRate * (now - checkpoint));
              if (stake[assessors[i]] == 0 ||
                  stake[assessors[i]] > cost){
                    assessorState[assessors[i]] = State.Burned;
                    stake[assessors[i]] = 0;
                    size--; //decrease size 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 < assessors.length; j++) {
           if(assessorState[assessors[j]] == State.Done) {
               finalAssessors.push(assessors[j]); //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 < assessors.length; i++) {
           if (assessorState[assessors[i]] == State.Done){
               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
                   //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
                   payoutValue = (q*cost*((100 - uint(scoreDistance))/100)) + stake[assessors[i]];
                   Concept(concept).addBalance(assessors[i], payoutValue);
               }
               if(inRewardCluster[score] == false) {
                   //The assessor's payout will be a propotion of their remaining stake determined by their distance from the final score
                   payoutValue = stake[assessors[i]]*((200 - uint(scoreDistance))/200);
                   Concept(concept).addBalance(assessors[i], payoutValue);
               }
               //Sends assessment info to the concept so that it can update its records
               Concept(concept).finishAssessment(finalScore, assessee, address(this));
               UserRegistry(userRegistry).notification(assessors[i], 6); //You  got paid!
           }
       }
   }
}


Function checkAddERC20 should be internal

pragma solidity ^0.4.11;

import './ERC20.sol';
import './governanceInterface.sol';

contract Bet is ProposalInterface {

  modifier onlyOwner() {
    require(msg.sender == owner);
    _;
  }
  modifier onlyArbiter() {
    require(msg.sender == address(arbiter));
    _;
  }
  modifier beforeTimestamp(uint timestamp) {
    require(block.timestamp < timestamp);
    _;
  }
  modifier afterTimestamp(uint timestamp) {
    require(block.timestamp >= timestamp);
    _;
  }
  modifier matchIsOpenOrUndecided() {
    require(betState == BET_STATES.OPEN || betState == BET_STATES.UNDECIDED);
    _;
  }
  modifier matchIsDecided() {
    require(betState == BET_STATES.TEAM_ZERO_WON ||
            betState == BET_STATES.TEAM_ONE_WON ||
            betState == BET_STATES.DRAW);
    _;
  }

  enum BET_STATES {
    OPEN,
    TEAM_ZERO_WON,
    TEAM_ONE_WON,
    DRAW,
    UNDECIDED,
    CALLED_RESOLVER
  }

  address public owner; // Can be a parent contract
  GovernanceInterface public arbiter; // Governance account

  // Bet data
  BET_STATES public betState = BET_STATES.OPEN;
  bool public isFeatured;
  string public team0Name;
  string public team1Name;
  string public category;
  uint public team0BetSum;
  uint public team1BetSum;
  mapping (address => uint) public betsToTeam0;
  mapping (address => uint) public betsToTeam1;

  // ERC20 support
  mapping (address => mapping (address => uint)) public ERC20BetsToTeam0;
  mapping (address => mapping (address => uint)) public ERC20BetsToTeam1;
  mapping (address => uint) ERC20Team0BetSum;
  mapping (address => uint) ERC20Team1BetSum;
  address[] validERC20;

  // Chronology data
  uint public timestampMatchBegin;
  uint public timestampMatchEnd;
  uint public timestampArbiterDeadline;
  // Self-destruct is possible if time > timestampSelfDestructDeadline
  uint public timestampSelfDestructDeadline;

  uint8 public constant TAX = 10;
  uint constant TIMESTAMP_MARGIN = 1000;

  event NewBet(bool forTeam, address indexed from, uint amount);
  event NewBetERC20(bool forTeam, address indexed from, uint amount, address erc20);
  event StateChanged(BET_STATES state);

  function Bet(GovernanceInterface _arbiter, string _team0Name,
               string _team1Name, string _category,
               uint[] _timestamps
               ) {
    require(block.timestamp < _timestamps[0]);
    require(_timestamps[0] < _timestamps[1]);
    require(_timestamps[1] < _timestamps[2]);
    require(_timestamps[2] < _timestamps[3]);

    isFeatured = false;
    owner = msg.sender;
    arbiter = _arbiter;
    team0Name = _team0Name;
    team1Name = _team1Name;
    category = _category;
    // TODO: PUT BACK TIMESTAMP_MARGIN SUMS, PUT REQUIRES!
    timestampMatchBegin = _timestamps[0];// - TIMESTAMP_MARGIN;
    timestampMatchEnd = _timestamps[1];// + TIMESTAMP_MARGIN;
    timestampArbiterDeadline = _timestamps[2];// + TIMESTAMP_MARGIN;
    timestampSelfDestructDeadline = _timestamps[3];// + TIMESTAMP_MARGIN;
  }

  function __resolve(uint outcome)
    onlyArbiter()
    afterTimestamp(timestampMatchEnd)
    beforeTimestamp(timestampArbiterDeadline) {
    require(betState == BET_STATES.CALLED_RESOLVER);
    if (outcome == 1)
      betState = BET_STATES.TEAM_ZERO_WON;
    else if (outcome == 2)
      betState = BET_STATES.TEAM_ONE_WON;
    else if (outcome == 3)
      betState = BET_STATES.DRAW;
    else
      betState = BET_STATES.UNDECIDED;
    StateChanged(betState);
  }

  // Will create a Proposal on the arbiter
  function updateResult() payable
    matchIsOpenOrUndecided()
    afterTimestamp(timestampMatchEnd) {
    require(betState != BET_STATES.CALLED_RESOLVER);
    betState = BET_STATES.CALLED_RESOLVER;
    StateChanged(betState);
    arbiter.addProposal(this, timestampArbiterDeadline);
  }

  function toggleFeatured() onlyOwner() {
    isFeatured = !isFeatured;
  }

  function modifyCategory(string newCategory) onlyOwner() {
    category = newCategory;
  }

  function bet(bool forTeam) payable
    beforeTimestamp(timestampMatchBegin) {
    require(!arbiter.isMember(msg.sender));
    require(msg.value > 0);
    uint prevSum;

    if (forTeam == false) {
      // Cannot bet in two teams
      require(betsToTeam1[msg.sender] == 0);
      prevSum = team0BetSum;
      require((prevSum + msg.value) >= prevSum); // Overflow
      team0BetSum += msg.value;
      assert(team0BetSum >= prevSum);
      betsToTeam0[msg.sender] += msg.value;
    }
    else {
      // Cannot bet in two teams
      require(betsToTeam0[msg.sender] == 0);
      prevSum = team1BetSum;
      require((prevSum + msg.value) >= prevSum); // Overflow
      team1BetSum += msg.value;
      assert(team1BetSum >= prevSum);
      betsToTeam1[msg.sender] += msg.value;
    }

    NewBet(forTeam, msg.sender, msg.value);
  }

  function checkAddERC20(address erc20) internal {
    if (ERC20Team0BetSum[erc20] == 0 && ERC20Team1BetSum[erc20] == 0) {
      validERC20.push(erc20);
    }
  }

  function betERC20(address erc20, bool forTeam, uint amount)
    beforeTimestamp(timestampMatchBegin) {
    require(!arbiter.isMember(msg.sender));
    require(amount > 0);
    uint prevSum;

    ERC20 erc20Contract = ERC20(erc20);
    require(erc20Contract.transferFrom(msg.sender, this, amount));

    checkAddERC20(erc20);

    if (forTeam == false) {
      // Cannot bet in two teams
      require(ERC20BetsToTeam1[erc20][msg.sender] == 0);
      prevSum = ERC20Team0BetSum[erc20];
      require((prevSum + amount) >= prevSum); // Overflow
      ERC20Team0BetSum[erc20] += amount;
      assert(ERC20Team0BetSum[erc20] >= prevSum);
      ERC20BetsToTeam0[erc20][msg.sender] += amount;
    }
    else {
      // Cannot bet in two teams
      require(ERC20BetsToTeam0[erc20][msg.sender] == 0);
      prevSum = ERC20Team1BetSum[erc20];
      require((prevSum + amount) >= prevSum); // Overflow
      ERC20Team1BetSum[erc20] += amount;
      assert(ERC20Team1BetSum[erc20] >= prevSum);
      ERC20BetsToTeam1[erc20][msg.sender] += amount;
    }

    NewBetERC20(forTeam, msg.sender, amount, erc20);
  }

  function withdraw()
    afterTimestamp(timestampMatchEnd)
    matchIsDecided() {
    uint idx;
    if (betState == BET_STATES.DRAW) {
      msg.sender.transfer(collectOriginalBet());
      for (idx = 0; idx < validERC20.length; ++idx) {
        uint amount = collectOriginalBetERC20(validERC20[idx]);
        if (amount > 0) {
          ERC20 erc20Contract = ERC20(validERC20[idx]);
          require(erc20Contract.transfer(msg.sender, amount));
        }
      }
    }
    else {
      collectProfit();
      for (idx = 0; idx < validERC20.length; ++idx) {
        collectProfitERC20(validERC20[idx]);
      }
    }
  }

  // Transfers the user's initial bet back
  function collectOriginalBet() internal returns(uint) {
    uint amount;
    if (betsToTeam0[msg.sender] > 0) {
      amount = betsToTeam0[msg.sender];
      betsToTeam0[msg.sender] = 0;
      return amount;
    }
    else if (betsToTeam1[msg.sender] > 0) {
      amount = betsToTeam1[msg.sender];
      betsToTeam1[msg.sender] = 0;
      return amount;
    }
    else {
      return 0;
    }
  }

  // Transfers the user's initial bet back
  function collectOriginalBetERC20(address erc20) internal returns(uint) {
    uint amount;
    if (ERC20BetsToTeam0[erc20][msg.sender] > 0) {
      amount = ERC20BetsToTeam0[erc20][msg.sender];
      ERC20BetsToTeam0[erc20][msg.sender] = 0;
      return amount;
    }
    else if (ERC20BetsToTeam1[erc20][msg.sender] > 0) {
      amount = ERC20BetsToTeam1[erc20][msg.sender];
      ERC20BetsToTeam1[erc20][msg.sender] = 0;
      return amount;
    }
    else {
      return 0;
    }
  }

  function collectProfit() internal {
    uint bet = 0;
    uint sum = 0;
    uint profit = 0;

    if (betState == BET_STATES.TEAM_ZERO_WON && betsToTeam0[msg.sender] > 0) {
      bet = betsToTeam0[msg.sender];
      sum = team0BetSum;
      profit = team1BetSum;
    }
    else if (betState == BET_STATES.TEAM_ONE_WON && betsToTeam1[msg.sender] > 0) {
      bet = betsToTeam1[msg.sender];
      sum = team1BetSum;
      profit = team0BetSum;
    }
    else {
      return;
    }

    assert(bet <= sum);

    profit = computeProfit(bet, sum, profit);
    msg.sender.transfer(profit + collectOriginalBet());
  }

  function collectProfitERC20(address erc20) internal {
    uint bet = 0;
    uint sum = 0;
    uint profit = 0;

    if (betState == BET_STATES.TEAM_ZERO_WON && ERC20BetsToTeam0[erc20][msg.sender] > 0) {
      bet = ERC20BetsToTeam0[erc20][msg.sender];
      sum = ERC20Team0BetSum[erc20];
      profit = ERC20Team1BetSum[erc20];
    }
    else if (betState == BET_STATES.TEAM_ONE_WON && ERC20BetsToTeam1[erc20][msg.sender] > 0) {
      bet = ERC20BetsToTeam1[erc20][msg.sender];
      sum = ERC20Team1BetSum[erc20];
      profit = ERC20Team0BetSum[erc20];
    }
    else {
      return;
    }

    assert(bet <= sum);

    profit = computeProfit(bet, sum, profit);
    ERC20 erc20Contract = ERC20(erc20);
    require(erc20Contract.transfer(msg.sender, profit + collectOriginalBetERC20(erc20)));
  }

  // Compute the user's profit
  function computeProfit(uint bet, uint sum, uint profit) internal returns(uint) {
    // Approach one:
    // We might lose precision, but no overflow
    var senderPc = bet / sum;
    assert(senderPc >= 0 && senderPc <= 1);

    var senderProfit = senderPc * profit;
    assert(senderProfit <= profit);

    // Approach two:
    // Better precision, since multiplication is done first, but may overflow
    //uint sender_profit = (bet * profit) / sum;

    var mulTax = (senderProfit * TAX);
    require(mulTax >= senderProfit); // Overflow
    var tax = mulTax / 100;
    assert(tax <= senderProfit);

    var notaxProfit = senderProfit;
    senderProfit -= tax;
    assert(senderProfit <= notaxProfit);

    return senderProfit;

    // We can collect the bet tax by ourselves when the bet self-destructs
    // owner.transfer(tax);
    //msg.sender.transfer(senderProfit + collectOriginalBet());
  }

  /* After the arbiter deadline and before the self-destruct
   * deadline, anyone can set the bet state to DRAW.
   * this is in the unlikely event if the arbiter don't
   * decide in time, every one can collect the funds.
  */
  function close()
    afterTimestamp(timestampArbiterDeadline)
    beforeTimestamp(timestampSelfDestructDeadline) {
    betState = BET_STATES.DRAW;
  }

  /* Selfdestructs the bet and return what it has in the account
   * as a fee to the bet's owner.
   */
  function terminate()
    afterTimestamp(timestampSelfDestructDeadline) {
    selfdestruct(owner);
  }

  /* Fallback just throws now
   * Can do something, maybe increase the value of both pools
  */
  function () { require(false); }
}

pragma solidity ^0.4.11;

import './ERC20.sol';
import './governanceInterface.sol';

contract Bet is ProposalInterface {

  modifier onlyOwner() {
    require(msg.sender == owner);
    _;
  }
  modifier onlyArbiter() {
    require(msg.sender == address(arbiter));
    _;
  }
  modifier beforeTimestamp(uint timestamp) {
    require(block.timestamp < timestamp);
    _;
  }
  modifier afterTimestamp(uint timestamp) {
    require(block.timestamp >= timestamp);
    _;
  }
  modifier matchIsOpenOrUndecided() {
    require(betState == BET_STATES.OPEN || betState == BET_STATES.UNDECIDED);
    _;
  }
  modifier matchIsDecided() {
    require(betState == BET_STATES.TEAM_ZERO_WON ||
            betState == BET_STATES.TEAM_ONE_WON ||
            betState == BET_STATES.DRAW);
    _;
  }

  enum BET_STATES {
    OPEN,
    TEAM_ZERO_WON,
    TEAM_ONE_WON,
    DRAW,
    UNDECIDED,
    CALLED_RESOLVER
  }

  address public owner; // Can be a parent contract
  GovernanceInterface public arbiter; // Governance account

  // Bet data
  BET_STATES public betState = BET_STATES.OPEN;
  bool public isFeatured;
  string public team0Name;
  string public team1Name;
  string public category;
  uint public team0BetSum;
  uint public team1BetSum;
  mapping (address => uint) public betsToTeam0;
  mapping (address => uint) public betsToTeam1;

  // ERC20 support
  mapping (address => mapping (address => uint)) public ERC20BetsToTeam0;
  mapping (address => mapping (address => uint)) public ERC20BetsToTeam1;
  mapping (address => uint) ERC20Team0BetSum;
  mapping (address => uint) ERC20Team1BetSum;
  address[] validERC20;

  // Chronology data
  uint public timestampMatchBegin;
  uint public timestampMatchEnd;
  uint public timestampArbiterDeadline;
  // Self-destruct is possible if time > timestampSelfDestructDeadline
  uint public timestampSelfDestructDeadline;

  uint8 public constant TAX = 10;
  uint constant TIMESTAMP_MARGIN = 1000;

  event NewBet(bool forTeam, address indexed from, uint amount);
  event NewBetERC20(bool forTeam, address indexed from, uint amount, address erc20);
  event StateChanged(BET_STATES state);

  function Bet(GovernanceInterface _arbiter, string _team0Name,
               string _team1Name, string _category,
               uint[] _timestamps
               ) {
    require(block.timestamp < _timestamps[0]);
    require(_timestamps[0] < _timestamps[1]);
    require(_timestamps[1] < _timestamps[2]);
    require(_timestamps[2] < _timestamps[3]);

    isFeatured = false;
    owner = msg.sender;
    arbiter = _arbiter;
    team0Name = _team0Name;
    team1Name = _team1Name;
    category = _category;
    // TODO: PUT BACK TIMESTAMP_MARGIN SUMS, PUT REQUIRES!
    timestampMatchBegin = _timestamps[0];// - TIMESTAMP_MARGIN;
    timestampMatchEnd = _timestamps[1];// + TIMESTAMP_MARGIN;
    timestampArbiterDeadline = _timestamps[2];// + TIMESTAMP_MARGIN;
    timestampSelfDestructDeadline = _timestamps[3];// + TIMESTAMP_MARGIN;
  }

  function __resolve(uint outcome)
    onlyArbiter()
    afterTimestamp(timestampMatchEnd)
    beforeTimestamp(timestampArbiterDeadline) {
    require(betState == BET_STATES.CALLED_RESOLVER);
    if (outcome == 1)
      betState = BET_STATES.TEAM_ZERO_WON;
    else if (outcome == 2)
      betState = BET_STATES.TEAM_ONE_WON;
    else if (outcome == 3)
      betState = BET_STATES.DRAW;
    else
      betState = BET_STATES.UNDECIDED;
    StateChanged(betState);
  }

  // Will create a Proposal on the arbiter
  function updateResult() payable
    matchIsOpenOrUndecided()
    afterTimestamp(timestampMatchEnd) {
    require(betState != BET_STATES.CALLED_RESOLVER);
    betState = BET_STATES.CALLED_RESOLVER;
    StateChanged(betState);
    arbiter.addProposal(this, timestampArbiterDeadline);
  }

  function toggleFeatured() onlyOwner() {
    isFeatured = !isFeatured;
  }

  function modifyCategory(string newCategory) onlyOwner() {
    category = newCategory;
  }

  function bet(bool forTeam) payable
    beforeTimestamp(timestampMatchBegin) {
    require(!arbiter.isMember(msg.sender));
    require(msg.value > 0);
    uint prevSum;

    if (forTeam == false) {
      // Cannot bet in two teams
      require(betsToTeam1[msg.sender] == 0);
      prevSum = team0BetSum;
      require((prevSum + msg.value) >= prevSum); // Overflow
      team0BetSum += msg.value;
      assert(team0BetSum >= prevSum);
      betsToTeam0[msg.sender] += msg.value;
    }
    else {
      // Cannot bet in two teams
      require(betsToTeam0[msg.sender] == 0);
      prevSum = team1BetSum;
      require((prevSum + msg.value) >= prevSum); // Overflow
      team1BetSum += msg.value;
      assert(team1BetSum >= prevSum);
      betsToTeam1[msg.sender] += msg.value;
    }

    NewBet(forTeam, msg.sender, msg.value);
  }

  function checkAddERC20(address erc20) {
    if (ERC20Team0BetSum[erc20] == 0 && ERC20Team1BetSum[erc20] == 0) {
      validERC20.push(erc20);
    }
  }

  function betERC20(address erc20, bool forTeam, uint amount)
    beforeTimestamp(timestampMatchBegin) {
    require(!arbiter.isMember(msg.sender));
    require(amount > 0);
    uint prevSum;

    ERC20 erc20Contract = ERC20(erc20);
    require(erc20Contract.transferFrom(msg.sender, this, amount));

    checkAddERC20(erc20);

    if (forTeam == false) {
      // Cannot bet in two teams
      require(ERC20BetsToTeam1[erc20][msg.sender] == 0);
      prevSum = ERC20Team0BetSum[erc20];
      require((prevSum + amount) >= prevSum); // Overflow
      ERC20Team0BetSum[erc20] += amount;
      assert(ERC20Team0BetSum[erc20] >= prevSum);
      ERC20BetsToTeam0[erc20][msg.sender] += amount;
    }
    else {
      // Cannot bet in two teams
      require(ERC20BetsToTeam0[erc20][msg.sender] == 0);
      prevSum = ERC20Team1BetSum[erc20];
      require((prevSum + amount) >= prevSum); // Overflow
      ERC20Team1BetSum[erc20] += amount;
      assert(ERC20Team1BetSum[erc20] >= prevSum);
      ERC20BetsToTeam1[erc20][msg.sender] += amount;
    }

    NewBetERC20(forTeam, msg.sender, amount, erc20);
  }

  function withdraw()
    afterTimestamp(timestampMatchEnd)
    matchIsDecided() {
    uint idx;
    if (betState == BET_STATES.DRAW) {
      msg.sender.transfer(collectOriginalBet());
      for (idx = 0; idx < validERC20.length; ++idx) {
        uint amount = collectOriginalBetERC20(validERC20[idx]);
        if (amount > 0) {
          ERC20 erc20Contract = ERC20(validERC20[idx]);
          require(erc20Contract.transfer(msg.sender, amount));
        }
      }
    }
    else {
      collectProfit();
      for (idx = 0; idx < validERC20.length; ++idx) {
        collectProfitERC20(validERC20[idx]);
      }
    }
  }

  // Transfers the user's initial bet back
  function collectOriginalBet() internal returns(uint) {
    uint amount;
    if (betsToTeam0[msg.sender] > 0) {
      amount = betsToTeam0[msg.sender];
      betsToTeam0[msg.sender] = 0;
      return amount;
    }
    else if (betsToTeam1[msg.sender] > 0) {
      amount = betsToTeam1[msg.sender];
      betsToTeam1[msg.sender] = 0;
      return amount;
    }
    else {
      return 0;
    }
  }

  // Transfers the user's initial bet back
  function collectOriginalBetERC20(address erc20) internal returns(uint) {
    uint amount;
    if (ERC20BetsToTeam0[erc20][msg.sender] > 0) {
      amount = ERC20BetsToTeam0[erc20][msg.sender];
      ERC20BetsToTeam0[erc20][msg.sender] = 0;
      return amount;
    }
    else if (ERC20BetsToTeam1[erc20][msg.sender] > 0) {
      amount = ERC20BetsToTeam1[erc20][msg.sender];
      ERC20BetsToTeam1[erc20][msg.sender] = 0;
      return amount;
    }
    else {
      return 0;
    }
  }

  function collectProfit() internal {
    uint bet = 0;
    uint sum = 0;
    uint profit = 0;

    if (betState == BET_STATES.TEAM_ZERO_WON && betsToTeam0[msg.sender] > 0) {
      bet = betsToTeam0[msg.sender];
      sum = team0BetSum;
      profit = team1BetSum;
    }
    else if (betState == BET_STATES.TEAM_ONE_WON && betsToTeam1[msg.sender] > 0) {
      bet = betsToTeam1[msg.sender];
      sum = team1BetSum;
      profit = team0BetSum;
    }
    else {
      return;
    }

    assert(bet <= sum);

    profit = computeProfit(bet, sum, profit);
    msg.sender.transfer(profit + collectOriginalBet());
  }

  function collectProfitERC20(address erc20) internal {
    uint bet = 0;
    uint sum = 0;
    uint profit = 0;

    if (betState == BET_STATES.TEAM_ZERO_WON && ERC20BetsToTeam0[erc20][msg.sender] > 0) {
      bet = ERC20BetsToTeam0[erc20][msg.sender];
      sum = ERC20Team0BetSum[erc20];
      profit = ERC20Team1BetSum[erc20];
    }
    else if (betState == BET_STATES.TEAM_ONE_WON && ERC20BetsToTeam1[erc20][msg.sender] > 0) {
      bet = ERC20BetsToTeam1[erc20][msg.sender];
      sum = ERC20Team1BetSum[erc20];
      profit = ERC20Team0BetSum[erc20];
    }
    else {
      return;
    }

    assert(bet <= sum);

    profit = computeProfit(bet, sum, profit);
    ERC20 erc20Contract = ERC20(erc20);
    require(erc20Contract.transfer(msg.sender, profit + collectOriginalBetERC20(erc20)));
  }

  // Compute the user's profit
  function computeProfit(uint bet, uint sum, uint profit) internal returns(uint) {
    // Approach one:
    // We might lose precision, but no overflow
    var senderPc = bet / sum;
    assert(senderPc >= 0 && senderPc <= 1);

    var senderProfit = senderPc * profit;
    assert(senderProfit <= profit);

    // Approach two:
    // Better precision, since multiplication is done first, but may overflow
    //uint sender_profit = (bet * profit) / sum;

    var mulTax = (senderProfit * TAX);
    require(mulTax >= senderProfit); // Overflow
    var tax = mulTax / 100;
    assert(tax <= senderProfit);

    var notaxProfit = senderProfit;
    senderProfit -= tax;
    assert(senderProfit <= notaxProfit);

    return senderProfit;

    // We can collect the bet tax by ourselves when the bet self-destructs
    // owner.transfer(tax);
    //msg.sender.transfer(senderProfit + collectOriginalBet());
  }

  /* After the arbiter deadline and before the self-destruct
   * deadline, anyone can set the bet state to DRAW.
   * this is in the unlikely event if the arbiter don't
   * decide in time, every one can collect the funds.
  */
  function close()
    afterTimestamp(timestampArbiterDeadline)
    beforeTimestamp(timestampSelfDestructDeadline) {
    betState = BET_STATES.DRAW;
  }

  /* Selfdestructs the bet and return what it has in the account
   * as a fee to the bet's owner.
   */
  function terminate()
    afterTimestamp(timestampSelfDestructDeadline) {
    selfdestruct(owner);
  }

  /* Fallback just throws now
   * Can do something, maybe increase the value of both pools
  */
  function () { require(false); }
}


cosmetic changes to BurnableToken

cosmetic changes to BurnableToken

pragma solidity ^0.4.13;

import './StandardToken.sol';

/**
 * @title Burnable Token
 * @dev Token that can be irreversibly burned (destroyed).
 */
contract BurnableToken is StandardToken {

    event Burn(address indexed burner, uint256 value);

    /**
     * @dev Burns a specific amount of tokens.
     * @param _value The amount of token to be burned.
     */
    function burn(uint256 _value) public {
        require(_value > 0);

        address burner = msg.sender;
        balances[burner] = balances[burner].sub(_value);
        totalSupply = totalSupply.sub(_value);
        Burn(burner, _value);
    }
}

pragma solidity ^0.4.13;

import './StandardToken.sol';

/**
 * @title Burnable Token
 * @dev Token that can be irreversibly burned (destroyed).
 */
contract BurnableToken is StandardToken {

    /**
     * @dev Burns a specific amount of tokens.
     * @param _value The amount of token to be burned.
     */
    function burn(uint _value)
        public
    {
        require(_value > 0);

        address burner = msg.sender;
        balances[burner] = balances[burner].sub(_value);
        totalSupply = totalSupply.sub(_value);
        Burn(burner, _value);
    }

    event Burn(address indexed burner, uint256 value);
}


added safe add for integers to ensure they dont wrap

/*
    Copyright 2017 Phillip A. Elsasser

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

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

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

// TODO BUILD TEST!
/// @title Math function library with overflow protection inspired by Open Zeppelin
library MathLib {

    int256 constant INT256_MIN = int256((uint256(1) << 255));
    int256 constant INT256_MAX = int256(~((uint256(1) << 255)));

    function multiply(uint256 a, uint256 b) pure internal returns (uint256) {
        uint256 c = a * b;
        assert(a == 0 || c / a == b);
        return c;
    }

    function subtract(uint256 a, uint256 b) pure internal returns (uint256) {
        assert(b <= a);
        return a - b;
    }

    function add(uint256 a, uint256 b) pure internal returns (uint256) {
        uint256 c = a + b;
        assert(c >= a);
        return c;
    }

    /// @notice safely adds to signed integers ensuring that no wrap occurs
    /// @param a
    /// @param b
    function add(int256 a, int256 b) pure internal returns (int256) {
        int256 c = a + b;
        if(!isSameSign(a, b)) { // result will always be smaller than current value, no wrap possible
            return c;
        }

        if(a >= 0) { // a is positive, b must be less than MAX - a to prevent wrap
            assert(b <= INT256_MAX - a);
        } else { // a is negative, b must be greater than MIN - a to prevent wrap
            assert(b >= INT256_MIN - a);
        }
        return c;
    }

    /// @param a integer to determine sign of
    /// @return int8 sign of original value, either +1,0,-1
    function sign(int a) pure internal returns (int8) {
        if(a > 0) {
            return 1;
        } else if (a < 0) {
            return -1;
        }
        return 0;
    }

    /// @param a integer to compare to b
    /// @param b integer to compare to a
    /// @return bool true if a and b are the same sign (+/-)
    function isSameSign(int a, int b) pure internal returns (bool) {
        return ( a == b || a * b > 0);
    }

    /// @param a integer to determine absolute value of
    /// @return uint non signed representation of a
    function abs(int a) pure internal returns (uint) {
        if(a < 0) {
            return uint(-a);
        }
        else {
            return uint(a);
        }
    }

}

/*
    Copyright 2017 Phillip A. Elsasser

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

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

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

// TODO BUILD TEST!
/// @title Math function library with overflow protection inspired by Open Zeppelin
library MathLib {

    function multiply(uint256 a, uint256 b) pure internal returns (uint256) {
        uint256 c = a * b;
        assert(a == 0 || c / a == b);
        return c;
    }

    function subtract(uint256 a, uint256 b) pure internal returns (uint256) {
        assert(b <= a);
        return a - b;
    }

    function add(uint256 a, uint256 b) pure internal returns (uint256) {
        uint256 c = a + b;
        assert(c >= a);
        return c;
    }

    /// @param a integer to determine sign of
    /// @return int8 sign of original value, either +1,0,-1
    function sign(int a) pure internal returns (int8) {
        if(a > 0) {
            return 1;
        } else if (a < 0) {
            return -1;
        }
        return 0;
    }

    /// @param a integer to compare to b
    /// @param b integer to compare to a
    /// @return bool true if a and b are the same sign (+/-)
    function isSameSign(int a, int b) pure internal returns (bool) {
        return ( a == b || a * b > 0);
    }

    /// @param a integer to determine absolute value of
    /// @return uint non signed representation of a
    function abs(int a) pure internal returns (uint) {
        if(a < 0) {
            return uint(-a);
        }
        else {
            return uint(a);
        }
    }

}