Goerli Testnet

Contract

0x9648cDC5D3D17A7DEc035ac2d0d943b511ECf8F6
Source Code
Transaction Hash
Method
Block
From
To
Value
Submit Challenge91067632023-06-02 4:01:24117 days 11 hrs ago1685678484IN
0x9648cD...11ECf8F6
0 ETH0.0009656311.19901412
Reveal Fleets An...91067612023-06-02 4:00:48117 days 11 hrs ago1685678448IN
0x9648cD...11ECf8F6
0 ETH0.0095794710.95893081
Accept Challenge91067592023-06-02 4:00:24117 days 11 hrs ago1685678424IN
0x9648cD...11ECf8F6
0 ETH0.0006315510.55169186
Submit Challenge91067382023-06-02 3:55:00117 days 11 hrs ago1685678100IN
0x9648cD...11ECf8F6
0 ETH0.0009105710.56039755
Reveal Fleets An...91067362023-06-02 3:54:36117 days 11 hrs ago1685678076IN
0x9648cD...11ECf8F6
0 ETH0.010277610.74791409
Accept Challenge91067342023-06-02 3:54:12117 days 11 hrs ago1685678052IN
0x9648cD...11ECf8F6
0 ETH0.0006241310.42781843
Submit Challenge91067052023-06-02 3:47:36117 days 11 hrs ago1685677656IN
0x9648cD...11ECf8F6
0 ETH0.0012529814.53158067
Reveal Fleets An...91067032023-06-02 3:47:12117 days 11 hrs ago1685677632IN
0x9648cD...11ECf8F6
0 ETH0.0108066915.04733708
Accept Challenge91067012023-06-02 3:46:48117 days 11 hrs ago1685677608IN
0x9648cD...11ECf8F6
0 ETH0.0008624614.40976214
Submit Challenge90463482023-05-22 22:42:48127 days 16 hrs ago1684795368IN
0x9648cD...11ECf8F6
0 ETH0.000303553.52052173
Reveal Fleets An...90463472023-05-22 22:42:36127 days 16 hrs ago1684795356IN
0x9648cD...11ECf8F6
0 ETH0.002551353.67569221
Accept Challenge90463462023-05-22 22:42:24127 days 16 hrs ago1684795344IN
0x9648cD...11ECf8F6
0 ETH0.000227053.80893633
Submit Challenge90463342023-05-22 22:39:24127 days 16 hrs ago1684795164IN
0x9648cD...11ECf8F6
0 ETH0.000327733.80088288
Reveal Fleets An...90463332023-05-22 22:39:12127 days 16 hrs ago1684795152IN
0x9648cD...11ECf8F6
0 ETH0.002897783.9993178
Accept Challenge90463322023-05-22 22:39:00127 days 16 hrs ago1684795140IN
0x9648cD...11ECf8F6
0 ETH0.000241164.04571626
Reveal Fleets An...90463272023-05-22 22:38:00127 days 16 hrs ago1684795080IN
0x9648cD...11ECf8F6
0 ETH0.002801354.43840171
Submit Challenge90463272023-05-22 22:38:00127 days 16 hrs ago1684795080IN
0x9648cD...11ECf8F6
0 ETH0.00038274.43840171
Accept Challenge90463262023-05-22 22:37:48127 days 16 hrs ago1684795068IN
0x9648cD...11ECf8F6
0 ETH0.00028264.7409227
Reveal Fleets An...90463252023-05-22 22:37:36127 days 16 hrs ago1684795056IN
0x9648cD...11ECf8F6
0 ETH0.002585614.3817049
Submit Challenge90463212023-05-22 22:36:12127 days 17 hrs ago1684794972IN
0x9648cD...11ECf8F6
0 ETH0.000348564.04253107
Reveal Fleets An...90462902023-05-22 22:28:48127 days 17 hrs ago1684794528IN
0x9648cD...11ECf8F6
0 ETH0.002295453.64352434
Accept Challenge90462882023-05-22 22:28:12127 days 17 hrs ago1684794492IN
0x9648cD...11ECf8F6
0 ETH0.000233313.91406357
Accept Challenge90462502023-05-22 22:18:48127 days 17 hrs ago1684793928IN
0x9648cD...11ECf8F6
0 ETH0.000236063.96018764
Submit Challenge90462452023-05-22 22:17:48127 days 17 hrs ago1684793868IN
0x9648cD...11ECf8F6
0 ETH0.00037654.36654549
Submit Challenge90462392023-05-22 22:16:36127 days 17 hrs ago1684793796IN
0x9648cD...11ECf8F6
0 ETH0.000450035.21932148
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Txn Hash Block From To Value
91067632023-06-02 4:01:24117 days 11 hrs ago1685678484
0x9648cD...11ECf8F6
0 ETH
91067612023-06-02 4:00:48117 days 11 hrs ago1685678448
0x9648cD...11ECf8F6
0 ETH
91067612023-06-02 4:00:48117 days 11 hrs ago1685678448
0x9648cD...11ECf8F6
0 ETH
91067612023-06-02 4:00:48117 days 11 hrs ago1685678448
0x9648cD...11ECf8F6
0 ETH
91067612023-06-02 4:00:48117 days 11 hrs ago1685678448
0x9648cD...11ECf8F6
0 ETH
91067612023-06-02 4:00:48117 days 11 hrs ago1685678448
0x9648cD...11ECf8F6
0 ETH
91067612023-06-02 4:00:48117 days 11 hrs ago1685678448
0x9648cD...11ECf8F6
0 ETH
91067612023-06-02 4:00:48117 days 11 hrs ago1685678448
0x9648cD...11ECf8F6
0 ETH
91067612023-06-02 4:00:48117 days 11 hrs ago1685678448
0x9648cD...11ECf8F6
0 ETH
91067612023-06-02 4:00:48117 days 11 hrs ago1685678448
0x9648cD...11ECf8F6
0 ETH
91067612023-06-02 4:00:48117 days 11 hrs ago1685678448
0x9648cD...11ECf8F6
0 ETH
91067612023-06-02 4:00:48117 days 11 hrs ago1685678448
0x9648cD...11ECf8F6
0 ETH
91067612023-06-02 4:00:48117 days 11 hrs ago1685678448
0x9648cD...11ECf8F6
0 ETH
91067612023-06-02 4:00:48117 days 11 hrs ago1685678448
0x9648cD...11ECf8F6
0 ETH
91067612023-06-02 4:00:48117 days 11 hrs ago1685678448
0x9648cD...11ECf8F6
0 ETH
91067612023-06-02 4:00:48117 days 11 hrs ago1685678448
0x9648cD...11ECf8F6
0 ETH
91067612023-06-02 4:00:48117 days 11 hrs ago1685678448
0x9648cD...11ECf8F6
0 ETH
91067612023-06-02 4:00:48117 days 11 hrs ago1685678448
0x9648cD...11ECf8F6
0 ETH
91067612023-06-02 4:00:48117 days 11 hrs ago1685678448
0x9648cD...11ECf8F6
0 ETH
91067612023-06-02 4:00:48117 days 11 hrs ago1685678448
0x9648cD...11ECf8F6
0 ETH
91067612023-06-02 4:00:48117 days 11 hrs ago1685678448
0x9648cD...11ECf8F6
0 ETH
91067612023-06-02 4:00:48117 days 11 hrs ago1685678448
0x9648cD...11ECf8F6
0 ETH
91067612023-06-02 4:00:48117 days 11 hrs ago1685678448
0x9648cD...11ECf8F6
0 ETH
91067612023-06-02 4:00:48117 days 11 hrs ago1685678448
0x9648cD...11ECf8F6
0 ETH
91067612023-06-02 4:00:48117 days 11 hrs ago1685678448
0x9648cD...11ECf8F6
0 ETH
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Game

Compiler Version
v0.8.17+commit.8df45f5f

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion

Contract Source Code (Solidity Standard Json-Input format)

File 1 of 5 : Game.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

import "./generals/IGeneral.sol";
import "./utils/Attacks.sol";
import "./utils/Fleet.sol";
import "./utils/Board.sol";

error ChallengeDoesNotExist();
error ChallengeAldreadyExists();
error ChallengeAldreadyLocked();
error ChallengeNeedsToBeLocked();
error ChallengerDoesNotWantToPlayAgainstYou();
error FaciliatorPercentageUnitsWrong();
error FleetsNeedToHaveBeenRevealed();
error NotYourGeneral();
error NotEnoughEth();
error InvalidChallengeIndex();
error InvalidFleetHash();
error InvalidMaxTurns();

/**
 * @title 0xShip: On-Chain Battleship Game
 * @author Nazar Ilamanov <@nazar_ilamanov>
 * @notice Here is how the game works at a high level:
 * 1. A challenger submits a Challenge py picking a general (the contract
 *    that has playing logic) and the fleet.
 * 2. Anyone can then then accept this challenge. (To accept the challenge
 *    you need to provide your own general and fleet). Accepting the
 *    challenge locks a battle between the challenger and the caller.
 * 3. At this point, nothing can be modified about the game. Next step is
 *    to reveal your fleet and start the battle. Both of these operations
 *    can be performed by a 3rd party facilitator that will be compensated
 *    by a percentage of game bid.

 * (Fleet reveal is necessary because fleet is initially obfuscated by
 * providing only the hash of the fleet. This is so that opponents don't
 * know each other's fleet before the battle begins).
 */
