dirty

dirty

import "libraries/GroveLib.sol";

library CallLib {
        /*
         *  Address: 0x2746bcf29bffafcc7906752f639819171d18ce2b
         */
        struct Call {
                address contract_address;
                bytes4 abi_signature;
                bytes call_data;
                uint anchor_gas_price;
                uint suggested_gas;

                address bidder;
                uint bid_amount;
                uint bidder_deposit;

                bool was_successful;
                bool was_called;
                bool is_cancelled;
        }

        // The number of blocks that each caller in the pool has to complete their
        // call.
        uint constant CALL_WINDOW_SIZE = 16;

        address constant creator = 0xd3cda913deb6f67967b99d67acdfa1712c293601;

        function extract_call_data(Call storage call, bytes data) public {
            call.call_data.length = data.length - 4;
            if (data.length > 4) {
                    for (uint i = 0; i < call.call_data.length; i++) {
                            call.call_data[i] = data[i + 4];
                    }
            }
        }

        function send_safe(address to_address, uint value) public returns (uint) {
                if (value > address(this).balance) {
                        value = address(this).balance;
                }
                if (value > 0) {
                        AccountingLib.sendRobust(to_address, value);
                        return value;
                }
                return 0;
        }

        function get_gas_scalar(uint base_gas_price, uint gas_price) constant returns (uint) {
                /*
                 *  Return a number between 0 - 200 to scale the fee based on
                 *  the gas price set for the calling transaction as compared
                 *  to the gas price of the scheduling transaction.
                 *
                 *  - number approaches zero as the transaction gas price goes
                 *  above the gas price recorded when the call was scheduled.
                 *
                 *  - the number approaches 200 as the transaction gas price
                 *  drops under the price recorded when the call was scheduled.
                 *
                 *  This encourages lower gas costs as the lower the gas price
                 *  for the executing transaction, the higher the payout to the
                 *  caller.
                 */
                if (gas_price > base_gas_price) {
                        return 100 * base_gas_price / gas_price;
                }
                else {
                        return 200 - 100 * base_gas_price / (2 * base_gas_price - gas_price);
                }
        }

        event CallExecuted(address indexed executor, uint gas_cost, uint payment, uint fee, bool success);

        event _CallAborted(address executor, bytes32 reason);
        function CallAborted(address executor, bytes32 reason) public {
            _CallAborted(executor, reason);
        }

        function execute(Call storage self, uint start_gas, address executor, uint base_payment, uint base_fee, uint overhead, uint extraGas) public {
            FutureCall call = FutureCall(this);

            // If the pre-execution checks do not pass, exit early.
            if (!call.before_execute(executor)) {
                return;
            }

            // Make the call
            call.was_successful = self.contract_address.self.gas(msg.gas - overhead)(self.abi_signature, self.call_data);
            call.was_called = true;

            // Compute the scalar (0 - 200) for the fee.
            uint gas_scalar = get_gas_scalar(self.anchor_gas_price, tx.gasprice);

            uint payment = call.deposit_amount + call.bid_amount * gas_scalar / 100;
            uint fee = base_fee * gas_scalar / 100;

            // Log how much gas this call used.  EXTRA_CALL_GAS is a fixed
            // amount that represents the gas usage of the commands that
            // happen after this line.
            uint gas_cost = tx.gasprice * (start_gas - msg.gas + extraGas);

            // Now we need to pay the executor as well as keep fee.
            payment = send_safe(executor, payment + gas_cost);
            fee = send_safe(creator, fee);

            // Log execution
            CallExecuted(executor, gas_cost, payment, fee, success);
        }

        event Cancelled(address indexed cancelled_by);

        function cancel(Call storage self, address sender) public {
                Cancelled(sender);
                if (self.deposit_amount >= 0) {
                    send_safe(self.bidder, self.deposit_amount);
                }
                send_safe(self.scheduler_address, this.balance);
                self.is_cancelled = true;
        }

        /*
         *  Bid API
         *  - Gas costs for this transaction are not covered so it
         *    must be up to the call executors to ensure that their actions
         *    remain profitable.  Any form of bidding war is likely to eat into
         *    profits.
         */
        event Claimed(address executor, uint bid_amount);

        // The duration (in blocks) during which the maximum bid will slowly rise
        // towards the base_payment amount.
        uint constant BID_GROWTH_WINDOW = 240;

        // The duration (in blocks) after the BID_WINDOW that bidding will
        // remain open.
        uint constant MAXIMUM_BID_WINDOW = 15;

        // The duration (in blocks) before the call's target block during which
        // all actions are frozen.  This includes bidding, cancellation,
        // registering call data.
        uint constant BEFORE_CALL_FREEZE_WINDOW = 10;

        /*
         *  The maximum allowed bid slowly rises across a window of blocks
         *  BID_GROWTH_WINDOW prior to the call.  No bidder is allowed to bid
         *  above this value.  This is intended to prevent bidding wars in that
         *  each caller should know how much they are willing to execute a call
         *  for.
         */
        function get_bid_amount_for_block(uint block_number) constant returns (uint) {
            var _call = FutureBlockCall(this);

            uint last_block = _call.target_block() - BEFORE_CALL_FREEZE_WINDOW;

            // bid window has closed
            if (block_number > last_block) return _call.base_payment();

            uint first_block = last_block - MAXIMUM_BID_WINDOW - BID_GROWTH_WINDOW;

            // bid window has not begun
            if (block_number < first_block) return 0;

            // in the maximum bid window.
            if (block_number > last_block - MAXIMUM_BID_WINDOW) return _call.base_payment();

            uint x = block_number - first_block;

            return 100 * x / BID_GROWTH_WINDOW;
        }

        function claim(Call storage self, address executor, uint deposit_amount, uint base_payment) public returns (bool) {
                // Already claimed
                if (self.bidder != 0x0) return false;

                // Insufficient Deposit
                if (deposit_amount < 2 * base_payment) return false;

                self.bid_amount = get_maximum_bid_for_block(block.number);
                self.bidder = executor;
                self.bidder_deposit = deposit_amount;

                // Log the bid.
                Claimed(executor, self.bid_amount);
        }

        function check_execution_authorization(Call storage self, address executor, uint block_number) returns (bool) {
                /*
                 *  Check whether the given `executor` is authorized.
                 */
                var call = FutureCall(this);

                uint target_block = call.target_block();

                // Invalid, not in call window.
                if (block_number < target_block || block_number > target_block + call.grace_period()) throw;

                // Within the reserved call window so if there is a bidder, the
                // executor must be the biddor.
                if (block_number - target_block < CALL_WINDOW_SIZE) {
                    return (self.bidder == 0x0 || self.bidder == executor);
                }

                // Must be in the free-for-all period.
                return true;
        }
}

