support bidder whitelisting

support bidder whitelisting

pragma solidity 0.4.11;

/// @title Abstract Mint contract - Functions to be implemented by Mint contracts.
/// FIXME: is it necessary to provide the full interface?

contract Mint {
    function registerMintingRight(address eligible, uint num, uint startTime, uint endTime) returns (bool);
    function mintable(address account) returns (uint);
    function maxMintable() returns (uint);
    function isReady() returns (bool);
    function addCollateral() returns (bool);
}

/// @title Dutch auction contract - distribution of Raiden token Minting rights using an auction
/// @author Heiko, also credits to team Gnosis!
/// This is a variation of the Gnosis model. The price and number of mintable tokens are fixed.
/// Bidders bid for mining rights and compete on the dimension of the their max acceptable minting period.
/// The result of the auctinon are minting rights.
contract DutchAuction {

    /*
     *  Events
     */
    event BidSubmission(address indexed sender, uint256 amount);

    /*
     *  Storage
     */
    Token public token;
    Mint public mint;
    address public owner;
    uint public maxTokensAvailable;
    uint public waitingPeriod;
    uint public collateralCeiling; // max total accepted ETH collateral
    uint public collateralFactor; // tokens mintable per collateral (wei), i.e. 1/price
    uint public minCollateralPerBidder; // minimum collateral a bidder must offer
    uint public maxCollateralFractionPerBidder; // limits the number of tokens a bidder can have
    uint public totalCollateralReceived;
    uint public mintingPeriodFactor;
    uint public mintingPeriodDevisorConstant;
    uint public finalMintingPeriod; // result of the auction is a
    uint public startBlock; // block the auction starts
    uint public endTime; // time the auction ends at latest

    mapping (address => uint) public bids;
    mapping (address => bool) public bidders;

    /*
     *  Enums
     */
    enum Stages {
        AuctionDeployed,
        AuctionSetUp,
        AuctionStarted,
        AuctionEnded,
        TradingStarted
    }
    Stages public stage;

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

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

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

    modifier timedTransitions() {
        if (stage == Stages.AuctionStarted && (now > endTime || totalCollateralReceived == collateralCeiling))
            finalizeAuction();
        if (stage == Stages.AuctionEnded && now > endTime + waitingPeriod)
            stage = Stages.TradingStarted;
        _;
    }

    /*
     *  Public functions
     */
    /// @dev Contract constructor function sets owner.
    /// @param _collateralCeiling Auction collateralCeiling.
    /// @param _collateralFactor Auction price factor.
    function DutchAuction(uint _collateralCeiling,
                          uint _collateralFactor,
                          uint _maxTokensAvailable
                          uint _minCollateralPerBidder,
                          uint _maxCollateralFractionPercentPerBidder,
                          uint _mintingPeriodFactor,
                          uint _mintingPeriodDevisorConstant,
                          uint _waitingPeriod)
        public
    {
        owner = msg.sender;
        assert(_collateralCeiling && _collateralFactor);
        collateralCeiling = _collateralCeiling;
        collateralFactor = _collateralFactor;
        assert(_maxTokensAvailable);
        maxTokensAvailable = _maxTokensAvailable;
        assert(_minCollateralPerBidder)
        minCollateralPerBidder = _minCollateralPerBidder;
        assert(0 < _maxCollateralFractionPerBidder <=100);
        maxCollateralFractionPerBidder = _maxCollateralFractionPercentPerBidder;
        assert(_mintingPeriodFactor && _mintingPeriodDevisorConstant);
        mintingPeriodFactor = _mintingPeriodFactor;
        mintingPeriodDevisorConstant = _mintingPeriodDevisorConstant;
        waitingPeriod = _waitingPeriod;
        stage = Stages.AuctionDeployed;
    }

    /// @dev call to whitelist bidders
    function registerEligibleBidders(address[] _bidders)
        public
        isOwner
        atStage(Stages.AuctionDeployed)
    {
        for (uint i=0; i<_bidders.length; i++) {
            assert(_bidders[i] != 0);
            bidders[_bidders[i]] = true;
        }
    }

    /// @dev Setup function sets external contracts' addresses.
    /// @param _token the token address.
    function setup(address _mint)
        public
        isOwner
        atStage(Stages.AuctionDeployed)
    {
        // register mint
        assert(_mint);
        mint = Mint(_mint);
        assert(mint.isReady());
        assert(mint.maxMintable() - mint.totalMintingRightsGranted() >= maxTokensAvailable);
        stage = Stages.AuctionSetUp;
    }

    /// @dev Changes auction collateralCeiling and start price factor before auction is started.
    /// @param _collateralCeiling Updated auction collateralCeiling.
    /// @param _collateralFactor Updated start price factor.
    function changeSettings(uint _collateralCeiling, uint _collateralFactor)
        public
        idOwner
        atStage(Stages.AuctionSetUp)
    {
        collateralCeiling = _collateralCeiling;
        collateralFactor = _collateralFactor;
    }

    /// @dev Starts auction and sets startBlock.
    function startAuction()
        public
        isOwner
        atStage(Stages.AuctionSetUp)
    {
        stage = Stages.AuctionStarted;
        startBlock = block.number;
    }

    /// @dev Returns correct stage, even if a function with timedTransitions modifier has not yet been called yet.
    /// @return Returns current auction stage.
    function updateStage()
        public
        timedTransitions
        returns (Stages)
    {
        return stage;
    }

    /// @dev Allows to send a bid to the auction.
    /// @param bidder Bid will be assigned to this address if set.
    function bid(address bidder)
        public
        payable
        isValidPayload
        timedTransitions
        atStage(Stages.AuctionStarted)
        returns (uint amount)
    {
        // If a bid is done on behalf of a user via ShapeShift, the bidder address is set.
        if (bidder == 0)
            bidder = msg.sender;
        // check if whitelisted
        assert(bidders[bidder]);

        // enforce percentage per bidder limit
        uint maxWeiAccepted = collateralCeiling * maxCollateralFractionPercentPerBidder / 100;
        maxWeiAccepted -= bids[bidder]; // take in to account previously sent wei

        // enforce total collateral limit
        maxWeiAccepted = min(maxWeiAccepted, collateralCeiling - totalCollateralReceived);

        uint numWei = msg.value;

        // refund non acceptable wei
        if (numWei > maxWeiAccepted) {
            numWei = maxWeiAccepted;
            // Send change back to bidder address. In case of a ShapeShift bid the user receives the change back directly.
            assert(msg.value >= numWei);
            uint refund = msg.value - numWei
            assert(bidder.send(refund));
        }

        // register bid
        assert(numWei>0);
        bids[bidder] += numWei;
        BidSubmission(bidder, numWei);

        // enforce minimum required collateral per bidder, while allowing to add amounts later
        assert(bids[bidder] > minCollateralPerBidder);
        totalCollateralReceived += numWei;
        assert(totalCollateralReceived <= collateralCeiling);
        assert(totalCollateralReceived * collateralFactor <= maxTokensAvailable);

        // finalize if full
        if (totalCollateralReceived == collateralCeiling)
            // When maxWei is equal to the big numWei the auction is ended and finalizeAuction is triggered.
            finalizeAuction();
    }

    // mintingPeriodFactor: 10_000_000, mintingPeriodDevisorConstant: 1_000
    // starts with 27yrs, 4.5yrs @24hs, 2.4yrs @48hrs, 1.5yrs @72hrs
    function calcMintingPeriod(uint elapsedBlocks)
        constant
        public
        returns (uint)
        {
            return mintingPeriodFactor / (elapsedBlocks + mintingPeriodDevisorConstant);
        }

    function currentMintingPeriod()
        constant
        public
        atStage(Stage.AuctionStarted)
        returns (uint)
        {
            return calcMintingPeriod(block.number - startBlock);
        }

    function finalizeAuction()
        private
    {
        stage = Stages.AuctionEnded;
        endTime = now;

        // register mintingPeriod for all successful bidders
        uint elapsed = block.number - startBlock;
        finalMintingPeriod = calcMintingPeriod(elapsed);

        // Transfer funding to collateralize the token
        assert(mint.addCollateral.value(this.value)()); // FIXME double check
    }

    /// @dev registers minting rights for bidder after auction with the Mint
    /// @param receiver MintingRighhts will be assigned to this address if set
    function registerMintingRights(address receiver)
        public
        isValidPayload
        timedTransitions
        atStage(Stages.TradingStarted)
    {
        if (receiver == 0)
            receiver = msg.sender;
        uint tokenCount = bids[receiver] * collateralFactor;
        assert(tokenCount>0);
        bids[receiver] = 0;
        assert(mint.registerMintingRight(receiver, tokenCount, endTime, endTime + finalMintingPeriod));
    }

}

pragma solidity 0.4.11;

/// @title Abstract Mint contract - Functions to be implemented by Mint contracts.
/// FIXME: is it necessary to provide the full interface?

contract Mint {
    function registerMintingRight(address eligible, uint num, uint startTime, uint endTime) returns (bool);
    function mintable(address account) returns (uint);
    function maxMintable() returns (uint);
    function isReady() returns (bool);
    function addCollateral() returns (bool);
}

