fix minor syntax

fix minor syntax

pragma solidity ^0.4.11;
import "./StandardToken.sol";
import "./PLCRVoting.sol";

/*
=======
 TO DO
=======

implement events
refactor & wrap check & transfer

*/

contract Registry {

    /*
     * Storage
     */

    //Registry storage
    StandardToken public token;
    PLCRVoting public voting;
    mapping(bytes32 => Publisher) public whitelist; //domainHash => Publisher struct
    mapping(bytes32 => Application) public appPool; //holds applications for both domain and parameter appPool
    mapping(bytes32 => Params) public paramSnapshots;
    mapping(uint => VoteInfo) public pollInfo; // holds information on individual polls
    mapping(address => mapping(uint => bool)) public voterInfo; // holds information on voters' token claims
    string domain;
    //Parameter storage
    mapping(bytes32 => uint) public Parameters;
    mapping(uint => bytes32) public idToHash;
    string parameter;
    uint value;

    struct Publisher {
        address owner;
        uint expTime;
        uint deposit;

        uint nextExpTime; //
        uint prevDeposit; // total withdrawable amount
        uint nextDeposit; //
        bool renewal;
    }

    struct Application {
        address owner;
        bool challenged;
        uint challengeTime; //End of challenge period
        address challenger;
        string domain;

        //for parameter changes
        string parameter;
        uint value;
    }

    struct Params {
        // parameters concerning the whitelist and application pool
        uint minDeposit;
        uint challengeLen;
        uint registryLen;

        // parameters to be passed into the voting contract
        uint commitVoteLen;
        uint revealVoteLen;
        uint majority;

        // parameter representing the scale of how token rewards are distributed
        uint dispensationPct;
    }

    struct VoteInfo {
        // if the vote has been processed
        bool processed;
        // amount of leftover tokens available for winning party to claim
        // (a byproduct of needing to floor the distributed tokens to voters)
        uint256 remainder;
        address claimer;
    }

    // constant used to help represent doubles as ints
    uint256 constant private MULTIPLIER = 10 ** 18;

    /*
     * Constructor
     */
    /// @param _minDeposit      application & challenger deposit amounts
    /// @param _challengeLen    duration of the challenge period
    /// @param _registryLen     duration of a registration’s validity
    /// @param _commitVoteLen   duration of the commit period in token votes
    /// @param _revealVoteLen   duration of reveal period in token votes
    /// @param _dispensationPct percentage of forfeited deposit distributed to winning party; uint between 0 and 100
    /// @param _majority        percentage of votes that constitutes the majority; uint between 0 and 100

    function Registry(address _token,
        address _voting,
       uint _minDeposit,
       uint _challengeLen,
       uint _registryLen,
       uint _commitVoteLen,
       uint _revealVoteLen,
       uint _dispensationPct,
       uint _majority) {

       token = StandardToken(_token);
       voting = PLCRVoting(_voting);
       // initialize values
       Parameters[sha3("minDeposit")]        = _minDeposit;
       Parameters[sha3("challengeLen")]      = _challengeLen;
       Parameters[sha3("registryLen")]       = _registryLen;
       Parameters[sha3("commitVoteLen")]     = _commitVoteLen;
       Parameters[sha3("revealVoteLen")]     = _revealVoteLen;
       Parameters[sha3("dispensationPct")]   = _dispensationPct;
       Parameters[sha3("majority")]          = _majority;
    }

    // called by an applicant to add to application pool on success
    function apply(string _domain) public {
        bytes32 domainHash = sha3(_domain);
        // must be a new member of the whitelist
        require(whitelist[domainHash].owner == 0); //not on whitelist
        require(appPool[domainHash].owner == 0); //not in appPool
        // initialize with the current values of all parameters
        initializeSnapshot(domainHash);
        initApplication(domainHash, msg.sender);
        appPool[domainHash].domain = _domain;
    }

    // helper function to apply() and proposeUpdate()
    // obtain deposit from applicant and initialize challenge end time and owner
    function initApplication(bytes32 _hash, address _applicant) private {
        require(appPool[_hash].owner == 0); // prevent repeat applications

        // applicant must pay the current value of minDeposit
        uint deposit = paramSnapshots[_hash].minDeposit;
        require(token.transferFrom(_applicant, this, deposit));

        setAppAttr(_hash, _applicant);
    }

    //called by the owner of a domain on the whitelist
    //make necessary token transfers and initialize application for renewal in the appPool
    function renew (string _domain) {
        bytes32 domainHash = sha3(_domain);
        require(hasRenewal(domainHash) == false); //prevent duplicate renewals
        require(msg.sender == whitelist[domainHash].owner); // must be the owner of the domain
        uint minDeposit = get('minDeposit');
        uint lockedTok = whitelist[domainHash].deposit;
        uint unlockedTok = whitelist[domainHash].prevDeposit;
        uint extraNeeded;

        if (lockedTok + unlockedTok >= minDeposit)
        {//existing total num tokens is sufficient
            if (lockedTok >= minDeposit)
            {// have enough locked tok, only take from currently locked deposit
                whitelist[domainHash].deposit = lockedTok - minDeposit;
            }
            else //lockedTok < minDeposit
            {// not enough locked tok, take entire locked deposit and part of unlocked
                extraNeeded = minDeposit - lockedTok;
                //update num unlocked tokens
                whitelist[domainHash].prevDeposit = unlockedTok - extraNeeded;
                whitelist[domainHash].deposit = 0;  // ************?*********
            }
        }
        else
        { //existing total num tokens is not sufficient, must send in more tokens
            extraNeeded = minDeposit - (lockedTok + unlockedTok);
            require(token.transferFrom(msg.sender, this, extraNeeded));
            whitelist[domainHash].deposit = 0;
            whitelist[domainHash].prevDeposit = 0;
        }
        //apply

        initializeSnapshot(domainHash);
        setAppAttr(domainHash, msg.sender);
        whitelist[domainHash].renewal = true;
    }

    //called by the owner of a domain on the whitelist
    //withdraw any number of unlocked tokens
    function claimDeposit(string _domain, uint _amount) public {
        bytes32 domainHash = sha3(_domain);
        uint unlockedTok = whitelist[domainHash].prevDeposit;
        require(msg.sender == whitelist[domainHash].owner);
        require(unlockedTok >= _amount);
        require(token.transfer(msg.sender, _amount));
        whitelist[domainHash].prevDeposit = unlockedTok - _amount;
    }

    //called by the owner of a domain on the whitelist
    //renew the domain on the whitelist and allow additional renewals
    function activateRenewal(string _domain) public {
        bytes32 _hash = sha3(_domain);
        if (hasRenewal(_hash) && whitelist[_hash].expTime <= now)
        {
            whitelist[_hash].expTime = whitelist[_hash].nextExpTime;
            whitelist[_hash].prevDeposit += whitelist[_hash].deposit;
            whitelist[_hash].deposit = whitelist[_hash].nextDeposit;
            whitelist[_hash].renewal = false;
        }
    }

    // called by any adtoken holder to challenge an application to the whitelist
    // initialize vote to accept/reject a domain to the registry
    function challengeApplication(string _domain) public returns(uint) {
        bytes32 domainHash = sha3(_domain);
        challenge(domainHash, msg.sender);
        // start a vote
        uint pollID = callVote(_domain
        ,paramSnapshots[domainHash].majority
        ,paramSnapshots[domainHash].commitVoteLen
        ,paramSnapshots[domainHash].revealVoteLen);
        idToHash[pollID] = domainHash;
        return pollID;
    }

    // helper function to challengeApplication() and challengeProposal()
    function challenge(bytes32 _hash, address _challenger) private {
        // check that registry can take sufficient amount of tokens from the challenger
        uint deposit = paramSnapshots[_hash].minDeposit;
        require(token.allowance(_challenger, this) >= deposit);
        token.transferFrom(_challenger, this, deposit);

        // prevent someone from challenging an unintialized application, rechallenging,
        // or challenging after the challenge period has ended
        require(appPool[_hash].owner != 0);
        require(appPool[_hash].challenged == false);
        require(appPool[_hash].challengeTime > now);

        // update the application's status
        appPool[_hash].challenged = true;
        appPool[_hash].challenger = _challenger;
    }

    // helper function to the challenge() function. Initializes a vote through the voting contract
    // returns a poll id
    function callVote(string _proposalString, uint _majority, uint _commitVoteLen,
        uint _revealVoteLen) private returns (uint) {
        // event that vote has started
        uint pollID = voting.startPoll( _proposalString, _majority, _commitVoteLen,  _revealVoteLen);
        return pollID;
    }

    // a one-time function for each completed vote
    // if domain won: domain is moved to the whitelist and applicant is rewarded tokens, return true
    // if domain lost: challenger is rewarded tokens, return false
    function processResult(uint _pollID) returns(bool)
    {
        bytes32 domainHash = idToHash[_pollID];
        require(isDomainApp(domainHash));  // processing parameter hash this way is unintended behavior
        require(pollInfo[_pollID].processed == false);
        // ensures the result cannot be processed again
        pollInfo[_pollID].processed = true;

        if (voting.isPassed(_pollID)) {
            // add to registry
            add(domainHash, appPool[domainHash].owner);
            pollInfo[_pollID].claimer = appPool[domainHash].owner;
            // give tokens to applicant based on dist and total tokens
            giveWinnerReward(domainHash, appPool[domainHash].owner);
            // uninitialize application
            delete appPool[domainHash].owner;
            return true;
        }
        else {
            pollInfo[_pollID].claimer = appPool[domainHash].challenger;
            giveWinnerReward(domainHash, appPool[domainHash].challenger);
            token.transfer(appPool[domainHash].challenger, paramSnapshots[domainHash].minDeposit);
            delete appPool[domainHash].owner;
            return false;
        }
    }

    // helper function to processResult()
    // reward a portion of minDeposit to _address
    // reward extra token to _address if dispensationPct does not divide minDeposit evenly
    function giveWinnerReward(bytes32 _hash, address _address) private {
        uint256 minDeposit = paramSnapshots[_hash].minDeposit;
        uint256 dispensationPct = paramSnapshots[_hash].dispensationPct;
        uint256 rewardTokens = minDeposit * (dispensationPct) / 100;
        if ((minDeposit * dispensationPct) % 100 != 0) {
            rewardTokens++;
        }
        require(token.transfer(_address, rewardTokens));
    }

    // called by each voter to claim their reward for each completed vote
    function claimReward(uint _pollID, uint _salt) {
        // ensure voter has not already claimed tokens
        require(voterInfo[msg.sender][_pollID] == false);
        uint reward = giveTokens(_pollID, _salt, msg.sender);
        // ensures a voter cannot claim tokens again
        require(token.transfer(msg.sender, reward));
        voterInfo[msg.sender][_pollID] = true;
    }

    // number of tokens person used to vote / total number of tokens for winning side
    // scale using distribution number, give the tokens
    function giveTokens(uint _pollID, uint _salt, address _voter) private returns(uint) {
        bytes32 hash = idToHash[_pollID];
        uint256 minDeposit = paramSnapshots[hash].minDeposit;
        uint256 dispensationPct = paramSnapshots[hash].dispensationPct;
        uint256 totalTokens = voting.getTotalNumberOfTokensForWinningOption(_pollID);
        uint256 voterTokens = voting.getNumPassingTokens(_pollID, _salt, _voter);

        uint256 rewardTokens = minDeposit * (100 - dispensationPct)*MULTIPLIER / 100;
        //what happens if expression does not divide evenly
        uint256 numerator = voterTokens * rewardTokens;
        uint256 denominator = totalTokens * MULTIPLIER;
        uint256 remainder = numerator % denominator;

        // save remainder tokens in the form of decimal numbers with 18 places represented
        // as a uint256
        pollInfo[_pollID].remainder += remainder;

        return numerator / denominator;
    }

    function claimExtraReward(uint _pollID) {
        uint256 totalTokens = voting.getTotalNumberOfTokensForWinningOption(_pollID);
        uint256 reward = pollInfo[_pollID].remainder / (MULTIPLIER);
        reward = reward / totalTokens;
        pollInfo[_pollID].remainder = pollInfo[_pollID].remainder - reward * MULTIPLIER;
        token.transfer(pollInfo[_pollID].claimer, reward);
    }

    // called to move an applying domain to the whitelist
    // iff the domain's challenge period has passed without a challenge
    function moveToRegistry(string _domain) public {
        bytes32 domainHash = sha3(_domain);
        require(appPool[domainHash].challengeTime < now);
        require(appPool[domainHash].challenged == false);
        // prevents moving a domain to the registry without ever applying
        require(appPool[domainHash].owner != 0);
        // prevent applicant from moving to registry multiple times
        add(domainHash, appPool[domainHash].owner);
        delete appPool[domainHash].owner; //remove from appPool
    }

    // ISSUE WITH OVERLAP

    // private function to add a domain name to the whitelist
    function add(bytes32 _domainHash, address _owner) private {
        uint expiration = paramSnapshots[_domainHash].registryLen;
        if (whitelist[_domainHash].renewal == true)
        {
            whitelist[_domainHash].nextExpTime = whitelist[_domainHash].expTime + expiration;
            whitelist[_domainHash].nextDeposit = paramSnapshots[_domainHash].minDeposit;
        }
        else
        {
            whitelist[_domainHash].expTime = now + expiration;
            whitelist[_domainHash].deposit = paramSnapshots[_domainHash].minDeposit;
        }
        whitelist[_domainHash].owner = _owner;
    }

    /*
     * Helper Functions
     */

    // STATIC

    // returns true if a renewal has been initialized
    function hasRenewal(bytes32 _hash) private constant returns (bool) {
        return whitelist[_hash].renewal;
    }

    // returns true if Application is for domain and not parameter
    function isDomainApp(bytes32 _hash) private constant returns(bool){
        return bytes(appPool[_hash].parameter).length == 0;  // checks if param string is initialized
    }

    // returns true if a domain name is in the whitelist and unexpired
    // provided for the user to verify the status of their domain
    function isInRegistry(string _domain) public constant returns (bool) {
        bytes32 domainHash = sha3(_domain);
        return whitelist[domainHash].expTime > now;
    }

    // DYNAMIC

    // Initialize snapshot of parameters for each application
    function initializeSnapshot(bytes32 _hash) private {
        initializeSnapshotParam(_hash);  // maybe put the two together
        paramSnapshots[_hash].registryLen = get("registryLen");
    }

    //set the challenge end time and the owner of an application
    function setAppAttr(bytes32 _hash, address _applicant) private {
        delete appPool[_hash].challenged;
        appPool[_hash].challengeTime = now + paramSnapshots[_hash].challengeLen;
        appPool[_hash].owner = _applicant;
    }

/*****************************************************************************/

    //called by a user who wishes to change a parameter
    //initializes a proposal to change a parameter
    function proposeUpdate(string _parameter, uint _value) public {
        //require(_parameter != "");
        bytes32 parameterHash = sha3(_parameter, _value);
        // initialize application with a with the current values of all parameters
        initializeSnapshotParam(parameterHash);
        initApplication(parameterHash, msg.sender);
        appPool[parameterHash].parameter = _parameter;
        appPool[parameterHash].value = _value;
    }

    //called by user who wishes to reject a proposal
    //initializes a vote to accept/reject the param change proposal
    function challengeProposal(string _parameter, uint _value) public {
        bytes32 parameterHash = sha3(_parameter, _value);
        challenge(parameterHash, msg.sender);
        // start a vote
        uint pollID = callVote(_parameter
        ,paramSnapshots[parameterHash].majority
        ,paramSnapshots[parameterHash].commitVoteLen
        ,paramSnapshots[parameterHash].revealVoteLen);
        idToHash[pollID] = parameterHash;
    }

    // called to change parameter
    // iff the proposal's challenge period has passed without a challenge
    function setParams(string _parameter, uint _value) public {
        bytes32 parameterHash = sha3(_parameter, _value);
        require(appPool[parameterHash].challengeTime < now);
        require(appPool[parameterHash].challenged == false);
        // prevents moving a domain to the registry without ever applying
        require(appPool[parameterHash].owner != 0);
        // prevent applicant from moving to registry multiple times
        Parameters[sha3(_parameter)] = _value;
        delete appPool[parameterHash].owner;
    }

    // a one-time function for each completed vote
    // if proposal won: new parameter value is set, and applicant is rewarded tokens, return true
    // if prospsal lost: challenger is rewarded tokens, return false
    function processProposal(uint _pollID) returns(bool)
    {
        require(pollInfo[_pollID].processed == false);
        bytes32 parameterHash = idToHash[_pollID];
        parameter = appPool[parameterHash].parameter;
        value = appPool[parameterHash].value;
        delete appPool[parameterHash].owner;

        if (voting.isPassed(_pollID)) {
            pollInfo[_pollID].claimer = appPool[parameterHash].owner;
            // setting the value of parameter
            Parameters[sha3(parameter)] = value;
            // give tokens to applicant based on dist and total tokens IMPLEMENT
            giveWinnerReward(parameterHash, appPool[parameterHash].owner);
            token.transfer(appPool[parameterHash].owner, paramSnapshots[parameterHash].minDeposit);
            return true;
        }
        else {
            pollInfo[_pollID].claimer = appPool[parameterHash].challenger;
            // give tokens to challenger based on dist and total tokens
            giveWinnerReward(parameterHash, appPool[parameterHash].challenger);
            token.transfer(appPool[parameterHash].challenger, paramSnapshots[parameterHash].minDeposit);
            return false;
        }
        // ensures the result cannot be processed again
        pollInfo[_pollID].processed = true;
    }

     // private function to initialize a snapshot of parameters for each proposal
     function initializeSnapshotParam(bytes32 _hash) private {
        paramSnapshots[_hash].minDeposit = get("minDeposit");
        paramSnapshots[_hash].challengeLen = get("challengeLen");
        paramSnapshots[_hash].commitVoteLen = get("commitVoteLen");
        paramSnapshots[_hash].revealVoteLen = get("revealVoteLen");
        paramSnapshots[_hash].majority = get("majority");
        paramSnapshots[_hash].dispensationPct = get("dispensationPct");
    }

    // interface for retrieving config parameter from hashmapping
    /// @param _keyword key for hashmap (only useful when keyword matches variable name)
    function get(string _keyword) public constant returns (uint) {
       return Parameters[sha3(_keyword)];
    }

/*****************************************************************************/

    // Helper Functions
     // FOR TESTING
    function toHash(string _domain) returns (bytes32){
        return sha3(_domain);
    }
    function toParameterHash(string _parameter, uint _value) returns (bytes32){
        return sha3(_parameter, _value);
    }
    function getCurrentTime() returns (uint){
        return now;
    }

}