contract Game {
    // -------------------------------------------- EVENTS --------------------------------------------

    event ChallengeSubmitted(
        bytes32 indexed challengeHash,
        uint256 indexed bidAmount,
        address indexed general,
        uint96 fleetHash,
        uint96 facilitatorPercentage,
        address preferredOpponent
    );
    event ChallengeAccepted(
        bytes32 indexed challengeHash,
        address indexed general,
        uint96 fleetHash
    );
    event ChallengeModified(
        bytes32 indexed challengeHash,
        uint256 indexed bidAmount,
        uint96 facilitatorPercentage,
        address preferredOpponent
    );
    event ChallengeWithdrawn(bytes32 indexed challengeHash);
    event FleetRevealed(
        uint96 indexed fleetHash,
        uint256 indexed fleet,
        bytes32 salt
    );
    event BattleConcluded(
        bytes32 indexed challengeHash,
        address indexed challengerGeneral,
        address indexed callerGeneral,
        uint256 challengerBoard,
        uint256 callerBoard,
        uint256 bidAmount,
        uint256 facilitatorPercentage,
        uint256 winnerIdx,
        uint256 outcome,
        uint256[] gameHistory,
        uint256 maxTurns
    );

    // ---------------- LOGIC FOR SUBMITTING/ACCEPTING/MODIFYING/WITHDRAWING CHALLENGES ----------------

    struct Challenge {
        Gear challenger; // initiator of the challenge
        Gear caller; // acceptor of the challenge
        // The rest is optional
        uint256 bidAmount; // can be 0 if not bidding any ETH
        uint96 facilitatorPercentage; // percentage of the bid rewarded for calling startBattle
        IGeneral preferredOpponent; // set by the challenger. If non-zero, then only preferredOpponent can accept the challenge
    }

    // gear brought to the game
    struct Gear {
        IGeneral general; // the general that contains the playing logic
        uint96 fleetHash; // hash of the fleet
        // hash is necessary so that players don't know each other fleet.
        // see revealFleet to understand how hash is computed.
        // using 96 bits for the hash so that entire struct is one word.
    }

    // challengeHash to Challenge
    mapping(bytes32 => Challenge) public challenges;
    // all challengeHashes
    bytes32[] public challengeHashes;

    function getAllChallenges()
        external
        view
        returns (Challenge[] memory allChallenges)
    {
        allChallenges = new Challenge[](challengeHashes.length);
        for (uint256 i = 0; i < allChallenges.length; i++) {
            allChallenges[i] = challenges[challengeHashes[i]];
        }
    }

    function _hashChallenge(Gear memory challengerGear)
        private
        pure
        returns (bytes32)
    {
        // challenger's gear is hashed as a way to "lock" the selected general and fleetHash.
        // but, the internal logic of the general can still be modified
        return
            keccak256(
                abi.encodePacked(
                    challengerGear.general,
                    challengerGear.fleetHash
                )
            );
    }

    modifier onlyOwnerOfGeneral(IGeneral general) {
        // check so players dont use other ppls code. Credit: 0xBeans
        if (general.owner() != msg.sender) revert NotYourGeneral();
        _;
    }

    function isChallengerGeneralSet(bytes32 challengeHash)
        private
        view
        returns (bool)
    {
        return
            address(challenges[challengeHash].challenger.general) != address(0);
    }

    function isCallerGeneralSet(bytes32 challengeHash)
        private
        view
        returns (bool)
    {
        return address(challenges[challengeHash].caller.general) != address(0);
    }

    // constant to scale uints into percentages (1e4 == 100%)
    uint96 private constant PERCENTAGE_SCALE = 1e4;

    function submitChallenge(
        Gear calldata gear,
        uint96 facilitatorPercentage,
        IGeneral preferredOpponent
    ) external payable onlyOwnerOfGeneral(gear.general) {
        bytes32 challengeHash = _hashChallenge(gear);
        if (isChallengerGeneralSet(challengeHash))
            revert ChallengeAldreadyExists();
        if (facilitatorPercentage > PERCENTAGE_SCALE)
            revert FaciliatorPercentageUnitsWrong();

        challenges[challengeHash].challenger = gear;
        challenges[challengeHash].bidAmount = msg.value;
        challenges[challengeHash].facilitatorPercentage = facilitatorPercentage;
        challenges[challengeHash].preferredOpponent = preferredOpponent;
        challengeHashes.push(challengeHash);

        emit ChallengeSubmitted(
            challengeHash,
            msg.value,
            address(gear.general),
            gear.fleetHash,
            facilitatorPercentage,
            address(preferredOpponent)
        );
    }

    function acceptChallenge(Gear calldata gear, bytes32 challengeHash)
        external
        payable
        onlyOwnerOfGeneral(gear.general)
    {
        if (!isChallengerGeneralSet(challengeHash))
            revert ChallengeDoesNotExist();
        if (isCallerGeneralSet(challengeHash)) revert ChallengeAldreadyLocked();

        IGeneral preferredOpponent = challenges[challengeHash]
            .preferredOpponent;
        if (
            address(preferredOpponent) != address(0) &&
            preferredOpponent != gear.general
        ) revert ChallengerDoesNotWantToPlayAgainstYou();

        if (msg.value < challenges[challengeHash].bidAmount)
            revert NotEnoughEth();

        // lock the challenge by making caller non-null
        challenges[challengeHash].caller = gear;

        emit ChallengeAccepted(
            challengeHash,
            address(gear.general),
            gear.fleetHash
        );
    }

    function modifyChallenge(
        Gear calldata oldGear,
        uint256 newBidAmount,
        uint96 newFacilitatorPercentage,
        IGeneral newPreferredOpponent
    ) external payable onlyOwnerOfGeneral(oldGear.general) {
        bytes32 challengeHash = _hashChallenge(oldGear);
        if (!isChallengerGeneralSet(challengeHash))
            revert ChallengeDoesNotExist();
        if (isCallerGeneralSet(challengeHash)) revert ChallengeAldreadyLocked();
        if (newFacilitatorPercentage > PERCENTAGE_SCALE)
            revert FaciliatorPercentageUnitsWrong();

        uint256 oldBidAmount = challenges[challengeHash].bidAmount;
        if (newBidAmount > oldBidAmount) {
            if (msg.value < (newBidAmount - oldBidAmount))
                revert NotEnoughEth();
        } else if (newBidAmount < oldBidAmount) {
            payable(msg.sender).transfer(oldBidAmount - newBidAmount);
        }
        challenges[challengeHash].bidAmount = newBidAmount;
        challenges[challengeHash]
            .facilitatorPercentage = newFacilitatorPercentage;
        challenges[challengeHash].preferredOpponent = newPreferredOpponent;

        emit ChallengeModified(
            challengeHash,
            newBidAmount,
            newFacilitatorPercentage,
            address(newPreferredOpponent)
        );
    }

    function withdrawChallenge(Gear calldata gear, uint256 challengeIdx)
        external
        onlyOwnerOfGeneral(gear.general)
    {
        bytes32 challengeHash = _hashChallenge(gear);
        if (isCallerGeneralSet(challengeHash)) revert ChallengeAldreadyLocked();

        uint256 bidAmount = challenges[challengeHash].bidAmount;
        if (bidAmount > 0) {
            payable(msg.sender).transfer(bidAmount);
        }

        if (challengeHashes[challengeIdx] != challengeHash)
            revert InvalidChallengeIndex();

        delete challenges[challengeHash];
        challengeHashes[challengeIdx] = challengeHashes[
            challengeHashes.length - 1
        ];
        challengeHashes.pop();

        emit ChallengeWithdrawn(challengeHash);
    }

    // -------------------------------------- LOGIC FOR REVEALING FLEET --------------------------------------

    // fleet uses 64 bits. See Fleet library for the layout of bits
    using Fleet for uint256;
    // board uses 192 bits. See Board library for the layout of bits
    using Board for uint256;

    struct FleetAndBoard {
        // in storage we only store what's necessary in order to bit-pack
        uint64 fleet;
        uint192 board;
    }

    // fleetHash to FleetAndBoard
    mapping(uint96 => FleetAndBoard) public fleetsAndBoards;

    function revealFleetsAndStartBattle(
        uint96 fleetHash1,
        uint256 fleet1,
        bytes32 salt1,
        uint96 fleetHash2,
        uint256 fleet2,
        bytes32 salt2,
        bytes32 challengeHash,
        uint256 challengeIdx,
        uint256 maxTurns,
        address facilitatorFeeAddress
    ) external {
        revealFleet(fleetHash1, fleet1, salt1);
        revealFleet(fleetHash2, fleet2, salt2);
        startBattle(
            challengeHash,
            challengeIdx,
            maxTurns,
            facilitatorFeeAddress
        );
    }

    function revealFleet(
        uint96 fleetHash,
        uint256 fleet,
        bytes32 salt
    ) public {
        // In order to obfuscate the fleet that a player starts with from the opponent,
        // we use fleetHash when commiting a/to Challenge.
        // After the challenge is accepted, the game is locked. Nothing can be changed about it.
        // So, now it's safe to reveal the fleet

        // in order to prevent memoization of fleet (rainbow attack), an optional salt can be
        // used to make it harder to reverse the hashing operation. salt can be any data.

        if (
            fleetHash !=
            uint96(uint256(keccak256(abi.encodePacked(fleet, salt))))
        ) revert InvalidFleetHash();

        // this function not only makes sure that the revealed fleet actually corresponds to the
        // provided fleetHash earlier, but also makes sure that fleet obeys the rules of the game,
        // i.e. correct number of ships, correct placement, etc.
        uint256 board = fleet.validateFleetAndConvertToBoard();

        // also store the board representation of the fleet for faster lookup
        fleetsAndBoards[fleetHash] = FleetAndBoard(
            uint64(fleet),
            uint192(board)
        );

        emit FleetRevealed(fleetHash, fleet, salt);
    }

    // ------------------------------------ LOGIC FOR PLAYING THE GAME ------------------------------------

    // attacks are represented using 192 bits. See Attacks library for the layout of bits
    using Attacks for uint256;

    uint256 internal constant OUTCOME_DRAW = 5;
    uint256 internal constant OUTCOME_ELIMINATED_OPPONENT = 1;
    uint256 internal constant OUTCOME_INFLICTED_MORE_DAMAGE = 2;
    uint256 internal constant NO_WINNER = 5;

    // To avoid stack too deep errors, use a struct to pack all game vars into one var
    // https://medium.com/1milliondevs/compilererror-stack-too-deep-try-removing-local-variables-solved-a6bcecc16231
    struct GameState {
        // The first 3 arrays are constant
        // TODO is it possible to shave off gas due to them being constant?
        IGeneral[2] generals;
        uint256[2] fleets;
        uint256[2] boards;
        // everything else is not constant
        uint256[2] attacks;
        uint256[2] lastMoves;
        uint256[2] opponentsDiscoveredFleet;
        uint256[5][2] remainingCells;
        uint256 currentPlayerIdx;
        uint256 otherPlayerIdx;
        uint256 winnerIdx;
        uint256 outcome;
        uint256[] gameHistory;
    }

    function startBattle(
        bytes32 challengeHash,
        uint256 challengeIdx,
        uint256 maxTurns,
        address facilitatorFeeAddress
    ) public {
        GameState memory gs = _getInitialGameState(challengeHash, maxTurns);

        if (address(gs.generals[1]) == address(0))
            revert ChallengeNeedsToBeLocked();
        if (gs.fleets[0] == 0 || gs.fleets[1] == 0)
            revert FleetsNeedToHaveBeenRevealed();
        if (
            ((maxTurns % 2) != 0) || (maxTurns < 21) // 21 is the least amount of moves to win the game
        ) revert InvalidMaxTurns();

        uint256 i;
        for (; i < maxTurns; i++) {
            gs.otherPlayerIdx = (gs.currentPlayerIdx + 1) % 2;

            uint256 returnedVal;
            uint256 cellToFire;
            try
                gs.generals[gs.currentPlayerIdx].fire{gas: 5_000}(
                    gs.boards[gs.currentPlayerIdx],
                    gs.attacks[gs.currentPlayerIdx],
                    gs.attacks[gs.otherPlayerIdx],
                    gs.lastMoves[gs.currentPlayerIdx],
                    gs.lastMoves[gs.otherPlayerIdx],
                    gs.opponentsDiscoveredFleet[gs.currentPlayerIdx]
                )
            returns (uint256 ret) {
                returnedVal = ret;
                cellToFire = ret & 63; // take last 6 bits only. 63 is 111111 in binary
            } catch {}

            gs.gameHistory[i + 1] = cellToFire;
            gs.lastMoves[gs.currentPlayerIdx] = returnedVal;

            // duplicate moves are ok
            if (
                !gs.attacks[gs.currentPlayerIdx].isOfType(
                    cellToFire,
                    Attacks.UNTOUCHED
                )
            ) {
                gs.currentPlayerIdx = gs.otherPlayerIdx;
                continue;
            }

            uint256 hitShipType = gs.boards[gs.otherPlayerIdx].getShipAt(
                cellToFire
            );

            if (hitShipType == Fleet.EMPTY) {
                gs.attacks[gs.currentPlayerIdx] = gs
                    .attacks[gs.currentPlayerIdx]
                    .markAs(cellToFire, Attacks.MISS);
                gs.currentPlayerIdx = gs.otherPlayerIdx;
                continue;
            }

            // it's a hit
            gs.attacks[gs.currentPlayerIdx] = gs
                .attacks[gs.currentPlayerIdx]
                .markAs(cellToFire, Attacks.HIT);

            // decrement number of cells remaining for the hit ship
            uint256 hitShipRemainingCells = --gs.remainingCells[
                gs.otherPlayerIdx
            ][hitShipType - 1];

            if (hitShipRemainingCells == 0) {
                // ship destroyed

                if (gs.attacks[gs.currentPlayerIdx].hasWon()) {
                    gs.winnerIdx = gs.currentPlayerIdx;
                    gs.outcome = OUTCOME_ELIMINATED_OPPONENT;
                    gs.gameHistory[i + 2] = 255;
                    break;
                }

                gs.opponentsDiscoveredFleet[gs.currentPlayerIdx] = gs
                    .fleets[gs.otherPlayerIdx]
                    .copyShipTo(
                        gs.opponentsDiscoveredFleet[gs.currentPlayerIdx],
                        uint8(hitShipType)
                    );
            }

            gs.currentPlayerIdx = gs.otherPlayerIdx;
        }

        if (gs.winnerIdx == NO_WINNER) {
            // game terminated due to maxTotalTurns
            gs.gameHistory[i + 1] = 255;

            uint256 numberOfShipDestroyed0 = _getNumberOfDestroyedShips(
                gs.remainingCells,
                0
            );
            uint256 numberOfShipDestroyed1 = _getNumberOfDestroyedShips(
                gs.remainingCells,
                1
            );

            if (numberOfShipDestroyed0 > numberOfShipDestroyed1) {
                gs.winnerIdx = 0;
                gs.outcome = OUTCOME_INFLICTED_MORE_DAMAGE;
            } else if (numberOfShipDestroyed0 < numberOfShipDestroyed1) {
                gs.winnerIdx = 1;
                gs.outcome = OUTCOME_INFLICTED_MORE_DAMAGE;
            } // else draw
        }

        distributeFunds(challengeHash, gs, maxTurns, facilitatorFeeAddress);

        if (challengeHashes[challengeIdx] != challengeHash)
            revert InvalidChallengeIndex();

        delete challenges[challengeHash];
        challengeHashes[challengeIdx] = challengeHashes[
            challengeHashes.length - 1
        ];
        challengeHashes.pop();
    }

    function distributeFunds(
        bytes32 challengeHash,
        GameState memory gs,
        uint256 maxTurns,
        address facilitatorFeeAddress
    ) private {
        uint256 bidAmount = challenges[challengeHash].bidAmount;
        uint256 amountToSplit = 2 * bidAmount;
        uint256 facilitatorPercentage = challenges[challengeHash]
            .facilitatorPercentage;

        if (amountToSplit > 0) {
            uint256 facilitatorFee = (amountToSplit * facilitatorPercentage) /
                PERCENTAGE_SCALE;
            payable(facilitatorFeeAddress).transfer(facilitatorFee);

            if (gs.winnerIdx == NO_WINNER) {
                amountToSplit = (amountToSplit - facilitatorFee) / 2;
                payable(gs.generals[0].owner()).transfer(amountToSplit);
                payable(gs.generals[1].owner()).transfer(amountToSplit);
            } else {
                amountToSplit -= facilitatorFee;
                payable(gs.generals[gs.winnerIdx].owner()).transfer(
                    amountToSplit
                );
            }
        }

        emit BattleConcluded(
            challengeHash,
            address(gs.generals[0]),
            address(gs.generals[1]),
            gs.boards[0],
            gs.boards[1],
            bidAmount,
            facilitatorPercentage,
            gs.winnerIdx,
            gs.outcome,
            gs.gameHistory,
            maxTurns
        );
    }

    function _getInitialGameState(bytes32 challengeHash, uint256 maxTurns)
        private
        view
        returns (GameState memory initialGameState)
    {
        initialGameState.generals = [
            challenges[challengeHash].challenger.general,
            challenges[challengeHash].caller.general
        ];

        {
            FleetAndBoard[2] memory fleetAndBoardsCached = [
                fleetsAndBoards[challenges[challengeHash].challenger.fleetHash],
                fleetsAndBoards[challenges[challengeHash].caller.fleetHash]
            ];
            initialGameState.fleets = [
                uint256(fleetAndBoardsCached[0].fleet),
                uint256(fleetAndBoardsCached[1].fleet)
            ];
            initialGameState.boards = [
                uint256(fleetAndBoardsCached[0].board),
                uint256(fleetAndBoardsCached[1].board)
            ];
        }

        initialGameState.attacks = [
            Attacks.EMPTY_ATTACKS,
            Attacks.EMPTY_ATTACKS
        ];
        initialGameState.lastMoves = [uint256(255), uint256(255)]; // initialize with 255 which indicates start of the game.
        //                                        valid moves are indicies into the 8x8 board, i.e. [0, 64)
        initialGameState.opponentsDiscoveredFleet = [
            Fleet.EMPTY_FLEET,
            Fleet.EMPTY_FLEET
        ];
        initialGameState.remainingCells = [
            [
                Fleet.PATROL_LENGTH,
                Fleet.DESTROYER_LENGTH,
                Fleet.DESTROYER_LENGTH,
                Fleet.CARRIER_LENGTH * Fleet.CARRIER_WIDTH,
                Fleet.BATTLESHIP_LENGTH
            ],
            [
                Fleet.PATROL_LENGTH,
                Fleet.DESTROYER_LENGTH,
                Fleet.DESTROYER_LENGTH,
                Fleet.CARRIER_LENGTH * Fleet.CARRIER_WIDTH,
                Fleet.BATTLESHIP_LENGTH
            ]
        ];

        // need to randomly choose first general to start firing.
        // use the timestamp as random input
        initialGameState.currentPlayerIdx = uint256(block.timestamp) % 2;

        initialGameState.winnerIdx = NO_WINNER;
        initialGameState.outcome = OUTCOME_DRAW;

        // used for emitting gameHistory in the event. first item in the history is the
        // idx of the first player to fire. Last item is 255 which indicates end of game.
        // the rest of the items are cells fired by players
        initialGameState.gameHistory = new uint256[](maxTurns + 2);
        initialGameState.gameHistory[0] = initialGameState.currentPlayerIdx;
    }

    function _getNumberOfDestroyedShips(
        uint256[5][2] memory remainingCells,
        uint256 playerIdx
    ) private pure returns (uint256 numberOfDestroyedShips) {
        for (uint256 i = 0; i < 5; i++) {
            if (remainingCells[playerIdx][i] == 0) {
                numberOfDestroyedShips++;
            }
        }
    }
}