contract FutureCall {
        address public scheduler_address;

        uint public base_payment;
        uint public base_fee;

        // TODO: These *should* live on FutureBlockCall but I haven't figured
        // the modularity part out quite yet.  For now I'm going to muddle
        // these two concepts together for the sake of progress and pay this
        // debt down later.
        uint public target_block;
        uint8 public grace_period;

        CallLib.Call call;

        /*
         *  Data accessor functions.
         */
        function contract_address() constant returns (address) {
                return call.contract_address;
        }

        function abi_signature() constant returns (bytes4) {
                return call.abi_signature;
        }

        function call_data() constant returns (bytes) {
                return call.call_data;
        }

        function anchor_gas_price() constant returns (uint) {
                return call.anchor_gas_price;
        }

        function suggested_gas() constant returns (uint) {
                return call.suggested_gas;
        }

        function () {
                // Fallback to allow sending funds to this contract.
                // Also allows call data registration.
                if (msg.sender == scheduler_address && msg.data.length > 0) {
                        if (call.call_data.length != 0) {
                            throw;
                        }
                        call.call_data = msg.data;
                }
        }

        modifier notcancelled { if (call.is_cancelled) throw; _ }

        modifier onlyscheduler { if (msg.sender == scheduler_address) _ }

        // The author (Piper Merriam) address.
        address constant creator = 0xd3cda913deb6f67967b99d67acdfa1712c293601;

        function register_data() public onlyscheduler {
                if (call.call_data.length > 0) {
                        // cannot write over call data
                        throw;
                }
                CallLib.extract_call_data(call, msg.data);
        }

        function bid(uint bidAmount) public returns (bool) public notcancelled {
                bool success = CallLib.bid(call, msg.sender, bidAmount, msg.value, base_payment);
                if (!success) {
                        if (!AccountingLib.sendRobust(msg.sender, msg.value)) throw;
                }
                return success;
        }

        function check_execution_authorization(address executor, uint block_number) constant returns (bool) {
                return CallLib.check_execution_authorization(call, executor, block_number);
        }

        // API for inherited contracts
        function before_execute(address executor) public returns (bool);
        function after_execute(address executor) internal;
        function get_overhead() constant returns (uint);
        function get_extra_gas() constant returns (uint);

        function send_safe(address to_address, uint value) internal {
                CallLib.send_safe(to_address, value);
        }

        function execute() public notcancelled {
            uint start_gas = msg.gas;

            // Check that the call should be executed now.
            if (!before_execute(msg.sender)) return;

            // Execute the call
            CallLib.execute(call, start_gas, msg.sender, base_payment, base_fee, get_overhead(), get_extra_gas());

            // Any logic that needs to occur after the call has executed should
            // go in after_execute
            after_execute(msg.sender);
        }
}