pragma solidity ^0.4.11;
import "./StandardToken.sol";
import "./PLCRVoting.sol";

/*
=======
 TO DO
=======

implement events
refactor & wrap check & transfer

*/

contract Registry {

    /*
     * Storage
     */

    //Registry storage
    StandardToken public token;
    PLCRVoting public voting;
    mapping(bytes32 => Publisher) public whitelist; //domainHash => Publisher struct
    mapping(bytes32 => Application) public appPool; //holds applications for both domain and parameter appPool
    mapping(bytes32 => Params) public paramSnapshots;
    mapping(uint => VoteInfo) public pollInfo; // holds information on individual polls
    mapping(address => mapping(uint => bool)) public voterInfo; // holds information on voters' token claims
    string domain;
    //Parameter storage
    mapping(bytes32 => uint) public Parameters;
    mapping(uint => bytes32) public idToHash;
    string parameter;
    uint value;

    struct Publisher {
        address owner;
        uint expTime;
        uint deposit;

        uint nextExpTime; //
        uint prevDeposit; // total withdrawable amount
        uint nextDeposit; //
        bool renewal;
    }

    struct Application {
        address owner;
        bool challenged;
        uint challengeTime; //End of challenge period
        address challenger;
        string domain;

        //for parameter changes
        string parameter;
        uint value;
    }

    struct Params {
        // parameters concerning the whitelist and application pool
        uint minDeposit;
        uint challengeLen;
        uint registryLen;

        // parameters to be passed into the voting contract
        uint commitVoteLen;
        uint revealVoteLen;
        uint majority;

        // parameter representing the scale of how token rewards are distributed
        uint dispensationPct;
    }

    struct VoteInfo {
        // if the vote has been processed
        bool processed;
        // amount of leftover tokens available for winning party to claim
        // (a byproduct of needing to floor the distributed tokens to voters)
        uint256 remainder;
        address claimer;
    }

    // constant used to help represent doubles as ints
    uint256 constant private MULTIPLIER = 10 ** 18;

    /*
     * Constructor
     */
    /// @param _minDeposit      application & challenger deposit amounts
    /// @param _challengeLen    duration of the challenge period
    /// @param _registryLen     duration of a registration’s validity
    /// @param _commitVoteLen   duration of the commit period in token votes
    /// @param _revealVoteLen   duration of reveal period in token votes
    /// @param _dispensationPct percentage of forfeited deposit distributed to winning party; uint between 0 and 100
    /// @param _majority        percentage of votes that constitutes the majority; uint between 0 and 100

    function Registry(address _token,
        address _voting,
       uint _minDeposit,
       uint _challengeLen,
       uint _registryLen,
       uint _commitVoteLen,
       uint _revealVoteLen,
       uint _dispensationPct,
       uint _majority) {

       token = StandardToken(_token);
       voting = PLCRVoting(_voting);
       // initialize values
       Parameters[sha3("minDeposit")]        = _minDeposit;
       Parameters[sha3("challengeLen")]      = _challengeLen;
       Parameters[sha3("registryLen")]       = _registryLen;
       Parameters[sha3("commitVoteLen")]     = _commitVoteLen;
       Parameters[sha3("revealVoteLen")]     = _revealVoteLen;
       Parameters[sha3("dispensationPct")]   = _dispensationPct;
       Parameters[sha3("majority")]          = _majority;
    }

    // called by an applicant to add to application pool on success
    function apply(string _domain) public {
        bytes32 domainHash = sha3(_domain);
        // must be a new member of the whitelist
        require(whitelist[domainHash].owner == 0); //not on whitelist
        require(appPool[domainHash].owner == 0); //not in appPool
        // initialize with the current values of all parameters
        initializeSnapshot(domainHash);
        initApplication(domainHash, msg.sender);
        appPool[domainHash].domain = _domain;
    }

    // helper function to apply() and proposeUpdate()
    // obtain deposit from applicant and initialize challenge end time and owner
    function initApplication(bytes32 _hash, address _applicant) private {
        require(appPool[_hash].owner == 0); // prevent repeat applications

        // applicant must pay the current value of minDeposit
        uint deposit = paramSnapshots[_hash].minDeposit;
        require(token.transferFrom(_applicant, this, deposit));

        setAppAttr(_hash, _applicant);
    }

    //called by the owner of a domain on the whitelist
    //make necessary token transfers and initialize application for renewal in the appPool
    function renew (string _domain) {
        bytes32 domainHash = sha3(_domain);
        require(hasRenewal(domainHash) == false); //prevent duplicate renewals
        require(msg.sender == whitelist[domainHash].owner); // must be the owner of the domain
        uint minDeposit = get('minDeposit');
        uint lockedTok = whitelist[domainHash].deposit;
        uint unlockedTok = whitelist[domainHash].prevDeposit;
        uint extraNeeded;

        if (lockedTok + unlockedTok >= minDeposit)
        {//existing total num tokens is sufficient
            if (lockedTok >= minDeposit)
            {// have enough locked tok, only take from currently locked deposit
                whitelist[domainHash].deposit = lockedTok - minDeposit;
            }
            else //lockedTok < minDeposit
            {// not enough locked tok, take entire locked deposit and part of unlocked
                extraNeeded = minDeposit - lockedTok;
                //update num unlocked tokens
                whitelist[domainHash].prevDeposit = unlockedTok - extraNeeded;
                whitelist[domainHash].deposit = 0;  // ************?*********
            }
        }
        else
        { //existing total num tokens is not sufficient, must send in more tokens
            extraNeeded = minDeposit - (lockedTok + unlockedTok);
            require(token.transferFrom(msg.sender, this, extraNeeded));
            whitelist[domainHash].deposit = 0;
            whitelist[domainHash].prevDeposit = 0;
        }
        //apply

        initializeSnapshot(domainHash);
        setAppAttr(domainHash, msg.sender);
        whitelist[domainHash].renewal = true;
    }

    //called by the owner of a domain on the whitelist
    //withdraw any number of unlocked tokens
    function claimDeposit(string _domain, uint _amount) public {
        bytes32 domainHash = sha3(_domain);
        uint unlockedTok = whitelist[domainHash].prevDeposit;
        require(msg.sender == whitelist[domainHash].owner);
        require(unlockedTok >= _amount);
        require(token.transfer(msg.sender, _amount));
        whitelist[domainHash].prevDeposit = unlockedTok - _amount;
    }

    //called by the owner of a domain on the whitelist
    //renew the domain on the whitelist and allow additional renewals
    function activateRenewal(string _domain) public {
        bytes32 _hash = sha3(_domain);
        if (hasRenewal(_hash) && whitelist[_hash].expTime <= now)
        {
            whitelist[_hash].expTime = whitelist[_hash].nextExpTime;
            whitelist[_hash].prevDeposit += whitelist[_hash].deposit;
            whitelist[_hash].deposit = whitelist[_hash].nextDeposit;
            whitelist[_hash].renewal = false;
        }
    }

    // called by any adtoken holder to challenge an application to the whitelist
    // initialize vote to accept/reject a domain to the registry
    function challengeApplication(string _domain) public returns(uint) {
        bytes32 domainHash = sha3(_domain);
        challenge(domainHash, msg.sender);
        // start a vote
        uint pollID = callVote(_domain
        ,paramSnapshots[domainHash].majority
        ,paramSnapshots[domainHash].commitVoteLen
        ,paramSnapshots[domainHash].revealVoteLen);
        idToHash[pollID] = domainHash;
        return pollID;
    }

    // helper function to challengeApplication() and challengeProposal()
    function challenge(bytes32 _hash, address _challenger) private {
        // check that registry can take sufficient amount of tokens from the challenger
        uint deposit = paramSnapshots[_hash].minDeposit;
        require(token.allowance(_challenger, this) >= deposit);
        token.transferFrom(_challenger, this, deposit);

        // prevent someone from challenging an unintialized application, rechallenging,
        // or challenging after the challenge period has ended
        require(appPool[_hash].owner != 0);
        require(appPool[_hash].challenged == false);
        require(appPool[_hash].challengeTime > now);

        // update the application's status
        appPool[_hash].challenged = true;
        appPool[_hash].challenger = _challenger;
    }

    // helper function to the challenge() function. Initializes a vote through the voting contract
    // returns a poll id
    function callVote(string _proposalString, uint _majority, uint _commitVoteLen,
        uint _revealVoteLen) private returns (uint) {
        // event that vote has started
        uint pollID = voting.startPoll( _proposalString, _majority, _commitVoteLen,  _revealVoteLen);
        return pollID;
    }

    // a one-time function for each completed vote
    // if domain won: domain is moved to the whitelist and applicant is rewarded tokens, return true
    // if domain lost: challenger is rewarded tokens, return false
    function processResult(uint _pollID) returns(bool)
    {
        bytes32 domainHash = idToHash[_pollID];
        require(isDomainApp(domainHash));  // processing parameter hash this way is unintended behavior
        require(pollInfo[_pollID].processed == false);
        // ensures the result cannot be processed again
        pollInfo[_pollID].processed = true;

        if (voting.isPassed(_pollID)) {
            // add to registry
            add(domainHash, appPool[domainHash].owner);
            pollInfo[_pollID].claimer = appPool[domainHash].owner;
            // give tokens to applicant based on dist and total tokens
            giveWinnerReward(domainHash, appPool[domainHash].owner);
            // uninitialize application
            delete appPool[domainHash].owner;
            return true;
        }
        else {
            pollInfo[_pollID].claimer = appPool[domainHash].challenger;
            giveWinnerReward(domainHash, appPool[domainHash].challenger);
            token.transfer(appPool[domainHash].challenger, paramSnapshots[domainHash].minDeposit);
            delete appPool[domainHash].owner;
            return false;
        }
    }

    // helper function to processResult()
    // reward a portion of minDeposit to _address
    // reward extra token to _address if dispensationPct does not divide minDeposit evenly
    function giveWinnerReward(bytes32 _hash, address _address) private {
        uint256 minDeposit = paramSnapshots[_hash].minDeposit;
        uint256 dispensationPct = paramSnapshots[_hash].dispensationPct;
        uint256 rewardTokens = minDeposit * (dispensationPct) / 100;
        if ((minDeposit * dispensationPct) % 100 != 0) {
            rewardTokens++;
        }
        require(token.transfer(_address, rewardTokens));
    }

    // called by each voter to claim their reward for each completed vote
    function claimReward(uint _pollID, uint _salt) {
        // ensure voter has not already claimed tokens
        require(voterInfo[msg.sender][_pollID] == false);
        uint reward = giveTokens(_pollID, _salt, msg.sender);
        // ensures a voter cannot claim tokens again
        require(token.transfer(msg.sender, reward));
        voterInfo[msg.sender][_pollID] = true;
    }

    // number of tokens person used to vote / total number of tokens for winning side
    // scale using distribution number, give the tokens
    function giveTokens(uint _pollID, uint _salt, address _voter) private returns(uint) {
        bytes32 hash = idToHash[_pollID];
        uint256 minDeposit = paramSnapshots[hash].minDeposit;
        uint256 dispensationPct = paramSnapshots[hash].dispensationPct;
        uint256 totalTokens = voting.getTotalNumberOfTokensForWinningOption(_pollID);
        uint256 voterTokens = voting.getNumPassingTokens(_pollID, _salt, _voter);

        uint256 rewardTokens = minDeposit * (100 - dispensationPct)*MULTIPLIER / 100;
        //what happens if expression does not divide evenly
        uint256 numerator = voterTokens * rewardTokens;
        uint256 denominator = totalTokens * MULTIPLIER;
        uint256 remainder = numerator % denominator;

        // save remainder tokens in the form of decimal numbers with 18 places represented
        // as a uint256
        pollInfo[_pollID].remainder += remainder;

        return numerator / denominator;
    }

    function claimExtraReward(uint _pollID) {
        uint256 totalTokens = voting.getTotalNumberOfTokensForWinningOption(_pollID);
        uint256 reward = pollInfo[_pollID].remainder / (MULTIPLIER);
        reward = reward / totalTokens;
        pollInfo[_pollID].remainder = pollInfo[_pollID].remainder - reward * MULTIPLIER;
        token.transfer(pollInfo[_pollID].claimer, reward);
    }

    // called to move an applying domain to the whitelist
    // iff the domain's challenge period has passed without a challenge
    function moveToRegistry(string _domain) public {
        bytes32 domainHash = sha3(_domain);
        require(appPool[domainHash].challengeTime < now);
        require(appPool[domainHash].challenged == false);
        // prevents moving a domain to the registry without ever applying
        require(appPool[domainHash].owner != 0);
        // prevent applicant from moving to registry multiple times
        add(domainHash, appPool[domainHash].owner);
        delete appPool[domainHash].owner; //remove from appPool
    }

    // ISSUE WITH OVERLAP

    // private function to add a domain name to the whitelist
    function add(bytes32 _domainHash, address _owner) private {
        uint expiration = paramSnapshots[_domainHash].registryLen;
        if (whitelist[_domainHash].renewal == true)
        {
            whitelist[_domainHash].nextExpTime = whitelist[_domainHash].expTime + expiration;
            whitelist[_domainHash].nextDeposit = paramSnapshots[_domainHash].minDeposit;
        }
        else
        {
            whitelist[_domainHash].expTime = now + expiration;
            whitelist[_domainHash].deposit = paramSnapshots[_domainHash].minDeposit;
        }
        whitelist[_domainHash].owner = _owner;
    }

    /*
     * Helper Functions
     */

    // STATIC

    // returns true if a renewal has been initialized
    function hasRenewal(bytes32 _hash) private constant returns (bool) {
        return whitelist[_hash].renewal;
    }

    // returns true if Application is for domain and not parameter
    function isDomainApp(bytes32 _hash) private constant returns(bool){
        return bytes(appPool[_hash].parameter).length == 0;  // checks if param string is initialized
    }

    // returns true if a domain name is in the whitelist and unexpired
    // provided for the user to verify the status of their domain
    function isInRegistry(string _domain) public constant returns (bool) {
        bytes32 domainHash = sha3(_domain);
        return whitelist[domainHash].expTime > now;
    }

    // DYNAMIC

    // Initialize snapshot of parameters for each application
    function initializeSnapshot(bytes32 _hash) private {
        initializeSnapshotParam(_hash);  // maybe put the two together
        paramSnapshots[_hash].registryLen = get("registryLen");
    }

    //set the challenge end time and the owner of an application
    function setAppAttr(bytes32 _hash, address _applicant) private {
        delete appPool[domainHash].challenged;
        appPool[_hash].challengeTime = now + paramSnapshots[_hash].challengeLen;
        appPool[_hash].owner = _applicant;
    }

/*****************************************************************************/

    //called by a user who wishes to change a parameter
    //initializes a proposal to change a parameter
    function proposeUpdate(string _parameter, uint _value) public {
        //require(_parameter != "");
        bytes32 parameterHash = sha3(_parameter, _value);
        // initialize application with a with the current values of all parameters
        initializeSnapshotParam(parameterHash);
        initApplication(parameterHash, msg.sender);
        appPool[parameterHash].parameter = _parameter;
        appPool[parameterHash].value = _value;
    }

    //called by user who wishes to reject a proposal
    //initializes a vote to accept/reject the param change proposal
    function challengeProposal(string _parameter, uint _value) public {
        bytes32 parameterHash = sha3(_parameter, _value);
        challenge(parameterHash, msg.sender);
        // start a vote
        uint pollID = callVote(_parameter
        ,paramSnapshots[parameterHash].majority
        ,paramSnapshots[parameterHash].commitVoteLen
        ,paramSnapshots[parameterHash].revealVoteLen);
        idToHash[pollID] = parameterHash;
    }

    // called to change parameter
    // iff the proposal's challenge period has passed without a challenge
    function setParams(string _parameter, uint _value) public {
        bytes32 parameterHash = sha3(_parameter, _value);
        require(appPool[parameterHash].challengeTime < now);
        require(appPool[parameterHash].challenged == false);
        // prevents moving a domain to the registry without ever applying
        require(appPool[parameterHash].owner != 0);
        // prevent applicant from moving to registry multiple times
        Parameters[sha3(_parameter)] = _value;
        delete appPool[parameterHash].owner;
    }

    // a one-time function for each completed vote
    // if proposal won: new parameter value is set, and applicant is rewarded tokens, return true
    // if prospsal lost: challenger is rewarded tokens, return false
    function processProposal(uint _pollID) returns(bool)
    {
        require(pollInfo[_pollID].processed == false);
        bytes32 parameterHash = idToHash[_pollID];
        parameter = appPool[parameterHash].parameter;
        value = appPool[parameterHash].value;
        delete appPool[parameterHash].owner;

        if (voting.isPassed(_pollID)) {
            pollInfo[_pollID].claimer = appPool[parameterHash].owner;
            // setting the value of parameter
            Parameters[sha3(parameter)] = value;
            // give tokens to applicant based on dist and total tokens IMPLEMENT
            giveWinnerReward(parameterHash, appPool[parameterHash].owner);
            token.transfer(appPool[parameterHash].owner, paramSnapshots[parameterHash].minDeposit);
            return true;
        }
        else {
            pollInfo[_pollID].claimer = appPool[parameterHash].challenger;
            // give tokens to challenger based on dist and total tokens
            giveWinnerReward(parameterHash, appPool[parameterHash].challenger);
            token.transfer(appPool[parameterHash].challenger, paramSnapshots[parameterHash].minDeposit);
            return false;
        }
        // ensures the result cannot be processed again
        pollInfo[_pollID].processed = true;
    }

     // private function to initialize a snapshot of parameters for each proposal
     function initializeSnapshotParam(bytes32 _hash) private {
        paramSnapshots[_hash].minDeposit = get("minDeposit");
        paramSnapshots[_hash].challengeLen = get("challengeLen");
        paramSnapshots[_hash].commitVoteLen = get("commitVoteLen");
        paramSnapshots[_hash].revealVoteLen = get("revealVoteLen");
        paramSnapshots[_hash].majority = get("majority");
        paramSnapshots[_hash].dispensationPct = get("dispensationPct");
    }

    // interface for retrieving config parameter from hashmapping
    /// @param _keyword key for hashmap (only useful when keyword matches variable name)
    function get(string _keyword) public constant returns (uint) {
       return Parameters[sha3(_keyword)];
    }

/*****************************************************************************/

    // Helper Functions
     // FOR TESTING
    function toHash(string _domain) returns (bytes32){
        return sha3(_domain);
    }
    function toParameterHash(string _parameter, uint _value) returns (bytes32){
        return sha3(_parameter, _value);
    }
    function getCurrentTime() returns (uint){
        return now;
    }

}


