renewals now seamless

renewals now seamless

pragma solidity ^0.4.11;
import "./StandardToken.sol";
import "./PLCRVoting.sol";
import "./Test.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;

/* Structs
 */
    struct Publisher {
        address owner;
        uint expTime;     // expiration of whitelist listing + renewal time
        uint expCurrent;  // expiration of the current whitelist period (tells us when renewal starts)
        uint deposit;

        uint prevDeposit; // total withdrawable amount
        uint nextDeposit; // deposit of renewal
        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 minParamDeposit;
        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;
    }

/* Constants
 */
    uint256 constant private MULTIPLIER = 10 ** 18;  // constant used to help represent doubles as ints
    bytes32 constant private MINDEPOSIT_h = sha3("minDeposit");
    bytes32 constant private MINPARAMDEPOSIT_h = sha3("minParamDeposit");
    bytes32 constant private CHALLENGELEN_h = sha3("challengeLen");
    bytes32 constant private REGISTRYLEN_h = sha3("registryLen");
    bytes32 constant private COMMITVOTELEN_h = sha3("commitVoteLen");
    bytes32 constant private REVEALVOTELEN_h = sha3("revealVoteLen");
    bytes32 constant private DISPENSATIONPCT_h = sha3("dispensationPct");
    bytes32 constant private MAJORITY_h = sha3("majority");

/* Constructor
 */
    /// @param _minDeposit      application & challenger deposit amounts for domains
    /// @param _minParamDeposit application & challenger deposit amounts for parameters
    /// @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 _minParamDeposit,
        uint _challengeLen,
        uint _registryLen,
        uint _commitVoteLen,
        uint _revealVoteLen,
        uint _dispensationPct,
        uint _majority) {

        token = StandardToken(_token);
        voting = PLCRVoting(_voting);
        // initialize values
        Parameters[MINDEPOSIT_h]        = _minDeposit;
        Parameters[MINPARAMDEPOSIT_h]   = _minParamDeposit;
        Parameters[CHALLENGELEN_h]      = _challengeLen;
        Parameters[REGISTRYLEN_h]       = _registryLen;
        Parameters[COMMITVOTELEN_h]     = _commitVoteLen;
        Parameters[REVEALVOTELEN_h]     = _revealVoteLen;
        Parameters[DISPENSATIONPCT_h]   = _dispensationPct;
        Parameters[MAJORITY_h]          = _majority;
    }

/* Registry Functions
 */

    // called by applicant to add to application pool on success
    function apply(string _domain) public {
        bytes32 domainHash = sha3(_domain);
        require(appPool[domainHash].owner == 0); // not in appPool
        // check if new applicant or renewal
        if (whitelist[domainHash].owner == 0)  // new applicant
        {
            // initialize with the current values of all parameters
            initializeSnapshot(domainHash);
            initApplication(domainHash, paramSnapshots[domainHash].minDeposit, msg.sender);
            appPool[domainHash].domain = _domain;
        }
        else  // renewal
        {
            renew(domainHash);
        }
    }

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

    // called by owner of a domain on the whitelist
    // make necessary token transfers and initialize application for renewal in the appPool
    function renew (bytes32 _domainHash) private {
        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 = Parameters[MINDEPOSIT_h];
        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
    // renew domain on the whitelist and allow additional renewal
    // without calling this, apply will not let a whitelist member
    // renew, and claimDeposit will not let them withdraw newly
    // freed tokens
    // however, isVerified will still return true without this call
    // for the renewal period as well as the current (or newly expired) whitelist period
    function activateRenewal(string _domain) public {
        bytes32 _hash = sha3(_domain);
        if (hasRenewal(_hash) && whitelist[_hash].expCurrent < now)
        {
            whitelist[_hash].expCurrent = whitelist[_hash].expTime;
            whitelist[_hash].prevDeposit += whitelist[_hash].deposit;
            whitelist[_hash].deposit = whitelist[_hash].nextDeposit;
            whitelist[_hash].renewal = false;
        }
    }

    // called by adtoken holder to challenge an application
    // initialize vote to accept/reject a domain to the registry
    function challengeApplication(string _domain) public returns(uint) {
        bytes32 domainHash = sha3(_domain);
        challenge(domainHash, paramSnapshots[domainHash].minDeposit, 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()
    // transfer tokens update application status
    function challenge(bytes32 _hash, uint deposit, address _challenger) private {
        // take tokens from challenger
        require(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 application status
        appPool[_hash].challenged = true;
        appPool[_hash].challenger = _challenger;
    }

    // helper function to challenge()
    // initialize vote through the voting contract. Return 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;
    }

    // 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 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);
            require(token.transfer(appPool[domainHash].challenger, paramSnapshots[domainHash].minDeposit));
            delete appPool[domainHash].owner;
            return false;
        }
    }

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

    // helper function to moveToRegistry() and processResult()
    // add a domain to whitelist or update renewal attributes
    function add(bytes32 _domainHash, address _owner) private {
        uint expiration = paramSnapshots[_domainHash].registryLen;
        if (whitelist[_domainHash].renewal == true)
        {
            if (whitelist[_domainHash].expCurrent < now) // if expired off whitelist
            { //determine the next expiry starting from now
                whitelist[_domainHash].expTime = now + expiration;
            }
            else // if domain has not expired
            { //determine next expiry starting from the end of the current expiry
                whitelist[_domainHash].expTime = whitelist[_domainHash].expCurrent + expiration;
            }
            whitelist[_domainHash].nextDeposit = paramSnapshots[_domainHash].minDeposit;
        }
        else
        {
            whitelist[_domainHash].expCurrent = now + expiration;
            whitelist[_domainHash].expTime = now + expiration;
            whitelist[_domainHash].deposit = paramSnapshots[_domainHash].minDeposit;
        }
        whitelist[_domainHash].owner = _owner;
    }

/* Token Distribution Functions
 */

    // 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);
        token.transfer(msg.sender, _amount);
        whitelist[domainHash].prevDeposit = unlockedTok - _amount;
    }

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

    // helper function to claimReward()
    // number of tokens person used to vote / total number of tokens for winning side
    // scale using distribution number, give the tokens
    function calculateTokens(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;
    }

    // gives reminder tokens from poll to a designated claimer
    // the claimer is the winner of the challenge
    // for every poll there will be ~0.5 nano AdTokens burned,
    // since the winner cannot withdraw a decimal amount of nano AdToken
    function claimExtraReward(uint _pollID) public {
        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);
    }

    // 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));
    }

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

