combine Proposals to appPool

combine Proposals to appPool

pragma solidity ^0.4.11;
//import "./StandardToken.sol";
// import "./PartialLockVoting.sol";
// import "./Parametrizer.sol";

// to do:
// implement events
// keep deposit if never challenged (?) if win (?)

contract Registry {

    /*
     * Storage
     */

    //Registry storage
    //StandardToken public token;
    mapping(bytes32 => Publisher) public whitelist;
    mapping(bytes32 => Application) public appPool; //holds applications for both domain and parameter appPool
    mapping(uint => bool) public voteProcessed;
    mapping(address => mapping(uint => bool)) public voterInfo;
    string domain;
    //Parameter storage
    mapping(bytes32 => uint) public Parameters;
    mapping(uint => Application) public idToApplications;
    string parameter;
    uint value;

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

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

        string domain;
        string parameter;
        uint value;
    }

    struct Param {
        // 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;
    }

    // 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,
       uint _minDeposit,
       uint _challengeLen,
       uint _registryLen,
       uint _commitVoteLen,
       uint _revealVoteLen,
       uint _dispensationPct,
       uint _majority) {

       token = StandardToken(_token);
       // 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 apply (moves them into the application pool on success)
    function apply(string _domain) {
        bytes32 domainHash = sha3(_domain);
        // applicant must pay the current value of minDeposit
        uint deposit = get("minDeposit");
        // check to prevent repeat applications
        require(appPool[domainHash].owner == 0);
        // check that registry can take sufficient amount of tokens from the applicant
        require(token.allowance(msg.sender, this) >= deposit);
        token.transferFrom(msg.sender, this, deposit);
        // initialize application with a snapshot with the current values of all parameters
        initializeSnapshot(_domain);
        appPool[domainHash].challengeTime = now + appPool[domainHash].snapshot.challengeLen;
        appPool[domainHash].owner = msg.sender;
    }

    // called by any adtoken holder to challenge an application to the whitelist and start a vote
    function challenge(string _domain) {
        bytes32 domainHash = sha3(_domain);
        // check that registry can take sufficient amount of tokens from the challenger
        uint deposit = appPool[domainHash].snapshot.minDeposit;
        require(token.allowance(msg.sender, this) >= deposit);
        token.transferFrom(msg.sender, this, deposit);
        // prevent someone from challenging an unintialized application, rechallenging,
        // or challenging after the challenge period has ended
        require(appPool[domainHash].owner != 0);
        require(appPool[domainHash].challenged == false);
        require(appPool[domainHash].challengeTime > now);
        // update the application's status
        appPool[domainHash].challenged = true;
        appPool[domainHash].challenger = msg.sender;
        appPool[domainHash].domain = _domain;
        // start a vote
        // uint pollID = callVote(voting params);
        // idToApplications[pollID] = appPool[domainHash];
    }

    // helper function to the challenge() function. Initializes a vote through the voting contract
    // returns a poll id
    function callVote(bytes32 _domainHash) private returns (uint) {
        // event that vote has started
        // ??
    }

    // a one-time function for each completed vote
    // if domain won: domain is moved to the whitelist and applicant is rewarded tokens
    // if domain lost: challenger is rewarded tokens
    function processResult(uint _pollID)
    {
        require(voteProcessed[_pollID] == false);
        domain = idToApplications[_pollID].domain;
        bytes32 domainHash = sha3(domain);
        if (didProposalPass(_pollID)) {
            //??what would happen if didProposalPass() called and vote's still ongoing??
            // add to registry
            add(domain, appPool[domainHash].owner);
            delete appPool[domainHash].owner;
            // give tokens to applicant based on dist and total tokens
        }
        else {
            delete appPool[domainHash].owner;
            uint minDeposit = appPool[domainHash].snapshot.minDeposit;
            uint dispensationPct = appPool[domainHash].snapshot.dispensationPct;
            uint winning = deposit * dispensationPct;
            tokens.transfer(appPool[domainHash].challenger, winning + deposit);
            // check math
        }
        // ensures the result cannot be processed again
        voteProcessed[_pollID] = true;
    }

    // called by each voter to claim their reward for each completed vote
    function claimReward(uint _pollID, uint _salt) {
        // checks if a voter has claimed tokens
        require(voterInfo[msg.sender][_pollID] == false);
        uint reward = giveTokens(_pollID, _salt);
        // ensures a voter cannot claim tokens again
        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) returns(uint) {
        domain = idToApplications[_pollID].domain;
        bytes32 domainHash = sha3(domain);
        uint minDeposit = appPool[domainHash].snapshot[minDeposit];
        uint dispensationPct = appPool[domainHash].snapshot[dispensationPct];
        uint totalTokens = getTotalNumberOfTokensForWinningOption(_pollID);
        uint voterTokens = getNumCorrectInvestment(_pollID, _salt);
        uint reward = voterTokens*minDeposit*(1-dispensationPct)/totalTokens;
        return 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) {
        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(_domain, appPool[domainHash].owner);
        delete appPool[domainHash].owner;
    }

    // private function to add a domain name to the whitelist
    function add(string _domain, address _owner)  {
        bytes32 domainHash = sha3(_domain);
        uint expiration = appPool[domainHash].snapshot.registryLen;
        whitelist[domainHash].expTime = now + expiration;
        whitelist[domainHash].owner = _owner;
        whitelist[domainHash].deposit = appPool[domainHash].snapshot.minDeposit;
    }

    // checks if a domain name is in the whitelist and unexpired
    function isVerified(string _domain) returns (bool) {
        bytes32 domainHash = sha3(_domain);
        if (whitelist[domainHash].expTime > now) {
            return true;
        }
        else {
            return false;
        }
    }

    // private function to initialize a snapshot of parameters for each application
    function initializeSnapshot(string _domain) {
        bytes32 domainHash = sha3(_domain);
        appPool[domainHash].snapshot.minDeposit = get("minDeposit");
        appPool[domainHash].snapshot.challengeLen = get("challengeLen");
        appPool[domainHash].snapshot.registryLen = get("registryLen");
        appPool[domainHash].snapshot.commitVoteLen = get("commitVoteLen");
        appPool[domainHash].snapshot.revealVoteLen = get("revealVoteLen");
        appPool[domainHash].snapshot.majority = get("majority");
        appPool[domainHash].snapshot.dispensationPct = get("dispensationPct");
    }

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

    //called by a user who wishes to change a parameter
    //initializes a proposal to change a parameter
    function proposeUpdate(string _parameter, uint _value) {
        bytes32 parameterHash = sha3(_parameter, _value);
        // applicant must pay the current value of minDeposit
        uint deposit = get("minDeposit");
        // check that registry can take sufficient amount of tokens from the applicant
        require(token.allowance(msg.sender, this) >= deposit);
        token.transferFrom(msg.sender, this, deposit);
        // initialize application with a snapshot with the current values of all parameters
        initializeSnapshotParam(parameterHash);
        uint challengeLen = appPool[parameterHash].snapshot[challengeLen];
        appPool[parameterHash].challengeTime= now + challengeLen;
        appPool[parameterHash].owner = msg.sender;

    }

    //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) {
        bytes32 parameterHash = sha3(_parameter, _value);

        // check that registry can take sufficient amount of tokens from the challenger
        uint deposit = appPool[parameterHash].snapshot.minDeposit;
        require(token.allowance(msg.sender, this) >= deposit);
        token.transferFrom(msg.sender, this, deposit);

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

        // update the application's status
        appPool[parameterHash].challenged = true;
        appPool[parameterHash].challenger = msg.sender;
        appPool[parameterHash].parameter = _parameter;
        appPool[parameterHash].value = _value;
        // start a vote
        // pollID = callVote(voting params);
        // idToApplications[pollID] = appPool[parameterHash];
    }

    // called to change parameter
    // iff the proposal's challenge period has passed without a challenge
    function setParams(string _parameter, uint _value) {
        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
    // if prospsal lost: challenger is rewarded tokens
    function processProposal(uint _pollID)
    {
        require(voteProcessed[_pollID] == false);
        parameter = idToApplications[_pollID].parameter;
        value = idToApplications[_pollID].value;
        bytes32 parameterHash = sha3(parameter, value);
        if (didProposalPass(_pollID)) {
            //??what would happen if didProposalPass() called and vote's still ongoing??
            // setting the value of parameter
            Parameters[sha3(parameter)] = value;
            delete appPool[parameterHash].owner;
            // give tokens to applicant based on dist and total tokens
        }
        else {
            delete appPool[parameterHash].owner;
            // give tokens to challenger based on dist and total tokens
        }
        // ensures the result cannot be processed again
        voteProcessed[_pollID] = true;
    }

    function claimParamReward(uint _pollID, uint _salt) {
        // checks if a voter has claimed tokens
        require(voterInfo[msg.sender][_pollID] == false);
        uint reward = giveTokens(_pollID, _salt);
        // ensures a voter cannot claim tokens again
        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 giveParamTokens(uint _pollID, uint _salt) returns(uint) {
        parameter = idToApplications[_pollID].parameter;
        value = idToApplications[_pollID].value;
        bytes32 parameterHash = sha3(parameter, value);
        uint minDeposit = appPool[parameterHash].snapshot[minDeposit];
        uint dispensationPct = appPool[parameterHash].snapshot[dispensationPct];
        uint totalTokens = getTotalNumberOfTokensForWinningOption(_pollID);
        uint voterTokens = getNumCorrectInvestment(_pollID, _salt);

        uint reward = voterTokens*minDeposit*(1-dispensationPct)/totalTokens;
        return reward;
    }

     // private function to initialize a snapshot of parameters for each proposal
     function initializeSnapshotParam(bytes32 _hash) {
        appPool[_hash].snapshot.minDeposit = get("minDeposit");
        appPool[_hash].snapshot.challengeLen = get("challengeLen");
        appPool[_hash].snapshot.commitVoteLen = get("commitVoteLen");
        appPool[_hash].snapshot.revealVoteLen = get("revealVoteLen");
        appPool[_hash].snapshot.majority = get("majority");
        appPool[_hash].snapshot.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) returns (uint) {
       return Parameters[sha3(_keyword)];
    }

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

    // FOR TESTING
    function toHash(string _domain) returns (bytes32){
        return sha3(_domain);
    }
    function getCurrentTime() returns (uint){
        return now;
    }

}

pragma solidity ^0.4.11;
//import "./StandardToken.sol";
// import "./PartialLockVoting.sol";
// import "./Parametrizer.sol";

// to do:
// implement events
// check on delete in solidity
// keep deposit if never challenged (?) if win (?)

contract Registry {

    /*
     * Storage
     */

    //Registry storage
    StandardToken public token;
    mapping(bytes32 => Publisher) public whitelist;
    mapping(bytes32 => Application) public appPool;
    mapping(uint => bool) public voteProcessed;
    mapping(address => mapping(uint => bool)) public voterInfo;
    //Parameter storage
    mapping(bytes32 => Application) public Proposals; // similar to appPool
    mapping(bytes32 => uint) public Parameters;

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

    struct Application {
        address owner;
        bool challenged;
        uint challengeTime; //End of challenge period
        address challenger;
        Param snapshot;
    }

    struct Param {
        // 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;
    }

    // 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,
       uint _minDeposit,
       uint _challengeLen,
       uint _registryLen,
       uint _commitVoteLen,
       uint _revealVoteLen,
       uint _dispensationPct,
       uint _majority) {

       token = StandardToken(_token);
       // 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 apply (moves them into the application pool on success)
    function apply(string _domain) {
        bytes32 domainHash = sha3(_domain);
        // applicant must pay the current value of minDeposit
        uint deposit = get("minDeposit");
        // check to prevent repeat applications
        require(appPool[domainHash].owner == 0);
        // check that registry can take sufficient amount of tokens from the applicant
        require(token.allowance(msg.sender, this) >= deposit);
        token.transferFrom(msg.sender, this, deposit);
        // initialize application with a snapshot with the current values of all parameters
        initializeSnapshot(_domain);
        appPool[domainHash].challengeTime = now + appPool[domainHash].snapshot.challengeLen;
        appPool[domainHash].owner = msg.sender;
    }

    // called by any adtoken holder to challenge an application to the whitelist and start a vote
    function challenge(string _domain) {
        bytes32 domainHash = sha3(_domain);
        // check that registry can take sufficient amount of tokens from the challenger
        uint deposit = appPool[domainHash].snapshot.minDeposit;
        require(token.allowance(msg.sender, this) >= deposit);
        token.transferFrom(msg.sender, this, deposit);
        // prevent someone from challenging an unintialized application, rechallenging,
        // or challenging after the challenge period has ended
        require(appPool[domainHash].owner != 0);
        require(appPool[domainHash].challenged == false);
        require(appPool[domainHash].challengeTime > now);
        // update the application's status
        appPool[domainHash].challenged = true;
        appPool[domainHash].challenger = msg.sender;
        // start a vote
        // poll ID = callVote(voting params);
    }

    // helper function to the challenge() function. Initializes a vote through the voting contract
    function callVote(bytes32 _domainHash) private returns (bool) {
        // event that vote has started
        // ??
    }

    // a one-time function for each completed vote
    // if domain won: domain is moved to the whitelist and applicant is rewarded tokens
    // if domain lost: challenger is rewarded tokens
    function processResult(uint _pollID)
    {
        require(voteProcessed[_pollID] == false);
        // string domain = ??;
        bytes32 domainHash = sha3(domain);
        if (didProposalPass(_pollID)) {
            //??what would happen if didProposalPass() called and vote's still ongoing??
            // add to registry
            add(domain, appPool[domainHash].owner);
            delete appPool[domainHash].owner;
            // give tokens to applicant based on dist and total tokens
        }
        else {
            delete appPool[domainHash].owner;
            deposit = appPool[domainHash].snapshot[minDeposit];
            winning = appPool[domainHash].snapshot[minDeposit]*appPool[domainHash].snapshot[dispensationPct];
            tokens.transfer(appPool[domainHash].challenger, winning+ deposit);
            // check math
        }
        // ensures the result cannot be processed again
        voteProcessed[_pollID] = true;
    }

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

    // called to move an applying domain to the whitelist
    // iff the domain's challenge period has passed without a challenge
    function moveToRegistry(string _domain) {
        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(_domain, appPool[domainHash].owner);
        delete appPool[domainHash].owner;
    }

    // private function to add a domain name to the whitelist
    function add(string _domain, address _owner)  {
        bytes32 domainHash = sha3(_domain);
        uint expiration = appPool[domainHash].snapshot.registryLen;
        whitelist[domainHash].expTime = now + expiration;
        whitelist[domainHash].owner = _owner;
        whitelist[domainHash].deposit = appPool[domainHash].snapshot.minDeposit;
    }

    // checks if a domain name is in the whitelist and unexpired
    function isVerified(string _domain) returns (bool) {
        bytes32 domainHash = sha3(_domain);
        if (whitelist[domainHash].expTime > now) {
            return true;
        }
        else {
            return false;
        }
    }

    // private function to initialize a snapshot of parameters for each application
    function initializeSnapshot(string _domain) {
        bytes32 domainHash = sha3(_domain);
        appPool[domainHash].snapshot.minDeposit = get("minDeposit");
        appPool[domainHash].snapshot.challengeLen = get("challengeLen");
        appPool[domainHash].snapshot.registryLen = get("registryLen");
        appPool[domainHash].snapshot.commitVoteLen = get("commitVoteLen");
        appPool[domainHash].snapshot.revealVoteLen = get("revealVoteLen");
        appPool[domainHash].snapshot.majority = get("majority");
        appPool[domainHash].snapshot.dispensationPct = get("dispensationPct");
    }

    function giveTokens(uint _pollID, uint _salt) returns(uint) {
        // number of tokens person used to vote / total number of tokens for winning side
        // scale using distribution number
        // give the tokens
        // string domain = ??
        bytes32 domainHash = sha3(domain);
        uint minDeposit = appPool[domainHash].snapshot[minDeposit];
        uint dispensationPct = appPool[domainHash].snapshot[dispensationPct];
        uint totalTokens = getTotalNumberOfTokensForWinningOption(_pollID);
        uint voterTokens = getNumCorrectInvestment(_pollID, _salt);

        uint reward = voterTokens*minDeposit*(1-dispensationPct)/totalTokens;
        return reward;
    }

    // FOR TESTING
    function toHash(string _domain) returns (bytes32){
        return sha3(_domain);
    }
    function getCurrentTime() returns (uint){
        return now;
    }

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

    //called by a user who wishes to change a parameter
    //initializes a proposal to change a parameter
    function proposeUpdate(string _parameter, uint _value) {
        bytes32 parameterHash = sha3(_parameter, _value);
        // applicant must pay the current value of minDeposit
        uint deposit = get("minDeposit");
        // check that registry can take sufficient amount of tokens from the applicant
        require(token.allowance(msg.sender, this) >= deposit);
        token.transferFrom(msg.sender, this, deposit);
        // initialize application with a snapshot with the current values of all parameters
        initializeSnapshotParam(parameterHash);
        uint challengeLen = Proposals[parameterHash].snapshot[challengeLen];
        Proposals[parameterHash].challengeTime= now + challengeLen;
        Proposals[parameterHash].owner = msg.sender;

    }

    //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) {
        bytes32 parameterHash = sha3(_parameter, _value);

        // check that registry can take sufficient amount of tokens from the challenger
        uint deposit = Proposals[parameterHash ].snapshot.minDeposit;
        require(token.allowance(msg.sender, this) >= deposit);
        token.transferFrom(msg.sender, this, deposit);

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

        // update the application's status
        Proposals[parameterHash].challenged = true;
        Proposals[parameterHash].challenger = msg.sender;
        // start a vote
        // poll ID = callVote(voting params);
    }

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

    // a one-time function for each completed vote
    // if proposal won: new parameter value is set, and applicant is rewarded tokens
    // if prospsal lost: challenger is rewarded tokens
    function processProposal(uint _pollID)
    {
        require(voteProcessed[_pollID] == false);
        // string parameter = ??;
        //uint value = ??
        bytes32 parameterHash = sha3(parameter, value);
        if (didProposalPass(_pollID)) {
            //??what would happen if didProposalPass() called and vote's still ongoing??
            // setting the value of parameter
            Parameters[sha3(parameter)] = value;
            delete Proposals[parameterHash].owner;
            // give tokens to applicant based on dist and total tokens
        }
        else {
            delete Proposals[parameterHash].owner;
            // give tokens to challenger based on dist and total tokens
        }
        // ensures the result cannot be processed again
        voteProcessed[_pollID] = true;
    }

    function claimParamReward(uint _pollID, uint _salt) {
        // checks if a voter has claimed tokens
        require(voterInfo[msg.sender][_pollID] == false);
        uint reward = giveTokens(_pollID, _salt);
        // ensures a voter cannot claim tokens again
        transfer(msg.sender, reward);
        voterInfo[msg.sender][_pollID] = true;
    }

     function giveParamTokens(uint _pollID, uint _salt) returns(uint) {
        // number of tokens person used to vote / total number of tokens for winning side
        // scale using distribution number
        // give the tokens
        // string parameter = ??
        bytes32 parameterHash = sha3(parameter, value);
        uint minDeposit = Proposals[parameterHash].snapshot[minDeposit];
        uint dispensationPct = Proposals[parameterHash].snapshot[dispensationPct];
        uint totalTokens = getTotalNumberOfTokensForWinningOption(_pollID);
        uint voterTokens = getNumCorrectInvestment(_pollID, _salt);

        uint reward = voterTokens*minDeposit*(1-dispensationPct)/totalTokens;
        return reward;
    }

     // private function to initialize a snapshot of parameters for each proposal
     function initializeSnapshotParam(bytes32 _hash) {
        Proposals[_hash].snapshot.minDeposit = get("minDeposit");
        Proposals[_hash].snapshot.challengeLen = get("challengeLen");
        Proposals[_hash].snapshot.commitVoteLen = get("commitVoteLen");
        Proposals[_hash].snapshot.revealVoteLen = get("revealVoteLen");
        Proposals[_hash].snapshot.majority = get("majority");
        Proposals[_hash].snapshot.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) returns (uint) {
       return Parameters[sha3(_keyword)];
    }

}