contract FutureBlockCall is FutureCall {
        // TODO: This it the *appropriate* place for these to live, but for
        // unfortunate reasons, they are present on the FutureCall contract
        // class.
        //uint public target_block;
        //uint8 public grace_period;

        function FutureBlockCall(address _scheduler_address, uint _target_block, uint8 _grace_period, address _contract_address, bytes4 _abi_signature, uint _suggested_gas, uint _base_payment, uint _base_fee) {
                // TODO: split this constructor across this contract and the
                // parent contract FutureCall
                scheduler_address = _scheduler_address;

                target_block = _target_block;
                grace_period = _grace_period;

                base_payment = _base_payment;
                base_fee = _base_fee;

                call.suggested_gas = _suggested_gas;
                call.anchor_gas_price = tx.gasprice;
                call.contract_address = _contract_address;
                call.abi_signature = _abi_signature;
        }

        function before_execute(address executor) public returns (bool) {
            if (block.number < target_block || block.number > target_block + grace_period) {
                // Not being called within call window.
                CallLib.CallAborted(executor, "NOT_IN_CALL_WINDOW");
                return false;
            }

            // If they are not authorized to execute the call at this time,
            // exit early.
            if (!CallLib.check_execution_authorization(executor, block.number)) {
                CallLib.CallAborted(executor, "NOT_AUTHORIZED");
                return;
            }

            return true;
        }

        function after_execute(address executor) internal {
            // TODO: Remove suicide
            suicide(scheduler_address);
        }

        function get_overhead() constant returns (uint) {
                // TODO real numbers
                return 46000;
        }

        function get_extra_gas() constant returns (uint) {
                // TODO real numbers
                return 17000;
        }

        uint constant BEFORE_CALL_FREEZE_WINDOW = 10;

        function cancel() public notcancelled {
                if ((block.number < target_block - BEFORE_CALL_FREEZE_WINDOW && msg.sender == scheduler_address) || block.number > target_block + grace_period) {
                        CallLib.cancel(call, scheduler_address);
                }
        }
}

import "libraries/GroveLib.sol";

library CallLib {
        /*
         *  Address: 0x2746bcf29bffafcc7906752f639819171d18ce2b
         */
        struct Call {
                address contract_address;
                bytes4 abi_signature;
                bytes call_data;
                uint anchor_gas_price;
                uint suggested_gas;

                address bidder;
                uint bid_amount;
                uint bidder_deposit;
        }

        // The number of blocks that each caller in the pool has to complete their
        // call.
        uint constant CALL_WINDOW_SIZE = 16;

        address constant creator = 0xd3cda913deb6f67967b99d67acdfa1712c293601;

        function extract_call_data(Call storage call, bytes data) public {
            call.call_data.length = data.length - 4;
            if (data.length > 4) {
                    for (uint i = 0; i < call.call_data.length; i++) {
                            call.call_data[i] = data[i + 4];
                    }
            }
        }

        function send_safe(address to_address, uint value) public returns (uint) {
                if (value > address(this).balance) {
                        value = address(this).balance;
                }
                if (value > 0) {
                        AccountingLib.sendRobust(to_address, value);
                        return value;
                }
                return 0;
        }

        function get_gas_scalar(uint base_gas_price, uint gas_price) constant returns (uint) {
                /*
                 *  Return a number between 0 - 200 to scale the fee based on
                 *  the gas price set for the calling transaction as compared
                 *  to the gas price of the scheduling transaction.
                 *
                 *  - number approaches zero as the transaction gas price goes
                 *  above the gas price recorded when the call was scheduled.
                 *
                 *  - the number approaches 200 as the transaction gas price
                 *  drops under the price recorded when the call was scheduled.
                 *
                 *  This encourages lower gas costs as the lower the gas price
                 *  for the executing transaction, the higher the payout to the
                 *  caller.
                 */
                if (gas_price > base_gas_price) {
                        return 100 * base_gas_price / gas_price;
                }
                else {
                        return 200 - 100 * base_gas_price / (2 * base_gas_price - gas_price);
                }
        }

        event CallExecuted(address indexed executor, uint gas_cost, uint payment, uint fee, bool success);

        event _CallAborted(address executor, bytes32 reason);
        function CallAborted(address executor, bytes32 reason) public {
            _CallAborted(executor, reason);
        }

        function execute(Call storage call, uint start_gas, address executor, uint base_payment, uint base_fee, uint overhead, uint extraGas) public {
            FutureCall _call = FutureCall(this);

            // If the pre-execution checks do not pass, exit early.
            if (!_call.before_execute(executor)) {
                return;
            }

            // Make the call
            bool success = call.contract_address.call.gas(msg.gas - overhead)(call.abi_signature, call.call_data);

            // Compute the scalar (0 - 200) for the fee.
            uint gas_scalar = get_gas_scalar(call.anchor_gas_price, tx.gasprice);

            uint payment = base_payment * gas_scalar / 100;
            uint fee = base_fee * gas_scalar / 100;

            // Log how much gas this call used.  EXTRA_CALL_GAS is a fixed
            // amount that represents the gas usage of the commands that
            // happen after this line.
            uint gas_cost = tx.gasprice * (start_gas - msg.gas + extraGas);

            // Now we need to pay the executor as well as keep fee.
            payment = send_safe(executor, payment + gas_cost);
            fee = send_safe(creator, fee);

            // Log execution
            CallExecuted(executor, gas_cost, payment, fee, success);
        }

        event Cancelled(address indexed cancelled_by);

        function cancel(address sender) public {
                Cancelled(sender);
                // TODO: remove suicide.
                suicide(sender);
        }

        /*
         *  Bid API
         *  - Gas costs for this transaction are not covered so it
         *    must be up to the call executors to ensure that their actions
         *    remain profitable.  Any form of bidding war is likely to eat into
         *    profits.
         */
        event Claimed(address executor, uint bid_amount);

        // The duration (in blocks) during which the maximum bid will slowly rise
        // towards the base_payment amount.
        uint constant BID_GROWTH_WINDOW = 240;

        // The duration (in blocks) after the BID_WINDOW that bidding will
        // remain open.
        uint constant MAXIMUM_BID_WINDOW = 15;

        // The duration (in blocks) before the call's target block during which
        // all actions are frozen.  This includes bidding, cancellation,
        // registering call data.
        uint constant BEFORE_CALL_FREEZE_WINDOW = 10;

        /*
         *  The maximum allowed bid slowly rises across a window of blocks
         *  BID_GROWTH_WINDOW prior to the call.  No bidder is allowed to bid
         *  above this value.  This is intended to prevent bidding wars in that
         *  each caller should know how much they are willing to execute a call
         *  for.
         */
        function get_bid_amount_for_block(uint block_number) constant returns (uint) {
            var _call = FutureBlockCall(this);

            uint last_block = _call.target_block() - BEFORE_CALL_FREEZE_WINDOW;

            // bid window has closed
            if (block_number > last_block) return _call.base_payment();

            uint first_block = last_block - MAXIMUM_BID_WINDOW - BID_GROWTH_WINDOW;

            // bid window has not begun
            if (block_number < first_block) return 0;

            // in the maximum bid window.
            if (block_number > last_block - MAXIMUM_BID_WINDOW) return _call.base_payment();

            uint x = block_number - first_block;

            return 100 * x / BID_GROWTH_WINDOW;
        }

        function claim(Call storage self, address executor, uint deposit_amount, uint base_payment) public returns (bool) {
                // Already claimed
                if (self.bidder != 0x0) return false;

                // Insufficient Deposit
                if (deposit_amount < 2 * base_payment) return false;

                self.bid_amount = get_maximum_bid_for_block(block.number);
                self.bidder = executor;
                self.bidder_deposit = deposit_amount;

                // Log the bid.
                Claimed(executor, self.bid_amount);
        }

        function check_execution_authorization(Call storage self, address executor, uint block_number) returns (bool) {
                /*
                 *  Check whether the given `executor` is authorized.
                 */
                var call = FutureCall(this);

                uint target_block = call.target_block();

                // Invalid, not in call window.
                if (block_number < target_block || block_number > target_block + call.grace_period()) throw;

                // Within the reserved call window so if there is a bidder, the
                // executor must be the biddor.
                if (block_number - target_block < CALL_WINDOW_SIZE) {
                    return (self.bidder == 0x0 || self.bidder == executor);
                }

                // Must be in the free-for-all period.
                return true;
        }
}