[WIP]feat HealthNexus/DRS/contracts/: on chain

pragma solidity ^0.5.0;

import '../node_modules/openzeppelin-solidity/contracts/ownership/Ownable.sol';
import '../node_modules/openzeppelin-solidity/contracts/token/ERC20/ERC20.sol';

/**
* Health Decentralized Record Service (DRS)
* This contract enables creation of services and keys which can
* be managed, shared, traded, and sold using Health Cash (HLTH).
*
* These keys enable gatekeeper services and
* cryptographically secure data exchanges.
*/

contract HealthDRS is Ownable {

   address public latestContract = address(this);
   uint8 public version = 1;
   uint public minimumHold = 0;
   uint256 public balance = address(this).balance;

   struct Service {
       string url;
       address owner;
   }

   struct Key {
       address owner;
       bool canShare;
       bool canTrade;
       bool canSell;
       bytes32 service;
   }

   struct SalesOffer {
       address buyer;
       uint price;
       bool canSell;
   }

   mapping (bytes32 => Service) public services;
   bytes32[] public serviceList;

   mapping(bytes32 => Key) keys;
   bytes32[] public keyList;

   mapping(bytes32 => address[]) public owners;
   mapping(bytes32 => bytes32) public keyData;
   mapping(bytes32 => SalesOffer) public salesOffers;
   mapping(bytes32 => bytes32) public tradeOffers;

   event ServiceCreated(address indexed _owner, bytes32 indexed _service);
   event KeyCreated(address indexed _owner, bytes32 indexed _key);
   event KeySold(bytes32 _key, address indexed _seller, address indexed _buyer, uint _price);
   event KeysTraded(bytes32 indexed _key1, bytes32 indexed _key2);
   event Access(address indexed _owner, bytes32 indexed _from, bytes32 indexed _to, uint _time, string _data);
   event Message(address indexed _owner, bytes32 indexed _from, bytes32 indexed _to, uint _time, string _category, string _data);
   event Log(address indexed _owner, bytes32 indexed _from, uint _time, string _data);

   modifier validKey(bytes32 key) {
     require(keys[key].owner != address(0), "validKey() error");
     _;
   }

   modifier validService(bytes32 service) {
     require(services[service].owner != address(0), "validService() error");
     _;
   }

   modifier ownsKey(bytes32 key) {
       require(isKeyOwner(key, msg.sender), "ownsKey() error");
       _;
   }
   modifier ownsService(bytes32 service) {
       require(isServiceOwner(service, msg.sender), "ownsService() error");
       _;
   }

   modifier canSell(bytes32 key) {
     require(keys[key].canSell, "canSell() key can't be sold error");
     require(owners[key].length == 0, "canSell() key does not exist error");
     _;
   }

   modifier canTrade(bytes32 key) {
     require(keys[key].canTrade, "canTrade() keys[key].canTrade error");
     require(owners[key].length == 0, "canTrade() owners[key].length error");
     _;
   }

   modifier canShare(bytes32 key) {
     require(keys[key].canShare, "canShare() error");
     _;
   }

    // ensure account has currency
    // TODO Remove and remove all references
    modifier holdingCurrency(){
        require(address(this).balance >= minimumHold, "holdingCurrency() error");
        _;
    }

   //prevent accidentally sending/trapping ether
   function() external {
       revert("function() line 104 error");
   }

//   //require token specified at deployment
//   constructor(ERC20 _token) public {
//       token = _token;
//   }

   function isKeyOwner(bytes32 key, address account)
       public
       view
       validKey(key)
       returns (bool)
   {
       if (keys[key].owner == account) {
           return true;
       } else {
           if (keys[key].canShare) {
               for (uint i = 0; i < owners[key].length; i++) {
                   if (owners[key][i] == account) {
                       return true;
                   }
               }
           }
       }
       return false;
   }

   function isServiceOwner(bytes32 service, address account)
       public
       view
       validService(service)
       returns (bool)
   {
       if (services[service].owner == account) {
           return true;
       } else {
           for (uint i = 0; i < owners[service].length; i++) {
               if (owners[service][i] == account) {
                   return true;
               }
          }
       }
       return false;
   }

   function getUrl(bytes32 service)
       public
       view
       validService(service)
       returns (string memory)
   {
      return services[service].url;
   }

   function getUrlFromKey(bytes32 key)
       public
       view
       validKey(key)
       returns (string memory)
   {
       return services[keys[key].service].url;
   }

   function updateUrl(bytes32 service, string memory url)
       public
       ownsService(service)
   {
      services[service].url = url;
   }

   function getOwnersLength(bytes32 key)
       public
       view
       returns (uint256)
    {
        return owners[key].length;
    }

   //user must authorize this contract to spend Health Cash (HLTH)
   function authorizedToSpend() public view returns (uint) {
    //    return token.allowance(msg.sender, address(this));
   }

    //allow owner access to tokens erroneously transferred to this contract
   function recoverTokens(address payable _token, uint amount) public onlyOwner {
       _token.transfer(amount);
   }

//    function setHealthCashToken(ERC20 _token) public onlyOwner {
//        token = _token;
//    }

   function setLatestContract(address _contract) public onlyOwner {
       latestContract = _contract;
   }

//    function setMinimumHold(uint _minimumHold) public onlyOwner {
//        minimumHold = _minimumHold;
//    }

  /**
  * Create Services & Keys
  * Keys can also be issued to accounts
  */
   function createService(string memory url)
        public
        holdingCurrency()
   {
       bytes32 id = keccak256(abi.encode(msg.sender, url));
       require(services[id].owner == address(0), "createService() error"); //prevent overwriting
       services[id].owner = msg.sender;
       services[id].url = url;
       serviceList.push(id);
       emit ServiceCreated(msg.sender, id);
   }

   function createKey(bytes32 service)
       public
       ownsService(service)
       holdingCurrency()
   {
       issueKey(service, msg.sender);
   }

   function issueKey(bytes32 service, address issueTo)
       public
       ownsService(service)
       holdingCurrency()
   {
       bytes32 id = keccak256(abi.encode(service, issueTo, now));
       require(keys[id].owner == address(0), "issueKey() error");
       keys[id].owner = issueTo;
       keys[id].service = service;
       keyList.push(id);
       emit KeyCreated(issueTo, id);
   }

  /**
  * Share Services and Keys
  * allow owners to authorize other accounts
  * a service can disable sharing for their keys.
  * Can also unshare.
  */
   function shareKey(bytes32 key, address account)
       public
       ownsKey(key)
       canShare(key)
       holdingCurrency()
   {
       if (isKeyOwner(key, account) == false) {
           owners[key].push(account);
       }
   }

   function shareService(bytes32 service, address account)
       public
       ownsService(service)
   {
       if (isServiceOwner(service, account) == false) {
           owners[service].push(account);
       }
   }

   function unshareKey(bytes32 key, address account)
       public
       ownsKey(key)
       holdingCurrency()
   {
       for (uint i = 0; i < owners[key].length; i++) {
           if (owners[key][i] == account) {
               if (i != owners[key].length - 1) {
                   owners[key][i] = owners[key][owners[key].length - 1];
               }
               owners[key].length--;
               break;
           }
       }
   }

   function unshareService(bytes32 service, address account)
       public
       ownsService(service)
   {
       for (uint i = 0; i < owners[service].length; i++) {
           if (owners[service][i] == account) {
               if (i != owners[service].length - 1) {
                   owners[service][i] = owners[service][owners[service].length - 1];
               }
               owners[service].length--;
               break;
           }
       }
   }

   /**
   * Sell Keys
   * Services have to authorize keys for sale.
   * Key owners can disable key selling at time
   * of sale to prevent re-selling.
   */
   function createSalesOffer(bytes32 key, address buyer, uint price, bool _canSell)
       public
       ownsKey(key)
       canSell(key)
   {
       //cancel trade offer & create sales offer
       cancelTradeOffer(key);
       salesOffers[key].buyer = buyer;
       salesOffers[key].price = price;
       salesOffers[key].canSell = _canSell;
   }

   function cancelSalesOffer(bytes32 key)
       public
       ownsKey(key)
   {
       salesOffers[key].buyer = address(0);
       salesOffers[key].price = 0;
       salesOffers[key].canSell = false;
   }

   function purchaseKey(bytes32 key)
       public
       canSell(key)
   {

      //require explicit authority to spend tokens on the purchasers behalf
      require(salesOffers[key].price <= balance, "purchaseKey() salesOffers[key].price error");
      require(salesOffers[key].buyer == msg.sender, "purchaseKey() salesOffers[key].buyer error");

      /**
      * Price in HLTH tokens is transferred from the purchaser
      * to the primary owner of the key.
      */
    //   assert(balance.transfer(msg.sender, keys[key].owner, salesOffers[key].price));

      emit KeySold(key, keys[key].owner, msg.sender, salesOffers[key].price);
      keys[key].owner = msg.sender;

      //set canSell - allows for non-resellable keys
      keys[key].canSell = salesOffers[key].canSell;

      //remove sales offer
      cancelSalesOffer(key);
   }

   /**
   * Trade keys
   * both keys have to be authorized
   * to trade by their respective services.
   */
    function createTradeOffer(bytes32 have, bytes32 want)
        public
        ownsKey(have)
        validKey(want)
        canTrade(have)
        canTrade(want)
    {
        //cancel sales offer & create a trade offer
        cancelSalesOffer(have);
        tradeOffers[have] = want;
    }

   function cancelTradeOffer(bytes32 key)
       public
       ownsKey(key)
   {
       tradeOffers[key] = bytes32(0); //remove the tradeOffer
   }

    function tradeKey(bytes32 have, bytes32 want)
        public
        ownsKey(have)
        validKey(want)
        canTrade(have)
        canTrade(want)
    {
        require(tradeOffers[want] == have, "tradeKey() error");

        emit KeysTraded(want, have);
        //complete the trade
        keys[have].owner = keys[want].owner;
        keys[want].owner = msg.sender;

        //remove trade offer
        cancelTradeOffer(want);
    }

   /**
   * Manage Keys
   * Service owner can set key permissions
   * disabling sharing, trading, or selling
   * removes shared owners, active trade
   * offers, and active sales offers respectively
   *
   * Should also be able to get a key and service,
   * get a count of keys and services, and get
   * a key and service key from the respective
   * lists.
   */
   //service owner can set permissions
   function setKeyPermissions(
       bytes32 key,
       bool canShare_,
       bool canTrade_,
       bool canSell_)
       public
       validKey(key)
       ownsService(keys[key].service)
   {
       keys[key].canShare = canShare_;
       if (canShare_ == false) {
           owners[key].length = 0;
       }

       keys[key].canTrade = canTrade_;
       if (canTrade_ == false) {
           tradeOffers[key] = bytes32(0);
       }

       keys[key].canSell = canSell_;
       if (canSell_ == false) {
           salesOffers[key].buyer = address(0);
           salesOffers[key].price = 0;
           salesOffers[key].canSell = false;
       }

   }

   function getServiceCount() public view returns (uint) {
       return serviceList.length;
   }

   function getKeyCount() public view returns (uint) {
       return keyList.length;
   }

   function getService(bytes32 service)
       public
       view
       validService(service)
       returns(string memory, address)
   {
      return (services[service].url, services[service].owner);
   }

   function getKey(bytes32 key)
       public
       view
       validKey(key)
       returns(address, bool, bool, bool, bytes32)
   {
      return (keys[key].owner,
              keys[key].canShare,
              keys[key].canTrade,
              keys[key].canSell,
              keys[key].service);
   }

   /**
   * Key Data
   * A service can store public data for its keys.
   */
   function setKeyData(bytes32 key, bytes32 dataKey, bytes32 dataValue)
       public
       validKey(key)
       ownsService(keys[key].service)
   {
       keyData[keccak256(abi.encodePacked(key,dataKey))] = dataValue;
   }

   function getKeyData(bytes32 key, bytes32 dataKey)
       public
       view
       validKey(key)
       returns (bytes32)
   {
       return keyData[keccak256(abi.encodePacked(key,dataKey))];
   }

   /**
   * ecrecover passthrough
   */
   function recoverAddress(
       bytes32 msgHash,
       uint8 v,
       bytes32 r,
       bytes32 s)
       public
       pure
       returns (address)
   {
     return ecrecover(msgHash, v, r, s);
   }

   /**
   * Logging & Messaging
   * functions for creating an auditable record of activity.
   * A service can log access from any of its keys.
   */
   function logAccess(bytes32 key, string memory data)
       public
       validKey(key)
       ownsService(keys[key].service)
   {
       emit Access(msg.sender, keys[key].service, key, now, data);
   }

   //services and keys can log messages to each other
   function message(bytes32 from, bytes32 to, string memory category, string memory data)
       public
   {
       require((keys[from].owner != address(0) && isKeyOwner(from, msg.sender)) ||
               isServiceOwner(from, msg.sender), "message() error 1");
       require(keys[to].owner != address(0) || services[to].owner != address(0), "message() error 2");

       emit Message(msg.sender, from, to, now, category, data);
   }

   //any key or service can log
   function log(bytes32 from, string memory data)
       public
   {
       require((keys[from].owner != address(0) && isKeyOwner(from, msg.sender)) ||
                isServiceOwner(from, msg.sender), "log() error");

       emit Log(msg.sender, from, now, data);
   }

}