Change parameter name

Change parameter name

import "UnanimousConsent.sol";

/**
* This contract will consent to some hashes on behalf of a specified
* address if and only if the specified address has signed off on it
*/
contract ECDSASignatureProxy {
	address signer;
	UnanimousConsent unanimousConsent;

	function ECDSASignatureProxy(address _signer, UnanimousConsent _unanimousConsent) {
		signer = _signer;
		unanimousConsent = _unanimousConsent;
	}

	// Checks if all of the hashes have been signed off on
	function forward(bytes32[] _hashes, uint8 _v, bytes32 _r, bytes32 _s) external returns (bool) {
		bytes32 hash = sha3(_hashes);
		if (ecrecover(hash, _v, _r, _s) != signer) {
			return false;
		} else {
			unanimousConsent.consent(hashes);
			return true;
		}
	}
}

import "UnanimousConsent.sol";

/**
* This contract will consent to some hashes on behalf of a specified
* address if and only if the specified address has signed off on it
*/
contract ECDSASignatureProxy {
	address signer;
	UnanimousConsent unanimousConsent;

	function ECDSASignatureProxy(address _signer, UnanimousConsent _unanimousConsent) {
		signer = _signer;
		unanimousConsent = _unanimousConsent;
	}

	// Checks if all of the hashes have been signed off on
	function forward(bytes32[] hashes, uint8 _v, bytes32 _r, bytes32 _s) external returns (bool) {
		bytes32 hash = sha3(hashes);
		if (ecrecover(hash, _v, _r, _s) != signer) {
			return false;
		} else {
			unanimousConsent.consent(hashes);
			return true;
		}
	}
}


