Source Code
Overview
ETH Balance
0.33 ETH
Token Holdings
More Info
ContractCreator
Multi Chain
Multichain Addresses
7 addresses found via
Latest 25 from a total of 420 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
Value | ||||
---|---|---|---|---|---|---|---|---|---|
Submit Challenge | 9106763 | 117 days 11 hrs ago | IN | 0 ETH | 0.00096563 | ||||
Reveal Fleets An... | 9106761 | 117 days 11 hrs ago | IN | 0 ETH | 0.00957947 | ||||
Accept Challenge | 9106759 | 117 days 11 hrs ago | IN | 0 ETH | 0.00063155 | ||||
Submit Challenge | 9106738 | 117 days 11 hrs ago | IN | 0 ETH | 0.00091057 | ||||
Reveal Fleets An... | 9106736 | 117 days 11 hrs ago | IN | 0 ETH | 0.0102776 | ||||
Accept Challenge | 9106734 | 117 days 11 hrs ago | IN | 0 ETH | 0.00062413 | ||||
Submit Challenge | 9106705 | 117 days 11 hrs ago | IN | 0 ETH | 0.00125298 | ||||
Reveal Fleets An... | 9106703 | 117 days 11 hrs ago | IN | 0 ETH | 0.01080669 | ||||
Accept Challenge | 9106701 | 117 days 11 hrs ago | IN | 0 ETH | 0.00086246 | ||||
Submit Challenge | 9046348 | 127 days 16 hrs ago | IN | 0 ETH | 0.00030355 | ||||
Reveal Fleets An... | 9046347 | 127 days 16 hrs ago | IN | 0 ETH | 0.00255135 | ||||
Accept Challenge | 9046346 | 127 days 16 hrs ago | IN | 0 ETH | 0.00022705 | ||||
Submit Challenge | 9046334 | 127 days 16 hrs ago | IN | 0 ETH | 0.00032773 | ||||
Reveal Fleets An... | 9046333 | 127 days 16 hrs ago | IN | 0 ETH | 0.00289778 | ||||
Accept Challenge | 9046332 | 127 days 16 hrs ago | IN | 0 ETH | 0.00024116 | ||||
Reveal Fleets An... | 9046327 | 127 days 16 hrs ago | IN | 0 ETH | 0.00280135 | ||||
Submit Challenge | 9046327 | 127 days 16 hrs ago | IN | 0 ETH | 0.0003827 | ||||
Accept Challenge | 9046326 | 127 days 16 hrs ago | IN | 0 ETH | 0.0002826 | ||||
Reveal Fleets An... | 9046325 | 127 days 16 hrs ago | IN | 0 ETH | 0.00258561 | ||||
Submit Challenge | 9046321 | 127 days 17 hrs ago | IN | 0 ETH | 0.00034856 | ||||
Reveal Fleets An... | 9046290 | 127 days 17 hrs ago | IN | 0 ETH | 0.00229545 | ||||
Accept Challenge | 9046288 | 127 days 17 hrs ago | IN | 0 ETH | 0.00023331 | ||||
Accept Challenge | 9046250 | 127 days 17 hrs ago | IN | 0 ETH | 0.00023606 | ||||
Submit Challenge | 9046245 | 127 days 17 hrs ago | IN | 0 ETH | 0.0003765 | ||||
Submit Challenge | 9046239 | 127 days 17 hrs ago | IN | 0 ETH | 0.00045003 |
Latest 25 internal transactions (View All)
Advanced mode:
Parent Txn Hash | Block | From | To | Value | ||
---|---|---|---|---|---|---|
9106763 | 117 days 11 hrs ago | 0 ETH | ||||
9106761 | 117 days 11 hrs ago | 0 ETH | ||||
9106761 | 117 days 11 hrs ago | 0 ETH | ||||
9106761 | 117 days 11 hrs ago | 0 ETH | ||||
9106761 | 117 days 11 hrs ago | 0 ETH | ||||
9106761 | 117 days 11 hrs ago | 0 ETH | ||||
9106761 | 117 days 11 hrs ago | 0 ETH | ||||
9106761 | 117 days 11 hrs ago | 0 ETH | ||||
9106761 | 117 days 11 hrs ago | 0 ETH | ||||
9106761 | 117 days 11 hrs ago | 0 ETH | ||||
9106761 | 117 days 11 hrs ago | 0 ETH | ||||
9106761 | 117 days 11 hrs ago | 0 ETH | ||||
9106761 | 117 days 11 hrs ago | 0 ETH | ||||
9106761 | 117 days 11 hrs ago | 0 ETH | ||||
9106761 | 117 days 11 hrs ago | 0 ETH | ||||
9106761 | 117 days 11 hrs ago | 0 ETH | ||||
9106761 | 117 days 11 hrs ago | 0 ETH | ||||
9106761 | 117 days 11 hrs ago | 0 ETH | ||||
9106761 | 117 days 11 hrs ago | 0 ETH | ||||
9106761 | 117 days 11 hrs ago | 0 ETH | ||||
9106761 | 117 days 11 hrs ago | 0 ETH | ||||
9106761 | 117 days 11 hrs ago | 0 ETH | ||||
9106761 | 117 days 11 hrs ago | 0 ETH | ||||
9106761 | 117 days 11 hrs ago | 0 ETH | ||||
9106761 | 117 days 11 hrs ago | 0 ETH |
Loading...
Loading
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)
// 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++; } } } }
// 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); }
// 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) + ... } }
// 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; } }
// 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; } }
{ "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": {} }
[{"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"}]
Contract Creation Code
608060405234801561001057600080fd5b50612a07806100206000396000f3fe60806040526004361061009c5760003560e01c8063c1e69b6611610064578063c1e69b6614610142578063dc645241146101e6578063dde8ab7814610206578063e3f5675814610226578063e7db485c14610246578063f698bfe3146102b757600080fd5b80636090e61b146100a157806371c3c892146100b6578063829ef1ac146100c9578063a8af8a8d146100f4578063b7dde4d714610122575b600080fd5b6100b46100af366004612453565b6102ca565b005b6100b46100c43660046124a5565b610527565b3480156100d557600080fd5b506100de61075d565b6040516100eb91906124f1565b60405180910390f35b34801561010057600080fd5b5061011461010f366004612583565b6108ec565b6040519081526020016100eb565b34801561012e57600080fd5b506100b461013d36600461259c565b61090d565b34801561014e57600080fd5b506101d561015d366004612583565b600060208181529181526040908190208151808301835281546001600160a01b0380821683526001600160601b03600160a01b92839004811684880152855180870190965260018501548083168752929092048216958501959095526002830154600390930154919490821691600160601b90041685565b6040516100eb95949392919061262d565b3480156101f257600080fd5b506100b4610201366004612676565b61093b565b34801561021257600080fd5b506100b46102213660046124a5565b610a32565b34801561023257600080fd5b506100b46102413660046126ab565b610c71565b34801561025257600080fd5b5061028f6102613660046126e1565b60026020526000908152604090205467ffffffffffffffff811690600160401b90046001600160c01b031682565b6040805167ffffffffffffffff90931683526001600160c01b039091166020830152016100eb565b6100b46102c5366004612705565b611307565b6102d7602085018561274f565b336001600160a01b0316816001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561031f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610343919061276c565b6001600160a01b03161461036a5760405163388d0a1f60e01b815260040160405180910390fd5b600061038361037e3688900388018861279f565b611524565b6000818152602081905260409020549091506001600160a01b03166103ba57604051623126e360e41b815260040160405180910390fd5b6000818152602081905260409020600101546001600160a01b0316156103f35760405163123af06b60e01b815260040160405180910390fd5b6127106001600160601b038516111561041f576040516361d2bb0360e01b815260040160405180910390fd5b60008181526020819052604090206002015480861115610468576104438187612822565b3410156104635760405163f14a42b760e01b815260040160405180910390fd5b6104a8565b808610156104a857336108fc61047e8884612822565b6040518115909202916000818181858888f193505050501580156104a6573d6000803e3d6000fd5b505b60008281526020818152604091829020600281018990556001600160601b038816600160601b6001600160a01b0389169081028217600390930192909255835190815291820152879184917f6887717706805f48aaf66cb6e4877e11e8eb9270a65f625d62a0b47121851427910160405180910390a350505050505050565b610534602083018361274f565b336001600160a01b0316816001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561057c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105a0919061276c565b6001600160a01b0316146105c75760405163388d0a1f60e01b815260040160405180910390fd5b6000828152602081905260409020546001600160a01b03166105fb57604051623126e360e41b815260040160405180910390fd5b6000828152602081905260409020600101546001600160a01b0316156106345760405163123af06b60e01b815260040160405180910390fd5b600082815260208190526040902060030154600160601b90046001600160a01b03168015801590610683575061066d602085018561274f565b6001600160a01b0316816001600160a01b031614155b156106a157604051630f06503560e41b815260040160405180910390fd5b6000838152602081905260409020600201543410156106d35760405163f14a42b760e01b815260040160405180910390fd5b600083815260208190526040902084906001016106f08282612835565b506107009050602085018561274f565b6001600160a01b0316837f6ee50ac97c0c46c8b2867cb72d830af9312101598bd23b5585679d7a0d01c06061073b60408801602089016126e1565b6040516001600160601b0390911681526020015b60405180910390a350505050565b60015460609067ffffffffffffffff81111561077b5761077b612789565b6040519080825280602002602001820160405280156107f257816020015b6040805160e081018252600060a0820181815260c0830182905282528251808401845281815260208082018390528301529181018290526060810182905260808101919091528152602001906001900390816107995790505b50905060005b81518110156108e8576000806001838154811061081757610817612877565b600091825260208083209091015483528281019390935260409182019020815160e08101835281546001600160a01b0380821660a084019081526001600160601b03600160a01b93849004811660c0860152908452855180870187526001860154808416825293909304811683880152958301919091526002830154938201939093526003909101549283166060820152600160601b90920416608082015282518390839081106108ca576108ca612877565b602002602001018190525080806108e09061288d565b9150506107f8565b5090565b600181815481106108fc57600080fd5b600091825260209091200154905081565b6109188a8a8a61093b565b61092387878761093b565b61092f84848484610c71565b50505050505050505050565b60408051602081018490529081018290526060016040516020818303038152906040528051906020012060001c6001600160601b0316836001600160601b031614610999576040516329077eab60e11b815260040160405180910390fd5b60006109a483611588565b60408051808201825267ffffffffffffffff80871682526001600160c01b0380851660208085019182526001600160601b038b16600081815260029092529086902094519151909216600160401b02921691909117909155905191925084917fccfa43dde42b308c80e0eea01887c538073ac753b3958d9fc5f1acfc75e9216a9061074f9086815260200190565b610a3f602083018361274f565b336001600160a01b0316816001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a87573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aab919061276c565b6001600160a01b031614610ad25760405163388d0a1f60e01b815260040160405180910390fd5b6000610ae661037e3686900386018661279f565b6000818152602081905260409020600101549091506001600160a01b031615610b225760405163123af06b60e01b815260040160405180910390fd5b6000818152602081905260409020600201548015610b6957604051339082156108fc029083906000818181858888f19350505050158015610b67573d6000803e3d6000fd5b505b8160018581548110610b7d57610b7d612877565b906000526020600020015414610ba657604051634bfe8d9f60e01b815260040160405180910390fd5b60008281526020819052604081208181556001808201839055600282018390556003909101919091558054610bdc908290612822565b81548110610bec57610bec612877565b906000526020600020015460018581548110610c0a57610c0a612877565b6000918252602090912001556001805480610c2757610c276128a6565b60019003818190600052602060002001600090559055817fa5c028458c27d7cc75621d18a58fe289c65a143f70064736b1ff38def064fb6460405160405180910390a25050505050565b6000610c7d85846119c2565b8051602001519091506001600160a01b0316610cac57604051633cdf589160e21b815260040160405180910390fd5b6020810151511580610cc357506020818101510151155b15610ce157604051630fbc4d2d60e01b815260040160405180910390fd5b610cec6002846128d2565b151580610cf95750601583105b15610d175760405163c7c2ccaf60e01b815260040160405180910390fd5b60005b838110156111835760028260e001516001610d3591906128e6565b610d3f91906128d2565b610100830152815160e0830151600091829160028110610d6157610d61612877565b60200201516001600160a01b031663436cc79561138886604001518760e0015160028110610d9157610d91612877565b602002015187606001518860e0015160028110610db057610db0612877565b6020020151886060015189610100015160028110610dd057610dd0612877565b602002015189608001518a60e0015160028110610def57610def612877565b60200201518a608001518b610100015160028110610e0f57610e0f612877565b60200201518b60a001518c60e0015160028110610e2e57610e2e612877565b60200201516040516001600160e01b031960e08a901b1681526004810196909652602486019490945260448501929092526064840152608483015260a482015260c40160206040518083038160008887f193505050508015610ead575060408051601f3d908101601f19168201909252610eaa918101906128f9565b60015b15610eba57915050603f81165b6101608401518190610ecd8560016128e6565b81518110610edd57610edd612877565b6020026020010181815250508184608001518560e0015160028110610f0457610f04612877565b602002018181525050610f3981600086606001518760e0015160028110610f2d57610f2d612877565b60200201519190611c1f565b610f4f57505061010082015160e0830152611171565b6000610f7b82866040015187610100015160028110610f7057610f70612877565b602002015190611c40565b905080610fe057610fae82600187606001518860e0015160028110610fa257610fa2612877565b60200201519190611c5c565b85606001518660e0015160028110610fc857610fc8612877565b602002015250505061010082015160e0830152611171565b61100082600287606001518860e0015160028110610fa257610fa2612877565b85606001518660e001516002811061101a5761101a612877565b602002015260c0850151610100860151600091906002811061103e5761103e612877565b602002015161104e600184612822565b6005811061105e5761105e612877565b60200201805161106d90612912565b9081815250905080600003611161576110a386606001518760e001516002811061109957611099612877565b6020020151611c93565b156110f45760e0860151610120870152600161014087015261016086015160ff906110cf8760026128e6565b815181106110df576110df612877565b60200260200101818152505050505050611183565b6111418660a001518760e001516002811061111157611111612877565b60200201518360ff1688602001518961010001516002811061113557611135612877565b60200201519190611cb5565b8660a001518760e001516002811061115b5761115b612877565b60200201525b50505061010083015160e0840152505b8061117b8161288d565b915050610d1a565b60058261012001510361121f5761016082015160ff906111a48360016128e6565b815181106111b4576111b4612877565b60200260200101818152505060006111d18360c001516000611cda565b905060006111e48460c001516001611cda565b905080821115611203576000610120850152600261014085015261121c565b8082101561121c57600161012085015260026101408501525b50505b61122b86838686611d42565b856001868154811061123f5761123f612877565b90600052602060002001541461126857604051634bfe8d9f60e01b815260040160405180910390fd5b6000868152602081905260408120818155600180820183905560028201839055600390910191909155805461129e908290612822565b815481106112ae576112ae612877565b9060005260206000200154600186815481106112cc576112cc612877565b60009182526020909120015560018054806112e9576112e96128a6565b60019003818190600052602060002001600090559055505050505050565b611314602084018461274f565b336001600160a01b0316816001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561135c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611380919061276c565b6001600160a01b0316146113a75760405163388d0a1f60e01b815260040160405180910390fd5b60006113bb61037e3687900387018761279f565b6000818152602081905260409020549091506001600160a01b0316156113f457604051634c93111160e01b815260040160405180910390fd5b6127106001600160601b0385161115611420576040516361d2bb0360e01b815260040160405180910390fd5b6000818152602081905260409020859061143a8282612835565b505060008181526020818152604082203460028201556001600160a01b038616600160601b026001600160601b0388161760039091015560018054808201825592527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf69091018290556114af9086018661274f565b6001600160a01b031634827f87143ee8969c7635cf96224732f26903c7736d877f7ec60bc44dec67dc88a5146114eb60408a0160208b016126e1565b604080516001600160601b039283168152918a1660208301526001600160a01b0389169082015260600160405180910390a45050505050565b60008160000151826020015160405160200161156b92919060609290921b6bffffffffffffffffffffffff1916825260a01b6001600160a01b031916601482015260200190565b604051602081830303815290604052805190602001209050919050565b60006115926122eb565b600061159f8460016120a3565b600681901c808452603f821660208501819052919250106115db576040516325e3b13160e21b8152600160048201526024015b60405180910390fd5b815160208301516115ec9190612822565b60408301526115fd60016002612822565b60608301819052600381901b608084015260408301511480611626575081608001518260400151145b61164657604051630ac662cf60e41b8152600160048201526024016115d2565b61164e6122eb565b6116598560026120a3565b600681901c808352603f82166020840181905291935010611690576040516325e3b13160e21b8152600260048201526024016115d2565b805160208201516116a19190612822565b60408201526116b260016003612822565b60608201819052600381901b6080830152604082015114806116db575080608001518160400151145b6116fb57604051630ac662cf60e41b8152600260048201526024016115d2565b6117036122eb565b61170e8660036120a3565b600681901c808352603f82166020840181905291945010611745576040516325e3b13160e21b8152600360048201526024016115d2565b805160208201516117569190612822565b6040820181905260608301511480611775575081608001518160400151145b61179557604051630ac662cf60e41b8152600360048201526024016115d2565b61179d6122eb565b6117a88760056120a3565b600681901c808352603f821660208401819052919550106117df576040516325e3b13160e21b8152600560048201526024016115d2565b805160208201516117f09190612822565b604082015261180160016005612822565b60608201819052600381901b60808301526040820151148061182a575080608001518160400151145b61184a57604051630ac662cf60e41b8152600560048201526024016115d2565b6118526122eb565b61185d8860046120a3565b600681901c808352603f82166020840181905291965010611893576040516325e3b13160e21b81526004818101526024016115d2565b805160208201516118a49190612822565b604082015260036118b760016002612822565b901b6118c560016004612822565b6118cf91906128e6565b60608201526118e060016002612822565b60036118ee60016004612822565b6118f992911b6128e6565b608082015260608101516040820151148061191b575080608001518160400151145b61193a57604051630ac662cf60e41b81526004818101526024016115d2565b60408051808201909152600080825260208083019190915287519088015161196591839160016120ca565b8451602086015161197991839160026120ca565b8351602085015161198d91839160036120ca565b815160208301516119a191839160046120ca565b825160208401516119b591839160056120ca565b5198975050505050505050565b6119ca61231a565b6040805180820182526000858152602081815283822080546001600160a01b0380821686526001909201549182168386015293865284516001600160601b03600160a01b9586900481168552600280855287862060808085018a52905467ffffffffffffffff808216868c019081526001600160c01b03600160401b9384900481166060808a01919091529188529a90970490941688528287528988208a51808c018c5290548086168252919091048916818801528487019081528951808b018b52855151851681528151518516818901528b8801528951808b018b529451870151891685525186015190971683860152888801929092528651808801885281815280850191909152828801528551808701875260ff8082528185015285880152855180870187528481529283019390935260a080870192909252845160e08101865294850183815260039186018290529385015283929190830190611b31906004612929565b8152602001600581525081526020016040518060a0016040528060028152602001600381526020016003815260200160026004611b6e9190612929565b81526005602090910152905260c0820152611b8a6002426128d2565b60e082015260056101208201819052610140820152611baa8260026128e6565b67ffffffffffffffff811115611bc257611bc2612789565b604051908082528060200260200182016040528015611beb578160200160208202803683370190505b50610160820181905260e08201518151909190600090611c0d57611c0d612877565b60200260200101818152505092915050565b600080611c3084600685901b6128e6565b6001901b85161190509392505050565b6000611c4d826003612929565b83901c60071690505b92915050565b6000700100000000000000010000000000000001831b1981611c8285600686901b6128e6565b6001901b9190951617949350505050565b6000611cac67ffffffffffffffff608084901c16612267565b60151492915050565b600080611cc3600184612822565b610fff901b85811690198516179150509392505050565b6000805b6005811015611d3b57838360028110611cf957611cf9612877565b60200201518160058110611d0f57611d0f612877565b6020020151600003611d295781611d258161288d565b9250505b80611d338161288d565b915050611cde565b5092915050565b60008481526020819052604081206002908101549190611d63908390612929565b6000878152602081905260409020600301549091506001600160601b03168115612014576000612710611d968385612929565b611da09190612940565b6040519091506001600160a01b0386169082156108fc029083906000818181858888f19350505050158015611dd9573d6000803e3d6000fd5b50600587610120015103611f4b576002611df38285612822565b611dfd9190612940565b8751909350600060200201516001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611e46573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e6a919061276c565b6001600160a01b03166108fc849081150290604051600060405180830381858888f19350505050158015611ea2573d6000803e3d6000fd5b508651600160200201516001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ee9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f0d919061276c565b6001600160a01b03166108fc849081150290604051600060405180830381858888f19350505050158015611f45573d6000803e3d6000fd5b50612012565b611f558184612822565b9250866000015187610120015160028110611f7257611f72612877565b60200201516001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611fb4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fd8919061276c565b6001600160a01b03166108fc849081150290604051600060405180830381858888f19350505050158015612010573d6000803e3d6000fd5b505b505b85516020810151905160408801516001600160a01b03928316929091169089907fdec5d867ed84be6d953aedc46aefecffb72ee1c2a55a7fe1a3a5fd5be6198225906000602002015160408b01516001602002015188878d61012001518e61014001518f61016001518f604051612092989796959493929190612954565b60405180910390a450505050505050565b60006120b0600183612822565b6120bb90600c612929565b83901c610fff16905092915050565b600383811c9083901c60006120e06008876128d2565b905060006120ef6008876128d2565b905080821115612115576040516319b6e55960e11b8152600481018690526024016115d2565b6000845b84811161216f57835b83811161215c5761213781600384901b6128e6565b612142906003612929565b88901b8317925080806121549061288d565b915050612122565b50806121678161288d565b915050612119565b50602089015181161561219857604051635624d5ff60e11b8152600481018790526024016115d2565b82156121ac57826121a881612912565b9350505b84156121c057846121bc81612912565b9550505b60078210156121d757816121d38161288d565b9250505b60078410156121ee57836121ea8161288d565b9450505b6000855b85811161224957845b8481116122365761221081600384901b6128e6565b61221b906003612929565b6007901b83179250808061222e9061288d565b9150506121fb565b50806122418161288d565b9150506121f2565b50895190911789526020909801805190981790975250505050505050565b6000612281675555555555555555600184901c1683612822565b915061229e673333333333333333600284901c81169084166128e6565b91506122ae600483901c836128e6565b670f0f0f0f0f0f0f0f16915060386122ce83670101010101010101612929565b67ffffffffffffffff16901c67ffffffffffffffff169050919050565b6040518060a0016040528060008152602001600081526020016000815260200160008152602001600081525090565b60405180610180016040528061232e6123a5565b815260200161233b6123a5565b81526020016123486123a5565b81526020016123556123a5565b81526020016123626123a5565b815260200161236f6123a5565b815260200161237c6123c3565b815260200160008152602001600081526020016000815260200160008152602001606081525090565b60405180604001604052806002906020820280368337509192915050565b60405180604001604052806002905b6123da6123f0565b8152602001906001900390816123d25790505090565b6040518060a001604052806005906020820280368337509192915050565b60006040828403121561242057600080fd5b50919050565b6001600160601b038116811461243b57600080fd5b50565b6001600160a01b038116811461243b57600080fd5b60008060008060a0858703121561246957600080fd5b612473868661240e565b935060408501359250606085013561248a81612426565b9150608085013561249a8161243e565b939692955090935050565b600080606083850312156124b857600080fd5b6124c2848461240e565b946040939093013593505050565b80516001600160a01b031682526020908101516001600160601b0316910152565b602080825282518282018190526000919060409081850190868401855b828110156125765781516125238582516124d0565b86810151612533878701826124d0565b508086015160808681019190915260608201516001600160601b031660a087015201516001600160a01b031660c085015260e0909301929085019060010161250e565b5091979650505050505050565b60006020828403121561259557600080fd5b5035919050565b6000806000806000806000806000806101408b8d0312156125bc57600080fd5b8a356125c781612426565b995060208b0135985060408b0135975060608b01356125e581612426565b965060808b0135955060a08b0135945060c08b0135935060e08b013592506101008b013591506101208b013561261a8161243e565b809150509295989b9194979a5092959850565b60e0810161263b82886124d0565b61264860408301876124d0565b60808201949094526001600160601b039290921660a08301526001600160a01b031660c09091015292915050565b60008060006060848603121561268b57600080fd5b833561269681612426565b95602085013595506040909401359392505050565b600080600080608085870312156126c157600080fd5b843593506020850135925060408501359150606085013561249a8161243e565b6000602082840312156126f357600080fd5b81356126fe81612426565b9392505050565b60008060006080848603121561271a57600080fd5b612724858561240e565b9250604084013561273481612426565b915060608401356127448161243e565b809150509250925092565b60006020828403121561276157600080fd5b81356126fe8161243e565b60006020828403121561277e57600080fd5b81516126fe8161243e565b634e487b7160e01b600052604160045260246000fd5b6000604082840312156127b157600080fd5b6040516040810181811067ffffffffffffffff821117156127e257634e487b7160e01b600052604160045260246000fd5b60405282356127f08161243e565b8152602083013561280081612426565b60208201529392505050565b634e487b7160e01b600052601160045260246000fd5b81810381811115611c5657611c5661280c565b81356128408161243e565b81546001600160a01b03199081166001600160a01b03929092169182178355602084013561286d81612426565b60a01b1617905550565b634e487b7160e01b600052603260045260246000fd5b60006001820161289f5761289f61280c565b5060010190565b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b6000826128e1576128e16128bc565b500690565b80820180821115611c5657611c5661280c565b60006020828403121561290b57600080fd5b5051919050565b6000816129215761292161280c565b506000190190565b8082028115828204841417611c5657611c5661280c565b60008261294f5761294f6128bc565b500490565b60006101008083018b845260208b818601528a60408601528960608601528860808601528760a08601528260c0860152819250865180835261012086019350818801925060005b818110156129b75783518552938201939282019260010161299b565b5050505060e092909201929092529897505050505050505056fea26469706673582212204e5900840ccb02dbc0aa3beafff8822aebd569f25dfccd400c96e50b56ee394664736f6c63430008110033
Deployed Bytecode
0x60806040526004361061009c5760003560e01c8063c1e69b6611610064578063c1e69b6614610142578063dc645241146101e6578063dde8ab7814610206578063e3f5675814610226578063e7db485c14610246578063f698bfe3146102b757600080fd5b80636090e61b146100a157806371c3c892146100b6578063829ef1ac146100c9578063a8af8a8d146100f4578063b7dde4d714610122575b600080fd5b6100b46100af366004612453565b6102ca565b005b6100b46100c43660046124a5565b610527565b3480156100d557600080fd5b506100de61075d565b6040516100eb91906124f1565b60405180910390f35b34801561010057600080fd5b5061011461010f366004612583565b6108ec565b6040519081526020016100eb565b34801561012e57600080fd5b506100b461013d36600461259c565b61090d565b34801561014e57600080fd5b506101d561015d366004612583565b600060208181529181526040908190208151808301835281546001600160a01b0380821683526001600160601b03600160a01b92839004811684880152855180870190965260018501548083168752929092048216958501959095526002830154600390930154919490821691600160601b90041685565b6040516100eb95949392919061262d565b3480156101f257600080fd5b506100b4610201366004612676565b61093b565b34801561021257600080fd5b506100b46102213660046124a5565b610a32565b34801561023257600080fd5b506100b46102413660046126ab565b610c71565b34801561025257600080fd5b5061028f6102613660046126e1565b60026020526000908152604090205467ffffffffffffffff811690600160401b90046001600160c01b031682565b6040805167ffffffffffffffff90931683526001600160c01b039091166020830152016100eb565b6100b46102c5366004612705565b611307565b6102d7602085018561274f565b336001600160a01b0316816001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561031f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610343919061276c565b6001600160a01b03161461036a5760405163388d0a1f60e01b815260040160405180910390fd5b600061038361037e3688900388018861279f565b611524565b6000818152602081905260409020549091506001600160a01b03166103ba57604051623126e360e41b815260040160405180910390fd5b6000818152602081905260409020600101546001600160a01b0316156103f35760405163123af06b60e01b815260040160405180910390fd5b6127106001600160601b038516111561041f576040516361d2bb0360e01b815260040160405180910390fd5b60008181526020819052604090206002015480861115610468576104438187612822565b3410156104635760405163f14a42b760e01b815260040160405180910390fd5b6104a8565b808610156104a857336108fc61047e8884612822565b6040518115909202916000818181858888f193505050501580156104a6573d6000803e3d6000fd5b505b60008281526020818152604091829020600281018990556001600160601b038816600160601b6001600160a01b0389169081028217600390930192909255835190815291820152879184917f6887717706805f48aaf66cb6e4877e11e8eb9270a65f625d62a0b47121851427910160405180910390a350505050505050565b610534602083018361274f565b336001600160a01b0316816001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561057c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105a0919061276c565b6001600160a01b0316146105c75760405163388d0a1f60e01b815260040160405180910390fd5b6000828152602081905260409020546001600160a01b03166105fb57604051623126e360e41b815260040160405180910390fd5b6000828152602081905260409020600101546001600160a01b0316156106345760405163123af06b60e01b815260040160405180910390fd5b600082815260208190526040902060030154600160601b90046001600160a01b03168015801590610683575061066d602085018561274f565b6001600160a01b0316816001600160a01b031614155b156106a157604051630f06503560e41b815260040160405180910390fd5b6000838152602081905260409020600201543410156106d35760405163f14a42b760e01b815260040160405180910390fd5b600083815260208190526040902084906001016106f08282612835565b506107009050602085018561274f565b6001600160a01b0316837f6ee50ac97c0c46c8b2867cb72d830af9312101598bd23b5585679d7a0d01c06061073b60408801602089016126e1565b6040516001600160601b0390911681526020015b60405180910390a350505050565b60015460609067ffffffffffffffff81111561077b5761077b612789565b6040519080825280602002602001820160405280156107f257816020015b6040805160e081018252600060a0820181815260c0830182905282528251808401845281815260208082018390528301529181018290526060810182905260808101919091528152602001906001900390816107995790505b50905060005b81518110156108e8576000806001838154811061081757610817612877565b600091825260208083209091015483528281019390935260409182019020815160e08101835281546001600160a01b0380821660a084019081526001600160601b03600160a01b93849004811660c0860152908452855180870187526001860154808416825293909304811683880152958301919091526002830154938201939093526003909101549283166060820152600160601b90920416608082015282518390839081106108ca576108ca612877565b602002602001018190525080806108e09061288d565b9150506107f8565b5090565b600181815481106108fc57600080fd5b600091825260209091200154905081565b6109188a8a8a61093b565b61092387878761093b565b61092f84848484610c71565b50505050505050505050565b60408051602081018490529081018290526060016040516020818303038152906040528051906020012060001c6001600160601b0316836001600160601b031614610999576040516329077eab60e11b815260040160405180910390fd5b60006109a483611588565b60408051808201825267ffffffffffffffff80871682526001600160c01b0380851660208085019182526001600160601b038b16600081815260029092529086902094519151909216600160401b02921691909117909155905191925084917fccfa43dde42b308c80e0eea01887c538073ac753b3958d9fc5f1acfc75e9216a9061074f9086815260200190565b610a3f602083018361274f565b336001600160a01b0316816001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a87573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aab919061276c565b6001600160a01b031614610ad25760405163388d0a1f60e01b815260040160405180910390fd5b6000610ae661037e3686900386018661279f565b6000818152602081905260409020600101549091506001600160a01b031615610b225760405163123af06b60e01b815260040160405180910390fd5b6000818152602081905260409020600201548015610b6957604051339082156108fc029083906000818181858888f19350505050158015610b67573d6000803e3d6000fd5b505b8160018581548110610b7d57610b7d612877565b906000526020600020015414610ba657604051634bfe8d9f60e01b815260040160405180910390fd5b60008281526020819052604081208181556001808201839055600282018390556003909101919091558054610bdc908290612822565b81548110610bec57610bec612877565b906000526020600020015460018581548110610c0a57610c0a612877565b6000918252602090912001556001805480610c2757610c276128a6565b60019003818190600052602060002001600090559055817fa5c028458c27d7cc75621d18a58fe289c65a143f70064736b1ff38def064fb6460405160405180910390a25050505050565b6000610c7d85846119c2565b8051602001519091506001600160a01b0316610cac57604051633cdf589160e21b815260040160405180910390fd5b6020810151511580610cc357506020818101510151155b15610ce157604051630fbc4d2d60e01b815260040160405180910390fd5b610cec6002846128d2565b151580610cf95750601583105b15610d175760405163c7c2ccaf60e01b815260040160405180910390fd5b60005b838110156111835760028260e001516001610d3591906128e6565b610d3f91906128d2565b610100830152815160e0830151600091829160028110610d6157610d61612877565b60200201516001600160a01b031663436cc79561138886604001518760e0015160028110610d9157610d91612877565b602002015187606001518860e0015160028110610db057610db0612877565b6020020151886060015189610100015160028110610dd057610dd0612877565b602002015189608001518a60e0015160028110610def57610def612877565b60200201518a608001518b610100015160028110610e0f57610e0f612877565b60200201518b60a001518c60e0015160028110610e2e57610e2e612877565b60200201516040516001600160e01b031960e08a901b1681526004810196909652602486019490945260448501929092526064840152608483015260a482015260c40160206040518083038160008887f193505050508015610ead575060408051601f3d908101601f19168201909252610eaa918101906128f9565b60015b15610eba57915050603f81165b6101608401518190610ecd8560016128e6565b81518110610edd57610edd612877565b6020026020010181815250508184608001518560e0015160028110610f0457610f04612877565b602002018181525050610f3981600086606001518760e0015160028110610f2d57610f2d612877565b60200201519190611c1f565b610f4f57505061010082015160e0830152611171565b6000610f7b82866040015187610100015160028110610f7057610f70612877565b602002015190611c40565b905080610fe057610fae82600187606001518860e0015160028110610fa257610fa2612877565b60200201519190611c5c565b85606001518660e0015160028110610fc857610fc8612877565b602002015250505061010082015160e0830152611171565b61100082600287606001518860e0015160028110610fa257610fa2612877565b85606001518660e001516002811061101a5761101a612877565b602002015260c0850151610100860151600091906002811061103e5761103e612877565b602002015161104e600184612822565b6005811061105e5761105e612877565b60200201805161106d90612912565b9081815250905080600003611161576110a386606001518760e001516002811061109957611099612877565b6020020151611c93565b156110f45760e0860151610120870152600161014087015261016086015160ff906110cf8760026128e6565b815181106110df576110df612877565b60200260200101818152505050505050611183565b6111418660a001518760e001516002811061111157611111612877565b60200201518360ff1688602001518961010001516002811061113557611135612877565b60200201519190611cb5565b8660a001518760e001516002811061115b5761115b612877565b60200201525b50505061010083015160e0840152505b8061117b8161288d565b915050610d1a565b60058261012001510361121f5761016082015160ff906111a48360016128e6565b815181106111b4576111b4612877565b60200260200101818152505060006111d18360c001516000611cda565b905060006111e48460c001516001611cda565b905080821115611203576000610120850152600261014085015261121c565b8082101561121c57600161012085015260026101408501525b50505b61122b86838686611d42565b856001868154811061123f5761123f612877565b90600052602060002001541461126857604051634bfe8d9f60e01b815260040160405180910390fd5b6000868152602081905260408120818155600180820183905560028201839055600390910191909155805461129e908290612822565b815481106112ae576112ae612877565b9060005260206000200154600186815481106112cc576112cc612877565b60009182526020909120015560018054806112e9576112e96128a6565b60019003818190600052602060002001600090559055505050505050565b611314602084018461274f565b336001600160a01b0316816001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561135c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611380919061276c565b6001600160a01b0316146113a75760405163388d0a1f60e01b815260040160405180910390fd5b60006113bb61037e3687900387018761279f565b6000818152602081905260409020549091506001600160a01b0316156113f457604051634c93111160e01b815260040160405180910390fd5b6127106001600160601b0385161115611420576040516361d2bb0360e01b815260040160405180910390fd5b6000818152602081905260409020859061143a8282612835565b505060008181526020818152604082203460028201556001600160a01b038616600160601b026001600160601b0388161760039091015560018054808201825592527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf69091018290556114af9086018661274f565b6001600160a01b031634827f87143ee8969c7635cf96224732f26903c7736d877f7ec60bc44dec67dc88a5146114eb60408a0160208b016126e1565b604080516001600160601b039283168152918a1660208301526001600160a01b0389169082015260600160405180910390a45050505050565b60008160000151826020015160405160200161156b92919060609290921b6bffffffffffffffffffffffff1916825260a01b6001600160a01b031916601482015260200190565b604051602081830303815290604052805190602001209050919050565b60006115926122eb565b600061159f8460016120a3565b600681901c808452603f821660208501819052919250106115db576040516325e3b13160e21b8152600160048201526024015b60405180910390fd5b815160208301516115ec9190612822565b60408301526115fd60016002612822565b60608301819052600381901b608084015260408301511480611626575081608001518260400151145b61164657604051630ac662cf60e41b8152600160048201526024016115d2565b61164e6122eb565b6116598560026120a3565b600681901c808352603f82166020840181905291935010611690576040516325e3b13160e21b8152600260048201526024016115d2565b805160208201516116a19190612822565b60408201526116b260016003612822565b60608201819052600381901b6080830152604082015114806116db575080608001518160400151145b6116fb57604051630ac662cf60e41b8152600260048201526024016115d2565b6117036122eb565b61170e8660036120a3565b600681901c808352603f82166020840181905291945010611745576040516325e3b13160e21b8152600360048201526024016115d2565b805160208201516117569190612822565b6040820181905260608301511480611775575081608001518160400151145b61179557604051630ac662cf60e41b8152600360048201526024016115d2565b61179d6122eb565b6117a88760056120a3565b600681901c808352603f821660208401819052919550106117df576040516325e3b13160e21b8152600560048201526024016115d2565b805160208201516117f09190612822565b604082015261180160016005612822565b60608201819052600381901b60808301526040820151148061182a575080608001518160400151145b61184a57604051630ac662cf60e41b8152600560048201526024016115d2565b6118526122eb565b61185d8860046120a3565b600681901c808352603f82166020840181905291965010611893576040516325e3b13160e21b81526004818101526024016115d2565b805160208201516118a49190612822565b604082015260036118b760016002612822565b901b6118c560016004612822565b6118cf91906128e6565b60608201526118e060016002612822565b60036118ee60016004612822565b6118f992911b6128e6565b608082015260608101516040820151148061191b575080608001518160400151145b61193a57604051630ac662cf60e41b81526004818101526024016115d2565b60408051808201909152600080825260208083019190915287519088015161196591839160016120ca565b8451602086015161197991839160026120ca565b8351602085015161198d91839160036120ca565b815160208301516119a191839160046120ca565b825160208401516119b591839160056120ca565b5198975050505050505050565b6119ca61231a565b6040805180820182526000858152602081815283822080546001600160a01b0380821686526001909201549182168386015293865284516001600160601b03600160a01b9586900481168552600280855287862060808085018a52905467ffffffffffffffff808216868c019081526001600160c01b03600160401b9384900481166060808a01919091529188529a90970490941688528287528988208a51808c018c5290548086168252919091048916818801528487019081528951808b018b52855151851681528151518516818901528b8801528951808b018b529451870151891685525186015190971683860152888801929092528651808801885281815280850191909152828801528551808701875260ff8082528185015285880152855180870187528481529283019390935260a080870192909252845160e08101865294850183815260039186018290529385015283929190830190611b31906004612929565b8152602001600581525081526020016040518060a0016040528060028152602001600381526020016003815260200160026004611b6e9190612929565b81526005602090910152905260c0820152611b8a6002426128d2565b60e082015260056101208201819052610140820152611baa8260026128e6565b67ffffffffffffffff811115611bc257611bc2612789565b604051908082528060200260200182016040528015611beb578160200160208202803683370190505b50610160820181905260e08201518151909190600090611c0d57611c0d612877565b60200260200101818152505092915050565b600080611c3084600685901b6128e6565b6001901b85161190509392505050565b6000611c4d826003612929565b83901c60071690505b92915050565b6000700100000000000000010000000000000001831b1981611c8285600686901b6128e6565b6001901b9190951617949350505050565b6000611cac67ffffffffffffffff608084901c16612267565b60151492915050565b600080611cc3600184612822565b610fff901b85811690198516179150509392505050565b6000805b6005811015611d3b57838360028110611cf957611cf9612877565b60200201518160058110611d0f57611d0f612877565b6020020151600003611d295781611d258161288d565b9250505b80611d338161288d565b915050611cde565b5092915050565b60008481526020819052604081206002908101549190611d63908390612929565b6000878152602081905260409020600301549091506001600160601b03168115612014576000612710611d968385612929565b611da09190612940565b6040519091506001600160a01b0386169082156108fc029083906000818181858888f19350505050158015611dd9573d6000803e3d6000fd5b50600587610120015103611f4b576002611df38285612822565b611dfd9190612940565b8751909350600060200201516001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611e46573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e6a919061276c565b6001600160a01b03166108fc849081150290604051600060405180830381858888f19350505050158015611ea2573d6000803e3d6000fd5b508651600160200201516001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ee9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f0d919061276c565b6001600160a01b03166108fc849081150290604051600060405180830381858888f19350505050158015611f45573d6000803e3d6000fd5b50612012565b611f558184612822565b9250866000015187610120015160028110611f7257611f72612877565b60200201516001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611fb4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fd8919061276c565b6001600160a01b03166108fc849081150290604051600060405180830381858888f19350505050158015612010573d6000803e3d6000fd5b505b505b85516020810151905160408801516001600160a01b03928316929091169089907fdec5d867ed84be6d953aedc46aefecffb72ee1c2a55a7fe1a3a5fd5be6198225906000602002015160408b01516001602002015188878d61012001518e61014001518f61016001518f604051612092989796959493929190612954565b60405180910390a450505050505050565b60006120b0600183612822565b6120bb90600c612929565b83901c610fff16905092915050565b600383811c9083901c60006120e06008876128d2565b905060006120ef6008876128d2565b905080821115612115576040516319b6e55960e11b8152600481018690526024016115d2565b6000845b84811161216f57835b83811161215c5761213781600384901b6128e6565b612142906003612929565b88901b8317925080806121549061288d565b915050612122565b50806121678161288d565b915050612119565b50602089015181161561219857604051635624d5ff60e11b8152600481018790526024016115d2565b82156121ac57826121a881612912565b9350505b84156121c057846121bc81612912565b9550505b60078210156121d757816121d38161288d565b9250505b60078410156121ee57836121ea8161288d565b9450505b6000855b85811161224957845b8481116122365761221081600384901b6128e6565b61221b906003612929565b6007901b83179250808061222e9061288d565b9150506121fb565b50806122418161288d565b9150506121f2565b50895190911789526020909801805190981790975250505050505050565b6000612281675555555555555555600184901c1683612822565b915061229e673333333333333333600284901c81169084166128e6565b91506122ae600483901c836128e6565b670f0f0f0f0f0f0f0f16915060386122ce83670101010101010101612929565b67ffffffffffffffff16901c67ffffffffffffffff169050919050565b6040518060a0016040528060008152602001600081526020016000815260200160008152602001600081525090565b60405180610180016040528061232e6123a5565b815260200161233b6123a5565b81526020016123486123a5565b81526020016123556123a5565b81526020016123626123a5565b815260200161236f6123a5565b815260200161237c6123c3565b815260200160008152602001600081526020016000815260200160008152602001606081525090565b60405180604001604052806002906020820280368337509192915050565b60405180604001604052806002905b6123da6123f0565b8152602001906001900390816123d25790505090565b6040518060a001604052806005906020820280368337509192915050565b60006040828403121561242057600080fd5b50919050565b6001600160601b038116811461243b57600080fd5b50565b6001600160a01b038116811461243b57600080fd5b60008060008060a0858703121561246957600080fd5b612473868661240e565b935060408501359250606085013561248a81612426565b9150608085013561249a8161243e565b939692955090935050565b600080606083850312156124b857600080fd5b6124c2848461240e565b946040939093013593505050565b80516001600160a01b031682526020908101516001600160601b0316910152565b602080825282518282018190526000919060409081850190868401855b828110156125765781516125238582516124d0565b86810151612533878701826124d0565b508086015160808681019190915260608201516001600160601b031660a087015201516001600160a01b031660c085015260e0909301929085019060010161250e565b5091979650505050505050565b60006020828403121561259557600080fd5b5035919050565b6000806000806000806000806000806101408b8d0312156125bc57600080fd5b8a356125c781612426565b995060208b0135985060408b0135975060608b01356125e581612426565b965060808b0135955060a08b0135945060c08b0135935060e08b013592506101008b013591506101208b013561261a8161243e565b809150509295989b9194979a5092959850565b60e0810161263b82886124d0565b61264860408301876124d0565b60808201949094526001600160601b039290921660a08301526001600160a01b031660c09091015292915050565b60008060006060848603121561268b57600080fd5b833561269681612426565b95602085013595506040909401359392505050565b600080600080608085870312156126c157600080fd5b843593506020850135925060408501359150606085013561249a8161243e565b6000602082840312156126f357600080fd5b81356126fe81612426565b9392505050565b60008060006080848603121561271a57600080fd5b612724858561240e565b9250604084013561273481612426565b915060608401356127448161243e565b809150509250925092565b60006020828403121561276157600080fd5b81356126fe8161243e565b60006020828403121561277e57600080fd5b81516126fe8161243e565b634e487b7160e01b600052604160045260246000fd5b6000604082840312156127b157600080fd5b6040516040810181811067ffffffffffffffff821117156127e257634e487b7160e01b600052604160045260246000fd5b60405282356127f08161243e565b8152602083013561280081612426565b60208201529392505050565b634e487b7160e01b600052601160045260246000fd5b81810381811115611c5657611c5661280c565b81356128408161243e565b81546001600160a01b03199081166001600160a01b03929092169182178355602084013561286d81612426565b60a01b1617905550565b634e487b7160e01b600052603260045260246000fd5b60006001820161289f5761289f61280c565b5060010190565b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b6000826128e1576128e16128bc565b500690565b80820180821115611c5657611c5661280c565b60006020828403121561290b57600080fd5b5051919050565b6000816129215761292161280c565b506000190190565b8082028115828204841417611c5657611c5661280c565b60008261294f5761294f6128bc565b500490565b60006101008083018b845260208b818601528a60408601528960608601528860808601528760a08601528260c0860152819250865180835261012086019350818801925060005b818110156129b75783518552938201939282019260010161299b565b5050505060e092909201929092529897505050505050505056fea26469706673582212204e5900840ccb02dbc0aa3beafff8822aebd569f25dfccd400c96e50b56ee394664736f6c63430008110033
Loading...
Loading
[ 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.