File 2 of 5 : IGeneral.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

interface IGeneral {
    // nickname of your general
    function name() external view returns (string memory);

    // must be the address you will be calling the Game contract from.
    // this value is to check that no one else is using your code to play. credit: 0xBeans
    function owner() external view returns (address);

    // this function needs to return an index into the 8x8 board, i.e. a value between [0 and 64).
    // a shell will be fired at this location. if you return >= 64, you're TKO'd
    // you're constrained by gas in this function. Check Game contract for max_gas
    // check Board library for the layout of bits of myBoard
    // check Attacks library for the layout of bits of attacks
    // check Fleet library for the layout of bits of fleet. Non-discovered fleet will have both,
    // the start and end coords =0
    function fire(
        uint256 myBoard,
        uint256 myAttacks,
        uint256 opponentsAttacks,
        uint256 myLastMove,
        uint256 opponentsLastMove,
        uint256 opponentsDiscoveredFleet
    ) external returns (uint256);
}

File 3 of 5 : Attacks.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

/**
 * Attacks are represented using 256 bits but only the rightmost 192 bits are used.
 * Bit layout of the 192 bits:
 * [64 bits: whether a cell is a hit | 64 bits: whether a cell is a miss | 64 bits: whether a cell is untouched]
 * Each 64-bit piece has a layout like this:
 * [bit for 63rd cell | bit for 62nd cell | bit for 0th cell]
 */
library Attacks {
    // initializer for new battle. All cells are untouched
    uint256 internal constant EMPTY_ATTACKS = 0xFFFFFFFFFFFFFFFF;

    uint256 internal constant UNTOUCHED = 0;
    uint256 internal constant MISS = 1;
    uint256 internal constant HIT = 2;

    // zero_mask is same as [...63 zeros ... 1 ... 63 zeros ... 1 ... 63 zeros ... 1]
    uint256 private constant FIRST_CELL = 0x100000000000000010000000000000001;

    function isOfType(
        uint256 attacks,
        uint256 cellIdx,
        uint256 attackType
    ) internal pure returns (bool) {
        // cell of interest is at shiftBy = attackType * 64 + cellIdx = (attackType << 6) + cellIdx
        // need to check whether attacks & (1 << shiftBy) is non-zero
        return (attacks & (1 << ((attackType << 6) + cellIdx))) > 0;
    }

    function markAs(
        uint256 attacks,
        uint256 cellIdx,
        uint256 attackType
    ) internal pure returns (uint256 updatedAttacks) {
        // zeroMask is for zeroing out all attackTypes for a given cell
        uint256 zeroMask = ~(FIRST_CELL << cellIdx);
        // oneMask is for setting bit at attackType to 1
        uint256 oneMask = 1 << ((attackType << 6) + cellIdx);
        return (attacks & zeroMask) | oneMask;
    }

    function numberOfEmptyCells(uint256 attacks)
        internal
        pure
        returns (uint256)
    {
        return
            hammingDistance64(
                (attacks >> (UNTOUCHED << 6)) & 0xFFFFFFFFFFFFFFFF
            );
    }

    function numberOfMisses(uint256 attacks) internal pure returns (uint256) {
        return hammingDistance64((attacks >> (MISS << 6)) & 0xFFFFFFFFFFFFFFFF);
    }

    function numberOfHits(uint256 attacks) internal pure returns (uint256) {
        return hammingDistance64((attacks >> (HIT << 6)) & 0xFFFFFFFFFFFFFFFF);
    }

    function hasWon(uint256 attacks) internal pure returns (bool) {
        // hasWon is when numberOfHits == 21
        return
            hammingDistance64((attacks >> (HIT << 6)) & 0xFFFFFFFFFFFFFFFF) ==
            21; // 21 is total number of cells occupied by ships
    }

    function hammingDistance64(uint256 x) internal pure returns (uint256) {
        // Computes hamming distance (weight) of a 64-bit number.
        // Hamming distance is number of bits that are set to 1. See:
        // - https://en.wikipedia.org/wiki/Hamming_weight
        // - https://stackoverflow.com/questions/2709430/count-number-of-bits-in-a-64-bit-long-big-integer
        // and for 32-bit version see:
        // - http://graphics.stanford.edu/~seander/bithacks.html (Counting bits set, in parallel section)
        // - https://stackoverflow.com/questions/14555607/number-of-bits-set-in-a-number
        // - https://stackoverflow.com/questions/15233121/calculating-hamming-weight-in-o1

        // implementation from https://en.wikipedia.org/wiki/Hamming_weight
        x -= (x >> 1) & 0x5555555555555555; // put count of each 2 bits into those 2 bits
        x = (x & 0x3333333333333333) + ((x >> 2) & 0x3333333333333333); // put count of each 4 bits into those 4 bits
        x = (x + (x >> 4)) & 0x0f0f0f0f0f0f0f0f; // put count of each 8 bits into those 8 bits
        return uint64(x * 0x0101010101010101) >> 56; // returns left 8 bits of x + (x<<8) + (x<<16) + (x<<24) + ...
    }
}

File 4 of 5 : Fleet.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

import "./Board.sol";

error CoordsAreNotSorted(uint256 shipType);
error NotRightSizeOrOrientation(uint256 shipType);

/**
 * Board is represented using 256 bits, but only rightmost 64 bits are used. Bit layout of the 64 bits:
 * [4 empty bits | battleship start coord | battleship end coord | carrier start coord | ... | patrol end coord]
 * Each coord is 6 bits and it's an index into the 8x8 board, i.e. [0, 64)
 */