/* Registry 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 = Parameters[REGISTRYLEN_h];
    }

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

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

/* Parameter Functions
 */

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

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

    // 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;

        // ensures the result cannot be processed again
        pollInfo[_pollID].processed = true;

        if (voting.isPassed(_pollID)) {
            pollInfo[_pollID].claimer = appPool[parameterHash].owner;
            // setting the value of parameter
            Parameters[sha3(parameter)] = value;
            // give winning tokens to applicant
            giveWinnerReward(parameterHash, appPool[parameterHash].owner);
            //give minParamDeposit to applicant
            token.transfer(appPool[parameterHash].owner, paramSnapshots[parameterHash].minParamDeposit);
            return true;
        }
        else {
            pollInfo[_pollID].claimer = appPool[parameterHash].challenger;
            // give winning tokens to challenger
            giveWinnerReward(parameterHash, appPool[parameterHash].challenger);
            //give minParamDeposit to challenger
            token.transfer(appPool[parameterHash].challenger, paramSnapshots[parameterHash].minParamDeposit);
            return false;
        }
    }

    // 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;
        // return proposer's deposit
        token.transfer(appPool[parameterHash].owner, paramSnapshots[parameterHash].minParamDeposit);
        delete appPool[parameterHash].owner;
    }

/* Parameter Helper Functions
 */

    // private function to initialize a snapshot of parameters for each proposal
    function initializeSnapshotParam(bytes32 _hash) private {
        paramSnapshots[_hash].minDeposit = Parameters[MINDEPOSIT_h];
        paramSnapshots[_hash].minParamDeposit = Parameters[MINPARAMDEPOSIT_h];
        paramSnapshots[_hash].challengeLen = Parameters[CHALLENGELEN_h];
        paramSnapshots[_hash].commitVoteLen = Parameters[COMMITVOTELEN_h];
        paramSnapshots[_hash].revealVoteLen = Parameters[REVEALVOTELEN_h];
        paramSnapshots[_hash].majority = Parameters[MAJORITY_h];
        paramSnapshots[_hash].dispensationPct = Parameters[DISPENSATIONPCT_h];
    }

    // provided for users to get value of parameter
    /// @param _keyword key for hashmap (only useful when keyword matches variable name)
    function get(string _keyword) public constant returns (uint) {
       return Parameters[sha3(_keyword)];
    }

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

/* Testing-Related Helper Functions
 */

    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";
import "./Test.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;

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

/* Constants
 */
    uint256 constant private MULTIPLIER = 10 ** 18;  // constant used to help represent doubles as ints
    bytes32 constant private MINDEPOSIT_h = sha3("minDeposit");
    bytes32 constant private MINPARAMDEPOSIT_h = sha3("minParamDeposit");
    bytes32 constant private CHALLENGELEN_h = sha3("challengeLen");
    bytes32 constant private REGISTRYLEN_h = sha3("registryLen");
    bytes32 constant private COMMITVOTELEN_h = sha3("commitVoteLen");
    bytes32 constant private REVEALVOTELEN_h = sha3("revealVoteLen");
    bytes32 constant private DISPENSATIONPCT_h = sha3("dispensationPct");
    bytes32 constant private MAJORITY_h = sha3("majority");

/* Constructor
 */
    /// @param _minDeposit      application & challenger deposit amounts for domains
    /// @param _minParamDeposit application & challenger deposit amounts for parameters
    /// @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 _minParamDeposit,
        uint _challengeLen,
        uint _registryLen,
        uint _commitVoteLen,
        uint _revealVoteLen,
        uint _dispensationPct,
        uint _majority) {

        token = StandardToken(_token);
        voting = PLCRVoting(_voting);
        // initialize values
        Parameters[MINDEPOSIT_h]        = _minDeposit;
        Parameters[MINPARAMDEPOSIT_h]   = _minParamDeposit;
        Parameters[CHALLENGELEN_h]      = _challengeLen;
        Parameters[REGISTRYLEN_h]       = _registryLen;
        Parameters[COMMITVOTELEN_h]     = _commitVoteLen;
        Parameters[REVEALVOTELEN_h]     = _revealVoteLen;
        Parameters[DISPENSATIONPCT_h]   = _dispensationPct;
        Parameters[MAJORITY_h]          = _majority;
    }

/* Registry Functions
 */

    // called by applicant to add to application pool on success
    function apply(string _domain) public {
        bytes32 domainHash = sha3(_domain);
        require(appPool[domainHash].owner == 0); // not in appPool
        // check if new applicant or renewal
        if (whitelist[domainHash].owner == 0)  // new applicant
        {
            // initialize with the current values of all parameters
            initializeSnapshot(domainHash);
            initApplication(domainHash, paramSnapshots[domainHash].minDeposit, msg.sender);
            appPool[domainHash].domain = _domain;
        }
        else  // renewal
        {
            renew(domainHash);
        }
    }

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

    // called by owner of a domain on the whitelist
    // make necessary token transfers and initialize application for renewal in the appPool
    function renew (bytes32 _domainHash) private {
        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 = Parameters[MINDEPOSIT_h];
        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
    //renew domain on the whitelist and allow additional renewal
    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 adtoken holder to challenge an application
    // initialize vote to accept/reject a domain to the registry
    function challengeApplication(string _domain) public returns(uint) {
        bytes32 domainHash = sha3(_domain);
        challenge(domainHash, paramSnapshots[domainHash].minDeposit, 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()
    // transfer tokens update application status
    function challenge(bytes32 _hash, uint deposit, address _challenger) private {
        // take tokens from challenger
        require(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 application status
        appPool[_hash].challenged = true;
        appPool[_hash].challenger = _challenger;
    }

    // helper function to challenge()
    // initialize vote through the voting contract. Return 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;
    }

    // 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 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);
            require(token.transfer(appPool[domainHash].challenger, paramSnapshots[domainHash].minDeposit));
            delete appPool[domainHash].owner;
            return false;
        }
    }

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

    // helper function to moveToRegistry() and processResult()
    // add a domain to whitelist or update renewal attributes
    function add(bytes32 _domainHash, address _owner) private {
        uint expiration = paramSnapshots[_domainHash].registryLen;
        if (whitelist[_domainHash].renewal == true)
        {
            if (whitelist[_domainHash].expTime < now) // if expired off whitelist
            {//determine the next expiry starting from now
                whitelist[_domainHash].nextExpTime = now + expiration;
            }
            else // if domain has not expired
            {//determine next expiry starting from the end of the current epiry
                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;
    }

/* Token Distribution Functions
 */

    // 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);
        token.transfer(msg.sender, _amount);
        whitelist[domainHash].prevDeposit = unlockedTok - _amount;
    }

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

    // helper function to claimReward()
    // number of tokens person used to vote / total number of tokens for winning side
    // scale using distribution number, give the tokens
    function calculateTokens(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;
    }

    // gives reminder tokens from poll to a designated claimer
    // the claimer is the winner of the challenge
    function claimExtraReward(uint _pollID) public {
        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);
    }

    // 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));
    }

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