/// @title Dutch auction contract - distribution of Raiden token Minting rights using an auction
/// @author Heiko, also credits to team Gnosis!
/// This is a variation of the Gnosis model. The price and number of mintable tokens are fixed.
/// Bidders bid for mining rights and compete on the dimension of the their max acceptable minting period.
/// The result of the auctinon are minting rights.
contract DutchAuction {

    /*
     *  Events
     */
    event BidSubmission(address indexed sender, uint256 amount);

    /*
     *  Storage
     */
    Token public token;
    Mint public mint;
    address public owner;
    uint public maxTokensAvailable;
    uint public waitingPeriod;
    uint public collateralCeiling; // max total accepted ETH collateral
    uint public collateralFactor; // tokens mintable per collateral (wei), i.e. 1/price
    uint public minCollateralPerBidder; // minimum collateral a bidder must offer
    uint public maxCollateralFractionPerBidder; // limits the number of tokens a bidder can have
    uint public totalCollateralReceived;
    uint public mintingPeriodFactor;
    uint public mintingPeriodDevisorConstant;
    uint public finalMintingPeriod; // result of the auction is a
    uint public startBlock; // block the auction starts
    uint public endTime; // time the auction ends at latest

    mapping (address => uint) public bids;

    /*
     *  Enums
     */
    enum Stages {
        AuctionDeployed,
        AuctionSetUp,
        AuctionStarted,
        AuctionEnded,
        TradingStarted
    }
    Stages public stage;

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

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

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

    modifier timedTransitions() {
        if (stage == Stages.AuctionStarted && (now > endTime || totalCollateralReceived == collateralCeiling))
            finalizeAuction();
        if (stage == Stages.AuctionEnded && now > endTime + waitingPeriod)
            stage = Stages.TradingStarted;
        _;
    }

    /*
     *  Public functions
     */
    /// @dev Contract constructor function sets owner.
    /// @param _collateralCeiling Auction collateralCeiling.
    /// @param _collateralFactor Auction price factor.
    function DutchAuction(uint _collateralCeiling,
                          uint _collateralFactor,
                          uint _maxTokensAvailable
                          uint _minCollateralPerBidder,
                          uint _maxCollateralFractionPercentPerBidder,
                          uint _mintingPeriodFactor,
                          uint _mintingPeriodDevisorConstant,
                          uint _waitingPeriod)
        public
    {
        owner = msg.sender;
        assert(_collateralCeiling && _collateralFactor);
        collateralCeiling = _collateralCeiling;
        collateralFactor = _collateralFactor;
        assert(_maxTokensAvailable);
        maxTokensAvailable = _maxTokensAvailable;
        assert(_minCollateralPerBidder)
        minCollateralPerBidder = _minCollateralPerBidder;
        assert(0 < _maxCollateralFractionPerBidder <=100);
        maxCollateralFractionPerBidder = _maxCollateralFractionPercentPerBidder;
        assert(_mintingPeriodFactor && _mintingPeriodDevisorConstant);
        mintingPeriodFactor = _mintingPeriodFactor;
        mintingPeriodDevisorConstant = _mintingPeriodDevisorConstant;
        waitingPeriod = _waitingPeriod;
        stage = Stages.AuctionDeployed;
    }

    /// @dev Setup function sets external contracts' addresses.
    /// @param _token the token address.
    function setup(address _mint)
        public
        isOwner
        atStage(Stages.AuctionDeployed)
    {
        // register mint
        assert(_mint);
        mint = Mint(_mint);
        assert(mint.isReady());
        assert(mint.maxMintable() - mint.totalMintingRightsGranted() >= maxTokensAvailable);
        stage = Stages.AuctionSetUp;
    }

    /// @dev Changes auction collateralCeiling and start price factor before auction is started.
    /// @param _collateralCeiling Updated auction collateralCeiling.
    /// @param _collateralFactor Updated start price factor.
    function changeSettings(uint _collateralCeiling, uint _collateralFactor)
        public
        idOwner
        atStage(Stages.AuctionSetUp)
    {
        collateralCeiling = _collateralCeiling;
        collateralFactor = _collateralFactor;
    }

    /// @dev Starts auction and sets startBlock.
    function startAuction()
        public
        isOwner
        atStage(Stages.AuctionSetUp)
    {
        stage = Stages.AuctionStarted;
        startBlock = block.number;
    }

    /// @dev Returns correct stage, even if a function with timedTransitions modifier has not yet been called yet.
    /// @return Returns current auction stage.
    function updateStage()
        public
        timedTransitions
        returns (Stages)
    {
        return stage;
    }

    /// @dev Allows to send a bid to the auction.
    /// @param bidder Bid will be assigned to this address if set.
    function bid(address bidder)
        public
        payable
        isValidPayload
        timedTransitions
        atStage(Stages.AuctionStarted)
        returns (uint amount)
    {
        // If a bid is done on behalf of a user via ShapeShift, the bidder address is set.
        if (bidder == 0)
            bidder = msg.sender;

        // enforce percentage per bidder limit
        uint maxWeiAccepted = collateralCeiling * maxCollateralFractionPercentPerBidder / 100;
        maxWeiAccepted -= bids[bidder]; // take in to account previously sent wei

        // enforce total collateral limit
        maxWeiAccepted = min(maxWeiAccepted, collateralCeiling - totalCollateralReceived);

        uint numWei = msg.value;

        // refund non acceptable wei
        if (numWei > maxWeiAccepted) {
            numWei = maxWeiAccepted;
            // Send change back to bidder address. In case of a ShapeShift bid the user receives the change back directly.
            assert(msg.value >= numWei);
            uint refund = msg.value - numWei
            assert(bidder.send(refund));
        }

        // register bid
        assert(numWei>0);
        bids[bidder] += numWei;
        BidSubmission(bidder, numWei);

        // enforce minimum required collateral per bidder, while allowing to add amounts later
        assert(bids[bidder] > minCollateralPerBidder);
        totalCollateralReceived += numWei;
        assert(totalCollateralReceived <= collateralCeiling);
        assert(totalCollateralReceived * collateralFactor <= maxTokensAvailable);

        // finalize if full
        if (totalCollateralReceived == collateralCeiling)
            // When maxWei is equal to the big numWei the auction is ended and finalizeAuction is triggered.
            finalizeAuction();
    }

    // mintingPeriodFactor: 10_000_000, mintingPeriodDevisorConstant: 1_000
    // starts with 27yrs, 4.5yrs @24hs, 2.4yrs @48hrs, 1.5yrs @72hrs
    function calcMintingPeriod(uint elapsedBlocks)
        constant
        public
        returns (uint)
        {
            return mintingPeriodFactor / (elapsedBlocks + mintingPeriodDevisorConstant);
        }

    function currentMintingPeriod()
        constant
        public
        atStage(Stage.AuctionStarted)
        returns (uint)
        {
            return calcMintingPeriod(block.number - startBlock);
        }

    function finalizeAuction()
        private
    {
        stage = Stages.AuctionEnded;
        endTime = now;

        // register mintingPeriod for all successful bidders
        uint elapsed = block.number - startBlock;
        finalMintingPeriod = calcMintingPeriod(elapsed);

        // Transfer funding to collateralize the token
        assert(mint.addCollateral.value(this.value)()); // FIXME double check
    }

    /// @dev registers minting rights for bidder after auction with the Mint
    /// @param receiver MintingRighhts will be assigned to this address if set
    function registerMintingRights(address receiver)
        public
        isValidPayload
        timedTransitions
        atStage(Stages.TradingStarted)
    {
        if (receiver == 0)
            receiver = msg.sender;
        uint tokenCount = bids[receiver] * collateralFactor;
        assert(tokenCount>0);
        bids[receiver] = 0;
        assert(mint.registerMintingRight(receiver, tokenCount, endTime, endTime + finalMintingPeriod));
    }

}


Update Chess.sol

Update Chess.sol

added some functions to validation

/**
 * Chess contract
 * Stores any amount of games with two players and current state.
 * State encoding:
 *    positive numbers for white, negative numbers for black
 *    for details, see
 *    https://github.com/ise-ethereum/on-chain-chess/wiki/Chess-board-representation
 */

