Flip signs of pieces again, now in hexcode

now:
white > 0
black < 0

/**
 * 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 {
    bytes constant defaultState = '\x04\x06\x05\x03\x02\x05\x06\x04\x08\x08\x08\x0c\x08\x08\x08\x08\x07\x07\x07\x07\x07\x07\x07\x07\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x09\x09\x09\x09\x09\x09\x09\x09\x08\x08\x08\x08\x08\x08\x08\x08\x0c\x0a\x0b\x0d\x0e\x0b\x0a\x0c\x08\x08\x08\x7c\x08\x08\x08\x08';

    struct Game {
        address player1;
        address player2;
        string player1Alias;
        string player2Alias;
        address nextPlayer;
        address playerWhite; // Player that is white in this game
        address winner;
        int8[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;

    /* Flags needed for validation
     * Usage e.g. Flags(Flag.FLAG_NAME)
     * Directions(Direction.UP)
     */
    enum Player { WHITE, BLACK }
    enum Direction { UP, UP_RIGHT, RIGHT, DOWN_RIGHT, DOWN, DOWN_LEFT, LEFT, UP_LEFT }
    bytes constant c_Directions = "\x30\x31\x41\x51\x50\x4f\x3f\x2f";
    enum Piece { WHITE_KING, WHITE_QUEEN, WHITE_ROOK, WHITE_BISHOP, WHITE_KNIGHT, WHITE_PAWN, EMPTY, BLACK_KING, BLACK_QUEEN, BLACK_ROOK, BLACK_BISHOP, BLACK_KNIGHT, BLACK_PAWN }
    bytes constant c_Pieces = "\x46\x45\x44\x43\x42\x41\x40\x3a\x3b\x3c\x3d\x3e\x3f";
    enum Flag { WHITE_KING_POS, BLACK_KING_POS, CURRENT_PLAYER, WHITE_LEFT_CASTLING, WHITE_RIGHT_CASTLING, BLACK_LEFT_CASTLING, BLACK_RIGHT_CASTLING, BLACK_EN_PASSANT, WHITE_EN_PASSANT}
    bytes constant c_Flags = "\x7b\x0b\x38\x4e\x4f\x3e\x3f\x3d\x4d\x3c\x4c";
    function Flags(Flag i) internal returns (uint) {
       return uint(c_Flags[uint(i)]);
    }
    function Pieces(Piece i) internal returns (int8) {
        return -64 + int8(c_Pieces[uint(i)]);
    }
    function Directions(Direction i) internal returns (int8) {
        return -64 + int8(c_Directions[uint(i)]);
    }
    function Players(Player p) internal returns (int8) {
        if (p == Player.WHITE) {
            return 1;
        }
        return -1;
    }

    bytes constant knightMoves = '\x1f\x21\x2e\x32\x4e\x52\x5f\x61';

    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, int8[128] state);
    event Move(bytes32 indexed gameId, address indexed player, uint256 fromIndex, uint256 toIndex);
    event GameEnded(bytes32 indexed gameId, address indexed winner);

    /**
     * Convenience function to set a flag
     * Usage: setFlag(gameId, Flag.BLACK_KING_POS, 4);
     */
    function setFlag(bytes32 gameId, Flag flag, int value) internal {
        games[gameId].state[Flags(flag)] = int8(value);
    }

    /**
     * Convenience function to set a flag
     * Usage: getFlag(gameId, Flag.BLACK_KING_POS);
     */
    function getFlag(bytes32 gameId, Flag flag) internal returns (int8) {
        return games[gameId].state[Flags(flag)];
    }

    /**
     * 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
        for (uint i = 0; i < 128; i++) {
            // Read defaultState bytes string, which is offset by 8 to be > 0
            games[gameId].state[i] = int8(defaultState[i]) - 8;
        }

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

        int8 currentPlayerColor;
        if (msg.sender == games[gameId].playerWhite) {
            currentPlayerColor = Players(Player.WHITE);
        } else {
            currentPlayerColor = Players(Player.BLACK);
        }

        int8 fromFigure = games[gameId].state[fromIndex];
        int8 toFigure = games[gameId].state[toIndex];

        // Simple sanity checks
        sanityCheck(fromIndex, toIndex, fromFigure, toFigure, currentPlayerColor);

        // Check if move is technically possible
        validateMove(gameId, fromIndex, toIndex, fromFigure, toFigure, currentPlayerColor);

        // For all pieces except knight, check if way is free
        // In case of king, it will check that he is not in check on any of the fields
        if (abs(fromFigure) != uint(Pieces(Piece.BLACK_KNIGHT))) {
            bool checkForCheck = abs(fromFigure) == uint(Pieces(Piece.BLACK_KING));
            checkWayFree(gameId, fromIndex, toIndex, currentPlayerColor, checkForCheck);
        }

        //makeTemporaryMove
        makeTemporaryMove(gameId, fromIndex, toIndex, fromFigure, toFigure);

        //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);
        GameStateChanged(gameId, games[gameId].state);
    }

    function sanityCheck(uint256 fromIndex, uint256 toIndex, int8 fromFigure, int8 toFigure, int8 currentPlayerColor) {
        // check if the move actually fits the data structure
        if ((toIndex & 0x88) != 0) {
            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 (currentPlayerColor * fromFigure > 0) {
            throw;
        }
    }

    /**
     * Validates if a move is technically (not legally) possible,
     * i.e. if piece is capable to move this way
     */
    function validateMove(bytes32 gameId, uint256 fromIndex, uint256 toIndex, int8 fromFigure, int8 toFigure, int8 movingPlayerColor) {
        int8 direction = getDirection(fromIndex, toIndex);
        bool isDiagonal = !(abs(direction) == 16 || abs(direction) == 1);

        // Kings
        if (abs(fromFigure) == uint(Pieces(Piece.BLACK_KING))) {
            // Normal move
            if (int(fromIndex) + direction == int(toIndex)) {
                return;
            }
            // Castling
            if (checkForCheck(gameId, fromIndex, movingPlayerColor)) {
                // Cannot move if already in check
                throw;
            }
            if (fromFigure == Pieces(Piece.BLACK_KING)) {
                if (4 == fromIndex && toFigure == 0) {
                    if (toIndex == 1 && getFlag(gameId, Flag.BLACK_LEFT_CASTLING) >= 0) {
                        return;
                    }
                    if (toIndex == 6 && getFlag(gameId, Flag.BLACK_RIGHT_CASTLING) >= 0) {
                        return;
                    }
                }
            }
            if (fromFigure == Pieces(Piece.WHITE_KING)) {
                if (116 == fromIndex && toFigure == 0) {
                    if (toIndex == 113 && getFlag(gameId, Flag.WHITE_LEFT_CASTLING) >= 0) {
                        return;
                    }
                    if (toIndex == 118 && getFlag(gameId, Flag.WHITE_RIGHT_CASTLING) >= 0) {
                        return;
                    }
                }
            }

            throw;
        }

        // Bishops, Queens, Rooks
        if (abs(fromFigure) == uint(Pieces(Piece.BLACK_BISHOP)) ||
            abs(fromFigure) == uint(Pieces(Piece.BLACK_QUEEN)) ||
            abs(fromFigure) == uint(Pieces(Piece.BLACK_ROOK))) {

            if (!isDiagonal && abs(fromFigure) == uint(Pieces(Piece.BLACK_BISHOP)) ||
                isDiagonal && abs(fromFigure) == uint(Pieces(Piece.BLACK_ROOK))) {
                return;
            }

            // Traverse all fields in direction
            int temp = int(fromIndex);
            while (temp & 0x88 != 0) {
                if (uint(temp) == toIndex) {
                    return;
                }
                temp += direction;
            }

            throw;
        }

        // Pawns
        if (abs(fromFigure) == uint(Pieces(Piece.BLACK_PAWN))) {
            // Black can only move in positive, White negative direction
            if (fromFigure == Pieces(Piece.BLACK_PAWN) && direction < 0 ||
                fromFigure == Pieces(Piece.WHITE_PAWN) && direction > 0) {
                throw;
            }
            // Forward move
            if (!isDiagonal) {
                if (abs(direction) < 2) {
                    throw;
                }
                // simple move
                if (int(fromIndex) + direction == int(toIndex)) {
                    return;
                }
                // double move
                if (int(fromIndex) + direction + direction == int(toIndex)) {
                    // Can only do double move starting form specific ranks
                    int rank = int(fromIndex/16);
                    if (1 == rank || 6 == rank) {
                        return;
                    }
                }
                throw;
            }
            // diagonal move
            if (int(fromIndex) + direction == int(toIndex)) {
                // if empty, the en passant flag needs to be set
                if (toFigure * fromFigure == 0) {
                    if (fromFigure == Pieces(Piece.BLACK_PAWN) &&
                        getFlag(gameId, Flag.WHITE_EN_PASSANT) == int(toIndex) ||
                        fromFigure == Pieces(Piece.WHITE_PAWN) &&
                        getFlag(gameId, Flag.BLACK_EN_PASSANT) == int(toIndex)) {
                        return;
                    }
                }
                // If not empty
                return;
            }

            throw;
        }

        // Knights
        if (abs(fromFigure) == uint(Pieces(Piece.BLACK_KNIGHT))) {
            for (uint i; i < 8; i++) {
                if (int(fromIndex) + int(knightMoves[i]) - 64 == int(toIndex)) {
                    return;
                }
            }
            throw;
        }

        throw;
    }

    /**
     * Checks if the way between fromIndex and toIndex is unblocked
     */
    function checkWayFree(bytes32 gameId, uint256 fromIndex, uint256 toIndex, int8 currentPlayerColor, bool shouldCheckForCheck) {
        int8 direction = getDirection(fromIndex, toIndex);
        int currentIndex = int(fromIndex) + direction;

        // as long as we do not reach the desired position
        while (int(toIndex) != currentIndex) {
            // we reached the end of the field
            if (currentIndex & 0x88 != 0) {
                throw;
            }
            // the path is blocked
            if (games[gameId].state[uint(currentIndex)] != 0) {
                throw;
            }
            // Check for check in case of kind
            if (shouldCheckForCheck && checkForCheck(gameId, uint(currentIndex), currentPlayerColor)) {
                throw;
            }
            currentIndex = currentIndex + direction;
        }
        return;
    }

    function checkForCheck(bytes32 gameId, uint256 kingAtIndex, int8 currentPlayerColor) returns (bool) {
        // TODO
        return true;
    }

    function getDirection(uint256 fromIndex, uint256 toIndex) returns (int8) {
        // check if the figure is moved up or left of its origin
        bool 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)
        bool isSameHorizontal = (abs(int256(fromIndex) - int256(toIndex)) < (8));

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

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

        /*Check directions*/
        if (isAboveLeft){
            if (isSameVertical){
                return Directions(Direction.UP);
            }
            if (isSameHorizontal){
                return Directions(Direction.LEFT);
            }
            if (isLeftSide){
                return Directions(Direction.UP_LEFT);
            } else {
                return Directions(Direction.UP_RIGHT);
            }
        } else {
            if (isSameVertical){
                return Directions(Direction.DOWN);
            }
            if (isSameHorizontal){
                return Directions(Direction.RIGHT);
            }
            if (isLeftSide){
                return Directions(Direction.DOWN_LEFT);
            } else{
                return Directions(Direction.DOWN_RIGHT);
            }
        }
    }

    function makeTemporaryMove(bytes32 gameId, uint256 fromIndex, uint256 toIndex, int8 fromFigure, int8 toFigure){
        setFlag(gameId, Flag.WHITE_EN_PASSANT, -1);
        setFlag(gameId, Flag.WHITE_EN_PASSANT, -1);

        // <---- Special Moves ---->

        // castling
        // it already passed valid we just need to move the rook

        // Black
        if (fromFigure == Pieces(Piece.BLACK_KING)){
            setFlag(gameId, Flag.BLACK_KING_POS, int8(toIndex));
            if ((fromIndex == 4)&&(toIndex == 1)){
                games[gameId].state[0] = 0;
                games[gameId].state[2] = Pieces(Piece.BLACK_ROOK);
            }
            if ((fromIndex == 4)&&(toIndex == 6)){
                games[gameId].state[7] = 0;
                games[gameId].state[5] = Pieces(Piece.BLACK_ROOK);
            }

        }
        // White
        if (fromFigure == Pieces(Piece.WHITE_KING)){
            setFlag(gameId, Flag.WHITE_KING_POS, int8(toIndex));
            if ((fromIndex == 116)&&(toIndex == 112)){
                games[gameId].state[112] = 0;
                games[gameId].state[114] = Pieces(Piece.BLACK_ROOK);
            }
            if ((fromIndex == 116)&&(toIndex == 118)){
                games[gameId].state[118] = 0;
                games[gameId].state[117] = Pieces(Piece.BLACK_ROOK);
            }

        }

        //Remove Castling Flag

        // Black
        if (fromFigure == Pieces(Piece.BLACK_KING)){
            if (fromIndex == 4){
                setFlag(gameId, Flag.BLACK_LEFT_CASTLING, -1);
                setFlag(gameId, Flag.BLACK_RIGHT_CASTLING, -1);
            }
        }
        if (fromFigure == Pieces(Piece.BLACK_ROOK)){
            if (fromIndex == 0){
                setFlag(gameId, Flag.BLACK_LEFT_CASTLING, -1);
            }
            if (fromIndex == 7){
                setFlag(gameId, Flag.BLACK_RIGHT_CASTLING, -1);
            }
        }

        // White
        if (fromFigure == Pieces(Piece.WHITE_KING)){
            if (fromIndex == 116){
                setFlag(gameId, Flag.WHITE_LEFT_CASTLING, -1);
                setFlag(gameId, Flag.WHITE_RIGHT_CASTLING, -1);
            }
        }
        if (fromFigure == Pieces(Piece.WHITE_ROOK)){
            if (fromIndex == 112){
                setFlag(gameId, Flag.WHITE_LEFT_CASTLING, -1);
            }
            if (fromIndex == 119){
                setFlag(gameId, Flag.WHITE_RIGHT_CASTLING, -1);
            }
        }
        // En Passant

        // Double Step

        // <---- Normal Moves --->

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

    }

    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) returns (uint256){
        if (value>=0) return uint256(value);
        else return uint256(-1*value);
    }

    function is_diagonal(Direction dir) internal returns (bool){
      if(abs(Directions(dir)) == 16)
        return false;
      if(abs(Directions(dir)) == 1)
        return false;
      return true;
    }

    /* 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 {
    bytes constant defaultState = '\x04\x06\x05\x03\x02\x05\x06\x04\x08\x08\x08\x0c\x08\x08\x08\x08\x07\x07\x07\x07\x07\x07\x07\x07\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x09\x09\x09\x09\x09\x09\x09\x09\x08\x08\x08\x08\x08\x08\x08\x08\x0c\x0a\x0b\x0d\x0e\x0b\x0a\x0c\x08\x08\x08\x7c\x08\x08\x08\x08';

    struct Game {
        address player1;
        address player2;
        string player1Alias;
        string player2Alias;
        address nextPlayer;
        address playerWhite; // Player that is white in this game
        address winner;
        int8[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;

    /* Flags needed for validation
     * Usage e.g. Flags(Flag.FLAG_NAME)
     * Directions(Direction.UP)
     */
    enum Player { WHITE, BLACK }
    enum Direction { UP, UP_RIGHT, RIGHT, DOWN_RIGHT, DOWN, DOWN_LEFT, LEFT, UP_LEFT }
    bytes constant c_Directions = "\x30\x31\x41\x51\x50\x4f\x3f\x2f";
    enum Piece { WHITE_KING, WHITE_QUEEN, WHITE_ROOK, WHITE_BISHOP, WHITE_KNIGHT, WHITE_PAWN, EMPTY, BLACK_KING, BLACK_QUEEN, BLACK_ROOK, BLACK_BISHOP, BLACK_KNIGHT, BLACK_PAWN }
    bytes constant c_Pieces = "\x3a\x3b\x3c\x3d\x3e\x3f\x40\x46\x45\x44\x43\x42\x41";
    enum Flag { WHITE_KING_POS, BLACK_KING_POS, CURRENT_PLAYER, WHITE_LEFT_CASTLING, WHITE_RIGHT_CASTLING, BLACK_LEFT_CASTLING, BLACK_RIGHT_CASTLING, BLACK_EN_PASSANT, WHITE_EN_PASSANT}
    bytes constant c_Flags = "\x7b\x0b\x38\x4e\x4f\x3e\x3f\x3d\x4d\x3c\x4c";
    function Flags(Flag i) internal returns (uint) {
       return uint(c_Flags[uint(i)]);
    }
    function Pieces(Piece i) internal returns (int8) {
        return -64 + int8(c_Pieces[uint(i)]);
    }
    function Directions(Direction i) internal returns (int8) {
        return -64 + int8(c_Directions[uint(i)]);
    }
    function Players(Player p) internal returns (int8) {
        if (p == Player.WHITE) {
            return 1;
        }
        return -1;
    }

    bytes constant knightMoves = '\x1f\x21\x2e\x32\x4e\x52\x5f\x61';

    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, int8[128] state);
    event Move(bytes32 indexed gameId, address indexed player, uint256 fromIndex, uint256 toIndex);
    event GameEnded(bytes32 indexed gameId, address indexed winner);

    /**
     * Convenience function to set a flag
     * Usage: setFlag(gameId, Flag.BLACK_KING_POS, 4);
     */
    function setFlag(bytes32 gameId, Flag flag, int value) internal {
        games[gameId].state[Flags(flag)] = int8(value);
    }

    /**
     * Convenience function to set a flag
     * Usage: getFlag(gameId, Flag.BLACK_KING_POS);
     */
    function getFlag(bytes32 gameId, Flag flag) internal returns (int8) {
        return games[gameId].state[Flags(flag)];
    }

    /**
     * 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
        for (uint i = 0; i < 128; i++) {
            // Read defaultState bytes string, which is offset by 8 to be > 0
            games[gameId].state[i] = int8(defaultState[i]) - 8;
        }

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

        int8 currentPlayerColor;
        if (msg.sender == games[gameId].playerWhite) {
            currentPlayerColor = Players(Player.WHITE);
        } else {
            currentPlayerColor = Players(Player.BLACK);
        }

        int8 fromFigure = games[gameId].state[fromIndex];
        int8 toFigure = games[gameId].state[toIndex];

        // Simple sanity checks
        sanityCheck(fromIndex, toIndex, fromFigure, toFigure, currentPlayerColor);

        // Check if move is technically possible
        validateMove(gameId, fromIndex, toIndex, fromFigure, toFigure, currentPlayerColor);

        // For all pieces except knight, check if way is free
        // In case of king, it will check that he is not in check on any of the fields
        if (abs(fromFigure) != uint(Pieces(Piece.BLACK_KNIGHT))) {
            bool checkForCheck = abs(fromFigure) == uint(Pieces(Piece.BLACK_KING));
            checkWayFree(gameId, fromIndex, toIndex, currentPlayerColor, checkForCheck);
        }

        //makeTemporaryMove
        makeTemporaryMove(gameId, fromIndex, toIndex, fromFigure, toFigure);

        //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);
        GameStateChanged(gameId, games[gameId].state);
    }

    function sanityCheck(uint256 fromIndex, uint256 toIndex, int8 fromFigure, int8 toFigure, int8 currentPlayerColor) {
        // check if the move actually fits the data structure
        if ((toIndex & 0x88) != 0) {
            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 (currentPlayerColor * fromFigure > 0) {
            throw;
        }
    }

    /**
     * Validates if a move is technically (not legally) possible,
     * i.e. if piece is capable to move this way
     */
    function validateMove(bytes32 gameId, uint256 fromIndex, uint256 toIndex, int8 fromFigure, int8 toFigure, int8 movingPlayerColor) {
        int8 direction = getDirection(fromIndex, toIndex);
        bool isDiagonal = !(abs(direction) == 16 || abs(direction) == 1);

        // Kings
        if (abs(fromFigure) == uint(Pieces(Piece.BLACK_KING))) {
            // Normal move
            if (int(fromIndex) + direction == int(toIndex)) {
                return;
            }
            // Castling
            if (checkForCheck(gameId, fromIndex, movingPlayerColor)) {
                // Cannot move if already in check
                throw;
            }
            if (fromFigure == Pieces(Piece.BLACK_KING)) {
                if (4 == fromIndex && toFigure == 0) {
                    if (toIndex == 1 && getFlag(gameId, Flag.BLACK_LEFT_CASTLING) >= 0) {
                        return;
                    }
                    if (toIndex == 6 && getFlag(gameId, Flag.BLACK_RIGHT_CASTLING) >= 0) {
                        return;
                    }
                }
            }
            if (fromFigure == Pieces(Piece.WHITE_KING)) {
                if (116 == fromIndex && toFigure == 0) {
                    if (toIndex == 113 && getFlag(gameId, Flag.WHITE_LEFT_CASTLING) >= 0) {
                        return;
                    }
                    if (toIndex == 118 && getFlag(gameId, Flag.WHITE_RIGHT_CASTLING) >= 0) {
                        return;
                    }
                }
            }

            throw;
        }

        // Bishops, Queens, Rooks
        if (abs(fromFigure) == uint(Pieces(Piece.BLACK_BISHOP)) ||
            abs(fromFigure) == uint(Pieces(Piece.BLACK_QUEEN)) ||
            abs(fromFigure) == uint(Pieces(Piece.BLACK_ROOK))) {

            if (!isDiagonal && abs(fromFigure) == uint(Pieces(Piece.BLACK_BISHOP)) ||
                isDiagonal && abs(fromFigure) == uint(Pieces(Piece.BLACK_ROOK))) {
                return;
            }

            // Traverse all fields in direction
            int temp = int(fromIndex);
            while (temp & 0x88 != 0) {
                if (uint(temp) == toIndex) {
                    return;
                }
                temp += direction;
            }

            throw;
        }

        // Pawns
        if (abs(fromFigure) == uint(Pieces(Piece.BLACK_PAWN))) {
            // Black can only move in positive, White negative direction
            if (fromFigure == Pieces(Piece.BLACK_PAWN) && direction < 0 ||
                fromFigure == Pieces(Piece.WHITE_PAWN) && direction > 0) {
                throw;
            }
            // Forward move
            if (!isDiagonal) {
                if (abs(direction) < 2) {
                    throw;
                }
                // simple move
                if (int(fromIndex) + direction == int(toIndex)) {
                    return;
                }
                // double move
                if (int(fromIndex) + direction + direction == int(toIndex)) {
                    // Can only do double move starting form specific ranks
                    int rank = int(fromIndex/16);
                    if (1 == rank || 6 == rank) {
                        return;
                    }
                }
                throw;
            }
            // diagonal move
            if (int(fromIndex) + direction == int(toIndex)) {
                // if empty, the en passant flag needs to be set
                if (toFigure * fromFigure == 0) {
                    if (fromFigure == Pieces(Piece.BLACK_PAWN) &&
                        getFlag(gameId, Flag.WHITE_EN_PASSANT) == int(toIndex) ||
                        fromFigure == Pieces(Piece.WHITE_PAWN) &&
                        getFlag(gameId, Flag.BLACK_EN_PASSANT) == int(toIndex)) {
                        return;
                    }
                }
                // If not empty
                return;
            }

            throw;
        }

        // Knights
        if (abs(fromFigure) == uint(Pieces(Piece.BLACK_KNIGHT))) {
            for (uint i; i < 8; i++) {
                if (int(fromIndex) + int(knightMoves[i]) - 64 == int(toIndex)) {
                    return;
                }
            }
            throw;
        }

        throw;
    }

    /**
     * Checks if the way between fromIndex and toIndex is unblocked
     */
    function checkWayFree(bytes32 gameId, uint256 fromIndex, uint256 toIndex, int8 currentPlayerColor, bool shouldCheckForCheck) {
        int8 direction = getDirection(fromIndex, toIndex);
        int currentIndex = int(fromIndex) + direction;

        // as long as we do not reach the desired position
        while (int(toIndex) != currentIndex) {
            // we reached the end of the field
            if (currentIndex & 0x88 != 0) {
                throw;
            }
            // the path is blocked
            if (games[gameId].state[uint(currentIndex)] != 0) {
                throw;
            }
            // Check for check in case of kind
            if (shouldCheckForCheck && checkForCheck(gameId, uint(currentIndex), currentPlayerColor)) {
                throw;
            }
            currentIndex = currentIndex + direction;
        }
        return;
    }

    function checkForCheck(bytes32 gameId, uint256 kingAtIndex, int8 currentPlayerColor) returns (bool) {
        // TODO
        return true;
    }

    function getDirection(uint256 fromIndex, uint256 toIndex) returns (int8) {
        // check if the figure is moved up or left of its origin
        bool 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)
        bool isSameHorizontal = (abs(int256(fromIndex) - int256(toIndex)) < (8));

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

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

        /*Check directions*/
        if (isAboveLeft){
            if (isSameVertical){
                return Directions(Direction.UP);
            }
            if (isSameHorizontal){
                return Directions(Direction.LEFT);
            }
            if (isLeftSide){
                return Directions(Direction.UP_LEFT);
            } else {
                return Directions(Direction.UP_RIGHT);
            }
        } else {
            if (isSameVertical){
                return Directions(Direction.DOWN);
            }
            if (isSameHorizontal){
                return Directions(Direction.RIGHT);
            }
            if (isLeftSide){
                return Directions(Direction.DOWN_LEFT);
            } else{
                return Directions(Direction.DOWN_RIGHT);
            }
        }
    }

    function makeTemporaryMove(bytes32 gameId, uint256 fromIndex, uint256 toIndex, int8 fromFigure, int8 toFigure){
        setFlag(gameId, Flag.WHITE_EN_PASSANT, -1);
        setFlag(gameId, Flag.WHITE_EN_PASSANT, -1);

        // <---- Special Moves ---->

        // castling
        // it already passed valid we just need to move the rook

        // Black
        if (fromFigure == Pieces(Piece.BLACK_KING)){
            setFlag(gameId, Flag.BLACK_KING_POS, int8(toIndex));
            if ((fromIndex == 4)&&(toIndex == 1)){
                games[gameId].state[0] = 0;
                games[gameId].state[2] = Pieces(Piece.BLACK_ROOK);
            }
            if ((fromIndex == 4)&&(toIndex == 6)){
                games[gameId].state[7] = 0;
                games[gameId].state[5] = Pieces(Piece.BLACK_ROOK);
            }

        }
        // White
        if (fromFigure == Pieces(Piece.WHITE_KING)){
            setFlag(gameId, Flag.WHITE_KING_POS, int8(toIndex));
            if ((fromIndex == 116)&&(toIndex == 112)){
                games[gameId].state[112] = 0;
                games[gameId].state[114] = Pieces(Piece.BLACK_ROOK);
            }
            if ((fromIndex == 116)&&(toIndex == 118)){
                games[gameId].state[118] = 0;
                games[gameId].state[117] = Pieces(Piece.BLACK_ROOK);
            }

        }

        //Remove Castling Flag

        // Black
        if (fromFigure == Pieces(Piece.BLACK_KING)){
            if (fromIndex == 4){
                setFlag(gameId, Flag.BLACK_LEFT_CASTLING, -1);
                setFlag(gameId, Flag.BLACK_RIGHT_CASTLING, -1);
            }
        }
        if (fromFigure == Pieces(Piece.BLACK_ROOK)){
            if (fromIndex == 0){
                setFlag(gameId, Flag.BLACK_LEFT_CASTLING, -1);
            }
            if (fromIndex == 7){
                setFlag(gameId, Flag.BLACK_RIGHT_CASTLING, -1);
            }
        }

        // White
        if (fromFigure == Pieces(Piece.WHITE_KING)){
            if (fromIndex == 116){
                setFlag(gameId, Flag.WHITE_LEFT_CASTLING, -1);
                setFlag(gameId, Flag.WHITE_RIGHT_CASTLING, -1);
            }
        }
        if (fromFigure == Pieces(Piece.WHITE_ROOK)){
            if (fromIndex == 112){
                setFlag(gameId, Flag.WHITE_LEFT_CASTLING, -1);
            }
            if (fromIndex == 119){
                setFlag(gameId, Flag.WHITE_RIGHT_CASTLING, -1);
            }
        }
        // En Passant

        // Double Step

        // <---- Normal Moves --->

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

    }

    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) returns (uint256){
        if (value>=0) return uint256(value);
        else return uint256(-1*value);
    }

    function is_diagonal(Direction dir) internal returns (bool){
      if(abs(Directions(dir)) == 16)
        return false;
      if(abs(Directions(dir)) == 1)
        return false;
      return true;
    }

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