/* Registry 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 = Parameters[REGISTRYLEN_h];
    }

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

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

/* Parameter Functions
 */

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

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

    // 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;

        // ensures the result cannot be processed again
        pollInfo[_pollID].processed = true;

        if (voting.isPassed(_pollID)) {
            pollInfo[_pollID].claimer = appPool[parameterHash].owner;
            // setting the value of parameter
            Parameters[sha3(parameter)] = value;
            // give winning tokens to applicant
            giveWinnerReward(parameterHash, appPool[parameterHash].owner);
            //give minParamDeposit to applicant
            token.transfer(appPool[parameterHash].owner, paramSnapshots[parameterHash].minParamDeposit);
            return true;
        }
        else {
            pollInfo[_pollID].claimer = appPool[parameterHash].challenger;
            // give winning tokens to challenger
            giveWinnerReward(parameterHash, appPool[parameterHash].challenger);
            //give minParamDeposit to challenger
            token.transfer(appPool[parameterHash].challenger, paramSnapshots[parameterHash].minParamDeposit);
            return false;
        }
    }

    // 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;
        // return proposer's deposit
        token.transfer(appPool[parameterHash].owner, paramSnapshots[parameterHash].minParamDeposit);
        delete appPool[parameterHash].owner;
    }

/* Parameter Helper Functions
 */

    // private function to initialize a snapshot of parameters for each proposal
    function initializeSnapshotParam(bytes32 _hash) private {
        paramSnapshots[_hash].minDeposit = Parameters[MINDEPOSIT_h];
        paramSnapshots[_hash].minParamDeposit = Parameters[MINPARAMDEPOSIT_h];
        paramSnapshots[_hash].challengeLen = Parameters[CHALLENGELEN_h];
        paramSnapshots[_hash].commitVoteLen = Parameters[COMMITVOTELEN_h];
        paramSnapshots[_hash].revealVoteLen = Parameters[REVEALVOTELEN_h];
        paramSnapshots[_hash].majority = Parameters[MAJORITY_h];
        paramSnapshots[_hash].dispensationPct = Parameters[DISPENSATIONPCT_h];
    }

    // provided for users to get value of parameter
    /// @param _keyword key for hashmap (only useful when keyword matches variable name)
    function get(string _keyword) public constant returns (uint) {
       return Parameters[sha3(_keyword)];
    }

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

/* Testing-Related Helper Functions
 */

    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;
    }

}


Add doc comments to multisig wallet

Add doc comments to multisig wallet

pragma solidity ^0.4.8;

import "./ownership/Multisig.sol";
import "./ownership/Shareable.sol";
import "./DayLimit.sol";

/**
 * MultisigWallet
 * Usage:
 *     bytes32 h = Wallet(w).from(oneOwner).execute(to, value, data);
 *     Wallet(w).from(anotherOwner).confirm(h);
 */
contract MultisigWallet is Multisig, Shareable, DayLimit {

  struct Transaction {
    address to;
    uint value;
    bytes data;
  }

  /**
   * Constructor, sets the owners addresses, number of approvals required, and daily spending limit
   * @param _owners A list of owners.
   * @param _required The amount required for a transaction to be approved.
   */
  function MultisigWallet(address[] _owners, uint _required, uint _daylimit)
    Shareable(_owners, _required)
    DayLimit(_daylimit) { }

  /**
   * @dev destroys the contract sending everything to `_to`.
   */
  function destroy(address _to) onlymanyowners(keccak256(msg.data)) external {
    selfdestruct(_to);
  }

  /**
   * @dev Fallback function, receives value and emits a deposit event.
   */
  function() payable {
    // just being sent some cash?
    if (msg.value > 0)
      Deposit(msg.sender, msg.value);
  }

  /**
   * @dev Outside-visible transaction entry point. Executes transaction immediately if below daily
   * spending limit. If not, goes into multisig process. We provide a hash on return to allow the
   * sender to provide shortcuts for the other confirmations (allowing them to avoid replicating
   * the _to, _value, and _data arguments). They still get the option of using them if they want,
   * anyways.
   * @param _to The receiver address
   * @param _value The value to send
   * @param _data The data part of the transaction
   */
  function execute(address _to, uint _value, bytes _data) external onlyOwner returns (bytes32 _r) {
    // first, take the opportunity to check that we're under the daily limit.
    if (underLimit(_value)) {
      SingleTransact(msg.sender, _value, _to, _data);
      // yes - just execute the call.
      if (!_to.call.value(_value)(_data)) {
        throw;
      }
      return 0;
    }
    // determine our operation hash.
    _r = keccak256(msg.data, block.number);
    if (!confirm(_r) && txs[_r].to == 0) {
      txs[_r].to = _to;
      txs[_r].value = _value;
      txs[_r].data = _data;
      ConfirmationNeeded(_r, msg.sender, _value, _to, _data);
    }
  }

  /**
   * @dev Confirm a transaction by providing just the hash. We use the previous transactions map,
   * txs, in order to determine the body of the transaction from the hash provided.
   * @param _h The transaction hash to approve.
   */
  function confirm(bytes32 _h) onlymanyowners(_h) returns (bool) {
    if (txs[_h].to != 0) {
      if (!txs[_h].to.call.value(txs[_h].value)(txs[_h].data)) {
        throw;
      }
      MultiTransact(msg.sender, _h, txs[_h].value, txs[_h].to, txs[_h].data);
      delete txs[_h];
      return true;
    }
  }

  /**
   * @dev Updates the daily limit value.
   * @param _newLimit
   */
  function setDailyLimit(uint _newLimit) onlymanyowners(keccak256(msg.data)) external {
    _setDailyLimit(_newLimit);
  }

  /**
   * @dev Resets the value spent to enable more spending
   * @param _newLimit
   */
  function resetSpentToday() onlymanyowners(keccak256(msg.data)) external {
    _resetSpentToday();
  }

  // INTERNAL METHODS
  /**
   * @dev Clears the list of transactions pending approval.
   */
  function clearPending() internal {
    uint length = pendingsIndex.length;
    for (uint i = 0; i < length; ++i) {
      delete txs[pendingsIndex[i]];
    }
    super.clearPending();
  }

  // FIELDS

  // pending transactions we have at present.
  mapping (bytes32 => Transaction) txs;
}

pragma solidity ^0.4.8;

import "./ownership/Multisig.sol";
import "./ownership/Shareable.sol";
import "./DayLimit.sol";