contract FutureCall {
        address public scheduler_address;

        uint public base_payment;
        uint public base_fee;

        // TODO: These *should* live on FutureBlockCall but I haven't figured
        // the modularity part out quite yet.  For now I'm going to muddle
        // these two concepts together for the sake of progress and pay this
        // debt down later.
        uint public target_block;
        uint8 public grace_period;

        CallLib.Call call;

        /*
         *  Data accessor functions.
         */
        function contract_address() constant returns (address) {
                return call.contract_address;
        }

        function abi_signature() constant returns (bytes4) {
                return call.abi_signature;
        }

        function call_data() constant returns (bytes) {
                return call.call_data;
        }

        function anchor_gas_price() constant returns (uint) {
                return call.anchor_gas_price;
        }

        function suggested_gas() constant returns (uint) {
                return call.suggested_gas;
        }

        function () {
                // Fallback to allow sending funds to this contract.
                // Also allows call data registration.
                if (msg.sender == scheduler_address && msg.data.length > 0) {
                        if (call.call_data.length != 0) {
                            throw;
                        }
                        call.call_data = msg.data;
                }
        }

        modifier onlyscheduler { if (msg.sender == scheduler_address) _ }

        // The author (Piper Merriam) address.
        address constant creator = 0xd3cda913deb6f67967b99d67acdfa1712c293601;

        function register_data() public onlyscheduler {
                if (call.call_data.length > 0) {
                        // cannot write over call data
                        throw;
                }
                CallLib.extract_call_data(call, msg.data);
        }

        function bid(uint bidAmount) public returns (bool) {
                bool success = CallLib.bid(call, msg.sender, bidAmount, msg.value, base_payment);
                if (!success) {
                        if (!AccountingLib.sendRobust(msg.sender, msg.value)) throw;
                }
                return success;
        }

        function check_execution_authorization(address executor, uint block_number) constant returns (bool) {
                return CallLib.check_execution_authorization(call, executor, block_number);
        }

        // API for inherited contracts
        function before_execute(address executor) public returns (bool);
        function after_execute(address executor) internal;
        function get_overhead() constant returns (uint);
        function get_extra_gas() constant returns (uint);

        function send_safe(address to_address, uint value) internal {
                CallLib.send_safe(to_address, value);
        }

        function execute() public {
            uint start_gas = msg.gas;

            // Check that the call should be executed now.
            if (!before_execute(msg.sender)) return;

            // Execute the call
            CallLib.execute(call, start_gas, msg.sender, base_payment, base_fee, get_overhead(), get_extra_gas());

            // Any logic that needs to occur after the call has executed should
            // go in after_execute
            after_execute(msg.sender);
        }
}

