ETH Price: $2,253.96 (-7.99%)

Contract

0x6a115E5938843515e55CF72Fe4B435fAF69725cF

Overview

ETH Balance

0 ETH

ETH Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Block
From
To
Set Placeholder4019966792025-11-19 19:32:3774 days ago1763580757IN
0x6a115E59...AF69725cF
0 ETH0.000000750.014236
Settle Game4019957832025-11-19 19:28:5174 days ago1763580531IN
0x6a115E59...AF69725cF
0 ETH0.000019170.03411
Show Chapters4019938362025-11-19 19:20:4774 days ago1763580047IN
0x6a115E59...AF69725cF
0 ETH0.000001660.019437
Set State4019936162025-11-19 19:19:5174 days ago1763579991IN
0x6a115E59...AF69725cF
0 ETH0.00000120.024416
Set Credits Cont...4019935702025-11-19 19:19:4074 days ago1763579980IN
0x6a115E59...AF69725cF
0 ETH0.000000720.025439
Set Auditor Cont...4019935682025-11-19 19:19:3974 days ago1763579979IN
0x6a115E59...AF69725cF
0 ETH0.000000730.02564
Set Max Extract4019935652025-11-19 19:19:3974 days ago1763579979IN
0x6a115E59...AF69725cF
0 ETH0.000000790.025724
Set Credits Cont...4019934762025-11-19 19:19:1674 days ago1763579956IN
0x6a115E59...AF69725cF
0 ETH0.00000080.028072
Set Auditor Cont...4019934742025-11-19 19:19:1674 days ago1763579956IN
0x6a115E59...AF69725cF
0 ETH0.000000790.027973
Set Max Extract4019934722025-11-19 19:19:1574 days ago1763579955IN
0x6a115E59...AF69725cF
0 ETH0.000000850.027965
Buy In4019933612025-11-19 19:18:4774 days ago1763579927IN
0x6a115E59...AF69725cF
0.00001 ETH0.000002230.028719
Set Credits Cont...4019932812025-11-19 19:18:2774 days ago1763579907IN
0x6a115E59...AF69725cF
0 ETH0.000000790.027951
Set Auditor Cont...4019932792025-11-19 19:18:2774 days ago1763579907IN
0x6a115E59...AF69725cF
0 ETH0.00000080.028185
Set Max Extract4019932772025-11-19 19:18:2674 days ago1763579906IN
0x6a115E59...AF69725cF
0 ETH0.000000860.028103
Buy In4019932682025-11-19 19:18:2474 days ago1763579904IN
0x6a115E59...AF69725cF
0.00001 ETH0.00000220.028402
Set Credits Cont...4019932222025-11-19 19:18:1274 days ago1763579892IN
0x6a115E59...AF69725cF
0 ETH0.00000080.028249
Set Auditor Cont...4019932162025-11-19 19:18:1174 days ago1763579891IN
0x6a115E59...AF69725cF
0 ETH0.000000780.027431
Set Max Extract4019932102025-11-19 19:18:0974 days ago1763579889IN
0x6a115E59...AF69725cF
0 ETH0.000000830.027251
Buy In4019931712025-11-19 19:18:0074 days ago1763579880IN
0x6a115E59...AF69725cF
0.00001 ETH0.000001960.025281
Buy In4019930682025-11-19 19:17:3474 days ago1763579854IN
0x6a115E59...AF69725cF
0.00001 ETH0.0000010.012807
Buy In4019927402025-11-19 19:16:1274 days ago1763579772IN
0x6a115E59...AF69725cF
0.00001 ETH0.000000790.01
Buy In4019925932025-11-19 19:15:3674 days ago1763579736IN
0x6a115E59...AF69725cF
0.00001 ETH0.000000790.01
Buy In4019922222025-11-19 19:14:0374 days ago1763579643IN
0x6a115E59...AF69725cF
0.00001 ETH0.000000790.01
Buy In4019921292025-11-19 19:13:4074 days ago1763579620IN
0x6a115E59...AF69725cF
0.00001 ETH0.000000810.010242
Buy In4019920332025-11-19 19:13:1674 days ago1763579596IN
0x6a115E59...AF69725cF
0.00001 ETH0.000000790.01
View all transactions

Latest 25 internal transactions (View All)

Parent Transaction Hash Block From To
4019957832025-11-19 19:28:5174 days ago1763580531
0x6a115E59...AF69725cF
0.00001 ETH
4019957832025-11-19 19:28:5174 days ago1763580531
0x6a115E59...AF69725cF
0.00001 ETH
4019957832025-11-19 19:28:5174 days ago1763580531
0x6a115E59...AF69725cF
0.00001 ETH
4019957832025-11-19 19:28:5174 days ago1763580531
0x6a115E59...AF69725cF
0.00001 ETH
4019957832025-11-19 19:28:5174 days ago1763580531
0x6a115E59...AF69725cF
0.00001 ETH
4019957832025-11-19 19:28:5174 days ago1763580531
0x6a115E59...AF69725cF
0.00001 ETH
4019957832025-11-19 19:28:5174 days ago1763580531
0x6a115E59...AF69725cF
0.00001 ETH
4019957832025-11-19 19:28:5174 days ago1763580531
0x6a115E59...AF69725cF
0.00001 ETH
4019957832025-11-19 19:28:5174 days ago1763580531
0x6a115E59...AF69725cF
0.00001 ETH
4019957832025-11-19 19:28:5174 days ago1763580531
0x6a115E59...AF69725cF
0.00001 ETH
4019957832025-11-19 19:28:5174 days ago1763580531
0x6a115E59...AF69725cF
0.00001 ETH
4019957832025-11-19 19:28:5174 days ago1763580531
0x6a115E59...AF69725cF
0.00001 ETH
4019957832025-11-19 19:28:5174 days ago1763580531
0x6a115E59...AF69725cF
0.00001 ETH
4019885192025-11-19 18:58:3874 days ago1763578718
0x6a115E59...AF69725cF
0.00001 ETH
4019885162025-11-19 18:58:3774 days ago1763578717
0x6a115E59...AF69725cF
0.00001 ETH
4019885162025-11-19 18:58:3774 days ago1763578717
0x6a115E59...AF69725cF
0.00001 ETH
4019885162025-11-19 18:58:3774 days ago1763578717
0x6a115E59...AF69725cF
0.00001 ETH
4019885162025-11-19 18:58:3774 days ago1763578717
0x6a115E59...AF69725cF
0.00001 ETH
4019885162025-11-19 18:58:3774 days ago1763578717
0x6a115E59...AF69725cF
0.00001 ETH
4019885162025-11-19 18:58:3774 days ago1763578717
0x6a115E59...AF69725cF
0.00001 ETH
4019885162025-11-19 18:58:3774 days ago1763578717
0x6a115E59...AF69725cF
0.00001 ETH
4019885162025-11-19 18:58:3774 days ago1763578717
0x6a115E59...AF69725cF
0.00001 ETH
4019885162025-11-19 18:58:3774 days ago1763578717
0x6a115E59...AF69725cF
0.00001 ETH
4019885162025-11-19 18:58:3774 days ago1763578717
0x6a115E59...AF69725cF
0.00001 ETH
4019885162025-11-19 18:58:3774 days ago1763578717
0x6a115E59...AF69725cF
0.00001 ETH
View All Internal Transactions

Cross-Chain Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Game

Compiler Version
v0.8.26+commit.8a97fa7a

Optimization Enabled:
Yes with 200 runs

Other Settings:
cancun EvmVersion
File 1 of 3 : Game.sol
//SPDX-License-Identifier: MIT
pragma solidity >=0.8.0 <0.9.0;


/*
'##::::'##::::'###::::'##::::'##::::'########:'##::::'##:'########:'########:::::'###:::::'######::'########:
 ###::'###:::'## ##:::. ##::'##::::: ##.....::. ##::'##::... ##..:: ##.... ##:::'## ##:::'##... ##:... ##..::
 ####'####::'##:. ##:::. ##'##:::::: ##::::::::. ##'##:::::: ##:::: ##:::: ##::'##:. ##:: ##:::..::::: ##::::
 ## ### ##:'##:::. ##:::. ###::::::: ######:::::. ###::::::: ##:::: ########::'##:::. ##: ##:::::::::: ##::::
 ##. #: ##: #########::: ## ##:::::: ##...:::::: ## ##:::::: ##:::: ##.. ##::: #########: ##:::::::::: ##::::
 ##:.:: ##: ##.... ##:: ##:. ##::::: ##:::::::: ##:. ##::::: ##:::: ##::. ##:: ##.... ##: ##::: ##:::: ##::::
 ##:::: ##: ##:::: ##: ##:::. ##:::: ########: ##:::. ##:::: ##:::: ##:::. ##: ##:::: ##:. ######::::: ##::::
..:::::..::..:::::..::..:::::..:::::........::..:::::..:::::..:::::..:::::..::..:::::..:::......::::::..:::::
.................................  
..####....####...##...##..######.
.##......##..##..###.###..##.....
.##.###..######..##.#.##..####...
.##..##..##..##..##...##..##.....
..####...##..##..##...##..######.
.................................                                                                                  */



import "./Universe.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

// WETH interface for safe ETH transfers
interface IWETH {
    function deposit() external payable;
    function transfer(address to, uint256 value) external returns (bool);
    function balanceOf(address) external view returns (uint256);
}

// MaxExtract interface for credential verification
interface IMaxExtract {
    function getActiveSectors() external view returns (uint256[] memory);
    function sectors(uint256 sectorId) external view returns (address);
    function sectorToOwner(uint256 sectorId) external view returns (address);
    function playerToSector(address player) external view returns (uint256);
    function getStakedBalance(address pilot) external view returns (uint256);
}

/**
 * Game Contract - Manages game sessions and player participation
 * Controls visible chapters, game state, and player buy-ins
 * @author Max Extract Protocol
 */