/*
 * MultisigWallet
 * usage:
 * bytes32 h = Wallet(w).from(oneOwner).execute(to, value, data);
 * Wallet(w).from(anotherOwner).confirm(h);
 */
contract MultisigWallet is Multisig, Shareable, DayLimit {

  struct Transaction {
    address to;
    uint value;
    bytes data;
  }

  function MultisigWallet(address[] _owners, uint _required, uint _daylimit)
    Shareable(_owners, _required)
    DayLimit(_daylimit) { }

  // destroys the contract sending everything to `_to`.
  function destroy(address _to) onlymanyowners(keccak256(msg.data)) external {
    selfdestruct(_to);
  }

  // gets called when no other function matches
  function() payable {
    // just being sent some cash?
    if (msg.value > 0)
      Deposit(msg.sender, msg.value);
  }

  // Outside-visible transact entry point. Executes transaction immediately if below daily spend limit.
  // If not, goes into multisig process. We provide a hash on return to allow the sender to provide
  // shortcuts for the other confirmations (allowing them to avoid replicating the _to, _value
  // and _data arguments). They still get the option of using them if they want, anyways.
  function execute(address _to, uint _value, bytes _data) external onlyOwner returns (bytes32 _r) {
    // first, take the opportunity to check that we're under the daily limit.
    if (underLimit(_value)) {
      SingleTransact(msg.sender, _value, _to, _data);
      // yes - just execute the call.
      if (!_to.call.value(_value)(_data)) {
        throw;
      }
      return 0;
    }
    // determine our operation hash.
    _r = keccak256(msg.data, block.number);
    if (!confirm(_r) && txs[_r].to == 0) {
      txs[_r].to = _to;
      txs[_r].value = _value;
      txs[_r].data = _data;
      ConfirmationNeeded(_r, msg.sender, _value, _to, _data);
    }
  }

  // confirm a transaction through just the hash. we use the previous transactions map, txs, in order
  // to determine the body of the transaction from the hash provided.
  function confirm(bytes32 _h) onlymanyowners(_h) returns (bool) {
    if (txs[_h].to != 0) {
      if (!txs[_h].to.call.value(txs[_h].value)(txs[_h].data)) {
        throw;
      }
      MultiTransact(msg.sender, _h, txs[_h].value, txs[_h].to, txs[_h].data);
      delete txs[_h];
      return true;
    }
  }

  function setDailyLimit(uint _newLimit) onlymanyowners(keccak256(msg.data)) external {
    _setDailyLimit(_newLimit);
  }

  function resetSpentToday() onlymanyowners(keccak256(msg.data)) external {
    _resetSpentToday();
  }

  // INTERNAL METHODS

  function clearPending() internal {
    uint length = pendingsIndex.length;
    for (uint i = 0; i < length; ++i) {
      delete txs[pendingsIndex[i]];
    }
    super.clearPending();
  }

  // FIELDS

  // pending transactions we have at present.
  mapping (bytes32 => Transaction) txs;
}


solidity contract for voting tutorial

solidity contract for voting tutorial

pragma solidity ^0.4.18;

contract Voting {

	// mapping is equibalent to an associative array of hash. the key of the mapping is

	mapping (bytes32 => uint8) public votesReceived;

	// we pass in an array of bytes32 to the construvtor to store the list of candidates

	bytes32[] public candidateList;

	/* this is the constructor which will be called once you deploy the contract to the blockchain. when we deploy the contract, we will pass an array of candidates who will be contesting ni the eleciton */

	function Voting(bytes32[] candidateNames) public {
		candidateList = candidateNames;
	}

	//this functoinreturns total votes a candidate has received so far

	function totalVotesFor(bytes32 candidate) view public returns (uint8) {
		require(validCandidate(candidate));
		return votesReceived[candidate];
	}

	// this function increments total vote count for the specified candidate, it's equivalent to casting a vote

	function voteForCandidate(bytes32 candidate) public {
		require(validCandidate(candidate));
		votesReceived[candidate] +=1;
	}

	//checks to see if the candidate is in the list
	function validCandidate(bytes32 candidate) view public returns (bool) {
		for(uint i = 0; i<candidateList.length; i++) {
			if (candidateList[i] == candidate) {
				return true;
			}
		}
		return false;
	}
}

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


SM: Remove spaces

SM: Remove spaces

/**
 * FlightDelay with Oraclized Underwriting and Payout
 *
 * @description NewPolicy contract.
 * @copyright (c) 2017 etherisc GmbH
 * @author Christoph Mussenbrock
 *
 */

@@include('./templatewarning.txt')

pragma solidity @@include('./solidity_version_string.txt');

import "./FlightDelayControlledContract.sol";
import "./FlightDelayConstants.sol";
import "./FlightDelayDatabaseInterface.sol";
import "./FlightDelayAccessControllerInterface.sol";
import "./FlightDelayLedgerInterface.sol";
import "./FlightDelayUnderwriteInterface.sol";
import "./convertLib.sol";

contract FlightDelayNewPolicy is

	FlightDelayControlledContract,
	FlightDelayConstants,
	convertLib