contract FutureBlockCall is FutureCall {
        // TODO: This it the *appropriate* place for these to live, but for
        // unfortunate reasons, they are present on the FutureCall contract
        // class.
        //uint public target_block;
        //uint8 public grace_period;

        function FutureBlockCall(address _scheduler_address, uint _target_block, uint8 _grace_period, address _contract_address, bytes4 _abi_signature, uint _suggested_gas, uint _base_payment, uint _base_fee) {
                // TODO: split this constructor across this contract and the
                // parent contract FutureCall
                scheduler_address = _scheduler_address;

                target_block = _target_block;
                grace_period = _grace_period;

                base_payment = _base_payment;
                base_fee = _base_fee;

                call.suggested_gas = _suggested_gas;
                call.anchor_gas_price = tx.gasprice;
                call.contract_address = _contract_address;
                call.abi_signature = _abi_signature;
        }

        function before_execute(address executor) public returns (bool) {
            if (block.number < target_block || block.number > target_block + grace_period) {
                // Not being called within call window.
                CallLib.CallAborted(executor, "NOT_IN_CALL_WINDOW");
                return false;
            }

            // If they are not authorized to execute the call at this time,
            // exit early.
            if (!CallLib.check_execution_authorization(executor, block.number)) {
                CallLib.CallAborted(executor, "NOT_AUTHORIZED");
                return;
            }

            return true;
        }

        function after_execute(address executor) internal {
            // TODO: Remove suicide
            suicide(scheduler_address);
        }

        function get_overhead() constant returns (uint) {
                // TODO real numbers
                return 46000;
        }

        function get_extra_gas() constant returns (uint) {
                // TODO real numbers
                return 17000;
        }

        uint constant BEFORE_CALL_FREEZE_WINDOW = 10;

        function cancel() public {
                if ((block.number < target_block - BEFORE_CALL_FREEZE_WINDOW && msg.sender == scheduler_address) || block.number > target_block + grace_period) {
                        CallLib.cancel(scheduler_address);
                }
        }
}


Fix missing storage keyword warnings

Fix missing storage keyword warnings

pragma solidity ^0.4.11;

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

/**
 * @title Vested token
 * @dev Tokens that can be vested for a group of addresses.
 */