contract Chess {
    int8[128] defaultState = [int8(-4),int8(-2),int8(-3),int8(-5),int8(-6),int8(-3),int8(-2),int8(-4),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(-1),int8(-1),int8(-1),int8(-1),int8(-1),int8(-1),int8(-1),int8(-1),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(1),int8(1),int8(1),int8(1),int8(1),int8(1),int8(1),int8(1),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(4),int8(2),int8(3),int8(5),int8(6),int8(3),int8(2),int8(4),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0)];

    struct Game {
        address player1;
        address player2;
        string player1Alias;
        string player2Alias;
        address nextPlayer;
        address playerWhite; // Player that is white in this game
        address winner;
        int[128] state;
    }

    mapping (bytes32 => Game) public games;
    mapping (address => mapping (int => bytes32)) public gamesOfPlayers;
    mapping (address => int) public numberGamesOfPlayers;

    // stack of open game ids
    mapping (bytes32 => bytes32) public openGameIds;
    bytes32 public head;

    function Chess() {
        head = 'end';
    }

    event GameInitialized(bytes32 indexed gameId, address indexed player1, string player1Alias, address playerWhite);
    event GameJoined(bytes32 indexed gameId, address indexed player1, string player1Alias, address indexed player2, string player2Alias, address playerWhite);
    event GameStateChanged(bytes32 indexed gameId, int[128] state);
    event Move(bytes32 indexed gameId, address indexed player, uint256 fromIndex, uint256 toIndex);
    event GameEnded(bytes32 indexed gameId, address indexed winner);

    /**
     * Initialize a new game
     * string player1Alias: Alias of the player creating the game
     * bool playAsWhite: Pass true or false depending on if the creator will play as white
     */
    function initGame(string player1Alias, bool playAsWhite) public {
        // Generate game id based on player's addresses and current block number
        bytes32 gameId = sha3(msg.sender, block.number);

        // Initialize participants
        games[gameId].player1 = msg.sender;
        games[gameId].player1Alias = player1Alias;

        // Initialize state
        games[gameId].state = defaultState;

        if (playAsWhite) {
            // Player 1 will play as white
            games[gameId].playerWhite = msg.sender;

            // Game starts with White, so here player 1
            games[gameId].nextPlayer = games[gameId].player1;
        }

        // Add game to gamesOfPlayers
        gamesOfPlayers[msg.sender][numberGamesOfPlayers[msg.sender]] = gameId;
        numberGamesOfPlayers[msg.sender]++;

        // Add to openGameIds
        openGameIds[gameId] = head;
        head = gameId;

        // Sent notification events
        GameInitialized(gameId, games[gameId].player1, player1Alias, games[gameId].playerWhite);
        GameStateChanged(gameId, games[gameId].state);
    }

    /**
     * Join an initialized game
     * bytes32 gameId: ID of the game to join
     * string player2Alias: Alias of the player that is joining
     */
    function joinGame(bytes32 gameId, string player2Alias) public {
      // Check that this game does not have a second player yet
      if (games[gameId].player2 != 0) {
        throw;
      }

      games[gameId].player2 = msg.sender;
      games[gameId].player2Alias = player2Alias;

      // If the other player isn't white, player2 will play as white
      if (games[gameId].playerWhite == 0) {
        games[gameId].playerWhite = msg.sender;
        // Game starts with White, so here P2
        games[gameId].nextPlayer = games[gameId].player2;
      }

      // Add game to gamesOfPlayers
      gamesOfPlayers[msg.sender][numberGamesOfPlayers[msg.sender]] = gameId;
      numberGamesOfPlayers[msg.sender]++;

      // Remove from openGameIds
      if (head == gameId) {
        head = openGameIds[head];
        openGameIds[gameId] = 0;
      } else {
        for (var g = head; g != 'end' && openGameIds[g] != 'end'; g = openGameIds[g]) {
          if (openGameIds[g] == gameId) {
            openGameIds[g] = openGameIds[gameId];
            openGameIds[gameId] = 0;
            break;
          }
        }
      }

      GameJoined(gameId, games[gameId].player1, games[gameId].player1Alias, games[gameId].player2, player2Alias, games[gameId].playerWhite);
    }

    /* validates a move and executes it */
    function move(bytes32 gameId, uint256 fromIndex, uint256 toIndex) public {
        // Check that it is this player's turn
        if (games[gameId].nextPlayer != msg.sender) {
            throw;
        }

        // TODO: Validate move

        int8 fromFigure = state[fromIndex]
        int8 toFigure = state[toIndex]
        int8 movingPlayerColor  = 1 // todo: set this to the actual color and set the datatype!

        //sanity check
        sanityCheck(fromIndex, toIndex, fromFigure, toFigure, movingPlayerColor)
        //isValid

        //makeTemporaryMove

        //isLegal

        //testIfCheck

        // Update state
        games[gameId].state[toIndex] = games[gameId].state[fromIndex];
        games[gameId].state[fromIndex] = 0;

        // Set nextPlayer
        if (msg.sender == games[gameId].player1) {
            games[gameId].nextPlayer = games[gameId].player2;
        } else {
            games[gameId].nextPlayer = games[gameId].player1;
        }

        Move(gameId, msg.sender, fromIndex, toIndex);
    }

        function sanityCheck(uint256 fromIndex, uint256 toIndex, int8 fromFigure, int8 toFigure, int8 movingPlayerColor){

            // check if the move actually fits the data structure
            if (fromIndex & 0x88){
                throw;
            }

            // check if the move actually fits the data structure
            if (toIndex & 0x88){
                throw;
            }

            // check if the move tries to move a figure onto it self
            if (fromIndex == toIndex){
                throw;
            }

            // check if the toIndex is empty (= is 0) or contains an enemy figure ("positive" * "negative" = "negative")
            // --> this only allows captures ( negative results ) or moves to empty fields ( = 0)
            if (fromFigure * toFigure > 0){
                throw;
            }

            // check if mover of the figure is the owner of the figure
            //todo: fix color to enum
            if (color of current player * fromFigure > 0){
                throw;
            }
        }

        function isValid(uint256 fromIndex, uint256 toIndex, int8 fromFigure, int8 toFigure, int8 movingPlayerColor) returns (bool){

            // check if the move actually fits the data structure
            if (fromIndex & 0x88){
                throw;
            }

        }
        function getDirection(uint256 fromIndex, uint256 toIndex){

            // check if the figure is moved up or left of its origin
            isAboveLeft = fromIndex > toindex

            // check if the figure is moved in an horizontal plane
            // this code works because there is an eight square difference between the horizontal panes (the offboard)
            isSameHorizontal = abs(fromIndex - toindex) < 8

            // check if the figure is moved in a vertical line
            isSameVertical = (fromIndex%8 == toIndex%8)

            // check if the figure is moved to the left of its origin
            isLeftSide = (fromIndex%8 > toIndex%8)

            /*Check directions*/

            if (isAboveLeft){

            }

        }

        function makeTemporaryMove(){

        }

        function isLegal(){

        }

        function testIfCheck(){

        }

    function surrender(bytes32 gameId) public {
        if (games[gameId].winner != 0) {
            // Game already ended
            throw;
        }
        if (games[gameId].player1 == msg.sender) {
            // Player 1 surrendered, player 2 won
            games[gameId].winner = games[gameId].player2;
        } else if(games[gameId].player2 == msg.sender) {
            // Player 2 surrendered, player 1 won
            games[gameId].winner = games[gameId].player1;
        } else {
            // Sender is not a participant of this game
            throw;
        }

        GameEnded(gameId, games[gameId].winner);
    }

    function getGameId(address player, int index) constant returns (bytes32) {
      return gamesOfPlayers[player][index];
    }

    /*------------------------HELPER FUNCTIONS------------------------*/

    // This returns the absolute value of an integer
    function abs(int256 value){
        if (value>=0)return value
        else return -1*value
    }

    /* This unnamed function is called whenever someone tries to send ether to it */
    function () {
        throw;     // Prevents accidental sending of ether
    }
}

/**
 * Chess contract
 * Stores any amount of games with two players and current state.
 * State encoding:
 *    positive numbers for white, negative numbers for black
 *    for details, see
 *    https://github.com/ise-ethereum/on-chain-chess/wiki/Chess-board-representation
 */

contract Chess {
    int8[128] defaultState = [int8(-4),int8(-2),int8(-3),int8(-5),int8(-6),int8(-3),int8(-2),int8(-4),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(-1),int8(-1),int8(-1),int8(-1),int8(-1),int8(-1),int8(-1),int8(-1),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(1),int8(1),int8(1),int8(1),int8(1),int8(1),int8(1),int8(1),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(4),int8(2),int8(3),int8(5),int8(6),int8(3),int8(2),int8(4),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0)];

    struct Game {
        address player1;
        address player2;
        string player1Alias;
        string player2Alias;
        address nextPlayer;
        address playerWhite; // Player that is white in this game
        address winner;
        int[128] state;
    }

    mapping (bytes32 => Game) public games;
    mapping (address => mapping (int => bytes32)) public gamesOfPlayers;
    mapping (address => int) public numberGamesOfPlayers;

    // stack of open game ids
    mapping (bytes32 => bytes32) public openGameIds;
    bytes32 public head;

    function Chess() {
        head = 'end';
    }

    event GameInitialized(bytes32 indexed gameId, address indexed player1, string player1Alias, address playerWhite);
    event GameJoined(bytes32 indexed gameId, address indexed player1, string player1Alias, address indexed player2, string player2Alias, address playerWhite);
    event GameStateChanged(bytes32 indexed gameId, int[128] state);
    event Move(bytes32 indexed gameId, address indexed player, uint256 fromIndex, uint256 toIndex);
    event GameEnded(bytes32 indexed gameId, address indexed winner);

    /**
     * Initialize a new game
     * string player1Alias: Alias of the player creating the game
     * bool playAsWhite: Pass true or false depending on if the creator will play as white
     */
    function initGame(string player1Alias, bool playAsWhite) public {
        // Generate game id based on player's addresses and current block number
        bytes32 gameId = sha3(msg.sender, block.number);

        // Initialize participants
        games[gameId].player1 = msg.sender;
        games[gameId].player1Alias = player1Alias;

        // Initialize state
        games[gameId].state = defaultState;

        if (playAsWhite) {
            // Player 1 will play as white
            games[gameId].playerWhite = msg.sender;

            // Game starts with White, so here player 1
            games[gameId].nextPlayer = games[gameId].player1;
        }

        // Add game to gamesOfPlayers
        gamesOfPlayers[msg.sender][numberGamesOfPlayers[msg.sender]] = gameId;
        numberGamesOfPlayers[msg.sender]++;

        // Add to openGameIds
        openGameIds[gameId] = head;
        head = gameId;

        // Sent notification events
        GameInitialized(gameId, games[gameId].player1, player1Alias, games[gameId].playerWhite);
        GameStateChanged(gameId, games[gameId].state);
    }

    /**
     * Join an initialized game
     * bytes32 gameId: ID of the game to join
     * string player2Alias: Alias of the player that is joining
     */
    function joinGame(bytes32 gameId, string player2Alias) public {
      // Check that this game does not have a second player yet
      if (games[gameId].player2 != 0) {
        throw;
      }

      games[gameId].player2 = msg.sender;
      games[gameId].player2Alias = player2Alias;

      // If the other player isn't white, player2 will play as white
      if (games[gameId].playerWhite == 0) {
        games[gameId].playerWhite = msg.sender;
        // Game starts with White, so here P2
        games[gameId].nextPlayer = games[gameId].player2;
      }

      // Add game to gamesOfPlayers
      gamesOfPlayers[msg.sender][numberGamesOfPlayers[msg.sender]] = gameId;
      numberGamesOfPlayers[msg.sender]++;

      // Remove from openGameIds
      if (head == gameId) {
        head = openGameIds[head];
        openGameIds[gameId] = 0;
      } else {
        for (var g = head; g != 'end' && openGameIds[g] != 'end'; g = openGameIds[g]) {
          if (openGameIds[g] == gameId) {
            openGameIds[g] = openGameIds[gameId];
            openGameIds[gameId] = 0;
            break;
          }
        }
      }

      GameJoined(gameId, games[gameId].player1, games[gameId].player1Alias, games[gameId].player2, player2Alias, games[gameId].playerWhite);
    }

    /* validates a move and executes it */
    function move(bytes32 gameId, uint256 fromIndex, uint256 toIndex) public {
        // Check that it is this player's turn
        if (games[gameId].nextPlayer != msg.sender) {
            throw;
        }

        // TODO: Validate move

        int8 fromFigure = state[fromIndex]
        int8 toFigure = state[toIndex]
        int8 movingPlayerColor  = 1 // todo: set this to the actual color and set the datatype!

        //sanity check

        //isValid

        //makeTemporaryMove

        //isLegal

        //testIfCheck

        // Update state
        games[gameId].state[toIndex] = games[gameId].state[fromIndex];
        games[gameId].state[fromIndex] = 0;

        // Set nextPlayer
        if (msg.sender == games[gameId].player1) {
            games[gameId].nextPlayer = games[gameId].player2;
        } else {
            games[gameId].nextPlayer = games[gameId].player1;
        }

        Move(gameId, msg.sender, fromIndex, toIndex);
    }

        function sanityCheck(uint256 fromIndex, uint256 toIndex, int8 fromFigure, int8 toFigure, int8 movingPlayerColor){

        }

        function isValid(){

        }

        function makeTemporaryMove(){

        }

        function isLegal(){

        }

        function testIfCheck(){

        }

    function surrender(bytes32 gameId) public {
        if (games[gameId].winner != 0) {
            // Game already ended
            throw;
        }
        if (games[gameId].player1 == msg.sender) {
            // Player 1 surrendered, player 2 won
            games[gameId].winner = games[gameId].player2;
        } else if(games[gameId].player2 == msg.sender) {
            // Player 2 surrendered, player 1 won
            games[gameId].winner = games[gameId].player1;
        } else {
            // Sender is not a participant of this game
            throw;
        }

        GameEnded(gameId, games[gameId].winner);
    }

    function getGameId(address player, int index) constant returns (bytes32) {
      return gamesOfPlayers[player][index];
    }

    /* This unnamed function is called whenever someone tries to send ether to it */
    function () {
        throw;     // Prevents accidental sending of ether
    }
}