contract Game {
    // Game configuration - hardcoded values
    uint256 public constant BUY_IN_PRICE = 0.00001 ether;
    uint256 public immutable gameEndTime = block.timestamp + 75 minutes;
    
    // WETH contract address (Ethereum mainnet - update for other networks)
    address public constant WETH_ADDRESS = 0x82aF49447D8a07e3bd95BD0d56f35241523fBab1;
    
    // Reference to the Universe contract
    Universe public immutable universe;
    
    // Reference to the MaxExtract contract for credential verification
    IMaxExtract public maxExtract;
    
    // Reference to the Auditor contract
    address public auditorContract;
    
    // Reference to the MaxExtract contract address for authorization checks
    address public maxExtractContract;
    
    // Reference to the Credits ERC20 token contract
    IERC20 public creditsContract;
    
    // Maintenance mode placeholder message
    string public placeholder;
    
    // Game states
    enum GameState {
        Open,    // 0 - Players can buy in
        Active,  // 1 - Game is active, no more buy-ins allowed
        Settled  // 2 - Game has been settled, winners determined
    }
    
    // Game state variables
    GameState public state;
    uint8[] public visibleChapters;
    address[] public players;
    address[] public pilots;
    
    // Game end and settlement variables
    address[] public gameWinners;          // Array of winner addresses after settlement
    uint256 public winningScore;           // The winning score after settlement
    
    // Player tracking
    mapping(address => bool) public isPlayerMapping;
    
    // Pilot tracking (use isPilot() function to exclude dead pilots)
    mapping(address => bool) public isPilotMapping;
    
    // Player scores mapping
    mapping(address => uint256) public scores;
    
    // Pilot death tracking
    mapping(address => bool) public deadPilots;
    
    // Track which pilots have minted credentials from which players (one per pilot per player)
    mapping(address => mapping(address => bool)) public pilotPlayerCredentialMinted;
    
    // Track the base type for each sector (1-6, where 1 is default/starter)
    // Base types represent different station tiers/visuals
    mapping(uint256 => uint8) public sectorBaseType;
    
    // Events
    event ChaptersUpdated(uint8[] newVisibleChapters);
    event GameStateChanged(GameState newState);
    event PlayerBoughtIn(address indexed player, uint256 amount);
    event PotPaidOut(address[] recipients, uint256[] percentages, uint256 totalAmount);
    event PilotAdded(address indexed pilot);
    event PilotsAdded(address[] pilots);
    event TipGiven(address indexed pilot, address indexed player, uint256 amount);
    event PilotDied(address indexed pilot, address indexed killer, address indexed playerPenalized, uint256 scorePenalty, uint256 ethForwarded);
    event GameSettled(address[] winners, uint256 winningScore, uint256 totalPayout, uint256 payoutPerWinner);
    event CredentialMinted(address indexed pilot, address indexed player, address indexed credentialContract);
    event PointsDeducted(address indexed player, uint256 amount, uint256 newScore);
    event StationUpgraded(uint256 indexed sectorId, address indexed player, address indexed pilotCaller, uint8 newBaseType);
    event StationBaseTypeSet(uint256 indexed sectorId, uint8 newBaseType, address indexed setBy);
    event PlaceholderUpdated(string newPlaceholder);
    
    // Errors
    error OnlyGod();
    error OnlyPilot();
    error GameNotOpen();
    error InsufficientPayment();
    error PlayerAlreadyJoined();
    error PilotAlreadyAdded();
    error InvalidArrayLengths();
    error InvalidPercentages();
    error PayoutFailed();
    error PilotAlreadyDead();
    error NotAPlayer();
    error GameNotEnded();
    error GameAlreadySettled();
    error NotACredential();
    error CredentialNotRegistered();
    error MaxExtractNotSet();
    error PilotAlreadyMintedFromPlayer();
    error OnlyAuditor();
    error InsufficientPoints();
    error NotARegistry();
    error InsufficientCreditsForUpgrade();
    error NotAFuelContract();
    error StationMaxLevel();
    error InvalidBaseType();
    error OnlyMaxExtract();
    
    modifier onlyGod() {
        if (msg.sender != universe.GOD()) revert OnlyGod();
        _;
    }
    
    modifier onlyPilot() {
        if (!isPilot(msg.sender)) revert OnlyPilot();
        _;
    }
    
    modifier gameOpen() {
        if (state != GameState.Open) revert GameNotOpen();
        _;
    }
    
    /**
     * Get a module address from a registry contract
     * @param registryAddress The registry contract address
     * @param moduleName The name of the module to look up
     * @return moduleAddress The address of the module, or address(0) if not found
     */
    function _getModule(
        address registryAddress,
        string memory moduleName
    ) private view returns (address moduleAddress) {
        (bool success, bytes memory data) = registryAddress.staticcall(
            abi.encodeWithSignature("modules(string)", moduleName)
        );
        
        if (!success || data.length < 32) {
            return address(0);
        }
        
        moduleAddress = abi.decode(data, (address));
    }
    
    constructor(address _universe) {
        universe = Universe(_universe);
        state = GameState.Open;
    }
    
    /**
     * Set which chapters are visible to players
     * Only callable by the God address
     * @param _chapters Array of chapter numbers to make visible
     */
    function showChapters(uint8[] calldata _chapters) external onlyGod {
        visibleChapters = _chapters;
        emit ChaptersUpdated(_chapters);
    }
    
    /**
     * Change the game state
     * Only callable by the God address
     * @param _newState The new game state
     */
    function setState(GameState _newState) external onlyGod {
        state = _newState;
        emit GameStateChanged(_newState);
    }
    
    
    /**
     * Add a pilot address
     * Only callable by the God address
     * @param _pilot Address to add as a pilot
     */
    function addPilot(address _pilot) external onlyGod {
        // Check if pilot is already added
        if (isPilot(_pilot)) revert PilotAlreadyAdded();
        
        pilots.push(_pilot);
        isPilotMapping[_pilot] = true; // Add to mapping for O(1) lookups
        emit PilotAdded(_pilot);
    }
    
    /**
     * Add multiple pilot addresses in batch and fund them with ETH
     * Only callable by the God address
     * @param _pilots Array of addresses to add as pilots
     */
    function addPilots(address[] calldata _pilots) external payable onlyGod {
        require(_pilots.length > 0, "No pilots provided");
        
        uint256 newPilotsCount = 0;
        
        // First pass: count new pilots and add them
        for (uint256 i = 0; i < _pilots.length; i++) {
            if (!isPilot(_pilots[i])) {
                pilots.push(_pilots[i]);
                isPilotMapping[_pilots[i]] = true;
                newPilotsCount++;
            }
        }
        
        // If ETH was sent and we have new pilots, distribute it equally
        if (msg.value > 0 && newPilotsCount > 0) {
            uint256 ethPerPilot = msg.value / newPilotsCount;
            uint256 remainder = msg.value % newPilotsCount;
            
            // Second pass: fund the new pilots
            for (uint256 i = 0; i < _pilots.length; i++) {
                // Check if this pilot was just added (appears exactly once in pilots array)
                bool wasJustAdded = false;
                uint256 pilotCount = 0;
                for (uint256 j = 0; j < pilots.length; j++) {
                    if (pilots[j] == _pilots[i]) {
                        pilotCount++;
                        if (pilotCount == 1) {
                            wasJustAdded = true;
                        } else {
                            wasJustAdded = false;
                            break;
                        }
                    }
                }
                
                if (wasJustAdded && ethPerPilot > 0) {
                    uint256 amountToSend = ethPerPilot;
                    if (remainder > 0) {
                        amountToSend += remainder;
                        remainder = 0;
                    }
                    
                    (bool success, ) = payable(_pilots[i]).call{value: amountToSend}("");
                    require(success, "ETH transfer failed");
                }
            }
        }
        
        emit PilotsAdded(_pilots);
    }
    
    /**
     * Fund existing pilots with ETH in batch - smart top-up system
     * Only callable by the God address
     * Checks each pilot's balance and only sends enough to reach the minimum
     * Refunds any unused ETH back to GOD
     * @param _pilots Array of pilot addresses to fund
     * @param minBalancePerPilot Minimum balance each pilot should have
     */
    function fundPilots(address[] calldata _pilots, uint256 minBalancePerPilot) external payable onlyGod {
        require(_pilots.length > 0, "No pilots provided");
        require(minBalancePerPilot > 0, "Invalid minimum balance");
        
        uint256 totalSent = 0;
        
        // Loop through each pilot and top up if needed
        for (uint256 i = 0; i < _pilots.length; i++) {
            uint256 currentBalance = _pilots[i].balance;
            
            // Only send if below minimum
            if (currentBalance < minBalancePerPilot) {
                uint256 amountNeeded = minBalancePerPilot - currentBalance;
                
                (bool success, ) = payable(_pilots[i]).call{value: amountNeeded}("");
                require(success, "ETH transfer failed");
                
                totalSent += amountNeeded;
            }
        }
        
        // Refund any unused ETH back to GOD
        uint256 remaining = msg.value - totalSent;
        if (remaining > 0) {
            (bool refundSuccess, ) = payable(msg.sender).call{value: remaining}("");
            require(refundSuccess, "Refund failed");
        }
    }
    
    /**
     * Buy into the game by paying the buy-in price
     * Only available when game state is Open
     * Players can only buy in once
     */
    function buyIn() external payable gameOpen {
        if (msg.value < BUY_IN_PRICE) revert InsufficientPayment();
        
        // Check if player has already joined
        if (isPlayerMapping[msg.sender]) revert PlayerAlreadyJoined();
        
        players.push(msg.sender);
        isPlayerMapping[msg.sender] = true;
        
        // Players start with 0 points
        scores[msg.sender] = 0;
        
        emit PlayerBoughtIn(msg.sender, msg.value);
        
        // Refund excess payment
        if (msg.value > BUY_IN_PRICE) {
            payable(msg.sender).transfer(msg.value - BUY_IN_PRICE);
        }
    }
    
    /**
     * Get all visible chapters
     * @return Array of visible chapter numbers
     */
    function getVisibleChapters() external view returns (uint8[] memory) {
        return visibleChapters;
    }
    
    /**
     * Get all players who have bought in
     * @return Array of player addresses
     */
    function getPlayers() external view returns (address[] memory) {
        return players;
    }
    
    /**
     * Get the number of players who have bought in
     * @return Number of players
     */
    function getPlayerCount() external view returns (uint256) {
        return players.length;
    }
    
    /**
     * Check if a specific address is a player
     * @param _player Address to check
     * @return True if the address is a player
     */
    function isPlayer(address _player) external view returns (bool) {
        return isPlayerMapping[_player];
    }
    
    /**
     * Check if a specific address is a pilot (excludes dead pilots)
     * @param _pilot Address to check
     * @return True if the address is a pilot and not dead
     */
    function isPilot(address _pilot) public view returns (bool) {
        if (deadPilots[_pilot]) {
            return false;
        }
        
        return isPilotMapping[_pilot];
    }
    
    /**
     * Check if a pilot is dead
     * @param _pilot Address to check
     * @return True if the pilot is dead
     */
    function isPilotDead(address _pilot) external view returns (bool) {
        return deadPilots[_pilot];
    }
    
    /**
     * Get all pilots
     * @return Array of pilot addresses
     */
    function getPilots() external view returns (address[] memory) {
        return pilots;
    }
    
    /**
     * Get the number of pilots
     * @return Number of pilots
     */
    function getPilotCount() external view returns (uint256) {
        return pilots.length;
    }
    
    /**
     * Get all pilots with their ETH balances and death status
     * @return pilotAddresses Array of pilot addresses
     * @return ethBalances Array of ETH balances (in wei)
     * @return isDead Array of death status for each pilot
     */
    function getAllPilotsAndBalances() external view returns (
        address[] memory pilotAddresses,
        uint256[] memory ethBalances,
        bool[] memory isDead
    ) {
        uint256 pilotCount = pilots.length;
        
        pilotAddresses = new address[](pilotCount);
        ethBalances = new uint256[](pilotCount);
        isDead = new bool[](pilotCount);
        
        for (uint256 i = 0; i < pilotCount; i++) {
            address pilot = pilots[i];
            pilotAddresses[i] = pilot;
            ethBalances[i] = pilot.balance;
            isDead[i] = deadPilots[pilot];
        }
        
        return (pilotAddresses, ethBalances, isDead);
    }

    /**
     * Dead man's switch - called when a pilot is killed
     * Marks the pilot as dead and penalizes the player with 10 points
     * Only callable by pilots
     * @param _killer Address of the pilot who killed this pilot
     * @param _playerToPenalize Address of the player to penalize (sector owner)
     */
    function deadMansSwitch(address _killer, address _playerToPenalize) external {
        // Use isPilotMapping directly to allow edge case calls
        if (!isPilotMapping[msg.sender]) revert OnlyPilot();
        
        // Check if pilot is already dead
        if (deadPilots[msg.sender]) revert PilotAlreadyDead();
        
        // Check if the player to penalize is actually a player
        if (!isPlayerMapping[_playerToPenalize]) revert NotAPlayer();
        
        // Mark pilot as dead
        deadPilots[msg.sender] = true;
        
        // Apply 10-point penalty to player
        uint256 currentScore = scores[_playerToPenalize];
        uint256 penalty = currentScore >= 10 ? 10 : currentScore;
        scores[_playerToPenalize] = currentScore - penalty;
        
        emit PilotDied(msg.sender, _killer, _playerToPenalize, penalty, 0);
    }
    
    /**
     * Dead man's slash - called when a pilot is killed and player has audited stake module
     * Marks the pilot as dead and slashes the killer via stake contract
     * Only callable by pilots
     * @param _killer Address of the pilot who killed this pilot
     * @param _playerToPenalize Address of the player (sector owner) - used to find stake contract
     */
    function deadMansSlash(address _killer, address _playerToPenalize) external {
        // Use isPilotMapping directly to allow edge case calls
        if (!isPilotMapping[msg.sender]) revert OnlyPilot();
        
        // Check if pilot is already dead
        if (deadPilots[msg.sender]) revert PilotAlreadyDead();
        
        // Check if the player to penalize is actually a player
        if (!isPlayerMapping[_playerToPenalize]) revert NotAPlayer();
        
        // Mark pilot as dead
        deadPilots[msg.sender] = true;
        
        // Get player's sector
        uint256 sectorId = maxExtract.playerToSector(_playerToPenalize);
        require(sectorId != 0, "Player has no sector");
        
        // Get registry
        address registry = maxExtract.sectors(sectorId);
        require(registry != address(0), "No registry");
        
        // Get stake module
        address stakeContract = _getModule(registry, "stake");
        require(stakeContract != address(0), "No stake module");
        
        // Verify audited for chapter 4
        require(auditorContract != address(0), "Auditor not set");
        (bool success, bytes memory data) = auditorContract.staticcall(
            abi.encodeWithSignature("isAudited(address)", stakeContract)
        );
        require(success && data.length >= 32, "Audit check failed");
        uint8 auditStatus = abi.decode(data, (uint8));
        require(auditStatus == 4, "Not audited for chapter 4");
        
        // Get killer's staked balance BEFORE slash
        uint256 balanceBefore = maxExtract.getStakedBalance(_killer);
        require(balanceBefore >= 10_000 * 10**18, "Killer has insufficient stake");
        
        // Call slash on stake contract
        (bool slashSuccess, ) = stakeContract.call(
            abi.encodeWithSignature("slash(address)", _killer)
        );
        require(slashSuccess, "Slash call failed");
        
        // VERIFY the slash actually burned the stake
        uint256 balanceAfter = maxExtract.getStakedBalance(_killer);
        require(balanceAfter == 0, "Slash did not burn stake - malicious stake contract");
        require(balanceBefore - balanceAfter >= 10_000 * 10**18, "Slash did not burn full stake amount");
        
        // Emit PilotDied with 0 penalty (slashing verified successful)
        emit PilotDied(msg.sender, _killer, _playerToPenalize, 0, 0);
    }
    
    /**
     * Tip a player with a score increase
     * Only callable by pilots
     * @param _player Address of the player to tip
     * @param _tipAmount Amount to add to the player's score
     */
    function tipPlayer(address _player, uint256 _tipAmount) external onlyPilot {
        scores[_player] += _tipAmount;
        emit TipGiven(msg.sender, _player, _tipAmount);
    }
    
    /**
     * Get a player's current score
     * @param _player Address of the player
     * @return The player's current score
     */
    function getPlayerScore(address _player) external view returns (uint256) {
        return scores[_player];
    }
    
    /**
     * Get the current game state information
     * @return _state Current game state
     * @return _playerCount Number of players
     * @return _buyInPrice Current buy-in price
     */
    function getGameInfo() external view returns (
        GameState _state,
        uint256 _playerCount,
        uint256 _buyInPrice
    ) {
        return (state, players.length, BUY_IN_PRICE);
    }
    
    /**
     * Pay out the pot to multiple recipients with specified percentages
     * Only callable by the God address
     * @param recipients Array of addresses to receive payouts
     * @param percentages Array of percentages (in basis points, e.g., 333 = 3.33%)
     */
    function payoutPot(address[] calldata recipients, uint256[] calldata percentages) external onlyGod {
        // Validate input arrays
        if (recipients.length == 0 || recipients.length != percentages.length) {
            revert InvalidArrayLengths();
        }
        
        // Validate percentages sum to 1000 (100.0%)
        uint256 totalPercentage = 0;
        for (uint256 i = 0; i < percentages.length; i++) {
            totalPercentage += percentages[i];
        }
        if (totalPercentage != 1000) {
            revert InvalidPercentages();
        }
        
        uint256 totalBalance = address(this).balance;
        if (totalBalance == 0) return; // Nothing to pay out
        
        // Pay out to each recipient
        for (uint256 i = 0; i < recipients.length; i++) {
            if (recipients[i] == address(0)) continue; // Skip zero addresses
            
            uint256 amount = (totalBalance * percentages[i]) / 1000;
            if (amount > 0) {
                (bool success, ) = payable(recipients[i]).call{value: amount}("");
                if (!success) revert PayoutFailed();
            }
        }
        
        emit PotPaidOut(recipients, percentages, totalBalance);
    }

    /**
     * Withdraw remaining contract balance to God address
     * Only callable by the God address
     */
    function withdraw() external onlyGod {
        payable(universe.GOD()).transfer(address(this).balance);
    }
    
    /**
     * Get contract balance
     * @return Contract balance in wei
     */
    function getBalance() external view returns (uint256) {
        return address(this).balance;
    }
    
    /**
     * Settle the game by finding the highest scoring player(s) and paying out the pot
     * Can be called by anyone after the game end time has passed
     * Splits the pot equally among all players with the highest score
     */
    function settleGame() external {
        // Check if game has ended
        if (block.timestamp < gameEndTime) revert GameNotEnded();
        
        // Check if game has already been settled
        if (state == GameState.Settled) revert GameAlreadySettled();
        
        // If no players, nothing to settle
        if (players.length == 0) {
            state = GameState.Settled;
            return;
        }
        
        // Find the highest score
        uint256 highestScore = 0;
        for (uint256 i = 0; i < players.length; i++) {
            uint256 playerScore = scores[players[i]];
            if (playerScore > highestScore) {
                highestScore = playerScore;
            }
        }
        
        // Find all players with the highest score
        address[] memory winners = new address[](players.length);
        uint256 winnerCount = 0;
        
        for (uint256 i = 0; i < players.length; i++) {
            if (scores[players[i]] == highestScore) {
                winners[winnerCount] = players[i];
                winnerCount++;
            }
        }
        
        // Resize winners array to actual winner count
        gameWinners = new address[](winnerCount);
        for (uint256 i = 0; i < winnerCount; i++) {
            gameWinners[i] = winners[i];
        }
        
        // Set winning score and mark as settled
        winningScore = highestScore;
        state = GameState.Settled;
        
        // Calculate and distribute payout
        uint256 totalPayout = address(this).balance;
        uint256 payoutPerWinner = 0;
        
        if (totalPayout > 0 && winnerCount > 0) {
            payoutPerWinner = totalPayout / winnerCount;
            
            // Pay each winner
            for (uint256 i = 0; i < winnerCount; i++) {
                (bool success, ) = payable(gameWinners[i]).call{value: payoutPerWinner}("");
                if (!success) revert PayoutFailed();
            }
        }
        
        emit GameSettled(gameWinners, winningScore, totalPayout, payoutPerWinner);
    }
    
    /**
     * Get the game winners (only available after settlement)
     * @return Array of winner addresses
     */
    function getGameWinners() external view returns (address[] memory) {
        return gameWinners;
    }
    
    /**
     * Check if the game can be settled (time has passed and not already settled)
     * @return True if current time is past game end time and game is not settled
     */
    function canGameSettle() external view returns (bool) {
        return block.timestamp >= gameEndTime && state != GameState.Settled;
    }
    
    /**
     * Get time remaining until game ends
     * @return Seconds remaining (0 if game has ended)
     */
    function getTimeRemaining() external view returns (uint256) {
        if (block.timestamp >= gameEndTime) {
            return 0;
        }
        return gameEndTime - block.timestamp;
    }
    
    /**
     * Set the MaxExtract contract address
     * Only callable by the God address
     * @param _maxExtract Address of the MaxExtract contract
     */
    function setMaxExtract(address _maxExtract) external onlyGod {
        require(_maxExtract != address(0), "Invalid address");
        maxExtract = IMaxExtract(_maxExtract);
        maxExtractContract = _maxExtract;
    }
    
    /**
     * Check if a pilot has access to a specific sector
     * Checks if the pilot owns a credential NFT from that sector's credential contract
     * @param _pilot The pilot address to check
     * @param _sectorId The sector ID to check access for
     * @return True if the pilot has a credential (balance > 0)
     */
    function canPilotAccessSector(address _pilot, uint256 _sectorId) external view returns (bool) {
        if (address(maxExtract) == address(0)) return false;
        
        // Get the registry for this sector
        address registryAddress = maxExtract.sectors(_sectorId);
        if (registryAddress == address(0)) return false;
        
        // Get the credential contract from the registry
        address credentialContract = _getModule(registryAddress, "credential");
        if (credentialContract == address(0)) return false;
        
        // Check the pilot's balance in the credential contract (ERC721 balanceOf)
        (bool balanceSuccess, bytes memory balanceData) = credentialContract.staticcall(
            abi.encodeWithSignature("balanceOf(address)", _pilot)
        );
        
        if (!balanceSuccess || balanceData.length < 32) return false;
        
        uint256 balance = abi.decode(balanceData, (uint256));
        return balance > 0;
    }
    
    /**
     * Called by a credential contract when a pilot mints a credential
     * Derives the player address from the sector owner
     * Awards 2 points to the player if verification succeeds
     * Only callable by registered credential contracts through pilot transactions
     * Each pilot can only mint one credential per player (prevents point farming)
     * @param _sectorId The sector ID that the credential belongs to
     */
    function pilotMintSectorCredential(uint256 _sectorId) external {
        if (address(maxExtract) == address(0)) revert MaxExtractNotSet();
        
        // tx.origin must be a pilot
        if (!isPilot(tx.origin)) revert OnlyPilot();
        
        // Get the registry for this sector
        address registryAddress = maxExtract.sectors(_sectorId);
        if (registryAddress == address(0)) revert NotARegistry();
        
        // Get the registered credential contract from the registry
        address registeredCredential = _getModule(registryAddress, "credential");
        if (registeredCredential == address(0)) revert CredentialNotRegistered();
        
        // Verify that msg.sender (the credential contract) matches the registered credential
        if (registeredCredential != msg.sender) revert CredentialNotRegistered();
        
        // Get the player who owns this sector
        address player = maxExtract.sectorToOwner(_sectorId);
        if (player == address(0)) revert NotAPlayer();
        
        // Check if this pilot has already minted a credential from this player
        if (pilotPlayerCredentialMinted[tx.origin][player]) revert PilotAlreadyMintedFromPlayer();
        
        // Mark that this pilot has minted from this player
        pilotPlayerCredentialMinted[tx.origin][player] = true;
        
        // All checks passed - award 2 points to the player
        scores[player] += 2;
        
        emit CredentialMinted(tx.origin, player, msg.sender);
    }
    
    /**
     * Called by a fuel contract when a pilot triggers the station upgrade
     * Verifies the fuel contract has 49,500 credits and transfers them to the game
     * Awards 50 points to the player upon successful upgrade
     * Only callable by registered fuel contracts through pilot transactions
     * @param _sectorId The sector ID that is being upgraded
     */
    function upgradeStation(uint256 _sectorId) external {
        if (address(maxExtract) == address(0)) revert MaxExtractNotSet();
        
        // tx.origin must be a pilot (the one calling upgrade on the fuel contract)
        if (!isPilot(tx.origin)) revert OnlyPilot();
        
        // Get the registry for this sector
        address registryAddress = maxExtract.sectors(_sectorId);
        if (registryAddress == address(0)) revert NotARegistry();
        
        // Get the registered sale contract from the registry
        address fuelContract = _getModule(registryAddress, "sale");
        if (fuelContract == address(0)) revert NotAFuelContract();
        
        // Verify that msg.sender (the sale contract) matches the registered sale contract
        if (fuelContract != msg.sender) revert NotAFuelContract();
        
        // Get the player who owns this sector
        address player = maxExtract.sectorToOwner(_sectorId);
        if (player == address(0)) revert NotAPlayer();
        
        // Get current base type (defaults to 1 if never upgraded)
        uint8 currentBaseType = sectorBaseType[_sectorId];
        if (currentBaseType == 0) currentBaseType = 1; // First time, start at base1
        
        // Check if station is already at max level
        if (currentBaseType >= 6) revert StationMaxLevel();
        
        // Verify the fuel contract has at least 49,500 credits
        uint256 upgradeAmount = 49_500 * 10**18;
        if (creditsContract.balanceOf(fuelContract) < upgradeAmount) {
            revert InsufficientCreditsForUpgrade();
        }
        
        // Transfer 49,500 credits from fuel contract to Game contract (requires prior approval)
        creditsContract.transferFrom(fuelContract, address(this), upgradeAmount);
        
        // Award 10 points to the player for upgrading their station
        scores[player] += 10;
        
        // Upgrade station to next level
        uint8 newBaseType = currentBaseType + 1;
        sectorBaseType[_sectorId] = newBaseType;
        
        emit StationUpgraded(_sectorId, player, tx.origin, newBaseType);
    }
    
    /**
     * Get the base type for a sector
     * Returns the base type (1-6) for rendering the correct station image
     * @param _sectorId The sector ID to query
     * @return baseType The base type (1-6), defaults to 1 if never upgraded
     */
    function getSectorBaseType(uint256 _sectorId) external view returns (uint8) {
        uint8 baseType = sectorBaseType[_sectorId];
        return baseType == 0 ? 1 : baseType; // Default to base1 if not set
    }
    
    /**
     * Set the base type for a sector (God only - for testing/admin)
     * Allows the God account to manually set any sector's base type
     * @param _sectorId The sector ID to set
     * @param _baseType The base type to set (1-6)
     */
    function setSectorBaseType(uint256 _sectorId, uint8 _baseType) external onlyGod {
        if (_baseType < 1 || _baseType > 6) revert InvalidBaseType();
        sectorBaseType[_sectorId] = _baseType;
        emit StationBaseTypeSet(_sectorId, _baseType, msg.sender);
    }
    
    /**
     * Deduct points from a player's score
     * Only callable by the Auditor contract
     * Used when players request contract audits or other point-deducting actions
     * @param _player The player address to deduct points from
     * @param _amount The number of points to deduct
     */
    function deductPoints(address _player, uint256 _amount) external {
        if (msg.sender != auditorContract) revert OnlyAuditor();
        
        // Check if the player exists
        bool isValidPlayer = false;
        for (uint256 i = 0; i < players.length; i++) {
            if (players[i] == _player) {
                isValidPlayer = true;
                break;
            }
        }
        if (!isValidPlayer) revert NotAPlayer();
        
        // Check if player has enough points
        uint256 currentScore = scores[_player];
        if (currentScore < _amount) revert InsufficientPoints();
        
        // Deduct points
        scores[_player] = currentScore - _amount;
        
        emit PointsDeducted(_player, _amount, scores[_player]);
    }
    
    /**
     * Award broadcast points to a player
     * Only callable by the MaxExtract contract
     * Called when a player broadcasts their sector for the first time
     * @param _player The player address to award points to
     */
    function awardBroadcastPoints(address _player) external {
        if (msg.sender != maxExtractContract) revert OnlyMaxExtract();
        
        // Check if the player exists
        bool isValidPlayer = false;
        for (uint256 i = 0; i < players.length; i++) {
            if (players[i] == _player) {
                isValidPlayer = true;
                break;
            }
        }
        if (!isValidPlayer) revert NotAPlayer();
        
        // Award 5 points
        scores[_player] += 5;
    }
    
    /**
     * Set the Auditor contract address
     * Only callable by the God address
     * @param _auditor Address of the Auditor contract
     */
    function setAuditorContract(address _auditor) external onlyGod {
        require(_auditor != address(0), "Invalid address");
        auditorContract = _auditor;
    }
    
    /**
     * Set the Credits ERC20 token contract address
     * Only callable by the God address
     * @param _credits Address of the Credits token contract
     */
    function setCreditsContract(address _credits) external onlyGod {
        require(_credits != address(0), "Invalid address");
        creditsContract = IERC20(_credits);
    }
    
    /**
     * Get all pilots with their CREDITS token balances in one call
     * @return pilotAddresses Array of pilot addresses
     * @return creditsBalances Array of CREDITS balances (in wei, 18 decimals)
     */
    function getAllPilotsWithCredits() external view returns (
        address[] memory pilotAddresses,
        uint256[] memory creditsBalances
    ) {
        uint256 pilotCount = pilots.length;
        
        pilotAddresses = new address[](pilotCount);
        creditsBalances = new uint256[](pilotCount);
        
        for (uint256 i = 0; i < pilotCount; i++) {
            address pilot = pilots[i];
            pilotAddresses[i] = pilot;
            
            // Get CREDITS balance if contract is set, otherwise return 0
            if (address(creditsContract) != address(0)) {
                creditsBalances[i] = creditsContract.balanceOf(pilot);
            } else {
                creditsBalances[i] = 0;
            }
        }
        
        return (pilotAddresses, creditsBalances);
    }
    
    /**
     * Set the placeholder message for maintenance mode
     * Only callable by the God address
     * When set to a non-empty string, the frontend will display maintenance mode
     * @param _placeholder The placeholder message to display (empty string to disable maintenance mode)
     */
    function setPlaceholder(string calldata _placeholder) external onlyGod {
        placeholder = _placeholder;
        emit PlaceholderUpdated(_placeholder);
    }
    
    /**
     * Accept direct ETH transfers to sweeten the pot
     * Anyone can contribute to increase the winner's prize pool
     */
    receive() external payable {
        // ETH is automatically added to contract balance
        // Will be distributed to winners in settleGame()
    }
}