Replace `if (...) revert()` with `require(...)` (#2376)

// SPDX-License-Identifier: MIT

pragma solidity ^0.6.0;

/**
 * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
 *
 * These functions can be used to verify that a message was signed by the holder
 * of the private keys of a given address.
 */
library ECDSA {
    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature`. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {toEthSignedMessageHash} on it.
     */
    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
        // Check the signature length
        if (signature.length != 65) {
            revert("ECDSA: invalid signature length");
        }

        // Divide the signature in r, s and v variables
        bytes32 r;
        bytes32 s;
        uint8 v;

        // ecrecover takes the signature parameters, and the only way to get them
        // currently is to use assembly.
        // solhint-disable-next-line no-inline-assembly
        assembly {
            r := mload(add(signature, 0x20))
            s := mload(add(signature, 0x40))
            v := byte(0, mload(add(signature, 0x60)))
        }

        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
        // the valid range for s in (281): 0 < s < secp256k1n ÷ 2 + 1, and for v in (282): v ∈ {27, 28}. Most
        // signatures from current libraries generate a unique signature with an s-value in the lower half order.
        //
        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
        // these malleable signatures as well.
        require(uint256(s) <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0, "ECDSA: invalid signature 's' value");
        require(v == 27 || v == 28, "ECDSA: invalid signature 'v' value");

        // If the signature is valid (and not malleable), return the signer address
        address signer = ecrecover(hash, v, r, s);
        require(signer != address(0), "ECDSA: invalid signature");

        return signer;
    }

    /**
     * @dev Returns an Ethereum Signed Message, created from a `hash`. This
     * replicates the behavior of the
     * https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign[`eth_sign`]
     * JSON-RPC method.
     *
     * See {recover}.
     */
    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
        // 32 is the length in bytes of hash,
        // enforced by the type signature above
        return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
    }
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.6.0;

/**
 * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
 *
 * These functions can be used to verify that a message was signed by the holder
 * of the private keys of a given address.
 */
library ECDSA {
    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature`. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {toEthSignedMessageHash} on it.
     */
    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
        // Check the signature length
        if (signature.length != 65) {
            revert("ECDSA: invalid signature length");
        }

        // Divide the signature in r, s and v variables
        bytes32 r;
        bytes32 s;
        uint8 v;

        // ecrecover takes the signature parameters, and the only way to get them
        // currently is to use assembly.
        // solhint-disable-next-line no-inline-assembly
        assembly {
            r := mload(add(signature, 0x20))
            s := mload(add(signature, 0x40))
            v := byte(0, mload(add(signature, 0x60)))
        }

        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
        // the valid range for s in (281): 0 < s < secp256k1n ÷ 2 + 1, and for v in (282): v ∈ {27, 28}. Most
        // signatures from current libraries generate a unique signature with an s-value in the lower half order.
        //
        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
        // these malleable signatures as well.
        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
            revert("ECDSA: invalid signature 's' value");
        }

        if (v != 27 && v != 28) {
            revert("ECDSA: invalid signature 'v' value");
        }

        // If the signature is valid (and not malleable), return the signer address
        address signer = ecrecover(hash, v, r, s);
        require(signer != address(0), "ECDSA: invalid signature");

        return signer;
    }

    /**
     * @dev Returns an Ethereum Signed Message, created from a `hash`. This
     * replicates the behavior of the
     * https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign[`eth_sign`]
     * JSON-RPC method.
     *
     * See {recover}.
     */
    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
        // 32 is the length in bytes of hash,
        // enforced by the type signature above
        return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
    }
}