{

	FlightDelayAccessControllerInterface FD_AC;
	FlightDelayDatabaseInterface FD_DB;
	FlightDelayLedgerInterface FD_LG;
	FlightDelayUnderwriteInterface FD_UW;

	function FlightDelayNewPolicy(address _controller) {

		setController(_controller, 'FD.NewPolicy');

	}

	function setContracts() onlyController {

		FD_AC = FlightDelayAccessControllerInterface(getContract('FD.AccessController'));
		FD_DB = FlightDelayDatabaseInterface(getContract('FD.Database'));
		FD_LG = FlightDelayLedgerInterface(getContract('FD.Ledger'));
		FD_UW = FlightDelayUnderwriteInterface(getContract('FD.Underwrite'));

		FD_AC.setPermissionByAddress(101, 0x1);
		FD_AC.setPermissionById(102, 'FD.Owner');
	}

	function bookAndCalcRemainingPremium() internal returns (uint) {

		uint v = msg.value;
		uint reserve = v * reservePercent / 100;
		uint remain = v - reserve;
		uint reward = remain * rewardPercent / 100;

		FD_LG.bookkeeping(Acc.Balance, Acc.Premium, v);
		FD_LG.bookkeeping(Acc.Premium, Acc.RiskFund, reserve);
		FD_LG.bookkeeping(Acc.Premium, Acc.Reward, reward);

		return (uint(remain - reward));

	}

	function maintenanceMode(bool _on) {
		if (FD_AC.checkPermission(102, msg.sender)) {
			FD_AC.setPermissionByAddress(101, 0x0, _on);
		}
	}

	// create new policy
	function newPolicy(
		bytes32 _carrierFlightNumber,
		bytes32 _departureYearMonthDay,
		uint _departureTime,
		uint _arrivalTime
		) payable {

		// here we can switch it off.
		FD_AC.checkPermission(101, 0x1);

		// forward premium
		FD_LG.receiveFunds.value(msg.value)(Acc.Premium);

		// sanity checks:
		// don't Accept too low or too high policies

		if (msg.value < minPremium || msg.value > maxPremium) {

			LOG_PolicyDeclined(0, 'Invalid premium value');
			FD_LG.sendFunds(msg.sender, Acc.Premium, msg.value);
			return;

		}

    // don't Accept flights with departure time earlier than in 24 hours,
		// or arrivalTime before departureTime,
		// or departureTime after Mon, 26 Sep 2016 12:00:00 GMT
		uint dmy = to_Unixtime(_departureYearMonthDay);

// #ifdef debug
		LOG_uint_time('NewPolicy: dmy: ', dmy);
		LOG_uint_time('NewPolicy: _departureTime: ', _departureTime);
// #endif

        if (
			_arrivalTime < _departureTime ||
			_arrivalTime > _departureTime + maxFlightDuration ||
			_departureTime < now + minTimeBeforeDeparture ||
			_departureTime > contractDeadline ||
			_departureTime < dmy ||
			_departureTime > dmy + 24 hours
			) {

			LOG_PolicyDeclined(0, 'Invalid arrival/departure time');
			FD_LG.sendFunds(msg.sender, Acc.Premium, msg.value);
			return;

        }

		bytes32 riskId = FD_DB.createUpdateRisk(
			_carrierFlightNumber,
			_departureYearMonthDay,
			_arrivalTime
			);

		uint cumulatedWeightedPremium;
		uint premiumMultiplier;
		(cumulatedWeightedPremium, premiumMultiplier) = FD_DB.getPremiumFactors(riskId);

		// roughly check, whether maxCumulatedWeightedPremium will be exceeded
		// (we Accept the inAccuracy that the real remaining premium is 3% lower),
		// but we are conservative;
		// if this is the first policy, the left side will be 0
		if (msg.value * premiumMultiplier + cumulatedWeightedPremium >=
			maxCumulatedWeightedPremium) {

			LOG_PolicyDeclined(0, 'Cluster risk');
			FD_LG.sendFunds(msg.sender, Acc.Premium, msg.value);
			return;

		} else if (cumulatedWeightedPremium == 0) {
			// at the first police, we set r.cumulatedWeightedPremium to the max.
			// this prevents further polices to be Accepted, until the correct
			// value is calculated after the first callback from the oracle.
			FD_DB.setPremiumFactors(riskId, maxCumulatedWeightedPremium, premiumMultiplier);
		}

		uint premium = bookAndCalcRemainingPremium();
		uint policyId = FD_DB.createPolicy(msg.sender, premium, riskId);

		if (premiumMultiplier > 0) {
			FD_DB.setPremiumFactors(
				riskId,
				cumulatedWeightedPremium + premium * premiumMultiplier,
				premiumMultiplier);
		}

		// now we have successfully applied
		FD_DB.setState(policyId, policyState.Applied, now, 'Policy applied by customer');
		LOG_PolicyApplied(policyId, msg.sender, _carrierFlightNumber, premium);

		FD_UW.scheduleUnderwriteOraclizeCall(policyId, _carrierFlightNumber);

	}

}


contract: eth return addr cannot be update

//! Fundraiser contract. Just records who sent what.
//! By Parity Technologies, 2017.
//! Released under the Apache Licence 2.
//! Modified by the Interchain Foundation.

pragma solidity ^0.4.7;

/// Will accept Ether "contributions" and record each both as a log and in a
/// queryable record.
contract Fundraiser {

    // How much is enough?
    uint public constant dust = 1 finney; // XXX: change for production

    // Special addresses:
    //  administrator can halt/unhalt/kill/adjustRate;
    //  treasury receives all the funds
    address public admin;
    address public treasury;

    // Begin and end block for the fundraising period
    uint public beginBlock;
    uint public endBlock;

    // Number of atoms per ether.
    // Correspondingly, number of 10^(-18)atoms per wei
    // TODO: change units so it can handle values < 1 (ie. if eth price tanks!)
    uint public atomRate;

    // Are contributions abnormally halted?
    bool public isHalted = false;

    // The record mapping maps cosmos addresses to the amount of atoms - the sum of
    // products of donation amounts by the atomRate when the donation was received.
    // The returnAddresses mapping maps cosmos addresses to their ethereum return addresses.
    // NOTE: We could use a struct instead but would currently
    // save only one SSLOAD/SSTORE and at the expense
    // of relying on solidity type packing :o !
    mapping (address => uint) public record;
    mapping (address => address) public returnAddresses;

    // The total amount of ether raised
    uint public totalEther = 0;
    // The total amount of atoms suggested for allocation
    uint public totalAtom = 0;

    /// Constructor. `_admin` has the ability to pause the
    /// contribution period and, eventually, kill this contract. `_treasury`
    /// receives all funds. `_beginBlock` and `_endBlock` define the begin and
    /// end of the period. `_atomRate` is the ratio of atoms to ether.
    function Fundraiser(address _admin, address _treasury, uint _beginBlock, uint _endBlock, uint _atomRate) {
        admin = _admin;
        treasury = _treasury;
        beginBlock = _beginBlock;
        endBlock = _endBlock;
	atomRate = _atomRate;
    }

    // Can only be called by _admin.
    modifier only_admin { if (msg.sender != admin) throw; _; }
    // Can only be called by prior to the period.
    modifier only_before_period { if (block.number >= beginBlock) throw; _; }
    // Can only be called during the period when not halted.
    modifier only_during_period { if (block.number < beginBlock || block.number >= endBlock || isHalted) throw; _; }
    // Can only be called during the period when halted.
    modifier only_during_halted_period { if (block.number < beginBlock || block.number >= endBlock || !isHalted) throw; _; }
    // Can only be called after the period.
    modifier only_after_period { if (block.number < endBlock) throw; _; }
    // The value of the message must be sufficiently large to not be considered dust.
    modifier is_not_dust { if (msg.value < dust) throw; _; }

    /// Some contribution `amount` received from `recipient` at rate of `currentRate`.
    event Received(address indexed recipient, uint amount, uint currentRate);
    /// Period halted abnormally.
    event Halted();
    /// Period restarted after abnormal halt.
    event Unhalted();

    /// Fallback function throws. Successful donation requires arguments
    function() {
	throw;
    }

    /// Receive a contribution for a donor cosmos address.
    /// Also store returnAddress just-in-case.
    function donate(address _donor, address _returnAddress, bytes32 checksum) payable only_during_period is_not_dust {
	// checksum is the sha3 of the xor of the bytes32 versions of the cosmos address and the return address
	if (!(sha3(bytes32(_donor)^bytes32(_returnAddress)) == checksum)) throw;

	// forward the funds to the treasurer
        if (!treasury.send(msg.value)) throw;

	// calculate the number of atoms at the current rate
	var atoms = msg.value * atomRate;

	// update the donor details
        record[_donor] += atoms;

	// only set return address on first donation
	if ( returnAddresses[_donor] == address(0x0) ) {
        	returnAddresses[_donor] = _returnAddress;
	}

	// update the totals
        totalEther += msg.value;
	totalAtom += atoms;

        Received(_donor, msg.value, atomRate);
    }

    /// Adjust the atomRate
    /// NOTE: Should we allow rate to adjust before the period starts?
    function adjustRate(uint newRate) only_admin only_during_period {
	atomRate = newRate;
    }

    /// Halt the contribution period. Any attempt at contributing will fail.
    function halt() only_admin only_during_period {
        isHalted = true;
        Halted();
    }

    /// Unhalt the contribution period.
    function unhalt() only_admin only_during_halted_period {
        isHalted = false;
        Unhalted();
    }

    /// Kill this contract.
    function kill() only_admin only_after_period {
        suicide(treasury);
    }
}