pragma solidity ^0.5.0;

import '../node_modules/openzeppelin-solidity/contracts/ownership/Ownable.sol';
import '../node_modules/openzeppelin-solidity/contracts/token/ERC20/ERC20.sol';

/**
* Health Decentralized Record Service (DRS)
* This contract enables creation of services and keys which can
* be managed, shared, traded, and sold using Health Cash (HLTH).
*
* These keys enable gatekeeper services and
* cryptographically secure data exchanges.
*/

contract HealthDRS is Ownable {

   ERC20 public token;
   address public latestContract = address(this);
   uint8 public version = 1;
   uint public minimumHold = 0;

   struct Service {
       string url;
       address owner;
   }

   struct Key {
       address owner;
       bool canShare;
       bool canTrade;
       bool canSell;
       bytes32 service;
   }

   struct SalesOffer {
       address buyer;
       uint price;
       bool canSell;
   }

   mapping (bytes32 => Service) public services;
   bytes32[] public serviceList;

   mapping(bytes32 => Key) keys;
   bytes32[] public keyList;

   mapping(bytes32 => address[]) public owners;
   mapping(bytes32 => bytes32) public keyData;
   mapping(bytes32 => SalesOffer) public salesOffers;
   mapping(bytes32 => bytes32) public tradeOffers;

   event ServiceCreated(address indexed _owner, bytes32 indexed _service);
   event KeyCreated(address indexed _owner, bytes32 indexed _key);
   event KeySold(bytes32 _key, address indexed _seller, address indexed _buyer, uint _price);
   event KeysTraded(bytes32 indexed _key1, bytes32 indexed _key2);
   event Access(address indexed _owner, bytes32 indexed _from, bytes32 indexed _to, uint _time, string _data);
   event Message(address indexed _owner, bytes32 indexed _from, bytes32 indexed _to, uint _time, string _category, string _data);
   event Log(address indexed _owner, bytes32 indexed _from, uint _time, string _data);

   modifier validKey(bytes32 key) {
     require(keys[key].owner != address(0), "validKey() error");
     _;
   }

   modifier validService(bytes32 service) {
     require(services[service].owner != address(0), "validService() error");
     _;
   }

   modifier ownsKey(bytes32 key) {
       require(isKeyOwner(key, msg.sender), "ownsKey() error");
       _;
   }
   modifier ownsService(bytes32 service) {
       require(isServiceOwner(service, msg.sender), "ownsService() error");
       _;
   }

   modifier canSell(bytes32 key) {
     require(keys[key].canSell, "canSell() key can't be sold error");
     require(owners[key].length == 0, "canSell() key does not exist error");
     _;
   }

   modifier canTrade(bytes32 key) {
     require(keys[key].canTrade, "canTrade() keys[key].canTrade error");
     require(owners[key].length == 0, "canTrade() owners[key].length error");
     _;
   }

   modifier canShare(bytes32 key) {
     require(keys[key].canShare, "canShare() error");
     _;
   }

    // ensure account has currency
    // TODO Remove and remove all references
    modifier holdingCurrency(){
        require(address(this).balance >= minimumHold, "holdingCurrency() error");
        _;
    }

   //prevent accidentally sending/trapping ether
   function() external {
       revert("function() line 104 error");
   }

//   //require token specified at deployment
//   constructor(ERC20 _token) public {
//       token = _token;
//   }

   function isKeyOwner(bytes32 key, address account)
       public
       view
       validKey(key)
       returns (bool)
   {
       if (keys[key].owner == account) {
           return true;
       } else {
           if (keys[key].canShare) {
               for (uint i = 0; i < owners[key].length; i++) {
                   if (owners[key][i] == account) {
                       return true;
                   }
               }
           }
       }
       return false;
   }

   function isServiceOwner(bytes32 service, address account)
       public
       view
       validService(service)
       returns (bool)
   {
       if (services[service].owner == account) {
           return true;
       } else {
           for (uint i = 0; i < owners[service].length; i++) {
               if (owners[service][i] == account) {
                   return true;
               }
          }
       }
       return false;
   }

   function getUrl(bytes32 service)
       public
       view
       validService(service)
       returns (string memory)
   {
      return services[service].url;
   }

   function getUrlFromKey(bytes32 key)
       public
       view
       validKey(key)
       returns (string memory)
   {
       return services[keys[key].service].url;
   }

   function updateUrl(bytes32 service, string memory url)
       public
       ownsService(service)
   {
      services[service].url = url;
   }

   function getOwnersLength(bytes32 key)
       public
       view
       returns (uint256)
    {
        return owners[key].length;
    }

   //user must authorize this contract to spend Health Cash (HLTH)
   function authorizedToSpend() public view returns (uint) {
       return token.allowance(msg.sender, address(this));
   }

    //allow owner access to tokens erroneously transferred to this contract
   function recoverTokens(address payable _token, uint amount) public onlyOwner {
       _token.transfer(amount);
   }

//    function setHealthCashToken(ERC20 _token) public onlyOwner {
//        token = _token;
//    }

   function setLatestContract(address _contract) public onlyOwner {
       latestContract = _contract;
   }

//    function setMinimumHold(uint _minimumHold) public onlyOwner {
//        minimumHold = _minimumHold;
//    }

  /**
  * Create Services & Keys
  * Keys can also be issued to accounts
  */
   function createService(string memory url)
        public
        holdingCurrency()
   {
       bytes32 id = keccak256(abi.encode(msg.sender, url));
       require(services[id].owner == address(0), "createService() error"); //prevent overwriting
       services[id].owner = msg.sender;
       services[id].url = url;
       serviceList.push(id);
       emit ServiceCreated(msg.sender, id);
   }

   function createKey(bytes32 service)
       public
       ownsService(service)
       holdingCurrency()
   {
       issueKey(service, msg.sender);
   }

   function issueKey(bytes32 service, address issueTo)
       public
       ownsService(service)
       holdingCurrency()
   {
       bytes32 id = keccak256(abi.encode(service, issueTo, now));
       require(keys[id].owner == address(0), "issueKey() error");
       keys[id].owner = issueTo;
       keys[id].service = service;
       keyList.push(id);
       emit KeyCreated(issueTo, id);
   }

  /**
  * Share Services and Keys
  * allow owners to authorize other accounts
  * a service can disable sharing for their keys.
  * Can also unshare.
  */
   function shareKey(bytes32 key, address account)
       public
       ownsKey(key)
       canShare(key)
       holdingCurrency()
   {
       if (isKeyOwner(key, account) == false) {
           owners[key].push(account);
       }
   }

   function shareService(bytes32 service, address account)
       public
       ownsService(service)
   {
       if (isServiceOwner(service, account) == false) {
           owners[service].push(account);
       }
   }

   function unshareKey(bytes32 key, address account)
       public
       ownsKey(key)
       holdingCurrency()
   {
       for (uint i = 0; i < owners[key].length; i++) {
           if (owners[key][i] == account) {
               if (i != owners[key].length - 1) {
                   owners[key][i] = owners[key][owners[key].length - 1];
               }
               owners[key].length--;
               break;
           }
       }
   }

   function unshareService(bytes32 service, address account)
       public
       ownsService(service)
   {
       for (uint i = 0; i < owners[service].length; i++) {
           if (owners[service][i] == account) {
               if (i != owners[service].length - 1) {
                   owners[service][i] = owners[service][owners[service].length - 1];
               }
               owners[service].length--;
               break;
           }
       }
   }

   /**
   * Sell Keys
   * Services have to authorize keys for sale.
   * Key owners can disable key selling at time
   * of sale to prevent re-selling.
   */
   function createSalesOffer(bytes32 key, address buyer, uint price, bool _canSell)
       public
       ownsKey(key)
       canSell(key)
   {
       //cancel trade offer & create sales offer
       cancelTradeOffer(key);
       salesOffers[key].buyer = buyer;
       salesOffers[key].price = price;
       salesOffers[key].canSell = _canSell;
   }

   function cancelSalesOffer(bytes32 key)
       public
       ownsKey(key)
   {
       salesOffers[key].buyer = address(0);
       salesOffers[key].price = 0;
       salesOffers[key].canSell = false;
   }

   function purchaseKey(bytes32 key)
       public
       canSell(key)
   {

      //require explicit authority to spend tokens on the purchasers behalf
      require(salesOffers[key].price <= authorizedToSpend(), "purchaseKey() salesOffers[key].price error");
      require(salesOffers[key].buyer == msg.sender, "purchaseKey() salesOffers[key].buyer error");

      /**
      * Price in HLTH tokens is transferred from the purchaser
      * to the primary owner of the key.
      */
      assert(token.transferFrom(msg.sender, keys[key].owner, salesOffers[key].price));

      emit KeySold(key, keys[key].owner, msg.sender, salesOffers[key].price);
      keys[key].owner = msg.sender;

      //set canSell - allows for non-resellable keys
      keys[key].canSell = salesOffers[key].canSell;

      //remove sales offer
      cancelSalesOffer(key);
   }

   /**
   * Trade keys
   * both keys have to be authorized
   * to trade by their respective services.
   */
    function createTradeOffer(bytes32 have, bytes32 want)
        public
        ownsKey(have)
        validKey(want)
        canTrade(have)
        canTrade(want)
    {
        //cancel sales offer & create a trade offer
        cancelSalesOffer(have);
        tradeOffers[have] = want;
    }

   function cancelTradeOffer(bytes32 key)
       public
       ownsKey(key)
   {
       tradeOffers[key] = bytes32(0); //remove the tradeOffer
   }

    function tradeKey(bytes32 have, bytes32 want)
        public
        ownsKey(have)
        validKey(want)
        canTrade(have)
        canTrade(want)
    {
        require(tradeOffers[want] == have, "tradeKey() error");

        emit KeysTraded(want, have);
        //complete the trade
        keys[have].owner = keys[want].owner;
        keys[want].owner = msg.sender;

        //remove trade offer
        cancelTradeOffer(want);
    }

   /**
   * Manage Keys
   * Service owner can set key permissions
   * disabling sharing, trading, or selling
   * removes shared owners, active trade
   * offers, and active sales offers respectively
   *
   * Should also be able to get a key and service,
   * get a count of keys and services, and get
   * a key and service key from the respective
   * lists.
   */
   //service owner can set permissions
   function setKeyPermissions(
       bytes32 key,
       bool canShare_,
       bool canTrade_,
       bool canSell_)
       public
       validKey(key)
       ownsService(keys[key].service)
   {
       keys[key].canShare = canShare_;
       if (canShare_ == false) {
           owners[key].length = 0;
       }

       keys[key].canTrade = canTrade_;
       if (canTrade_ == false) {
           tradeOffers[key] = bytes32(0);
       }

       keys[key].canSell = canSell_;
       if (canSell_ == false) {
           salesOffers[key].buyer = address(0);
           salesOffers[key].price = 0;
           salesOffers[key].canSell = false;
       }

   }

   function getServiceCount() public view returns (uint) {
       return serviceList.length;
   }

   function getKeyCount() public view returns (uint) {
       return keyList.length;
   }

   function getService(bytes32 service)
       public
       view
       validService(service)
       returns(string memory, address)
   {
      return (services[service].url, services[service].owner);
   }

   function getKey(bytes32 key)
       public
       view
       validKey(key)
       returns(address, bool, bool, bool, bytes32)
   {
      return (keys[key].owner,
              keys[key].canShare,
              keys[key].canTrade,
              keys[key].canSell,
              keys[key].service);
   }

   /**
   * Key Data
   * A service can store public data for its keys.
   */
   function setKeyData(bytes32 key, bytes32 dataKey, bytes32 dataValue)
       public
       validKey(key)
       ownsService(keys[key].service)
   {
       keyData[keccak256(abi.encodePacked(key,dataKey))] = dataValue;
   }

   function getKeyData(bytes32 key, bytes32 dataKey)
       public
       view
       validKey(key)
       returns (bytes32)
   {
       return keyData[keccak256(abi.encodePacked(key,dataKey))];
   }

   /**
   * ecrecover passthrough
   */
   function recoverAddress(
       bytes32 msgHash,
       uint8 v,
       bytes32 r,
       bytes32 s)
       public
       pure
       returns (address)
   {
     return ecrecover(msgHash, v, r, s);
   }

   /**
   * Logging & Messaging
   * functions for creating an auditable record of activity.
   * A service can log access from any of its keys.
   */
   function logAccess(bytes32 key, string memory data)
       public
       validKey(key)
       ownsService(keys[key].service)
   {
       emit Access(msg.sender, keys[key].service, key, now, data);
   }

   //services and keys can log messages to each other
   function message(bytes32 from, bytes32 to, string memory category, string memory data)
       public
   {
       require((keys[from].owner != address(0) && isKeyOwner(from, msg.sender)) ||
               isServiceOwner(from, msg.sender), "message() error 1");
       require(keys[to].owner != address(0) || services[to].owner != address(0), "message() error 2");

       emit Message(msg.sender, from, to, now, category, data);
   }

   //any key or service can log
   function log(bytes32 from, string memory data)
       public
   {
       require((keys[from].owner != address(0) && isKeyOwner(from, msg.sender)) ||
                isServiceOwner(from, msg.sender), "log() error");

       emit Log(msg.sender, from, now, data);
   }

}