Add events

Add events

pragma solidity ^0.4.4;

contract PunchClock {
    // the owner of the contract
    address owner;

    // The data structure to store the time in and out of a person
    struct PunchCard {
        uint64 timeIn; // time the person gets in, unix timestamp
        uint64 timeOut; // time the person gets out, unix timestamp
    }

    // The list of all admins. The reason for having these two mapping is that
    // it's not possible to iterate through the list of keys in a mapping,
    // so the workaround is to have two mapping, with the second mapping is basically
    // just a map by index so that we can get all the keys. Similarly, it's not
    // possible to iterate through a mapping, so the workaround is to keep track
    // of the size manually.
    mapping(address => bool) admins;
    mapping(uint64 => address) adminsByIndex;
    uint64 totalNumberOfAdmins;

    // The list of all members.
    mapping(address => bool) members;
    mapping(uint64 => address) membersByIndex;
    uint64 totalNumberOfMembers;

    // All punch cards of all members
    mapping(address => PunchCard[]) punchClock;

    // events
    event AdminAdded(address indexed admin);
    event MemberAdded(address indexed member);
    event AdminRemoved(address indexed admin);
    event MemberRemoved(address indexed member);
    event PunchedIn(address indexed member, uint64 inTime);
    event PunchedOut(address indexed member, uint64 outTime);
    event OwnerChanged(address indexed oldOwner, address indexed newOwner);

    // Constructor, create a new punch clock and assign the creator as the owner of the punch clock
    function PunchClock() {
        owner = msg.sender;
        admins[owner] = true;
        adminsByIndex[0] = owner;
        totalNumberOfAdmins = 1;
        members[owner] = true;
        membersByIndex[0] = owner;
        totalNumberOfMembers = 1;
    }

    modifier onlyOwner() {
        if (msg.sender != owner) throw;
        _;
    }
    modifier onlyAdmins() {
        if (admins[msg.sender] == false) throw;
        _;
    }
    modifier onlyMembers() {
        if (members[msg.sender] == false) throw;
        _;
    }

    // Add a member to the contract if the member does not already exist
    function addMemberInternal(address member) internal {
        if (members[member] == false) {
            var newMemberIndex = totalNumberOfMembers;
            members[member] = true;
            membersByIndex[newMemberIndex] = member;
            totalNumberOfMembers++;
        }
    }
    // Add a new admin. Only the owner can perform this task.
    function addAdmin(address admin) onlyOwner {
        if (admins[admin] == false) {
            var indexOfNewAdmin = totalNumberOfAdmins;
            admins[admin] = true;
            adminsByIndex[indexOfNewAdmin] = admin;
            totalNumberOfAdmins++;

            addMemberInternal(admin);
            AdminAdded(admin);
        }
    }

    // Add a new member to the list of member. Only admins can perform this task
    function addMember(address member) onlyAdmins {
        addMemberInternal(member);
        MemberAdded(member);
    }

    // Return all punch cards of a member
    function getPunchCardsInternal(address member) constant internal returns(uint64[2][]) {
        var allCards = punchClock[member];
        uint64[2][] memory tmp = new uint64[2][](allCards.length);
        for (uint64 i = 0; i < allCards.length; i++) {
            tmp[i] = [allCards[i].timeIn, allCards[i].timeOut];
        }
        return tmp;
    }

    // Return all punch cards of the requestor. Only member can perform this task
    function getMyPunchCards() onlyMembers constant returns(uint64[2][] punchCards) {
        return getPunchCardsInternal(msg.sender);
    }

    // Return all punch cards of a member. Only admin can perform this task
    function getPunchCardsOf(address member) onlyAdmins constant returns(uint64[2][] punchcards) {
        return getPunchCardsInternal(member);
    }

    // Return all members in the contract. Only admins can perform this task.
    function getAllMembers() onlyAdmins constant returns(address[]) {
        address[] memory allMembers = new address[](totalNumberOfMembers);
        for (uint64 i = 0; i < totalNumberOfMembers; i++) {
            allMembers[i] = membersByIndex[i];
        }
        return allMembers;
    }

    // Return all admins in the contract. Only owner can perform this task.
    function getAllAdmins() onlyOwner constant returns(address[]) {
        address[] memory allAdmins = new address[](totalNumberOfAdmins);
        for (uint64 i = 0; i < totalNumberOfAdmins; i++) {
            allAdmins[i] = adminsByIndex[i];
        }
        return allAdmins;
    }

    // Return the owner of the contract. Anyone can perform this task.
    function getOwner() constant returns(address) {
        return owner;
    }

    // Helper function to get the last element in an array
    function getLast(PunchCard[] punchCards) constant internal returns(PunchCard) {
        return punchCards[punchCards.length - 1];
    }

    // Register an in time for a member. Only admins can perform this task.
    function punchIn(address member, uint64 inTime) onlyAdmins {
        // If the member does not exist, throw
        if (members[member] == false) throw;

        var allCards = punchClock[member];
        if (allCards.length > 0) {
            var lastCard = getLast(allCards);
            if (lastCard.timeOut == 0) {
                // remove the last card if it's incomplete. We'll replace it with a new one.
                punchClock[member].length = punchClock[member].length - 1;
            }
        }

        punchClock[member].push(
            PunchCard({
                timeIn: inTime,
                timeOut: 0
            })
        );
        PunchedIn(member, inTime);
    }

    // Register an out time for a member. Only admins can perform this task.
    function punchOut(address member, uint64 outTime) onlyAdmins {
        // If the member does not exist, throw
        if (members[member] == false) throw;

        var allCards = punchClock[member];
        if (allCards.length == 0) throw;
        var lastCard = getLast(allCards);
        if (lastCard.timeOut != 0) throw;
        // Remove the last card and replace it with a new one
        punchClock[member].length = punchClock[member].length - 1;
        punchClock[member].push(
            PunchCard({
                timeIn: lastCard.timeIn,
                timeOut: outTime
            })
        );
        PunchedOut(member, outTime);
    }

    // Remove an admin. Only owner can perform this task.
    function removeAdmin(address admin) onlyOwner {
        if (admins[admin] == true) {
            admins[admin] = false;
            members[admin] = false;
        }
        AdminRemoved(admin);
    }

    // Remove a member. Only admin can perform this task.
    function removeMember(address member) onlyAdmins {
        if (members[member] == true) {
            members[member] = false;
        }
        MemberRemoved(member);
    }

    // Check if a certain person is a member
    function isMember(address person) constant returns(bool) {
        return members[person];
    }

    // Check if a certain person is an admin
    function isAdmin(address person) constant returns(bool) {
        return admins[person];
    }

    // Change the owner to another person. Only owner can perform this task.
    function changeOwner(address newOwner) onlyOwner {
        var oldOwner = owner;
        owner = newOwner;
        OwnerChanged(oldOwner, newOwner);
    }

    // Kill the contract
    function destroy() onlyOwner {
        suicide(owner);
    }

    // TODO: batch adding
    // function addAdmins(address[] admins) onlyOwner
    // function addMembers(address[] members) onlyAdmins

    // TODO: batch punching
    //  function batchPunchIn(address[] members,  uint64[] inTimes) onlyAdmins
    //  function batchPunchOut(address[] members,  uint64[] outTimes) onlyAdmins
}