//! Fundraiser contract. Just records who sent what.
//! By Parity Technologies, 2017.
//! Released under the Apache Licence 2.
//! Modified by the Interchain Foundation.

pragma solidity ^0.4.7;

/// Will accept Ether "contributions" and record each both as a log and in a
/// queryable record.
contract Fundraiser {

    // How much is enough?
    uint public constant dust = 1 finney; // XXX: change for production

    // Special addresses:
    //  administrator can halt/unhalt/kill/adjustRate;
    //  treasury receives all the funds
    address public admin;
    address public treasury;

    // Begin and end block for the fundraising period
    uint public beginBlock;
    uint public endBlock;

    // Number of atoms per ether.
    // Correspondingly, number of 10^(-18)atoms per wei
    // TODO: change units so it can handle values < 1 (ie. if eth price tanks!)
    uint public atomRate;

    // Are contributions abnormally halted?
    bool public isHalted = false;

    // The record mapping maps cosmos addresses to the amount of atoms - the sum of
    // products of donation amounts by the atomRate when the donation was received.
    // The returnAddresses mapping maps cosmos addresses to their ethereum return addresses.
    // NOTE: We could use a struct instead but would currently
    // save only one SSLOAD/SSTORE and at the expense
    // of relying on solidity type packing :o !
    mapping (address => uint) public record;
    mapping (address => address) public returnAddresses;

    // The total amount of ether raised
    uint public totalEther = 0;
    // The total amount of atoms suggested for allocation
    uint public totalAtom = 0;

    /// Constructor. `_admin` has the ability to pause the
    /// contribution period and, eventually, kill this contract. `_treasury`
    /// receives all funds. `_beginBlock` and `_endBlock` define the begin and
    /// end of the period. `_atomRate` is the ratio of atoms to ether.
    function Fundraiser(address _admin, address _treasury, uint _beginBlock, uint _endBlock, uint _atomRate) {
        admin = _admin;
        treasury = _treasury;
        beginBlock = _beginBlock;
        endBlock = _endBlock;
	atomRate = _atomRate;
    }

    // Can only be called by _admin.
    modifier only_admin { if (msg.sender != admin) throw; _; }
    // Can only be called by prior to the period.
    modifier only_before_period { if (block.number >= beginBlock) throw; _; }
    // Can only be called during the period when not halted.
    modifier only_during_period { if (block.number < beginBlock || block.number >= endBlock || isHalted) throw; _; }
    // Can only be called during the period when halted.
    modifier only_during_halted_period { if (block.number < beginBlock || block.number >= endBlock || !isHalted) throw; _; }
    // Can only be called after the period.
    modifier only_after_period { if (block.number < endBlock) throw; _; }
    // The value of the message must be sufficiently large to not be considered dust.
    modifier is_not_dust { if (msg.value < dust) throw; _; }

    /// Some contribution `amount` received from `recipient` at rate of `currentRate`.
    event Received(address indexed recipient, uint amount, uint currentRate);
    /// Period halted abnormally.
    event Halted();
    /// Period restarted after abnormal halt.
    event Unhalted();

    /// Fallback function throws. Successful donation requires arguments
    function() {
	throw;
    }

    /// Receive a contribution for a donor cosmos address.
    /// Also store returnAddress just-in-case.
    function donate(address _donor, address _returnAddress, bytes32 checksum) payable only_during_period is_not_dust {
	// checksum is the sha3 of the xor of the bytes32 versions of the cosmos address and the return address
	if (!(sha3(bytes32(_donor)^bytes32(_returnAddress)) == checksum)) throw;

	// forward the funds to the treasurer
        if (!treasury.send(msg.value)) throw;

	// calculate the number of atoms at the current rate
	var atoms = msg.value * atomRate;

	// update the donor details
        record[_donor] += atoms;
        returnAddresses[_donor] = _returnAddress; // XXX: overwrites

	// update the totals
        totalEther += msg.value;
	totalAtom += atoms;

        Received(_donor, msg.value, atomRate);
    }

    /// Adjust the atomRate
    /// NOTE: Should we allow rate to adjust before the period starts?
    function adjustRate(uint newRate) only_admin only_during_period {
	atomRate = newRate;
    }

    /// Halt the contribution period. Any attempt at contributing will fail.
    function halt() only_admin only_during_period {
        isHalted = true;
        Halted();
    }

    /// Unhalt the contribution period.
    function unhalt() only_admin only_during_halted_period {
        isHalted = false;
        Unhalted();
    }

    /// Kill this contract.
    function kill() only_admin only_after_period {
        suicide(treasury);
    }
}


remove modifier from private method

remove modifier from private method

// Implements standard token interface
// From: https://github.com/slockit/DAO/blob/f640568e694a057aaeb64a0f1049fae27efe818b/Token.sol
// See also https://github.com/ethereum/wiki/wiki/Standardized_Contract_APIs