MarketContractOraclize: Rename valid queries mapping to validQueryIDs.

Issue: #57

/*
    Copyright 2017-2018 Phillip A. Elsasser

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

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

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

pragma solidity ^0.4.18;

import "./oraclizeAPI.sol";
import "../libraries/MathLib.sol";
import "../MarketContract.sol";

/// @title MarketContract first example of a MarketProtocol contract using Oraclize services
/// @author Phil Elsasser <phil@marketprotocol.io>
contract MarketContractOraclize is MarketContract, usingOraclize {
    using MathLib for uint;

    // constants
    string public ORACLE_DATA_SOURCE;
    string public ORACLE_QUERY;
    uint constant public QUERY_CALLBACK_GAS = 180000;
    //uint constant public QUERY_CALLBACK_GAS_PRICE = 20000000000 wei; // 20 gwei - need to make this dynamic!

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

    /// @param contractName viewable name of this contract (BTC/ETH, LTC/ETH, etc)
    /// @param marketTokenAddress address of our member token
    /// @param baseTokenAddress address of the ERC20 token that will be used for collateral and pricing
    /// @param contractSpecs array of unsigned integers including:
    /// floorPrice minimum tradeable price of this contract, contract enters settlement if breached
    /// capPrice maximum tradeable price of this contract, contract enters settlement if breached
    /// priceDecimalPlaces number of decimal places to convert our queried price from a floating point to
    /// an integer
    /// qtyMultiplier multiply traded qty by this value from base units of collateral token.
    /// expirationTimeStamp - seconds from epoch that this contract expires and enters settlement
    /// @param oracleDataSource a data-source such as "URL", "WolframAlpha", "IPFS"
    /// see http://docs.oraclize.it/#ethereum-quick-start-simple-query
    /// @param oracleQuery see http://docs.oraclize.it/#ethereum-quick-start-simple-query for examples
    function MarketContractOraclize(
        string contractName,
        address marketTokenAddress,
        address baseTokenAddress,
        uint[5] contractSpecs,
        string oracleDataSource,
        string oracleQuery
    ) MarketContract(
        contractName,
        marketTokenAddress,
        baseTokenAddress,
        contractSpecs
    )  public payable
    {
        oraclize_setProof(proofType_TLSNotary | proofStorage_IPFS);
        //oraclize_setCustomGasPrice(QUERY_CALLBACK_GAS_PRICE);  //TODO: allow this to be changed by creator.
        ORACLE_DATA_SOURCE = oracleDataSource;
        ORACLE_QUERY = oracleQuery;
        queryOracle();  // Schedule a call to oracle at contract expiration time.
    }

    /// @notice allows a user to request an extra query to oracle in order to push the contract into
    /// settlement.  A user may call this as many times as they like, since they are the ones paying for
    /// the call to our oracle and post processing. This is useful for both a failsafe and as a way to
    /// settle a contract early if a price cap or floor has been breached.
    function requestEarlySettlement() external payable {
        uint cost = oraclize_getPrice(ORACLE_DATA_SOURCE, QUERY_CALLBACK_GAS);
        require(msg.value >= cost); // user must pay enough to cover query and callback
        // create immediate query, we must make sure to store this one separately, so
        // we do not schedule recursive callbacks when the query completes.
        bytes32 queryId = oraclize_query(
            ORACLE_DATA_SOURCE,
            ORACLE_QUERY,
            QUERY_CALLBACK_GAS
        );
        validQueryIDs[queryId] = true;
    }

    /*
    // PUBLIC METHODS
    */

    /// @notice only public for callbacks from oraclize, do not call
    /// @param queryID of the returning query, this should match our own internal mapping
    /// @param result query to be processed
    /// @param proof result proof
    function __callback(bytes32 queryID, string result, bytes proof) public {
        require(msg.sender == oraclize_cbAddress());
        require(validQueryIDs[queryID]);  // At expiration or early settlement.
        lastPriceQueryResult = result;
        lastPrice = parseInt(result, PRICE_DECIMAL_PLACES);
        UpdatedLastPrice(result);
        checkSettlement();  // Verify settlement at expiration or requested early settlement.
        delete validQueryIDs[queryID];
    }

    /*
    // PRIVATE METHODS
    */

    /// @dev call to oraclize to set up our query and record its hash.
    function queryOracle() private {
        // Require that sufficient funds are available to pay for the query.
        require(oraclize_getPrice(ORACLE_DATA_SOURCE, QUERY_CALLBACK_GAS) < this.balance);
        // Require expiration time in the future.
        require(EXPIRATION > now);
        // Future timestamp must be within 60 days from now.
        // https://docs.oraclize.it/#ethereum-quick-start-schedule-a-query-in-the-future
        require(EXPIRATION - now <= 60 * 60 * 24 * 60);

        bytes32 queryId = oraclize_query(
            EXPIRATION - now,
            ORACLE_DATA_SOURCE,
            ORACLE_QUERY,
            QUERY_CALLBACK_GAS
        );
        validQueryIDs[queryId] = true;
    }
}