BC: Enable offerDraw when claimTimeout is long ago

/**
 * Chess contract
 * Stores any amount of games with two players and current state.
 * State encoding:
 *    positive numbers for white, negative numbers for black
 *    for details, see
 *    https://github.com/ise-ethereum/on-chain-chess/wiki/Chess-board-representation
 */

import "TurnBasedGame.sol";
import "ChessLogic.sol";
import "Auth.sol";

contract Chess is TurnBasedGame, Auth {
    using ChessLogic for ChessLogic.State;
    mapping (bytes32 => ChessLogic.State) gameStates;

    event GameInitialized(bytes32 indexed gameId, address indexed player1, string player1Alias, address playerWhite, uint pot);
    event GameJoined(bytes32 indexed gameId, address indexed player1, string player1Alias, address indexed player2, string player2Alias, address playerWhite, uint pot);
    event GameStateChanged(bytes32 indexed gameId, int8[128] state);
    event GameTimeoutStarted(bytes32 indexed gameId,uint timeoutStarted, int8 timeoutState);
    // GameDrawOfferRejected: notification that a draw of the currently turning player
    //                        is rejected by the waiting player
    event GameDrawOfferRejected(bytes32 indexed gameId);
    event Move(bytes32 indexed gameId, address indexed player, uint256 fromIndex, uint256 toIndex);

    function Chess(bool enableDebugging) TurnBasedGame(enableDebugging) {
    }

    /**
     * Initialize a new game
     * string player1Alias: Alias of the player creating the game
     * bool playAsWhite: Pass true or false depending on if the creator will play as white
     */
    function initGame(string player1Alias, bool playAsWhite) public returns (bytes32) {
        bytes32 gameId = super.initGame(player1Alias, playAsWhite);

        // Setup game state
        int8 nextPlayerColor = int8(1);
        gameStates[gameId].setupState(nextPlayerColor);
        if (playAsWhite) {
            // Player 1 will play as white
            gameStates[gameId].playerWhite = msg.sender;

            // Game starts with White, so here player 1
            games[gameId].nextPlayer = games[gameId].player1;
        }

        // Sent notification events
        GameInitialized(gameId, games[gameId].player1, player1Alias, gameStates[gameId].playerWhite, games[gameId].pot);
        GameStateChanged(gameId, gameStates[gameId].fields);
        return gameId;
    }

    /**
     * Join an initialized game
     * bytes32 gameId: ID of the game to join
     * string player2Alias: Alias of the player that is joining
     */
    function joinGame(bytes32 gameId, string player2Alias) public {
        super.joinGame(gameId, player2Alias);

        // If the other player isn't white, player2 will play as white
        if (gameStates[gameId].playerWhite == 0) {
            gameStates[gameId].playerWhite = msg.sender;
            // Game starts with White, so here player2
            games[gameId].nextPlayer = games[gameId].player2;
        }

        GameJoined(gameId, games[gameId].player1, games[gameId].player1Alias, games[gameId].player2, player2Alias, gameStates[gameId].playerWhite, games[gameId].pot);
    }

    /**
    *
    * verify signature of state
    * verify signature of move
    * apply state, verify move
    */
    function moveFromState(bytes32 gameId, int8[128] state, uint256 fromIndex,
                           uint256 toIndex, bytes sigState) notEnded(gameId) public {
        // check whether sender is a member of this game
        if (games[gameId].player1 != msg.sender && games[gameId].player2 != msg.sender) {
            throw;
        }

        // find opponent to msg.sender
        address opponent;
        if (msg.sender == games[gameId].player1) {
            opponent = games[gameId].player2;
        } else {
            opponent = games[gameId].player1;
        }

        // verify state - should be signed by the other member of game - not mover
        if (!verifySig(opponent, sha3(state), sigState)) {
            throw;
        }

        // check move count. New state should have a higher move count.
        if ((state[8] * int8(128) + state[9]) < (gameStates[gameId].fields[8] * int8(128) + gameStates[gameId].fields[9])) {
            throw;
        }

        int8 playerColor = msg.sender == gameStates[gameId].playerWhite ? int8(1) : int8(-1);

        // apply state
        gameStates[gameId].setState(state, playerColor);
        games[gameId].nextPlayer =  msg.sender;

        // apply and verify move
        move(gameId, fromIndex, toIndex);
    }

    function move(bytes32 gameId, uint256 fromIndex, uint256 toIndex) notEnded(gameId) public {
        if (games[gameId].nextPlayer != msg.sender) {
            throw;
        }
        if(games[gameId].timeoutState != 0) {
            games[gameId].timeoutState = 0;
        }
        // Chess move validation
        gameStates[gameId].move(fromIndex, toIndex);

        // Set nextPlayer
        if (msg.sender == games[gameId].player1) {
            games[gameId].nextPlayer = games[gameId].player2;
        } else {
            games[gameId].nextPlayer = games[gameId].player1;
        }

        // Send events
        Move(gameId, msg.sender, fromIndex, toIndex);
        GameStateChanged(gameId, gameStates[gameId].fields);
    }

    /* Explicit set game state. Only in debug mode */
    function setGameState(bytes32 gameId, int8[128] state, address nextPlayer) debugOnly public {
        int8 playerColor = nextPlayer == gameStates[gameId].playerWhite ? int8(1) : int8(-1);
        gameStates[gameId].setState(state, playerColor);
        games[gameId].nextPlayer = nextPlayer;
        GameStateChanged(gameId, gameStates[gameId].fields);
    }

    function getCurrentGameState(bytes32 gameId) constant returns (int8[128]) {
       return gameStates[gameId].fields;
    }

    function getWhitePlayer(bytes32 gameId) constant returns (address) {
       return gameStates[gameId].playerWhite;
    }

    /* The sender claims he has won the game. Starts a timeout. */
    function claimWin(bytes32 gameId) notEnded(gameId) public {

        var game = games[gameId];
        // just the two players currently playing
        if (msg.sender != game.player1 && msg.sender != game.player2)
            throw;
        // only if timeout has not started
        if (game.timeoutState != 0)
            throw;
        // you can only claim draw / victory in the enemies turn
        if (msg.sender == game.nextPlayer)
            throw;
        // get the color of the player that wants to claim win
        int8 otherPlayerColor = gameStates[gameId].playerWhite == msg.sender ? int8(-1) : int8(1);
        // the one not sending is white -> the sending player is Black

        // We get the king position of that player
        uint256 kingIndex = uint256(gameStates[gameId].getOwnKing(otherPlayerColor));
        // if he is in check the request is legal
        if (gameStates[gameId].checkForCheck(kingIndex, otherPlayerColor)){
            game.timeoutStarted = now;
            game.timeoutState = 1;
            GameTimeoutStarted(gameId, game.timeoutStarted, game.timeoutState);
        // else it is not
        } else {
            throw;
        }

    }

    /* The sender offers the other player a draw. Starts a timeout. */
    function offerDraw(bytes32 gameId) notEnded(gameId) public {
        var game = games[gameId];
        // just the two players currently playing
        if (msg.sender != game.player1 && msg.sender != game.player2)
            throw;
        // only if timeout has not started or is a draw by nextPlayer
        if (game.timeoutState != 0 && game.timeoutState != 2)
            throw;
        // if state = timeout, timeout has to be 2*timeoutTime
        if (game.timeoutState == 2 && now < game.timeoutStarted + 20 minutes)
            throw;

        game.timeoutStarted = now;
        if (msg.sender == game.nextPlayer) {
            game.timeoutState = -2;
        } else {
            game.timeoutState = -1;
        }
        GameTimeoutStarted(gameId, game.timeoutStarted, game.timeoutState);
    }

    /*
     * The sender claims that the other player is not in the game anymore.
     * Starts a Timeout that can be claimed
     */
    function claimTimeout(bytes32 gameId) notEnded(gameId) public {
        var game = games[gameId];
        // just the two players currently playing
        if (msg.sender != game.player1 && msg.sender != game.player2)
            throw;
        // only if timeout has not started
        if (game.timeoutState != 0)
            throw;
        // you can only claim draw / victory in the enemies turn
        if (msg.sender == game.nextPlayer)
            throw;
        game.timeoutStarted = now;
        game.timeoutState = 2;
        GameTimeoutStarted(gameId, game.timeoutStarted, game.timeoutState);
    }

    /*
     * The sender (waiting player) rejects the draw offered by the
     * other (turning / current) player.
     */
    function rejectCurrentPlayerDraw(bytes32 gameId) notEnded(gameId) public {
        var game = games[gameId];
        // just the two players currently playing
        if (msg.sender != game.player1 && msg.sender != game.player2)
            throw;
        // only if timeout is present
        if (game.timeoutState != -2)
            throw;
        // only not playing player is able to reject a draw offer of the nextPlayer
        if (msg.sender == game.nextPlayer)
            throw;
        game.timeoutState = 0;
        GameDrawOfferRejected(gameId);
    }

    /*
     * The sender (currently waiting player) claims that the other (turning)
     * player timed out and has to provide a move, the other player could
     * have done to prevent the timeout.
     */
    function claimTimeoutEndedWithMove(bytes32 gameId, uint256 fromIndex, uint256 toIndex) notEnded(gameId) public {
        var game = games[gameId];
        // just the two players currently playing
        if (msg.sender != game.player1 && msg.sender != game.player2)
            throw;
        if (now < game.timeoutStarted + 10 minutes)
            throw;
        if (msg.sender == game.nextPlayer)
            throw;
        if (game.timeoutState != 2)
            throw;

        // TODO we need other move function
        // move is valid if it does not throw
        move(gameId, fromIndex, toIndex);

        game.ended = true;
        game.winner = msg.sender;
        if(msg.sender == game.player1) {
            games[gameId].player1Winnings = games[gameId].pot;
            games[gameId].pot = 0;
        } else {
            games[gameId].player2Winnings = games[gameId].pot;
            games[gameId].pot = 0;
        }
        GameEnded(gameId);
    }

    /* The sender claims a previously started timeout. */
    function claimTimeoutEnded(bytes32 gameId) notEnded(gameId) public {
        var game = games[gameId];
        // just the two players currently playing
        if (msg.sender != game.player1 && msg.sender != game.player2)
            throw;
        if (game.timeoutState == 0 || game.timeoutState == 2)
            throw;
        if (now < game.timeoutStarted + 10 minutes)
            throw;
        if (msg.sender == game.nextPlayer) {
            if (game.timeoutState == -2) { // draw
                game.ended = true;
                games[gameId].player1Winnings = games[gameId].pot / 2;
                games[gameId].player2Winnings = games[gameId].pot / 2;
                games[gameId].pot = 0;
                GameEnded(gameId);
            } else {
                throw;
            }
        } else {
            if (game.timeoutState == -1) { // draw
                game.ended = true;
                games[gameId].player1Winnings = games[gameId].pot / 2;
                games[gameId].player2Winnings = games[gameId].pot / 2;
                games[gameId].pot = 0;
                GameEnded(gameId);
            } else if (game.timeoutState == 1){ // win
                game.ended = true;
                game.winner = msg.sender;
                if(msg.sender == game.player1) {
                    games[gameId].player1Winnings = games[gameId].pot;
                    games[gameId].pot = 0;
                } else {
                    games[gameId].player2Winnings = games[gameId].pot;
                    games[gameId].pot = 0;
                }
                GameEnded(gameId);
            } else {
                throw;
            }
        }
    }

    /* A timeout can be confirmed by the non-initializing player. */
    function confirmGameEnded(bytes32 gameId) notEnded(gameId) public {
        var game = games[gameId];
        // just the two players currently playing
        if (msg.sender != game.player1 && msg.sender != game.player2)
            throw;
        if (game.timeoutState == 0)
            throw;
        if (msg.sender != game.nextPlayer) {
            if (game.timeoutState == -2) { // draw
                game.ended = true;
                games[gameId].player1Winnings = games[gameId].pot / 2;
                games[gameId].player2Winnings = games[gameId].pot / 2;
                games[gameId].pot = 0;
                GameEnded(gameId);
            } else {
                throw;
            }
        } else {
            if (game.timeoutState == -1) { // draw
                game.ended = true;
                games[gameId].player1Winnings = games[gameId].pot / 2;
                games[gameId].player2Winnings = games[gameId].pot / 2;
                games[gameId].pot = 0;
                GameEnded(gameId);
            } else if (game.timeoutState == 1 || game.timeoutState == 2) { // win
                // TODO: do we want to allow this for timeoutState == 2 ?
                game.ended = true;
                if(msg.sender == game.player1) {
                    game.winner = game.player2;
                    games[gameId].player2Winnings = games[gameId].pot;
                    games[gameId].pot = 0;
                } else {
                    game.winner = game.player1;
                    games[gameId].player1Winnings = games[gameId].pot;
                    games[gameId].pot = 0;
                }
                GameEnded(gameId);
            } else {
                throw;
            }
        }
    }

    /* This unnamed function is called whenever someone tries to send ether to the contract */
    function () {
        throw; // Prevents accidental sending of ether
    }
}