pragma solidity ^0.4.4;

contract PunchClock {
    // the owner of the contract
    address owner;

    // The data structure to store the time in and out of a person
    struct PunchCard {
        uint64 timeIn; // time the person gets in, unix timestamp
        uint64 timeOut; // time the person gets out, unix timestamp
    }

    // The list of all admins. The reason for having these two mapping is that
    // it's not possible to iterate through the list of keys in a mapping,
    // so the workaround is to have two mapping, with the second mapping is basically
    // just a map by index so that we can get all the keys. Similarly, it's not
    // possible to iterate through a mapping, so the workaround is to keep track
    // of the size manually.
    mapping(address => bool) admins;
    mapping(uint64 => address) adminsByIndex;
    uint64 totalNumberOfAdmins;

    // The list of all members.
    mapping(address => bool) members;
    mapping(uint64 => address) membersByIndex;
    uint64 totalNumberOfMembers;

    // All punch cards of all members
    mapping(address => PunchCard[]) punchClock;

    // Constructor, create a new punch clock and assign the creator as the owner of the punch clock
    function PunchClock() {
        owner = msg.sender;
        admins[owner] = true;
        adminsByIndex[0] = owner;
        totalNumberOfAdmins = 1;
        members[owner] = true;
        membersByIndex[0] = owner;
        totalNumberOfMembers = 1;
    }

    modifier onlyOwner() {
        if (msg.sender != owner) throw;
        _;
    }
    modifier onlyAdmins() {
        if (admins[msg.sender] == false) throw;
        _;
    }
    modifier onlyMembers() {
        if (members[msg.sender] == false) throw;
        _;
    }

    // Add a member to the contract if the member does not already exist
    function addMemberInternal(address member) internal {
        if (members[member] == false) {
            var newMemberIndex = totalNumberOfMembers;
            members[member] = true;
            membersByIndex[newMemberIndex] = member;
            totalNumberOfMembers++;
        }
    }
    // Add a new admin. Only the owner can perform this task.
    function addAdmin(address admin) onlyOwner {
        if (admins[admin] == false) {
            var indexOfNewAdmin = totalNumberOfAdmins;
            admins[admin] = true;
            adminsByIndex[indexOfNewAdmin] = admin;
            totalNumberOfAdmins++;

            addMemberInternal(admin);
        }
    }

    // Add a new member to the list of member. Only admins can perform this task
    function addMember(address member) onlyAdmins {
        addMemberInternal(member);
    }

    // Return all punch cards of a member
    function getPunchCardsInternal(address member) constant internal returns(uint64[2][]) {
        var allCards = punchClock[member];
        uint64[2][] memory tmp = new uint64[2][](allCards.length);
        for (uint64 i = 0; i < allCards.length; i++) {
            tmp[i] = [allCards[i].timeIn, allCards[i].timeOut];
        }
        return tmp;
    }

    // Return all punch cards of the requestor. Only member can perform this task
    function getMyPunchCards() onlyMembers constant returns(uint64[2][] punchCards) {
        return getPunchCardsInternal(msg.sender);
    }

    // Return all punch cards of a member. Only admin can perform this task
    function getPunchCardsOf(address member) onlyAdmins constant returns(uint64[2][] punchcards) {
        return getPunchCardsInternal(member);
    }

    // Return all members in the contract. Only admins can perform this task.
    function getAllMembers() onlyAdmins constant returns(address[]) {
        address[] memory allMembers = new address[](totalNumberOfMembers);
        for (uint64 i = 0; i < totalNumberOfMembers; i++) {
            allMembers[i] = membersByIndex[i];
        }
        return allMembers;
    }

    // Return all admins in the contract. Only owner can perform this task.
    function getAllAdmins() onlyOwner constant returns(address[]) {
        address[] memory allAdmins = new address[](totalNumberOfAdmins);
        for (uint64 i = 0; i < totalNumberOfAdmins; i++) {
            allAdmins[i] = adminsByIndex[i];
        }
        return allAdmins;
    }

    // Return the owner of the contract. Anyone can perform this task.
    function getOwner() constant returns(address) {
        return owner;
    }

    // Helper function to get the last element in an array
    function getLast(PunchCard[] punchCards) constant internal returns(PunchCard) {
        return punchCards[punchCards.length - 1];
    }

    // Register an in time for a member. Only admins can perform this task.
    function punchIn(address member, uint64 inTime) onlyAdmins {
        // If the member does not exist, throw
        if (members[member] == false) throw;

        var allCards = punchClock[member];
        if (allCards.length > 0) {
            var lastCard = getLast(allCards);
            if (lastCard.timeOut == 0) {
                // remove the last card if it's incomplete. We'll replace it with a new one.
                punchClock[member].length = punchClock[member].length - 1;
            }
        }

        punchClock[member].push(
            PunchCard({
            timeIn: inTime,
            timeOut: 0
        })
        );
    }

    // Register an out time for a member. Only admins can perform this task.
    function punchOut(address member, uint64 outTime) onlyAdmins {
        // If the member does not exist, throw
        if (members[member] == false) throw;

        var allCards = punchClock[member];
        if (allCards.length == 0) throw;
        var lastCard = getLast(allCards);
        if (lastCard.timeOut != 0) throw;
        // Remove the last card and replace it with a new one
        punchClock[member].length = punchClock[member].length - 1;
        //lastCard.timeOut = outTime;
        punchClock[member].push(
            PunchCard({
            timeIn: lastCard.timeIn,
            timeOut: outTime
        })
        );
    }

    // Remove an admin. Only owner can perform this task.
    function removeAdmin(address admin) onlyOwner {
        if (admins[admin] == true) {
            admins[admin] = false;
            members[admin] = false;
        }
    }

    // Remove a member. Only admin can perform this task.
    function removeMember(address member) onlyAdmins {
        if (members[member] == true) {
            members[member] = false;
        }
    }

    // Check if a certain person is a member
    function isMember(address person) constant returns(bool) {
        return members[person];
    }

    // Check if a certain person is an admin
    function isAdmin(address person) constant returns(bool) {
        return admins[person];
    }

    // Change the owner to another person. Only owner can perform this task.
    function changeOwner(address newOwner) onlyOwner {
        owner = newOwner;
    }

    // Kill the contract
    function destroy() onlyOwner {
        suicide(owner);
    }

    // TODO: publish events

    // TODO: batch adding
    // function addAdmins(address[] admins) onlyOwner
    // function addMembers(address[] members) onlyAdmins

    // TODO: batch punching
    //  function batchPunchIn(address[] members,  uint64[] inTimes) onlyAdmins
    //  function batchPunchOut(address[] members,  uint64[] outTimes) onlyAdmins
}