/*
    Copyright 2017-2018 Phillip A. Elsasser

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

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

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

pragma solidity ^0.4.18;

import "./oraclizeAPI.sol";
import "../libraries/MathLib.sol";
import "../MarketContract.sol";

/// @title MarketContract first example of a MarketProtocol contract using Oraclize services
/// @author Phil Elsasser <phil@marketprotocol.io>
contract MarketContractOraclize is MarketContract, usingOraclize {
    using MathLib for uint;

    // constants
    string public ORACLE_DATA_SOURCE;
    string public ORACLE_QUERY;
    uint constant public QUERY_CALLBACK_GAS = 180000;
    //uint constant public QUERY_CALLBACK_GAS_PRICE = 20000000000 wei; // 20 gwei - need to make this dynamic!

    // state variables
    string public lastPriceQueryResult;
    mapping(bytes32 => bool) validUserRequestedQueryIDs;

    /// @param contractName viewable name of this contract (BTC/ETH, LTC/ETH, etc)
    /// @param marketTokenAddress address of our member token
    /// @param baseTokenAddress address of the ERC20 token that will be used for collateral and pricing
    /// @param contractSpecs array of unsigned integers including:
    /// floorPrice minimum tradeable price of this contract, contract enters settlement if breached
    /// capPrice maximum tradeable price of this contract, contract enters settlement if breached
    /// priceDecimalPlaces number of decimal places to convert our queried price from a floating point to
    /// an integer
    /// qtyMultiplier multiply traded qty by this value from base units of collateral token.
    /// expirationTimeStamp - seconds from epoch that this contract expires and enters settlement
    /// @param oracleDataSource a data-source such as "URL", "WolframAlpha", "IPFS"
    /// see http://docs.oraclize.it/#ethereum-quick-start-simple-query
    /// @param oracleQuery see http://docs.oraclize.it/#ethereum-quick-start-simple-query for examples
    function MarketContractOraclize(
        string contractName,
        address marketTokenAddress,
        address baseTokenAddress,
        uint[5] contractSpecs,
        string oracleDataSource,
        string oracleQuery
    ) MarketContract(
        contractName,
        marketTokenAddress,
        baseTokenAddress,
        contractSpecs
    )  public payable
    {
        oraclize_setProof(proofType_TLSNotary | proofStorage_IPFS);
        //oraclize_setCustomGasPrice(QUERY_CALLBACK_GAS_PRICE);  //TODO: allow this to be changed by creator.
        ORACLE_DATA_SOURCE = oracleDataSource;
        ORACLE_QUERY = oracleQuery;
        // Require that sufficient funds are available to pay for the query.
        require(oraclize_getPrice(ORACLE_DATA_SOURCE, QUERY_CALLBACK_GAS) < this.balance);
        queryOracle();  // Schedule a call to oracle at contract expiration time.
    }

    /// @notice allows a user to request an extra query to oracle in order to push the contract into
    /// settlement.  A user may call this as many times as they like, since they are the ones paying for
    /// the call to our oracle and post processing. This is useful for both a failsafe and as a way to
    /// settle a contract early if a price cap or floor has been breached.
    function requestEarlySettlement() external payable {
        uint cost = oraclize_getPrice(ORACLE_DATA_SOURCE, QUERY_CALLBACK_GAS);
        require(msg.value >= cost); // user must pay enough to cover query and callback
        // create immediate query, we must make sure to store this one separately, so
        // we do not schedule recursive callbacks when the query completes.
        bytes32 queryId = oraclize_query(
            ORACLE_DATA_SOURCE,
            ORACLE_QUERY,
            QUERY_CALLBACK_GAS
        );
        validUserRequestedQueryIDs[queryId] = true;
    }

    /*
    // PUBLIC METHODS
    */

    /// @notice only public for callbacks from oraclize, do not call
    /// @param queryID of the returning query, this should match our own internal mapping
    /// @param result query to be processed
    /// @param proof result proof
    function __callback(bytes32 queryID, string result, bytes proof) public {
        require(msg.sender == oraclize_cbAddress());
        require(validUserRequestedQueryIDs[queryID]);
        lastPriceQueryResult = result;
        lastPrice = parseInt(result, PRICE_DECIMAL_PLACES);
        UpdatedLastPrice(result);
        checkSettlement();  // Verify settlement at expiration or requested early settlement.
        delete validUserRequestedQueryIDs[queryID];
    }

    /*
    // PRIVATE METHODS
    */

    /// @dev call to oraclize to set up our query and record its hash.
    function queryOracle() private {
        // Require expiration time in the future.
        require(EXPIRATION > now);
        // Future timestamp must be within 60 days from now.
        // https://docs.oraclize.it/#ethereum-quick-start-schedule-a-query-in-the-future
        require(EXPIRATION - now <= 60 * 60 * 24 * 60);

        bytes32 queryId = oraclize_query(
            EXPIRATION - now,
            ORACLE_DATA_SOURCE,
            ORACLE_QUERY,
            QUERY_CALLBACK_GAS
        );
    }
}