Improved documentation for _preValidatePurchase method in Crowdsale (#1101)

* Improved documentation for _preValidatePurchase in Crowdsale

* Added newline at EOF

pragma solidity ^0.4.24;

import "../token/ERC20/ERC20.sol";
import "../math/SafeMath.sol";
import "../token/ERC20/SafeERC20.sol";

/**
 * @title Crowdsale
 * @dev Crowdsale is a base contract for managing a token crowdsale,
 * allowing investors to purchase tokens with ether. This contract implements
 * such functionality in its most fundamental form and can be extended to provide additional
 * functionality and/or custom behavior.
 * The external interface represents the basic interface for purchasing tokens, and conform
 * the base architecture for crowdsales. They are *not* intended to be modified / overridden.
 * The internal interface conforms the extensible and modifiable surface of crowdsales. Override
 * the methods to add functionality. Consider using 'super' where appropriate to concatenate
 * behavior.
 */
contract Crowdsale {
  using SafeMath for uint256;
  using SafeERC20 for ERC20;

  // The token being sold
  ERC20 public token;

  // Address where funds are collected
  address public wallet;

  // How many token units a buyer gets per wei.
  // The rate is the conversion between wei and the smallest and indivisible token unit.
  // So, if you are using a rate of 1 with a DetailedERC20 token with 3 decimals called TOK
  // 1 wei will give you 1 unit, or 0.001 TOK.
  uint256 public rate;

  // Amount of wei raised
  uint256 public weiRaised;

  /**
   * Event for token purchase logging
   * @param purchaser who paid for the tokens
   * @param beneficiary who got the tokens
   * @param value weis paid for purchase
   * @param amount amount of tokens purchased
   */
  event TokenPurchase(
    address indexed purchaser,
    address indexed beneficiary,
    uint256 value,
    uint256 amount
  );

  /**
   * @param _rate Number of token units a buyer gets per wei
   * @param _wallet Address where collected funds will be forwarded to
   * @param _token Address of the token being sold
   */
  constructor(uint256 _rate, address _wallet, ERC20 _token) public {
    require(_rate > 0);
    require(_wallet != address(0));
    require(_token != address(0));

    rate = _rate;
    wallet = _wallet;
    token = _token;
  }

  // -----------------------------------------
  // Crowdsale external interface
  // -----------------------------------------

  /**
   * @dev fallback function ***DO NOT OVERRIDE***
   */
  function () external payable {
    buyTokens(msg.sender);
  }

  /**
   * @dev low level token purchase ***DO NOT OVERRIDE***
   * @param _beneficiary Address performing the token purchase
   */
  function buyTokens(address _beneficiary) public payable {

    uint256 weiAmount = msg.value;
    _preValidatePurchase(_beneficiary, weiAmount);

    // calculate token amount to be created
    uint256 tokens = _getTokenAmount(weiAmount);

    // update state
    weiRaised = weiRaised.add(weiAmount);

    _processPurchase(_beneficiary, tokens);
    emit TokenPurchase(
      msg.sender,
      _beneficiary,
      weiAmount,
      tokens
    );

    _updatePurchasingState(_beneficiary, weiAmount);

    _forwardFunds();
    _postValidatePurchase(_beneficiary, weiAmount);
  }

  // -----------------------------------------
  // Internal interface (extensible)
  // -----------------------------------------

  /**
   * @dev Validation of an incoming purchase. Use require statements to revert state when conditions are not met. Use `super` in contracts that inherit from Crowdsale to extend their validations.
   * Example from CappedCrowdsale.sol's _preValidatePurchase method:
   *   super._preValidatePurchase(_beneficiary, _weiAmount);
   *   require(weiRaised.add(_weiAmount) <= cap);
   * @param _beneficiary Address performing the token purchase
   * @param _weiAmount Value in wei involved in the purchase
   */
  function _preValidatePurchase(
    address _beneficiary,
    uint256 _weiAmount
  )
    internal
  {
    require(_beneficiary != address(0));
    require(_weiAmount != 0);
  }

  /**
   * @dev Validation of an executed purchase. Observe state and use revert statements to undo rollback when valid conditions are not met.
   * @param _beneficiary Address performing the token purchase
   * @param _weiAmount Value in wei involved in the purchase
   */
  function _postValidatePurchase(
    address _beneficiary,
    uint256 _weiAmount
  )
    internal
  {
    // optional override
  }

  /**
   * @dev Source of tokens. Override this method to modify the way in which the crowdsale ultimately gets and sends its tokens.
   * @param _beneficiary Address performing the token purchase
   * @param _tokenAmount Number of tokens to be emitted
   */
  function _deliverTokens(
    address _beneficiary,
    uint256 _tokenAmount
  )
    internal
  {
    token.safeTransfer(_beneficiary, _tokenAmount);
  }

  /**
   * @dev Executed when a purchase has been validated and is ready to be executed. Not necessarily emits/sends tokens.
   * @param _beneficiary Address receiving the tokens
   * @param _tokenAmount Number of tokens to be purchased
   */
  function _processPurchase(
    address _beneficiary,
    uint256 _tokenAmount
  )
    internal
  {
    _deliverTokens(_beneficiary, _tokenAmount);
  }

  /**
   * @dev Override for extensions that require an internal state to check for validity (current user contributions, etc.)
   * @param _beneficiary Address receiving the tokens
   * @param _weiAmount Value in wei involved in the purchase
   */
  function _updatePurchasingState(
    address _beneficiary,
    uint256 _weiAmount
  )
    internal
  {
    // optional override
  }

  /**
   * @dev Override to extend the way in which ether is converted to tokens.
   * @param _weiAmount Value in wei to be converted into tokens
   * @return Number of tokens that can be purchased with the specified _weiAmount
   */
  function _getTokenAmount(uint256 _weiAmount)
    internal view returns (uint256)
  {
    return _weiAmount.mul(rate);
  }

  /**
   * @dev Determines how ETH is stored/forwarded on purchases.
   */
  function _forwardFunds() internal {
    wallet.transfer(msg.value);
  }
}

pragma solidity ^0.4.24;

import "../token/ERC20/ERC20.sol";
import "../math/SafeMath.sol";
import "../token/ERC20/SafeERC20.sol";

/**
 * @title Crowdsale
 * @dev Crowdsale is a base contract for managing a token crowdsale,
 * allowing investors to purchase tokens with ether. This contract implements
 * such functionality in its most fundamental form and can be extended to provide additional
 * functionality and/or custom behavior.
 * The external interface represents the basic interface for purchasing tokens, and conform
 * the base architecture for crowdsales. They are *not* intended to be modified / overridden.
 * The internal interface conforms the extensible and modifiable surface of crowdsales. Override
 * the methods to add functionality. Consider using 'super' where appropriate to concatenate
 * behavior.
 */
contract Crowdsale {
  using SafeMath for uint256;
  using SafeERC20 for ERC20;

  // The token being sold
  ERC20 public token;

  // Address where funds are collected
  address public wallet;

  // How many token units a buyer gets per wei.
  // The rate is the conversion between wei and the smallest and indivisible token unit.
  // So, if you are using a rate of 1 with a DetailedERC20 token with 3 decimals called TOK
  // 1 wei will give you 1 unit, or 0.001 TOK.
  uint256 public rate;

  // Amount of wei raised
  uint256 public weiRaised;

  /**
   * Event for token purchase logging
   * @param purchaser who paid for the tokens
   * @param beneficiary who got the tokens
   * @param value weis paid for purchase
   * @param amount amount of tokens purchased
   */
  event TokenPurchase(
    address indexed purchaser,
    address indexed beneficiary,
    uint256 value,
    uint256 amount
  );

  /**
   * @param _rate Number of token units a buyer gets per wei
   * @param _wallet Address where collected funds will be forwarded to
   * @param _token Address of the token being sold
   */
  constructor(uint256 _rate, address _wallet, ERC20 _token) public {
    require(_rate > 0);
    require(_wallet != address(0));
    require(_token != address(0));

    rate = _rate;
    wallet = _wallet;
    token = _token;
  }

  // -----------------------------------------
  // Crowdsale external interface
  // -----------------------------------------

  /**
   * @dev fallback function ***DO NOT OVERRIDE***
   */
  function () external payable {
    buyTokens(msg.sender);
  }

  /**
   * @dev low level token purchase ***DO NOT OVERRIDE***
   * @param _beneficiary Address performing the token purchase
   */
  function buyTokens(address _beneficiary) public payable {

    uint256 weiAmount = msg.value;
    _preValidatePurchase(_beneficiary, weiAmount);

    // calculate token amount to be created
    uint256 tokens = _getTokenAmount(weiAmount);

    // update state
    weiRaised = weiRaised.add(weiAmount);

    _processPurchase(_beneficiary, tokens);
    emit TokenPurchase(
      msg.sender,
      _beneficiary,
      weiAmount,
      tokens
    );

    _updatePurchasingState(_beneficiary, weiAmount);

    _forwardFunds();
    _postValidatePurchase(_beneficiary, weiAmount);
  }

  // -----------------------------------------
  // Internal interface (extensible)
  // -----------------------------------------

  /**
   * @dev Validation of an incoming purchase. Use require statements to revert state when conditions are not met. Use super to concatenate validations.
   * @param _beneficiary Address performing the token purchase
   * @param _weiAmount Value in wei involved in the purchase
   */
  function _preValidatePurchase(
    address _beneficiary,
    uint256 _weiAmount
  )
    internal
  {
    require(_beneficiary != address(0));
    require(_weiAmount != 0);
  }

  /**
   * @dev Validation of an executed purchase. Observe state and use revert statements to undo rollback when valid conditions are not met.
   * @param _beneficiary Address performing the token purchase
   * @param _weiAmount Value in wei involved in the purchase
   */
  function _postValidatePurchase(
    address _beneficiary,
    uint256 _weiAmount
  )
    internal
  {
    // optional override
  }

  /**
   * @dev Source of tokens. Override this method to modify the way in which the crowdsale ultimately gets and sends its tokens.
   * @param _beneficiary Address performing the token purchase
   * @param _tokenAmount Number of tokens to be emitted
   */
  function _deliverTokens(
    address _beneficiary,
    uint256 _tokenAmount
  )
    internal
  {
    token.safeTransfer(_beneficiary, _tokenAmount);
  }

  /**
   * @dev Executed when a purchase has been validated and is ready to be executed. Not necessarily emits/sends tokens.
   * @param _beneficiary Address receiving the tokens
   * @param _tokenAmount Number of tokens to be purchased
   */
  function _processPurchase(
    address _beneficiary,
    uint256 _tokenAmount
  )
    internal
  {
    _deliverTokens(_beneficiary, _tokenAmount);
  }

  /**
   * @dev Override for extensions that require an internal state to check for validity (current user contributions, etc.)
   * @param _beneficiary Address receiving the tokens
   * @param _weiAmount Value in wei involved in the purchase
   */
  function _updatePurchasingState(
    address _beneficiary,
    uint256 _weiAmount
  )
    internal
  {
    // optional override
  }

  /**
   * @dev Override to extend the way in which ether is converted to tokens.
   * @param _weiAmount Value in wei to be converted into tokens
   * @return Number of tokens that can be purchased with the specified _weiAmount
   */
  function _getTokenAmount(uint256 _weiAmount)
    internal view returns (uint256)
  {
    return _weiAmount.mul(rate);
  }

  /**
   * @dev Determines how ETH is stored/forwarded on purchases.
   */
  function _forwardFunds() internal {
    wallet.transfer(msg.value);
  }
}


tightly stored payments (#46)

tightly stored payments (#46)

pragma solidity 0.4.11;

import '../SafeMath.sol';
import "../ownership/Ownable.sol";
import "../controller/ControllerInterface.sol";

/**
 * @title PullPayment
 * @dev Base contract supporting async send for pull payments.
 */
contract PullPayment is Ownable {
  using SafeMath for uint256;

  uint public dailyLimit = 1000000000000000000000;  // 1 ETH
  uint public lastDay;
  uint public spentToday;

  // 8bytes date, 24 bytes value
  mapping(address => uint256) internal payments;

  modifier whenNotPaused () {
    require(!ControllerInterface(owner).paused());
     _;
  }
  function balanceOf(address _owner) constant returns (uint256 value) {
    return uint192(payments[_owner]);
  }

  function paymentOf(address _owner) constant returns (uint256 value, uint256 date) {
    value = uint192(payments[_owner]);
    date = (payments[_owner] >> 192);
    return;
  }

  /// @dev Allows to change the daily limit. Transaction has to be sent by wallet.
  /// @param _dailyLimit Amount in wei.
  function changeDailyLimit(uint _dailyLimit) public onlyOwner {
      dailyLimit = _dailyLimit;
  }

  function changeWithdrawalDate(address _owner, uint256 _newDate)  public onlyOwner {
    // allow to withdraw immediately
    // move witdrawal date more days into future
    payments[_owner] = (_newDate << 192) + uint192(payments[_owner]);
  }

  function asyncSend(address _dest) public payable onlyOwner {
    require(msg.value > 0);
    uint256 newValue = msg.value.add(uint192(payments[_dest]));
    uint256 newDate;
    if (isUnderLimit(msg.value)) {
      uint256 date = payments[_dest] >> 192;
      newDate = (date > now) ? date : now;
    } else {
      newDate = now.add(3 days);
    }
    spentToday = spentToday.add(msg.value);
    payments[_dest] = (newDate << 192) + uint192(newValue);
  }

  function withdraw() public whenNotPaused {
    address untrustedRecipient = msg.sender;
    uint256 amountWei = uint192(payments[untrustedRecipient]);

    require(amountWei != 0);
    require(now >= (payments[untrustedRecipient] >> 192));
    require(this.balance >= amountWei);

    payments[untrustedRecipient] = 0;

    untrustedRecipient.transfer(amountWei);
  }

  /*
   * Internal functions
   */
  /// @dev Returns if amount is within daily limit and resets spentToday after one day.
  /// @param amount Amount to withdraw.
  /// @return Returns if amount is under daily limit.
  function isUnderLimit(uint amount) internal returns (bool) {
    if (now > lastDay.add(24 hours)) {
      lastDay = now;
      spentToday = 0;
    }
    // not using safe math because we don't want to throw;
    if (spentToday + amount > dailyLimit || spentToday + amount < spentToday) {
      return false;
    }
    return true;
  }

}

pragma solidity 0.4.11;

import '../SafeMath.sol';
import "../ownership/Ownable.sol";
import "../controller/ControllerInterface.sol";

/**
 * @title PullPayment
 * @dev Base contract supporting async send for pull payments.
 */
contract PullPayment is Ownable {
  using SafeMath for uint256;

  struct Payment {
    uint256 value;  // TODO: use compact storage
    uint256 date;   //
  }

  uint public dailyLimit = 1000000000000000000000;  // 1 ETH
  uint public lastDay;
  uint public spentToday;

  mapping(address => Payment) internal payments;

  modifier whenNotPaused () {
    require(!ControllerInterface(owner).paused());
     _;
  }
  function balanceOf(address _owner) constant returns (uint256 value) {
    return payments[_owner].value;
  }

  function paymentOf(address _owner) constant returns (uint256 value, uint256 date) {
    value = payments[_owner].value;
    date = payments[_owner].date;
    return;
  }

  /// @dev Allows to change the daily limit. Transaction has to be sent by wallet.
  /// @param _dailyLimit Amount in wei.
  function changeDailyLimit(uint _dailyLimit) public onlyOwner {
      dailyLimit = _dailyLimit;
  }

  function changeWithdrawalDate(address _owner, uint256 _newDate)  public onlyOwner {
    // allow to withdraw immediately
    // move witdrawal date more days into future
    payments[_owner].date = _newDate;
  }

  function asyncSend(address _dest) public payable onlyOwner {
    require(msg.value > 0);
    uint256 newValue = payments[_dest].value.add(msg.value);
    uint256 newDate;
    if (isUnderLimit(msg.value)) {
      newDate = (payments[_dest].date > now) ? payments[_dest].date : now;
    } else {
      newDate = now.add(3 days);
    }
    spentToday = spentToday.add(msg.value);
    payments[_dest] = Payment(newValue, newDate);
  }

  function withdraw() public whenNotPaused {
    address untrustedRecipient = msg.sender;
    uint256 amountWei = payments[untrustedRecipient].value;

    require(amountWei != 0);
    require(now >= payments[untrustedRecipient].date);
    require(this.balance >= amountWei);

    payments[untrustedRecipient].value = 0;

    untrustedRecipient.transfer(amountWei);
  }

  /*
   * Internal functions
   */
  /// @dev Returns if amount is within daily limit and resets spentToday after one day.
  /// @param amount Amount to withdraw.
  /// @return Returns if amount is under daily limit.
  function isUnderLimit(uint amount) internal returns (bool) {
    if (now > lastDay.add(24 hours)) {
      lastDay = now;
      spentToday = 0;
    }
    // not using safe math because we don't want to throw;
    if (spentToday + amount > dailyLimit || spentToday + amount < spentToday) {
      return false;
    }
    return true;
  }

}


Update ReentrancyGuard.sol (#1862)

Update ReentrancyGuard.sol (#1862)

Fix typo

pragma solidity ^0.5.0;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 */
contract ReentrancyGuard {
    // counter to allow mutex lock with only one SSTORE operation
    uint256 private _guardCounter;

    constructor () internal {
        // The counter starts at one to prevent changing it from zero to a non-zero
        // value, which is a more expensive operation.
        _guardCounter = 1;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and make it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _guardCounter += 1;
        uint256 localCounter = _guardCounter;
        _;
        require(localCounter == _guardCounter, "ReentrancyGuard: reentrant call");
    }
}

pragma solidity ^0.5.0;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be aplied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 */
contract ReentrancyGuard {
    // counter to allow mutex lock with only one SSTORE operation
    uint256 private _guardCounter;

    constructor () internal {
        // The counter starts at one to prevent changing it from zero to a non-zero
        // value, which is a more expensive operation.
        _guardCounter = 1;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and make it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _guardCounter += 1;
        uint256 localCounter = _guardCounter;
        _;
        require(localCounter == _guardCounter, "ReentrancyGuard: reentrant call");
    }
}


Fixing bug, swapped vars

Fixing bug, swapped vars

contract PlutusDex {
    enum CurrencySymbol { EUR, GBP, USD }
    //Addresses of ethereum accounts that are approved to verify bitcoin transactions,
    //, verify/perform deposit of fiat to escrow account and verify/perform deposit
    //of fiat to vdc
    mapping(address => bool) approvedPlutusCentral;

    struct FiatDeposit {
        address trader;
        uint fiatDeposited;
        CurrencySymbol fiatSymbol;
        uint btcAsked;
        //From https://forum.ethereum.org/discussion/3139/store-bitcoin-address-in-smart-contract
        bytes20 btcAddress; //Public address to deposit the bitcoin too
    }

    mapping(address => FiatDeposit) fiatDeposits;

    event FiatDeposited(address trader, uint fiatDeposited, CurrencySymbol fiatSymbol, uint btcAsked, bytes20 btcAddress);

    event VdcLoaded(bytes32 userVdcIban, uint fiatAmount, CurrencySymbol fiatSymbol);

    function PlutusDex() {
        approvedPlutusCentral[msg.sender] = true;
    }

    function depositFiat(address trader, uint fiatDeposited, CurrencySymbol fiatSymbol, uint btcAsked, bytes20 btcAddress) {
        if (! approvedPlutusCentral[msg.sender]) {
            //Only approved fiat trackers can make deposit
            throw;
        }
        fiatDeposits[trader] = FiatDeposit(trader, fiatDeposited, fiatSymbol, btcAsked, btcAddress);
        //Emit event, to notify all plutus-users
        FiatDeposited(trader, fiatDeposited, fiatSymbol, btcAsked, btcAddress);
    }

    function offerBtc(address trader, uint btcOffered, bytes32 userVdcIban) {
        if (! approvedPlutusCentral[msg.sender]) {
            //Only approved btc trackers can offer bitcoin
            throw;
        }
        //TODO some Null check
        FiatDeposit deposited = fiatDeposits[trader];
        uint btcTraded;
        if (deposited.btcAsked < btcOffered) {
            btcTraded = btcOffered;
        } else {
            btcTraded = deposited.btcAsked;
        }
        uint fiatReceived = deposited.fiatDeposited * (btcTraded / btcOffered);
        deposited.btcAsked -= btcOffered;
        deposited.fiatDeposited -= fiatReceived;
        //Notify user
        VdcLoaded(userVdcIban, fiatReceived, deposited.fiatSymbol);
    }
}

contract PlutusDex {
    enum CurrencySymbol { EUR, GBP, USD }
    //Addresses of ethereum accounts that are approved to verify bitcoin transactions,
    //, verify/perform deposit of fiat to escrow account and verify/perform deposit
    //of fiat to vdc
    mapping(address => bool) approvedPlutusCentral;

    struct FiatDeposit {
        address trader;
        uint fiatDeposited;
        CurrencySymbol fiatSymbol;
        uint btcAsked;
        //From https://forum.ethereum.org/discussion/3139/store-bitcoin-address-in-smart-contract
        bytes20 btcAddress; //Public address to deposit the bitcoin too
    }

    mapping(address => FiatDeposit) fiatDeposits;

    event FiatDeposited(address trader, uint fiatDeposited, CurrencySymbol fiatSymbol, uint btcAsked, bytes20 btcAddress);

    event VdcLoaded(bytes32 userVdcIban, uint fiatAmount, CurrencySymbol fiatSymbol);

    function PlutusDex() {
        approvedPlutusCentral[msg.sender] = true;
    }

    function depositFiat(address trader, uint fiatDeposited, CurrencySymbol fiatSymbol, uint btcAsked, bytes20 btcAddress) {
        if (! approvedPlutusCentral[msg.sender]) {
            //Only approved fiat trackers can make deposit
            throw;
        }
        fiatDeposits[trader] = FiatDeposit(trader, fiatDeposited, fiatSymbol, btcAsked, btcAddress);
        //Emit event, to notify all plutus-users
        FiatDeposited(trader, fiatDeposited, fiatSymbol, btcAsked, btcAddress);
    }

    function offerBtc(address trader, uint btcOffered, bytes32 userVdcIban) {
        if (! approvedPlutusCentral[msg.sender]) {
            //Only approved btc trackers can offer bitcoin
            throw;
        }
        //TODO some Null check
        FiatDeposit deposited = fiatDeposits[trader];
        uint btcTraded;
        if (deposited.btcAsked < btcOffered) {
            btcTraded = btcOffered;
        } else {
            btcOffered = deposited.btcAsked;
        }
        uint fiatReceived = deposited.fiatDeposited * (btcTraded / btcOffered);
        deposited.btcAsked -= btcOffered;
        deposited.fiatDeposited -= fiatReceived;
        //Notify user
        VdcLoaded(userVdcIban, fiatReceived, deposited.fiatSymbol);
    }
}


Updated comments in random

Updated comments in random

/*
@type: contract
@name: Random
@purpose: To generate weak random numbers
*/

contract Random
{
  /*
  @type: function
  @name: getRandom
  @purpose: To generate a weak random number between 0 and the specified maximum
  @param: uint seed = seed number for the generation of a random number
  @param: uint max = the max for the range of random numbers that can be made
  @returns: The random number
  */
  function getRandom(uint seed, uint max) constant returns(uint) //Based on the original function written by github user alexvandesande
  {
    return(uint(sha3(block.blockhash(block.number-1), seed))%(max+1)); //Hashes the seed number with the last blockhash to generate a random number and shifts it into the desired range by using a modulus
  }

  /*
  @type: function
  @name: getRandom
  @purpose: To generate a weak random number between a specified minimum and the specified maximum
  @param: uint seed = seed number for the generation of a random number
  @param: uint max = the max for the range of random numbers that can be made
  @param: uint min = the min for the range of random numbers that can be made
  @returns: The random number
  */
  function getRandom(uint seed, uint min, uint max) constant returns(uint) //Based on the original function written by github user alexvandesande
  {
    return(uint(sha3(block.blockhash(block.number-1), seed))%(max-min+1) + min); //Hashes the seed number with the last blockhash to generate a random number and shifts it into the desired range by using a modulus and addition
  }
}

contract Random
{
  function getRandom(uint seed, uint max) constant returns (uint randomNumber) //Based on the original function written by github user alexvandesande
  {
    return(uint(sha3(block.blockhash(block.number-1), seed))%(max+1));
  }

  function getRandom(uint seed, uint min, uint max) constant returns (uint randomNumber) //Based on the original function written by github user alexvandesande
  {
    return(uint(sha3(block.blockhash(block.number-1), seed))%(max-min+1) + min);
  }
}


Fix owned std contract

Fix owned std contract

contract owned {
    address owner;

    modifier onlyowner() {
        if (msg.sender == owner) {
            _;
        }
    }

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

contract owned {
    address owner;

    modifier onlyowner() {
        if (msg.sender == owner) {
            _
        }
    }

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


Fix comments in Broker contract

Fix comments in Broker contract

pragma solidity ^0.4.2;

import "Mortal.sol";

contract Broker is Mortal {
    enum ChannelState { Open, Settling, Settled }

    struct PaymentChannel {
        address sender;
        address receiver;
        uint256 value;

        uint settlementPeriod;

        ChannelState state;
        /* until state is invalid */
        uint until;

        uint256 payment;
    }

    mapping(bytes32 => PaymentChannel) channels;
    uint id;

    event DidCreateChannel(address indexed sender, address indexed receiver, bytes32 channelId);
    event DidDeposit(bytes32 indexed channelId, uint256 value);
    event DidStartSettle(bytes32 indexed channelId, uint256 payment);
    event DidSettle(bytes32 indexed channelId, uint256 payment, uint256 oddValue);

    function Broker() {
        id = 0;
    }

    /******** ACTIONS ********/

    /* Create payment channel */
    function createChannel(address receiver, uint duration, uint settlementPeriod) public payable {
        var channelId = sha3(id++);
        var sender = msg.sender;
        var value = msg.value;
        channels[channelId] =
          PaymentChannel(sender, receiver, value, settlementPeriod, ChannelState.Open, block.timestamp + duration, 0);

        DidCreateChannel(sender, receiver, channelId);
    }

    /* Add funds to the channel */
    function deposit(bytes32 channelId) public payable {
        if (!canDeposit(msg.sender, channelId)) throw;

        var channel = channels[channelId];
        channel.value += msg.value;

        DidDeposit(channelId, msg.value);
    }

    /* Receiver settles channel */
    function claim(bytes32 channelId, uint256 payment, uint8 v, bytes32 r, bytes32 s) public {
        if (!canClaim(channelId, payment, v, r, s)) return;

        this.settle(channelId, payment);
    }

    /* Sender starts settling */
    function startSettle(bytes32 channelId, uint256 payment) public {
        if (!canStartSettle(msg.sender, channelId)) throw;
        var channel = channels[channelId];
        channel.state = ChannelState.Settling;
        channel.until = now + channel.settlementPeriod;
        channel.payment = payment;
        DidStartSettle(channelId, payment);
    }

    /* Sender settles the channel, if receiver have not done that */
    function finishSettle(bytes32 channelId) public {
      if (!canFinishSettle(msg.sender, channelId)) throw;
      this.settle(channelId, channels[channelId].payment);
    }

    function close(bytes32 channelId) {
        var channel = channels[channelId];
        if (channel.state == ChannelState.Settled && (msg.sender == owner || msg.sender == channel.sender || msg.sender == channel.receiver)) {
            if (channel.value > 0) {
                if (!channel.sender.send(channel.value)) throw;
            }
            delete channels[channelId];
        }
    }

    /******** BEHIND THE SCENES ********/

    function settle(bytes32 channelId, uint256 payment) {
      var channel = channels[channelId];
      uint256 paid = payment;
      uint256 oddMoney = 0;

      if (payment > channel.value) {
        paid = channel.value;
        if (!channel.receiver.send(paid)) throw;
      } else {
        if (!channel.receiver.send(paid)) throw;
        oddMoney = channel.value - paid;
        if (!channel.sender.send(oddMoney)) throw;
        channel.value = 0;
      }

      channels[channelId].state = ChannelState.Settled;
      DidSettle(channelId, payment, oddMoney);
    }

    /******** CAN CHECKS ********/

    function canDeposit(address sender, bytes32 channelId) constant returns(bool) {
        var channel = channels[channelId];
        return channel.state == ChannelState.Open &&
            channel.sender == sender;
    }

    function canClaim(bytes32 channelId, uint256 payment, uint8 v, bytes32 r, bytes32 s) constant returns(bool) {
        var channel = channels[channelId];
        return (channel.state == ChannelState.Open || channel.state == ChannelState.Settling) &&
            channel.until > now &&
            channel.sender == ecrecover(getHash(channelId, payment), v, r, s);
    }

    function canStartSettle(address sender, bytes32 channelId) constant returns(bool) {
        var channel = channels[channelId];
        return channel.state == ChannelState.Open &&
            channel.sender == sender;
    }

    function canFinishSettle(address sender, bytes32 channelId) constant returns(bool) {
        var channel = channels[channelId];
        return channel.state == ChannelState.Settling &&
            (sender == channel.sender || sender == owner) &&
            channel.until >= now;
    }

    /******** READERS ********/

    function getState(bytes32 channelId) constant returns(ChannelState) {
        return channels[channelId].state;
    }

    function getUntil(bytes32 channelId) constant returns(uint) {
        return channels[channelId].until;
    }

    function getPayment(bytes32 channelId) constant returns(uint) {
        return channels[channelId].payment;
    }

    function getHash(bytes32 channelId, uint256 value) constant returns(bytes32) {
        return sha3(channelId, value);
    }

    function isOpenChannel(bytes32 channelId) constant returns(bool) {
        var channel = channels[channelId];
        return channel.state == ChannelState.Open && channel.until >= now;
    }
}

pragma solidity ^0.4.2;

import "Mortal.sol";

contract Broker is Mortal {
    enum ChannelState { Open, Settling, Settled }

    struct PaymentChannel {
        address sender;
        address receiver;
        uint256 value;

        uint settlementPeriod;

        ChannelState state;
        uint until; // state is invalid

        uint256 payment;
    }

    mapping(bytes32 => PaymentChannel) channels;
    uint id;

    event DidCreateChannel(address indexed sender, address indexed receiver, bytes32 channelId);
    event DidDeposit(bytes32 indexed channelId, uint256 value);
    event DidStartSettle(bytes32 indexed channelId, uint256 payment);
    event DidSettle(bytes32 indexed channelId, uint256 payment, uint256 oddValue);

    function Broker() {
        id = 0;
    }

    /******** ACTIONS ********/

    /* Create payment channel */
    function createChannel(address receiver, uint duration, uint settlementPeriod) public payable {
        var channelId = sha3(id++);
        var sender = msg.sender;
        var value = msg.value;
        channels[channelId] =
          PaymentChannel(sender, receiver, value, settlementPeriod, ChannelState.Open, block.timestamp + duration, 0);

        DidCreateChannel(sender, receiver, channelId);
    }

    /* Add funds to the channel */
    function deposit(bytes32 channelId) public payable {
        if (!canDeposit(msg.sender, channelId)) throw;

        var channel = channels[channelId];
        channel.value += msg.value;

        DidDeposit(channelId, msg.value);
    }

    /* Receiver settles channel */
    function claim(bytes32 channelId, uint256 payment, uint8 v, bytes32 r, bytes32 s) public {
        if (!canClaim(channelId, payment, v, r, s)) return;

        this.settle(channelId, payment);
    }

    /* Sender starts settling */
    function startSettle(bytes32 channelId, uint256 payment) public {
        if (!canStartSettle(msg.sender, channelId)) throw;
        var channel = channels[channelId];
        channel.state = ChannelState.Settling;
        channel.until = now + channel.settlementPeriod;
        channel.payment = payment;
        DidStartSettle(channelId, payment);
    }

    /* Sender settles the channel, if receiver have not done that */
    function finishSettle(bytes32 channelId) public {
      if (!canFinishSettle(msg.sender, channelId)) throw;
      this.settle(channelId, channels[channelId].payment);
    }

    function close(bytes32 channelId) {
        var channel = channels[channelId];
        if (channel.state == ChannelState.Settled && (msg.sender == owner || msg.sender == channel.sender || msg.sender == channel.receiver)) {
            if (channel.value > 0) {
                if (!channel.sender.send(channel.value)) throw;
            }
            delete channels[channelId];
        }
    }

    /******** BEHIND THE SCENES ********/

    function settle(bytes32 channelId, uint256 payment) {
      var channel = channels[channelId];
      uint256 paid = payment;
      uint256 oddMoney = 0;

      if (payment > channel.value) {
        paid = channel.value;
        if (!channel.receiver.send(paid)) throw;
      } else {
        if (!channel.receiver.send(paid)) throw;
        oddMoney = channel.value - paid;
        if (!channel.sender.send(oddMoney)) throw;
        channel.value = 0;
      }

      channels[channelId].state = ChannelState.Settled;
      DidSettle(channelId, payment, oddMoney);
    }

    /******** CAN CHECKS ********/

    function canDeposit(address sender, bytes32 channelId) constant returns(bool) {
        var channel = channels[channelId]; // FIXME what if there is no channelId present?!
        return channel.state == ChannelState.Open &&
            channel.sender == sender;
    }

    function canClaim(bytes32 channelId, uint256 payment, uint8 v, bytes32 r, bytes32 s) constant returns(bool) {
        var channel = channels[channelId];
        return (channel.state == ChannelState.Open || channel.state == ChannelState.Settling) &&
            channel.until > now &&
            channel.sender == ecrecover(getHash(channelId, payment), v, r, s);
    }

    function canStartSettle(address sender, bytes32 channelId) constant returns(bool) {
        var channel = channels[channelId];
        return channel.state == ChannelState.Open &&
            channel.sender == sender;
    }

    function canFinishSettle(address sender, bytes32 channelId) constant returns(bool) {
        var channel = channels[channelId];
        return channel.state == ChannelState.Settling &&
            (sender == channel.sender || sender == owner) &&
            channel.until >= now;
    }

    /******** READERS ********/

    function getState(bytes32 channelId) constant returns(ChannelState) {
        return channels[channelId].state;
    }

    function getUntil(bytes32 channelId) constant returns(uint) {
        return channels[channelId].until;
    }

    function getPayment(bytes32 channelId) constant returns(uint) {
        return channels[channelId].payment;
    }

    function getHash(bytes32 channelId, uint256 value) constant returns(bytes32) {
        return sha3(channelId, value);
    }

    function isOpenChannel(bytes32 channelId) constant returns(bool) {
        var channel = channels[channelId];
        return channel.state == ChannelState.Open && channel.until >= now;
    }
}


Fix precision on final_price

Fix precision on final_price

Closes https://github.com/raiden-network/raiden-token/issues/59

pragma solidity ^0.4.11;

import './token.sol';

/// @title Dutch auction contract - distribution of tokens using an auction.
contract DutchAuction {
    /*
     * Auction for the TKN Token.
     *
     * Terminology:
     * 1 token unit = Tei
     * 1 token = TKN = Tei * multiplier
     * multiplier set from token's number of decimals (i.e. 10**decimals)
     */

    /*
     * Storage
     */

    CustomToken public token;
    address public owner;
    address public wallet;

    // Price function parameters
    uint public price_factor;
    uint public price_const;

    // For calculating elapsed time for price
    uint public start_time;
    uint public end_time;
    uint public start_block;

    // Keep track of all ETH received in the bids
    uint public received_ether;

    // Keep track of funds claimed after auction has ended
    uint public funds_claimed;

    // Total number of Tei (TKN * multiplier) that will be auctioned
    uint public multiplier;
    uint public tokens_auctioned;

    // Wei per TKN (Tei * multiplier)
    uint public final_price;

    mapping (address => uint) public bids;

    Stages public stage;

    // TODO - remove after testing
    uint rounding_error_tokens;

    /*
     * Enums
     */
    enum Stages {
        AuctionDeployed,
        AuctionSetUp,
        AuctionStarted,
        AuctionEnded,
        TokensDistributed
    }

    /*
     * Modifiers
     */
    modifier atStage(Stages _stage) {
        require(stage == _stage);
        _;
    }

    modifier isOwner() {
        require(msg.sender == owner);
        _;
    }

    modifier isValidPayload() {
        require(msg.data.length == 0 || msg.data.length == 4 || msg.data.length == 36);
        _;
    }

    /*
     * Events
     */

    event Deployed(
        address indexed _auction,
        uint indexed _price_factor,
        uint indexed _price_const
    );
    event Setup();
    event SettingsChanged(uint indexed _price_factor, uint indexed _price_const);
    event AuctionStarted(uint indexed _start_time, uint indexed _block_number);
    event BidSubmission(
        address indexed _sender,
        uint indexed _amount,
        uint indexed _missing_funds
    );
    event ClaimedTokens(address indexed _recipient, uint indexed _sent_amount);
    event AuctionEnded(uint indexed _final_price);
    event TokensDistributed();

    /*
     * Public functions
     */

    /// @dev Contract constructor function sets price factor and constant for
    /// calculating the Dutch Auction price.
    /// @param _wallet Wallet address to which all contributed ETH will be forwarded.
    /// @param _price_factor Auction price factor.
    /// @param _price_const Auction price divisor constant.
    function DutchAuction(address _wallet, uint _price_factor, uint _price_const) public {
        require(_wallet != 0x0);
        wallet = _wallet;

        owner = msg.sender;
        stage = Stages.AuctionDeployed;
        Deployed(this, price_factor, price_const);
        changeSettings(_price_factor, _price_const);
    }

    /// @dev Fallback function for the contract, which calls bid() if the auction has started.
    function () public payable atStage(Stages.AuctionStarted) {
        bid(msg.sender);
    }

    /// @notice Set `_token` as the token address to be used in the auction.
    /// @dev Setup function sets external contracts addresses.
    /// @param _token Token address.
    function setup(address _token) public isOwner atStage(Stages.AuctionDeployed) {
        require(_token != 0x0);
        token = CustomToken(_token);
        require(token.owner() == owner);
        require(token.auction_address() == address(this));

        // Get number of Tei (TKN * multiplier) to be auctioned from token auction balance
        tokens_auctioned = token.balanceOf(this);

        // Set number of tokens multiplier from token decimals
        multiplier = 10**uint(token.decimals());

        stage = Stages.AuctionSetUp;
        Setup();

        // Tei auctioned
        require(tokens_auctioned > multiplier);
    }

    /// @notice Set `_price_factor` and `_price_const` as the new price factor
    /// and price divisor constant.
    /// @dev Changes auction start price factor before auction is started.
    /// @param _price_factor Updated price factor.
    /// @param _price_const Updated price divisor constant.
    function changeSettings(uint _price_factor, uint _price_const) public isOwner {
        require(stage == Stages.AuctionDeployed || stage == Stages.AuctionSetUp);
        require(_price_factor > 0);
        require(_price_const > 0);

        price_factor = _price_factor;
        price_const = _price_const;
        SettingsChanged(price_factor, price_const);
    }

    /// @notice Start the auction.
    /// @dev Starts auction and sets start_time.
    function startAuction() public isOwner atStage(Stages.AuctionSetUp) {
        stage = Stages.AuctionStarted;
        start_time = now;
        start_block = block.number;
        AuctionStarted(start_time, start_block);
    }

    /// @notice Finalize the auction - sets the final price and changes the auction
    /// stage after no bids are allowed anymore.
    /// @dev Finalize auction and set the final token price.
    function finalizeAuction() public atStage(Stages.AuctionStarted)
    {
        // Missing funds should be 0 at this point
        uint missing_funds = missingFundsToEndAuction();
        assert(missing_funds == 0);

        // Calculate the final price WEI / TKN = WEI / (Tei / multiplier)
        final_price = multiplier * received_ether / tokens_auctioned;

        end_time = now;
        stage = Stages.AuctionEnded;
        AuctionEnded(final_price);

        assert(final_price > 0);
    }

    /// --------------------------------- Auction Functions ------------------

    /// @notice Send `msg.value` WEI to the auction from the `msg.sender` account.
    /// @dev Allows to send a bid to the auction.
    function bid() public payable atStage(Stages.AuctionStarted) {
        bid(msg.sender);
    }

    /// @notice Send `msg.value` WEI to the auction from the `receiver` account.
    /// @dev Allows to send a bid to the auction.
    /// @param receiver Bidder account address.
    function bid(address receiver)
        public
        payable
        isValidPayload
        atStage(Stages.AuctionStarted)
    {
        require(receiver != 0x0);
        require(msg.value > 0);
        require(bids[receiver] + msg.value >= msg.value);

        uint pre_receiver_funds = bids[receiver];

        // Missing funds without the current bid value
        uint missing_funds = missingFundsToEndAuction();

        // We only allow bid values less than the missing funds to end the auction value.
        require(msg.value <= missing_funds);

        bids[receiver] += msg.value;
        received_ether += msg.value;

        // Send bid amount to wallet
        wallet.transfer(msg.value);

        BidSubmission(receiver, msg.value, missing_funds);

        assert(bids[receiver] == pre_receiver_funds + msg.value);
        assert(received_ether >= msg.value);
    }

    /// @notice Claim auction tokens for `msg.sender` after the auction has ended.
    /// @dev Claims tokens for bidder after auction. To be used if tokens can be claimed by bidders, individually.
    function claimTokens() public atStage(Stages.AuctionEnded) {
        claimTokens(msg.sender);
    }

    /// @notice Claim auction tokens for `receiver` after the auction has ended.
    /// @dev Claims tokens for bidder after auction.
    /// @param receiver Tokens will be assigned to this address if set.
    function claimTokens(address receiver)
        public
        isValidPayload
        atStage(Stages.AuctionEnded)
    {
        require(receiver != 0x0);
        require(bids[receiver] > 0);

        // Number of Tei = bidded_wei / wei_per_TKN * multiplier
        uint num = multiplier * bids[receiver] / final_price;

        // Update funds claimed with full bidded amount
        // rounding errors are included to not block the contract
        funds_claimed += bids[receiver];

        // Set receiver bid to 0 before assigning tokens
        bids[receiver] = 0;

        require(token.transfer(receiver, num));

        ClaimedTokens(receiver, num);

        // Test for a correct claimed tokens calculation
        /* TODO remove this after testing */
        uint auction_unclaimed_tokens = token.balanceOf(this);

        uint unclaimed_tokens = (received_ether - funds_claimed) * multiplier / final_price;
        unclaimed_tokens += rounding_error_tokens;

        if (auction_unclaimed_tokens != unclaimed_tokens) {
            rounding_error_tokens += 1;
            unclaimed_tokens += 1;
        }
        assert(auction_unclaimed_tokens == unclaimed_tokens);
        /* End of removable test */

        // After the last tokens are claimed, we send the auction balance to the owner
        // and change the auction stage
        if (funds_claimed == received_ether) {
            stage = Stages.TokensDistributed;
            TokensDistributed();
        }

        assert(token.balanceOf(receiver) >= num);
        assert(bids[receiver] == 0);
    }

    /*
     *  Private functions
     */

    /// @dev Calculates the token price (WEI / TKN) at the current timestamp
    /// during the auction; elapsed time = 0 before auction starts.
    /// @dev At AuctionDeployed the price is 1, because multiplier is 0
    /// @return Returns the token price - Wei per TKN.
    function calcTokenPrice() constant private returns (uint) {
        uint elapsed;
        if (stage == Stages.AuctionStarted) {
            elapsed = now - start_time;
        }
        return multiplier * price_factor / (elapsed + price_const) + 1;
    }

    /// --------------------------------- Price Functions ----------------------

    /// @notice Get the TKN price in WEI during the auction, at the moment of
    /// calling this method. Returns `0` if auction has ended.
    /// @dev Calculates current token price.
    /// @return Returns num Wei per TKN (multiplier * Tei).
    function price() public constant returns (uint) {
        if (stage == Stages.AuctionEnded ||
            stage == Stages.TokensDistributed) {
            return 0;
        }
        return calcTokenPrice();
    }

    /// @notice Get the missing funds needed to end the auction,
    /// calculated at the current TKN price.
    /// @dev The missing funds amount necessary to end the auction at the current price.
    /// @return Returns the missing funds amount.
    function missingFundsToEndAuction() constant public returns (uint) {
        uint funds_at_price = tokens_auctioned * price() / multiplier;
        if (funds_at_price < received_ether) {
            return 0;
        }
        return funds_at_price - received_ether;
    }
}

pragma solidity ^0.4.11;

import './token.sol';

/// @title Dutch auction contract - distribution of tokens using an auction.
contract DutchAuction {
    /*
     * Auction for the TKN Token.
     *
     * Terminology:
     * 1 token unit = Tei
     * 1 token = TKN = Tei * multiplier
     * multiplier set from token's number of decimals (i.e. 10**decimals)
     */

    /*
     * Storage
     */

    CustomToken public token;
    address public owner;
    address public wallet;

    // Price function parameters
    uint public price_factor;
    uint public price_const;

    // For calculating elapsed time for price
    uint public start_time;
    uint public end_time;
    uint public start_block;

    // Keep track of all ETH received in the bids
    uint public received_ether;

    // Keep track of funds claimed after auction has ended
    uint public funds_claimed;

    // Total number of Tei (TKN * multiplier) that will be auctioned
    uint public multiplier;
    uint public tokens_auctioned;

    // Wei per TKN (Tei * multiplier)
    uint public final_price;

    mapping (address => uint) public bids;

    Stages public stage;

    // TODO - remove after testing
    uint rounding_error_tokens;

    /*
     * Enums
     */
    enum Stages {
        AuctionDeployed,
        AuctionSetUp,
        AuctionStarted,
        AuctionEnded,
        TokensDistributed
    }

    /*
     * Modifiers
     */
    modifier atStage(Stages _stage) {
        require(stage == _stage);
        _;
    }

    modifier isOwner() {
        require(msg.sender == owner);
        _;
    }

    modifier isValidPayload() {
        require(msg.data.length == 0 || msg.data.length == 4 || msg.data.length == 36);
        _;
    }

    /*
     * Events
     */

    event Deployed(
        address indexed _auction,
        uint indexed _price_factor,
        uint indexed _price_const
    );
    event Setup();
    event SettingsChanged(uint indexed _price_factor, uint indexed _price_const);
    event AuctionStarted(uint indexed _start_time, uint indexed _block_number);
    event BidSubmission(
        address indexed _sender,
        uint indexed _amount,
        uint indexed _missing_funds
    );
    event ClaimedTokens(address indexed _recipient, uint indexed _sent_amount);
    event AuctionEnded(uint indexed _final_price);
    event TokensDistributed();

    /*
     * Public functions
     */

    /// @dev Contract constructor function sets price factor and constant for
    /// calculating the Dutch Auction price.
    /// @param _wallet Wallet address to which all contributed ETH will be forwarded.
    /// @param _price_factor Auction price factor.
    /// @param _price_const Auction price divisor constant.
    function DutchAuction(address _wallet, uint _price_factor, uint _price_const) public {
        require(_wallet != 0x0);
        wallet = _wallet;

        owner = msg.sender;
        stage = Stages.AuctionDeployed;
        Deployed(this, price_factor, price_const);
        changeSettings(_price_factor, _price_const);
    }

    /// @dev Fallback function for the contract, which calls bid() if the auction has started.
    function () public payable atStage(Stages.AuctionStarted) {
        bid(msg.sender);
    }

    /// @notice Set `_token` as the token address to be used in the auction.
    /// @dev Setup function sets external contracts addresses.
    /// @param _token Token address.
    function setup(address _token) public isOwner atStage(Stages.AuctionDeployed) {
        require(_token != 0x0);
        token = CustomToken(_token);
        require(token.owner() == owner);
        require(token.auction_address() == address(this));

        // Get number of Tei (TKN * multiplier) to be auctioned from token auction balance
        tokens_auctioned = token.balanceOf(this);

        // Set number of tokens multiplier from token decimals
        multiplier = 10**uint(token.decimals());

        stage = Stages.AuctionSetUp;
        Setup();

        // Tei auctioned
        require(tokens_auctioned > multiplier);
    }

    /// @notice Set `_price_factor` and `_price_const` as the new price factor
    /// and price divisor constant.
    /// @dev Changes auction start price factor before auction is started.
    /// @param _price_factor Updated price factor.
    /// @param _price_const Updated price divisor constant.
    function changeSettings(uint _price_factor, uint _price_const) public isOwner {
        require(stage == Stages.AuctionDeployed || stage == Stages.AuctionSetUp);
        require(_price_factor > 0);
        require(_price_const > 0);

        price_factor = _price_factor;
        price_const = _price_const;
        SettingsChanged(price_factor, price_const);
    }

    /// @notice Start the auction.
    /// @dev Starts auction and sets start_time.
    function startAuction() public isOwner atStage(Stages.AuctionSetUp) {
        stage = Stages.AuctionStarted;
        start_time = now;
        start_block = block.number;
        AuctionStarted(start_time, start_block);
    }

    /// @notice Finalize the auction - sets the final price and changes the auction
    /// stage after no bids are allowed anymore.
    /// @dev Finalize auction and set the final token price.
    function finalizeAuction() public atStage(Stages.AuctionStarted)
    {
        // Missing funds should be 0 at this point
        uint missing_funds = missingFundsToEndAuction();
        assert(missing_funds == 0);

        // Calculate the final price WEI / TKN
        final_price = received_ether / (tokens_auctioned / multiplier);

        end_time = now;
        stage = Stages.AuctionEnded;
        AuctionEnded(final_price);

        assert(final_price > 0);
    }

    /// --------------------------------- Auction Functions ------------------

    /// @notice Send `msg.value` WEI to the auction from the `msg.sender` account.
    /// @dev Allows to send a bid to the auction.
    function bid() public payable atStage(Stages.AuctionStarted) {
        bid(msg.sender);
    }

    /// @notice Send `msg.value` WEI to the auction from the `receiver` account.
    /// @dev Allows to send a bid to the auction.
    /// @param receiver Bidder account address.
    function bid(address receiver)
        public
        payable
        isValidPayload
        atStage(Stages.AuctionStarted)
    {
        require(receiver != 0x0);
        require(msg.value > 0);
        require(bids[receiver] + msg.value >= msg.value);

        uint pre_receiver_funds = bids[receiver];

        // Missing funds without the current bid value
        uint missing_funds = missingFundsToEndAuction();

        // We only allow bid values less than the missing funds to end the auction value.
        require(msg.value <= missing_funds);

        bids[receiver] += msg.value;
        received_ether += msg.value;

        // Send bid amount to wallet
        wallet.transfer(msg.value);

        BidSubmission(receiver, msg.value, missing_funds);

        assert(bids[receiver] == pre_receiver_funds + msg.value);
        assert(received_ether >= msg.value);
    }

    /// @notice Claim auction tokens for `msg.sender` after the auction has ended.
    /// @dev Claims tokens for bidder after auction. To be used if tokens can be claimed by bidders, individually.
    function claimTokens() public atStage(Stages.AuctionEnded) {
        claimTokens(msg.sender);
    }

    /// @notice Claim auction tokens for `receiver` after the auction has ended.
    /// @dev Claims tokens for bidder after auction.
    /// @param receiver Tokens will be assigned to this address if set.
    function claimTokens(address receiver)
        public
        isValidPayload
        atStage(Stages.AuctionEnded)
    {
        require(receiver != 0x0);
        require(bids[receiver] > 0);

        // Number of Tei = bidded_wei / wei_per_TKN * multiplier
        uint num = multiplier * bids[receiver] / final_price;

        // Update funds claimed with full bidded amount
        // rounding errors are included to not block the contract
        funds_claimed += bids[receiver];

        // Set receiver bid to 0 before assigning tokens
        bids[receiver] = 0;

        require(token.transfer(receiver, num));

        ClaimedTokens(receiver, num);

        // Test for a correct claimed tokens calculation
        /* TODO remove this after testing */
        uint auction_unclaimed_tokens = token.balanceOf(this);

        uint unclaimed_tokens = (received_ether - funds_claimed) * multiplier / final_price;
        unclaimed_tokens += rounding_error_tokens;

        if (auction_unclaimed_tokens != unclaimed_tokens) {
            rounding_error_tokens += 1;
            unclaimed_tokens += 1;
        }
        assert(auction_unclaimed_tokens == unclaimed_tokens);
        /* End of removable test */

        // After the last tokens are claimed, we send the auction balance to the owner
        // and change the auction stage
        if (funds_claimed == received_ether) {
            stage = Stages.TokensDistributed;
            TokensDistributed();
        }

        assert(token.balanceOf(receiver) >= num);
        assert(bids[receiver] == 0);
    }

    /*
     *  Private functions
     */

    /// @dev Calculates the token price (WEI / TKN) at the current timestamp
    /// during the auction; elapsed time = 0 before auction starts.
    /// @dev At AuctionDeployed the price is 1, because multiplier is 0
    /// @return Returns the token price - Wei per TKN.
    function calcTokenPrice() constant private returns (uint) {
        uint elapsed;
        if (stage == Stages.AuctionStarted) {
            elapsed = now - start_time;
        }
        return multiplier * price_factor / (elapsed + price_const) + 1;
    }

    /// --------------------------------- Price Functions ----------------------

    /// @notice Get the TKN price in WEI during the auction, at the moment of
    /// calling this method. Returns `0` if auction has ended.
    /// @dev Calculates current token price.
    /// @return Returns num Wei per TKN (multiplier * Tei).
    function price() public constant returns (uint) {
        if (stage == Stages.AuctionEnded ||
            stage == Stages.TokensDistributed) {
            return 0;
        }
        return calcTokenPrice();
    }

    /// @notice Get the missing funds needed to end the auction,
    /// calculated at the current TKN price.
    /// @dev The missing funds amount necessary to end the auction at the current price.
    /// @return Returns the missing funds amount.
    function missingFundsToEndAuction() constant public returns (uint) {
        uint funds_at_price = tokens_auctioned * price() / multiplier;
        if (funds_at_price < received_ether) {
            return 0;
        }
        return funds_at_price - received_ether;
    }
}