Fix typo: to be find (#1642)

Fix typo: to be find (#1642)

pragma solidity ^0.5.2;

import "../math/Math.sol";

/**
 * @title Arrays
 * @dev Utility library of inline array functions
 */
library Arrays {
    /**
     * @dev Upper bound search function which is kind of binary search algoritm. It searches sorted
     * array to find index of the element value. If element is found then returns it's index otherwise
     * it returns index of first element which is grater than searched value. If searched element is
     * bigger than any array element function then returns first index after last element (i.e. all
     * values inside the array are smaller than the target). Complexity O(log n).
     * @param array The array sorted in ascending order.
     * @param element The element's value to be found.
     * @return The calculated index value. Returns 0 for empty array.
     */
    function findUpperBound(uint256[] storage array, uint256 element) internal view returns (uint256) {
        if (array.length == 0) {
            return 0;
        }

        uint256 low = 0;
        uint256 high = array.length;

        while (low < high) {
            uint256 mid = Math.average(low, high);

            // Note that mid will always be strictly less than high (i.e. it will be a valid array index)
            // because Math.average rounds down (it does integer division with truncation).
            if (array[mid] > element) {
                high = mid;
            } else {
                low = mid + 1;
            }
        }

        // At this point `low` is the exclusive upper bound. We will return the inclusive upper bound.
        if (low > 0 && array[low - 1] == element) {
            return low - 1;
        } else {
            return low;
        }
    }
}

pragma solidity ^0.5.2;

import "../math/Math.sol";

/**
 * @title Arrays
 * @dev Utility library of inline array functions
 */
library Arrays {
    /**
     * @dev Upper bound search function which is kind of binary search algoritm. It searches sorted
     * array to find index of the element value. If element is found then returns it's index otherwise
     * it returns index of first element which is grater than searched value. If searched element is
     * bigger than any array element function then returns first index after last element (i.e. all
     * values inside the array are smaller than the target). Complexity O(log n).
     * @param array The array sorted in ascending order.
     * @param element The element's value to be find.
     * @return The calculated index value. Returns 0 for empty array.
     */
    function findUpperBound(uint256[] storage array, uint256 element) internal view returns (uint256) {
        if (array.length == 0) {
            return 0;
        }

        uint256 low = 0;
        uint256 high = array.length;

        while (low < high) {
            uint256 mid = Math.average(low, high);

            // Note that mid will always be strictly less than high (i.e. it will be a valid array index)
            // because Math.average rounds down (it does integer division with truncation).
            if (array[mid] > element) {
                high = mid;
            } else {
                low = mid + 1;
            }
        }

        // At this point `low` is the exclusive upper bound. We will return the inclusive upper bound.
        if (low > 0 && array[low - 1] == element) {
            return low - 1;
        } else {
            return low;
        }
    }
}


updated open issues

updated open issues

pragma solidity ^0.4.9;
import "owned.sol";

/*
    Open issues:
    - throw vs. return value?
    - possibly add modifiers for each stage
    - possibly create a shared standard token contract and inherit from it, both for the BancorToken and for the BancorEtherToken
    - add miner abuse protection
    - allow exchanging between 2 reserve tokens directly? can be done through a 3rd party contract
    - startTrading - looping over the reserve - can run out of gas. Possibly split it and do it as a multi-step process
    - what happens if one of the reserve tokens gets exploited/hacked/crashes etc.?
    - approve - to minimize the risk of the approve/transferFrom attack vector
                (see https://docs.google.com/document/d/1YLPtQxZu1UAvO9cZ1O2RPXBbT0mooh4DYKjA_jp-RLM/), approve has to be called twice
                in 2 separate transactions - once to change the allowance to 0 and secondly to change it to the new allowance value.
                Also relevant to the BancorEtherToken
*/

// interfaces

contract ReserveToken { // any ERC20 standard token
    function balanceOf(address _owner) public constant returns (uint256 balance);
    function transfer(address _to, uint256 _value) public returns (bool success);
    function transferFrom(address _from, address _to, uint256 _value) public returns (bool success);
}

contract BancorFormula {
    function calculatePurchaseValue(uint256 _supply, uint256 _reserveBalance, uint16 _reserveRatio, uint256 _depositAmount) public constant returns (uint256 value);
    function calculateSaleValue(uint256 _supply, uint256 _reserveBalance, uint16 _reserveRatio, uint256 _sellAmount) public constant returns (uint256 value);
    function newFormula() public constant returns (address newFormula);
}

contract BancorEvents {
    function newToken() public;
    function tokenUpdate() public;
    function tokenTransfer(address _from, address _to, uint256 _value) public;
    function tokenApproval(address _owner, address _spender, uint256 _value) public;
    function tokenConversion(address _reserveToken, address _trader, bool _isPurchase, uint256 _totalSupply,
                             uint256 _reserveBalance, uint256 _tokenAmount, uint256 _reserveAmount) public;
}

/*
    Bancor Token v0.2
*/
contract BancorToken is owned {
    enum Stage { Managed, Crowdsale, Traded }

    string public standard = 'Token 0.1';
    string public name = "";
    string public symbol = "";                          // 1-6 characters
    uint8 public numDecimalUnits = 0;                   // for display purposes only
    uint256 public totalSupply = 0;
    address public formula = 0x0;                       // bancor calculation formula contract address
    address public events = 0x0;                        // bancor events contract address
    address public crowdsale = 0x0;                     // crowdsale contract address
    int256 public crowdsaleAllowance = 0;               // current number of tokens the crowdsale contract is allowed to issue, or -1 for unlimited
    Stage public stage = Stage.Managed;                 // token stage
    address[] public reserveTokens;                     // ERC20 standard token addresses
    mapping (address => uint8) public reserveRatioOf;   // token addresses -> constant reserve ratio, 1-99
    mapping (address => uint256) public balanceOf;
    mapping (address => mapping (address => uint256)) public allowance;

    // events, can be used to listen to the contract directly, as opposed to through the events contract
    event Update();
    event Transfer(address indexed _from, address indexed _to, uint256 _value);
    event Approval(address indexed _owner, address indexed _spender, uint256 _value);
    event Conversion(address indexed _reserveToken, address indexed _trader, bool _isPurchase,
                     uint256 _totalSupply, uint256 _reserveBalance, uint256 _tokenAmount, uint256 _reserveAmount);

    /*
        _name               token name
        _symbol             token short symbol
        _numDecimalUnits    for display purposes only
        _formula            address of a bancor formula contract
        _events             optional, address of a bancor events contract
    */
    function BancorToken(string _name, string _symbol, uint8 _numDecimalUnits, address _formula, address _events) {
        if (bytes(_name).length == 0 || bytes(_symbol).length < 1 || bytes(_symbol).length > 6 || _formula == 0x0) // validate input
            throw;

        name = _name;
        symbol = _symbol;
        numDecimalUnits = _numDecimalUnits;
        formula = _formula;
        events = _events;

        if (events == 0x0)
            return;

        BancorEvents eventsContract = BancorEvents(events);
        eventsContract.newToken();
    }

    // allows executing a function by the owner in managed stage or by the crowdsale contract in crowdsale stage
    modifier onlyManager {
        if (stage == Stage.Traded ||
            stage == Stage.Managed && msg.sender != owner ||
            stage == Stage.Crowdsale && msg.sender != crowdsale) // validate state & permissions
            throw;
        _;
    }

    /*
        updates the bancor calculation formula contract address
        can only be called by the token owner

        the owner can only update the formula to a new one approved by the current formula's owner

        _formula     new formula contract address
    */
    function setFormula(address _formula) public onlyOwner returns (bool success) {
        BancorFormula formulaContract = BancorFormula(formula);
        if (formulaContract.newFormula() != _formula)
            throw;

        formula = _formula;
        return true;
    }

    /*
        returns the number of reserve tokens defined
    */
    function reserveTokenCount() public constant returns (uint8 count) {
        return uint8(reserveTokens.length);
    }

    /*
        defines a new reserve for the token (managed stage only)
        can only be called by the token owner

        _token  address of the reserve token
        _ratio  constant reserve ratio, 1-99
    */
    function addReserve(address _token, uint8 _ratio) public onlyOwner returns (bool success) {
        if (reserveRatioOf[_token] != 0 || _ratio < 1 || _ratio > 99) // validate input
            throw;
        if (stage != Stage.Managed) // validate state
            throw;

        reserveRatioOf[_token] = _ratio;
        reserveTokens.push(_token);
        dispatchUpdate();
        return true;
    }

    /*
        increases the token supply and sends the new tokens to an account
        can only be called by the token owner (in managed stage only) or the crowdsale contract (in a non manged stage only)

        _to         account to receive the new amount
        _amount     amount to increase the supply by
    */
    function issue(address _to, uint256 _amount) public returns (bool success) {
        if (_amount == 0) // validate input
            throw;
        if (stage == Stage.Managed && msg.sender != owner ||
            stage != Stage.Managed && msg.sender != crowdsale) // validate permissions
            throw;
        if (totalSupply + _amount < totalSupply) // supply overflow protection
            throw;
        if (balanceOf[_to] + _amount < balanceOf[_to]) // target account balance overflow protection
            throw;
        if (stage != Stage.Managed && crowdsaleAllowance >= 0 && _amount > uint256(crowdsaleAllowance)) // check if the crowdsale contract is trying to issue more tokens than allowed
            throw;

        totalSupply += _amount;
        balanceOf[_to] += _amount;
        if (stage != Stage.Managed && crowdsaleAllowance >= 0)
            crowdsaleAllowance -= int256(_amount);

        dispatchUpdate();
        dispatchTransfer(this, _to, _amount);
        return true;
    }

    /*
        Removes tokens from an account and decreases the token supply
        can only be called by the token owner (in managed stage only) or the crowdsale contract (in crowdsale stage only)

        _from       account to remove the new amount from
        _amount     amount to decrease the supply by
    */
    function destroy(address _from, uint256 _amount) public onlyManager returns (bool success) {
        if (_amount == 0) // validate input
            throw;
        if (_amount > totalSupply) // negative supply protection
            throw;
        if (_amount > balanceOf[_from]) // target account negative balance protection
            throw;

        totalSupply -= _amount;
        balanceOf[_from] -= _amount;
        dispatchUpdate();
        dispatchTransfer(_from, this, _amount);
        return true;
    }

    /*
        withdraws tokens from the reserve and sends them to an account
        can only be called by the token owner (in managed stage only) or the crowdsale contract (in crowdsale stage only)

        _reserveToken    reserve token contract address
        _to              account to receive the new amount
        _amount          amount to withdraw (in the reserve token)
    */
    function withdraw(address _reserveToken, address _to, uint256 _amount) public onlyManager returns (bool success) {
        if (reserveRatioOf[_reserveToken] == 0 || _amount == 0) // validate input
            throw;

        ReserveToken reserveToken = ReserveToken(_reserveToken);
        return reserveToken.transfer(_to, _amount);
    }

    /*
        starts the crowdsale stage (managed stage only)
        can only be called by the token owner

        _crowdsale      new crowdsale contract address
        _allowance      maximum number of tokens that can be issued by the crowdsale contract, or -1 for unlimited
    */
    function startCrowdsale(address _crowdsale, int256 _allowance) public onlyOwner returns (bool success) {
        if (_crowdsale == 0x0 || _allowance == 0) // validate input
            throw;
        if (stage != Stage.Managed || reserveTokens.length == 0) // validate state
            throw;

        crowdsale = _crowdsale;
        crowdsaleAllowance = _allowance;
        stage = Stage.Crowdsale;
        dispatchUpdate();
        return true;
    }

    /*
        starts the traded stage
        can only be called by the token owner (in managed stage only) or the crowdsale contract (in crowdsale stage only)
    */
    function startTrading() public onlyManager returns (bool success) {
        if (totalSupply == 0) // validate state
            throw;

        // make sure that there's balance in all the reserves
        for (uint16 i = 0; i < reserveTokens.length; ++i) {
            ReserveToken reserveToken = ReserveToken(reserveTokens[i]);
            if (reserveToken.balanceOf(this) == 0)
                throw;
        }

        stage = Stage.Traded;
        dispatchUpdate();
        return true;
    }

    /*
        buys the token by depositing one of its reserve tokens

        _reserveToken   reserve token contract address
        _depositAmount  amount to deposit (in the reserve token)
        _minimumValue   if the conversion results in a value smaller than this value, it is cancelled
    */
    function buy(address _reserveToken, uint256 _depositAmount, uint256 _minimumValue) public returns (uint256 value) {
        uint8 reserveRatio = reserveRatioOf[_reserveToken];
        if (reserveRatio == 0 || _depositAmount == 0) // validate input
            throw;
        if (stage != Stage.Traded) // validate state
            throw;

        ReserveToken reserveToken = ReserveToken(_reserveToken);
        uint256 reserveBalance = reserveToken.balanceOf(this);

        BancorFormula formulaContract = BancorFormula(formula);
        value = formulaContract.calculatePurchaseValue(totalSupply, reserveBalance, reserveRatio, _depositAmount);
        if (value == 0 || value < _minimumValue) // trade gave nothing in return or didn't return a value that meets the minimum requested value
            throw;
        if (totalSupply + value < totalSupply) // supply overflow protection
            throw;
        if (!reserveToken.transferFrom(msg.sender, this, _depositAmount)) // can't withdraw funds from the reserve token
            throw;

        uint256 startSupply = totalSupply;
        totalSupply += value;
        balanceOf[msg.sender] += value;
        dispatchConversion(_reserveToken, msg.sender, true, startSupply, reserveBalance, value, _depositAmount);
        return value;
    }

    /*
        sells the token by withdrawing from one of its reserve tokens

        _reserveToken   reserve token contract address
        _sellAmount     amount to sell (in the token)
        _minimumValue   if the conversion results in a value smaller than this value, it is cancelled
    */
    function sell(address _reserveToken, uint256 _sellAmount, uint256 _minimumValue) public returns (uint256 value) {
        uint8 reserveRatio = reserveRatioOf[_reserveToken];
        if (reserveRatio == 0 || _sellAmount == 0) // validate input
            throw;
        if (stage != Stage.Traded) // validate state
            throw;
        if (balanceOf[msg.sender] < _sellAmount) // balance check
            throw;

        ReserveToken reserveToken = ReserveToken(_reserveToken);
        uint256 reserveBalance = reserveToken.balanceOf(this);

        BancorFormula formulaContract = BancorFormula(formula);
        value = formulaContract.calculateSaleValue(totalSupply, reserveBalance, reserveRatio, _sellAmount);
        if (value == 0 || value < _minimumValue) // trade gave nothing in return or didn't return a value that meets the minimum requested value
            throw;
        if (reserveBalance <= value) // trade will deplete the reserve
            throw;

        uint256 startSupply = totalSupply;
        totalSupply -= _sellAmount;
        balanceOf[msg.sender] -= _sellAmount;
        if (!reserveToken.transfer(msg.sender, value)) // can't transfer funds to the caller
            throw;

        // if the supply was totally depleted, return to managed stage
        if (totalSupply == 0) {
            crowdsale = 0x0;
            crowdsaleAllowance = 0;
            stage = Stage.Managed;
        }

        dispatchConversion(_reserveToken, msg.sender, false, startSupply, reserveBalance, _sellAmount, value);
        return value;
    }

    // ERC20 standard methods

    // send coins
    function transfer(address _to, uint256 _value) public returns (bool success) {
        if (balanceOf[msg.sender] < _value) // balance check
            throw;
        if (balanceOf[_to] + _value < balanceOf[_to]) // overflow protection
            throw;

        balanceOf[msg.sender] -= _value;
        if (_to == address(this)) // transferring to the contract address destroys tokens
            totalSupply -= _value;
        else
            balanceOf[_to] += _value;

        dispatchTransfer(msg.sender, _to, _value);
        return true;
    }

    // allow another account/contract to spend some tokens on your behalf
    function approve(address _spender, uint256 _value) public returns (bool success) {
        // if the allowance isn't 0, it can only be updated to 0 to prevent an allowance change immediately after withdrawal
        if (_value != 0 && allowance[msg.sender][_spender] != 0)
            throw;

        allowance[msg.sender][_spender] = _value;

        Approval(msg.sender, _spender, _value);
        if (events == 0x0)
            return true;

        BancorEvents eventsContract = BancorEvents(events);
        eventsContract.tokenApproval(msg.sender, _spender, _value);
        return true;
    }

    // an account/contract attempts to get the coins
    function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {
        if (balanceOf[_from] < _value) // balance check
            throw;
        if (balanceOf[_to] + _value < balanceOf[_to]) // overflow protection
            throw;
        if (_value > allowance[_from][msg.sender]) // allowance check
            throw;

        balanceOf[_from] -= _value;
        balanceOf[_to] += _value;
        allowance[_from][msg.sender] -= _value;

        dispatchTransfer(_from, _to, _value);
        return true;
    }

    // utility

    function dispatchUpdate() private {
        Update();
        if (events == 0x0)
            return;

        BancorEvents eventsContract = BancorEvents(events);
        eventsContract.tokenUpdate();
    }

    function dispatchTransfer(address _from, address _to, uint256 _value) private {
        Transfer(_from, _to, _value);
        if (events == 0x0)
            return;

        BancorEvents eventsContract = BancorEvents(events);
        eventsContract.tokenTransfer(_from, _to, _value);
    }

    function dispatchConversion(address _reserveToken, address _trader, bool _isPurchase,
                                uint256 _totalSupply, uint256 _reserveBalance, uint256 _tokenAmount, uint256 _reserveAmount) private {
        Conversion(_reserveToken, _trader, _isPurchase, _totalSupply, _reserveBalance, _tokenAmount, _reserveAmount);
        if (events == 0x0)
            return;

        BancorEvents eventsContract = BancorEvents(events);
        eventsContract.tokenConversion(_reserveToken, _trader, _isPurchase, _totalSupply, _reserveBalance, _tokenAmount, _reserveAmount);
    }

    // fallback

    function() {
        throw;
    }
}

pragma solidity ^0.4.9;
import "owned.sol";

/*
    Open issues:
    - throw vs. return value?
    - possibly add modifiers for each stage
    - possibly create a shared standard token contract and inherit from it, both for the BancorToken and for the BancorEtherToken
    - add miner abuse protection
    - allow exchanging between 2 reserve tokens directly? can be done through a 3rd party contract
    - startTrading - looping over the reserve - can run out of gas. Possibly split it and do it as a multi-step process
    - approve - to minimize the risk of the approve/transferFrom attack vector
                (see https://docs.google.com/document/d/1YLPtQxZu1UAvO9cZ1O2RPXBbT0mooh4DYKjA_jp-RLM/), approve has to be called twice
                in 2 separate transactions - once to change the allowance to 0 and secondly to change it to the new allowance value.
                Also relevant to the BancorEtherToken
*/

// interfaces

contract ReserveToken { // any ERC20 standard token
    function balanceOf(address _owner) public constant returns (uint256 balance);
    function transfer(address _to, uint256 _value) public returns (bool success);
    function transferFrom(address _from, address _to, uint256 _value) public returns (bool success);
}

contract BancorFormula {
    function calculatePurchaseValue(uint256 _supply, uint256 _reserveBalance, uint16 _reserveRatio, uint256 _depositAmount) public constant returns (uint256 value);
    function calculateSaleValue(uint256 _supply, uint256 _reserveBalance, uint16 _reserveRatio, uint256 _sellAmount) public constant returns (uint256 value);
    function newFormula() public constant returns (address newFormula);
}

contract BancorEvents {
    function newToken() public;
    function tokenUpdate() public;
    function tokenTransfer(address _from, address _to, uint256 _value) public;
    function tokenApproval(address _owner, address _spender, uint256 _value) public;
    function tokenConversion(address _reserveToken, address _trader, bool _isPurchase, uint256 _totalSupply,
                             uint256 _reserveBalance, uint256 _tokenAmount, uint256 _reserveAmount) public;
}

/*
    Bancor Token v0.2
*/
contract BancorToken is owned {
    enum Stage { Managed, Crowdsale, Traded }

    string public standard = 'Token 0.1';
    string public name = "";
    string public symbol = "";                          // 1-6 characters
    uint8 public numDecimalUnits = 0;                   // for display purposes only
    uint256 public totalSupply = 0;
    address public formula = 0x0;                       // bancor calculation formula contract address
    address public events = 0x0;                        // bancor events contract address
    address public crowdsale = 0x0;                     // crowdsale contract address
    int256 public crowdsaleAllowance = 0;               // current number of tokens the crowdsale contract is allowed to issue, or -1 for unlimited
    Stage public stage = Stage.Managed;                 // token stage
    address[] public reserveTokens;                     // ERC20 standard token addresses
    mapping (address => uint8) public reserveRatioOf;   // token addresses -> constant reserve ratio, 1-99
    mapping (address => uint256) public balanceOf;
    mapping (address => mapping (address => uint256)) public allowance;

    // events, can be used to listen to the contract directly, as opposed to through the events contract
    event Update();
    event Transfer(address indexed _from, address indexed _to, uint256 _value);
    event Approval(address indexed _owner, address indexed _spender, uint256 _value);
    event Conversion(address indexed _reserveToken, address indexed _trader, bool _isPurchase,
                     uint256 _totalSupply, uint256 _reserveBalance, uint256 _tokenAmount, uint256 _reserveAmount);

    /*
        _name               token name
        _symbol             token short symbol
        _numDecimalUnits    for display purposes only
        _formula            address of a bancor formula contract
        _events             optional, address of a bancor events contract
    */
    function BancorToken(string _name, string _symbol, uint8 _numDecimalUnits, address _formula, address _events) {
        if (bytes(_name).length == 0 || bytes(_symbol).length < 1 || bytes(_symbol).length > 6 || _formula == 0x0) // validate input
            throw;

        name = _name;
        symbol = _symbol;
        numDecimalUnits = _numDecimalUnits;
        formula = _formula;
        events = _events;

        if (events == 0x0)
            return;

        BancorEvents eventsContract = BancorEvents(events);
        eventsContract.newToken();
    }

    // allows executing a function by the owner in managed stage or by the crowdsale contract in crowdsale stage
    modifier onlyManager {
        if (stage == Stage.Traded ||
            stage == Stage.Managed && msg.sender != owner ||
            stage == Stage.Crowdsale && msg.sender != crowdsale) // validate state & permissions
            throw;
        _;
    }

    /*
        updates the bancor calculation formula contract address
        can only be called by the token owner

        the owner can only update the formula to a new one approved by the current formula's owner

        _formula     new formula contract address
    */
    function setFormula(address _formula) public onlyOwner returns (bool success) {
        BancorFormula formulaContract = BancorFormula(formula);
        if (formulaContract.newFormula() != _formula)
            throw;

        formula = _formula;
        return true;
    }

    /*
        returns the number of reserve tokens defined
    */
    function reserveTokenCount() public constant returns (uint8 count) {
        return uint8(reserveTokens.length);
    }

    /*
        defines a new reserve for the token (managed stage only)
        can only be called by the token owner

        _token  address of the reserve token
        _ratio  constant reserve ratio, 1-99
    */
    function addReserve(address _token, uint8 _ratio) public onlyOwner returns (bool success) {
        if (reserveRatioOf[_token] != 0 || _ratio < 1 || _ratio > 99) // validate input
            throw;
        if (stage != Stage.Managed) // validate state
            throw;

        reserveRatioOf[_token] = _ratio;
        reserveTokens.push(_token);
        dispatchUpdate();
        return true;
    }

    /*
        increases the token supply and sends the new tokens to an account
        can only be called by the token owner (in managed stage only) or the crowdsale contract (in a non manged stage only)

        _to         account to receive the new amount
        _amount     amount to increase the supply by
    */
    function issue(address _to, uint256 _amount) public returns (bool success) {
        if (_amount == 0) // validate input
            throw;
        if (stage == Stage.Managed && msg.sender != owner ||
            stage != Stage.Managed && msg.sender != crowdsale) // validate permissions
            throw;
        if (totalSupply + _amount < totalSupply) // supply overflow protection
            throw;
        if (balanceOf[_to] + _amount < balanceOf[_to]) // target account balance overflow protection
            throw;
        if (stage != Stage.Managed && crowdsaleAllowance >= 0 && _amount > uint256(crowdsaleAllowance)) // check if the crowdsale contract is trying to issue more tokens than allowed
            throw;

        totalSupply += _amount;
        balanceOf[_to] += _amount;
        if (stage != Stage.Managed && crowdsaleAllowance >= 0)
            crowdsaleAllowance -= int256(_amount);

        dispatchUpdate();
        dispatchTransfer(this, _to, _amount);
        return true;
    }

    /*
        Removes tokens from an account and decreases the token supply
        can only be called by the token owner (in managed stage only) or the crowdsale contract (in crowdsale stage only)

        _from       account to remove the new amount from
        _amount     amount to decrease the supply by
    */
    function destroy(address _from, uint256 _amount) public onlyManager returns (bool success) {
        if (_amount == 0) // validate input
            throw;
        if (_amount > totalSupply) // negative supply protection
            throw;
        if (_amount > balanceOf[_from]) // target account negative balance protection
            throw;

        totalSupply -= _amount;
        balanceOf[_from] -= _amount;
        dispatchUpdate();
        dispatchTransfer(_from, this, _amount);
        return true;
    }

    /*
        withdraws tokens from the reserve and sends them to an account
        can only be called by the token owner (in managed stage only) or the crowdsale contract (in crowdsale stage only)

        _reserveToken    reserve token contract address
        _to              account to receive the new amount
        _amount          amount to withdraw (in the reserve token)
    */
    function withdraw(address _reserveToken, address _to, uint256 _amount) public onlyManager returns (bool success) {
        if (reserveRatioOf[_reserveToken] == 0 || _amount == 0) // validate input
            throw;

        ReserveToken reserveToken = ReserveToken(_reserveToken);
        return reserveToken.transfer(_to, _amount);
    }

    /*
        starts the crowdsale stage (managed stage only)
        can only be called by the token owner

        _crowdsale      new crowdsale contract address
        _allowance      maximum number of tokens that can be issued by the crowdsale contract, or -1 for unlimited
    */
    function startCrowdsale(address _crowdsale, int256 _allowance) public onlyOwner returns (bool success) {
        if (_crowdsale == 0x0 || _allowance == 0) // validate input
            throw;
        if (stage != Stage.Managed || reserveTokens.length == 0) // validate state
            throw;

        crowdsale = _crowdsale;
        crowdsaleAllowance = _allowance;
        stage = Stage.Crowdsale;
        dispatchUpdate();
        return true;
    }

    /*
        starts the traded stage
        can only be called by the token owner (in managed stage only) or the crowdsale contract (in crowdsale stage only)
    */
    function startTrading() public onlyManager returns (bool success) {
        if (totalSupply == 0) // validate state
            throw;

        // make sure that there's balance in all the reserves
        for (uint16 i = 0; i < reserveTokens.length; ++i) {
            ReserveToken reserveToken = ReserveToken(reserveTokens[i]);
            if (reserveToken.balanceOf(this) == 0)
                throw;
        }

        stage = Stage.Traded;
        dispatchUpdate();
        return true;
    }

    /*
        buys the token by depositing one of its reserve tokens

        _reserveToken   reserve token contract address
        _depositAmount  amount to deposit (in the reserve token)
        _minimumValue   if the conversion results in a value smaller than this value, it is cancelled
    */
    function buy(address _reserveToken, uint256 _depositAmount, uint256 _minimumValue) public returns (uint256 value) {
        uint8 reserveRatio = reserveRatioOf[_reserveToken];
        if (reserveRatio == 0 || _depositAmount == 0) // validate input
            throw;
        if (stage != Stage.Traded) // validate state
            throw;

        ReserveToken reserveToken = ReserveToken(_reserveToken);
        uint256 reserveBalance = reserveToken.balanceOf(this);

        BancorFormula formulaContract = BancorFormula(formula);
        value = formulaContract.calculatePurchaseValue(totalSupply, reserveBalance, reserveRatio, _depositAmount);
        if (value == 0 || value < _minimumValue) // trade gave nothing in return or didn't return a value that meets the minimum requested value
            throw;
        if (totalSupply + value < totalSupply) // supply overflow protection
            throw;
        if (!reserveToken.transferFrom(msg.sender, this, _depositAmount)) // can't withdraw funds from the reserve token
            throw;

        uint256 startSupply = totalSupply;
        totalSupply += value;
        balanceOf[msg.sender] += value;
        dispatchConversion(_reserveToken, msg.sender, true, startSupply, reserveBalance, value, _depositAmount);
        return value;
    }

    /*
        sells the token by withdrawing from one of its reserve tokens

        _reserveToken   reserve token contract address
        _sellAmount     amount to sell (in the token)
        _minimumValue   if the conversion results in a value smaller than this value, it is cancelled
    */
    function sell(address _reserveToken, uint256 _sellAmount, uint256 _minimumValue) public returns (uint256 value) {
        uint8 reserveRatio = reserveRatioOf[_reserveToken];
        if (reserveRatio == 0 || _sellAmount == 0) // validate input
            throw;
        if (stage != Stage.Traded) // validate state
            throw;
        if (balanceOf[msg.sender] < _sellAmount) // balance check
            throw;

        ReserveToken reserveToken = ReserveToken(_reserveToken);
        uint256 reserveBalance = reserveToken.balanceOf(this);

        BancorFormula formulaContract = BancorFormula(formula);
        value = formulaContract.calculateSaleValue(totalSupply, reserveBalance, reserveRatio, _sellAmount);
        if (value == 0 || value < _minimumValue) // trade gave nothing in return or didn't return a value that meets the minimum requested value
            throw;
        if (reserveBalance <= value) // trade will deplete the reserve
            throw;

        uint256 startSupply = totalSupply;
        totalSupply -= _sellAmount;
        balanceOf[msg.sender] -= _sellAmount;
        if (!reserveToken.transfer(msg.sender, value)) // can't transfer funds to the caller
            throw;

        // if the supply was totally depleted, return to managed stage
        if (totalSupply == 0) {
            crowdsale = 0x0;
            crowdsaleAllowance = 0;
            stage = Stage.Managed;
        }

        dispatchConversion(_reserveToken, msg.sender, false, startSupply, reserveBalance, _sellAmount, value);
        return value;
    }

    // ERC20 standard methods

    // send coins
    function transfer(address _to, uint256 _value) public returns (bool success) {
        if (balanceOf[msg.sender] < _value) // balance check
            throw;
        if (balanceOf[_to] + _value < balanceOf[_to]) // overflow protection
            throw;

        balanceOf[msg.sender] -= _value;
        if (_to == address(this)) // transferring to the contract address destroys tokens
            totalSupply -= _value;
        else
            balanceOf[_to] += _value;

        dispatchTransfer(msg.sender, _to, _value);
        return true;
    }

    // allow another account/contract to spend some tokens on your behalf
    function approve(address _spender, uint256 _value) public returns (bool success) {
        // if the allowance isn't 0, it can only be updated to 0 to prevent an allowance change immediately after withdrawal
        if (_value != 0 && allowance[msg.sender][_spender] != 0)
            throw;

        allowance[msg.sender][_spender] = _value;

        Approval(msg.sender, _spender, _value);
        if (events == 0x0)
            return true;

        BancorEvents eventsContract = BancorEvents(events);
        eventsContract.tokenApproval(msg.sender, _spender, _value);
        return true;
    }

    // an account/contract attempts to get the coins
    function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {
        if (balanceOf[_from] < _value) // balance check
            throw;
        if (balanceOf[_to] + _value < balanceOf[_to]) // overflow protection
            throw;
        if (_value > allowance[_from][msg.sender]) // allowance check
            throw;

        balanceOf[_from] -= _value;
        balanceOf[_to] += _value;
        allowance[_from][msg.sender] -= _value;

        dispatchTransfer(_from, _to, _value);
        return true;
    }

    // utility

    function dispatchUpdate() private {
        Update();
        if (events == 0x0)
            return;

        BancorEvents eventsContract = BancorEvents(events);
        eventsContract.tokenUpdate();
    }

    function dispatchTransfer(address _from, address _to, uint256 _value) private {
        Transfer(_from, _to, _value);
        if (events == 0x0)
            return;

        BancorEvents eventsContract = BancorEvents(events);
        eventsContract.tokenTransfer(_from, _to, _value);
    }

    function dispatchConversion(address _reserveToken, address _trader, bool _isPurchase,
                                uint256 _totalSupply, uint256 _reserveBalance, uint256 _tokenAmount, uint256 _reserveAmount) private {
        Conversion(_reserveToken, _trader, _isPurchase, _totalSupply, _reserveBalance, _tokenAmount, _reserveAmount);
        if (events == 0x0)
            return;

        BancorEvents eventsContract = BancorEvents(events);
        eventsContract.tokenConversion(_reserveToken, _trader, _isPurchase, _totalSupply, _reserveBalance, _tokenAmount, _reserveAmount);
    }

    // fallback

    function() {
        throw;
    }
}


fix rebase conflicts

fix rebase conflicts

pragma solidity ^0.4.0;

import "./ChannelManagerContract.sol";

contract Registry {
    mapping(address => address) public registry;
    address[] public tokens;

    event TokenAdded(address token_address, address channel_manager_address);

    modifier addressExists(address _address) {
        require(registry[_address] != 0x0);
        _;
    }

    modifier doesNotExist(address _address) {
        // Check if it's already registered or token contract is invalid.
        // We assume if it has a valid totalSupply() function it's a valid Token contract
        require(registry[_address] == 0x0);
        Token token = Token(_address);
        token.totalSupply();
        _;
    }

    /// @notice Register a new ERC20 token
    /// @param token_address Address of the token
    /// @return The address of the channel manager
    function addToken(address token_address)
        doesNotExist(token_address)
        returns (address)
    {
        address manager_address;

        manager_address = new ChannelManagerContract(token_address);

        registry[token_address] = manager_address;
        tokens.push(token_address);

        TokenAdded(token_address, manager_address);

        return manager_address;
    }

    /// @notice Get the ChannelManager address for a specific token
    /// @param token_address The address of the given token
    /// @return Address of channel manager
    function channelManagerByToken(address token_address)
        addressExists(token_address)
        constant
        returns (address)
    {
        return registry[token_address];
    }

    /// @notice Get all registered tokens
    /// @return addresses of all registered tokens
    function tokenAddresses()
        constant
        returns (address[])
    {
        return tokens;
    }

    /// @notice Get the addresses of all channel managers for all registered tokens
    /// @return addresses of all channel managers
    function channelManagerAddresses()
        constant
        returns (address[])
    {
        uint i;
        address token_address;
        address[] memory result;

        result = new address[](tokens.length);

        for (i = 0; i < tokens.length; i++) {
            token_address = tokens[i];
            result[i] = registry[token_address];
        }

        return result;
    }

    function () { revert(); }
}

pragma solidity ^0.4.0;

import "./ChannelManagerContract.sol";

contract Registry {
    mapping(address => address) public registry;
    address[] public tokens;

    event TokenAdded(address token_address, address channel_manager_address);

    modifier addressExists(address _address) {
        require(registry[_address] != 0x0);
        _;
    }

    modifier doesNotExist(address _address) {
        // Check if it's already registered or token contract is invalid.
        // We assume if it has a valid totalSupply() function it's a valid Token contract
        if (registry[_address] != 0x0)
            throw;
        Token token = Token(_address);
        token.totalSupply();
        _;
    }

    /// @notice Register a new ERC20 token
    /// @param token_address Address of the token
    /// @return The address of the channel manager
    function addToken(address token_address)
        doesNotExist(token_address)
        returns (address)
    {
        address manager_address;

        manager_address = new ChannelManagerContract(token_address);

        registry[token_address] = manager_address;
        tokens.push(token_address);

        TokenAdded(token_address, manager_address);

        return manager_address;
    }

    /// @notice Get the ChannelManager address for a specific token
    /// @param token_address The address of the given token
    /// @return Address of channel manager
    function channelManagerByToken(address token_address)
        addressExists(token_address)
        constant
        returns (address)
    {
        return registry[token_address];
    }

    /// @notice Get all registered tokens
    /// @return addresses of all registered tokens
    function tokenAddresses()
        constant
        returns (address[])
    {
        return tokens;
    }

    /// @notice Get the addresses of all channel managers for all registered tokens
    /// @return addresses of all channel managers
    function channelManagerAddresses()
        constant
        returns (address[])
    {
        uint i;
        address token_address;
        address[] memory result;

        result = new address[](tokens.length);

        for (i = 0; i < tokens.length; i++) {
            token_address = tokens[i];
            result[i] = registry[token_address];
        }

        return result;
    }

    function () { revert(); }
}


documentation

documentation

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

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

implement events
refactor & wrap check & transfer ?

*/

contract Registry {

/* Storage
 */

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

/* Structs
 */
    struct Publisher {
        address owner;
        uint expTime;
        uint deposit;

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

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

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

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

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

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

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

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

/* Constructor
 */
    /// @param _minDeposit      application & challenger deposit amounts for domains
    /// @param _minParamDeposit application & challenger deposit amounts for parameters
    /// @param _challengeLen    duration of the challenge period
    /// @param _registryLen     duration of a registration’s validity
    /// @param _commitVoteLen   duration of the commit period in token votes
    /// @param _revealVoteLen   duration of reveal period in token votes
    /// @param _dispensationPct percentage of forfeited deposit distributed to winning party; uint between 0 and 100
    /// @param _majority        percentage of votes that constitutes the majority; uint between 0 and 100
    function Registry(address _token,
        address _voting,
        uint _minDeposit,
        uint _minParamDeposit,
        uint _challengeLen,
        uint _registryLen,
        uint _commitVoteLen,
        uint _revealVoteLen,
        uint _dispensationPct,
        uint _majority) {

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

/* Registry Functions
 */

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

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

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

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

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

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

    // helper function to challengeApplication() and challengeProposal()
    // transfer tokens update application status
    function challenge(bytes32 _hash, uint deposit, address _challenger) private {
        // take tokens from challenger
        require(token.transferFrom(_challenger, this, deposit));

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

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

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

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

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

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

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

/* Token Distribution Functions
 */

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

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

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

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

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

        return numerator / denominator;
    }

    // gives reminder tokens from poll to a designated claimer
    // the claimer is the winner of the challenge
    function claimExtraReward(uint _pollID) public {
        uint256 totalTokens = voting.getTotalNumberOfTokensForWinningOption(_pollID);
        uint256 reward = pollInfo[_pollID].remainder / (MULTIPLIER);
        reward = reward / totalTokens;
        pollInfo[_pollID].remainder = pollInfo[_pollID].remainder - reward * MULTIPLIER;
        token.transfer(pollInfo[_pollID].claimer, reward);
    }

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

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

/* Registry Helper Functions
 */

    // STATIC

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

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

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

    // DYNAMIC

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

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

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

/* Parameter Functions
 */

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

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

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

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

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

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

/* Parameter Helper Functions
 */

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

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

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

/* Testing-Related Helper Functions
 */

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

}

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

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

implement events
refactor & wrap check & transfer ?

*/

contract Registry {

/* Storage
 */

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

/* Structs
 */
    struct Publisher {
        address owner;
        uint expTime;
        uint deposit;

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

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

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

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

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

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

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

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

/* Constructor
 */
    /// @param _minDeposit      application & challenger deposit amounts for domains
    /// @param _minParamDeposit application & challenger deposit amounts for parameters
    /// @param _challengeLen    duration of the challenge period
    /// @param _registryLen     duration of a registration’s validity
    /// @param _commitVoteLen   duration of the commit period in token votes
    /// @param _revealVoteLen   duration of reveal period in token votes
    /// @param _dispensationPct percentage of forfeited deposit distributed to winning party; uint between 0 and 100
    /// @param _majority        percentage of votes that constitutes the majority; uint between 0 and 100
    function Registry(address _token,
        address _voting,
        uint _minDeposit,
        uint _minParamDeposit,
        uint _challengeLen,
        uint _registryLen,
        uint _commitVoteLen,
        uint _revealVoteLen,
        uint _dispensationPct,
        uint _majority) {

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

/* Registry Functions
 */

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

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

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

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

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

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

    // helper function to challengeApplication() and challengeProposal()
    // transfer tokens update application status
    function challenge(bytes32 _hash, uint deposit, address _challenger) private {
        // take tokens from challenger
        require(token.transferFrom(_challenger, this, deposit));

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

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

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

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

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

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

    // helper function to moveToRegistry() and processResult()
    // add a domain to whitelist or update renewal attributes
    function add(bytes32 _domainHash, address _owner) private {
        uint expiration = paramSnapshots[_domainHash].registryLen;
        if (whitelist[_domainHash].renewal == true)
        {
            if (whitelist[_domainHash].expTime < now)
            {
                whitelist[_domainHash].nextExpTime = now + expiration;
            }
            else
            {
                whitelist[_domainHash].nextExpTime = whitelist[_domainHash].expTime + expiration;
            }
            whitelist[_domainHash].nextDeposit = paramSnapshots[_domainHash].minDeposit;
        }
        else
        {
            whitelist[_domainHash].expTime = now + expiration;
            whitelist[_domainHash].deposit = paramSnapshots[_domainHash].minDeposit;
        }
        whitelist[_domainHash].owner = _owner;
    }

/* Token Distribution Functions
 */

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

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

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

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

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

        return numerator / denominator;
    }

    // gives reminder tokens from poll to a designated claimer
    // the claimer is the winner of the challenge
    function claimExtraReward(uint _pollID) public {
        uint256 totalTokens = voting.getTotalNumberOfTokensForWinningOption(_pollID);
        uint256 reward = pollInfo[_pollID].remainder / (MULTIPLIER);
        reward = reward / totalTokens;
        pollInfo[_pollID].remainder = pollInfo[_pollID].remainder - reward * MULTIPLIER;
        token.transfer(pollInfo[_pollID].claimer, reward);
    }

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

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

/* Registry Helper Functions
 */

    // STATIC

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

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

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

    // DYNAMIC

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

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

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

/* Parameter Functions
 */

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

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

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

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

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

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

/* Parameter Helper Functions
 */

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

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

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

/* Testing-Related Helper Functions
 */

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

}