Battle contract (first phase);

Battle contract (first phase);

pragma solidity ^0.4.11;

import "./TokenERC20.sol";

contract Battle {

    //Battle counters
    mapping (address => uint256) public warriorsOnTheBattlefield;
    mapping (address => mapping (address => uint256)) public balances;

    //Token addresses
    address public constant persiansAddress = 0xF63D4Ec615898163CdE5EBC2Aa8d5768ccC92965;  //0xaec98a708810414878c3bcdf46aad31ded4a4557 MainNet
    address public constant immortalsAddress = 0xED19698C0abdE8635413aE7AD7224DF6ee30bF22;  //0xED19698C0abdE8635413aE7AD7224DF6ee30bF22 MainNet
    address public constant spartansAddress = 0x94F72fa9d9e035a40F22f6e7ceDb78E697fF54C2;  //0x163733bcc28dbf26B41a8CfA83e369b5B3af741b MainNet
    address public constant atheniansAddress = 0x17052d51E954592C1046320c2371AbaB6C73Ef10; //0x17052d51e954592c1046320c2371abab6c73ef10 MainNet

    //Battle events
    event PersiansAssigned(address indexed _from, uint256 _battlePointsIncrementForecast);
    event ImmortalsAssigned(address indexed _from, uint256 _battlePointsIncrementForecast);
    event SpartansAssigned(address indexed _from, uint256 _battlePointsIncrementForecast);
    event AtheniansAssigned(address indexed _from, uint256 _battlePointsIncrementForecast);

    //
    function assignPersiansToBattle(uint256 _value) returns (bool success) {
        if(assignWarriorsToBattle(persiansAddress, _value)) {
            PersiansAssigned(msg.sender, _value / 10**18);
            return true;
        }
        return false;
    }

    function assignImmortalsToBattle(uint256 _value) returns (bool success) {
        if(assignWarriorsToBattle(immortalsAddress, _value)) {
            ImmortalsAssigned(msg.sender, (_value / 10**18) * 100);
            return true;
        }
        return false;
    }

    function assignSpartansToBattle(uint256 _value) returns (bool success) {
        if(assignWarriorsToBattle(spartansAddress, _value)) {
            SpartansAssigned(msg.sender, (_value / 10**18) * 1000);
            return true;
        }
        return false;
    }

    function assignAtheniansToBattle(uint256 _value) returns (bool success) {
        if(assignWarriorsToBattle(atheniansAddress, _value)) {
            AtheniansAssigned(msg.sender, (_value / 10**18) * 100);
            return true;
        }
        return false;
    }

    function assignWarriorsToBattle(address faction, uint256 _value) internal returns (bool success) {
        if(TokenERC20(faction).allowance(msg.sender, address(this)) < _value) return false;
        if(!TokenERC20(faction).transferFrom(msg.sender, address(this), _value)) return false;
        balances[faction][msg.sender] += _value;
        warriorsOnTheBattlefield[faction] += _value;
    }

}