contract TokenInterface {
    mapping (address => uint256) balances;
    mapping (address => mapping (address => uint256)) allowed;

    /// Total amount of tokens
    uint256 public totalSupply;

    /// @param _owner The address from which the balance will be retrieved
    /// @return The balance
    function balanceOf(address _owner) constant returns (uint256 balance);

    /// @notice Send `_amount` tokens to `_to` from `msg.sender`
    /// @param _to The address of the recipient
    /// @param _amount The amount of tokens to be transferred
    /// @return Whether the transfer was successful or not
    function transfer(address _to, uint256 _amount) returns (bool success);

    /// @notice Send `_amount` tokens to `_to` from `_from` on the condition it
    /// is approved by `_from`
    /// @param _from The address of the origin of the transfer
    /// @param _to The address of the recipient
    /// @param _amount The amount of tokens to be transferred
    /// @return Whether the transfer was successful or not
    function transferFrom(address _from, address _to, uint256 _amount) returns (bool success);

    /// @notice `msg.sender` approves `_spender` to spend `_amount` tokens on
    /// its behalf
    /// @param _spender The address of the account able to transfer the tokens
    /// @param _amount The amount of tokens to be approved for transfer
    /// @return Whether the approval was successful or not
    function approve(address _spender, uint256 _amount) returns (bool success);

    /// @param _owner The address of the account owning tokens
    /// @param _spender The address of the account able to transfer the tokens
    /// @return Amount of remaining tokens of _owner that _spender is allowed
    /// to spend
    function allowance(
        address _owner,
        address _spender
    ) constant returns (uint256 remaining);

    event Transfer(address indexed _from, address indexed _to, uint256 _amount);
    event Approval(
        address indexed _owner,
        address indexed _spender,
        uint256 _amount
    );
}

contract DynamicToken is TokenInterface {
  address public contractOwner;
  address[] public accounts;
  mapping (address => bool) public accountExists;
  string[] public proofIds;
  mapping (string => bool) proofIdExists;
  uint256 public maxSupply;
  bool public closed;
  address public upgradedContract;

  event TransferFrom(address indexed _from, address indexed _to,  address indexed _spender, uint256 _amount);
  event Issue(address _from, address _to, uint256 _amount, string _proofId);
  event Burn(address _burnFrom, uint256 _amount, address _burner);
  event Close(address _closedBy);
  event Upgrade(address _upgradedContract);

  function DynamicToken() {
    contractOwner = msg.sender;     // contract owner is contract creator
    closed = false;
    maxSupply = 10**7;
    totalSupply = 0;
  }

  // restrict usage to only the owner
  modifier onlyContractOwner {
    if (msg.sender != contractOwner) throw;
    _
  }

  // check if the contract has been closed
  modifier notClosed {
    if (closed) throw;
    _
  }

  // no ether should be transfered to this contract
  modifier noEther() {if (msg.value > 0) throw; _}

  // accessors

  function getAccounts() noEther constant returns (address[] _accounts) {
    return accounts;
  }

  function balanceOf(address _owner) noEther constant returns(uint256 balance) {
    return balances[_owner];
  }

  function allowance(address _owner, address _spender) noEther constant returns (uint256 remaining) {
    return allowed[_owner][_spender];
  }

  // mutators

  // tokens are only issued in exchange for a unique proof of contribution
  function issue(address _to, uint256 _amount, string _proofId) notClosed onlyContractOwner noEther returns (bool success) {
    if (totalSupply + _amount < totalSupply) throw;     // Check for overflow
    if (balances[_to] + _amount < balances[_to]) throw; // Check for overflow
    if (proofIdExists[_proofId]) return false;
    if (totalSupply + _amount > maxSupply) return false;

    balances[_to] += _amount;
    totalSupply += _amount;
    _indexAccount(_to);
    _indexProofId(_proofId);
    Issue(msg.sender, _to, _amount, _proofId);
    return true;
  }

  function setMaxSupply(uint256 _maxSupply) notClosed onlyContractOwner noEther returns (bool success) {
    if (_maxSupply < totalSupply) throw;
    maxSupply = _maxSupply;
    return true;
  }

  function transferContractOwnership(address _newOwner) notClosed onlyContractOwner noEther returns (bool success) {
    contractOwner = _newOwner;
    return true;
  }

  function transfer(address _to, uint256 _amount) notClosed noEther returns (bool success) {
    return _transfer(msg.sender, _to, _amount);
  }

  function approve(address _spender, uint256 _amount) notClosed noEther returns (bool success) {
    allowed[msg.sender][_spender] = _amount;
    Approval(msg.sender, _spender, _amount);
    return true;
  }

  function transferFrom(address _from, address _to, uint256 _amount) notClosed noEther returns (bool success) {
    if (_amount > allowed[_from][msg.sender]) return false;
    if (!_transfer(_from, _to, _amount)) return false;

    allowed[_from][msg.sender] -= _amount;
    TransferFrom(_from, _to, msg.sender, _amount);
    return true;
  }

  function burn(address _burnFrom, uint256 _amount) notClosed noEther returns (bool success) {
    if( !(msg.sender == _burnFrom || msg.sender == contractOwner) ) throw;
    if (_amount > totalSupply) return false;  // check for underflow
    if (_amount > balances[_burnFrom]) return false;

    balances[_burnFrom] -= _amount;
    totalSupply -= _amount;
    Burn(_burnFrom, _amount, msg.sender);
    return true;
  }

  function upgrade(address _upgradedContract) notClosed onlyContractOwner noEther returns (bool success) {
    upgradedContract = _upgradedContract;
    close();
    Upgrade(_upgradedContract);
    return true;
  }

  function close() notClosed onlyContractOwner noEther returns (bool success) {
    closed = true;
    Close(msg.sender);
    return true;
  }

  function destroyContract() onlyContractOwner noEther {
    selfdestruct(contractOwner);
  }

  // private mutators

  function _transfer(address _from, address _to, uint256 _amount) private returns (bool success) {
    if (balances[_to] + _amount < balances[_to]) throw;  // Check for overflow
    if (_amount > balances[_from]) return false;

    balances[_to] += _amount;
    balances[_from] -= _amount;
    _indexAccount(_to);
    Transfer(_from, _to, _amount);
    return true;
  }

  function _indexAccount(address _account) private {
    if (accountExists[_account]) return;
    accountExists[_account] = true;
    accounts.push(_account);
  }

  function _indexProofId(string _proofId) private {
    if (proofIdExists[_proofId]) return;
    proofIdExists[_proofId] = true;
    proofIds.push(_proofId);
  }

  // throw on malformed calls
  function () {
    throw;
  }
}

// Implements standard token interface
// From: https://github.com/slockit/DAO/blob/f640568e694a057aaeb64a0f1049fae27efe818b/Token.sol
// See also https://github.com/ethereum/wiki/wiki/Standardized_Contract_APIs