//SPDX-License-Identifier: MIT
pragma solidity >=0.8.0 <0.9.0;


/*
'##::::'##::::'###::::'##::::'##::::'########:'##::::'##:'########:'########:::::'###:::::'######::'########:
 ###::'###:::'## ##:::. ##::'##::::: ##.....::. ##::'##::... ##..:: ##.... ##:::'## ##:::'##... ##:... ##..::
 ####'####::'##:. ##:::. ##'##:::::: ##::::::::. ##'##:::::: ##:::: ##:::: ##::'##:. ##:: ##:::..::::: ##::::
 ## ### ##:'##:::. ##:::. ###::::::: ######:::::. ###::::::: ##:::: ########::'##:::. ##: ##:::::::::: ##::::
 ##. #: ##: #########::: ## ##:::::: ##...:::::: ## ##:::::: ##:::: ##.. ##::: #########: ##:::::::::: ##::::
 ##:.:: ##: ##.... ##:: ##:. ##::::: ##:::::::: ##:. ##::::: ##:::: ##::. ##:: ##.... ##: ##::: ##:::: ##::::
 ##:::: ##: ##:::: ##: ##:::. ##:::: ########: ##:::. ##:::: ##:::: ##:::. ##: ##:::: ##:. ######::::: ##::::
..:::::..::..:::::..::..:::::..:::::........::..:::::..:::::..:::::..:::::..::..:::::..:::......::::::..:::::
................................................................
.##..##..##..##..######..##..##..######..#####....####...######.
.##..##..###.##....##....##..##..##......##..##..##......##.....
.##..##..##.###....##....##..##..####....#####....####...####...
.##..##..##..##....##.....####...##......##..##......##..##.....
..####...##..##..######....##....######..##..##...####...######.
................................................................
                                                                                    
                                                                                    
                                                                                    */



/**
 * Universe Contract - Manages the game world state
 * Handles asteroid lifecycle, ship tracking, mining actions, and verification
 * Uses commit-reveal scheme for secure entropy generation
 * @author Max Extract Protocol
 */