contract VestedToken is StandardToken, LimitedTransferToken {

  uint256 MAX_GRANTS_PER_ADDRESS = 20;

  struct TokenGrant {
    address granter;     // 20 bytes
    uint256 value;       // 32 bytes
    uint64 cliff;
    uint64 vesting;
    uint64 start;        // 3 * 8 = 24 bytes
    bool revokable;
    bool burnsOnRevoke;  // 2 * 1 = 2 bits? or 2 bytes?
  } // total 78 bytes = 3 sstore per operation (32 per sstore)

  mapping (address => TokenGrant[]) public grants;

  event NewTokenGrant(address indexed from, address indexed to, uint256 value, uint256 grantId);

  /**
   * @dev Grant tokens to a specified address
   * @param _to address The address which the tokens will be granted to.
   * @param _value uint256 The amount of tokens to be granted.
   * @param _start uint64 Time of the beginning of the grant.
   * @param _cliff uint64 Time of the cliff period.
   * @param _vesting uint64 The vesting period.
   */
  function grantVestedTokens(
    address _to,
    uint256 _value,
    uint64 _start,
    uint64 _cliff,
    uint64 _vesting,
    bool _revokable,
    bool _burnsOnRevoke
  ) public {

    // Check for date inconsistencies that may cause unexpected behavior
    require(_cliff >= _start && _vesting >= _cliff);

    require(tokenGrantsCount(_to) < MAX_GRANTS_PER_ADDRESS);   // To prevent a user being spammed and have his balance locked (out of gas attack when calculating vesting).

    uint256 count = grants[_to].push(
                TokenGrant(
                  _revokable ? msg.sender : 0, // avoid storing an extra 20 bytes when it is non-revokable
                  _value,
                  _cliff,
                  _vesting,
                  _start,
                  _revokable,
                  _burnsOnRevoke
                )
              );

    transfer(_to, _value);

    NewTokenGrant(msg.sender, _to, _value, count - 1);
  }

  /**
   * @dev Revoke the grant of tokens of a specifed address.
   * @param _holder The address which will have its tokens revoked.
   * @param _grantId The id of the token grant.
   */
  function revokeTokenGrant(address _holder, uint256 _grantId) public {
    TokenGrant storage grant = grants[_holder][_grantId];

    require(grant.revokable);
    require(grant.granter == msg.sender); // Only granter can revoke it

    address receiver = grant.burnsOnRevoke ? 0xdead : msg.sender;

    uint256 nonVested = nonVestedTokens(grant, uint64(now));

    // remove grant from array
    delete grants[_holder][_grantId];
    grants[_holder][_grantId] = grants[_holder][grants[_holder].length.sub(1)];
    grants[_holder].length -= 1;

    balances[receiver] = balances[receiver].add(nonVested);
    balances[_holder] = balances[_holder].sub(nonVested);

    Transfer(_holder, receiver, nonVested);
  }

  /**
   * @dev Calculate the total amount of transferable tokens of a holder at a given time
   * @param holder address The address of the holder
   * @param time uint64 The specific time.
   * @return An uint256 representing a holder's total amount of transferable tokens.
   */
  function transferableTokens(address holder, uint64 time) constant public returns (uint256) {
    uint256 grantIndex = tokenGrantsCount(holder);

    if (grantIndex == 0) return super.transferableTokens(holder, time); // shortcut for holder without grants

    // Iterate through all the grants the holder has, and add all non-vested tokens
    uint256 nonVested = 0;
    for (uint256 i = 0; i < grantIndex; i++) {
      nonVested = SafeMath.add(nonVested, nonVestedTokens(grants[holder][i], time));
    }

    // Balance - totalNonVested is the amount of tokens a holder can transfer at any given time
    uint256 vestedTransferable = SafeMath.sub(balanceOf(holder), nonVested);

    // Return the minimum of how many vested can transfer and other value
    // in case there are other limiting transferability factors (default is balanceOf)
    return Math.min256(vestedTransferable, super.transferableTokens(holder, time));
  }

  /**
   * @dev Check the amount of grants that an address has.
   * @param _holder The holder of the grants.
   * @return A uint256 representing the total amount of grants.
   */
  function tokenGrantsCount(address _holder) constant returns (uint256 index) {
    return grants[_holder].length;
  }

  /**
   * @dev Calculate amount of vested tokens at a specifc time.
   * @param tokens uint256 The amount of tokens grantted.
   * @param time uint64 The time to be checked
   * @param start uint64 A time representing the begining of the grant
   * @param cliff uint64 The cliff period.
   * @param vesting uint64 The vesting period.
   * @return An uint256 representing the amount of vested tokensof a specif grant.
   *  transferableTokens
   *   |                         _/--------   vestedTokens rect
   *   |                       _/
   *   |                     _/
   *   |                   _/
   *   |                 _/
   *   |                /
   *   |              .|
   *   |            .  |
   *   |          .    |
   *   |        .      |
   *   |      .        |
   *   |    .          |
   *   +===+===========+---------+----------> time
   *      Start       Clift    Vesting
   */
  function calculateVestedTokens(
    uint256 tokens,
    uint256 time,
    uint256 start,
    uint256 cliff,
    uint256 vesting) constant returns (uint256)
    {
      // Shortcuts for before cliff and after vesting cases.
      if (time < cliff) return 0;
      if (time >= vesting) return tokens;

      // Interpolate all vested tokens.
      // As before cliff the shortcut returns 0, we can use just calculate a value
      // in the vesting rect (as shown in above's figure)

      // vestedTokens = tokens * (time - start) / (vesting - start)
      uint256 vestedTokens = SafeMath.div(
                                    SafeMath.mul(
                                      tokens,
                                      SafeMath.sub(time, start)
                                      ),
                                    SafeMath.sub(vesting, start)
                                    );

      return vestedTokens;
  }

  /**
   * @dev Get all information about a specifc grant.
   * @param _holder The address which will have its tokens revoked.
   * @param _grantId The id of the token grant.
   * @return Returns all the values that represent a TokenGrant(address, value, start, cliff,
   * revokability, burnsOnRevoke, and vesting) plus the vested value at the current time.
   */
  function tokenGrant(address _holder, uint256 _grantId) constant returns (address granter, uint256 value, uint256 vested, uint64 start, uint64 cliff, uint64 vesting, bool revokable, bool burnsOnRevoke) {
    TokenGrant storage grant = grants[_holder][_grantId];

    granter = grant.granter;
    value = grant.value;
    start = grant.start;
    cliff = grant.cliff;
    vesting = grant.vesting;
    revokable = grant.revokable;
    burnsOnRevoke = grant.burnsOnRevoke;

    vested = vestedTokens(grant, uint64(now));
  }

  /**
   * @dev Get the amount of vested tokens at a specific time.
   * @param grant TokenGrant The grant to be checked.
   * @param time The time to be checked
   * @return An uint256 representing the amount of vested tokens of a specific grant at a specific time.
   */
  function vestedTokens(TokenGrant grant, uint64 time) private constant returns (uint256) {
    return calculateVestedTokens(
      grant.value,
      uint256(time),
      uint256(grant.start),
      uint256(grant.cliff),
      uint256(grant.vesting)
    );
  }

  /**
   * @dev Calculate the amount of non vested tokens at a specific time.
   * @param grant TokenGrant The grant to be checked.
   * @param time uint64 The time to be checked
   * @return An uint256 representing the amount of non vested tokens of a specifc grant on the
   * passed time frame.
   */
  function nonVestedTokens(TokenGrant grant, uint64 time) private constant returns (uint256) {
    return grant.value.sub(vestedTokens(grant, time));
  }

  /**
   * @dev Calculate the date when the holder can trasfer all its tokens
   * @param holder address The address of the holder
   * @return An uint256 representing the date of the last transferable tokens.
   */
  function lastTokenIsTransferableDate(address holder) constant public returns (uint64 date) {
    date = uint64(now);
    uint256 grantIndex = grants[holder].length;
    for (uint256 i = 0; i < grantIndex; i++) {
      date = Math.max64(grants[holder][i].vesting, date);
    }
  }
}