/**
 * Chess contract
 * Stores any amount of games with two players and current state.
 * State encoding:
 *    positive numbers for white, negative numbers for black
 *    for details, see
 *    https://github.com/ise-ethereum/on-chain-chess/wiki/Chess-board-representation
 */

import "TurnBasedGame.sol";
import "ChessLogic.sol";
import "Auth.sol";

contract Chess is TurnBasedGame, Auth {
    using ChessLogic for ChessLogic.State;
    mapping (bytes32 => ChessLogic.State) gameStates;

    event GameInitialized(bytes32 indexed gameId, address indexed player1, string player1Alias, address playerWhite, uint pot);
    event GameJoined(bytes32 indexed gameId, address indexed player1, string player1Alias, address indexed player2, string player2Alias, address playerWhite, uint pot);
    event GameStateChanged(bytes32 indexed gameId, int8[128] state);
    event GameTimeoutStarted(bytes32 indexed gameId,uint timeoutStarted, int8 timeoutState);
    // GameDrawOfferRejected: notification that a draw of the currently turning player
    //                        is rejected by the waiting player
    event GameDrawOfferRejected(bytes32 indexed gameId);
    event Move(bytes32 indexed gameId, address indexed player, uint256 fromIndex, uint256 toIndex);

    function Chess(bool enableDebugging) TurnBasedGame(enableDebugging) {
    }

    /**
     * Initialize a new game
     * string player1Alias: Alias of the player creating the game
     * bool playAsWhite: Pass true or false depending on if the creator will play as white
     */
    function initGame(string player1Alias, bool playAsWhite) public returns (bytes32) {
        bytes32 gameId = super.initGame(player1Alias, playAsWhite);

        // Setup game state
        int8 nextPlayerColor = int8(1);
        gameStates[gameId].setupState(nextPlayerColor);
        if (playAsWhite) {
            // Player 1 will play as white
            gameStates[gameId].playerWhite = msg.sender;

            // Game starts with White, so here player 1
            games[gameId].nextPlayer = games[gameId].player1;
        }

        // Sent notification events
        GameInitialized(gameId, games[gameId].player1, player1Alias, gameStates[gameId].playerWhite, games[gameId].pot);
        GameStateChanged(gameId, gameStates[gameId].fields);
        return gameId;
    }

    /**
     * Join an initialized game
     * bytes32 gameId: ID of the game to join
     * string player2Alias: Alias of the player that is joining
     */
    function joinGame(bytes32 gameId, string player2Alias) public {
        super.joinGame(gameId, player2Alias);

        // If the other player isn't white, player2 will play as white
        if (gameStates[gameId].playerWhite == 0) {
            gameStates[gameId].playerWhite = msg.sender;
            // Game starts with White, so here player2
            games[gameId].nextPlayer = games[gameId].player2;
        }

        GameJoined(gameId, games[gameId].player1, games[gameId].player1Alias, games[gameId].player2, player2Alias, gameStates[gameId].playerWhite, games[gameId].pot);
    }

    /**
    *
    * verify signature of state
    * verify signature of move
    * apply state, verify move
    */
    function moveFromState(bytes32 gameId, int8[128] state, uint256 fromIndex,
                           uint256 toIndex, bytes sigState) notEnded(gameId) public {
        // check whether sender is a member of this game
        if (games[gameId].player1 != msg.sender && games[gameId].player2 != msg.sender) {
            throw;
        }

        // find opponent to msg.sender
        address opponent;
        if (msg.sender == games[gameId].player1) {
            opponent = games[gameId].player2;
        } else {
            opponent = games[gameId].player1;
        }

        // verify state - should be signed by the other member of game - not mover
        if (!verifySig(opponent, sha3(state), sigState)) {
            throw;
        }

        // check move count. New state should have a higher move count.
        if ((state[8] * int8(128) + state[9]) < (gameStates[gameId].fields[8] * int8(128) + gameStates[gameId].fields[9])) {
            throw;
        }

        int8 playerColor = msg.sender == gameStates[gameId].playerWhite ? int8(1) : int8(-1);

        // apply state
        gameStates[gameId].setState(state, playerColor);
        games[gameId].nextPlayer =  msg.sender;

        // apply and verify move
        move(gameId, fromIndex, toIndex);
    }

    function move(bytes32 gameId, uint256 fromIndex, uint256 toIndex) notEnded(gameId) public {
        if (games[gameId].nextPlayer != msg.sender) {
            throw;
        }
        if(games[gameId].timeoutState != 0) {
            games[gameId].timeoutState = 0;
        }
        // Chess move validation
        gameStates[gameId].move(fromIndex, toIndex);

        // Set nextPlayer
        if (msg.sender == games[gameId].player1) {
            games[gameId].nextPlayer = games[gameId].player2;
        } else {
            games[gameId].nextPlayer = games[gameId].player1;
        }

        // Send events
        Move(gameId, msg.sender, fromIndex, toIndex);
        GameStateChanged(gameId, gameStates[gameId].fields);
    }

    /* Explicit set game state. Only in debug mode */
    function setGameState(bytes32 gameId, int8[128] state, address nextPlayer) debugOnly public {
        int8 playerColor = nextPlayer == gameStates[gameId].playerWhite ? int8(1) : int8(-1);
        gameStates[gameId].setState(state, playerColor);
        games[gameId].nextPlayer = nextPlayer;
        GameStateChanged(gameId, gameStates[gameId].fields);
    }

    function getCurrentGameState(bytes32 gameId) constant returns (int8[128]) {
       return gameStates[gameId].fields;
    }

    function getWhitePlayer(bytes32 gameId) constant returns (address) {
       return gameStates[gameId].playerWhite;
    }

    /* The sender claims he has won the game. Starts a timeout. */
    function claimWin(bytes32 gameId) notEnded(gameId) public {

        var game = games[gameId];
        // just the two players currently playing
        if (msg.sender != game.player1 && msg.sender != game.player2)
            throw;
        // only if timeout has not started
        if (game.timeoutState != 0)
            throw;
        // you can only claim draw / victory in the enemies turn
        if (msg.sender == game.nextPlayer)
            throw;
        // get the color of the player that wants to claim win
        int8 otherPlayerColor = gameStates[gameId].playerWhite == msg.sender ? int8(-1) : int8(1);
        // the one not sending is white -> the sending player is Black

        // We get the king position of that player
        uint256 kingIndex = uint256(gameStates[gameId].getOwnKing(otherPlayerColor));
        // if he is in check the request is legal
        if (gameStates[gameId].checkForCheck(kingIndex, otherPlayerColor)){
            game.timeoutStarted = now;
            game.timeoutState = 1;
            GameTimeoutStarted(gameId, game.timeoutStarted, game.timeoutState);
        // else it is not
        } else {
            throw;
        }

    }

    /* The sender offers the other player a draw. Starts a timeout. */
    function offerDraw(bytes32 gameId) notEnded(gameId) public {
        var game = games[gameId];
        // just the two players currently playing
        if (msg.sender != game.player1 && msg.sender != game.player2)
            throw;
        // only if timeout has not started or state = timeout and 2*timeoutTime is over
        if (game.timeoutState != 0 && (game.timeoutState != 2 || now < game.timeoutStarted + 20 minutes))
            throw;

        game.timeoutStarted = now;
        if (msg.sender == game.nextPlayer) {
            game.timeoutState = -2;
        } else {
            game.timeoutState = -1;
        }
        GameTimeoutStarted(gameId, game.timeoutStarted, game.timeoutState);
    }

    /*
     * The sender claims that the other player is not in the game anymore.
     * Starts a Timeout that can be claimed
     */
    function claimTimeout(bytes32 gameId) notEnded(gameId) public {
        var game = games[gameId];
        // just the two players currently playing
        if (msg.sender != game.player1 && msg.sender != game.player2)
            throw;
        // only if timeout has not started
        if (game.timeoutState != 0)
            throw;
        // you can only claim draw / victory in the enemies turn
        if (msg.sender == game.nextPlayer)
            throw;
        game.timeoutStarted = now;
        game.timeoutState = 2;
        GameTimeoutStarted(gameId, game.timeoutStarted, game.timeoutState);
    }

    /*
     * The sender (waiting player) rejects the draw offered by the
     * other (turning / current) player.
     */
    function rejectCurrentPlayerDraw(bytes32 gameId) notEnded(gameId) public {
        var game = games[gameId];
        // just the two players currently playing
        if (msg.sender != game.player1 && msg.sender != game.player2)
            throw;
        // only if timeout is present
        if (game.timeoutState != -2)
            throw;
        // only not playing player is able to reject a draw offer of the nextPlayer
        if (msg.sender == game.nextPlayer)
            throw;
        game.timeoutState = 0;
        GameDrawOfferRejected(gameId);
    }

    /*
     * The sender (currently waiting player) claims that the other (turning)
     * player timed out and has to provide a move, the other player could
     * have done to prevent the timeout.
     */
    function claimTimeoutEndedWithMove(bytes32 gameId, uint256 fromIndex, uint256 toIndex) notEnded(gameId) public {
        var game = games[gameId];
        // just the two players currently playing
        if (msg.sender != game.player1 && msg.sender != game.player2)
            throw;
        if (now < game.timeoutStarted + 10 minutes)
            throw;
        if (msg.sender == game.nextPlayer)
            throw;
        if (game.timeoutState != 2)
            throw;

        // TODO we need other move function
        // move is valid if it does not throw
        move(gameId, fromIndex, toIndex);

        game.ended = true;
        game.winner = msg.sender;
        if(msg.sender == game.player1) {
            games[gameId].player1Winnings = games[gameId].pot;
            games[gameId].pot = 0;
        } else {
            games[gameId].player2Winnings = games[gameId].pot;
            games[gameId].pot = 0;
        }
        GameEnded(gameId);
    }

    /* The sender claims a previously started timeout. */
    function claimTimeoutEnded(bytes32 gameId) notEnded(gameId) public {
        var game = games[gameId];
        // just the two players currently playing
        if (msg.sender != game.player1 && msg.sender != game.player2)
            throw;
        if (game.timeoutState == 0 || game.timeoutState == 2)
            throw;
        if (now < game.timeoutStarted + 10 minutes)
            throw;
        if (msg.sender == game.nextPlayer) {
            if (game.timeoutState == -2) { // draw
                game.ended = true;
                games[gameId].player1Winnings = games[gameId].pot / 2;
                games[gameId].player2Winnings = games[gameId].pot / 2;
                games[gameId].pot = 0;
                GameEnded(gameId);
            } else {
                throw;
            }
        } else {
            if (game.timeoutState == -1) { // draw
                game.ended = true;
                games[gameId].player1Winnings = games[gameId].pot / 2;
                games[gameId].player2Winnings = games[gameId].pot / 2;
                games[gameId].pot = 0;
                GameEnded(gameId);
            } else if (game.timeoutState == 1){ // win
                game.ended = true;
                game.winner = msg.sender;
                if(msg.sender == game.player1) {
                    games[gameId].player1Winnings = games[gameId].pot;
                    games[gameId].pot = 0;
                } else {
                    games[gameId].player2Winnings = games[gameId].pot;
                    games[gameId].pot = 0;
                }
                GameEnded(gameId);
            } else {
                throw;
            }
        }
    }

    /* A timeout can be confirmed by the non-initializing player. */
    function confirmGameEnded(bytes32 gameId) notEnded(gameId) public {
        var game = games[gameId];
        // just the two players currently playing
        if (msg.sender != game.player1 && msg.sender != game.player2)
            throw;
        if (game.timeoutState == 0)
            throw;
        if (msg.sender != game.nextPlayer) {
            if (game.timeoutState == -2) { // draw
                game.ended = true;
                games[gameId].player1Winnings = games[gameId].pot / 2;
                games[gameId].player2Winnings = games[gameId].pot / 2;
                games[gameId].pot = 0;
                GameEnded(gameId);
            } else {
                throw;
            }
        } else {
            if (game.timeoutState == -1) { // draw
                game.ended = true;
                games[gameId].player1Winnings = games[gameId].pot / 2;
                games[gameId].player2Winnings = games[gameId].pot / 2;
                games[gameId].pot = 0;
                GameEnded(gameId);
            } else if (game.timeoutState == 1 || game.timeoutState == 2) { // win
                // TODO: do we want to allow this for timeoutState == 2 ?
                game.ended = true;
                if(msg.sender == game.player1) {
                    game.winner = game.player2;
                    games[gameId].player2Winnings = games[gameId].pot;
                    games[gameId].pot = 0;
                } else {
                    game.winner = game.player1;
                    games[gameId].player1Winnings = games[gameId].pot;
                    games[gameId].pot = 0;
                }
                GameEnded(gameId);
            } else {
                throw;
            }
        }
    }

    /* This unnamed function is called whenever someone tries to send ether to the contract */
    function () {
        throw; // Prevents accidental sending of ether
    }
}