library Fleet {
    // initializer for undiscovered fleet
    uint256 internal constant EMPTY_FLEET = 0;

    // ship types
    uint256 internal constant EMPTY = 0;
    uint256 internal constant PATROL = 1;
    uint256 internal constant DESTROYER1 = 2;
    uint256 internal constant DESTROYER2 = 3;
    uint256 internal constant CARRIER = 4;
    uint256 internal constant BATTLESHIP = 5;

    // ship sizes
    uint256 internal constant PATROL_LENGTH = 2;
    uint256 internal constant DESTROYER_LENGTH = 3;
    uint256 internal constant CARRIER_LENGTH = 4;
    uint256 internal constant CARRIER_WIDTH = 2;
    uint256 internal constant BATTLESHIP_LENGTH = 5;

    function getCoords(uint256 fleet, uint256 shipType)
        internal
        pure
        returns (uint256)
    {
        // each ship takes up 2*6=12 bits. Need to shift right by
        // correct number of bits and take only the remaining 12 bits (0xFFF is 12 ones)
        return (fleet >> (12 * (shipType - 1))) & 0xFFF;
    }

    // populate toFleet with the coords of shipType from fromFleet
    function copyShipTo(
        uint256 fromFleet,
        uint256 toFleet,
        uint256 shipType
    ) internal pure returns (uint256) {
        uint256 selectShip = 0xFFF << (shipType - 1); // 0xFFF is 12 ones
        return (fromFleet & selectShip) | (toFleet & ~selectShip);
    }

    using Board for Board.BuildData;

    // This struct is only used to avoid stack too deep errors, use a struct to pack all vars into one var
    // https://medium.com/1milliondevs/compilererror-stack-too-deep-try-removing-local-variables-solved-a6bcecc16231
    struct Coords {
        uint256 start;
        uint256 end;
        uint256 diff;
        uint256 horizontal;
        uint256 vertical;
    }

    // only used in Game.revealBoard to validate the fleet and store the board representation
    // of the fleet for faster lookup
    function validateFleetAndConvertToBoard(uint256 fleet)
        internal
        pure
        returns (uint256)
    {
        // make sure that the fleet is properly formatted: ships have the right size and
        // orientation (either horizontal or vertical)

        // ------------------------------ PATROL ship validation ------------------------------
        Coords memory patrolCoords;
        uint256 tmpCoords = getCoords(fleet, PATROL);
        patrolCoords.start = tmpCoords >> 6;
        patrolCoords.end = tmpCoords & 0x3F;
        // start and end are guaranteed to be within [0, 64)
        // because we mask out the leading bits in getCoords[X]
        if (patrolCoords.start >= patrolCoords.end)
            revert CoordsAreNotSorted(PATROL);

        patrolCoords.diff = patrolCoords.end - patrolCoords.start;
        patrolCoords.horizontal = PATROL_LENGTH - 1;
        // required difference between end and start coords of Patrol ship in horizontal orientation
        patrolCoords.vertical = patrolCoords.horizontal << 3; // "<< 3" is same as "* 8"
        // required difference in vertical orientation (because indices wrap around the 8x8 board)
        if (
            !(patrolCoords.diff == patrolCoords.horizontal ||
                patrolCoords.diff == patrolCoords.vertical)
        ) revert NotRightSizeOrOrientation(PATROL);

        // ------------------------------ DESTROYER1 ship validation ------------------------------
        Coords memory destroyer1Coords;
        tmpCoords = getCoords(fleet, DESTROYER1);
        destroyer1Coords.start = tmpCoords >> 6;
        destroyer1Coords.end = tmpCoords & 0x3F;
        if (destroyer1Coords.start >= destroyer1Coords.end)
            revert CoordsAreNotSorted(DESTROYER1);

        destroyer1Coords.diff = destroyer1Coords.end - destroyer1Coords.start;
        destroyer1Coords.horizontal = DESTROYER_LENGTH - 1;
        destroyer1Coords.vertical = destroyer1Coords.horizontal << 3;
        if (
            !(destroyer1Coords.diff == destroyer1Coords.horizontal ||
                destroyer1Coords.diff == destroyer1Coords.vertical)
        ) revert NotRightSizeOrOrientation(DESTROYER1);

        // ------------------------------ DESTROYER2 ship validation ------------------------------
        Coords memory destroyer2Coords;
        tmpCoords = getCoords(fleet, DESTROYER2);
        destroyer2Coords.start = tmpCoords >> 6;
        destroyer2Coords.end = tmpCoords & 0x3F;
        if (destroyer2Coords.start >= destroyer2Coords.end)
            revert CoordsAreNotSorted(DESTROYER2);

        destroyer2Coords.diff = destroyer2Coords.end - destroyer2Coords.start;
        if (
            !(destroyer2Coords.diff == destroyer1Coords.horizontal ||
                destroyer2Coords.diff == destroyer1Coords.vertical)
        ) revert NotRightSizeOrOrientation(DESTROYER2);

        // ------------------------------ BATTLESHIP ship validation ------------------------------
        Coords memory battleshipCoords;
        tmpCoords = getCoords(fleet, BATTLESHIP);
        battleshipCoords.start = tmpCoords >> 6;
        battleshipCoords.end = tmpCoords & 0x3F;
        if (battleshipCoords.start >= battleshipCoords.end)
            revert CoordsAreNotSorted(BATTLESHIP);

        battleshipCoords.diff = battleshipCoords.end - battleshipCoords.start;
        battleshipCoords.horizontal = BATTLESHIP_LENGTH - 1;
        battleshipCoords.vertical = battleshipCoords.horizontal << 3;
        if (
            !(battleshipCoords.diff == battleshipCoords.horizontal ||
                battleshipCoords.diff == battleshipCoords.vertical)
        ) revert NotRightSizeOrOrientation(BATTLESHIP);

        // ------------------------------ CARRIER ship validation ------------------------------
        Coords memory carrierCoords;
        tmpCoords = getCoords(fleet, CARRIER);
        carrierCoords.start = tmpCoords >> 6;
        carrierCoords.end = tmpCoords & 0x3F;
        if (carrierCoords.start >= carrierCoords.end)
            revert CoordsAreNotSorted(CARRIER);

        carrierCoords.diff = carrierCoords.end - carrierCoords.start;
        carrierCoords.horizontal =
            (CARRIER_LENGTH - 1) +
            ((CARRIER_WIDTH - 1) << 3); // carrier size is 4x2
        carrierCoords.vertical =
            ((CARRIER_LENGTH - 1) << 3) +
            (CARRIER_WIDTH - 1);
        if (
            !(carrierCoords.diff == carrierCoords.horizontal ||
                carrierCoords.diff == carrierCoords.vertical)
        ) revert NotRightSizeOrOrientation(CARRIER);

        // ------------------------------ building the board ------------------------------
        // This piece converts the fleet into 8x8 board representation.
        // It also validates that ships don't overlap and that
        // ships are not too close.

        // construct the board from fleet info
        Board.BuildData memory constructedBoard = Board.BuildData(0, 0);
        constructedBoard.placeShip(
            patrolCoords.start,
            patrolCoords.end,
            PATROL
        );
        constructedBoard.placeShip(
            destroyer1Coords.start,
            destroyer1Coords.end,
            DESTROYER1
        );
        constructedBoard.placeShip(
            destroyer2Coords.start,
            destroyer2Coords.end,
            DESTROYER2
        );
        constructedBoard.placeShip(
            carrierCoords.start,
            carrierCoords.end,
            CARRIER
        );
        constructedBoard.placeShip(
            battleshipCoords.start,
            battleshipCoords.end,
            BATTLESHIP
        );
        return constructedBoard.board;
    }
}

File 5 of 5 : Board.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

error CantWrapShip(uint256 shipType);
error ShipCollidesOrTooClose(uint256 shipType);

/**
 * Board is represented using 256 bits, but only rightmost 192 bits are used. Bit layout of the 192 bits:
 * [3 bits: 63rd cell | 3 bits: 62nd cell | ... | 3 bits: 0th cell]
 * Each cell is 3 bits and it indicates shipType (1,2,3,4,5) or empty (0) at that cell.
 * The shipType values are from Fleet.PATROL, Fleet.DESTROYER1, etc.
 */
library Board {
    function getShipAt(uint256 board, uint256 cellIdx)
        internal
        pure
        returns (uint256)
    {
        return (board >> (cellIdx * 3)) & 0x7;
    }

    // ---------- Helper to build a board from its fleet representation ----------
    struct BuildData {
        uint256 board;
        uint256 occupancyGrid; // all 3 bits at each cell will be 1 if there is a ship at a given cell
    }

    // assumes startCoord < endCoord
    function placeShip(
        BuildData memory buildData,
        uint256 startCoord,
        uint256 endCoord,
        uint256 shipType
    ) internal pure {
        // TODO is there a constant time bit operation that we can use instead of a loop in the function?
        uint256 startY = startCoord >> 3; // divide by 8
        uint256 endY = endCoord >> 3;
        uint256 startX = startCoord % 8;
        uint256 endX = endCoord % 8;

        if (startX > endX) revert CantWrapShip(shipType);

        uint256 ship; // cells occupied by this ship
        for (uint256 y = startY; y <= endY; y++) {
            for (uint256 x = startX; x <= endX; x++) {
                // to mark the cell we need to do shipType << (3 * cellIdx)
                // where cellIdx = y * 8 + x = (y << 3) + x
                ship |= shipType << (3 * ((y << 3) + x));
            }
        }
        if (ship & buildData.occupancyGrid != 0)
            revert ShipCollidesOrTooClose(shipType);

        if (startX > 0) {
            startX--;
        }
        if (startY > 0) {
            startY--;
        }
        if (endX < 7) {
            endX++;
        }
        if (endY < 7) {
            endY++;
        }
        uint256 shipAndAdjacent; // cells occupied by this ship and a padding of 1
        // You can't place another ship close than this padding
        for (uint256 y = startY; y <= endY; y++) {
            for (uint256 x = startX; x <= endX; x++) {
                // we do the same as in the above loop but use 111=0x7 instead of shipType
                shipAndAdjacent |= 0x7 << (3 * ((y << 3) + x));
            }
        }

        buildData.board |= ship;
        buildData.occupancyGrid |= shipAndAdjacent;
    }
}