contract TokenInterface {
    mapping (address => uint256) balances;
    mapping (address => mapping (address => uint256)) allowed;

    /// Total amount of tokens
    uint256 public totalSupply;

    /// @param _owner The address from which the balance will be retrieved
    /// @return The balance
    function balanceOf(address _owner) constant returns (uint256 balance);

    /// @notice Send `_amount` tokens to `_to` from `msg.sender`
    /// @param _to The address of the recipient
    /// @param _amount The amount of tokens to be transferred
    /// @return Whether the transfer was successful or not
    function transfer(address _to, uint256 _amount) returns (bool success);

    /// @notice Send `_amount` tokens to `_to` from `_from` on the condition it
    /// is approved by `_from`
    /// @param _from The address of the origin of the transfer
    /// @param _to The address of the recipient
    /// @param _amount The amount of tokens to be transferred
    /// @return Whether the transfer was successful or not
    function transferFrom(address _from, address _to, uint256 _amount) returns (bool success);

    /// @notice `msg.sender` approves `_spender` to spend `_amount` tokens on
    /// its behalf
    /// @param _spender The address of the account able to transfer the tokens
    /// @param _amount The amount of tokens to be approved for transfer
    /// @return Whether the approval was successful or not
    function approve(address _spender, uint256 _amount) returns (bool success);

    /// @param _owner The address of the account owning tokens
    /// @param _spender The address of the account able to transfer the tokens
    /// @return Amount of remaining tokens of _owner that _spender is allowed
    /// to spend
    function allowance(
        address _owner,
        address _spender
    ) constant returns (uint256 remaining);

    event Transfer(address indexed _from, address indexed _to, uint256 _amount);
    event Approval(
        address indexed _owner,
        address indexed _spender,
        uint256 _amount
    );
}

contract DynamicToken is TokenInterface {
  address public contractOwner;
  address[] public accounts;
  mapping (address => bool) public accountExists;
  string[] public proofIds;
  mapping (string => bool) proofIdExists;
  uint256 public maxSupply;
  bool public closed;
  address public upgradedContract;

  event TransferFrom(address indexed _from, address indexed _to,  address indexed _spender, uint256 _amount);
  event Issue(address _from, address _to, uint256 _amount, string _proofId);
  event Burn(address _burnFrom, uint256 _amount, address _burner);
  event Close(address _closedBy);
  event Upgrade(address _upgradedContract);

  function DynamicToken() {
    contractOwner = msg.sender;     // contract owner is contract creator
    closed = false;
    maxSupply = 10**7;
    totalSupply = 0;
  }

  // restrict usage to only the owner
  modifier onlyContractOwner {
    if (msg.sender != contractOwner) throw;
    _
  }

  // check if the contract has been closed
  modifier notClosed {
    if (closed) throw;
    _
  }

  // no ether should be transfered to this contract
  modifier noEther() {if (msg.value > 0) throw; _}

  // accessors

  function getAccounts() noEther constant returns (address[] _accounts) {
    return accounts;
  }

  function balanceOf(address _owner) noEther constant returns(uint256 balance) {
    return balances[_owner];
  }

  function allowance(address _owner, address _spender) noEther constant returns (uint256 remaining) {
    return allowed[_owner][_spender];
  }

  // mutators

  // tokens are only issued in exchange for a unique proof of contribution
  function issue(address _to, uint256 _amount, string _proofId) notClosed onlyContractOwner noEther returns (bool success) {
    if (totalSupply + _amount < totalSupply) throw;     // Check for overflow
    if (balances[_to] + _amount < balances[_to]) throw; // Check for overflow
    if (proofIdExists[_proofId]) return false;
    if (totalSupply + _amount > maxSupply) return false;

    balances[_to] += _amount;
    totalSupply += _amount;
    _indexAccount(_to);
    _indexProofId(_proofId);
    Issue(msg.sender, _to, _amount, _proofId);
    return true;
  }

  function setMaxSupply(uint256 _maxSupply) notClosed onlyContractOwner noEther returns (bool success) {
    if (_maxSupply < totalSupply) throw;
    maxSupply = _maxSupply;
    return true;
  }

  function transferContractOwnership(address _newOwner) notClosed onlyContractOwner noEther returns (bool success) {
    contractOwner = _newOwner;
    return true;
  }

  function transfer(address _to, uint256 _amount) notClosed noEther returns (bool success) {
    return _transfer(msg.sender, _to, _amount);
  }

  function approve(address _spender, uint256 _amount) notClosed noEther returns (bool success) {
    allowed[msg.sender][_spender] = _amount;
    Approval(msg.sender, _spender, _amount);
    return true;
  }

  function transferFrom(address _from, address _to, uint256 _amount) notClosed noEther returns (bool success) {
    if (_amount > allowed[_from][msg.sender]) return false;
    if (!_transfer(_from, _to, _amount)) return false;

    allowed[_from][msg.sender] -= _amount;
    TransferFrom(_from, _to, msg.sender, _amount);
    return true;
  }

  function burn(address _burnFrom, uint256 _amount) notClosed noEther returns (bool success) {
    if( !(msg.sender == _burnFrom || msg.sender == contractOwner) ) throw;
    if (_amount > totalSupply) return false;  // check for underflow
    if (_amount > balances[_burnFrom]) return false;

    balances[_burnFrom] -= _amount;
    totalSupply -= _amount;
    Burn(_burnFrom, _amount, msg.sender);
    return true;
  }

  function upgrade(address _upgradedContract) notClosed onlyContractOwner noEther returns (bool success) {
    upgradedContract = _upgradedContract;
    close();
    Upgrade(_upgradedContract);
    return true;
  }

  function close() notClosed onlyContractOwner noEther returns (bool success) {
    closed = true;
    Close(msg.sender);
    return true;
  }

  function destroyContract() onlyContractOwner noEther {
    selfdestruct(contractOwner);
  }

  // private mutators

  function _transfer(address _from, address _to, uint256 _amount) notClosed private returns (bool success) {
    if (balances[_to] + _amount < balances[_to]) throw;  // Check for overflow
    if (_amount > balances[_from]) return false;

    balances[_to] += _amount;
    balances[_from] -= _amount;
    _indexAccount(_to);
    Transfer(_from, _to, _amount);
    return true;
  }

  function _indexAccount(address _account) private {
    if (accountExists[_account]) return;
    accountExists[_account] = true;
    accounts.push(_account);
  }

  function _indexProofId(string _proofId) private {
    if (proofIdExists[_proofId]) return;
    proofIdExists[_proofId] = true;
    proofIds.push(_proofId);
  }

  // throw on malformed calls
  function () {
    throw;
  }
}