Add requires to token transfers

Add requires to token transfers

pragma solidity ^0.4.11;

import "./StandardToken.sol";
import "./PLCRVoting.sol";
import "./Parameterizer.sol";

contract Registry {

    struct Listing {
        uint applicationExpiry; // expiration date of apply stage
        bool whitelisted;       // indicates registry status
        address owner;          // owner of Listing
        uint currentDeposit;    // number of tokens staked
        uint challengeID;       // identifier of canonical challenge
    }

    struct Challenge {
        uint rewardPool;        // pool of tokens distributed amongst winning voters
        address challenger;     // owner of Challenge
        bool resolved;          // indication of if challenge is resolved
        uint stake;             // number of tokens at risk for either party during challenge
        uint remainder;         // remainder tokens from flooring rewards to be claimed by the winner
    }

    // maps challengeIDs to associated challenge data
    mapping(uint => Challenge) challengeMap;
    // maps domainHashes to associated listing data
    mapping(bytes32 => Listing) public listingMap;
    // maps challengeIDs and address to token claim data
    mapping(uint => mapping(address => bool)) public tokenClaims;

    // Global Variables
    StandardToken public token;
    PLCRVoting public voting;
    Parameterizer public parameterizer;

    // Constants
    bytes32 constant private MINDEPOSIT_h = sha3("minDeposit");
    bytes32 constant private MINPARAMDEPOSIT_h = sha3("minParamDeposit");
    bytes32 constant private APPLYSTAGELEN_h = sha3("applyStageLen");
    bytes32 constant private COMMITPERIODLEN_h = sha3("commitPeriodLen");
    bytes32 constant private REVEALPERIODLEN_h = sha3("revealPeriodLen");
    bytes32 constant private DISPENSATIONPCT_h = sha3("dispensationPct");
    bytes32 constant private VOTEQUORUM_h = sha3("voteQuorum");
    uint256 constant private MULTIPLIER = 10 ** 18;  // used to help represent doubles as ints in token rewards

    // ------------
    // CONSTRUCTOR:
    // ------------

    function Registry(
        address _tokenAddr,
        address _paramAddr,
        address _votingAddr
    ) {
        token = StandardToken(_tokenAddr);
        parameterizer = Parameterizer(_paramAddr);
        voting = PLCRVoting(_tokenAddr);
    }

    // --------------------
    // PUBLISHER INTERFACE:
    // --------------------

    //Allow a user to start an application
    //take tokens from user and set apply stage end time
    function apply(string domain) external {
        require(!isWhitelisted(domain));
        require(!appExists(domain));

        //set owner
        Listing storage listing = listingMap[sha3(domain)];
        listing.owner = msg.sender;

        //transfer tokens
        uint minDeposit = parameterizer.params(MINDEPOSIT_h);
        require(token.transferFrom(listing.owner, this, minDeposit));

        //set apply stage end time
        listing.applicationExpiry = block.timestamp + parameterizer.params(APPLYSTAGELEN_h);
        listing.currentDeposit = minDeposit;
    }

    //Allow the owner of a domain in the listing to increase their deposit
    function deposit(string domain, uint amount) external {
        Listing storage listing = listingMap[sha3(domain)];

        require(listing.owner == msg.sender);
        require(token.transferFrom(msg.sender, this, amount));

        listing.currentDeposit += amount;
    }

    //Allow the owner of a domain in the listing to withdraw
    //tokens not locked in a challenge.
    //The publisher's domain remains whitelisted
    function withdraw(string domain, uint amount) external {
        Listing storage listing = listingMap[sha3(domain)];

        require(listing.owner == msg.sender);
        require(amount <= listing.currentDeposit);
        require(token.transfer(msg.sender, amount));

        listing.currentDeposit -= amount;
    }

    //Allow the owner of a domain to remove the domain from the whitelist
    //Return all tokens to the owner
    function exit(string domain) external {
        Listing storage listing = listingMap[sha3(domain)];

        require(isWhitelisted(domain));
        // cannot exit during ongoing challenge
        require(challengeMap[listing.challengeID].resolved);

        //remove domain & return tokens
        resetListing(domain);
    }

    // -----------------------
    // TOKEN HOLDER INTERFACE:
    // -----------------------

    //start a poll for a domain in the apply stage or already on the whitelist
    //tokens are taken from the challenger and the publisher's tokens are locked
    function challenge(string domain) external returns (uint challengeID) {
        bytes32 domainHash = sha3(domain);
        Listing storage listing = listingMap[domainHash];

        //to be challenged, domain must be in apply stage or already on the whitelist
        require(appExists(domain) || listing.whitelisted);
        require(challengeMap[listing.challengeID].resolved); // prevent multiple challenges

        if (listing.currentDeposit < parameterizer.params(MINDEPOSIT_h)) {
            // not enough tokens, publisher auto-delisted
            resetListing(domain);
            return 0;
        }
        //take tokens from challenger
        uint deposit = parameterizer.params(MINDEPOSIT_h);
        require(token.transferFrom(msg.sender, this, deposit));
        //start poll
        uint pollID = voting.startPoll(domain,
            parameterizer.params(VOTEQUORUM_h),
            parameterizer.params(COMMITPERIODLEN_h),
            parameterizer.params(REVEALPERIODLEN_h)
        );

        challengeMap[pollID] = Challenge({
            challenger: msg.sender,
            rewardPool: ((100 - parameterizer.params(DISPENSATIONPCT_h)) * deposit) / 100,
            stake: deposit,
            resolved: false,
            remainder: 0
        });

        listingMap[domainHash].challengeID = pollID;      // update listing to store most recent challenge
        listingMap[domainHash].currentDeposit -= deposit; // lock tokens for listing during challenge

        return pollID;
    }

    // whitelist domain if apply stage ended without a challenge
    function updateStatus(string domain) public {
        bytes32 domainHash = sha3(domain);
        uint challengeID = listingMap[domainHash].challengeID;
        require(!challengeMap[challengeID].resolved);  // require processed flag to be false

        // IF NO CHALLENGE AFTER APPLY STAGE
        if (challengeID == 0 && isExpired(listingMap[domainHash].applicationExpiry)) {
            listingMap[domainHash].whitelisted = true;
        } else {
        // PROCESS THE RESULT OF THE POLL

            // winner gets back their full staked deposit, and dispensationPct*loser's stake
            // (1-dispensationPct)*loser's stake = rewardPool
            uint stake = 2*challengeMap[challengeID].stake - challengeMap[challengeID].rewardPool;

            if (voting.isPassed(challengeID)) {
                listingMap[domainHash].whitelisted = true;
                listingMap[domainHash].currentDeposit += stake; // give stake back to applicant
            } else {
                resetListing(domain); // whitelisted = false
                require(token.transfer(challengeMap[challengeID].challenger, stake)); // give stake to challenger
            }

            challengeMap[challengeID].resolved = true; // set flag on challenge being processed
        }
    }

    // ----------------
    // TOKEN FUNCTIONS:
    // ----------------

    // called by voter to claim reward for each completed vote
    function claimReward(uint _challengeID, uint _salt) public {
        // ensure voter has not already claimed tokens
        require(tokenClaims[_challengeID][msg.sender] == false);
        uint reward = calculateTokens(_challengeID, _salt, msg.sender);
        // ensures a voter cannot claim tokens again
        require(token.transfer(msg.sender, reward));
        tokenClaims[_challengeID][msg.sender] = 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 _challengeID, uint _salt, address _voter) private returns(uint) {
        uint256 totalTokens = voting.getTotalNumberOfTokensForWinningOption(_challengeID);
        uint256 voterTokens = voting.getNumPassingTokens(_voter, _challengeID, _salt);

        uint256 rewardPool = challengeMap[_challengeID].rewardPool * MULTIPLIER;
        uint256 numerator = voterTokens * rewardPool;
        uint256 denominator = totalTokens * MULTIPLIER;
        uint256 remainder = numerator % denominator;

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

        return numerator / denominator;
    }

    // gives reminder tokens from poll to a designated claimer
    // the claimer is the winner of the challenge
    // for every poll there will be ~0.5 nano AdTokens burned,
    // since the winner cannot withdraw a decimal amount of nano AdToken
    function claimExtraReward(uint _challengeID, string _domain) public {
        // uint256 totalTokens = voting.getTotalNumberOfTokensForWinningOption(_challengeID);
        uint256 reward = challengeMap[_challengeID].remainder / (MULTIPLIER);
        // reward = reward / totalTokens; // should this be here?
        challengeMap[_challengeID].remainder -= (reward * MULTIPLIER);
        if (voting.isPassed(_challengeID)) {
            // if challenger won, transfer tokens to challenger
            token.transfer(challengeMap[_challengeID].challenger, reward);
        } else {
            // if publisher won, give tokens to the domain's deposit
            listingMap[sha3(_domain)].currentDeposit += reward;
        }
    }

    // --------
    // HELPERS:
    // --------

    //return true if domain is whitelisted
    function isWhitelisted(string domain) constant public returns (bool whitelisted) {
        return listingMap[sha3(domain)].whitelisted;
    }

    //return true if apply(domain) was called for this domain
    function appExists(string domain) constant public returns (bool exists) {
        return listingMap[sha3(domain)].applicationExpiry > 0;
    }

    //return true if termDate has passed
    function isExpired(uint termDate) constant public returns (bool expired) {
        return termDate < block.timestamp;
    }

    //delete listing from whitelist and return tokens to owner
    function resetListing(string domain) internal {
        bytes32 domainHash = sha3(domain);
        Listing storage listing = listingMap[domainHash];

        require(token.transfer(listing.owner, listing.currentDeposit));

        delete listingMap[domainHash];
    }
}