contract Universe {
    // The god address - only this address can set the universe entropy
    address public constant GOD = 0x0647603E7711D9686BdB9fDB1fe0b04162b73dD7;
    //address public constant GOD = 0x43D9B634006B4fCe2523a710990a397AC3d18D7a;
    //address public immutable GOD;

     /**
     * DEV FUNCTION COMMENT OUT to set entropy directly (bypasses commit-reveal)
     * Only available to GOD for easier testing/development
     */
     /*
    function setEntropyDirect(bytes32 _entropy) external onlyGod entropyNotSet {
        entropy = _entropy;
        entropySet = true;
        
        emit EntropyRevealed(_entropy, bytes32(0), 0);
    }*/

    
    // The universe entropy - immutable once set via commit-reveal
    bytes32 public entropy;
    bool public entropySet;
    
    // Commit-reveal state
    bytes32 public commitmentHash;
    uint256 public commitBlock;
    bool public commitmentMade;
    
    // Rolling commit-reveal state for ongoing entropy generation
    bytes32 public rollingEntropy;
    bytes32 public lastCommit;
    uint256 public roundNumber;
    
    // Events
    event CommitmentMade(bytes32 indexed commitmentHash, uint256 indexed blockNumber);
    event EntropyRevealed(bytes32 indexed entropy, bytes32 reveal, uint256 commitBlockHash);
    event RollingCommitReveal(uint256 indexed roundNumber, bytes32 indexed newCommit, bytes32 reveal, bytes32 newRollingEntropy);
    
    // Errors
    error OnlyGod();
    error EntropyAlreadySet();
    error NoCommitmentMade();
    error BlockhashUnavailable();
    error InvalidReveal();
    error CommitmentAlreadyMade();

    modifier onlyGod() {
        if (msg.sender != GOD) revert OnlyGod();
        _;
    }

    modifier entropyNotSet() {
        if (entropySet) revert EntropyAlreadySet();
        _;
    }

    constructor() {
    }

    /**
     * Step 1: God commits to a secret random number
     * @param _commitmentHash keccak256(randomNumber) - commitment to secret random number
     */
    function commit(bytes32 _commitmentHash) external onlyGod entropyNotSet {
        if (commitmentMade) revert CommitmentAlreadyMade();
        
        commitmentHash = _commitmentHash;
        commitBlock = block.number;
        commitmentMade = true;
        
        emit CommitmentMade(_commitmentHash, block.number);
    }

    /**
     * Step 2: God reveals the random number to generate entropy
     * Must be called in a subsequent block to ensure commit block hash is available
     * @param randomNumber The secret random number that was committed to
     */
    function reveal(uint256 randomNumber) external onlyGod entropyNotSet {
        if (!commitmentMade) revert NoCommitmentMade();
        
        // Get the commit block hash for additional entropy
        bytes32 commitBlockHash = blockhash(commitBlock);
        if (commitBlockHash == 0) revert BlockhashUnavailable();
        
        // Verify the reveal matches the commitment
        bytes32 expectedCommitment = keccak256(abi.encodePacked(randomNumber));
        if (expectedCommitment != commitmentHash) revert InvalidReveal();
        
        // Generate final entropy by combining random number with commit block hash
        entropy = keccak256(abi.encodePacked(randomNumber, commitBlockHash));
        entropySet = true;
        
        emit EntropyRevealed(entropy, bytes32(randomNumber), uint256(commitBlockHash));
    }

    /**
     * Get the current universe entropy
     * @return The entropy bytes32, or 0x0 if not set yet
     */
    function getEntropy() external view returns (bytes32) {
        return entropy;
    }

    /**
     * Check if entropy has been set
     * @return True if entropy is available
     */
    function isEntropySet() external view returns (bool) {
        return entropySet;
    }

    /**
     * Get commit-reveal state for frontend
     * @return _commitmentMade Whether a commitment has been made
     * @return _commitBlock The block number of the commitment
     * @return _entropySet Whether entropy has been revealed
     */
    function getCommitRevealState() external view returns (
        bool _commitmentMade,
        uint256 _commitBlock,
        bool _entropySet
    ) {
        return (commitmentMade, commitBlock, entropySet);
    }


    /**
     * Rolling commit-reveal function for ongoing entropy generation
     * Commits to next round while revealing current round in same transaction
     * @param nextCommit Commitment hash for the next round (keccak256(randomNumber))
     * @param revealNumber The random number being revealed for current round (0x0 for round 0)
     */
    function rollingCommitReveal(bytes32 nextCommit, uint256 revealNumber) external onlyGod {
        // For round 0, allow reveal to be 0 and initialize rolling entropy
        if (roundNumber == 0) {
            // For the first round, we accept any reveal (including 0) and initialize rolling entropy
            // Use a combination of reveal and block hash for initial entropy
            bytes32 currentBlockHash = blockhash(block.number - 1);
            rollingEntropy = keccak256(abi.encodePacked(revealNumber, currentBlockHash));
            lastCommit = nextCommit;
            roundNumber = 1;
            
            emit RollingCommitReveal(0, nextCommit, bytes32(revealNumber), rollingEntropy);
            return;
        }
        
        // For subsequent rounds, verify the reveal matches the last commit
        bytes32 expectedCommit = keccak256(abi.encodePacked(revealNumber));
        if (expectedCommit != lastCommit) revert InvalidReveal();
        
        // Get the block hash from when the last commit was made
        // Note: We use the current block hash as the source of additional entropy
        bytes32 blockHash = blockhash(block.number - 1);
        
        // Generate new rolling entropy by combining reveal with block hash
        rollingEntropy = keccak256(abi.encodePacked(revealNumber, blockHash, rollingEntropy));
        
        // Store the new commit for next round
        lastCommit = nextCommit;
        roundNumber++;
        
        emit RollingCommitReveal(roundNumber - 1, nextCommit, bytes32(revealNumber), rollingEntropy);
    }

    /**
     * Get the current rolling entropy and round information
     * @return _rollingEntropy Current rolling entropy
     * @return _roundNumber Current round number
     * @return _lastCommit Last commitment hash
     */
    function getRollingState() external view returns (
        bytes32 _rollingEntropy,
        uint256 _roundNumber,
        bytes32 _lastCommit
    ) {
        return (rollingEntropy, roundNumber, lastCommit);
    }

    /**
     * Get the main commitment hash for display purposes
     * @return The current commitment hash
     */
    function getCommitmentHash() external view returns (bytes32) {
        return commitmentHash;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/IERC20.sol)

pragma solidity >=0.4.16;

/**
 * @dev Interface of the ERC-20 standard as defined in the ERC.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the value of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the value of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 value) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the
     * allowance mechanism. `value` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 value) external returns (bool);
}

Settings
{
  "remappings": [
    "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
    "ds-test/=lib/solidity-bytes-utils/lib/forge-std/lib/ds-test/src/",
    "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
    "forge-std/=lib/forge-std/src/",
    "halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/",
    "solidity-bytes-utils/=lib/solidity-bytes-utils/contracts/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "cancun",
  "viaIR": false
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"_universe","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"CredentialNotRegistered","type":"error"},{"inputs":[],"name":"GameAlreadySettled","type":"error"},{"inputs":[],"name":"GameNotEnded","type":"error"},{"inputs":[],"name":"GameNotOpen","type":"error"},{"inputs":[],"name":"InsufficientCreditsForUpgrade","type":"error"},{"inputs":[],"name":"InsufficientPayment","type":"error"},{"inputs":[],"name":"InsufficientPoints","type":"error"},{"inputs":[],"name":"InvalidArrayLengths","type":"error"},{"inputs":[],"name":"InvalidBaseType","type":"error"},{"inputs":[],"name":"InvalidPercentages","type":"error"},{"inputs":[],"name":"MaxExtractNotSet","type":"error"},{"inputs":[],"name":"NotACredential","type":"error"},{"inputs":[],"name":"NotAFuelContract","type":"error"},{"inputs":[],"name":"NotAPlayer","type":"error"},{"inputs":[],"name":"NotARegistry","type":"error"},{"inputs":[],"name":"OnlyAuditor","type":"error"},{"inputs":[],"name":"OnlyGod","type":"error"},{"inputs":[],"name":"OnlyMaxExtract","type":"error"},{"inputs":[],"name":"OnlyPilot","type":"error"},{"inputs":[],"name":"PayoutFailed","type":"error"},{"inputs":[],"name":"PilotAlreadyAdded","type":"error"},{"inputs":[],"name":"PilotAlreadyDead","type":"error"},{"inputs":[],"name":"PilotAlreadyMintedFromPlayer","type":"error"},{"inputs":[],"name":"PlayerAlreadyJoined","type":"error"},{"inputs":[],"name":"StationMaxLevel","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8[]","name":"newVisibleChapters","type":"uint8[]"}],"name":"ChaptersUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pilot","type":"address"},{"indexed":true,"internalType":"address","name":"player","type":"address"},{"indexed":true,"internalType":"address","name":"credentialContract","type":"address"}],"name":"CredentialMinted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"winners","type":"address[]"},{"indexed":false,"internalType":"uint256","name":"winningScore","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalPayout","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"payoutPerWinner","type":"uint256"}],"name":"GameSettled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"enum Game.GameState","name":"newState","type":"uint8"}],"name":"GameStateChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pilot","type":"address"}],"name":"PilotAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pilot","type":"address"},{"indexed":true,"internalType":"address","name":"killer","type":"address"},{"indexed":true,"internalType":"address","name":"playerPenalized","type":"address"},{"indexed":false,"internalType":"uint256","name":"scorePenalty","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"ethForwarded","type":"uint256"}],"name":"PilotDied","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"pilots","type":"address[]"}],"name":"PilotsAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"newPlaceholder","type":"string"}],"name":"PlaceholderUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"player","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"PlayerBoughtIn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"player","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newScore","type":"uint256"}],"name":"PointsDeducted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"recipients","type":"address[]"},{"indexed":false,"internalType":"uint256[]","name":"percentages","type":"uint256[]"},{"indexed":false,"internalType":"uint256","name":"totalAmount","type":"uint256"}],"name":"PotPaidOut","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"sectorId","type":"uint256"},{"indexed":false,"internalType":"uint8","name":"newBaseType","type":"uint8"},{"indexed":true,"internalType":"address","name":"setBy","type":"address"}],"name":"StationBaseTypeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"sectorId","type":"uint256"},{"indexed":true,"internalType":"address","name":"player","type":"address"},{"indexed":true,"internalType":"address","name":"pilotCaller","type":"address"},{"indexed":false,"internalType":"uint8","name":"newBaseType","type":"uint8"}],"name":"StationUpgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pilot","type":"address"},{"indexed":true,"internalType":"address","name":"player","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TipGiven","type":"event"},{"inputs":[],"name":"BUY_IN_PRICE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WETH_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_pilot","type":"address"}],"name":"addPilot","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_pilots","type":"address[]"}],"name":"addPilots","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"auditorContract","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_player","type":"address"}],"name":"awardBroadcastPoints","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"buyIn","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"canGameSettle","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_pilot","type":"address"},{"internalType":"uint256","name":"_sectorId","type":"uint256"}],"name":"canPilotAccessSector","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"creditsContract","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_killer","type":"address"},{"internalType":"address","name":"_playerToPenalize","type":"address"}],"name":"deadMansSlash","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_killer","type":"address"},{"internalType":"address","name":"_playerToPenalize","type":"address"}],"name":"deadMansSwitch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"deadPilots","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_player","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"deductPoints","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_pilots","type":"address[]"},{"internalType":"uint256","name":"minBalancePerPilot","type":"uint256"}],"name":"fundPilots","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"gameEndTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"gameWinners","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAllPilotsAndBalances","outputs":[{"internalType":"address[]","name":"pilotAddresses","type":"address[]"},{"internalType":"uint256[]","name":"ethBalances","type":"uint256[]"},{"internalType":"bool[]","name":"isDead","type":"bool[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAllPilotsWithCredits","outputs":[{"internalType":"address[]","name":"pilotAddresses","type":"address[]"},{"internalType":"uint256[]","name":"creditsBalances","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getGameInfo","outputs":[{"internalType":"enum Game.GameState","name":"_state","type":"uint8"},{"internalType":"uint256","name":"_playerCount","type":"uint256"},{"internalType":"uint256","name":"_buyInPrice","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getGameWinners","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPilotCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPilots","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPlayerCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_player","type":"address"}],"name":"getPlayerScore","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPlayers","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_sectorId","type":"uint256"}],"name":"getSectorBaseType","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTimeRemaining","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getVisibleChapters","outputs":[{"internalType":"uint8[]","name":"","type":"uint8[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_pilot","type":"address"}],"name":"isPilot","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_pilot","type":"address"}],"name":"isPilotDead","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isPilotMapping","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_player","type":"address"}],"name":"isPlayer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isPlayerMapping","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxExtract","outputs":[{"internalType":"contract IMaxExtract","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxExtractContract","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"recipients","type":"address[]"},{"internalType":"uint256[]","name":"percentages","type":"uint256[]"}],"name":"payoutPot","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_sectorId","type":"uint256"}],"name":"pilotMintSectorCredential","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"pilotPlayerCredentialMinted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"pilots","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"placeholder","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"players","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"scores","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"sectorBaseType","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_auditor","type":"address"}],"name":"setAuditorContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_credits","type":"address"}],"name":"setCreditsContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_maxExtract","type":"address"}],"name":"setMaxExtract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_placeholder","type":"string"}],"name":"setPlaceholder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_sectorId","type":"uint256"},{"internalType":"uint8","name":"_baseType","type":"uint8"}],"name":"setSectorBaseType","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum Game.GameState","name":"_newState","type":"uint8"}],"name":"setState","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"settleGame","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8[]","name":"_chapters","type":"uint8[]"}],"name":"showChapters","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"state","outputs":[{"internalType":"enum Game.GameState","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_player","type":"address"},{"internalType":"uint256","name":"_tipAmount","type":"uint256"}],"name":"tipPlayer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"universe","outputs":[{"internalType":"contract Universe","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_sectorId","type":"uint256"}],"name":"upgradeStation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"visibleChapters","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"winningScore","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

60c060405261001042611194610058565b60805234801561001e575f80fd5b50604051614b52380380614b5283398101604081905261003d9161007d565b6001600160a01b031660a0526005805460ff191690556100aa565b8082018082111561007757634e487b7160e01b5f52601160045260245ffd5b92915050565b5f6020828403121561008d575f80fd5b81516001600160a01b03811681146100a3575f80fd5b9392505050565b60805160a051614a106101425f395f818161063701528181610dc501528181610e7601528181610f2e01528181611357015281816116270152818161178d01528181611a3a01528181611fd2015281816128630152818161302e0152818161394301528181613d360152613e3501525f818161055e01528181611b45015281816129bb0152818161333a015261336a0152614a105ff3fe60806040526004361061038a575f3560e01c80637fd6b2e7116101d3578063b7a17c4c116100fd578063ded72d1f1161009d578063e83267451161006d578063e832674514610b06578063f4e8b45014610b19578063f71d96cb14610b38578063fe74379114610b57575f80fd5b8063ded72d1f14610a66578063e085c53914610a94578063e19ddff314610ac8578063e5b42e9214610ae7575f80fd5b8063c7a77e2f116100d8578063c7a77e2f146109fe578063d529251d14610a11578063dac6270d14610a30578063dbb838a914610a44575f80fd5b8063b7a17c4c146109ab578063c19d93fb146109c4578063c2e52206146109ea575f80fd5b8063938a864511610173578063b2652ec411610143578063b2652ec41461092c578063b329be371461094b578063b33ac8aa1461095f578063b38321a21461097d575f80fd5b8063938a8645146108ae5780639e75143c146108cd578063a83b589c146108ee578063af331b651461090d575f80fd5b80638aa0cb6c116101ae5780638aa0cb6c146108485780638b5b9ccc146108675780638bb98fd91461087b5780639129ce391461088f575f80fd5b80637fd6b2e7146107d157806388aafa60146107f057806388f4e6eb14610829575f80fd5b8063516f4f30116102b45780637350f431116102545780637776282011610224578063777628201461075157806379390faa146107655780637bdd449c146107845780637df3c497146107a3575f80fd5b80637350f431146106ba5780637488ad24146106e8578063755b77b31461070757806376dd110f14610726575f80fd5b8063554c1b1f1161028f578063554c1b1f1461062657806356de96db1461065957806356df26be14610678578063620274061461069b575f80fd5b8063516f4f30146105d257806353aab43414610609578063546216f114610611575f80fd5b806318edd1781161032a57806344d9bc5f116102fa57806344d9bc5f1461054d57806348bb35a2146105805780634ded2e8e1461059f5780634ffac413146105be575f80fd5b806318edd178146104c6578063241e5622146104e75780632f5a90a6146105085780633ccfd60b14610539575f80fd5b806309c95e101161036557806309c95e101461041957806312065fe01461046057806316c44e6f1461047c5780631746bd1b1461049b575f80fd5b8063040141e5146103955780630642bc41146103d9578063093119f7146103f8575f80fd5b3661039157005b5f80fd5b3480156103a0575f80fd5b506103bc7382af49447d8a07e3bd95bd0d56f35241523fbab181565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156103e4575f80fd5b506003546103bc906001600160a01b031681565b348015610403575f80fd5b5061041761041236600461411a565b610b76565b005b348015610424575f80fd5b50610450610433366004614151565b6001600160a01b03165f908152600b602052604090205460ff1690565b60405190151581526020016103d0565b34801561046b575f80fd5b50475b6040519081526020016103d0565b348015610487575f80fd5b506001546103bc906001600160a01b031681565b3480156104a6575f80fd5b506005546007546040516103d09260ff1691906509184e72a000906141a0565b3480156104d1575f80fd5b506104da610cc0565b6040516103d091906141bf565b3480156104f2575f80fd5b506104fb610d33565b6040516103d09190614247565b348015610513575f80fd5b50610527610522366004614259565b610d92565b60405160ff90911681526020016103d0565b348015610544575f80fd5b50610417610dc3565b348015610558575f80fd5b5061046e7f000000000000000000000000000000000000000000000000000000000000000081565b34801561058b575f80fd5b5061041761059a3660046142b7565b610f2c565b3480156105aa575f80fd5b506104506105b93660046142f5565b611027565b3480156105c9575f80fd5b5060085461046e565b3480156105dd575f80fd5b506104506105ec366004614151565b6001600160a01b03165f908152600e602052604090205460ff1690565b6104176111e1565b34801561061c575f80fd5b5061046e600a5481565b348015610631575f80fd5b506103bc7f000000000000000000000000000000000000000000000000000000000000000081565b348015610664575f80fd5b5061041761067336600461431f565b611355565b348015610683575f80fd5b5061068c611463565b6040516103d09392919061436d565b3480156106a6575f80fd5b506104176106b5366004614151565b611625565b3480156106c5575f80fd5b506104506106d4366004614151565b600c6020525f908152604090205460ff1681565b3480156106f3575f80fd5b506104176107023660046143d8565b61178b565b348015610712575f80fd5b50610417610721366004614151565b611a38565b348015610731575f80fd5b5061046e610740366004614151565b600d6020525f908152604090205481565b34801561075c575f80fd5b50610417611b43565b348015610770575f80fd5b5061041761077f3660046142f5565b611f11565b34801561078f575f80fd5b506103bc61079e366004614259565b611fa8565b3480156107ae575f80fd5b506104506107bd366004614151565b600b6020525f908152604090205460ff1681565b3480156107dc575f80fd5b506104176107eb366004614450565b611fd0565b3480156107fb575f80fd5b5061045061080a36600461411a565b600f60209081525f928352604080842090915290825290205460ff1681565b348015610834575f80fd5b5061041761084336600461411a565b612106565b348015610853575f80fd5b50610417610862366004614151565b612861565b348015610872575f80fd5b506104fb61295a565b348015610886575f80fd5b506104506129b8565b34801561089a575f80fd5b506104176108a9366004614259565b612a05565b3480156108b9575f80fd5b506104176108c8366004614151565b612cc5565b3480156108d8575f80fd5b506108e1612d94565b6040516103d09190614473565b3480156108f9575f80fd5b506104176109083660046142f5565b612e20565b348015610918575f80fd5b50610527610927366004614259565b612f62565b348015610937575f80fd5b50610450610946366004614151565b612f89565b348015610956575f80fd5b506104fb612fce565b34801561096a575f80fd5b505f546103bc906001600160a01b031681565b348015610988575f80fd5b50610450610997366004614151565b600e6020525f908152604090205460ff1681565b3480156109b6575f80fd5b5061046e6509184e72a00081565b3480156109cf575f80fd5b506005546109dd9060ff1681565b6040516103d091906144a8565b3480156109f5575f80fd5b5060075461046e565b610417610a0c3660046144b6565b61302c565b348015610a1c575f80fd5b506002546103bc906001600160a01b031681565b348015610a3b575f80fd5b5061046e613337565b348015610a4f575f80fd5b50610a5861338e565b6040516103d09291906144fd565b348015610a71575f80fd5b50610527610a80366004614259565b60106020525f908152604090205460ff1681565b348015610a9f575f80fd5b5061046e610aae366004614151565b6001600160a01b03165f908152600d602052604090205490565b348015610ad3575f80fd5b506103bc610ae2366004614259565b613549565b348015610af2575f80fd5b50610417610b01366004614259565b613558565b610417610b143660046142b7565b613941565b348015610b24575f80fd5b50610417610b33366004614521565b613d34565b348015610b43575f80fd5b506103bc610b52366004614259565b613e24565b348015610b62575f80fd5b50610417610b71366004614151565b613e33565b335f908152600c602052604090205460ff16610ba557604051634632ffe360e01b815260040160405180910390fd5b335f908152600e602052604090205460ff1615610bd557604051631894063360e21b815260040160405180910390fd5b6001600160a01b0381165f908152600b602052604090205460ff16610c0d5760405163abca351760e01b815260040160405180910390fd5b335f908152600e60209081526040808320805460ff191660011790556001600160a01b0384168352600d90915281205490600a821015610c4d5781610c50565b600a5b9050610c5c81836145a1565b6001600160a01b038481165f818152600d602090815260408083209590955584518681529081019190915290929187169133917f8044fa4da29a21540b095aa9cddd2e3f31d47978eb3d8440183b6ac98bf3bda1910160405180910390a450505050565b60606006805480602002602001604051908101604052809291908181526020018280548015610d2957602002820191905f5260205f20905f905b825461010083900a900460ff16815260206001928301818104948501949093039092029101808411610cfa5790505b5050505050905090565b60606008805480602002602001604051908101604052809291908181526020018280548015610d2957602002820191905f5260205f20905b81546001600160a01b03168152600190910190602001808311610d6b575050505050905090565b60068181548110610da1575f80fd5b905f5260205f209060209182820401919006915054906101000a900460ff1681565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663af30ee3f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e1f573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e4391906145b4565b6001600160a01b0316336001600160a01b031614610e7457604051630cb73db360e21b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663af30ee3f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ed0573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ef491906145b4565b6001600160a01b03166108fc4790811502906040515f60405180830381858888f19350505050158015610f29573d5f803e3d5ffd5b50565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663af30ee3f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f88573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610fac91906145b4565b6001600160a01b0316336001600160a01b031614610fdd57604051630cb73db360e21b815260040160405180910390fd5b610fe960068383613ffb565b507f94e1ce80c1f560eae2d7da116779b3aacee5613170afb9876373e3c761aa1956828260405161101b9291906145cf565b60405180910390a15050565b5f80546001600160a01b031661103e57505f6111db565b5f8054604051633ff3649360e01b8152600481018590526001600160a01b0390911690633ff3649390602401602060405180830381865afa158015611085573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110a991906145b4565b90506001600160a01b0381166110c2575f9150506111db565b5f6110ef826040518060400160405280600a81526020016918dc9959195b9d1a585b60b21b815250613f2c565b90506001600160a01b038116611109575f925050506111db565b6040516001600160a01b0386811660248301525f91829184169060440160408051601f198184030181529181526020820180516001600160e01b03166370a0823160e01b1790525161115b9190614615565b5f60405180830381855afa9150503d805f8114611193576040519150601f19603f3d011682016040523d82523d5f602084013e611198565b606091505b50915091508115806111ab575060208151105b156111bc575f9450505050506111db565b5f818060200190518101906111d1919061462b565b1515955050505050505b92915050565b5f60055460ff1660028111156111f9576111f961416c565b1461121757604051635c07b6d760e11b815260040160405180910390fd5b6509184e72a00034101561123e5760405163cd1c886760e01b815260040160405180910390fd5b335f908152600b602052604090205460ff161561126e576040516314c4fea760e31b815260040160405180910390fd5b6007805460018181019092557fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c6880180546001600160a01b031916339081179091555f818152600b60209081526040808320805460ff1916909517909455600d90528281205590517f7dbd99091135732d8894a7112b904af6bf7fee8441105b31987f90c32329fdd9906113049034815260200190565b60405180910390a26509184e72a00034111561135357336108fc61132e6509184e72a000346145a1565b6040518115909202915f818181858888f19350505050158015610f29573d5f803e3d5ffd5b565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663af30ee3f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113b1573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906113d591906145b4565b6001600160a01b0316336001600160a01b03161461140657604051630cb73db360e21b815260040160405180910390fd5b6005805482919060ff191660018360028111156114255761142561416c565b02179055507ea8b06dd72552dea96e97c9a96acf39a1908ada44765cefe367620485b2c7e18160405161145891906144a8565b60405180910390a150565b60085460609081908190806001600160401b0381111561148557611485614642565b6040519080825280602002602001820160405280156114ae578160200160208202803683370190505b509350806001600160401b038111156114c9576114c9614642565b6040519080825280602002602001820160405280156114f2578160200160208202803683370190505b509250806001600160401b0381111561150d5761150d614642565b604051908082528060200260200182016040528015611536578160200160208202803683370190505b5091505f5b8181101561161e575f6008828154811061155757611557614656565b905f5260205f20015f9054906101000a90046001600160a01b031690508086838151811061158757611587614656565b60200260200101906001600160a01b031690816001600160a01b031681525050806001600160a01b0316318583815181106115c4576115c4614656565b6020908102919091018101919091526001600160a01b0382165f908152600e9091526040902054845160ff9091169085908490811061160557611605614656565b911515602092830291909101909101525060010161153b565b5050909192565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663af30ee3f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611681573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116a591906145b4565b6001600160a01b0316336001600160a01b0316146116d657604051630cb73db360e21b815260040160405180910390fd5b6116df81612f89565b156116fd5760405163e0dbb1a760e01b815260040160405180910390fd5b6008805460018082019092557ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee30180546001600160a01b0319166001600160a01b0384169081179091555f818152600c6020526040808220805460ff1916909417909355915190917f07577ee4d7b640060b986e698b16d90aef8e3a4fffa36dd13d3b79195e70b3d691a250565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663af30ee3f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156117e7573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061180b91906145b4565b6001600160a01b0316336001600160a01b03161461183c57604051630cb73db360e21b815260040160405180910390fd5b8215806118495750828114155b156118675760405163a9854bc960e01b815260040160405180910390fd5b5f805b828110156118a05783838281811061188457611884614656565b9050602002013582611896919061466a565b915060010161186a565b50806103e8146118c357604051636d2fd3c960e01b815260040160405180910390fd5b475f8190036118d3575050611a32565b5f5b858110156119ef575f8787838181106118f0576118f0614656565b90506020020160208101906119059190614151565b6001600160a01b0316146119e7575f6103e886868481811061192957611929614656565b905060200201358461193b919061467d565b61194591906146a8565b905080156119e5575f88888481811061196057611960614656565b90506020020160208101906119759190614151565b6001600160a01b0316826040515f6040518083038185875af1925050503d805f81146119bc576040519150601f19603f3d011682016040523d82523d5f602084013e6119c1565b606091505b50509050806119e357604051630ec6ac4160e21b815260040160405180910390fd5b505b505b6001016118d5565b507f5a31676f5fc71e56ec99e78f1f76a78352cdc05a4c1be0d3accdbb305a512ce48686868685604051611a279594939291906146f9565b60405180910390a150505b50505050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663af30ee3f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a94573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ab891906145b4565b6001600160a01b0316336001600160a01b031614611ae957604051630cb73db360e21b815260040160405180910390fd5b6001600160a01b038116611b185760405162461bcd60e51b8152600401611b0f9061474c565b60405180910390fd5b5f80546001600160a01b039092166001600160a01b0319928316811790915560028054909216179055565b7f0000000000000000000000000000000000000000000000000000000000000000421015611b8457604051638f86c6b360e01b815260040160405180910390fd5b600260055460ff166002811115611b9d57611b9d61416c565b03611bbb57604051636e2ab89360e11b815260040160405180910390fd5b6007545f03611bd3576005805460ff19166002179055565b5f805b600754811015611c32575f600d5f60078481548110611bf757611bf7614656565b5f9182526020808320909101546001600160a01b03168352820192909252604001902054905082811115611c29578092505b50600101611bd6565b506007545f906001600160401b03811115611c4f57611c4f614642565b604051908082528060200260200182016040528015611c78578160200160208202803683370190505b5090505f805b600754811015611d365783600d5f60078481548110611c9f57611c9f614656565b5f9182526020808320909101546001600160a01b0316835282019290925260400190205403611d2e5760078181548110611cdb57611cdb614656565b905f5260205f20015f9054906101000a90046001600160a01b0316838381518110611d0857611d08614656565b6001600160a01b039092166020928302919091019091015281611d2a81614775565b9250505b600101611c7e565b50806001600160401b03811115611d4f57611d4f614642565b604051908082528060200260200182016040528015611d78578160200160208202803683370190505b508051611d8d9160099160209091019061409f565b505f5b81811015611df557828181518110611daa57611daa614656565b602002602001015160098281548110611dc557611dc5614656565b5f91825260209091200180546001600160a01b0319166001600160a01b0392909216919091179055600101611d90565b50600a8390556005805460ff19166002179055475f8115801590611e1857505f83115b15611eca57611e2783836146a8565b90505f5b83811015611ec8575f60098281548110611e4757611e47614656565b5f9182526020822001546040516001600160a01b039091169185919081818185875af1925050503d805f8114611e98576040519150601f19603f3d011682016040523d82523d5f602084013e611e9d565b606091505b5050905080611ebf57604051630ec6ac4160e21b815260040160405180910390fd5b50600101611e2b565b505b7f8b8f0658aa11ba65d0656d3982f05a3d5d88b0190cc77264e6fc6aff7e711da06009600a548484604051611f02949392919061478d565b60405180910390a15050505050565b611f1a33612f89565b611f3757604051634632ffe360e01b815260040160405180910390fd5b6001600160a01b0382165f908152600d602052604081208054839290611f5e90849061466a565b90915550506040518181526001600160a01b0383169033907f8c1e155b9f22132fd0366f32e05296679a0174614fe6dc4b2f7e2fcfc0385534906020015b60405180910390a35050565b60098181548110611fb7575f80fd5b5f918252602090912001546001600160a01b0316905081565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663af30ee3f6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561202c573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061205091906145b4565b6001600160a01b0316336001600160a01b03161461208157604051630cb73db360e21b815260040160405180910390fd5b60018160ff161080612096575060068160ff16115b156120b45760405163560612c960e01b815260040160405180910390fd5b5f82815260106020908152604091829020805460ff191660ff85169081179091559151918252339184917fa5df98dd2060f5d5cfe17f03fee367e49d826fa19635fb6874523063191cc30e9101611f9c565b335f908152600c602052604090205460ff1661213557604051634632ffe360e01b815260040160405180910390fd5b335f908152600e602052604090205460ff161561216557604051631894063360e21b815260040160405180910390fd5b6001600160a01b0381165f908152600b602052604090205460ff1661219d5760405163abca351760e01b815260040160405180910390fd5b335f908152600e6020526040808220805460ff19166001179055815490516370b131c360e11b81526001600160a01b0384811660048301529091169063e162638690602401602060405180830381865afa1580156121fd573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612221919061462b565b9050805f036122695760405162461bcd60e51b8152602060048201526014602482015273283630bcb2b9103430b99037379039b2b1ba37b960611b6044820152606401611b0f565b5f8054604051633ff3649360e01b8152600481018490526001600160a01b0390911690633ff3649390602401602060405180830381865afa1580156122b0573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906122d491906145b4565b90506001600160a01b03811661231a5760405162461bcd60e51b815260206004820152600b60248201526a4e6f20726567697374727960a81b6044820152606401611b0f565b5f61234282604051806040016040528060058152602001647374616b6560d81b815250613f2c565b90506001600160a01b03811661238c5760405162461bcd60e51b815260206004820152600f60248201526e4e6f207374616b65206d6f64756c6560881b6044820152606401611b0f565b6001546001600160a01b03166123d65760405162461bcd60e51b815260206004820152600f60248201526e105d591a5d1bdc881b9bdd081cd95d608a1b6044820152606401611b0f565b6001546040516001600160a01b0383811660248301525f92839291169060440160408051601f198184030181529181526020820180516001600160e01b0316639d26080960e01b1790525161242b9190614615565b5f60405180830381855afa9150503d805f8114612463576040519150601f19603f3d011682016040523d82523d5f602084013e612468565b606091505b509150915081801561247c57506020815110155b6124bd5760405162461bcd60e51b8152602060048201526012602482015271105d591a5d0818da1958dac819985a5b195960721b6044820152606401611b0f565b5f818060200190518101906124d291906147f1565b90508060ff166004146125275760405162461bcd60e51b815260206004820152601960248201527f4e6f74206175646974656420666f7220636861707465722034000000000000006044820152606401611b0f565b5f8054604051633a02a42d60e01b81526001600160a01b038b8116600483015290911690633a02a42d90602401602060405180830381865afa15801561256f573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612593919061462b565b905069021e19e0c9bab24000008110156125ef5760405162461bcd60e51b815260206004820152601d60248201527f4b696c6c65722068617320696e73756666696369656e74207374616b650000006044820152606401611b0f565b6040516001600160a01b038a811660248301525f919087169060440160408051601f198184030181529181526020820180516001600160e01b031663c96be4cb60e01b179052516126409190614615565b5f604051808303815f865af19150503d805f8114612679576040519150601f19603f3d011682016040523d82523d5f602084013e61267e565b606091505b50509050806126c35760405162461bcd60e51b815260206004820152601160248201527014db185cda0818d85b1b0819985a5b1959607a1b6044820152606401611b0f565b5f8054604051633a02a42d60e01b81526001600160a01b038d8116600483015290911690633a02a42d90602401602060405180830381865afa15801561270b573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061272f919061462b565b9050801561279b5760405162461bcd60e51b815260206004820152603360248201527f536c61736820646964206e6f74206275726e207374616b65202d206d616c69636044820152721a5bdd5cc81cdd185ad94818dbdb9d1c9858dd606a1b6064820152608401611b0f565b69021e19e0c9bab24000006127b082856145a1565b101561280a5760405162461bcd60e51b8152602060048201526024808201527f536c61736820646964206e6f74206275726e2066756c6c207374616b6520616d6044820152631bdd5b9d60e21b6064820152608401611b0f565b604080515f80825260208201526001600160a01b03808d1692908e169133917f8044fa4da29a21540b095aa9cddd2e3f31d47978eb3d8440183b6ac98bf3bda1910160405180910390a45050505050505050505050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663af30ee3f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156128bd573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906128e191906145b4565b6001600160a01b0316336001600160a01b03161461291257604051630cb73db360e21b815260040160405180910390fd5b6001600160a01b0381166129385760405162461bcd60e51b8152600401611b0f9061474c565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b60606007805480602002602001604051908101604052809291908181526020018280548015610d2957602002820191905f5260205f209081546001600160a01b03168152600190910190602001808311610d6b575050505050905090565b5f7f00000000000000000000000000000000000000000000000000000000000000004210158015612a005750600260055460ff1660028111156129fd576129fd61416c565b14155b905090565b5f546001600160a01b0316612a2d57604051631e0aa0c360e21b815260040160405180910390fd5b612a3632612f89565b612a5357604051634632ffe360e01b815260040160405180910390fd5b5f8054604051633ff3649360e01b8152600481018490526001600160a01b0390911690633ff3649390602401602060405180830381865afa158015612a9a573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612abe91906145b4565b90506001600160a01b038116612ae7576040516381d522f560e01b815260040160405180910390fd5b5f612b14826040518060400160405280600a81526020016918dc9959195b9d1a585b60b21b815250613f2c565b90506001600160a01b038116612b3d57604051635e5b1d7560e11b815260040160405180910390fd5b6001600160a01b0381163314612b6657604051635e5b1d7560e11b815260040160405180910390fd5b5f8054604051634650b04560e01b8152600481018690526001600160a01b0390911690634650b04590602401602060405180830381865afa158015612bad573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612bd191906145b4565b90506001600160a01b038116612bfa5760405163abca351760e01b815260040160405180910390fd5b325f908152600f602090815260408083206001600160a01b038516845290915290205460ff1615612c3e5760405163933099c160e01b815260040160405180910390fd5b325f908152600f602090815260408083206001600160a01b03851684528252808320805460ff19166001179055600d9091528120805460029290612c8390849061466a565b909155505060405133906001600160a01b0383169032907f8483d60736ac8e5fa0068cccf221544749b1c7acc419a99c12df90a44c966c9d905f90a450505050565b6002546001600160a01b03163314612cf05760405163cbf6cf7b60e01b815260040160405180910390fd5b5f805b600754811015612d4457826001600160a01b031660078281548110612d1a57612d1a614656565b5f918252602090912001546001600160a01b031603612d3c5760019150612d44565b600101612cf3565b5080612d635760405163abca351760e01b815260040160405180910390fd5b6001600160a01b0382165f908152600d60205260408120805460059290612d8b90849061466a565b90915550505050565b60048054612da19061480c565b80601f0160208091040260200160405190810160405280929190818152602001828054612dcd9061480c565b8015612e185780601f10612def57610100808354040283529160200191612e18565b820191905f5260205f20905b815481529060010190602001808311612dfb57829003601f168201915b505050505081565b6001546001600160a01b03163314612e4b5760405163f87c866960e01b815260040160405180910390fd5b5f805b600754811015612e9f57836001600160a01b031660078281548110612e7557612e75614656565b5f918252602090912001546001600160a01b031603612e975760019150612e9f565b600101612e4e565b5080612ebe5760405163abca351760e01b815260040160405180910390fd5b6001600160a01b0383165f908152600d602052604090205482811015612ef75760405163303e7a0760e01b815260040160405180910390fd5b612f0183826145a1565b6001600160a01b0385165f818152600d6020526040908190208390555190917f2d8ea5250bf29dafe8cda27d1a8c9aaf28837abf1505e7f02097a7f44bbee54c91612f5491878252602082015260400190565b60405180910390a250505050565b5f8181526010602052604081205460ff168015612f7f5780612f82565b60015b9392505050565b6001600160a01b0381165f908152600e602052604081205460ff1615612fb057505f919050565b506001600160a01b03165f908152600c602052604090205460ff1690565b60606009805480602002602001604051908101604052809291908181526020018280548015610d2957602002820191905f5260205f209081546001600160a01b03168152600190910190602001808311610d6b575050505050905090565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663af30ee3f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613088573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906130ac91906145b4565b6001600160a01b0316336001600160a01b0316146130dd57604051630cb73db360e21b815260040160405180910390fd5b8161311f5760405162461bcd60e51b8152602060048201526012602482015271139bc81c1a5b1bdd1cc81c1c9bdd9a59195960721b6044820152606401611b0f565b5f811161316e5760405162461bcd60e51b815260206004820152601760248201527f496e76616c6964206d696e696d756d2062616c616e63650000000000000000006044820152606401611b0f565b5f805b83811015613295575f85858381811061318c5761318c614656565b90506020020160208101906131a19190614151565b6001600160a01b03163190508381101561328c575f6131c082866145a1565b90505f8787858181106131d5576131d5614656565b90506020020160208101906131ea9190614151565b6001600160a01b0316826040515f6040518083038185875af1925050503d805f8114613231576040519150601f19603f3d011682016040523d82523d5f602084013e613236565b606091505b505090508061327d5760405162461bcd60e51b8152602060048201526013602482015272115512081d1c985b9cd9995c8819985a5b1959606a1b6044820152606401611b0f565b613287828661466a565b945050505b50600101613171565b505f6132a182346145a1565b90508015613330576040515f90339083908381818185875af1925050503d805f81146132e8576040519150601f19603f3d011682016040523d82523d5f602084013e6132ed565b606091505b505090508061332e5760405162461bcd60e51b815260206004820152600d60248201526c1499599d5b990819985a5b1959609a1b6044820152606401611b0f565b505b5050505050565b5f7f0000000000000000000000000000000000000000000000000000000000000000421061336457505f90565b612a00427f00000000000000000000000000000000000000000000000000000000000000006145a1565b6008546060908190806001600160401b038111156133ae576133ae614642565b6040519080825280602002602001820160405280156133d7578160200160208202803683370190505b509250806001600160401b038111156133f2576133f2614642565b60405190808252806020026020018201604052801561341b578160200160208202803683370190505b5091505f5b81811015613543575f6008828154811061343c5761343c614656565b905f5260205f20015f9054906101000a90046001600160a01b031690508085838151811061346c5761346c614656565b6001600160a01b039283166020918202929092010152600354161561351a576003546040516370a0823160e01b81526001600160a01b038381166004830152909116906370a0823190602401602060405180830381865afa1580156134d3573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906134f7919061462b565b84838151811061350957613509614656565b60200260200101818152505061353a565b5f84838151811061352d5761352d614656565b6020026020010181815250505b50600101613420565b50509091565b60088181548110611fb7575f80fd5b5f546001600160a01b031661358057604051631e0aa0c360e21b815260040160405180910390fd5b61358932612f89565b6135a657604051634632ffe360e01b815260040160405180910390fd5b5f8054604051633ff3649360e01b8152600481018490526001600160a01b0390911690633ff3649390602401602060405180830381865afa1580156135ed573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061361191906145b4565b90506001600160a01b03811661363a576040516381d522f560e01b815260040160405180910390fd5b5f613661826040518060400160405280600481526020016373616c6560e01b815250613f2c565b90506001600160a01b03811661368a57604051631b3473a560e21b815260040160405180910390fd5b6001600160a01b03811633146136b357604051631b3473a560e21b815260040160405180910390fd5b5f8054604051634650b04560e01b8152600481018690526001600160a01b0390911690634650b04590602401602060405180830381865afa1580156136fa573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061371e91906145b4565b90506001600160a01b0381166137475760405163abca351760e01b815260040160405180910390fd5b5f8481526010602052604081205460ff1690819003613764575060015b60068160ff16106137885760405163e2a31caf60e01b815260040160405180910390fd5b6003546040516370a0823160e01b81526001600160a01b038581166004830152690a7b667f19c28bf000009283929116906370a0823190602401602060405180830381865afa1580156137dd573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613801919061462b565b1015613820576040516317f5126160e11b815260040160405180910390fd5b6003546040516323b872dd60e01b81526001600160a01b03868116600483015230602483015260448201849052909116906323b872dd906064016020604051808303815f875af1158015613876573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061389a9190614844565b506001600160a01b0383165f908152600d602052604081208054600a92906138c390849061466a565b909155505f90506138d5836001614863565b5f88815260106020908152604091829020805460ff191660ff8516908117909155915191825291925032916001600160a01b038716918a917f6544a62572f716ddb5ef122f657bcced3130b4e6b6e7ea78bccf9f8694a27df4910160405180910390a450505050505050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663af30ee3f6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561399d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906139c191906145b4565b6001600160a01b0316336001600160a01b0316146139f257604051630cb73db360e21b815260040160405180910390fd5b80613a345760405162461bcd60e51b8152602060048201526012602482015271139bc81c1a5b1bdd1cc81c1c9bdd9a59195960721b6044820152606401611b0f565b5f805b82811015613b3157613a69848483818110613a5457613a54614656565b90506020020160208101906109469190614151565b613b29576008848483818110613a8157613a81614656565b9050602002016020810190613a969190614151565b8154600180820184555f9384526020842090910180546001600160a01b0319166001600160a01b03939093169290921790915590600c90868685818110613adf57613adf614656565b9050602002016020810190613af49190614151565b6001600160a01b0316815260208101919091526040015f20805460ff191691151591909117905581613b2581614775565b9250505b600101613a37565b505f34118015613b4057505f81115b15613cf6575f613b5082346146a8565b90505f613b5d833461487c565b90505f5b84811015613cf2575f805f5b600854811015613c0157888885818110613b8957613b89614656565b9050602002016020810190613b9e9190614151565b6001600160a01b031660088281548110613bba57613bba614656565b5f918252602090912001546001600160a01b031603613bf95781613bdd81614775565b92505081600103613bf15760019250613bf9565b5f9250613c01565b600101613b6d565b50818015613c0e57505f85115b15613ce857848415613c2a57613c24858261466a565b90505f94505b5f898986818110613c3d57613c3d614656565b9050602002016020810190613c529190614151565b6001600160a01b0316826040515f6040518083038185875af1925050503d805f8114613c99576040519150601f19603f3d011682016040523d82523d5f602084013e613c9e565b606091505b5050905080613ce55760405162461bcd60e51b8152602060048201526013602482015272115512081d1c985b9cd9995c8819985a5b1959606a1b6044820152606401611b0f565b50505b5050600101613b61565b5050505b7fe117669371937de9be25bcb2289999348317901d98fc0f3329182571cf613c2c8383604051613d2792919061488f565b60405180910390a1505050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663af30ee3f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613d90573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613db491906145b4565b6001600160a01b0316336001600160a01b031614613de557604051630cb73db360e21b815260040160405180910390fd5b6004613df28284836148f3565b507fd28e4ca79028f3e151e2b2496a82ad2095820d02b3e69b0fa88cac665a9a88ce828260405161101b9291906149ac565b60078181548110611fb7575f80fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663af30ee3f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613e8f573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613eb391906145b4565b6001600160a01b0316336001600160a01b031614613ee457604051630cb73db360e21b815260040160405180910390fd5b6001600160a01b038116613f0a5760405162461bcd60e51b8152600401611b0f9061474c565b600380546001600160a01b0319166001600160a01b0392909216919091179055565b5f805f846001600160a01b031684604051602401613f4a9190614473565b60408051601f198184030181529181526020820180516001600160e01b031663099b0d6d60e41b17905251613f7f9190614615565b5f60405180830381855afa9150503d805f8114613fb7576040519150601f19603f3d011682016040523d82523d5f602084013e613fbc565b606091505b5091509150811580613fcf575060208151105b15613fde575f925050506111db565b80806020019051810190613ff291906145b4565b95945050505050565b828054828255905f5260205f2090601f0160209004810192821561408f579160200282015f5b8382111561406157833560ff1683826101000a81548160ff021916908360ff16021790555092602001926001016020815f01049283019260010302614021565b801561408d5782816101000a81549060ff02191690556001016020815f01049283019260010302614061565b505b5061409b9291506140f2565b5090565b828054828255905f5260205f2090810192821561408f579160200282015b8281111561408f57825182546001600160a01b0319166001600160a01b039091161782556020909201916001909101906140bd565b5b8082111561409b575f81556001016140f3565b6001600160a01b0381168114610f29575f80fd5b5f806040838503121561412b575f80fd5b823561413681614106565b9150602083013561414681614106565b809150509250929050565b5f60208284031215614161575f80fd5b8135612f8281614106565b634e487b7160e01b5f52602160045260245ffd5b6003811061419c57634e487b7160e01b5f52602160045260245ffd5b9052565b606081016141ae8286614180565b602082019390935260400152919050565b602080825282518282018190525f918401906040840190835b818110156141f957835160ff168352602093840193909201916001016141d8565b509095945050505050565b5f8151808452602084019350602083015f5b8281101561423d5781516001600160a01b0316865260209586019590910190600101614216565b5093949350505050565b602081525f612f826020830184614204565b5f60208284031215614269575f80fd5b5035919050565b5f8083601f840112614280575f80fd5b5081356001600160401b03811115614296575f80fd5b6020830191508360208260051b85010111156142b0575f80fd5b9250929050565b5f80602083850312156142c8575f80fd5b82356001600160401b038111156142dd575f80fd5b6142e985828601614270565b90969095509350505050565b5f8060408385031215614306575f80fd5b823561431181614106565b946020939093013593505050565b5f6020828403121561432f575f80fd5b813560038110612f82575f80fd5b5f8151808452602084019350602083015f5b8281101561423d57815186526020958601959091019060010161434f565b606081525f61437f6060830186614204565b8281036020840152614391818661433d565b8381036040850152845180825260208087019350909101905f5b818110156143cb57835115158352602093840193909201916001016143ab565b5090979650505050505050565b5f805f80604085870312156143eb575f80fd5b84356001600160401b03811115614400575f80fd5b61440c87828801614270565b90955093505060208501356001600160401b0381111561442a575f80fd5b61443687828801614270565b95989497509550505050565b60ff81168114610f29575f80fd5b5f8060408385031215614461575f80fd5b82359150602083013561414681614442565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b602081016111db8284614180565b5f805f604084860312156144c8575f80fd5b83356001600160401b038111156144dd575f80fd5b6144e986828701614270565b909790965060209590950135949350505050565b604081525f61450f6040830185614204565b8281036020840152613ff2818561433d565b5f8060208385031215614532575f80fd5b82356001600160401b03811115614547575f80fd5b8301601f81018513614557575f80fd5b80356001600160401b0381111561456c575f80fd5b85602082840101111561457d575f80fd5b6020919091019590945092505050565b634e487b7160e01b5f52601160045260245ffd5b818103818111156111db576111db61458d565b5f602082840312156145c4575f80fd5b8151612f8281614106565b602080825281018290525f8360408301825b8581101561460b5782356145f481614442565b60ff168252602092830192909101906001016145e1565b5095945050505050565b5f82518060208501845e5f920191825250919050565b5f6020828403121561463b575f80fd5b5051919050565b634e487b7160e01b5f52604160045260245ffd5b634e487b7160e01b5f52603260045260245ffd5b808201808211156111db576111db61458d565b80820281158282048414176111db576111db61458d565b634e487b7160e01b5f52601260045260245ffd5b5f826146b6576146b6614694565b500490565b8183526020830192505f815f5b8481101561423d5781356146db81614106565b6001600160a01b0316865260209586019591909101906001016146c8565b606081525f61470c6060830187896146bb565b82810360208401528481526001600160fb1b0385111561472a575f80fd5b8460051b80876020840137604093909301939093525001602001949350505050565b6020808252600f908201526e496e76616c6964206164647265737360881b604082015260600190565b5f600182016147865761478661458d565b5060010190565b608080825285549082018190525f86815260208120909160a0840190835b818110156147d25783546001600160a01b03168352600193840193602090930192016147ab565b5050602084019690965250506040810192909252606090910152919050565b5f60208284031215614801575f80fd5b8151612f8281614442565b600181811c9082168061482057607f821691505b60208210810361483e57634e487b7160e01b5f52602260045260245ffd5b50919050565b5f60208284031215614854575f80fd5b81518015158114612f82575f80fd5b60ff81811683821601908111156111db576111db61458d565b5f8261488a5761488a614694565b500690565b602081525f6148a26020830184866146bb565b949350505050565b601f8211156148ee57805f5260205f20601f840160051c810160208510156148cf5750805b601f840160051c820191505b81811015613330575f81556001016148db565b505050565b6001600160401b0383111561490a5761490a614642565b61491e83614918835461480c565b836148aa565b5f601f84116001811461494f575f85156149385750838201355b5f19600387901b1c1916600186901b178355613330565b5f83815260208120601f198716915b8281101561497e578685013582556020948501946001909201910161495e565b508682101561499a575f1960f88860031b161c19848701351681555b505060018560011b0183555050505050565b60208152816020820152818360408301375f818301604090810191909152601f909201601f1916010191905056fea26469706673582212205b3bac2216f03366b23ba16633b7a124ad19508b5fd3d806a9fe0c714e4dcad764736f6c634300081a0033000000000000000000000000cae3fec333be0c5f4bfe932f5cafcc6f86c4c887

Deployed Bytecode

0x60806040526004361061038a575f3560e01c80637fd6b2e7116101d3578063b7a17c4c116100fd578063ded72d1f1161009d578063e83267451161006d578063e832674514610b06578063f4e8b45014610b19578063f71d96cb14610b38578063fe74379114610b57575f80fd5b8063ded72d1f14610a66578063e085c53914610a94578063e19ddff314610ac8578063e5b42e9214610ae7575f80fd5b8063c7a77e2f116100d8578063c7a77e2f146109fe578063d529251d14610a11578063dac6270d14610a30578063dbb838a914610a44575f80fd5b8063b7a17c4c146109ab578063c19d93fb146109c4578063c2e52206146109ea575f80fd5b8063938a864511610173578063b2652ec411610143578063b2652ec41461092c578063b329be371461094b578063b33ac8aa1461095f578063b38321a21461097d575f80fd5b8063938a8645146108ae5780639e75143c146108cd578063a83b589c146108ee578063af331b651461090d575f80fd5b80638aa0cb6c116101ae5780638aa0cb6c146108485780638b5b9ccc146108675780638bb98fd91461087b5780639129ce391461088f575f80fd5b80637fd6b2e7146107d157806388aafa60146107f057806388f4e6eb14610829575f80fd5b8063516f4f30116102b45780637350f431116102545780637776282011610224578063777628201461075157806379390faa146107655780637bdd449c146107845780637df3c497146107a3575f80fd5b80637350f431146106ba5780637488ad24146106e8578063755b77b31461070757806376dd110f14610726575f80fd5b8063554c1b1f1161028f578063554c1b1f1461062657806356de96db1461065957806356df26be14610678578063620274061461069b575f80fd5b8063516f4f30146105d257806353aab43414610609578063546216f114610611575f80fd5b806318edd1781161032a57806344d9bc5f116102fa57806344d9bc5f1461054d57806348bb35a2146105805780634ded2e8e1461059f5780634ffac413146105be575f80fd5b806318edd178146104c6578063241e5622146104e75780632f5a90a6146105085780633ccfd60b14610539575f80fd5b806309c95e101161036557806309c95e101461041957806312065fe01461046057806316c44e6f1461047c5780631746bd1b1461049b575f80fd5b8063040141e5146103955780630642bc41146103d9578063093119f7146103f8575f80fd5b3661039157005b5f80fd5b3480156103a0575f80fd5b506103bc7382af49447d8a07e3bd95bd0d56f35241523fbab181565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156103e4575f80fd5b506003546103bc906001600160a01b031681565b348015610403575f80fd5b5061041761041236600461411a565b610b76565b005b348015610424575f80fd5b50610450610433366004614151565b6001600160a01b03165f908152600b602052604090205460ff1690565b60405190151581526020016103d0565b34801561046b575f80fd5b50475b6040519081526020016103d0565b348015610487575f80fd5b506001546103bc906001600160a01b031681565b3480156104a6575f80fd5b506005546007546040516103d09260ff1691906509184e72a000906141a0565b3480156104d1575f80fd5b506104da610cc0565b6040516103d091906141bf565b3480156104f2575f80fd5b506104fb610d33565b6040516103d09190614247565b348015610513575f80fd5b50610527610522366004614259565b610d92565b60405160ff90911681526020016103d0565b348015610544575f80fd5b50610417610dc3565b348015610558575f80fd5b5061046e7f00000000000000000000000000000000000000000000000000000000691e1a7181565b34801561058b575f80fd5b5061041761059a3660046142b7565b610f2c565b3480156105aa575f80fd5b506104506105b93660046142f5565b611027565b3480156105c9575f80fd5b5060085461046e565b3480156105dd575f80fd5b506104506105ec366004614151565b6001600160a01b03165f908152600e602052604090205460ff1690565b6104176111e1565b34801561061c575f80fd5b5061046e600a5481565b348015610631575f80fd5b506103bc7f000000000000000000000000cae3fec333be0c5f4bfe932f5cafcc6f86c4c88781565b348015610664575f80fd5b5061041761067336600461431f565b611355565b348015610683575f80fd5b5061068c611463565b6040516103d09392919061436d565b3480156106a6575f80fd5b506104176106b5366004614151565b611625565b3480156106c5575f80fd5b506104506106d4366004614151565b600c6020525f908152604090205460ff1681565b3480156106f3575f80fd5b506104176107023660046143d8565b61178b565b348015610712575f80fd5b50610417610721366004614151565b611a38565b348015610731575f80fd5b5061046e610740366004614151565b600d6020525f908152604090205481565b34801561075c575f80fd5b50610417611b43565b348015610770575f80fd5b5061041761077f3660046142f5565b611f11565b34801561078f575f80fd5b506103bc61079e366004614259565b611fa8565b3480156107ae575f80fd5b506104506107bd366004614151565b600b6020525f908152604090205460ff1681565b3480156107dc575f80fd5b506104176107eb366004614450565b611fd0565b3480156107fb575f80fd5b5061045061080a36600461411a565b600f60209081525f928352604080842090915290825290205460ff1681565b348015610834575f80fd5b5061041761084336600461411a565b612106565b348015610853575f80fd5b50610417610862366004614151565b612861565b348015610872575f80fd5b506104fb61295a565b348015610886575f80fd5b506104506129b8565b34801561089a575f80fd5b506104176108a9366004614259565b612a05565b3480156108b9575f80fd5b506104176108c8366004614151565b612cc5565b3480156108d8575f80fd5b506108e1612d94565b6040516103d09190614473565b3480156108f9575f80fd5b506104176109083660046142f5565b612e20565b348015610918575f80fd5b50610527610927366004614259565b612f62565b348015610937575f80fd5b50610450610946366004614151565b612f89565b348015610956575f80fd5b506104fb612fce565b34801561096a575f80fd5b505f546103bc906001600160a01b031681565b348015610988575f80fd5b50610450610997366004614151565b600e6020525f908152604090205460ff1681565b3480156109b6575f80fd5b5061046e6509184e72a00081565b3480156109cf575f80fd5b506005546109dd9060ff1681565b6040516103d091906144a8565b3480156109f5575f80fd5b5060075461046e565b610417610a0c3660046144b6565b61302c565b348015610a1c575f80fd5b506002546103bc906001600160a01b031681565b348015610a3b575f80fd5b5061046e613337565b348015610a4f575f80fd5b50610a5861338e565b6040516103d09291906144fd565b348015610a71575f80fd5b50610527610a80366004614259565b60106020525f908152604090205460ff1681565b348015610a9f575f80fd5b5061046e610aae366004614151565b6001600160a01b03165f908152600d602052604090205490565b348015610ad3575f80fd5b506103bc610ae2366004614259565b613549565b348015610af2575f80fd5b50610417610b01366004614259565b613558565b610417610b143660046142b7565b613941565b348015610b24575f80fd5b50610417610b33366004614521565b613d34565b348015610b43575f80fd5b506103bc610b52366004614259565b613e24565b348015610b62575f80fd5b50610417610b71366004614151565b613e33565b335f908152600c602052604090205460ff16610ba557604051634632ffe360e01b815260040160405180910390fd5b335f908152600e602052604090205460ff1615610bd557604051631894063360e21b815260040160405180910390fd5b6001600160a01b0381165f908152600b602052604090205460ff16610c0d5760405163abca351760e01b815260040160405180910390fd5b335f908152600e60209081526040808320805460ff191660011790556001600160a01b0384168352600d90915281205490600a821015610c4d5781610c50565b600a5b9050610c5c81836145a1565b6001600160a01b038481165f818152600d602090815260408083209590955584518681529081019190915290929187169133917f8044fa4da29a21540b095aa9cddd2e3f31d47978eb3d8440183b6ac98bf3bda1910160405180910390a450505050565b60606006805480602002602001604051908101604052809291908181526020018280548015610d2957602002820191905f5260205f20905f905b825461010083900a900460ff16815260206001928301818104948501949093039092029101808411610cfa5790505b5050505050905090565b60606008805480602002602001604051908101604052809291908181526020018280548015610d2957602002820191905f5260205f20905b81546001600160a01b03168152600190910190602001808311610d6b575050505050905090565b60068181548110610da1575f80fd5b905f5260205f209060209182820401919006915054906101000a900460ff1681565b7f000000000000000000000000cae3fec333be0c5f4bfe932f5cafcc6f86c4c8876001600160a01b031663af30ee3f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e1f573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e4391906145b4565b6001600160a01b0316336001600160a01b031614610e7457604051630cb73db360e21b815260040160405180910390fd5b7f000000000000000000000000cae3fec333be0c5f4bfe932f5cafcc6f86c4c8876001600160a01b031663af30ee3f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ed0573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ef491906145b4565b6001600160a01b03166108fc4790811502906040515f60405180830381858888f19350505050158015610f29573d5f803e3d5ffd5b50565b7f000000000000000000000000cae3fec333be0c5f4bfe932f5cafcc6f86c4c8876001600160a01b031663af30ee3f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f88573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610fac91906145b4565b6001600160a01b0316336001600160a01b031614610fdd57604051630cb73db360e21b815260040160405180910390fd5b610fe960068383613ffb565b507f94e1ce80c1f560eae2d7da116779b3aacee5613170afb9876373e3c761aa1956828260405161101b9291906145cf565b60405180910390a15050565b5f80546001600160a01b031661103e57505f6111db565b5f8054604051633ff3649360e01b8152600481018590526001600160a01b0390911690633ff3649390602401602060405180830381865afa158015611085573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110a991906145b4565b90506001600160a01b0381166110c2575f9150506111db565b5f6110ef826040518060400160405280600a81526020016918dc9959195b9d1a585b60b21b815250613f2c565b90506001600160a01b038116611109575f925050506111db565b6040516001600160a01b0386811660248301525f91829184169060440160408051601f198184030181529181526020820180516001600160e01b03166370a0823160e01b1790525161115b9190614615565b5f60405180830381855afa9150503d805f8114611193576040519150601f19603f3d011682016040523d82523d5f602084013e611198565b606091505b50915091508115806111ab575060208151105b156111bc575f9450505050506111db565b5f818060200190518101906111d1919061462b565b1515955050505050505b92915050565b5f60055460ff1660028111156111f9576111f961416c565b1461121757604051635c07b6d760e11b815260040160405180910390fd5b6509184e72a00034101561123e5760405163cd1c886760e01b815260040160405180910390fd5b335f908152600b602052604090205460ff161561126e576040516314c4fea760e31b815260040160405180910390fd5b6007805460018181019092557fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c6880180546001600160a01b031916339081179091555f818152600b60209081526040808320805460ff1916909517909455600d90528281205590517f7dbd99091135732d8894a7112b904af6bf7fee8441105b31987f90c32329fdd9906113049034815260200190565b60405180910390a26509184e72a00034111561135357336108fc61132e6509184e72a000346145a1565b6040518115909202915f818181858888f19350505050158015610f29573d5f803e3d5ffd5b565b7f000000000000000000000000cae3fec333be0c5f4bfe932f5cafcc6f86c4c8876001600160a01b031663af30ee3f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113b1573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906113d591906145b4565b6001600160a01b0316336001600160a01b03161461140657604051630cb73db360e21b815260040160405180910390fd5b6005805482919060ff191660018360028111156114255761142561416c565b02179055507ea8b06dd72552dea96e97c9a96acf39a1908ada44765cefe367620485b2c7e18160405161145891906144a8565b60405180910390a150565b60085460609081908190806001600160401b0381111561148557611485614642565b6040519080825280602002602001820160405280156114ae578160200160208202803683370190505b509350806001600160401b038111156114c9576114c9614642565b6040519080825280602002602001820160405280156114f2578160200160208202803683370190505b509250806001600160401b0381111561150d5761150d614642565b604051908082528060200260200182016040528015611536578160200160208202803683370190505b5091505f5b8181101561161e575f6008828154811061155757611557614656565b905f5260205f20015f9054906101000a90046001600160a01b031690508086838151811061158757611587614656565b60200260200101906001600160a01b031690816001600160a01b031681525050806001600160a01b0316318583815181106115c4576115c4614656565b6020908102919091018101919091526001600160a01b0382165f908152600e9091526040902054845160ff9091169085908490811061160557611605614656565b911515602092830291909101909101525060010161153b565b5050909192565b7f000000000000000000000000cae3fec333be0c5f4bfe932f5cafcc6f86c4c8876001600160a01b031663af30ee3f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611681573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116a591906145b4565b6001600160a01b0316336001600160a01b0316146116d657604051630cb73db360e21b815260040160405180910390fd5b6116df81612f89565b156116fd5760405163e0dbb1a760e01b815260040160405180910390fd5b6008805460018082019092557ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee30180546001600160a01b0319166001600160a01b0384169081179091555f818152600c6020526040808220805460ff1916909417909355915190917f07577ee4d7b640060b986e698b16d90aef8e3a4fffa36dd13d3b79195e70b3d691a250565b7f000000000000000000000000cae3fec333be0c5f4bfe932f5cafcc6f86c4c8876001600160a01b031663af30ee3f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156117e7573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061180b91906145b4565b6001600160a01b0316336001600160a01b03161461183c57604051630cb73db360e21b815260040160405180910390fd5b8215806118495750828114155b156118675760405163a9854bc960e01b815260040160405180910390fd5b5f805b828110156118a05783838281811061188457611884614656565b9050602002013582611896919061466a565b915060010161186a565b50806103e8146118c357604051636d2fd3c960e01b815260040160405180910390fd5b475f8190036118d3575050611a32565b5f5b858110156119ef575f8787838181106118f0576118f0614656565b90506020020160208101906119059190614151565b6001600160a01b0316146119e7575f6103e886868481811061192957611929614656565b905060200201358461193b919061467d565b61194591906146a8565b905080156119e5575f88888481811061196057611960614656565b90506020020160208101906119759190614151565b6001600160a01b0316826040515f6040518083038185875af1925050503d805f81146119bc576040519150601f19603f3d011682016040523d82523d5f602084013e6119c1565b606091505b50509050806119e357604051630ec6ac4160e21b815260040160405180910390fd5b505b505b6001016118d5565b507f5a31676f5fc71e56ec99e78f1f76a78352cdc05a4c1be0d3accdbb305a512ce48686868685604051611a279594939291906146f9565b60405180910390a150505b50505050565b7f000000000000000000000000cae3fec333be0c5f4bfe932f5cafcc6f86c4c8876001600160a01b031663af30ee3f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a94573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ab891906145b4565b6001600160a01b0316336001600160a01b031614611ae957604051630cb73db360e21b815260040160405180910390fd5b6001600160a01b038116611b185760405162461bcd60e51b8152600401611b0f9061474c565b60405180910390fd5b5f80546001600160a01b039092166001600160a01b0319928316811790915560028054909216179055565b7f00000000000000000000000000000000000000000000000000000000691e1a71421015611b8457604051638f86c6b360e01b815260040160405180910390fd5b600260055460ff166002811115611b9d57611b9d61416c565b03611bbb57604051636e2ab89360e11b815260040160405180910390fd5b6007545f03611bd3576005805460ff19166002179055565b5f805b600754811015611c32575f600d5f60078481548110611bf757611bf7614656565b5f9182526020808320909101546001600160a01b03168352820192909252604001902054905082811115611c29578092505b50600101611bd6565b506007545f906001600160401b03811115611c4f57611c4f614642565b604051908082528060200260200182016040528015611c78578160200160208202803683370190505b5090505f805b600754811015611d365783600d5f60078481548110611c9f57611c9f614656565b5f9182526020808320909101546001600160a01b0316835282019290925260400190205403611d2e5760078181548110611cdb57611cdb614656565b905f5260205f20015f9054906101000a90046001600160a01b0316838381518110611d0857611d08614656565b6001600160a01b039092166020928302919091019091015281611d2a81614775565b9250505b600101611c7e565b50806001600160401b03811115611d4f57611d4f614642565b604051908082528060200260200182016040528015611d78578160200160208202803683370190505b508051611d8d9160099160209091019061409f565b505f5b81811015611df557828181518110611daa57611daa614656565b602002602001015160098281548110611dc557611dc5614656565b5f91825260209091200180546001600160a01b0319166001600160a01b0392909216919091179055600101611d90565b50600a8390556005805460ff19166002179055475f8115801590611e1857505f83115b15611eca57611e2783836146a8565b90505f5b83811015611ec8575f60098281548110611e4757611e47614656565b5f9182526020822001546040516001600160a01b039091169185919081818185875af1925050503d805f8114611e98576040519150601f19603f3d011682016040523d82523d5f602084013e611e9d565b606091505b5050905080611ebf57604051630ec6ac4160e21b815260040160405180910390fd5b50600101611e2b565b505b7f8b8f0658aa11ba65d0656d3982f05a3d5d88b0190cc77264e6fc6aff7e711da06009600a548484604051611f02949392919061478d565b60405180910390a15050505050565b611f1a33612f89565b611f3757604051634632ffe360e01b815260040160405180910390fd5b6001600160a01b0382165f908152600d602052604081208054839290611f5e90849061466a565b90915550506040518181526001600160a01b0383169033907f8c1e155b9f22132fd0366f32e05296679a0174614fe6dc4b2f7e2fcfc0385534906020015b60405180910390a35050565b60098181548110611fb7575f80fd5b5f918252602090912001546001600160a01b0316905081565b7f000000000000000000000000cae3fec333be0c5f4bfe932f5cafcc6f86c4c8876001600160a01b031663af30ee3f6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561202c573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061205091906145b4565b6001600160a01b0316336001600160a01b03161461208157604051630cb73db360e21b815260040160405180910390fd5b60018160ff161080612096575060068160ff16115b156120b45760405163560612c960e01b815260040160405180910390fd5b5f82815260106020908152604091829020805460ff191660ff85169081179091559151918252339184917fa5df98dd2060f5d5cfe17f03fee367e49d826fa19635fb6874523063191cc30e9101611f9c565b335f908152600c602052604090205460ff1661213557604051634632ffe360e01b815260040160405180910390fd5b335f908152600e602052604090205460ff161561216557604051631894063360e21b815260040160405180910390fd5b6001600160a01b0381165f908152600b602052604090205460ff1661219d5760405163abca351760e01b815260040160405180910390fd5b335f908152600e6020526040808220805460ff19166001179055815490516370b131c360e11b81526001600160a01b0384811660048301529091169063e162638690602401602060405180830381865afa1580156121fd573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612221919061462b565b9050805f036122695760405162461bcd60e51b8152602060048201526014602482015273283630bcb2b9103430b99037379039b2b1ba37b960611b6044820152606401611b0f565b5f8054604051633ff3649360e01b8152600481018490526001600160a01b0390911690633ff3649390602401602060405180830381865afa1580156122b0573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906122d491906145b4565b90506001600160a01b03811661231a5760405162461bcd60e51b815260206004820152600b60248201526a4e6f20726567697374727960a81b6044820152606401611b0f565b5f61234282604051806040016040528060058152602001647374616b6560d81b815250613f2c565b90506001600160a01b03811661238c5760405162461bcd60e51b815260206004820152600f60248201526e4e6f207374616b65206d6f64756c6560881b6044820152606401611b0f565b6001546001600160a01b03166123d65760405162461bcd60e51b815260206004820152600f60248201526e105d591a5d1bdc881b9bdd081cd95d608a1b6044820152606401611b0f565b6001546040516001600160a01b0383811660248301525f92839291169060440160408051601f198184030181529181526020820180516001600160e01b0316639d26080960e01b1790525161242b9190614615565b5f60405180830381855afa9150503d805f8114612463576040519150601f19603f3d011682016040523d82523d5f602084013e612468565b606091505b509150915081801561247c57506020815110155b6124bd5760405162461bcd60e51b8152602060048201526012602482015271105d591a5d0818da1958dac819985a5b195960721b6044820152606401611b0f565b5f818060200190518101906124d291906147f1565b90508060ff166004146125275760405162461bcd60e51b815260206004820152601960248201527f4e6f74206175646974656420666f7220636861707465722034000000000000006044820152606401611b0f565b5f8054604051633a02a42d60e01b81526001600160a01b038b8116600483015290911690633a02a42d90602401602060405180830381865afa15801561256f573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612593919061462b565b905069021e19e0c9bab24000008110156125ef5760405162461bcd60e51b815260206004820152601d60248201527f4b696c6c65722068617320696e73756666696369656e74207374616b650000006044820152606401611b0f565b6040516001600160a01b038a811660248301525f919087169060440160408051601f198184030181529181526020820180516001600160e01b031663c96be4cb60e01b179052516126409190614615565b5f604051808303815f865af19150503d805f8114612679576040519150601f19603f3d011682016040523d82523d5f602084013e61267e565b606091505b50509050806126c35760405162461bcd60e51b815260206004820152601160248201527014db185cda0818d85b1b0819985a5b1959607a1b6044820152606401611b0f565b5f8054604051633a02a42d60e01b81526001600160a01b038d8116600483015290911690633a02a42d90602401602060405180830381865afa15801561270b573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061272f919061462b565b9050801561279b5760405162461bcd60e51b815260206004820152603360248201527f536c61736820646964206e6f74206275726e207374616b65202d206d616c69636044820152721a5bdd5cc81cdd185ad94818dbdb9d1c9858dd606a1b6064820152608401611b0f565b69021e19e0c9bab24000006127b082856145a1565b101561280a5760405162461bcd60e51b8152602060048201526024808201527f536c61736820646964206e6f74206275726e2066756c6c207374616b6520616d6044820152631bdd5b9d60e21b6064820152608401611b0f565b604080515f80825260208201526001600160a01b03808d1692908e169133917f8044fa4da29a21540b095aa9cddd2e3f31d47978eb3d8440183b6ac98bf3bda1910160405180910390a45050505050505050505050565b7f000000000000000000000000cae3fec333be0c5f4bfe932f5cafcc6f86c4c8876001600160a01b031663af30ee3f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156128bd573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906128e191906145b4565b6001600160a01b0316336001600160a01b03161461291257604051630cb73db360e21b815260040160405180910390fd5b6001600160a01b0381166129385760405162461bcd60e51b8152600401611b0f9061474c565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b60606007805480602002602001604051908101604052809291908181526020018280548015610d2957602002820191905f5260205f209081546001600160a01b03168152600190910190602001808311610d6b575050505050905090565b5f7f00000000000000000000000000000000000000000000000000000000691e1a714210158015612a005750600260055460ff1660028111156129fd576129fd61416c565b14155b905090565b5f546001600160a01b0316612a2d57604051631e0aa0c360e21b815260040160405180910390fd5b612a3632612f89565b612a5357604051634632ffe360e01b815260040160405180910390fd5b5f8054604051633ff3649360e01b8152600481018490526001600160a01b0390911690633ff3649390602401602060405180830381865afa158015612a9a573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612abe91906145b4565b90506001600160a01b038116612ae7576040516381d522f560e01b815260040160405180910390fd5b5f612b14826040518060400160405280600a81526020016918dc9959195b9d1a585b60b21b815250613f2c565b90506001600160a01b038116612b3d57604051635e5b1d7560e11b815260040160405180910390fd5b6001600160a01b0381163314612b6657604051635e5b1d7560e11b815260040160405180910390fd5b5f8054604051634650b04560e01b8152600481018690526001600160a01b0390911690634650b04590602401602060405180830381865afa158015612bad573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612bd191906145b4565b90506001600160a01b038116612bfa5760405163abca351760e01b815260040160405180910390fd5b325f908152600f602090815260408083206001600160a01b038516845290915290205460ff1615612c3e5760405163933099c160e01b815260040160405180910390fd5b325f908152600f602090815260408083206001600160a01b03851684528252808320805460ff19166001179055600d9091528120805460029290612c8390849061466a565b909155505060405133906001600160a01b0383169032907f8483d60736ac8e5fa0068cccf221544749b1c7acc419a99c12df90a44c966c9d905f90a450505050565b6002546001600160a01b03163314612cf05760405163cbf6cf7b60e01b815260040160405180910390fd5b5f805b600754811015612d4457826001600160a01b031660078281548110612d1a57612d1a614656565b5f918252602090912001546001600160a01b031603612d3c5760019150612d44565b600101612cf3565b5080612d635760405163abca351760e01b815260040160405180910390fd5b6001600160a01b0382165f908152600d60205260408120805460059290612d8b90849061466a565b90915550505050565b60048054612da19061480c565b80601f0160208091040260200160405190810160405280929190818152602001828054612dcd9061480c565b8015612e185780601f10612def57610100808354040283529160200191612e18565b820191905f5260205f20905b815481529060010190602001808311612dfb57829003601f168201915b505050505081565b6001546001600160a01b03163314612e4b5760405163f87c866960e01b815260040160405180910390fd5b5f805b600754811015612e9f57836001600160a01b031660078281548110612e7557612e75614656565b5f918252602090912001546001600160a01b031603612e975760019150612e9f565b600101612e4e565b5080612ebe5760405163abca351760e01b815260040160405180910390fd5b6001600160a01b0383165f908152600d602052604090205482811015612ef75760405163303e7a0760e01b815260040160405180910390fd5b612f0183826145a1565b6001600160a01b0385165f818152600d6020526040908190208390555190917f2d8ea5250bf29dafe8cda27d1a8c9aaf28837abf1505e7f02097a7f44bbee54c91612f5491878252602082015260400190565b60405180910390a250505050565b5f8181526010602052604081205460ff168015612f7f5780612f82565b60015b9392505050565b6001600160a01b0381165f908152600e602052604081205460ff1615612fb057505f919050565b506001600160a01b03165f908152600c602052604090205460ff1690565b60606009805480602002602001604051908101604052809291908181526020018280548015610d2957602002820191905f5260205f209081546001600160a01b03168152600190910190602001808311610d6b575050505050905090565b7f000000000000000000000000cae3fec333be0c5f4bfe932f5cafcc6f86c4c8876001600160a01b031663af30ee3f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613088573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906130ac91906145b4565b6001600160a01b0316336001600160a01b0316146130dd57604051630cb73db360e21b815260040160405180910390fd5b8161311f5760405162461bcd60e51b8152602060048201526012602482015271139bc81c1a5b1bdd1cc81c1c9bdd9a59195960721b6044820152606401611b0f565b5f811161316e5760405162461bcd60e51b815260206004820152601760248201527f496e76616c6964206d696e696d756d2062616c616e63650000000000000000006044820152606401611b0f565b5f805b83811015613295575f85858381811061318c5761318c614656565b90506020020160208101906131a19190614151565b6001600160a01b03163190508381101561328c575f6131c082866145a1565b90505f8787858181106131d5576131d5614656565b90506020020160208101906131ea9190614151565b6001600160a01b0316826040515f6040518083038185875af1925050503d805f8114613231576040519150601f19603f3d011682016040523d82523d5f602084013e613236565b606091505b505090508061327d5760405162461bcd60e51b8152602060048201526013602482015272115512081d1c985b9cd9995c8819985a5b1959606a1b6044820152606401611b0f565b613287828661466a565b945050505b50600101613171565b505f6132a182346145a1565b90508015613330576040515f90339083908381818185875af1925050503d805f81146132e8576040519150601f19603f3d011682016040523d82523d5f602084013e6132ed565b606091505b505090508061332e5760405162461bcd60e51b815260206004820152600d60248201526c1499599d5b990819985a5b1959609a1b6044820152606401611b0f565b505b5050505050565b5f7f00000000000000000000000000000000000000000000000000000000691e1a71421061336457505f90565b612a00427f00000000000000000000000000000000000000000000000000000000691e1a716145a1565b6008546060908190806001600160401b038111156133ae576133ae614642565b6040519080825280602002602001820160405280156133d7578160200160208202803683370190505b509250806001600160401b038111156133f2576133f2614642565b60405190808252806020026020018201604052801561341b578160200160208202803683370190505b5091505f5b81811015613543575f6008828154811061343c5761343c614656565b905f5260205f20015f9054906101000a90046001600160a01b031690508085838151811061346c5761346c614656565b6001600160a01b039283166020918202929092010152600354161561351a576003546040516370a0823160e01b81526001600160a01b038381166004830152909116906370a0823190602401602060405180830381865afa1580156134d3573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906134f7919061462b565b84838151811061350957613509614656565b60200260200101818152505061353a565b5f84838151811061352d5761352d614656565b6020026020010181815250505b50600101613420565b50509091565b60088181548110611fb7575f80fd5b5f546001600160a01b031661358057604051631e0aa0c360e21b815260040160405180910390fd5b61358932612f89565b6135a657604051634632ffe360e01b815260040160405180910390fd5b5f8054604051633ff3649360e01b8152600481018490526001600160a01b0390911690633ff3649390602401602060405180830381865afa1580156135ed573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061361191906145b4565b90506001600160a01b03811661363a576040516381d522f560e01b815260040160405180910390fd5b5f613661826040518060400160405280600481526020016373616c6560e01b815250613f2c565b90506001600160a01b03811661368a57604051631b3473a560e21b815260040160405180910390fd5b6001600160a01b03811633146136b357604051631b3473a560e21b815260040160405180910390fd5b5f8054604051634650b04560e01b8152600481018690526001600160a01b0390911690634650b04590602401602060405180830381865afa1580156136fa573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061371e91906145b4565b90506001600160a01b0381166137475760405163abca351760e01b815260040160405180910390fd5b5f8481526010602052604081205460ff1690819003613764575060015b60068160ff16106137885760405163e2a31caf60e01b815260040160405180910390fd5b6003546040516370a0823160e01b81526001600160a01b038581166004830152690a7b667f19c28bf000009283929116906370a0823190602401602060405180830381865afa1580156137dd573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613801919061462b565b1015613820576040516317f5126160e11b815260040160405180910390fd5b6003546040516323b872dd60e01b81526001600160a01b03868116600483015230602483015260448201849052909116906323b872dd906064016020604051808303815f875af1158015613876573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061389a9190614844565b506001600160a01b0383165f908152600d602052604081208054600a92906138c390849061466a565b909155505f90506138d5836001614863565b5f88815260106020908152604091829020805460ff191660ff8516908117909155915191825291925032916001600160a01b038716918a917f6544a62572f716ddb5ef122f657bcced3130b4e6b6e7ea78bccf9f8694a27df4910160405180910390a450505050505050565b7f000000000000000000000000cae3fec333be0c5f4bfe932f5cafcc6f86c4c8876001600160a01b031663af30ee3f6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561399d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906139c191906145b4565b6001600160a01b0316336001600160a01b0316146139f257604051630cb73db360e21b815260040160405180910390fd5b80613a345760405162461bcd60e51b8152602060048201526012602482015271139bc81c1a5b1bdd1cc81c1c9bdd9a59195960721b6044820152606401611b0f565b5f805b82811015613b3157613a69848483818110613a5457613a54614656565b90506020020160208101906109469190614151565b613b29576008848483818110613a8157613a81614656565b9050602002016020810190613a969190614151565b8154600180820184555f9384526020842090910180546001600160a01b0319166001600160a01b03939093169290921790915590600c90868685818110613adf57613adf614656565b9050602002016020810190613af49190614151565b6001600160a01b0316815260208101919091526040015f20805460ff191691151591909117905581613b2581614775565b9250505b600101613a37565b505f34118015613b4057505f81115b15613cf6575f613b5082346146a8565b90505f613b5d833461487c565b90505f5b84811015613cf2575f805f5b600854811015613c0157888885818110613b8957613b89614656565b9050602002016020810190613b9e9190614151565b6001600160a01b031660088281548110613bba57613bba614656565b5f918252602090912001546001600160a01b031603613bf95781613bdd81614775565b92505081600103613bf15760019250613bf9565b5f9250613c01565b600101613b6d565b50818015613c0e57505f85115b15613ce857848415613c2a57613c24858261466a565b90505f94505b5f898986818110613c3d57613c3d614656565b9050602002016020810190613c529190614151565b6001600160a01b0316826040515f6040518083038185875af1925050503d805f8114613c99576040519150601f19603f3d011682016040523d82523d5f602084013e613c9e565b606091505b5050905080613ce55760405162461bcd60e51b8152602060048201526013602482015272115512081d1c985b9cd9995c8819985a5b1959606a1b6044820152606401611b0f565b50505b5050600101613b61565b5050505b7fe117669371937de9be25bcb2289999348317901d98fc0f3329182571cf613c2c8383604051613d2792919061488f565b60405180910390a1505050565b7f000000000000000000000000cae3fec333be0c5f4bfe932f5cafcc6f86c4c8876001600160a01b031663af30ee3f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613d90573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613db491906145b4565b6001600160a01b0316336001600160a01b031614613de557604051630cb73db360e21b815260040160405180910390fd5b6004613df28284836148f3565b507fd28e4ca79028f3e151e2b2496a82ad2095820d02b3e69b0fa88cac665a9a88ce828260405161101b9291906149ac565b60078181548110611fb7575f80fd5b7f000000000000000000000000cae3fec333be0c5f4bfe932f5cafcc6f86c4c8876001600160a01b031663af30ee3f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613e8f573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613eb391906145b4565b6001600160a01b0316336001600160a01b031614613ee457604051630cb73db360e21b815260040160405180910390fd5b6001600160a01b038116613f0a5760405162461bcd60e51b8152600401611b0f9061474c565b600380546001600160a01b0319166001600160a01b0392909216919091179055565b5f805f846001600160a01b031684604051602401613f4a9190614473565b60408051601f198184030181529181526020820180516001600160e01b031663099b0d6d60e41b17905251613f7f9190614615565b5f60405180830381855afa9150503d805f8114613fb7576040519150601f19603f3d011682016040523d82523d5f602084013e613fbc565b606091505b5091509150811580613fcf575060208151105b15613fde575f925050506111db565b80806020019051810190613ff291906145b4565b95945050505050565b828054828255905f5260205f2090601f0160209004810192821561408f579160200282015f5b8382111561406157833560ff1683826101000a81548160ff021916908360ff16021790555092602001926001016020815f01049283019260010302614021565b801561408d5782816101000a81549060ff02191690556001016020815f01049283019260010302614061565b505b5061409b9291506140f2565b5090565b828054828255905f5260205f2090810192821561408f579160200282015b8281111561408f57825182546001600160a01b0319166001600160a01b039091161782556020909201916001909101906140bd565b5b8082111561409b575f81556001016140f3565b6001600160a01b0381168114610f29575f80fd5b5f806040838503121561412b575f80fd5b823561413681614106565b9150602083013561414681614106565b809150509250929050565b5f60208284031215614161575f80fd5b8135612f8281614106565b634e487b7160e01b5f52602160045260245ffd5b6003811061419c57634e487b7160e01b5f52602160045260245ffd5b9052565b606081016141ae8286614180565b602082019390935260400152919050565b602080825282518282018190525f918401906040840190835b818110156141f957835160ff168352602093840193909201916001016141d8565b509095945050505050565b5f8151808452602084019350602083015f5b8281101561423d5781516001600160a01b0316865260209586019590910190600101614216565b5093949350505050565b602081525f612f826020830184614204565b5f60208284031215614269575f80fd5b5035919050565b5f8083601f840112614280575f80fd5b5081356001600160401b03811115614296575f80fd5b6020830191508360208260051b85010111156142b0575f80fd5b9250929050565b5f80602083850312156142c8575f80fd5b82356001600160401b038111156142dd575f80fd5b6142e985828601614270565b90969095509350505050565b5f8060408385031215614306575f80fd5b823561431181614106565b946020939093013593505050565b5f6020828403121561432f575f80fd5b813560038110612f82575f80fd5b5f8151808452602084019350602083015f5b8281101561423d57815186526020958601959091019060010161434f565b606081525f61437f6060830186614204565b8281036020840152614391818661433d565b8381036040850152845180825260208087019350909101905f5b818110156143cb57835115158352602093840193909201916001016143ab565b5090979650505050505050565b5f805f80604085870312156143eb575f80fd5b84356001600160401b03811115614400575f80fd5b61440c87828801614270565b90955093505060208501356001600160401b0381111561442a575f80fd5b61443687828801614270565b95989497509550505050565b60ff81168114610f29575f80fd5b5f8060408385031215614461575f80fd5b82359150602083013561414681614442565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b602081016111db8284614180565b5f805f604084860312156144c8575f80fd5b83356001600160401b038111156144dd575f80fd5b6144e986828701614270565b909790965060209590950135949350505050565b604081525f61450f6040830185614204565b8281036020840152613ff2818561433d565b5f8060208385031215614532575f80fd5b82356001600160401b03811115614547575f80fd5b8301601f81018513614557575f80fd5b80356001600160401b0381111561456c575f80fd5b85602082840101111561457d575f80fd5b6020919091019590945092505050565b634e487b7160e01b5f52601160045260245ffd5b818103818111156111db576111db61458d565b5f602082840312156145c4575f80fd5b8151612f8281614106565b602080825281018290525f8360408301825b8581101561460b5782356145f481614442565b60ff168252602092830192909101906001016145e1565b5095945050505050565b5f82518060208501845e5f920191825250919050565b5f6020828403121561463b575f80fd5b5051919050565b634e487b7160e01b5f52604160045260245ffd5b634e487b7160e01b5f52603260045260245ffd5b808201808211156111db576111db61458d565b80820281158282048414176111db576111db61458d565b634e487b7160e01b5f52601260045260245ffd5b5f826146b6576146b6614694565b500490565b8183526020830192505f815f5b8481101561423d5781356146db81614106565b6001600160a01b0316865260209586019591909101906001016146c8565b606081525f61470c6060830187896146bb565b82810360208401528481526001600160fb1b0385111561472a575f80fd5b8460051b80876020840137604093909301939093525001602001949350505050565b6020808252600f908201526e496e76616c6964206164647265737360881b604082015260600190565b5f600182016147865761478661458d565b5060010190565b608080825285549082018190525f86815260208120909160a0840190835b818110156147d25783546001600160a01b03168352600193840193602090930192016147ab565b5050602084019690965250506040810192909252606090910152919050565b5f60208284031215614801575f80fd5b8151612f8281614442565b600181811c9082168061482057607f821691505b60208210810361483e57634e487b7160e01b5f52602260045260245ffd5b50919050565b5f60208284031215614854575f80fd5b81518015158114612f82575f80fd5b60ff81811683821601908111156111db576111db61458d565b5f8261488a5761488a614694565b500690565b602081525f6148a26020830184866146bb565b949350505050565b601f8211156148ee57805f5260205f20601f840160051c810160208510156148cf5750805b601f840160051c820191505b81811015613330575f81556001016148db565b505050565b6001600160401b0383111561490a5761490a614642565b61491e83614918835461480c565b836148aa565b5f601f84116001811461494f575f85156149385750838201355b5f19600387901b1c1916600186901b178355613330565b5f83815260208120601f198716915b8281101561497e578685013582556020948501946001909201910161495e565b508682101561499a575f1960f88860031b161c19848701351681555b505060018560011b0183555050505050565b60208152816020820152818360408301375f818301604090810191909152601f909201601f1916010191905056fea26469706673582212205b3bac2216f03366b23ba16633b7a124ad19508b5fd3d806a9fe0c714e4dcad764736f6c634300081a0033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

000000000000000000000000cae3fec333be0c5f4bfe932f5cafcc6f86c4c887

-----Decoded View---------------
Arg [0] : _universe (address): 0xcAe3fEC333BE0c5F4BfE932F5CafCC6F86c4c887

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000cae3fec333be0c5f4bfe932f5cafcc6f86c4c887


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
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.