Settings
{
  "remappings": [
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "forge-std/=lib/forge-std/src/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "bytecodeHash": "ipfs"
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "london",
  "libraries": {}
}

Contract ABI

[{"inputs":[{"internalType":"uint256","name":"shipType","type":"uint256"}],"name":"CantWrapShip","type":"error"},{"inputs":[],"name":"ChallengeAldreadyExists","type":"error"},{"inputs":[],"name":"ChallengeAldreadyLocked","type":"error"},{"inputs":[],"name":"ChallengeDoesNotExist","type":"error"},{"inputs":[],"name":"ChallengeNeedsToBeLocked","type":"error"},{"inputs":[],"name":"ChallengerDoesNotWantToPlayAgainstYou","type":"error"},{"inputs":[{"internalType":"uint256","name":"shipType","type":"uint256"}],"name":"CoordsAreNotSorted","type":"error"},{"inputs":[],"name":"FaciliatorPercentageUnitsWrong","type":"error"},{"inputs":[],"name":"FleetsNeedToHaveBeenRevealed","type":"error"},{"inputs":[],"name":"InvalidChallengeIndex","type":"error"},{"inputs":[],"name":"InvalidFleetHash","type":"error"},{"inputs":[],"name":"InvalidMaxTurns","type":"error"},{"inputs":[],"name":"NotEnoughEth","type":"error"},{"inputs":[{"internalType":"uint256","name":"shipType","type":"uint256"}],"name":"NotRightSizeOrOrientation","type":"error"},{"inputs":[],"name":"NotYourGeneral","type":"error"},{"inputs":[{"internalType":"uint256","name":"shipType","type":"uint256"}],"name":"ShipCollidesOrTooClose","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"challengeHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"challengerGeneral","type":"address"},{"indexed":true,"internalType":"address","name":"callerGeneral","type":"address"},{"indexed":false,"internalType":"uint256","name":"challengerBoard","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"callerBoard","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"bidAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"facilitatorPercentage","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"winnerIdx","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"outcome","type":"uint256"},{"indexed":false,"internalType":"uint256[]","name":"gameHistory","type":"uint256[]"},{"indexed":false,"internalType":"uint256","name":"maxTurns","type":"uint256"}],"name":"BattleConcluded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"challengeHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"general","type":"address"},{"indexed":false,"internalType":"uint96","name":"fleetHash","type":"uint96"}],"name":"ChallengeAccepted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"challengeHash","type":"bytes32"},{"indexed":true,"internalType":"uint256","name":"bidAmount","type":"uint256"},{"indexed":false,"internalType":"uint96","name":"facilitatorPercentage","type":"uint96"},{"indexed":false,"internalType":"address","name":"preferredOpponent","type":"address"}],"name":"ChallengeModified","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"challengeHash","type":"bytes32"},{"indexed":true,"internalType":"uint256","name":"bidAmount","type":"uint256"},{"indexed":true,"internalType":"address","name":"general","type":"address"},{"indexed":false,"internalType":"uint96","name":"fleetHash","type":"uint96"},{"indexed":false,"internalType":"uint96","name":"facilitatorPercentage","type":"uint96"},{"indexed":false,"internalType":"address","name":"preferredOpponent","type":"address"}],"name":"ChallengeSubmitted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"challengeHash","type":"bytes32"}],"name":"ChallengeWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint96","name":"fleetHash","type":"uint96"},{"indexed":true,"internalType":"uint256","name":"fleet","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"salt","type":"bytes32"}],"name":"FleetRevealed","type":"event"},{"inputs":[{"components":[{"internalType":"contract IGeneral","name":"general","type":"address"},{"internalType":"uint96","name":"fleetHash","type":"uint96"}],"internalType":"struct Game.Gear","name":"gear","type":"tuple"},{"internalType":"bytes32","name":"challengeHash","type":"bytes32"}],"name":"acceptChallenge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"challengeHashes","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"challenges","outputs":[{"components":[{"internalType":"contract IGeneral","name":"general","type":"address"},{"internalType":"uint96","name":"fleetHash","type":"uint96"}],"internalType":"struct Game.Gear","name":"challenger","type":"tuple"},{"components":[{"internalType":"contract IGeneral","name":"general","type":"address"},{"internalType":"uint96","name":"fleetHash","type":"uint96"}],"internalType":"struct Game.Gear","name":"caller","type":"tuple"},{"internalType":"uint256","name":"bidAmount","type":"uint256"},{"internalType":"uint96","name":"facilitatorPercentage","type":"uint96"},{"internalType":"contract IGeneral","name":"preferredOpponent","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint96","name":"","type":"uint96"}],"name":"fleetsAndBoards","outputs":[{"internalType":"uint64","name":"fleet","type":"uint64"},{"internalType":"uint192","name":"board","type":"uint192"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAllChallenges","outputs":[{"components":[{"components":[{"internalType":"contract IGeneral","name":"general","type":"address"},{"internalType":"uint96","name":"fleetHash","type":"uint96"}],"internalType":"struct Game.Gear","name":"challenger","type":"tuple"},{"components":[{"internalType":"contract IGeneral","name":"general","type":"address"},{"internalType":"uint96","name":"fleetHash","type":"uint96"}],"internalType":"struct Game.Gear","name":"caller","type":"tuple"},{"internalType":"uint256","name":"bidAmount","type":"uint256"},{"internalType":"uint96","name":"facilitatorPercentage","type":"uint96"},{"internalType":"contract IGeneral","name":"preferredOpponent","type":"address"}],"internalType":"struct Game.Challenge[]","name":"allChallenges","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"contract IGeneral","name":"general","type":"address"},{"internalType":"uint96","name":"fleetHash","type":"uint96"}],"internalType":"struct Game.Gear","name":"oldGear","type":"tuple"},{"internalType":"uint256","name":"newBidAmount","type":"uint256"},{"internalType":"uint96","name":"newFacilitatorPercentage","type":"uint96"},{"internalType":"contract IGeneral","name":"newPreferredOpponent","type":"address"}],"name":"modifyChallenge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint96","name":"fleetHash","type":"uint96"},{"internalType":"uint256","name":"fleet","type":"uint256"},{"internalType":"bytes32","name":"salt","type":"bytes32"}],"name":"revealFleet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint96","name":"fleetHash1","type":"uint96"},{"internalType":"uint256","name":"fleet1","type":"uint256"},{"internalType":"bytes32","name":"salt1","type":"bytes32"},{"internalType":"uint96","name":"fleetHash2","type":"uint96"},{"internalType":"uint256","name":"fleet2","type":"uint256"},{"internalType":"bytes32","name":"salt2","type":"bytes32"},{"internalType":"bytes32","name":"challengeHash","type":"bytes32"},{"internalType":"uint256","name":"challengeIdx","type":"uint256"},{"internalType":"uint256","name":"maxTurns","type":"uint256"},{"internalType":"address","name":"facilitatorFeeAddress","type":"address"}],"name":"revealFleetsAndStartBattle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"challengeHash","type":"bytes32"},{"internalType":"uint256","name":"challengeIdx","type":"uint256"},{"internalType":"uint256","name":"maxTurns","type":"uint256"},{"internalType":"address","name":"facilitatorFeeAddress","type":"address"}],"name":"startBattle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"contract IGeneral","name":"general","type":"address"},{"internalType":"uint96","name":"fleetHash","type":"uint96"}],"internalType":"struct Game.Gear","name":"gear","type":"tuple"},{"internalType":"uint96","name":"facilitatorPercentage","type":"uint96"},{"internalType":"contract IGeneral","name":"preferredOpponent","type":"address"}],"name":"submitChallenge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"contract IGeneral","name":"general","type":"address"},{"internalType":"uint96","name":"fleetHash","type":"uint96"}],"internalType":"struct Game.Gear","name":"gear","type":"tuple"},{"internalType":"uint256","name":"challengeIdx","type":"uint256"}],"name":"withdrawChallenge","outputs":[],"stateMutability":"nonpayable","type":"function"}]