Change _hash to _id

Change _hash to _id

import "./Adjudicator.sol";
import "./BulletinBoard.sol";

library AdjudicatorPoster {
	function postAdjudicator(
		BulletinBoard _bulletinBoard,
		bytes32 _id,
		CompareOp _compareOp,
		address _owner,
		uint _timeout
	) {
		_bulletinBoard.updateRegistry(_id, new Adjudicator(_compareOp, _owner, _timeout));
	}
}

import "./Adjudicator.sol";
import "./BulletinBoard.sol";

library AdjudicatorPoster {
	function postAdjudicator(
		BulletinBoard _bulletinBoard,
		bytes32 _hash,
		CompareOp _compareOp,
		address _owner,
		uint _timeout
	) {
		_bulletinBoard.updateRegistry(_hash, new Adjudicator(_compareOp, _owner, _timeout));
	}
}


Fix: Check recipient address in transfer function (#32)

pragma solidity 0.4.11;

import "../SafeMath.sol";
import "./StorageEnabled.sol";
import "../Pausable.sol";
import "../ERC223ReceivingContract.sol";

contract NutzEnabled is Pausable, StorageEnabled {
  using SafeMath for uint;

  // satelite contract addresses
  address public nutzAddr;

  modifier onlyNutz() {
    require(msg.sender == nutzAddr);
    _;
  }

  function NutzEnabled(address _nutzAddr, address _storageAddr)
    StorageEnabled(_storageAddr) {
    nutzAddr = _nutzAddr;
  }

  // this flag allows or denies deposits of NTZ into non-contract accounts
  bool public onlyContractHolders;

  function setOnlyContractHolders(bool _onlyContractHolders) public onlyAdmins {
    onlyContractHolders = _onlyContractHolders;
  }

  // ############################################
  // ########### NUTZ FUNCTIONS  ################
  // ############################################

  // total supply
  function totalSupply() constant returns (uint256) {
    return activeSupply().add(powerPool()).add(burnPool());
  }

  // allowances according to ERC20
  // not written to storage, as not very critical
  mapping (address => mapping (address => uint)) internal allowed;

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

  function approve(address _owner, address _spender, uint256 _amountBabz) public onlyNutz whenNotPaused {
    require(_owner != _spender);
    allowed[_owner][_spender] = _amountBabz;
  }

  function _checkDestination(address _from, address _to, uint256 _value, bytes _data) internal {
    // erc223: Retrieve the size of the code on target address, this needs assembly .
    uint256 codeLength;
    assembly {
      codeLength := extcodesize(_to)
    }
    if(codeLength>0) {
      ERC223ReceivingContract untrustedReceiver = ERC223ReceivingContract(_to);
      // untrusted contract call
      untrustedReceiver.tokenFallback(_from, _value, _data);
    } else {
      require(onlyContractHolders == false);
    }
  }

  // assumption that params have allready be sanity checked:
  // require(_from != _to)
  // require(_from != powerAddr)
  function _transfer(address _from, address _to, uint256 _amountBabz, bytes _data) internal {
    require(_to != address(this));
    require(_to != address(0x0));
    require(_amountBabz > 0);
    _setBabzBalanceOf(_from, babzBalanceOf(_from).sub(_amountBabz));
    _setBabzBalanceOf(_to, babzBalanceOf(_to).add(_amountBabz));
    _checkDestination(_from, _to, _amountBabz, _data);
  }

  function transfer(address _from, address _to, uint256 _amountBabz, bytes _data) public onlyNutz whenNotPaused {
    _transfer(_from, _to, _amountBabz, _data);
  }

  function transferFrom(address _sender, address _from, address _to, uint256 _amountBabz, bytes _data) public onlyNutz whenNotPaused returns (bool) {
    require(_from != _to);
    allowed[_from][_sender] = allowed[_from][_sender].sub(_amountBabz);
    _transfer(_from, _to, _amountBabz, _data);
    return true;
  }

}

pragma solidity 0.4.11;

import "../SafeMath.sol";
import "./StorageEnabled.sol";
import "../Pausable.sol";
import "../ERC223ReceivingContract.sol";

contract NutzEnabled is Pausable, StorageEnabled {
  using SafeMath for uint;

  // satelite contract addresses
  address public nutzAddr;

  modifier onlyNutz() {
    require(msg.sender == nutzAddr);
    _;
  }

  function NutzEnabled(address _nutzAddr, address _storageAddr)
    StorageEnabled(_storageAddr) {
    nutzAddr = _nutzAddr;
  }

  // this flag allows or denies deposits of NTZ into non-contract accounts
  bool public onlyContractHolders;

  function setOnlyContractHolders(bool _onlyContractHolders) public onlyAdmins {
    onlyContractHolders = _onlyContractHolders;
  }

  // ############################################
  // ########### NUTZ FUNCTIONS  ################
  // ############################################

  // total supply
  function totalSupply() constant returns (uint256) {
    return activeSupply().add(powerPool()).add(burnPool());
  }

  // allowances according to ERC20
  // not written to storage, as not very critical
  mapping (address => mapping (address => uint)) internal allowed;

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

  function approve(address _owner, address _spender, uint256 _amountBabz) public onlyNutz whenNotPaused {
    require(_owner != _spender);
    allowed[_owner][_spender] = _amountBabz;
  }

  function _checkDestination(address _from, address _to, uint256 _value, bytes _data) internal {
    // erc223: Retrieve the size of the code on target address, this needs assembly .
    uint256 codeLength;
    assembly {
      codeLength := extcodesize(_to)
    }
    if(codeLength>0) {
      ERC223ReceivingContract untrustedReceiver = ERC223ReceivingContract(_to);
      // untrusted contract call
      untrustedReceiver.tokenFallback(_from, _value, _data);
    } else {
      require(onlyContractHolders == false);
    }
  }

  // assumption that params have allready be sanity checked:
  // require(_from != _to)
  // require(_from != powerAddr)
  function _transfer(address _from, address _to, uint256 _amountBabz, bytes _data) internal {
    require(_to != address(this));
    require(_amountBabz > 0);
    _setBabzBalanceOf(_from, babzBalanceOf(_from).sub(_amountBabz));
    _setBabzBalanceOf(_to, babzBalanceOf(_to).add(_amountBabz));
    _checkDestination(_from, _to, _amountBabz, _data);
  }

  function transfer(address _from, address _to, uint256 _amountBabz, bytes _data) public onlyNutz whenNotPaused {
    _transfer(_from, _to, _amountBabz, _data);
  }

  function transferFrom(address _sender, address _from, address _to, uint256 _amountBabz, bytes _data) public onlyNutz whenNotPaused returns (bool) {
    require(_from != _to);
    allowed[_from][_sender] = allowed[_from][_sender].sub(_amountBabz);
    _transfer(_from, _to, _amountBabz, _data);
    return true;
  }

}


added missing semicolon

added missing semicolon

pragma solidity ^0.4.2;

contract TokenContract {
  function transferFrom(address _from, address _to, uint256 _value) returns (bool success);
}

contract USDZAR {

  uint256 public rate;

  struct Approval{
    address approver;
    address tokenContract;
    uint256 value;
    uint256 rate;
  }

  mapping(address => Approval) approvals;

  event Approval(
      address indexed approver
    , address indexed tokenContract
    , uint256 indexed value
    , uint256 rate
  );

  function USDZAR(uint256 rate_) {
    rate = rate_;
  }

  // TODO: Should approvals only be valid for a specified time?
  function addApproval(address requester, address tokenContract, uint256 value, uint256 rate)
    returns (bool success){

    Approval memory newApproval = Approval({
      approver: msg.sender,
      tokenContract: tokenContract,
      value: value,
      rate: rate
    });
    approvals[requester] = newApproval;
    Approval(msg.sender, tokenContract, value, rate);
    return true;
  }

  function receiveApproval(address requester, uint256 value, address tokenContract, bytes extraData)
    returns (bool success) {
    //TODO: first check both balances
    var approval = approvals[requester];
    //TODO: check that approval hasn't expired yet
    //TODO: check rate against value approved for
    TokenContract token1 = TokenContract(approval.tokenContract);
    TokenContract token2 = TokenContract(tokenContract);
    //TODO: add checks for success
    token1.transferFrom(requester, approval.approver, value);
    token2.transferFrom(approval.approver, requester, approval.value);

    return true;
  }

  function setRate(uint256 _value) {
    rate = _value;
  }

  function getRate() returns (uint256){
    return rate;
  }

  function () {
    throw;
  }
}

pragma solidity ^0.4.2;

contract TokenContract {
  function transferFrom(address _from, address _to, uint256 _value) returns (bool success);
}

contract USDZAR {

  uint256 public rate;

  struct Approval{
    address approver;
    address tokenContract;
    uint256 value;
    uint256 rate;
  }

  mapping(address => Approval) approvals;

  event Approval(
      address indexed approver
    , address indexed tokenContract
    , uint256 indexed value
    , uint256 rate
  );

  function USDZAR(uint256 rate_) {
    rate = rate_;
  }

  // TODO: Should approvals only be valid for a specified time?
  function addApproval(address requester, address tokenContract, uint256 value, uint256 rate)
    returns (bool success){

    Approval memory newApproval = Approval({
      approver: msg.sender,
      tokenContract: tokenContract,
      value: value,
      rate: rate
    });
    approvals[requester] = newApproval;
    Approval(msg.sender, tokenContract, value, rate);
    return true;
  }

  function receiveApproval(address requester, uint256 value, address tokenContract, bytes extraData)
    returns (bool success) {
    //TODO: first check both balances
    var approval = approvals[requester]
    //TODO: check that approval hasn't expired yet
    //TODO: check rate against value approved for
    TokenContract token1 = TokenContract(approval.tokenContract);
    TokenContract token2 = TokenContract(tokenContract);
    //TODO: add checks for success
    token1.transferFrom(requester, approval.approver, value);
    token2.transferFrom(approval.approver, requester, approval.value);

    return true;
  }

  function setRate(uint256 _value) {
    rate = _value;
  }

  function getRate() returns (uint256){
    return rate;
  }

  function () {
    throw;
  }
}


Fix NatSpec comment syntax

Fix NatSpec comment syntax

// SPDX-License-Identifier: MIT

pragma solidity >=0.6.9 <0.8.0;
pragma experimental ABIEncoderV2;

import "./../math/SafeMath.sol";
import "./AccessControl.sol";

/**
 * @dev Contract module which acts as a timelocked controller. When set as the
 * owner of an `Ownable` smart contract, it enforces a timelock on all
 * `onlyOwner` maintenance operations. This gives time for users of the
 * controlled contract to exit before a potentially dangerous maintenance
 * operation is applied.
 *
 * By default, this contract is self administered, meaning administration tasks
 * have to go through the timelock process. The proposer (resp executor) role
 * is in charge of proposing (resp executing) operations. A common use case is
 * to position this {TimelockController} as the owner of a smart contract, with
 * a multisig or a DAO as the sole proposer.
 */
contract TimelockController is AccessControl {

    bytes32 public constant TIMELOCK_ADMIN_ROLE = keccak256("TIMELOCK_ADMIN_ROLE");
    bytes32 public constant PROPOSER_ROLE = keccak256("PROPOSER_ROLE");
    bytes32 public constant EXECUTOR_ROLE = keccak256("EXECUTOR_ROLE");
    uint256 internal constant _DONE_TIMESTAMP = uint256(1);

    mapping(bytes32 => uint256) private _timestamps;
    uint256 private _minDelay;

    /**
     * @dev Emitted when a call is scheduled as part of operation `id`.
     */
    event CallScheduled(bytes32 indexed id, uint256 indexed index, address target, uint256 value, bytes data, bytes32 predecessor, uint256 delay);

    /**
     * @dev Emitted when a call is performed as part of operation `id`.
     */
    event CallExecuted(bytes32 indexed id, uint256 indexed index, address target, uint256 value, bytes data);

    /**
     * @dev Emitted when operation `id` is cancelled.
     */
    event Cancelled(bytes32 indexed id);

    /**
     * @dev Emitted when the minimum delay for future operations is modified.
     */
    event MinDelayChange(uint256 oldDuration, uint256 newDuration);

    /**
     * @dev Initializes the contract with a given `minDelay`.
     */
    constructor(uint256 minDelay, address[] memory proposers, address[] memory executors) public {
        _setRoleAdmin(TIMELOCK_ADMIN_ROLE, TIMELOCK_ADMIN_ROLE);
        _setRoleAdmin(PROPOSER_ROLE, TIMELOCK_ADMIN_ROLE);
        _setRoleAdmin(EXECUTOR_ROLE, TIMELOCK_ADMIN_ROLE);

        // deployer + self administration
        _setupRole(TIMELOCK_ADMIN_ROLE, _msgSender());
        _setupRole(TIMELOCK_ADMIN_ROLE, address(this));

        // register proposers
        for (uint256 i = 0; i < proposers.length; ++i) {
            _setupRole(PROPOSER_ROLE, proposers[i]);
        }

        // register executors
        for (uint256 i = 0; i < executors.length; ++i) {
            _setupRole(EXECUTOR_ROLE, executors[i]);
        }

        _minDelay = minDelay;
        emit MinDelayChange(0, minDelay);
    }

    /**
     * @dev Modifier to make a function callable only by a certain role. In
     * addition to checking the sender's role, `address(0)` 's role is also
     * considered. Granting a role to `address(0)` is equivalent to enabling
     * this role for everyone.
     */
    modifier onlyRole(bytes32 role) {
        require(hasRole(role, _msgSender()) || hasRole(role, address(0)), "TimelockController: sender requires permission");
        _;
    }

    /**
     * @dev Contract might receive/hold ETH as part of the maintenance process.
     */
    receive() external payable {}

    /**
     * @dev Returns whether an operation is pending or not.
     */
    function isOperationPending(bytes32 id) public view returns (bool pending) {
        return _timestamps[id] > _DONE_TIMESTAMP;
    }

    /**
     * @dev Returns whether an operation is ready or not.
     */
    function isOperationReady(bytes32 id) public view returns (bool ready) {
        // solhint-disable-next-line not-rely-on-time
        return _timestamps[id] > _DONE_TIMESTAMP && _timestamps[id] <= block.timestamp;
    }

    /**
     * @dev Returns whether an operation is done or not.
     */
    function isOperationDone(bytes32 id) public view returns (bool done) {
        return _timestamps[id] == _DONE_TIMESTAMP;
    }

    /**
     * @dev Returns the timestamp at with an operation becomes ready (0 for
     * unset operations, 1 for done operations).
     */
    function getTimestamp(bytes32 id) public view returns (uint256 timestamp) {
        return _timestamps[id];
    }

    /**
     * @dev Returns the minimum delay for an operation to become valid.
     */
    function getMinDelay() public view returns (uint256 duration) {
        return _minDelay;
    }

    /**
     * @dev Returns the identifier of an operation containing a single
     * transaction.
     */
    function hashOperation(address target, uint256 value, bytes calldata data, bytes32 predecessor, bytes32 salt) public pure returns (bytes32 hash) {
        return keccak256(abi.encode(target, value, data, predecessor, salt));
    }

    /**
     * @dev Returns the identifier of an operation containing a batch of
     * transactions.
     */
    function hashOperationBatch(address[] calldata targets, uint256[] calldata values, bytes[] calldata datas, bytes32 predecessor, bytes32 salt) public pure returns (bytes32 hash) {
        return keccak256(abi.encode(targets, values, datas, predecessor, salt));
    }

    /**
     * @dev Schedule an operation containing a single transaction.
     *
     * Emits a {CallScheduled} event.
     *
     * Requirements:
     *
     * - the caller must have the 'proposer' role.
     */
    function schedule(address target, uint256 value, bytes calldata data, bytes32 predecessor, bytes32 salt, uint256 delay) public virtual onlyRole(PROPOSER_ROLE) {
        bytes32 id = hashOperation(target, value, data, predecessor, salt);
        _schedule(id, delay);
        emit CallScheduled(id, 0, target, value, data, predecessor, delay);
    }

    /**
     * @dev Schedule an operation containing a batch of transactions.
     *
     * Emits one {CallScheduled} event per transaction in the batch.
     *
     * Requirements:
     *
     * - the caller must have the 'proposer' role.
     */
    function scheduleBatch(address[] calldata targets, uint256[] calldata values, bytes[] calldata datas, bytes32 predecessor, bytes32 salt, uint256 delay) public virtual onlyRole(PROPOSER_ROLE) {
        require(targets.length == values.length, "TimelockController: length mismatch");
        require(targets.length == datas.length, "TimelockController: length mismatch");

        bytes32 id = hashOperationBatch(targets, values, datas, predecessor, salt);
        _schedule(id, delay);
        for (uint256 i = 0; i < targets.length; ++i) {
            emit CallScheduled(id, i, targets[i], values[i], datas[i], predecessor, delay);
        }
    }

    /**
     * @dev Schedule an operation that is to becomes valid after a given delay.
     */
    function _schedule(bytes32 id, uint256 delay) private {
        require(_timestamps[id] == 0, "TimelockController: operation already scheduled");
        require(delay >= _minDelay, "TimelockController: insufficient delay");
        // solhint-disable-next-line not-rely-on-time
        _timestamps[id] = SafeMath.add(block.timestamp, delay);
    }

    /**
     * @dev Cancel an operation.
     *
     * Requirements:
     *
     * - the caller must have the 'proposer' role.
     */
    function cancel(bytes32 id) public virtual onlyRole(PROPOSER_ROLE) {
        require(isOperationPending(id), "TimelockController: operation cannot be cancelled");
        delete _timestamps[id];

        emit Cancelled(id);
    }

    /**
     * @dev Execute an (ready) operation containing a single transaction.
     *
     * Emits a {CallExecuted} event.
     *
     * Requirements:
     *
     * - the caller must have the 'executor' role.
     */
    function execute(address target, uint256 value, bytes calldata data, bytes32 predecessor, bytes32 salt) public payable virtual onlyRole(EXECUTOR_ROLE) {
        bytes32 id = hashOperation(target, value, data, predecessor, salt);
        _beforeCall(predecessor);
        _call(id, 0, target, value, data);
        _afterCall(id);
    }

    /**
     * @dev Execute an (ready) operation containing a batch of transactions.
     *
     * Emits one {CallExecuted} event per transaction in the batch.
     *
     * Requirements:
     *
     * - the caller must have the 'executor' role.
     */
    function executeBatch(address[] calldata targets, uint256[] calldata values, bytes[] calldata datas, bytes32 predecessor, bytes32 salt) public payable virtual onlyRole(EXECUTOR_ROLE) {
        require(targets.length == values.length, "TimelockController: length mismatch");
        require(targets.length == datas.length, "TimelockController: length mismatch");

        bytes32 id = hashOperationBatch(targets, values, datas, predecessor, salt);
        _beforeCall(predecessor);
        for (uint256 i = 0; i < targets.length; ++i) {
            _call(id, i, targets[i], values[i], datas[i]);
        }
        _afterCall(id);
    }

    /**
     * @dev Checks before execution of an operation's calls.
     */
    function _beforeCall(bytes32 predecessor) private view {
        require(predecessor == bytes32(0) || isOperationDone(predecessor), "TimelockController: missing dependency");
    }

    /**
     * @dev Checks after execution of an operation's calls.
     */
    function _afterCall(bytes32 id) private {
        require(isOperationReady(id), "TimelockController: operation is not ready");
        _timestamps[id] = _DONE_TIMESTAMP;
    }

    /**
     * @dev Execute an operation's call.
     *
     * Emits a {CallExecuted} event.
     */
    function _call(bytes32 id, uint256 index, address target, uint256 value, bytes calldata data) private {
        // solhint-disable-next-line avoid-low-level-calls
        (bool success,) = target.call{value: value}(data);
        require(success, "TimelockController: underlying transaction reverted");

        emit CallExecuted(id, index, target, value, data);
    }

    /**
     * @dev Changes the timelock duration for future operations.
     *
     * Emits a {MinDelayChange} event.
     */
    function updateDelay(uint256 newDelay) external virtual {
        require(msg.sender == address(this), "TimelockController: caller must be timelock");
        emit MinDelayChange(_minDelay, newDelay);
        _minDelay = newDelay;
    }
}

// SPDX-License-Identifier: MIT

pragma solidity >=0.6.9 <0.8.0;
pragma experimental ABIEncoderV2;

import "./../math/SafeMath.sol";
import "./AccessControl.sol";

/**
 * @dev Contract module which acts as a timelocked controller. When set as the
 * owner of an `Ownable` smart contract, it enforces a timelock on all
 * `onlyOwner` maintenance operations. This gives time for users of the
 * controlled contract to exit before a potentially dangerous maintenance
 * operation is applied.
 *
 * By default, this contract is self administered, meaning administration tasks
 * have to go through the timelock process. The proposer (resp executor) role
 * is in charge of proposing (resp executing) operations. A common use case is
 * to position this {TimelockController} as the owner of a smart contract, with
 * a multisig or a DAO as the sole proposer.
 */
contract TimelockController is AccessControl {

    bytes32 public constant TIMELOCK_ADMIN_ROLE = keccak256("TIMELOCK_ADMIN_ROLE");
    bytes32 public constant PROPOSER_ROLE = keccak256("PROPOSER_ROLE");
    bytes32 public constant EXECUTOR_ROLE = keccak256("EXECUTOR_ROLE");
    uint256 internal constant _DONE_TIMESTAMP = uint256(1);

    mapping(bytes32 => uint256) private _timestamps;
    uint256 private _minDelay;

    /**
     * @dev Emitted when a call is scheduled as part of operation `id`.
     */
    event CallScheduled(bytes32 indexed id, uint256 indexed index, address target, uint256 value, bytes data, bytes32 predecessor, uint256 delay);

    /**
     * @dev Emitted when a call is performed as part of operation `id`.
     */
    event CallExecuted(bytes32 indexed id, uint256 indexed index, address target, uint256 value, bytes data);

    /**
     * @dev Emitted when operation `id` is cancelled.
     */
    event Cancelled(bytes32 indexed id);

    /**
     * @dev Emitted when the minimum delay for future operations is modified.
     */
    event MinDelayChange(uint256 oldDuration, uint256 newDuration);

    /**
     * @dev Initializes the contract with a given `minDelay`.
     */
    constructor(uint256 minDelay, address[] memory proposers, address[] memory executors) public {
        _setRoleAdmin(TIMELOCK_ADMIN_ROLE, TIMELOCK_ADMIN_ROLE);
        _setRoleAdmin(PROPOSER_ROLE, TIMELOCK_ADMIN_ROLE);
        _setRoleAdmin(EXECUTOR_ROLE, TIMELOCK_ADMIN_ROLE);

        // deployer + self administration
        _setupRole(TIMELOCK_ADMIN_ROLE, _msgSender());
        _setupRole(TIMELOCK_ADMIN_ROLE, address(this));

        // register proposers
        for (uint256 i = 0; i < proposers.length; ++i) {
            _setupRole(PROPOSER_ROLE, proposers[i]);
        }

        // register executors
        for (uint256 i = 0; i < executors.length; ++i) {
            _setupRole(EXECUTOR_ROLE, executors[i]);
        }

        _minDelay = minDelay;
        emit MinDelayChange(0, minDelay);
    }

    /**
     * @dev Modifier to make a function callable only by a certain role. In
     * addition to checking the sender's role, `address(0)` 's role is also
     * considered. Granting a role to `address(0)` is equivalent to enabling
     * this role for everyone.
     */
    modifier onlyRole(bytes32 role) {
        require(hasRole(role, _msgSender()) || hasRole(role, address(0)), "TimelockController: sender requires permission");
        _;
    }

    /*
     * @dev Contract might receive/hold ETH as part of the maintenance process.
     */
    receive() external payable {}

    /**
     * @dev Returns whether an operation is pending or not.
     */
    function isOperationPending(bytes32 id) public view returns (bool pending) {
        return _timestamps[id] > _DONE_TIMESTAMP;
    }

    /**
     * @dev Returns whether an operation is ready or not.
     */
    function isOperationReady(bytes32 id) public view returns (bool ready) {
        // solhint-disable-next-line not-rely-on-time
        return _timestamps[id] > _DONE_TIMESTAMP && _timestamps[id] <= block.timestamp;
    }

    /**
     * @dev Returns whether an operation is done or not.
     */
    function isOperationDone(bytes32 id) public view returns (bool done) {
        return _timestamps[id] == _DONE_TIMESTAMP;
    }

    /**
     * @dev Returns the timestamp at with an operation becomes ready (0 for
     * unset operations, 1 for done operations).
     */
    function getTimestamp(bytes32 id) public view returns (uint256 timestamp) {
        return _timestamps[id];
    }

    /**
     * @dev Returns the minimum delay for an operation to become valid.
     */
    function getMinDelay() public view returns (uint256 duration) {
        return _minDelay;
    }

    /**
     * @dev Returns the identifier of an operation containing a single
     * transaction.
     */
    function hashOperation(address target, uint256 value, bytes calldata data, bytes32 predecessor, bytes32 salt) public pure returns (bytes32 hash) {
        return keccak256(abi.encode(target, value, data, predecessor, salt));
    }

    /**
     * @dev Returns the identifier of an operation containing a batch of
     * transactions.
     */
    function hashOperationBatch(address[] calldata targets, uint256[] calldata values, bytes[] calldata datas, bytes32 predecessor, bytes32 salt) public pure returns (bytes32 hash) {
        return keccak256(abi.encode(targets, values, datas, predecessor, salt));
    }

    /**
     * @dev Schedule an operation containing a single transaction.
     *
     * Emits a {CallScheduled} event.
     *
     * Requirements:
     *
     * - the caller must have the 'proposer' role.
     */
    function schedule(address target, uint256 value, bytes calldata data, bytes32 predecessor, bytes32 salt, uint256 delay) public virtual onlyRole(PROPOSER_ROLE) {
        bytes32 id = hashOperation(target, value, data, predecessor, salt);
        _schedule(id, delay);
        emit CallScheduled(id, 0, target, value, data, predecessor, delay);
    }

    /**
     * @dev Schedule an operation containing a batch of transactions.
     *
     * Emits one {CallScheduled} event per transaction in the batch.
     *
     * Requirements:
     *
     * - the caller must have the 'proposer' role.
     */
    function scheduleBatch(address[] calldata targets, uint256[] calldata values, bytes[] calldata datas, bytes32 predecessor, bytes32 salt, uint256 delay) public virtual onlyRole(PROPOSER_ROLE) {
        require(targets.length == values.length, "TimelockController: length mismatch");
        require(targets.length == datas.length, "TimelockController: length mismatch");

        bytes32 id = hashOperationBatch(targets, values, datas, predecessor, salt);
        _schedule(id, delay);
        for (uint256 i = 0; i < targets.length; ++i) {
            emit CallScheduled(id, i, targets[i], values[i], datas[i], predecessor, delay);
        }
    }

    /**
     * @dev Schedule an operation that is to becomes valid after a given delay.
     */
    function _schedule(bytes32 id, uint256 delay) private {
        require(_timestamps[id] == 0, "TimelockController: operation already scheduled");
        require(delay >= _minDelay, "TimelockController: insufficient delay");
        // solhint-disable-next-line not-rely-on-time
        _timestamps[id] = SafeMath.add(block.timestamp, delay);
    }

    /**
     * @dev Cancel an operation.
     *
     * Requirements:
     *
     * - the caller must have the 'proposer' role.
     */
    function cancel(bytes32 id) public virtual onlyRole(PROPOSER_ROLE) {
        require(isOperationPending(id), "TimelockController: operation cannot be cancelled");
        delete _timestamps[id];

        emit Cancelled(id);
    }

    /**
     * @dev Execute an (ready) operation containing a single transaction.
     *
     * Emits a {CallExecuted} event.
     *
     * Requirements:
     *
     * - the caller must have the 'executor' role.
     */
    function execute(address target, uint256 value, bytes calldata data, bytes32 predecessor, bytes32 salt) public payable virtual onlyRole(EXECUTOR_ROLE) {
        bytes32 id = hashOperation(target, value, data, predecessor, salt);
        _beforeCall(predecessor);
        _call(id, 0, target, value, data);
        _afterCall(id);
    }

    /**
     * @dev Execute an (ready) operation containing a batch of transactions.
     *
     * Emits one {CallExecuted} event per transaction in the batch.
     *
     * Requirements:
     *
     * - the caller must have the 'executor' role.
     */
    function executeBatch(address[] calldata targets, uint256[] calldata values, bytes[] calldata datas, bytes32 predecessor, bytes32 salt) public payable virtual onlyRole(EXECUTOR_ROLE) {
        require(targets.length == values.length, "TimelockController: length mismatch");
        require(targets.length == datas.length, "TimelockController: length mismatch");

        bytes32 id = hashOperationBatch(targets, values, datas, predecessor, salt);
        _beforeCall(predecessor);
        for (uint256 i = 0; i < targets.length; ++i) {
            _call(id, i, targets[i], values[i], datas[i]);
        }
        _afterCall(id);
    }

    /**
     * @dev Checks before execution of an operation's calls.
     */
    function _beforeCall(bytes32 predecessor) private view {
        require(predecessor == bytes32(0) || isOperationDone(predecessor), "TimelockController: missing dependency");
    }

    /**
     * @dev Checks after execution of an operation's calls.
     */
    function _afterCall(bytes32 id) private {
        require(isOperationReady(id), "TimelockController: operation is not ready");
        _timestamps[id] = _DONE_TIMESTAMP;
    }

    /**
     * @dev Execute an operation's call.
     *
     * Emits a {CallExecuted} event.
     */
    function _call(bytes32 id, uint256 index, address target, uint256 value, bytes calldata data) private {
        // solhint-disable-next-line avoid-low-level-calls
        (bool success,) = target.call{value: value}(data);
        require(success, "TimelockController: underlying transaction reverted");

        emit CallExecuted(id, index, target, value, data);
    }

    /**
     * @dev Changes the timelock duration for future operations.
     *
     * Emits a {MinDelayChange} event.
     */
    function updateDelay(uint256 newDelay) external virtual {
        require(msg.sender == address(this), "TimelockController: caller must be timelock");
        emit MinDelayChange(_minDelay, newDelay);
        _minDelay = newDelay;
    }
}