pragma solidity ^0.4.11;

import "./Persians.sol";

contract Battle {

    event PersiansAssigned(address indexed _from, address indexed _to, uint256 _value);

    address spartan = 0x94F72fa9d9e035a40F22f6e7ceDb78E697fF54C2;
    address persian = 0xF63D4Ec615898163CdE5EBC2Aa8d5768ccC92965;

    uint256 public persiansOnTheBattlefield;

    mapping (address => uint256) persianBalances;

    //
    function assignPersiansToBattle(uint256 _value) returns (bool success) {
        //Refer to the Persian Token contract
        PersianToken persian = PersianToken(persian);
        //Check if contract was previously allowed to move enough tokens
        if(persian.allowance(msg.sender, address(this)) < _value) return false;
        //Move tokens to this contract
        if(!persian.transferFrom(msg.sender, address(this), _value)) return false;
        //Increase the sender balance
        persianBalances[msg.sender] += _value;
        persiansOnTheBattlefield += _value;
        PersiansAssigned(msg.sender, address(this), _value);
        return true;
    }

}


Update TimeVault.sol

Update TimeVault.sol

pragma solidity ^0.4.8;

import './StandardToken.sol';

/**
 *
 * Time-locked token vault of allocated founder tokens.
 *
 * See TokenVault for multi user implementation.
 */
contract TimeVault is SafeMath {

  /** Interface flag to determine if address is for a real contract or not */
  bool public isTimeVault = true;

  /** Token we are holding */
  StandardToken public token;

  /** Address that can claim tokens */
  address public teamMultisig;

  /** UNIX timestamp when tokens can be claimed. */
  uint256 public unlockedAt;

  event Unlocked();

  function TimeVault(address _teamMultisig, StandardToken _token, uint _unlockedAt) {

    teamMultisig = _teamMultisig;
    token = _token;
    unlockedAt = _unlockedAt;

    // Sanity check
    if (teamMultisig == 0x0) throw;
    if (address(token) == 0x0) throw;
  }

  function getTokenBalance() public constant returns (uint) {
    return token.balanceOf(address(this));
  }

  function unlock() public {
    // Wait your turn!
    if (now < unlockedAt) throw;

    // StandardToken will throw in the case of transaction fails
    token.transfer(teamMultisig, getTokenBalance());

    Unlocked();
  }

  // disallow CHX payment for this vault
  function () { throw; }

}

pragma solidity ^0.4.8;

import './StandardToken.sol';

/**
 *
 * Time-locked token vault of allocated founder tokens.
 *
 * See TokenVault for multi user implementation.
 */
contract TimeVault is SafeMath {

  /** Interface flag to determine if address is for a real contract or not */
  bool public isTimeVault = true;

  /** Token we are holding */
  StandardToken public token;

  /** Address that can claim tokens */
  address public teamMultisig;

  /** UNIX timestamp when tokens can be claimed. */
  uint256 public unlockedAt;

  event Unlocked();

  function TimeVault(address _teamMultisig, StandardToken _token, uint _unlockedAt) {

    teamMultisig = _teamMultisig;
    token = _token;
    unlockedAt = _unlockedAt;

    // Sanity check
    if (teamMultisig == 0x0) throw;
    if (address(token) == 0x0) throw;
  }

  function getTokenBalance() public constant returns (uint) {
    return token.balanceOf(address(this));
  }

  function unlock() public {
    // Wait your turn!
    if (now < unlockedAt) throw;

    // StandardToken will throw in the case of transaction fails
    token.transfer(teamMultisig, getTokenBalance());

    Unlocked();
  }

  // disallow ETH payment for this vault
  function () { throw; }

}