608060405234801561001057600080fd5b50612a07806100206000396000f3fe60806040526004361061009c5760003560e01c8063c1e69b6611610064578063c1e69b6614610142578063dc645241146101e6578063dde8ab7814610206578063e3f5675814610226578063e7db485c14610246578063f698bfe3146102b757600080fd5b80636090e61b146100a157806371c3c892146100b6578063829ef1ac146100c9578063a8af8a8d146100f4578063b7dde4d714610122575b600080fd5b6100b46100af366004612453565b6102ca565b005b6100b46100c43660046124a5565b610527565b3480156100d557600080fd5b506100de61075d565b6040516100eb91906124f1565b60405180910390f35b34801561010057600080fd5b5061011461010f366004612583565b6108ec565b6040519081526020016100eb565b34801561012e57600080fd5b506100b461013d36600461259c565b61090d565b34801561014e57600080fd5b506101d561015d366004612583565b600060208181529181526040908190208151808301835281546001600160a01b0380821683526001600160601b03600160a01b92839004811684880152855180870190965260018501548083168752929092048216958501959095526002830154600390930154919490821691600160601b90041685565b6040516100eb95949392919061262d565b3480156101f257600080fd5b506100b4610201366004612676565b61093b565b34801561021257600080fd5b506100b46102213660046124a5565b610a32565b34801561023257600080fd5b506100b46102413660046126ab565b610c71565b34801561025257600080fd5b5061028f6102613660046126e1565b60026020526000908152604090205467ffffffffffffffff811690600160401b90046001600160c01b031682565b6040805167ffffffffffffffff90931683526001600160c01b039091166020830152016100eb565b6100b46102c5366004612705565b611307565b6102d7602085018561274f565b336001600160a01b0316816001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561031f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610343919061276c565b6001600160a01b03161461036a5760405163388d0a1f60e01b815260040160405180910390fd5b600061038361037e3688900388018861279f565b611524565b6000818152602081905260409020549091506001600160a01b03166103ba57604051623126e360e41b815260040160405180910390fd5b6000818152602081905260409020600101546001600160a01b0316156103f35760405163123af06b60e01b815260040160405180910390fd5b6127106001600160601b038516111561041f576040516361d2bb0360e01b815260040160405180910390fd5b60008181526020819052604090206002015480861115610468576104438187612822565b3410156104635760405163f14a42b760e01b815260040160405180910390fd5b6104a8565b808610156104a857336108fc61047e8884612822565b6040518115909202916000818181858888f193505050501580156104a6573d6000803e3d6000fd5b505b60008281526020818152604091829020600281018990556001600160601b038816600160601b6001600160a01b0389169081028217600390930192909255835190815291820152879184917f6887717706805f48aaf66cb6e4877e11e8eb9270a65f625d62a0b47121851427910160405180910390a350505050505050565b610534602083018361274f565b336001600160a01b0316816001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561057c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105a0919061276c565b6001600160a01b0316146105c75760405163388d0a1f60e01b815260040160405180910390fd5b6000828152602081905260409020546001600160a01b03166105fb57604051623126e360e41b815260040160405180910390fd5b6000828152602081905260409020600101546001600160a01b0316156106345760405163123af06b60e01b815260040160405180910390fd5b600082815260208190526040902060030154600160601b90046001600160a01b03168015801590610683575061066d602085018561274f565b6001600160a01b0316816001600160a01b031614155b156106a157604051630f06503560e41b815260040160405180910390fd5b6000838152602081905260409020600201543410156106d35760405163f14a42b760e01b815260040160405180910390fd5b600083815260208190526040902084906001016106f08282612835565b506107009050602085018561274f565b6001600160a01b0316837f6ee50ac97c0c46c8b2867cb72d830af9312101598bd23b5585679d7a0d01c06061073b60408801602089016126e1565b6040516001600160601b0390911681526020015b60405180910390a350505050565b60015460609067ffffffffffffffff81111561077b5761077b612789565b6040519080825280602002602001820160405280156107f257816020015b6040805160e081018252600060a0820181815260c0830182905282528251808401845281815260208082018390528301529181018290526060810182905260808101919091528152602001906001900390816107995790505b50905060005b81518110156108e8576000806001838154811061081757610817612877565b600091825260208083209091015483528281019390935260409182019020815160e08101835281546001600160a01b0380821660a084019081526001600160601b03600160a01b93849004811660c0860152908452855180870187526001860154808416825293909304811683880152958301919091526002830154938201939093526003909101549283166060820152600160601b90920416608082015282518390839081106108ca576108ca612877565b602002602001018190525080806108e09061288d565b9150506107f8565b5090565b600181815481106108fc57600080fd5b600091825260209091200154905081565b6109188a8a8a61093b565b61092387878761093b565b61092f84848484610c71565b50505050505050505050565b60408051602081018490529081018290526060016040516020818303038152906040528051906020012060001c6001600160601b0316836001600160601b031614610999576040516329077eab60e11b815260040160405180910390fd5b60006109a483611588565b60408051808201825267ffffffffffffffff80871682526001600160c01b0380851660208085019182526001600160601b038b16600081815260029092529086902094519151909216600160401b02921691909117909155905191925084917fccfa43dde42b308c80e0eea01887c538073ac753b3958d9fc5f1acfc75e9216a9061074f9086815260200190565b610a3f602083018361274f565b336001600160a01b0316816001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a87573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aab919061276c565b6001600160a01b031614610ad25760405163388d0a1f60e01b815260040160405180910390fd5b6000610ae661037e3686900386018661279f565b6000818152602081905260409020600101549091506001600160a01b031615610b225760405163123af06b60e01b815260040160405180910390fd5b6000818152602081905260409020600201548015610b6957604051339082156108fc029083906000818181858888f19350505050158015610b67573d6000803e3d6000fd5b505b8160018581548110610b7d57610b7d612877565b906000526020600020015414610ba657604051634bfe8d9f60e01b815260040160405180910390fd5b60008281526020819052604081208181556001808201839055600282018390556003909101919091558054610bdc908290612822565b81548110610bec57610bec612877565b906000526020600020015460018581548110610c0a57610c0a612877565b6000918252602090912001556001805480610c2757610c276128a6565b60019003818190600052602060002001600090559055817fa5c028458c27d7cc75621d18a58fe289c65a143f70064736b1ff38def064fb6460405160405180910390a25050505050565b6000610c7d85846119c2565b8051602001519091506001600160a01b0316610cac57604051633cdf589160e21b815260040160405180910390fd5b6020810151511580610cc357506020818101510151155b15610ce157604051630fbc4d2d60e01b815260040160405180910390fd5b610cec6002846128d2565b151580610cf95750601583105b15610d175760405163c7c2ccaf60e01b815260040160405180910390fd5b60005b838110156111835760028260e001516001610d3591906128e6565b610d3f91906128d2565b610100830152815160e0830151600091829160028110610d6157610d61612877565b60200201516001600160a01b031663436cc79561138886604001518760e0015160028110610d9157610d91612877565b602002015187606001518860e0015160028110610db057610db0612877565b6020020151886060015189610100015160028110610dd057610dd0612877565b602002015189608001518a60e0015160028110610def57610def612877565b60200201518a608001518b610100015160028110610e0f57610e0f612877565b60200201518b60a001518c60e0015160028110610e2e57610e2e612877565b60200201516040516001600160e01b031960e08a901b1681526004810196909652602486019490945260448501929092526064840152608483015260a482015260c40160206040518083038160008887f193505050508015610ead575060408051601f3d908101601f19168201909252610eaa918101906128f9565b60015b15610eba57915050603f81165b6101608401518190610ecd8560016128e6565b81518110610edd57610edd612877565b6020026020010181815250508184608001518560e0015160028110610f0457610f04612877565b602002018181525050610f3981600086606001518760e0015160028110610f2d57610f2d612877565b60200201519190611c1f565b610f4f57505061010082015160e0830152611171565b6000610f7b82866040015187610100015160028110610f7057610f70612877565b602002015190611c40565b905080610fe057610fae82600187606001518860e0015160028110610fa257610fa2612877565b60200201519190611c5c565b85606001518660e0015160028110610fc857610fc8612877565b602002015250505061010082015160e0830152611171565b61100082600287606001518860e0015160028110610fa257610fa2612877565b85606001518660e001516002811061101a5761101a612877565b602002015260c0850151610100860151600091906002811061103e5761103e612877565b602002015161104e600184612822565b6005811061105e5761105e612877565b60200201805161106d90612912565b9081815250905080600003611161576110a386606001518760e001516002811061109957611099612877565b6020020151611c93565b156110f45760e0860151610120870152600161014087015261016086015160ff906110cf8760026128e6565b815181106110df576110df612877565b60200260200101818152505050505050611183565b6111418660a001518760e001516002811061111157611111612877565b60200201518360ff1688602001518961010001516002811061113557611135612877565b60200201519190611cb5565b8660a001518760e001516002811061115b5761115b612877565b60200201525b50505061010083015160e0840152505b8061117b8161288d565b915050610d1a565b60058261012001510361121f5761016082015160ff906111a48360016128e6565b815181106111b4576111b4612877565b60200260200101818152505060006111d18360c001516000611cda565b905060006111e48460c001516001611cda565b905080821115611203576000610120850152600261014085015261121c565b8082101561121c57600161012085015260026101408501525b50505b61122b86838686611d42565b856001868154811061123f5761123f612877565b90600052602060002001541461126857604051634bfe8d9f60e01b815260040160405180910390fd5b6000868152602081905260408120818155600180820183905560028201839055600390910191909155805461129e908290612822565b815481106112ae576112ae612877565b9060005260206000200154600186815481106112cc576112cc612877565b60009182526020909120015560018054806112e9576112e96128a6565b60019003818190600052602060002001600090559055505050505050565b611314602084018461274f565b336001600160a01b0316816001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561135c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611380919061276c565b6001600160a01b0316146113a75760405163388d0a1f60e01b815260040160405180910390fd5b60006113bb61037e3687900387018761279f565b6000818152602081905260409020549091506001600160a01b0316156113f457604051634c93111160e01b815260040160405180910390fd5b6127106001600160601b0385161115611420576040516361d2bb0360e01b815260040160405180910390fd5b6000818152602081905260409020859061143a8282612835565b505060008181526020818152604082203460028201556001600160a01b038616600160601b026001600160601b0388161760039091015560018054808201825592527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf69091018290556114af9086018661274f565b6001600160a01b031634827f87143ee8969c7635cf96224732f26903c7736d877f7ec60bc44dec67dc88a5146114eb60408a0160208b016126e1565b604080516001600160601b039283168152918a1660208301526001600160a01b0389169082015260600160405180910390a45050505050565b60008160000151826020015160405160200161156b92919060609290921b6bffffffffffffffffffffffff1916825260a01b6001600160a01b031916601482015260200190565b604051602081830303815290604052805190602001209050919050565b60006115926122eb565b600061159f8460016120a3565b600681901c808452603f821660208501819052919250106115db576040516325e3b13160e21b8152600160048201526024015b60405180910390fd5b815160208301516115ec9190612822565b60408301526115fd60016002612822565b60608301819052600381901b608084015260408301511480611626575081608001518260400151145b61164657604051630ac662cf60e41b8152600160048201526024016115d2565b61164e6122eb565b6116598560026120a3565b600681901c808352603f82166020840181905291935010611690576040516325e3b13160e21b8152600260048201526024016115d2565b805160208201516116a19190612822565b60408201526116b260016003612822565b60608201819052600381901b6080830152604082015114806116db575080608001518160400151145b6116fb57604051630ac662cf60e41b8152600260048201526024016115d2565b6117036122eb565b61170e8660036120a3565b600681901c808352603f82166020840181905291945010611745576040516325e3b13160e21b8152600360048201526024016115d2565b805160208201516117569190612822565b6040820181905260608301511480611775575081608001518160400151145b61179557604051630ac662cf60e41b8152600360048201526024016115d2565b61179d6122eb565b6117a88760056120a3565b600681901c808352603f821660208401819052919550106117df576040516325e3b13160e21b8152600560048201526024016115d2565b805160208201516117f09190612822565b604082015261180160016005612822565b60608201819052600381901b60808301526040820151148061182a575080608001518160400151145b61184a57604051630ac662cf60e41b8152600560048201526024016115d2565b6118526122eb565b61185d8860046120a3565b600681901c808352603f82166020840181905291965010611893576040516325e3b13160e21b81526004818101526024016115d2565b805160208201516118a49190612822565b604082015260036118b760016002612822565b901b6118c560016004612822565b6118cf91906128e6565b60608201526118e060016002612822565b60036118ee60016004612822565b6118f992911b6128e6565b608082015260608101516040820151148061191b575080608001518160400151145b61193a57604051630ac662cf60e41b81526004818101526024016115d2565b60408051808201909152600080825260208083019190915287519088015161196591839160016120ca565b8451602086015161197991839160026120ca565b8351602085015161198d91839160036120ca565b815160208301516119a191839160046120ca565b825160208401516119b591839160056120ca565b5198975050505050505050565b6119ca61231a565b6040805180820182526000858152602081815283822080546001600160a01b0380821686526001909201549182168386015293865284516001600160601b03600160a01b9586900481168552600280855287862060808085018a52905467ffffffffffffffff808216868c019081526001600160c01b03600160401b9384900481166060808a01919091529188529a90970490941688528287528988208a51808c018c5290548086168252919091048916818801528487019081528951808b018b52855151851681528151518516818901528b8801528951808b018b529451870151891685525186015190971683860152888801929092528651808801885281815280850191909152828801528551808701875260ff8082528185015285880152855180870187528481529283019390935260a080870192909252845160e08101865294850183815260039186018290529385015283929190830190611b31906004612929565b8152602001600581525081526020016040518060a0016040528060028152602001600381526020016003815260200160026004611b6e9190612929565b81526005602090910152905260c0820152611b8a6002426128d2565b60e082015260056101208201819052610140820152611baa8260026128e6565b67ffffffffffffffff811115611bc257611bc2612789565b604051908082528060200260200182016040528015611beb578160200160208202803683370190505b50610160820181905260e08201518151909190600090611c0d57611c0d612877565b60200260200101818152505092915050565b600080611c3084600685901b6128e6565b6001901b85161190509392505050565b6000611c4d826003612929565b83901c60071690505b92915050565b6000700100000000000000010000000000000001831b1981611c8285600686901b6128e6565b6001901b9190951617949350505050565b6000611cac67ffffffffffffffff608084901c16612267565b60151492915050565b600080611cc3600184612822565b610fff901b85811690198516179150509392505050565b6000805b6005811015611d3b57838360028110611cf957611cf9612877565b60200201518160058110611d0f57611d0f612877565b6020020151600003611d295781611d258161288d565b9250505b80611d338161288d565b915050611cde565b5092915050565b60008481526020819052604081206002908101549190611d63908390612929565b6000878152602081905260409020600301549091506001600160601b03168115612014576000612710611d968385612929565b611da09190612940565b6040519091506001600160a01b0386169082156108fc029083906000818181858888f19350505050158015611dd9573d6000803e3d6000fd5b50600587610120015103611f4b576002611df38285612822565b611dfd9190612940565b8751909350600060200201516001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611e46573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e6a919061276c565b6001600160a01b03166108fc849081150290604051600060405180830381858888f19350505050158015611ea2573d6000803e3d6000fd5b508651600160200201516001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ee9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f0d919061276c565b6001600160a01b03166108fc849081150290604051600060405180830381858888f19350505050158015611f45573d6000803e3d6000fd5b50612012565b611f558184612822565b9250866000015187610120015160028110611f7257611f72612877565b60200201516001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611fb4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fd8919061276c565b6001600160a01b03166108fc849081150290604051600060405180830381858888f19350505050158015612010573d6000803e3d6000fd5b505b505b85516020810151905160408801516001600160a01b03928316929091169089907fdec5d867ed84be6d953aedc46aefecffb72ee1c2a55a7fe1a3a5fd5be6198225906000602002015160408b01516001602002015188878d61012001518e61014001518f61016001518f604051612092989796959493929190612954565b60405180910390a450505050505050565b60006120b0600183612822565b6120bb90600c612929565b83901c610fff16905092915050565b600383811c9083901c60006120e06008876128d2565b905060006120ef6008876128d2565b905080821115612115576040516319b6e55960e11b8152600481018690526024016115d2565b6000845b84811161216f57835b83811161215c5761213781600384901b6128e6565b612142906003612929565b88901b8317925080806121549061288d565b915050612122565b50806121678161288d565b915050612119565b50602089015181161561219857604051635624d5ff60e11b8152600481018790526024016115d2565b82156121ac57826121a881612912565b9350505b84156121c057846121bc81612912565b9550505b60078210156121d757816121d38161288d565b9250505b60078410156121ee57836121ea8161288d565b9450505b6000855b85811161224957845b8481116122365761221081600384901b6128e6565b61221b906003612929565b6007901b83179250808061222e9061288d565b9150506121fb565b50806122418161288d565b9150506121f2565b50895190911789526020909801805190981790975250505050505050565b6000612281675555555555555555600184901c1683612822565b915061229e673333333333333333600284901c81169084166128e6565b91506122ae600483901c836128e6565b670f0f0f0f0f0f0f0f16915060386122ce83670101010101010101612929565b67ffffffffffffffff16901c67ffffffffffffffff169050919050565b6040518060a0016040528060008152602001600081526020016000815260200160008152602001600081525090565b60405180610180016040528061232e6123a5565b815260200161233b6123a5565b81526020016123486123a5565b81526020016123556123a5565b81526020016123626123a5565b815260200161236f6123a5565b815260200161237c6123c3565b815260200160008152602001600081526020016000815260200160008152602001606081525090565b60405180604001604052806002906020820280368337509192915050565b60405180604001604052806002905b6123da6123f0565b8152602001906001900390816123d25790505090565b6040518060a001604052806005906020820280368337509192915050565b60006040828403121561242057600080fd5b50919050565b6001600160601b038116811461243b57600080fd5b50565b6001600160a01b038116811461243b57600080fd5b60008060008060a0858703121561246957600080fd5b612473868661240e565b935060408501359250606085013561248a81612426565b9150608085013561249a8161243e565b939692955090935050565b600080606083850312156124b857600080fd5b6124c2848461240e565b946040939093013593505050565b80516001600160a01b031682526020908101516001600160601b0316910152565b602080825282518282018190526000919060409081850190868401855b828110156125765781516125238582516124d0565b86810151612533878701826124d0565b508086015160808681019190915260608201516001600160601b031660a087015201516001600160a01b031660c085015260e0909301929085019060010161250e565b5091979650505050505050565b60006020828403121561259557600080fd5b5035919050565b6000806000806000806000806000806101408b8d0312156125bc57600080fd5b8a356125c781612426565b995060208b0135985060408b0135975060608b01356125e581612426565b965060808b0135955060a08b0135945060c08b0135935060e08b013592506101008b013591506101208b013561261a8161243e565b809150509295989b9194979a5092959850565b60e0810161263b82886124d0565b61264860408301876124d0565b60808201949094526001600160601b039290921660a08301526001600160a01b031660c09091015292915050565b60008060006060848603121561268b57600080fd5b833561269681612426565b95602085013595506040909401359392505050565b600080600080608085870312156126c157600080fd5b843593506020850135925060408501359150606085013561249a8161243e565b6000602082840312156126f357600080fd5b81356126fe81612426565b9392505050565b60008060006080848603121561271a57600080fd5b612724858561240e565b9250604084013561273481612426565b915060608401356127448161243e565b809150509250925092565b60006020828403121561276157600080fd5b81356126fe8161243e565b60006020828403121561277e57600080fd5b81516126fe8161243e565b634e487b7160e01b600052604160045260246000fd5b6000604082840312156127b157600080fd5b6040516040810181811067ffffffffffffffff821117156127e257634e487b7160e01b600052604160045260246000fd5b60405282356127f08161243e565b8152602083013561280081612426565b60208201529392505050565b634e487b7160e01b600052601160045260246000fd5b81810381811115611c5657611c5661280c565b81356128408161243e565b81546001600160a01b03199081166001600160a01b03929092169182178355602084013561286d81612426565b60a01b1617905550565b634e487b7160e01b600052603260045260246000fd5b60006001820161289f5761289f61280c565b5060010190565b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b6000826128e1576128e16128bc565b500690565b80820180821115611c5657611c5661280c565b60006020828403121561290b57600080fd5b5051919050565b6000816129215761292161280c565b506000190190565b8082028115828204841417611c5657611c5661280c565b60008261294f5761294f6128bc565b500490565b60006101008083018b845260208b818601528a60408601528960608601528860808601528760a08601528260c0860152819250865180835261012086019350818801925060005b818110156129b75783518552938201939282019260010161299b565b5050505060e092909201929092529897505050505050505056fea26469706673582212204e5900840ccb02dbc0aa3beafff8822aebd569f25dfccd400c96e50b56ee394664736f6c63430008110033