pragma solidity ^0.4.11;

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

/**
 * @title Vested token
 * @dev Tokens that can be vested for a group of addresses.
 */
contract VestedToken is StandardToken, LimitedTransferToken {

  uint256 MAX_GRANTS_PER_ADDRESS = 20;

  struct TokenGrant {
    address granter;     // 20 bytes
    uint256 value;       // 32 bytes
    uint64 cliff;
    uint64 vesting;
    uint64 start;        // 3 * 8 = 24 bytes
    bool revokable;
    bool burnsOnRevoke;  // 2 * 1 = 2 bits? or 2 bytes?
  } // total 78 bytes = 3 sstore per operation (32 per sstore)

  mapping (address => TokenGrant[]) public grants;

  event NewTokenGrant(address indexed from, address indexed to, uint256 value, uint256 grantId);

  /**
   * @dev Grant tokens to a specified address
   * @param _to address The address which the tokens will be granted to.
   * @param _value uint256 The amount of tokens to be granted.
   * @param _start uint64 Time of the beginning of the grant.
   * @param _cliff uint64 Time of the cliff period.
   * @param _vesting uint64 The vesting period.
   */
  function grantVestedTokens(
    address _to,
    uint256 _value,
    uint64 _start,
    uint64 _cliff,
    uint64 _vesting,
    bool _revokable,
    bool _burnsOnRevoke
  ) public {

    // Check for date inconsistencies that may cause unexpected behavior
    require(_cliff >= _start && _vesting >= _cliff);

    require(tokenGrantsCount(_to) < MAX_GRANTS_PER_ADDRESS);   // To prevent a user being spammed and have his balance locked (out of gas attack when calculating vesting).

    uint256 count = grants[_to].push(
                TokenGrant(
                  _revokable ? msg.sender : 0, // avoid storing an extra 20 bytes when it is non-revokable
                  _value,
                  _cliff,
                  _vesting,
                  _start,
                  _revokable,
                  _burnsOnRevoke
                )
              );

    transfer(_to, _value);

    NewTokenGrant(msg.sender, _to, _value, count - 1);
  }

  /**
   * @dev Revoke the grant of tokens of a specifed address.
   * @param _holder The address which will have its tokens revoked.
   * @param _grantId The id of the token grant.
   */
  function revokeTokenGrant(address _holder, uint256 _grantId) public {
    TokenGrant grant = grants[_holder][_grantId];

    require(grant.revokable);
    require(grant.granter == msg.sender); // Only granter can revoke it

    address receiver = grant.burnsOnRevoke ? 0xdead : msg.sender;

    uint256 nonVested = nonVestedTokens(grant, uint64(now));

    // remove grant from array
    delete grants[_holder][_grantId];
    grants[_holder][_grantId] = grants[_holder][grants[_holder].length.sub(1)];
    grants[_holder].length -= 1;

    balances[receiver] = balances[receiver].add(nonVested);
    balances[_holder] = balances[_holder].sub(nonVested);

    Transfer(_holder, receiver, nonVested);
  }

  /**
   * @dev Calculate the total amount of transferable tokens of a holder at a given time
   * @param holder address The address of the holder
   * @param time uint64 The specific time.
   * @return An uint256 representing a holder's total amount of transferable tokens.
   */
  function transferableTokens(address holder, uint64 time) constant public returns (uint256) {
    uint256 grantIndex = tokenGrantsCount(holder);

    if (grantIndex == 0) return super.transferableTokens(holder, time); // shortcut for holder without grants

    // Iterate through all the grants the holder has, and add all non-vested tokens
    uint256 nonVested = 0;
    for (uint256 i = 0; i < grantIndex; i++) {
      nonVested = SafeMath.add(nonVested, nonVestedTokens(grants[holder][i], time));
    }

    // Balance - totalNonVested is the amount of tokens a holder can transfer at any given time
    uint256 vestedTransferable = SafeMath.sub(balanceOf(holder), nonVested);

    // Return the minimum of how many vested can transfer and other value
    // in case there are other limiting transferability factors (default is balanceOf)
    return Math.min256(vestedTransferable, super.transferableTokens(holder, time));
  }

  /**
   * @dev Check the amount of grants that an address has.
   * @param _holder The holder of the grants.
   * @return A uint256 representing the total amount of grants.
   */
  function tokenGrantsCount(address _holder) constant returns (uint256 index) {
    return grants[_holder].length;
  }

  /**
   * @dev Calculate amount of vested tokens at a specifc time.
   * @param tokens uint256 The amount of tokens grantted.
   * @param time uint64 The time to be checked
   * @param start uint64 A time representing the begining of the grant
   * @param cliff uint64 The cliff period.
   * @param vesting uint64 The vesting period.
   * @return An uint256 representing the amount of vested tokensof a specif grant.
   *  transferableTokens
   *   |                         _/--------   vestedTokens rect
   *   |                       _/
   *   |                     _/
   *   |                   _/
   *   |                 _/
   *   |                /
   *   |              .|
   *   |            .  |
   *   |          .    |
   *   |        .      |
   *   |      .        |
   *   |    .          |
   *   +===+===========+---------+----------> time
   *      Start       Clift    Vesting
   */
  function calculateVestedTokens(
    uint256 tokens,
    uint256 time,
    uint256 start,
    uint256 cliff,
    uint256 vesting) constant returns (uint256)
    {
      // Shortcuts for before cliff and after vesting cases.
      if (time < cliff) return 0;
      if (time >= vesting) return tokens;

      // Interpolate all vested tokens.
      // As before cliff the shortcut returns 0, we can use just calculate a value
      // in the vesting rect (as shown in above's figure)

      // vestedTokens = tokens * (time - start) / (vesting - start)
      uint256 vestedTokens = SafeMath.div(
                                    SafeMath.mul(
                                      tokens,
                                      SafeMath.sub(time, start)
                                      ),
                                    SafeMath.sub(vesting, start)
                                    );

      return vestedTokens;
  }

  /**
   * @dev Get all information about a specifc grant.
   * @param _holder The address which will have its tokens revoked.
   * @param _grantId The id of the token grant.
   * @return Returns all the values that represent a TokenGrant(address, value, start, cliff,
   * revokability, burnsOnRevoke, and vesting) plus the vested value at the current time.
   */
  function tokenGrant(address _holder, uint256 _grantId) constant returns (address granter, uint256 value, uint256 vested, uint64 start, uint64 cliff, uint64 vesting, bool revokable, bool burnsOnRevoke) {
    TokenGrant grant = grants[_holder][_grantId];

    granter = grant.granter;
    value = grant.value;
    start = grant.start;
    cliff = grant.cliff;
    vesting = grant.vesting;
    revokable = grant.revokable;
    burnsOnRevoke = grant.burnsOnRevoke;

    vested = vestedTokens(grant, uint64(now));
  }

  /**
   * @dev Get the amount of vested tokens at a specific time.
   * @param grant TokenGrant The grant to be checked.
   * @param time The time to be checked
   * @return An uint256 representing the amount of vested tokens of a specific grant at a specific time.
   */
  function vestedTokens(TokenGrant grant, uint64 time) private constant returns (uint256) {
    return calculateVestedTokens(
      grant.value,
      uint256(time),
      uint256(grant.start),
      uint256(grant.cliff),
      uint256(grant.vesting)
    );
  }

  /**
   * @dev Calculate the amount of non vested tokens at a specific time.
   * @param grant TokenGrant The grant to be checked.
   * @param time uint64 The time to be checked
   * @return An uint256 representing the amount of non vested tokens of a specifc grant on the
   * passed time frame.
   */
  function nonVestedTokens(TokenGrant grant, uint64 time) private constant returns (uint256) {
    return grant.value.sub(vestedTokens(grant, time));
  }

  /**
   * @dev Calculate the date when the holder can trasfer all its tokens
   * @param holder address The address of the holder
   * @return An uint256 representing the date of the last transferable tokens.
   */
  function lastTokenIsTransferableDate(address holder) constant public returns (uint64 date) {
    date = uint64(now);
    uint256 grantIndex = grants[holder].length;
    for (uint256 i = 0; i < grantIndex; i++) {
      date = Math.max64(grants[holder][i].vesting, date);
    }
  }
}


renew and apply now one function

renew and apply now one function

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

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

implement events
refactor & wrap check & transfer ?

*/

contract Registry {

/* Storage
 */

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

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

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

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

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

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

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

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

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

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

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

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

/* Registry Functions
 */

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

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

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

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

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

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

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

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

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

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

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

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

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

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

/* Token Distribution Functions
 */

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

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

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

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

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

        return numerator / denominator;
    }

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

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

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

/* Registry Helper Functions
 */

    // STATIC

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

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

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

    // DYNAMIC

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

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

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

/* Parameter Functions
 */

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

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

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

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

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

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

/* Parameter Helper Functions
 */

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

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

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

/* Testing-Related Helper Functions
 */

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

}

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

}