pragma solidity ^0.4.11;

import "./StandardToken.sol";
import "./PLCRVoting.sol";
import "./Parameterizer.sol";

contract Registry {

    struct Listing {
        uint applicationExpiry; // expiration date of apply stage
        bool whitelisted;       // indicates registry status
        address owner;          // owner of Listing
        uint currentDeposit;    // number of tokens staked
        uint challengeID;       // identifier of canonical challenge
    }

    struct Challenge {
        uint rewardPool;        // pool of tokens distributed amongst winning voters
        address challenger;     // owner of Challenge
        bool resolved;          // indication of if challenge is resolved
        uint stake;             // number of tokens at risk for either party during challenge
        uint remainder;         // remainder tokens from flooring rewards to be claimed by the winner
    }

    // maps challengeIDs to associated challenge data
    mapping(uint => Challenge) challengeMap;
    // maps domainHashes to associated listing data
    mapping(bytes32 => Listing) public listingMap;
    // maps challengeIDs and address to token claim data
    mapping(uint => mapping(address => bool)) public tokenClaims;

    // Global Variables
    StandardToken public token;
    PLCRVoting public voting;
    Parameterizer public parameterizer;

    // Constants
    bytes32 constant private MINDEPOSIT_h = sha3("minDeposit");
    bytes32 constant private MINPARAMDEPOSIT_h = sha3("minParamDeposit");
    bytes32 constant private APPLYSTAGELEN_h = sha3("applyStageLen");
    bytes32 constant private COMMITPERIODLEN_h = sha3("commitPeriodLen");
    bytes32 constant private REVEALPERIODLEN_h = sha3("revealPeriodLen");
    bytes32 constant private DISPENSATIONPCT_h = sha3("dispensationPct");
    bytes32 constant private VOTEQUORUM_h = sha3("voteQuorum");
    uint256 constant private MULTIPLIER = 10 ** 18;  // used to help represent doubles as ints in token rewards

    // ------------
    // CONSTRUCTOR:
    // ------------

    function Registry(
        address _tokenAddr,
        address _paramAddr,
        address _votingAddr
    ) {
        token = StandardToken(_tokenAddr);
        parameterizer = Parameterizer(_paramAddr);
        voting = PLCRVoting(_tokenAddr);
    }

    // --------------------
    // PUBLISHER INTERFACE:
    // --------------------

    //Allow a user to start an application
    //take tokens from user and set apply stage end time
    function apply(string domain) external {
        require(!isWhitelisted(domain));
        require(!appExists(domain));

        //set owner
        Listing storage listing = listingMap[sha3(domain)];
        listing.owner = msg.sender;

        //transfer tokens
        uint minDeposit = parameterizer.params(MINDEPOSIT_h);
        require(token.transferFrom(listing.owner, this, minDeposit));

        //set apply stage end time
        listing.applicationExpiry = block.timestamp + parameterizer.params(APPLYSTAGELEN_h);
        listing.currentDeposit = minDeposit;
    }

    //Allow the owner of a domain in the listing to increase their deposit
    function deposit(string domain, uint amount) external {
        Listing storage listing = listingMap[sha3(domain)];

        require(listing.owner == msg.sender);
        require(token.transferFrom(msg.sender, this, amount));

        listing.currentDeposit += amount;
    }

    //Allow the owner of a domain in the listing to withdraw
    //tokens not locked in a challenge.
    //The publisher's domain remains whitelisted
    function withdraw(string domain, uint amount) external {
        Listing storage listing = listingMap[sha3(domain)];

        require(listing.owner == msg.sender);
        require(amount <= listing.currentDeposit);
        require(token.transfer(msg.sender, amount));

        listing.currentDeposit -= amount;
    }

    //Allow the owner of a domain to remove the domain from the whitelist
    //Return all tokens to the owner
    function exit(string domain) external {
        Listing storage listing = listingMap[sha3(domain)];

        require(isWhitelisted(domain));
        // cannot exit during ongoing challenge
        require(challengeMap[listing.challengeID].resolved);

        //remove domain & return tokens
        resetListing(domain);
    }

    // -----------------------
    // TOKEN HOLDER INTERFACE:
    // -----------------------

    //start a poll for a domain in the apply stage or already on the whitelist
    //tokens are taken from the challenger and the publisher's tokens are locked
    function challenge(string domain) external returns (uint challengeID) {
        bytes32 domainHash = sha3(domain);
        Listing storage listing = listingMap[domainHash];

        //to be challenged, domain must be in apply stage or already on the whitelist
        require(appExists(domain) || listing.whitelisted);
        require(challengeMap[listing.challengeID].resolved); // prevent multiple challenges

        if (listing.currentDeposit < parameterizer.params(MINDEPOSIT_h)) {
            // not enough tokens, publisher auto-delisted
            resetListing(domain);
            return 0;
        }
        //take tokens from challenger
        uint deposit = parameterizer.params(MINDEPOSIT_h);
        require(token.transferFrom(msg.sender, this, deposit));
        //start poll
        uint pollID = voting.startPoll(domain,
            parameterizer.params(VOTEQUORUM_h),
            parameterizer.params(COMMITPERIODLEN_h),
            parameterizer.params(REVEALPERIODLEN_h)
        );

        challengeMap[pollID] = Challenge({
            challenger: msg.sender,
            rewardPool: ((100 - parameterizer.params(DISPENSATIONPCT_h)) * deposit) / 100,
            stake: deposit,
            resolved: false,
            remainder: 0
        });

        listingMap[domainHash].challengeID = pollID;      // update listing to store most recent challenge
        listingMap[domainHash].currentDeposit -= deposit; // lock tokens for listing during challenge

        return pollID;
    }

    // whitelist domain if apply stage ended without a challenge
    function updateStatus(string domain) public {
        bytes32 domainHash = sha3(domain);
        uint challengeID = listingMap[domainHash].challengeID;
        require(!challengeMap[challengeID].resolved);  // require processed flag to be false

        // IF NO CHALLENGE AFTER APPLY STAGE
        if (challengeID == 0 && isExpired(listingMap[domainHash].applicationExpiry)) {
            listingMap[domainHash].whitelisted = true;
        } else {
        // PROCESS THE RESULT OF THE POLL

            // winner gets back their full staked deposit, and dispensationPct*loser's stake
            // (1-dispensationPct)*loser's stake = rewardPool
            uint stake = 2*challengeMap[challengeID].stake - challengeMap[challengeID].rewardPool;

            if (voting.isPassed(challengeID)) {
                listingMap[domainHash].whitelisted = true;
                listingMap[domainHash].currentDeposit += stake; // give stake back to applicant
            } else {
                resetListing(domain); // whitelisted = false
                require(token.transfer(challengeMap[challengeID].challenger, stake)); // give stake to challenger
            }

            challengeMap[challengeID].resolved = true; // set flag on challenge being processed
        }
    }

    // ----------------
    // TOKEN FUNCTIONS:
    // ----------------

    // called by voter to claim reward for each completed vote
    function claimReward(uint _challengeID, uint _salt) public {
        // ensure voter has not already claimed tokens
        require(tokenClaims[_challengeID][msg.sender] == false);
        uint reward = calculateTokens(_challengeID, _salt, msg.sender);
        // ensures a voter cannot claim tokens again
        token.transfer(msg.sender, reward);
        tokenClaims[_challengeID][msg.sender] = 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 _challengeID, uint _salt, address _voter) private returns(uint) {
        uint256 totalTokens = voting.getTotalNumberOfTokensForWinningOption(_challengeID);
        uint256 voterTokens = voting.getNumPassingTokens(_voter, _challengeID, _salt);

        uint256 rewardPool = challengeMap[_challengeID].rewardPool * MULTIPLIER;
        uint256 numerator = voterTokens * rewardPool;
        uint256 denominator = totalTokens * MULTIPLIER;
        uint256 remainder = numerator % denominator;

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

        return numerator / denominator;
    }

    // gives reminder tokens from poll to a designated claimer
    // the claimer is the winner of the challenge
    // for every poll there will be ~0.5 nano AdTokens burned,
    // since the winner cannot withdraw a decimal amount of nano AdToken
    function claimExtraReward(uint _challengeID, string _domain) public {
        // uint256 totalTokens = voting.getTotalNumberOfTokensForWinningOption(_challengeID);
        uint256 reward = challengeMap[_challengeID].remainder / (MULTIPLIER);
        // reward = reward / totalTokens; // should this be here?
        challengeMap[_challengeID].remainder -= (reward * MULTIPLIER);
        if (voting.isPassed(_challengeID)) {
            // if challenger won, transfer tokens to challenger
            token.transfer(challengeMap[_challengeID].challenger, reward);
        } else {
            // if publisher won, give tokens to the domain's deposit
            listingMap[sha3(_domain)].currentDeposit += reward;
        }
    }

    // --------
    // HELPERS:
    // --------

    //return true if domain is whitelisted
    function isWhitelisted(string domain) constant public returns (bool whitelisted) {
        return listingMap[sha3(domain)].whitelisted;
    }

    //return true if apply(domain) was called for this domain
    function appExists(string domain) constant public returns (bool exists) {
        return listingMap[sha3(domain)].applicationExpiry > 0;
    }

    //return true if termDate has passed
    function isExpired(uint termDate) constant public returns (bool expired) {
        return termDate < block.timestamp;
    }

    //delete listing from whitelist and return tokens to owner
    function resetListing(string domain) internal {
        bytes32 domainHash = sha3(domain);
        Listing storage listing = listingMap[domainHash];

        require(token.transfer(listing.owner, listing.currentDeposit));

        delete listingMap[domainHash];
    }
}