Deployed Bytecode

0x60806040526004361061009c5760003560e01c8063c1e69b6611610064578063c1e69b6614610142578063dc645241146101e6578063dde8ab7814610206578063e3f5675814610226578063e7db485c14610246578063f698bfe3146102b757600080fd5b80636090e61b146100a157806371c3c892146100b6578063829ef1ac146100c9578063a8af8a8d146100f4578063b7dde4d714610122575b600080fd5b6100b46100af366004612453565b6102ca565b005b6100b46100c43660046124a5565b610527565b3480156100d557600080fd5b506100de61075d565b6040516100eb91906124f1565b60405180910390f35b34801561010057600080fd5b5061011461010f366004612583565b6108ec565b6040519081526020016100eb565b34801561012e57600080fd5b506100b461013d36600461259c565b61090d565b34801561014e57600080fd5b506101d561015d366004612583565b600060208181529181526040908190208151808301835281546001600160a01b0380821683526001600160601b03600160a01b92839004811684880152855180870190965260018501548083168752929092048216958501959095526002830154600390930154919490821691600160601b90041685565b6040516100eb95949392919061262d565b3480156101f257600080fd5b506100b4610201366004612676565b61093b565b34801561021257600080fd5b506100b46102213660046124a5565b610a32565b34801561023257600080fd5b506100b46102413660046126ab565b610c71565b34801561025257600080fd5b5061028f6102613660046126e1565b60026020526000908152604090205467ffffffffffffffff811690600160401b90046001600160c01b031682565b6040805167ffffffffffffffff90931683526001600160c01b039091166020830152016100eb565b6100b46102c5366004612705565b611307565b6102d7602085018561274f565b336001600160a01b0316816001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561031f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610343919061276c565b6001600160a01b03161461036a5760405163388d0a1f60e01b815260040160405180910390fd5b600061038361037e3688900388018861279f565b611524565b6000818152602081905260409020549091506001600160a01b03166103ba57604051623126e360e41b815260040160405180910390fd5b6000818152602081905260409020600101546001600160a01b0316156103f35760405163123af06b60e01b815260040160405180910390fd5b6127106001600160601b038516111561041f576040516361d2bb0360e01b815260040160405180910390fd5b60008181526020819052604090206002015480861115610468576104438187612822565b3410156104635760405163f14a42b760e01b815260040160405180910390fd5b6104a8565b808610156104a857336108fc61047e8884612822565b6040518115909202916000818181858888f193505050501580156104a6573d6000803e3d6000fd5b505b60008281526020818152604091829020600281018990556001600160601b038816600160601b6001600160a01b0389169081028217600390930192909255835190815291820152879184917f6887717706805f48aaf66cb6e4877e11e8eb9270a65f625d62a0b47121851427910160405180910390a350505050505050565b610534602083018361274f565b336001600160a01b0316816001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561057c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105a0919061276c565b6001600160a01b0316146105c75760405163388d0a1f60e01b815260040160405180910390fd5b6000828152602081905260409020546001600160a01b03166105fb57604051623126e360e41b815260040160405180910390fd5b6000828152602081905260409020600101546001600160a01b0316156106345760405163123af06b60e01b815260040160405180910390fd5b600082815260208190526040902060030154600160601b90046001600160a01b03168015801590610683575061066d602085018561274f565b6001600160a01b0316816001600160a01b031614155b156106a157604051630f06503560e41b815260040160405180910390fd5b6000838152602081905260409020600201543410156106d35760405163f14a42b760e01b815260040160405180910390fd5b600083815260208190526040902084906001016106f08282612835565b506107009050602085018561274f565b6001600160a01b0316837f6ee50ac97c0c46c8b2867cb72d830af9312101598bd23b5585679d7a0d01c06061073b60408801602089016126e1565b6040516001600160601b0390911681526020015b60405180910390a350505050565b60015460609067ffffffffffffffff81111561077b5761077b612789565b6040519080825280602002602001820160405280156107f257816020015b6040805160e081018252600060a0820181815260c0830182905282528251808401845281815260208082018390528301529181018290526060810182905260808101919091528152602001906001900390816107995790505b50905060005b81518110156108e8576000806001838154811061081757610817612877565b600091825260208083209091015483528281019390935260409182019020815160e08101835281546001600160a01b0380821660a084019081526001600160601b03600160a01b93849004811660c0860152908452855180870187526001860154808416825293909304811683880152958301919091526002830154938201939093526003909101549283166060820152600160601b90920416608082015282518390839081106108ca576108ca612877565b602002602001018190525080806108e09061288d565b9150506107f8565b5090565b600181815481106108fc57600080fd5b600091825260209091200154905081565b6109188a8a8a61093b565b61092387878761093b565b61092f84848484610c71565b50505050505050505050565b60408051602081018490529081018290526060016040516020818303038152906040528051906020012060001c6001600160601b0316836001600160601b031614610999576040516329077eab60e11b815260040160405180910390fd5b60006109a483611588565b60408051808201825267ffffffffffffffff80871682526001600160c01b0380851660208085019182526001600160601b038b16600081815260029092529086902094519151909216600160401b02921691909117909155905191925084917fccfa43dde42b308c80e0eea01887c538073ac753b3958d9fc5f1acfc75e9216a9061074f9086815260200190565b610a3f602083018361274f565b336001600160a01b0316816001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a87573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aab919061276c565b6001600160a01b031614610ad25760405163388d0a1f60e01b815260040160405180910390fd5b6000610ae661037e3686900386018661279f565b6000818152602081905260409020600101549091506001600160a01b031615610b225760405163123af06b60e01b815260040160405180910390fd5b6000818152602081905260409020600201548015610b6957604051339082156108fc029083906000818181858888f19350505050158015610b67573d6000803e3d6000fd5b505b8160018581548110610b7d57610b7d612877565b906000526020600020015414610ba657604051634bfe8d9f60e01b815260040160405180910390fd5b60008281526020819052604081208181556001808201839055600282018390556003909101919091558054610bdc908290612822565b81548110610bec57610bec612877565b906000526020600020015460018581548110610c0a57610c0a612877565b6000918252602090912001556001805480610c2757610c276128a6565b60019003818190600052602060002001600090559055817fa5c028458c27d7cc75621d18a58fe289c65a143f70064736b1ff38def064fb6460405160405180910390a25050505050565b6000610c7d85846119c2565b8051602001519091506001600160a01b0316610cac57604051633cdf589160e21b815260040160405180910390fd5b6020810151511580610cc357506020818101510151155b15610ce157604051630fbc4d2d60e01b815260040160405180910390fd5b610cec6002846128d2565b151580610cf95750601583105b15610d175760405163c7c2ccaf60e01b815260040160405180910390fd5b60005b838110156111835760028260e001516001610d3591906128e6565b610d3f91906128d2565b610100830152815160e0830151600091829160028110610d6157610d61612877565b60200201516001600160a01b031663436cc79561138886604001518760e0015160028110610d9157610d91612877565b602002015187606001518860e0015160028110610db057610db0612877565b6020020151886060015189610100015160028110610dd057610dd0612877565b602002015189608001518a60e0015160028110610def57610def612877565b60200201518a608001518b610100015160028110610e0f57610e0f612877565b60200201518b60a001518c60e0015160028110610e2e57610e2e612877565b60200201516040516001600160e01b031960e08a901b1681526004810196909652602486019490945260448501929092526064840152608483015260a482015260c40160206040518083038160008887f193505050508015610ead575060408051601f3d908101601f19168201909252610eaa918101906128f9565b60015b15610eba57915050603f81165b6101608401518190610ecd8560016128e6565b81518110610edd57610edd612877565b6020026020010181815250508184608001518560e0015160028110610f0457610f04612877565b602002018181525050610f3981600086606001518760e0015160028110610f2d57610f2d612877565b60200201519190611c1f565b610f4f57505061010082015160e0830152611171565b6000610f7b82866040015187610100015160028110610f7057610f70612877565b602002015190611c40565b905080610fe057610fae82600187606001518860e0015160028110610fa257610fa2612877565b60200201519190611c5c565b85606001518660e0015160028110610fc857610fc8612877565b602002015250505061010082015160e0830152611171565b61100082600287606001518860e0015160028110610fa257610fa2612877565b85606001518660e001516002811061101a5761101a612877565b602002015260c0850151610100860151600091906002811061103e5761103e612877565b602002015161104e600184612822565b6005811061105e5761105e612877565b60200201805161106d90612912565b9081815250905080600003611161576110a386606001518760e001516002811061109957611099612877565b6020020151611c93565b156110f45760e0860151610120870152600161014087015261016086015160ff906110cf8760026128e6565b815181106110df576110df612877565b60200260200101818152505050505050611183565b6111418660a001518760e001516002811061111157611111612877565b60200201518360ff1688602001518961010001516002811061113557611135612877565b60200201519190611cb5565b8660a001518760e001516002811061115b5761115b612877565b60200201525b50505061010083015160e0840152505b8061117b8161288d565b915050610d1a565b60058261012001510361121f5761016082015160ff906111a48360016128e6565b815181106111b4576111b4612877565b60200260200101818152505060006111d18360c001516000611cda565b905060006111e48460c001516001611cda565b905080821115611203576000610120850152600261014085015261121c565b8082101561121c57600161012085015260026101408501525b50505b61122b86838686611d42565b856001868154811061123f5761123f612877565b90600052602060002001541461126857604051634bfe8d9f60e01b815260040160405180910390fd5b6000868152602081905260408120818155600180820183905560028201839055600390910191909155805461129e908290612822565b815481106112ae576112ae612877565b9060005260206000200154600186815481106112cc576112cc612877565b60009182526020909120015560018054806112e9576112e96128a6565b60019003818190600052602060002001600090559055505050505050565b611314602084018461274f565b336001600160a01b0316816001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561135c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611380919061276c565b6001600160a01b0316146113a75760405163388d0a1f60e01b815260040160405180910390fd5b60006113bb61037e3687900387018761279f565b6000818152602081905260409020549091506001600160a01b0316156113f457604051634c93111160e01b815260040160405180910390fd5b6127106001600160601b0385161115611420576040516361d2bb0360e01b815260040160405180910390fd5b6000818152602081905260409020859061143a8282612835565b505060008181526020818152604082203460028201556001600160a01b038616600160601b026001600160601b0388161760039091015560018054808201825592527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf69091018290556114af9086018661274f565b6001600160a01b031634827f87143ee8969c7635cf96224732f26903c7736d877f7ec60bc44dec67dc88a5146114eb60408a0160208b016126e1565b604080516001600160601b039283168152918a1660208301526001600160a01b0389169082015260600160405180910390a45050505050565b60008160000151826020015160405160200161156b92919060609290921b6bffffffffffffffffffffffff1916825260a01b6001600160a01b031916601482015260200190565b604051602081830303815290604052805190602001209050919050565b60006115926122eb565b600061159f8460016120a3565b600681901c808452603f821660208501819052919250106115db576040516325e3b13160e21b8152600160048201526024015b60405180910390fd5b815160208301516115ec9190612822565b60408301526115fd60016002612822565b60608301819052600381901b608084015260408301511480611626575081608001518260400151145b61164657604051630ac662cf60e41b8152600160048201526024016115d2565b61164e6122eb565b6116598560026120a3565b600681901c808352603f82166020840181905291935010611690576040516325e3b13160e21b8152600260048201526024016115d2565b805160208201516116a19190612822565b60408201526116b260016003612822565b60608201819052600381901b6080830152604082015114806116db575080608001518160400151145b6116fb57604051630ac662cf60e41b8152600260048201526024016115d2565b6117036122eb565b61170e8660036120a3565b600681901c808352603f82166020840181905291945010611745576040516325e3b13160e21b8152600360048201526024016115d2565b805160208201516117569190612822565b6040820181905260608301511480611775575081608001518160400151145b61179557604051630ac662cf60e41b8152600360048201526024016115d2565b61179d6122eb565b6117a88760056120a3565b600681901c808352603f821660208401819052919550106117df576040516325e3b13160e21b8152600560048201526024016115d2565b805160208201516117f09190612822565b604082015261180160016005612822565b60608201819052600381901b60808301526040820151148061182a575080608001518160400151145b61184a57604051630ac662cf60e41b8152600560048201526024016115d2565b6118526122eb565b61185d8860046120a3565b600681901c808352603f82166020840181905291965010611893576040516325e3b13160e21b81526004818101526024016115d2565b805160208201516118a49190612822565b604082015260036118b760016002612822565b901b6118c560016004612822565b6118cf91906128e6565b60608201526118e060016002612822565b60036118ee60016004612822565b6118f992911b6128e6565b608082015260608101516040820151148061191b575080608001518160400151145b61193a57604051630ac662cf60e41b81526004818101526024016115d2565b60408051808201909152600080825260208083019190915287519088015161196591839160016120ca565b8451602086015161197991839160026120ca565b8351602085015161198d91839160036120ca565b815160208301516119a191839160046120ca565b825160208401516119b591839160056120ca565b5198975050505050505050565b6119ca61231a565b6040805180820182526000858152602081815283822080546001600160a01b0380821686526001909201549182168386015293865284516001600160601b03600160a01b9586900481168552600280855287862060808085018a52905467ffffffffffffffff808216868c019081526001600160c01b03600160401b9384900481166060808a01919091529188529a90970490941688528287528988208a51808c018c5290548086168252919091048916818801528487019081528951808b018b52855151851681528151518516818901528b8801528951808b018b529451870151891685525186015190971683860152888801929092528651808801885281815280850191909152828801528551808701875260ff8082528185015285880152855180870187528481529283019390935260a080870192909252845160e08101865294850183815260039186018290529385015283929190830190611b31906004612929565b8152602001600581525081526020016040518060a0016040528060028152602001600381526020016003815260200160026004611b6e9190612929565b81526005602090910152905260c0820152611b8a6002426128d2565b60e082015260056101208201819052610140820152611baa8260026128e6565b67ffffffffffffffff811115611bc257611bc2612789565b604051908082528060200260200182016040528015611beb578160200160208202803683370190505b50610160820181905260e08201518151909190600090611c0d57611c0d612877565b60200260200101818152505092915050565b600080611c3084600685901b6128e6565b6001901b85161190509392505050565b6000611c4d826003612929565b83901c60071690505b92915050565b6000700100000000000000010000000000000001831b1981611c8285600686901b6128e6565b6001901b9190951617949350505050565b6000611cac67ffffffffffffffff608084901c16612267565b60151492915050565b600080611cc3600184612822565b610fff901b85811690198516179150509392505050565b6000805b6005811015611d3b57838360028110611cf957611cf9612877565b60200201518160058110611d0f57611d0f612877565b6020020151600003611d295781611d258161288d565b9250505b80611d338161288d565b915050611cde565b5092915050565b60008481526020819052604081206002908101549190611d63908390612929565b6000878152602081905260409020600301549091506001600160601b03168115612014576000612710611d968385612929565b611da09190612940565b6040519091506001600160a01b0386169082156108fc029083906000818181858888f19350505050158015611dd9573d6000803e3d6000fd5b50600587610120015103611f4b576002611df38285612822565b611dfd9190612940565b8751909350600060200201516001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611e46573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e6a919061276c565b6001600160a01b03166108fc849081150290604051600060405180830381858888f19350505050158015611ea2573d6000803e3d6000fd5b508651600160200201516001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ee9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f0d919061276c565b6001600160a01b03166108fc849081150290604051600060405180830381858888f19350505050158015611f45573d6000803e3d6000fd5b50612012565b611f558184612822565b9250866000015187610120015160028110611f7257611f72612877565b60200201516001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611fb4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fd8919061276c565b6001600160a01b03166108fc849081150290604051600060405180830381858888f19350505050158015612010573d6000803e3d6000fd5b505b505b85516020810151905160408801516001600160a01b03928316929091169089907fdec5d867ed84be6d953aedc46aefecffb72ee1c2a55a7fe1a3a5fd5be6198225906000602002015160408b01516001602002015188878d61012001518e61014001518f61016001518f604051612092989796959493929190612954565b60405180910390a450505050505050565b60006120b0600183612822565b6120bb90600c612929565b83901c610fff16905092915050565b600383811c9083901c60006120e06008876128d2565b905060006120ef6008876128d2565b905080821115612115576040516319b6e55960e11b8152600481018690526024016115d2565b6000845b84811161216f57835b83811161215c5761213781600384901b6128e6565b612142906003612929565b88901b8317925080806121549061288d565b915050612122565b50806121678161288d565b915050612119565b50602089015181161561219857604051635624d5ff60e11b8152600481018790526024016115d2565b82156121ac57826121a881612912565b9350505b84156121c057846121bc81612912565b9550505b60078210156121d757816121d38161288d565b9250505b60078410156121ee57836121ea8161288d565b9450505b6000855b85811161224957845b8481116122365761221081600384901b6128e6565b61221b906003612929565b6007901b83179250808061222e9061288d565b9150506121fb565b50806122418161288d565b9150506121f2565b50895190911789526020909801805190981790975250505050505050565b6000612281675555555555555555600184901c1683612822565b915061229e673333333333333333600284901c81169084166128e6565b91506122ae600483901c836128e6565b670f0f0f0f0f0f0f0f16915060386122ce83670101010101010101612929565b67ffffffffffffffff16901c67ffffffffffffffff169050919050565b6040518060a0016040528060008152602001600081526020016000815260200160008152602001600081525090565b60405180610180016040528061232e6123a5565b815260200161233b6123a5565b81526020016123486123a5565b81526020016123556123a5565b81526020016123626123a5565b815260200161236f6123a5565b815260200161237c6123c3565b815260200160008152602001600081526020016000815260200160008152602001606081525090565b60405180604001604052806002906020820280368337509192915050565b60405180604001604052806002905b6123da6123f0565b8152602001906001900390816123d25790505090565b6040518060a001604052806005906020820280368337509192915050565b60006040828403121561242057600080fd5b50919050565b6001600160601b038116811461243b57600080fd5b50565b6001600160a01b038116811461243b57600080fd5b60008060008060a0858703121561246957600080fd5b612473868661240e565b935060408501359250606085013561248a81612426565b9150608085013561249a8161243e565b939692955090935050565b600080606083850312156124b857600080fd5b6124c2848461240e565b946040939093013593505050565b80516001600160a01b031682526020908101516001600160601b0316910152565b602080825282518282018190526000919060409081850190868401855b828110156125765781516125238582516124d0565b86810151612533878701826124d0565b508086015160808681019190915260608201516001600160601b031660a087015201516001600160a01b031660c085015260e0909301929085019060010161250e565b5091979650505050505050565b60006020828403121561259557600080fd5b5035919050565b6000806000806000806000806000806101408b8d0312156125bc57600080fd5b8a356125c781612426565b995060208b0135985060408b0135975060608b01356125e581612426565b965060808b0135955060a08b0135945060c08b0135935060e08b013592506101008b013591506101208b013561261a8161243e565b809150509295989b9194979a5092959850565b60e0810161263b82886124d0565b61264860408301876124d0565b60808201949094526001600160601b039290921660a08301526001600160a01b031660c09091015292915050565b60008060006060848603121561268b57600080fd5b833561269681612426565b95602085013595506040909401359392505050565b600080600080608085870312156126c157600080fd5b843593506020850135925060408501359150606085013561249a8161243e565b6000602082840312156126f357600080fd5b81356126fe81612426565b9392505050565b60008060006080848603121561271a57600080fd5b612724858561240e565b9250604084013561273481612426565b915060608401356127448161243e565b809150509250925092565b60006020828403121561276157600080fd5b81356126fe8161243e565b60006020828403121561277e57600080fd5b81516126fe8161243e565b634e487b7160e01b600052604160045260246000fd5b6000604082840312156127b157600080fd5b6040516040810181811067ffffffffffffffff821117156127e257634e487b7160e01b600052604160045260246000fd5b60405282356127f08161243e565b8152602083013561280081612426565b60208201529392505050565b634e487b7160e01b600052601160045260246000fd5b81810381811115611c5657611c5661280c565b81356128408161243e565b81546001600160a01b03199081166001600160a01b03929092169182178355602084013561286d81612426565b60a01b1617905550565b634e487b7160e01b600052603260045260246000fd5b60006001820161289f5761289f61280c565b5060010190565b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b6000826128e1576128e16128bc565b500690565b80820180821115611c5657611c5661280c565b60006020828403121561290b57600080fd5b5051919050565b6000816129215761292161280c565b506000190190565b8082028115828204841417611c5657611c5661280c565b60008261294f5761294f6128bc565b500490565b60006101008083018b845260208b818601528a60408601528960608601528860808601528760a08601528260c0860152819250865180835261012086019350818801925060005b818110156129b75783518552938201939282019260010161299b565b5050505060e092909201929092529897505050505050505056fea26469706673582212204e5900840ccb02dbc0aa3beafff8822aebd569f25dfccd400c96e50b56ee394664736f6c63430008110033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Txn Hash Block Value Eth2 PubKey Valid
View All Deposits
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.