ETH Price: $2,526.21 (+0.44%)

Contract

0xf70922C3a029AED3714DddeC2e0e3b085b349b41
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
0x60806040197995192024-05-04 21:47:23118 days ago1714859243IN
 Create: PayoutPursuit
0 ETH0.022908334.32889351

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
PayoutPursuit

Compiler Version
v0.8.20+commit.a1b79de6

Optimization Enabled:
Yes with 999 runs

Other Settings:
default evmVersion
File 1 of 12 : PayoutPursuit.sol
/**
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Copyright (c) 2024, PayoutPursuit | DRIFTToken
 *
 * DRIFT is the studio token behind the Drift studio. Drift is a Web3 game studio, which already has a ready-to-play Beta version of its game, Payout Pursuit.
 *
 * The DRIFT token has utility for gamers and non-gamers. Gamers that hold DRIFT will be able to customize their gaming experience with NFT skins and other features.
 * Non-gamers who stake DRIFT receive a percentage of game revenue, and the token also receives Liquidity from a percentage of game revenue.
 *
 * The Drift project has been developed by a highly experienced, fully doxxed Web3 team, with multiple successes in the Web3 space.
 *
 * Drift:
 * https://drifttoken.io/
 *
 * Influ3nce:
 * https://influ3nce.me/
 *
 * Amba$$ador:
 * https://influ3nce.me/ambassador/
 *
 * Twitter / X:
 * https://twitter.com/TheDriftToken
 *
 * Telegram:
 * https://t.me/driftportal
 *
 */

pragma solidity ^0.8.20;

import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {ReentrancyGuardUpgradeable} from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";
import {AggregatorV3Interface} from "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
import {PayoutPursuitTime} from "./extension/PayoutPursuitTime.sol";
import {PayoutPursuitPlayer} from "./extension/PayoutPursuitPlayer.sol";
import {SafeMath} from "@openzeppelin/contracts/utils/math/SafeMath.sol";
import {AllowableAddress} from "./utils/AllowableAddress.sol";
import {Utils} from "./utils/Utils.sol";

// Interface of Payout Pursuit NFT cars
interface IPayoutPursuitCars {
    function setupIdsForEvent(
        bytes32 _eventId,
        uint256 idDk,
        uint256 idT10,
        uint256 idT30
    ) external;

    function updateURI(uint256[] memory ids, string[] memory newuri) external;

    function mint(
        address account,
        uint256 id,
        uint256 amount,
        bytes memory data
    ) external;

    function getTokenPerEvent(bytes32 _eventId, uint8 _tier)
        external
        view
        returns (uint256);

    function uriPerEvent(bytes32 _eventId)
        external
        view
        returns (
            string memory driftKing,
            string memory top10,
            string memory top30
        );

    function removeAllIdsOfEvent(bytes32 _eventId) external;

    function balanceOf(address account, uint256 id)
        external
        view
        returns (uint256);
}

// Entry of Payout Pursuit Contract
contract PayoutPursuit is
    OwnableUpgradeable,
    AllowableAddress,
    PayoutPursuitTime,
    PayoutPursuitPlayer,
    ReentrancyGuardUpgradeable,
    Utils
{
    using SafeMath for uint256;

    enum EventStatus {
        PROGRESS,
        CANCELLED,
        COMPLETED
    }

    struct EventRound {
        bytes32 eventId;
        string eventName;
        string eventMap;
        uint256 entryFeesUsd;
        uint256 startTimestamp;
        uint256 endTimestamp;
        uint256 totalFeesRaised;
        uint256 totalFeesRaisedInUSD;
        EventStatus status;
    }

    struct RewardLocked {
        uint256 amount;
        uint256 deadline;
    }

    /* Variables */
    bool public initialized = false;
    string public version;

    address payable public feesWallet;
    AggregatorV3Interface public priceFeed;
    IPayoutPursuitCars public payoutPursuitNft;

    uint256 public eventNonce = 0;
    uint256 public minParticipants = 5; // Minimum participant required
    uint256 public claimDeadline = 30 days; // 1 month deadline; otherwise admin withdraw

    bytes32[] private allEvents;
    bytes32[] private activeEvents;

    uint256 private _additionalPoolAmount;
    uint256 private _totalFeesCollectedAllEvents;

    mapping(bytes32 => EventRound) private eventDetails;
    mapping(bytes32 => bool) public eventLeaderboardLocked;
    mapping(bytes32 => bool) public eventStoppedAndRefund;
    mapping(bytes32 => mapping(address => bool)) public eventClaims;
    mapping(bytes32 => mapping(PercentageDist => uint256))
        private rewardDistribution;
    mapping(PercentageDist => uint256) public percentage; // Percentages multiplication with 1000. (i.e. 7% = 7 * 1000 = 7000 OR 23.10% = 23.10 * 1000 = 23100)
    mapping(bytes32 => RewardLocked) public lockedReward;

    /* Modifiers */
    modifier isUserAlreadyNotEntered(bytes32 _currEventId) {
        require(
            !playerData[_currEventId][_msgSender()].userAccess,
            "PayoutPursuit: already registered for current event"
        );
        _;
    }

    /* Events */
    event EventStatusUpdated(
        bytes32 indexed eventId,
        string indexed status,
        uint256 timestamp
    );
    event TierPercentagesUpdated(
        uint256 percentageOfDriftking,
        uint256 percentageOfTop10,
        uint256 percentageOfTop30,
        uint256 percentageOfRev
    );
    event PriceFeedUpdated(address newPriceFeed);
    event FeesWalletUpdated(address newFeesWallet);
    event NFTAddressUpdated(address newNFTAddress);
    event DeadlineOfClaimUpdated(uint256 newDeadline);

    /* Constructor */
    /**
     * @notice Initialize Construction called from proxy initialization
     * @param _owner                        Owner Address
     * @param _feesWallet                   Fee Wallet Address
     * @param _priceFeed                    Price feed contract address by chain link
     * @param _payoutPursuitNftAddress      Payout Pursuit cars NFT contract address
     */
    function initialize(
        address _owner,
        address _feesWallet,
        address _priceFeed,
        address _payoutPursuitNftAddress
    ) external initializer {
        __Ownable_init(_owner);
        feesWallet = payable(_feesWallet);
        priceFeed = AggregatorV3Interface(_priceFeed);
        payoutPursuitNft = IPayoutPursuitCars(_payoutPursuitNftAddress);
        percentage[PercentageDist.DRIFTKING] = 28.00 * 1000;
        percentage[PercentageDist.TOP10] = 23.10 * 1000;
        percentage[PercentageDist.TOP30] = 18.90 * 1000;
        percentage[PercentageDist.REV] = 30.00 * 1000;

        eventNonce = 0;
        minParticipants = 5;
        claimDeadline = 30 days;

        version = "1";
        initialized = true;
    }

    /*
     * @notice fallback functions
     */
    receive() external payable {}

    fallback() external payable {}

    /**
     * @notice Internal callable function when player first time entered in event and paid fees and this function checks if the player send required wei to participate.
     * @param _eventId      Unique ID of event
     * @return {price in native and usd}
     */
    function isFeesOkay(bytes32 _eventId) internal returns (uint256, uint256) {
        uint256 priceNative = getPriceRate(_eventId);
        require(msg.value >= priceNative, "PayoutPursuit: invalid entry fees");
        _additionalPoolAmount += (msg.value - priceNative);
        _totalFeesCollectedAllEvents += priceNative;
        return (priceNative, eventDetails[_eventId].entryFeesUsd);
    }

    /**
     * @notice Internal callable function when create event. It generates unique ID for new event.
     * @return {new generated event ID}
     */
    function generateEventId() internal returns (bytes32) {
        bytes32 newEventId = bytes32(
            keccak256(abi.encodePacked(block.timestamp, eventNonce))
        );
        eventNonce++;
        return newEventId;
    }

    /**
     * @notice Create new event
     * @notice Accessable to only allowed address
     * @param _eventId              Unique ID of event if available, else empty and it generates a new unique event ID
     * @param _eventName            New event name
     * @param _eventMapName         Map name of new event
     * @param _entryFeesInUsd       Event entry fees in USD
     * @param _openingTime          Opening timestamp of Event
     * @param _closingTime          Closing timestamp of Event
     * @param _nftIdForDriftKing    Payout Pursuit car NFT ID for Drift King if available, zero otherwise
     * @param _nftIdFortop10        Payout Pursuit car NFT ID for Top 10% winners if available, zero otherwise
     * @param _nftIdFortop30        Payout Pursuit car NFT ID for Top 30% winners if available, zero otherwise
     */
    function createEvent(
        bytes32 _eventId,
        string memory _eventName,
        string memory _eventMapName,
        uint256 _entryFeesInUsd,
        uint256 _openingTime,
        uint256 _closingTime,
        uint256 _nftIdForDriftKing,
        uint256 _nftIdFortop10,
        uint256 _nftIdFortop30
    ) external onlyAllowedAddress nonReentrant returns (bool) {
        bytes32 raceEvent = _eventId > 0 ? _eventId : generateEventId();
        require(
            eventDetails[raceEvent].eventId == 0,
            "PayoutPursuit: event id already exists"
        );
        _newEvent(_openingTime, _closingTime, raceEvent);
        eventDetails[raceEvent] = EventRound({
            eventId: raceEvent,
            eventName: _eventName,
            eventMap: _eventMapName,
            entryFeesUsd: _entryFeesInUsd,
            startTimestamp: _openingTime,
            endTimestamp: _closingTime,
            totalFeesRaised: 0,
            totalFeesRaisedInUSD: 0,
            status: EventStatus.PROGRESS
        });
        activeEvents.push(raceEvent);
        allEvents.push(raceEvent);

        if (
            _nftIdForDriftKing != 0 ||
            _nftIdFortop10 != 0 ||
            _nftIdFortop30 != 0
        ) {
            payoutPursuitNft.setupIdsForEvent(
                raceEvent,
                _nftIdForDriftKing,
                _nftIdFortop10,
                _nftIdFortop30
            );
        }
        return true;
    }

    /**
     * @notice Update event
     * @notice Accessable to only allowed address
     * @param _entryFeesInUsd       Event entry fees in USD
     * @param _eventName            Event new name if needs update, empty otherwise
     * @param _eventMap             Map name of event if needs update, empty otherwise
     * @param _eventId              Existing unique ID of event
     */
    function updateEvent(
        uint256 _entryFeesInUsd,
        string memory _eventName,
        string memory _eventMap,
        bytes32 _eventId
    ) external onlyAllowedAddress nonReentrant {
        if (_entryFeesInUsd > 0) {
            eventDetails[_eventId].entryFeesUsd = _entryFeesInUsd;
        }
        if (!compareStrings(_eventName, "")) {
            eventDetails[_eventId].eventName = _eventName;
        }
        if (!compareStrings(_eventMap, "")) {
            eventDetails[_eventId].eventMap = _eventMap;
        }
    }

    /**
     * @notice Extend event time
     * @notice Accessable to only owner
     * @param _newClosingTime       New closing timestamp
     * @param _eventId              Existing unique ID of event
     */
    function extendEventTime(uint256 _newClosingTime, bytes32 _eventId)
        public
        onlyOwner
        nonReentrant
    {
        _extendEventTime(_newClosingTime, _eventId);
        eventDetails[_eventId].endTimestamp = _newClosingTime;
    }

    /**
     * @notice Cancel event if not
     * @notice Accessable to only owner
     * @param _refundToPlayers      Refund to players pass true, false otherwise
     * @param _eventId              Existing unique ID of event
     * @param _force                If true, no checking of minimum participants joined as well as no checking of already event closed and forcedly cancelled
     */
    function cancelEvent(
        bool _refundToPlayers,
        bytes32 _eventId,
        bool _force
    ) external onlyOwner nonReentrant {
        EventRound storage _eventDetails = eventDetails[_eventId];
        require(
            _eventDetails.status != EventStatus.CANCELLED,
            "PayoutPursuit: event already cancelled"
        );

        // Check if event already closed and no user has been participated
        if (getTotalPlayers(_eventId).length >= minParticipants && !_force) {
            require(!hasClosed(_eventId), "PayoutPursuitTime: already closed");
        }
        _cancelEvent(_eventId);
        _eventDetails.endTimestamp = closingTime(_eventId);
        _eventDetails.status = EventStatus.CANCELLED;

        if (_refundToPlayers) {
            lockedReward[_eventId] = RewardLocked({
                amount: _eventDetails.totalFeesRaised,
                deadline: block.timestamp + claimDeadline
            });

            eventStoppedAndRefund[_eventId] = _refundToPlayers;
        }

        payoutPursuitNft.removeAllIdsOfEvent(_eventId);

        emit EventStatusUpdated(_eventId, "CANCELLED", block.timestamp);
    }

    /**
     * @notice Pause event if open and not already paused
     * @notice Accessable to only owner
     * @param _eventId              Existing unique ID of event
     */
    function pauseEvent(bytes32 _eventId)
        external
        onlyOwner
        onlyWhileOpen(_eventId)
        nonReentrant
    {
        _pauseEvent(_eventId);

        emit EventStatusUpdated(_eventId, "PAUSED", block.timestamp);
    }

    /**
     * @notice Resume event if already paused
     * @notice Accessable to only owner
     * @param _eventId              Existing unique ID of event
     * @param _newClosingTime       New closing timestamp if needs to extend, zero otherwise
     */
    function unpauseEvent(bytes32 _eventId, uint256 _newClosingTime)
        external
        onlyOwner
        nonReentrant
    {
        if (_newClosingTime != 0) {
            extendEventTime(_newClosingTime, _eventId);
        }
        _unpauseEvent(_eventId);

        emit EventStatusUpdated(_eventId, "ACTIVE", block.timestamp);
    }

    /**
     * @notice Participate in event by entry and pay fees.
     * @param _eventId              Existing unique ID of event
     */
    function entryInEvent(bytes32 _eventId)
        external
        payable
        onlyWhileOpen(_eventId)
        isEventPaused(_eventId)
        isUserAlreadyNotEntered(_eventId)
        nonReentrant
    {
        (uint256 feesNative, uint256 feesUsd) = isFeesOkay(_eventId);
        eventDetails[_eventId].totalFeesRaised += feesNative;
        eventDetails[_eventId].totalFeesRaisedInUSD += feesUsd;
        _playerEntered(
            _eventId,
            _msgSender(),
            block.timestamp,
            feesNative,
            feesUsd
        );
    }

    /**
     * @notice Submit user addresses when event completed.
     * @notice Accessable to only owner
     * @param _eventId          Existing unique ID of event
     * @param _playerDK         Array of addresses of Drift King if multiple rarely, otherwise only one address i.e Just ONE Drift King
     * @param _playersTop10     Array of addresses of Top 10% winners
     * @param _playersTop30     Array of addresses of Top 30% winners
     * @param isLocked          True if submission is final and verified and should lock for permanent, false otherwise
     */
    function submitUsersData(
        bytes32 _eventId,
        address[] memory _playerDK,
        address[] memory _playersTop10,
        address[] memory _playersTop30,
        bool isLocked
    )
        external
        onlyOwner
        nonReentrant
        onlyWhenClosed(_eventId)
        returns (bytes[] memory x)
    {
        require(
            !eventLeaderboardLocked[_eventId],
            "PayoutPursuit: event leaderboard locked"
        );
        require(
            _eventId != 0 && eventDetails[_eventId].eventId != 0,
            "PayoutPursuit: event id invalid"
        );
        {
            bytes[] memory y = new bytes[](3);
            y[0] = encode(_eventId, PercentageDist.DRIFTKING, _playerDK);
            y[1] = encode(_eventId, PercentageDist.TOP10, _playersTop10);
            y[2] = encode(_eventId, PercentageDist.TOP30, _playersTop30);
            x = y;
        }
        _removeFromArray(activeEvents, _eventId);
        eventDetails[_eventId].status = EventStatus.COMPLETED;

        emit EventStatusUpdated(_eventId, "COMPLETED", block.timestamp);

        if (isLocked) {
            lockLeaderboard(_eventId);
        }
    }

    /**
     * @notice Lock leaderboard of completed event if not already locked and data already submitted.
     * @notice Accessable to only owner
     * @param _eventId      Existing unique ID of event
     */
    function lockLeaderboard(bytes32 _eventId) public onlyOwner {
        (
            address[] memory _playersTop10,
            address[] memory _playersTop30,
            address[] memory _playerDK
        ) = getUsersData(_eventId);

        require(
            (_playersTop10.length > 0 || _playersTop30.length > 0) &&
                _playerDK.length > 0,
            "PayoutPursuit: leaderboard not found"
        );

        eventLeaderboardLocked[_eventId] = true;

        uint256 _totalFeesRaised = eventDetails[_eventId].totalFeesRaised;
        uint256 _eventRev = (_totalFeesRaised *
            percentage[PercentageDist.REV]) / 10**5;
        rewardDistribution[_eventId][PercentageDist.DRIFTKING] =
            (_totalFeesRaised * percentage[PercentageDist.DRIFTKING]) /
            10**5;
        rewardDistribution[_eventId][PercentageDist.TOP10] = _playersTop10
            .length > 0
            ? ((_totalFeesRaised * percentage[PercentageDist.TOP10]) / 10**5) /
                _playersTop10.length
            : 0;
        rewardDistribution[_eventId][PercentageDist.TOP30] = _playersTop30
            .length > 0
            ? ((_totalFeesRaised * percentage[PercentageDist.TOP30]) / 10**5) /
                _playersTop30.length
            : 0;
        lockedReward[_eventId] = RewardLocked({
            amount: _totalFeesRaised - _eventRev,
            deadline: block.timestamp + claimDeadline
        });
        _transferNative(feesWallet, _eventRev);
    }

    /**
     * @notice Claim refund of cancelled event by the participants if available
     * @param _eventId          Existing unique ID of event
     */
    function claimRefund(bytes32 _eventId) external nonReentrant {
        require(
            eventStoppedAndRefund[_eventId] &&
                block.timestamp <= lockedReward[_eventId].deadline,
            "PayoutPursuit: no refunds available"
        );
        require(
            !eventClaims[_eventId][_msgSender()],
            "PayoutPursuit: already claimed"
        );
        PlayerData memory _playerData = playerData[_eventId][_msgSender()];
        require(
            _playerData.userAccess &&
                _playerData.player == _msgSender() &&
                _playerData.player != address(0),
            "PayoutPursuit: invalid address"
        );

        eventClaims[_eventId][_msgSender()] = true;

        uint256 _refundAmount = min(
            _playerData.feesPaidInNative,
            address(this).balance
        );

        lockedReward[_eventId].amount -= _refundAmount;

        require(
            _refundAmount > 0,
            "PayoutPursuit: insufficient funds, please contact support"
        );

        _transferNative(_msgSender(), _refundAmount);
    }

    /**
     * @notice Internally called function from "isRewardAvailable"
     * @param _eventId      Existing unique ID of event
     * @param _per          Tier of players (0 for DRIFTKING, 1 for TOP10, 2 for TOP30)
     * @return  {Per player reward}
     */
    function playerRewardCalculation(bytes32 _eventId, PercentageDist _per)
        internal
        view
        returns (uint256)
    {
        return rewardDistribution[_eventId][_per];
    }

    /**
     * @notice Claim reward by participant if wins and claim available
     * @param _eventId      Existing unique ID of event
     */
    function claimReward(bytes32 _eventId)
        external
        nonReentrant
        onlyWhenClosed(_eventId)
    {
        require(
            !eventClaims[_eventId][_msgSender()],
            "PayoutPursuit: already claimed"
        );

        PlayerData storage _playerData = playerData[_eventId][_msgSender()];

        uint256 calculatedReward = 0;
        PercentageDist rank = PercentageDist.NONE;

        if (lockedReward[_eventId].deadline >= block.timestamp) {
            (
                uint256 _calculatedReward,
                PercentageDist _rank,

            ) = isRewardAvailable(_eventId, _msgSender());

            calculatedReward = _calculatedReward;
            rank = _rank;
        }

        require(
            calculatedReward > 0,
            "PayoutPursuit: no claim available or already claimed"
        );

        eventClaims[_eventId][_msgSender()] = true;

        _playerData.claimTimestamp = block.timestamp;
        _playerData.rank = rank;
        _playerData.player = _msgSender();

        uint256 reward = min(calculatedReward, address(this).balance);

        lockedReward[_eventId].amount -= reward;

        if (rank != PercentageDist.NONE) {
            uint256 _nftId = payoutPursuitNft.getTokenPerEvent(
                _eventId,
                uint8(rank)
            );
            if (payoutPursuitNft.balanceOf(_msgSender(), _nftId) == 0) {
                payoutPursuitNft.mint(_msgSender(), _nftId, 1, "");
            }
        }

        require(
            reward > 0,
            "PayoutPursuit: insufficient funds, please contact support"
        );

        _transferNative(_msgSender(), reward);
    }

    /**
     * @notice Check if reward available for participant
     * @param _eventId      Existing unique ID of event
     * @param _user         Address of Participant
     * @return {Amount, Tier, true if already claimed otherwise false}
     */
    function isRewardAvailable(bytes32 _eventId, address _user)
        public
        view
        returns (
            uint256,
            PercentageDist,
            bool
        )
    {
        (
            address[] memory _playersTop10,
            address[] memory _playersTop30,
            address[] memory _playerDK
        ) = getUsersData(_eventId);

        address _playerData;
        PercentageDist _per = PercentageDist.NONE;

        if (_playerDK.length > 0) {
            for (uint8 i = 0; i < _playerDK.length; i++) {
                if (_playerDK[i] == _user) {
                    _playerData = _playerDK[i];
                    _per = PercentageDist.DRIFTKING;
                    break;
                }
            }
        }

        if (_per == PercentageDist.NONE) {
            for (uint256 j = 0; j < _playersTop10.length; j++) {
                if (_playersTop10[j] == _user) {
                    _playerData = _playersTop10[j];
                    _per = PercentageDist.TOP10;
                    break;
                }
            }
        }

        if (_per == PercentageDist.NONE) {
            for (uint256 k = 0; k < _playersTop30.length; k++) {
                if (_playersTop30[k] == _user) {
                    _playerData = _playersTop30[k];
                    _per = PercentageDist.TOP30;
                    break;
                }
            }
        }

        if (_per == PercentageDist.NONE) {
            return (0, _per, false);
        }

        return (
            min(
                playerRewardCalculation(_eventId, _per),
                lockedReward[_eventId].amount
            ),
            _per,
            eventClaims[_eventId][_user]
        );
    }

    /**
     * @notice Update percentages of Tiers (in multiplication with 1000)
     * @notice Accessable to only owner
     * @param _driftking    Percentage for Drift King Tier
     * @param _top10        Percentage for Top 10% Tier
     * @param _top30        Percentage for Top 30% Tier
     * @param _rev          Percentage for Platform revenue Tier
     */
    function updatePercentages(
        uint256 _driftking,
        uint256 _top10,
        uint256 _top30,
        uint256 _rev
    ) external onlyOwner {
        percentage[PercentageDist.DRIFTKING] = _driftking;
        percentage[PercentageDist.TOP10] = _top10;
        percentage[PercentageDist.TOP30] = _top30;
        percentage[PercentageDist.REV] = _rev;
        emit TierPercentagesUpdated(_driftking, _top10, _top30, _rev);
    }

    /**
     * @notice Update price feed address of chain link
     * @notice Accessable to only owner
     * @param _priceFeed    New address of Price Feed
     */
    function updatePriceFeed(address _priceFeed) external onlyOwner {
        priceFeed = AggregatorV3Interface(_priceFeed);
        emit PriceFeedUpdated(_priceFeed);
    }

    /**
     * @notice Update fees wallet address
     * @notice Accessable to only owner
     * @param _feesWallet    New address of Fees wallet
     */
    function updateFeesWallet(address _feesWallet) external onlyOwner {
        feesWallet = payable(_feesWallet);
        emit FeesWalletUpdated(_feesWallet);
    }

    /**
     * @notice Update NFT contract address
     * @notice Accessable to only owner
     * @param _payoutPursuitNft    New address of NFT contract
     */
    function updatePayoutPursuitNftAddress(address _payoutPursuitNft)
        external
        onlyOwner
    {
        payoutPursuitNft = IPayoutPursuitCars(_payoutPursuitNft);
        emit NFTAddressUpdated(_payoutPursuitNft);
    }

    /**
     * @notice Update claim deadline in days
     * @notice Accessable to only owner
     * @param _newDeadlineInDays    New deadline in days
     */
    function updateClaimDeadline(uint256 _newDeadlineInDays) external onlyOwner {
        claimDeadline = _newDeadlineInDays * 1 days;
        emit DeadlineOfClaimUpdated(_newDeadlineInDays);
    }

    /**
     * @notice Get submitted data of addresses of completed events
     * @param _eventId      Existing unique ID of event
     * @return top10        Addresses of Top 10% winners
     * @return top30        Addresses of Top 30% winners
     * @return dk           Address(es) of Drift King
     */
    function getUsersData(bytes32 _eventId)
        public
        view
        returns (
            address[] memory top10,
            address[] memory top30,
            address[] memory dk
        )
    {
        bytes[] memory _encodedData1 = encodeData[_eventId][
            PercentageDist.DRIFTKING
        ];
        bytes[] memory _encodedData2 = encodeData[_eventId][
            PercentageDist.TOP10
        ];
        bytes[] memory _encodedData3 = encodeData[_eventId][
            PercentageDist.TOP30
        ];
        if (_encodedData1.length > 0) {
            dk = decode(
                _eventId,
                PercentageDist.DRIFTKING,
                _encodedData1[_encodedData1.length - 1]
            );
        }
        if (_encodedData2.length > 0) {
            top10 = decode(
                _eventId,
                PercentageDist.TOP10,
                _encodedData2[_encodedData2.length - 1]
            );
        }
        if (_encodedData3.length > 0) {
            top30 = decode(
                _eventId,
                PercentageDist.TOP30,
                _encodedData3[_encodedData3.length - 1]
            );
        }
    }

    /**
     * @notice Get all event IDs that ever created
     * @return x    All IDs of events
     */
    function getAllEvents() external view returns (bytes32[] memory x) {
        return allEvents;
    }

    /**
     * @notice Get all active event IDs
     * @return x    All IDs of active events
     */
    function getActiveEvents() external view returns (bytes32[] memory x) {
        x = new bytes32[](activeEvents.length);
        uint256 _index = 0;
        bool _isClosed = false;
        for (uint8 i = 0; i < activeEvents.length; i++) {
            if (isEventOpen(activeEvents[i])) {
                x[_index] = activeEvents[i];
                _index++;
            } else {
                _isClosed = true;
            }
        }

        if (_isClosed) {
            bytes32[] memory _temp = new bytes32[](_index);
            for (uint8 j = 0; j < _index; j++) {
                _temp[j] = x[j];
            }
            x = _temp;
        }
    }

    /**
     * @notice Get all inactive event IDs
     * @return completed    All IDs of completed events
     * @return cancelled    All IDs of cancelled events
     * @return paused       All IDs of paused events
     * @return pending      All IDs of events that will active soon
     * @return process      All IDs of events that closed and leaderboard submission is pending
     */
    function getInactiveEvents()
        external
        view
        returns (
            bytes32[] memory completed,
            bytes32[] memory cancelled,
            bytes32[] memory paused,
            bytes32[] memory pending,
            bytes32[] memory process
        )
    {
        bytes32[] memory tempCompleted = new bytes32[](allEvents.length);
        bytes32[] memory tempCancelled = new bytes32[](allEvents.length);
        bytes32[] memory tempPaused = new bytes32[](allEvents.length);
        bytes32[] memory tempPending = new bytes32[](allEvents.length);
        bytes32[] memory tempProcess = new bytes32[](allEvents.length);
        {
            uint256 completedCount;
            uint256 cancelledCount;
            uint256 pausedCount;
            uint256 pendingCount;
            uint256 processCount;

            for (uint8 i = 0; i < allEvents.length; i++) {
                bytes32 v = allEvents[i];
                if (eventDetails[v].status == EventStatus.COMPLETED) {
                    tempCompleted[completedCount++] = v;
                }
                if (eventDetails[v].status == EventStatus.CANCELLED) {
                    tempCancelled[cancelledCount++] = v;
                }
                if (
                    eventPaused[v] &&
                    eventDetails[v].status == EventStatus.PROGRESS
                ) {
                    tempPaused[pausedCount++] = v;
                }
                if (
                    openingTime(v) > block.timestamp &&
                    eventDetails[v].status == EventStatus.PROGRESS
                ) {
                    tempPending[pendingCount++] = v;
                }
                if (
                    hasClosed(v) &&
                    eventDetails[v].status == EventStatus.PROGRESS
                ) {
                    tempProcess[processCount++] = v;
                }
            }

            completed = new bytes32[](completedCount);
            cancelled = new bytes32[](cancelledCount);
            paused = new bytes32[](pausedCount);
            pending = new bytes32[](pendingCount);
            process = new bytes32[](processCount);
        }

        for (uint256 j = 0; j < completed.length; j++) {
            completed[j] = tempCompleted[j];
        }
        for (uint256 k = 0; k < cancelled.length; k++) {
            cancelled[k] = tempCancelled[k];
        }
        for (uint256 l = 0; l < paused.length; l++) {
            paused[l] = tempPaused[l];
        }
        for (uint256 m = 0; m < pending.length; m++) {
            pending[m] = tempPending[m];
        }
        for (uint256 n = 0; n < process.length; n++) {
            process[n] = tempProcess[n];
        }
    }

    /**
     * @notice Get detail about event
     * @param _eventId                  Existing unique ID of event
     * @return eventId                  Event ID
     * @return eventName                Name of event
     * @return eventMap                 Name of event map
     * @return entryFeesUsd             Entry fees in USD
     * @return startTimestamp           Event start time
     * @return endTimestamp             Event end time
     * @return totalFeesRaised          Total fees raised in event
     * @return totalFeesRaisedInUSD     Total fees raised in event in USD
     * @return status                   Current status of event
     * @return nftUri                   URI of all NFTs of event
     */
    function getEventDetails(bytes32 _eventId)
        public
        view
        returns (
            bytes32 eventId,
            string memory eventName,
            string memory eventMap,
            uint256 entryFeesUsd,
            uint256 startTimestamp,
            uint256 endTimestamp,
            uint256 totalFeesRaised,
            uint256 totalFeesRaisedInUSD,
            string memory status,
            string[] memory nftUri
        )
    {
        EventRound memory _event = eventDetails[_eventId];
        string memory _eventStatus;
        if (_event.status == EventStatus.PROGRESS) {
            _eventStatus = "ACTIVE";
            if (_event.startTimestamp == 0) {
                _eventStatus = "NOTEXIST";
            } else if (eventPaused[_eventId]) {
                _eventStatus = "PAUSED";
            } else if (openingTime(_eventId) > block.timestamp) {
                _eventStatus = "PENDING";
            } else if (hasClosed(_eventId)) {
                _eventStatus = "PROCESS";
            }
        } else if (_event.status == EventStatus.COMPLETED) {
            _eventStatus = "COMPLETED";
        } else if (_event.status == EventStatus.CANCELLED) {
            _eventStatus = "CANCELLED";
        }

        string[] memory _uris = new string[](3);
        (_uris[0], _uris[1], _uris[2]) = payoutPursuitNft.uriPerEvent(_eventId);

        return (
            _event.eventId,
            _event.eventName,
            _event.eventMap,
            _event.entryFeesUsd,
            _event.startTimestamp,
            _event.endTimestamp,
            _event.totalFeesRaised,
            _event.totalFeesRaisedInUSD,
            _eventStatus,
            _uris
        );
    }

    /**
     * @notice Get Native value from USD
     * @param _amount       Amount in USD
     * @return {amount in native}
     */
    function getPriceUsdToNative(uint256 _amount)
        public
        view
        returns (uint256)
    {
        (, int256 price, , , ) = priceFeed.latestRoundData();
        uint256 adjust_price = uint256(price) * 1e10;
        uint256 usd = _amount;
        uint256 rate = (usd * 1e18) / adjust_price;
        return rate;
    }

    /**
     * @notice Get event fees rate in native from USD
     * @param _eventId      Existing unique ID of event
     * @return {event fees in native}
     */
    function getPriceRate(bytes32 _eventId) public view returns (uint256) {
        uint256 feeInUSD = eventDetails[_eventId].entryFeesUsd;
        uint256 rate = getPriceUsdToNative(feeInUSD);
        return rate;
    }

    /**
     * @notice Deposit Reward to Pool for winners
     * @notice Accessable to only owner
     * @param _amount       Amount in wei
     * @param _eventId      Existing unique ID of event
     * @return {True or False}
     */
    function depositToRewardPool(uint256 _amount, bytes32 _eventId)
        public
        payable
        onlyOwner
        returns (bool)
    {
        require(
            eventDetails[_eventId].startTimestamp != 0,
            "PayoutPursuit: invalid event id"
        );
        require(msg.value >= _amount, "PayoutPursuit: insufficient amount");
        _additionalPoolAmount += (msg.value - _amount);
        _totalFeesCollectedAllEvents += _amount;
        eventDetails[_eventId].totalFeesRaised += _amount;
        return true;
    }

    /**
     * @notice Withdraw funds if available
     * @notice Accessable to only owner
     * @param _eventId      Existing unique ID of event
     */
    function withdrawFunds(bytes32 _eventId) public onlyOwner {
        // Admin can withdraw funds if winners not claimed within 1 month
        require(
            block.timestamp >= lockedReward[_eventId].deadline,
            "PayoutPursuit: event rewards locked for winners to claim"
        );
        _transferNative(
            feesWallet,
            min(lockedReward[_eventId].amount, address(this).balance)
        );
    }

    /**
     * @notice Withdraw other funds if available
     * @notice Accessable to only owner
     * @param _token    Token address or (zero address for Native)
     */
    function withdrawAdditionalFunds(address _token) public onlyOwner {
        if (_token != address(0)) {
            uint256 _balance = IERC20(_token).balanceOf(address(this));
            require(
                _balance > 0,
                "PayoutPursuit: insufficient contract balance"
            );
            require(IERC20(_token).transfer(feesWallet, _balance));
        } else {
            require(
                address(this).balance > 0,
                "PayoutPursuit: insufficient additional contract balance"
            );
            _transferNative(
                feesWallet,
                min(_additionalPoolAmount, address(this).balance)
            );
            _additionalPoolAmount = 0;
        }
    }

    /**
     * @notice Internally called when transferring native amounts
     * @param _recipient    Recipient address
     * @param _amount       Amount in wei
     */
    function _transferNative(address _recipient, uint256 _amount) internal {
        (bool sent, ) = payable(_recipient).call{value: _amount}("");
        require(sent);
    }
}

File 2 of 12 : Utils.sol
/**
 * SPDX-License-Identifier: Apache-2.0
 *
 * Copyright (c) 2023, DriftToken | DecentraCrew.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

pragma solidity ^0.8.9;

contract Utils {

    /**
     * @notice Helper function to find the minimum of two values.
     * @param a     Number 1
     * @param b     Number 2
     * @return {Minimum number} 
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @notice Helper internal function to remove specific value from an array
     * @param _data     Array data
     * @param _target   Item to find in array and remove
     */
    function _removeFromArray(bytes32[] storage _data, bytes32 _target)
        internal
    {
        if (_data.length > 0) {
            uint256 index = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff;
            uint256 i = 0;
            uint256 j = _data.length - 1;
            while (i <= j) {
                if (_data[i] == _target) {
                    index = i;
                    break;
                }
                if (_data[j] == _target) {
                    index = j;
                    break;
                }
                i++;
                j--;
            }
            if (
                index !=
                0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
            ) {
                _data[index] = _data[_data.length - 1];
                _data.pop();
            }
        }
    }

    /**
     * @notice Implementation of comparision of strings.
     * @param s1    String 1
     * @param s2    String 2
     * @return {True or False}
     */
    function compareStrings(string memory s1, string memory s2)
        internal
        pure
        returns (bool)
    {
        return
            keccak256(abi.encodePacked(s1)) == keccak256(abi.encodePacked(s2));
    }
}

File 3 of 12 : AllowableAddress.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";

contract AllowableAddress is OwnableUpgradeable {
    /******* Variables *******/
    // allowed address => bool
    mapping(address => bool) private allowedAddress;
    // blacklist address => bool
    mapping(address => bool) private blacklistAddress;

    /******* Modifiers *******/
    modifier onlyAllowedAddress() {
        require(
            allowedAddress[_msgSender()] == true ||
                owner() == _msgSender(),
            "You are not allowed."
        );
        _;
    }

    modifier blacklistCheck() {
        require(!blacklistAddress[_msgSender()], "Address is blacklisted");
        _;
    }

    /******* Events *******/
    event BlacklistUpdated(bool status);

    /******* Constructor *******/
    function __AllowableAddress_init(address _ownerAddress) internal {
        __Ownable_init(_ownerAddress);
    }

    /**
     * @notice Disallow the address and remove from onlyAllowedAddress
     * @param _address  Any address
     */
    function disallowAddress(address _address) public onlyOwner {
        require(
            allowedAddress[_address] == true,
            "The address is already not allowed."
        );
        allowedAddress[_address] = true;
    }

    /**
     * @notice Allow the address and add to onlyAllowedAddress
     * @param _address  Any address
     */
    function allowAddress(address _address) public onlyOwner {
        require(
            allowedAddress[_address] == false,
            "The address is already allowed."
        );
        allowedAddress[_address] = true;
    }

    /**
     * @notice Manage blacklisting to restrict addresses
     * @param addresses     Any addresses
     * @param status        true or false
     */
    function manageBlacklist(address[] calldata addresses, bool status)
        external
        virtual
        onlyAllowedAddress
    {
        for (uint256 i; i < addresses.length; ++i) {
            blacklistAddress[addresses[i]] = status;
        }
        emit BlacklistUpdated(status);
    }

    /**
     * @param _address  Any address
     * @return {The address is allowed or not allowed}
     */
    function isAddressAllowed(address _address) public view returns (bool) {
        return allowedAddress[_address];
    }

    /**
     * @param _address  Any address
     * @return {The address is blacklisted or not}
     */
    function isBlacklisted(address _address) public view returns (bool) {
        return blacklistAddress[_address];
    }
}

File 4 of 12 : SafeMath.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/SafeMath.sol)

pragma solidity ^0.8.0;

// CAUTION
// This version of SafeMath should only be used with Solidity 0.8 or later,
// because it relies on the compiler's built in overflow checks.

/**
 * @dev Wrappers over Solidity's arithmetic operations.
 *
 * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler
 * now has built in overflow checking.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            uint256 c = a + b;
            if (c < a) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b > a) return (false, 0);
            return (true, a - b);
        }
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
            // benefit is lost if 'b' is also tested.
            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
            if (a == 0) return (true, 0);
            uint256 c = a * b;
            if (c / a != b) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a / b);
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a % b);
        }
    }

    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        return a + b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return a - b;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        return a * b;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator.
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        return a % b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {trySub}.
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        unchecked {
            require(b <= a, errorMessage);
            return a - b;
        }
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        unchecked {
            require(b > 0, errorMessage);
            return a / b;
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting with custom message when dividing by zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryMod}.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        unchecked {
            require(b > 0, errorMessage);
            return a % b;
        }
    }
}

File 5 of 12 : PayoutPursuitPlayer.sol
/**
 * SPDX-License-Identifier: Apache-2.0
 *
 * Copyright (c) 2024, DriftToken
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

pragma solidity ^0.8.20;

abstract contract PayoutPursuitPlayer {
    enum PercentageDist {
        DRIFTKING,
        TOP10,
        TOP30,
        REV,
        NONE
    }

    struct PlayerData {
        address player;
        PercentageDist rank;
        uint256 feesPaidInNative;
        uint256 feesPaidInUsd;
        uint256 eventRegisterTimestamp;
        uint256 claimTimestamp;
        bool userAccess;
    }

    mapping(bytes32 => mapping(address => PlayerData)) public playerData;
    mapping(bytes32 => address[]) private totalPlayers;
    mapping(bytes32 => mapping(PercentageDist => bytes[])) internal encodeData;

    event PlayerEntry(
        bytes32 indexed currEvent,
        address indexed player,
        uint256 regTimestamp
    );

    function _playerEntered(
        bytes32 _eventId,
        address _player,
        uint256 _regTimestamp,
        uint256 _feesNative,
        uint256 _feesUsd
    ) internal {
        playerData[_eventId][_player] = PlayerData({
            player: _player,
            rank: PercentageDist.NONE,
            feesPaidInNative: _feesNative,
            feesPaidInUsd: _feesUsd,
            eventRegisterTimestamp: _regTimestamp,
            claimTimestamp: 0,
            userAccess: true
        });
        totalPlayers[_eventId].push(_player);
        emit PlayerEntry(_eventId, _player, _regTimestamp);
    }

    function encode(
        bytes32 _eventId,
        PercentageDist _percent,
        address[] memory x
    ) internal returns (bytes memory) {
        bytes memory encoded = abi.encode(x);
        encodeData[_eventId][_percent].push(encoded);
        return encoded;
    }

    function decode(
        bytes32 _eventId,
        PercentageDist _percent,
        bytes memory _encodedData
    ) internal view returns (address[] memory x) {
        if (encodeData[_eventId][_percent].length > 0) {
            bytes memory _data = encodeData[_eventId][_percent][
                encodeData[_eventId][_percent].length - 1
            ];
            if (_encodedData.length > 0) {
                _data = _encodedData;
            }
            (x) = abi.decode(_data, (address[]));
        }
    }

    function getTotalPlayers(bytes32 _eventId)
        public
        view
        returns (address[] memory players)
    {
        players = totalPlayers[_eventId];
    }
}

File 6 of 12 : PayoutPursuitTime.sol
/**
 * SPDX-License-Identifier: Apache-2.0
 *
 * Copyright (c) 2024, DriftToken
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

pragma solidity ^0.8.20;

abstract contract PayoutPursuitTime {
    mapping(bytes32 => uint256) private _openingTime;
    mapping(bytes32 => uint256) private _closingTime;
    mapping(bytes32 => bool) public eventPaused;

    event EventTimeExtended(uint256 prevClosingTime, uint256 newClosingTime);
    event NewEvent(uint256 newOpeningTime, uint256 newClosingTime);
    event CancelEvent(uint256 closingTime);
    event EventPaused(bytes32 eventId);
    event EventUnpaused(bytes32 eventId);

    modifier onlyWhileOpen(bytes32 _eventId) {
        require(isOpen(_eventId), "PayoutPursuitTime: not open");
        _;
    }

    modifier onlyWhenClosed(bytes32 _eventId) {
        require(hasClosed(_eventId), "PayoutPursuitTime: event in progress");
        _;
    }

    modifier isEventPaused(bytes32 _eventId) {
        require(!eventPaused[_eventId], "PayoutPursuitTime: event is paused");
        _;
    }

    function openingTime(bytes32 _eventId) public view returns (uint256) {
        return _openingTime[_eventId];
    }

    function closingTime(bytes32 _eventId) public view returns (uint256) {
        return _closingTime[_eventId];
    }

    function isOpen(bytes32 _eventId) internal view returns (bool) {
        return
            block.timestamp >= _openingTime[_eventId] &&
            block.timestamp <= _closingTime[_eventId];
    }

    function hasClosed(bytes32 _eventId) public view returns (bool) {
        return block.timestamp > _closingTime[_eventId] && _closingTime[_eventId] != 0;
    }

    function _extendEventTime(uint256 newClosingTime, bytes32 _eventId)
        internal
    {
        require(!hasClosed(_eventId) || eventPaused[_eventId], "PayoutPursuitTime: already closed");
        require(
            newClosingTime > _closingTime[_eventId],
            "PayoutPursuitTime: new closing time is before current closing time"
        );

        emit EventTimeExtended(_closingTime[_eventId], newClosingTime);
        _closingTime[_eventId] = newClosingTime;
    }

    function _newEvent(
        uint256 newOpeningTime,
        uint256 newClosingTime,
        bytes32 _eventId
    ) internal {
        require(
            newOpeningTime >= block.timestamp,
            "PayoutPursuitTime: opening time is before current time"
        );
        require(
            newClosingTime > newOpeningTime,
            "PayoutPursuitTime: closing time is before opening time"
        );

        emit NewEvent(newOpeningTime, newClosingTime);
        _openingTime[_eventId] = newOpeningTime;
        _closingTime[_eventId] = newClosingTime;
    }

    function _cancelEvent(bytes32 _eventId) internal {
        uint256 currentTimestamp = block.timestamp;
        emit CancelEvent(currentTimestamp);
        _closingTime[_eventId] = currentTimestamp;
    }

    function _pauseEvent(bytes32 _eventId)
        internal
        onlyWhileOpen(_eventId)
    {
        eventPaused[_eventId] = true;
        emit EventPaused(_eventId);
    }

    function _unpauseEvent(bytes32 _eventId)
        internal
    {
        eventPaused[_eventId] = false;
        emit EventUnpaused(_eventId);
    }

    function isEventOpen(bytes32 _eventId) public view returns (bool) {
        return isOpen(_eventId) && !eventPaused[_eventId];
    }
}

File 7 of 12 : AggregatorV3Interface.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface AggregatorV3Interface {
  function decimals() external view returns (uint8);

  function description() external view returns (string memory);

  function version() external view returns (uint256);

  function getRoundData(
    uint80 _roundId
  ) external view returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);

  function latestRoundData()
    external
    view
    returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);
}

File 8 of 12 : ReentrancyGuardUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)

pragma solidity ^0.8.0;
import {Initializable} from "../proxy/utils/Initializable.sol";

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuardUpgradeable is Initializable {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    function __ReentrancyGuard_init() internal onlyInitializing {
        __ReentrancyGuard_init_unchained();
    }

    function __ReentrancyGuard_init_unchained() internal onlyInitializing {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    function _nonReentrantBefore() private {
        // On the first call to nonReentrant, _status will be _NOT_ENTERED
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        // Any calls to nonReentrant after this point will fail
        _status = _ENTERED;
    }

    function _nonReentrantAfter() private {
        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
     * `nonReentrant` function in the call stack.
     */
    function _reentrancyGuardEntered() internal view returns (bool) {
        return _status == _ENTERED;
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[49] private __gap;
}

File 9 of 12 : OwnableUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)

pragma solidity ^0.8.20;

import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * The initial owner is set to the address provided by the deployer. This can
 * later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
    /// @custom:storage-location erc7201:openzeppelin.storage.Ownable
    struct OwnableStorage {
        address _owner;
    }

    // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Ownable")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant OwnableStorageLocation = 0x9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300;

    function _getOwnableStorage() private pure returns (OwnableStorage storage $) {
        assembly {
            $.slot := OwnableStorageLocation
        }
    }

    /**
     * @dev The caller account is not authorized to perform an operation.
     */
    error OwnableUnauthorizedAccount(address account);

    /**
     * @dev The owner is not a valid owner account. (eg. `address(0)`)
     */
    error OwnableInvalidOwner(address owner);

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
     */
    function __Ownable_init(address initialOwner) internal onlyInitializing {
        __Ownable_init_unchained(initialOwner);
    }

    function __Ownable_init_unchained(address initialOwner) internal onlyInitializing {
        if (initialOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(initialOwner);
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        OwnableStorage storage $ = _getOwnableStorage();
        return $._owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        if (owner() != _msgSender()) {
            revert OwnableUnauthorizedAccount(_msgSender());
        }
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby disabling any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        if (newOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        OwnableStorage storage $ = _getOwnableStorage();
        address oldOwner = $._owner;
        $._owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

File 10 of 12 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
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);
}

File 11 of 12 : Initializable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)

pragma solidity ^0.8.20;

/**
 * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
 * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
 * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
 * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
 *
 * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
 * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
 * case an upgrade adds a module that needs to be initialized.
 *
 * For example:
 *
 * [.hljs-theme-light.nopadding]
 * ```solidity
 * contract MyToken is ERC20Upgradeable {
 *     function initialize() initializer public {
 *         __ERC20_init("MyToken", "MTK");
 *     }
 * }
 *
 * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
 *     function initializeV2() reinitializer(2) public {
 *         __ERC20Permit_init("MyToken");
 *     }
 * }
 * ```
 *
 * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
 * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
 *
 * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
 * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
 *
 * [CAUTION]
 * ====
 * Avoid leaving a contract uninitialized.
 *
 * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
 * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
 * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * /// @custom:oz-upgrades-unsafe-allow constructor
 * constructor() {
 *     _disableInitializers();
 * }
 * ```
 * ====
 */
abstract contract Initializable {
    /**
     * @dev Storage of the initializable contract.
     *
     * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
     * when using with upgradeable contracts.
     *
     * @custom:storage-location erc7201:openzeppelin.storage.Initializable
     */
    struct InitializableStorage {
        /**
         * @dev Indicates that the contract has been initialized.
         */
        uint64 _initialized;
        /**
         * @dev Indicates that the contract is in the process of being initialized.
         */
        bool _initializing;
    }

    // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;

    /**
     * @dev The contract is already initialized.
     */
    error InvalidInitialization();

    /**
     * @dev The contract is not initializing.
     */
    error NotInitializing();

    /**
     * @dev Triggered when the contract has been initialized or reinitialized.
     */
    event Initialized(uint64 version);

    /**
     * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
     * `onlyInitializing` functions can be used to initialize parent contracts.
     *
     * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
     * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
     * production.
     *
     * Emits an {Initialized} event.
     */
    modifier initializer() {
        // solhint-disable-next-line var-name-mixedcase
        InitializableStorage storage $ = _getInitializableStorage();

        // Cache values to avoid duplicated sloads
        bool isTopLevelCall = !$._initializing;
        uint64 initialized = $._initialized;

        // Allowed calls:
        // - initialSetup: the contract is not in the initializing state and no previous version was
        //                 initialized
        // - construction: the contract is initialized at version 1 (no reininitialization) and the
        //                 current contract is just being deployed
        bool initialSetup = initialized == 0 && isTopLevelCall;
        bool construction = initialized == 1 && address(this).code.length == 0;

        if (!initialSetup && !construction) {
            revert InvalidInitialization();
        }
        $._initialized = 1;
        if (isTopLevelCall) {
            $._initializing = true;
        }
        _;
        if (isTopLevelCall) {
            $._initializing = false;
            emit Initialized(1);
        }
    }

    /**
     * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
     * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
     * used to initialize parent contracts.
     *
     * A reinitializer may be used after the original initialization step. This is essential to configure modules that
     * are added through upgrades and that require initialization.
     *
     * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
     * cannot be nested. If one is invoked in the context of another, execution will revert.
     *
     * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
     * a contract, executing them in the right order is up to the developer or operator.
     *
     * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
     *
     * Emits an {Initialized} event.
     */
    modifier reinitializer(uint64 version) {
        // solhint-disable-next-line var-name-mixedcase
        InitializableStorage storage $ = _getInitializableStorage();

        if ($._initializing || $._initialized >= version) {
            revert InvalidInitialization();
        }
        $._initialized = version;
        $._initializing = true;
        _;
        $._initializing = false;
        emit Initialized(version);
    }

    /**
     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
     * {initializer} and {reinitializer} modifiers, directly or indirectly.
     */
    modifier onlyInitializing() {
        _checkInitializing();
        _;
    }

    /**
     * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
     */
    function _checkInitializing() internal view virtual {
        if (!_isInitializing()) {
            revert NotInitializing();
        }
    }

    /**
     * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
     * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
     * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
     * through proxies.
     *
     * Emits an {Initialized} event the first time it is successfully executed.
     */
    function _disableInitializers() internal virtual {
        // solhint-disable-next-line var-name-mixedcase
        InitializableStorage storage $ = _getInitializableStorage();

        if ($._initializing) {
            revert InvalidInitialization();
        }
        if ($._initialized != type(uint64).max) {
            $._initialized = type(uint64).max;
            emit Initialized(type(uint64).max);
        }
    }

    /**
     * @dev Returns the highest version that has been initialized. See {reinitializer}.
     */
    function _getInitializedVersion() internal view returns (uint64) {
        return _getInitializableStorage()._initialized;
    }

    /**
     * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
     */
    function _isInitializing() internal view returns (bool) {
        return _getInitializableStorage()._initializing;
    }

    /**
     * @dev Returns a pointer to the storage namespace.
     */
    // solhint-disable-next-line var-name-mixedcase
    function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
        assembly {
            $.slot := INITIALIZABLE_STORAGE
        }
    }
}

File 12 of 12 : ContextUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity ^0.8.20;
import {Initializable} from "../proxy/utils/Initializable.sol";

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract ContextUpgradeable is Initializable {
    function __Context_init() internal onlyInitializing {
    }

    function __Context_init_unchained() internal onlyInitializing {
    }
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 999
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  }
}

Contract Security Audit

Contract ABI

[{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"status","type":"bool"}],"name":"BlacklistUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"closingTime","type":"uint256"}],"name":"CancelEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newDeadline","type":"uint256"}],"name":"DeadlineOfClaimUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"eventId","type":"bytes32"}],"name":"EventPaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"eventId","type":"bytes32"},{"indexed":true,"internalType":"string","name":"status","type":"string"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"EventStatusUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"prevClosingTime","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newClosingTime","type":"uint256"}],"name":"EventTimeExtended","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"eventId","type":"bytes32"}],"name":"EventUnpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newFeesWallet","type":"address"}],"name":"FeesWalletUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newNFTAddress","type":"address"}],"name":"NFTAddressUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newOpeningTime","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newClosingTime","type":"uint256"}],"name":"NewEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"currEvent","type":"bytes32"},{"indexed":true,"internalType":"address","name":"player","type":"address"},{"indexed":false,"internalType":"uint256","name":"regTimestamp","type":"uint256"}],"name":"PlayerEntry","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newPriceFeed","type":"address"}],"name":"PriceFeedUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"percentageOfDriftking","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"percentageOfTop10","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"percentageOfTop30","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"percentageOfRev","type":"uint256"}],"name":"TierPercentagesUpdated","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[{"internalType":"address","name":"_address","type":"address"}],"name":"allowAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_refundToPlayers","type":"bool"},{"internalType":"bytes32","name":"_eventId","type":"bytes32"},{"internalType":"bool","name":"_force","type":"bool"}],"name":"cancelEvent","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimDeadline","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_eventId","type":"bytes32"}],"name":"claimRefund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_eventId","type":"bytes32"}],"name":"claimReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_eventId","type":"bytes32"}],"name":"closingTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_eventId","type":"bytes32"},{"internalType":"string","name":"_eventName","type":"string"},{"internalType":"string","name":"_eventMapName","type":"string"},{"internalType":"uint256","name":"_entryFeesInUsd","type":"uint256"},{"internalType":"uint256","name":"_openingTime","type":"uint256"},{"internalType":"uint256","name":"_closingTime","type":"uint256"},{"internalType":"uint256","name":"_nftIdForDriftKing","type":"uint256"},{"internalType":"uint256","name":"_nftIdFortop10","type":"uint256"},{"internalType":"uint256","name":"_nftIdFortop30","type":"uint256"}],"name":"createEvent","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bytes32","name":"_eventId","type":"bytes32"}],"name":"depositToRewardPool","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"}],"name":"disallowAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_eventId","type":"bytes32"}],"name":"entryInEvent","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"address","name":"","type":"address"}],"name":"eventClaims","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"eventLeaderboardLocked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"eventNonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"eventPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"eventStoppedAndRefund","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newClosingTime","type":"uint256"},{"internalType":"bytes32","name":"_eventId","type":"bytes32"}],"name":"extendEventTime","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"feesWallet","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getActiveEvents","outputs":[{"internalType":"bytes32[]","name":"x","type":"bytes32[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAllEvents","outputs":[{"internalType":"bytes32[]","name":"x","type":"bytes32[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_eventId","type":"bytes32"}],"name":"getEventDetails","outputs":[{"internalType":"bytes32","name":"eventId","type":"bytes32"},{"internalType":"string","name":"eventName","type":"string"},{"internalType":"string","name":"eventMap","type":"string"},{"internalType":"uint256","name":"entryFeesUsd","type":"uint256"},{"internalType":"uint256","name":"startTimestamp","type":"uint256"},{"internalType":"uint256","name":"endTimestamp","type":"uint256"},{"internalType":"uint256","name":"totalFeesRaised","type":"uint256"},{"internalType":"uint256","name":"totalFeesRaisedInUSD","type":"uint256"},{"internalType":"string","name":"status","type":"string"},{"internalType":"string[]","name":"nftUri","type":"string[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getInactiveEvents","outputs":[{"internalType":"bytes32[]","name":"completed","type":"bytes32[]"},{"internalType":"bytes32[]","name":"cancelled","type":"bytes32[]"},{"internalType":"bytes32[]","name":"paused","type":"bytes32[]"},{"internalType":"bytes32[]","name":"pending","type":"bytes32[]"},{"internalType":"bytes32[]","name":"process","type":"bytes32[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_eventId","type":"bytes32"}],"name":"getPriceRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"getPriceUsdToNative","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_eventId","type":"bytes32"}],"name":"getTotalPlayers","outputs":[{"internalType":"address[]","name":"players","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_eventId","type":"bytes32"}],"name":"getUsersData","outputs":[{"internalType":"address[]","name":"top10","type":"address[]"},{"internalType":"address[]","name":"top30","type":"address[]"},{"internalType":"address[]","name":"dk","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_eventId","type":"bytes32"}],"name":"hasClosed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_feesWallet","type":"address"},{"internalType":"address","name":"_priceFeed","type":"address"},{"internalType":"address","name":"_payoutPursuitNftAddress","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"initialized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"}],"name":"isAddressAllowed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"}],"name":"isBlacklisted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_eventId","type":"bytes32"}],"name":"isEventOpen","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_eventId","type":"bytes32"},{"internalType":"address","name":"_user","type":"address"}],"name":"isRewardAvailable","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"enum PayoutPursuitPlayer.PercentageDist","name":"","type":"uint8"},{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_eventId","type":"bytes32"}],"name":"lockLeaderboard","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"lockedReward","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"addresses","type":"address[]"},{"internalType":"bool","name":"status","type":"bool"}],"name":"manageBlacklist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"minParticipants","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_eventId","type":"bytes32"}],"name":"openingTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_eventId","type":"bytes32"}],"name":"pauseEvent","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"payoutPursuitNft","outputs":[{"internalType":"contract IPayoutPursuitCars","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum PayoutPursuitPlayer.PercentageDist","name":"","type":"uint8"}],"name":"percentage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"address","name":"","type":"address"}],"name":"playerData","outputs":[{"internalType":"address","name":"player","type":"address"},{"internalType":"enum PayoutPursuitPlayer.PercentageDist","name":"rank","type":"uint8"},{"internalType":"uint256","name":"feesPaidInNative","type":"uint256"},{"internalType":"uint256","name":"feesPaidInUsd","type":"uint256"},{"internalType":"uint256","name":"eventRegisterTimestamp","type":"uint256"},{"internalType":"uint256","name":"claimTimestamp","type":"uint256"},{"internalType":"bool","name":"userAccess","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"priceFeed","outputs":[{"internalType":"contract AggregatorV3Interface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_eventId","type":"bytes32"},{"internalType":"address[]","name":"_playerDK","type":"address[]"},{"internalType":"address[]","name":"_playersTop10","type":"address[]"},{"internalType":"address[]","name":"_playersTop30","type":"address[]"},{"internalType":"bool","name":"isLocked","type":"bool"}],"name":"submitUsersData","outputs":[{"internalType":"bytes[]","name":"x","type":"bytes[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_eventId","type":"bytes32"},{"internalType":"uint256","name":"_newClosingTime","type":"uint256"}],"name":"unpauseEvent","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newDeadlineInDays","type":"uint256"}],"name":"updateClaimDeadline","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_entryFeesInUsd","type":"uint256"},{"internalType":"string","name":"_eventName","type":"string"},{"internalType":"string","name":"_eventMap","type":"string"},{"internalType":"bytes32","name":"_eventId","type":"bytes32"}],"name":"updateEvent","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_feesWallet","type":"address"}],"name":"updateFeesWallet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_payoutPursuitNft","type":"address"}],"name":"updatePayoutPursuitNftAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_driftking","type":"uint256"},{"internalType":"uint256","name":"_top10","type":"uint256"},{"internalType":"uint256","name":"_top30","type":"uint256"},{"internalType":"uint256","name":"_rev","type":"uint256"}],"name":"updatePercentages","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_priceFeed","type":"address"}],"name":"updatePriceFeed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"withdrawAdditionalFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_eventId","type":"bytes32"}],"name":"withdrawFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

60806040908152603a805460ff191690555f603f556005905562278d0060415534801561002a575f80fd5b50615dee80620000395f395ff3fe60806040526004361061033e575f3560e01c80637cb414eb116101ad578063b7c58d7a116100ea578063e1d69fe61161008e578063f54140231161006b578063f541402314610aff578063f8c8765e14610b1e578063fb2f349214610b3d578063fe575a8714610b5c57005b8063e1d69fe614610a96578063ebb32ec014610ac1578063f2fde38b14610ae057005b8063bea87817116100c7578063bea8781714610a10578063c27a500d14610a35578063c3610f0c14610a49578063dffb6b6714610a6857005b8063b7c58d7a146109b3578063b89596fa146109d2578063bddc99b4146109f157005b8063966722d211610151578063b0a750171161012e578063b0a7501714610900578063b38a397b14610947578063b43c789514610966578063b7086cc51461098557005b8063966722d2146108ad5780639e4146e1146108cc578063a54cd4f7146108eb57005b80638a0cf9e91161018a5780638a0cf9e9146107ef5780638da5cb5b1461081b5780638fa2a9031461085757806395877f781461088e57005b80637cb414eb146107835780637e44d2cc146107b15780638486758e146107d057005b80633ba86c441161027b578063715018a61161021f5780637491a0b3116101fc5780637491a0b3146106ed5780637706130c1461070c578063790692961461072b5780637917be031461074a57005b8063715018a61461068357806371de2ffc14610697578063741bef1a146106b657005b80635d31f873116102585780635d31f873146105865780635f629466146105b4578063651b8226146106365780636e2b54ee1461066457005b80633ba86c44146105315780634ea486a01461054657806354fd4d501461056557005b8063199a28cf116102e257806323bb7211116102bf57806323bb7211146104a95780632ca10898146104bc5780632e3740e7146104f15780633612280f1461051057005b8063199a28cf146104625780631c3e6ee6146104815780631e216c431461049657005b8063158ef93e1161031b578063158ef93e146103c357806316161e6e146103ec578063168e8ec91461040b57806317ea277f1461043657005b806308af4d88146103475780630ebc5f2a14610366578063124bcf6d146103a457005b3661034557005b005b348015610352575f80fd5b5061034561036136600461514a565b610b93565b348015610371575f80fd5b50610391610380366004615165565b5f9081526002602052604090205490565b6040519081526020015b60405180910390f35b3480156103af575f80fd5b506103456103be366004615189565b610c2b565b3480156103ce575f80fd5b50603a546103dc9060ff1681565b604051901515815260200161039b565b3480156103f7575f80fd5b506103dc610406366004615165565b610ebd565b348015610416575f80fd5b506103916104253660046151c8565b604b6020525f908152604090205481565b348015610441575f80fd5b506104556104503660046152bf565b610ee7565b60405161039b91906153ac565b34801561046d575f80fd5b5061034561047c36600461514a565b611192565b34801561048c575f80fd5b50610391603f5481565b6103dc6104a436600461540c565b6111ef565b6103456104b7366004615165565b611332565b3480156104c7575f80fd5b506104db6104d6366004615165565b611523565b60405161039b9a9998979695949392919061542c565b3480156104fc575f80fd5b5061034561050b36600461540c565b611a0a565b34801561051b575f80fd5b50610524611a96565b60405161039b9190615530565b34801561053c575f80fd5b5061039160415481565b348015610551575f80fd5b50610391610560366004615165565b611c34565b348015610570575f80fd5b50610579611c57565b60405161039b9190615542565b348015610591575f80fd5b506103dc6105a0366004615165565b60476020525f908152604090205460ff1681565b3480156105bf575f80fd5b506106236105ce366004615554565b600560208181525f938452604080852090915291835291208054600182015460028301546003840154600485015494909501546001600160a01b03841695600160a01b90940460ff9081169593949293911687565b60405161039b97969594939291906155b6565b348015610641575f80fd5b50610655610650366004615554565b611ce3565b60405161039b939291906155fe565b34801561066f575f80fd5b5061034561067e366004615165565b611f26565b34801561068e575f80fd5b50610345611fe5565b3480156106a2575f80fd5b506103456106b1366004615165565b611ff8565b3480156106c1575f80fd5b50603d546106d5906001600160a01b031681565b6040516001600160a01b03909116815260200161039b565b3480156106f8575f80fd5b5061034561070736600461514a565b612306565b348015610717575f80fd5b5061034561072636600461514a565b61235c565b348015610736575f80fd5b50610345610745366004615165565b61259a565b348015610755575f80fd5b506103dc610764366004615554565b604960209081525f928352604080842090915290825290205460ff1681565b34801561078e575f80fd5b506103dc61079d366004615165565b60486020525f908152604090205460ff1681565b3480156107bc575f80fd5b50603c546106d5906001600160a01b031681565b3480156107db575f80fd5b50603e546106d5906001600160a01b031681565b3480156107fa575f80fd5b5061080e610809366004615165565b6125e2565b60405161039b9190615659565b348015610826575f80fd5b507f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b03166106d5565b348015610862575f80fd5b506103dc61087136600461514a565b6001600160a01b03165f9081526020819052604090205460ff1690565b348015610899575f80fd5b506103456108a836600461514a565b61264b565b3480156108b8575f80fd5b506103dc6108c73660046156df565b6126a1565b3480156108d7575f80fd5b506103456108e6366004615165565b6129fe565b3480156108f6575f80fd5b5061039160405481565b34801561090b575f80fd5b5061093261091a366004615165565b604c6020525f90815260409020805460019091015482565b6040805192835260208301919091520161039b565b348015610952575f80fd5b50610345610961366004615165565b612a84565b348015610971575f80fd5b5061034561098036600461577c565b612d49565b348015610990575f80fd5b506109a461099f366004615165565b612e8b565b60405161039b939291906157ec565b3480156109be575f80fd5b506103456109cd36600461514a565b6131be565b3480156109dd575f80fd5b506103456109ec36600461540c565b613258565b3480156109fc575f80fd5b506103dc610a0b366004615165565b61328f565b348015610a1b575f80fd5b50610a246132ba565b60405161039b959493929190615824565b348015610a40575f80fd5b50610524613986565b348015610a54575f80fd5b50610391610a63366004615165565b6139dc565b348015610a73575f80fd5b506103dc610a82366004615165565b60046020525f908152604090205460ff1681565b348015610aa1575f80fd5b50610391610ab0366004615165565b5f9081526003602052604090205490565b348015610acc575f80fd5b50610345610adb366004615890565b613a95565b348015610aeb575f80fd5b50610345610afa36600461514a565b613b83565b348015610b0a575f80fd5b50610345610b19366004615165565b613bd6565b348015610b29575f80fd5b50610345610b383660046158bf565b61409f565b348015610b48575f80fd5b50610345610b57366004615918565b61431b565b348015610b67575f80fd5b506103dc610b7636600461514a565b6001600160a01b03165f9081526001602052604090205460ff1690565b610b9b614468565b6001600160a01b0381165f9081526020819052604090205460ff1615610c085760405162461bcd60e51b815260206004820152601f60248201527f546865206164647265737320697320616c726561647920616c6c6f7765642e0060448201526064015b60405180910390fd5b6001600160a01b03165f908152602081905260409020805460ff19166001179055565b610c33614468565b610c3b6144dc565b5f8281526046602052604090206001600882015460ff166002811115610c6357610c63615582565b03610cd65760405162461bcd60e51b815260206004820152602660248201527f5061796f7574507572737569743a206576656e7420616c72656164792063616e60448201527f63656c6c656400000000000000000000000000000000000000000000000000006064820152608401610bff565b604054610ce2846125e2565b5110158015610cef575081155b15610d5457610cfd8361328f565b15610d545760405162461bcd60e51b815260206004820152602160248201527f5061796f75745075727375697454696d653a20616c726561647920636c6f73656044820152601960fa1b6064820152608401610bff565b610d5d83614535565b5f83815260036020526040902054600582015560088101805460ff191660011790558315610ddd5760405180604001604052808260060154815260200160415442610da891906159a0565b90525f848152604c6020908152604080832084518155938201516001909401939093556048905220805460ff19168515151790555b603e546040517f3fc3b182000000000000000000000000000000000000000000000000000000008152600481018590526001600160a01b0390911690633fc3b182906024015f604051808303815f87803b158015610e39575f80fd5b505af1158015610e4b573d5f803e3d5ffd5b50505050604051610e6b906810d05390d15313115160ba1b815260090190565b6040518091039020837f64adf624f09c3abf7f8ff522d02f9297d5f69180632098d84933c1f2ec4e174742604051610ea591815260200190565b60405180910390a350610eb86001600855565b505050565b5f610ec78261457b565b8015610ee157505f8281526004602052604090205460ff16155b92915050565b6060610ef1614468565b610ef96144dc565b85610f038161328f565b610f5b5760405162461bcd60e51b8152602060048201526024808201527f5061796f75745075727375697454696d653a206576656e7420696e2070726f676044820152637265737360e01b6064820152608401610bff565b5f8781526047602052604090205460ff1615610fdf5760405162461bcd60e51b815260206004820152602760248201527f5061796f7574507572737569743a206576656e74206c6561646572626f61726460448201527f206c6f636b6564000000000000000000000000000000000000000000000000006064820152608401610bff565b8615801590610ffa57505f8781526046602052604090205415155b6110465760405162461bcd60e51b815260206004820152601f60248201527f5061796f7574507572737569743a206576656e7420696420696e76616c6964006044820152606401610bff565b604080516003808252608082019092525f91816020015b606081526020019060019003908161105d57905050905061107f885f896145a8565b815f81518110611091576110916159b3565b60200260200101819052506110a8886001886145a8565b816001815181106110bb576110bb6159b3565b60200260200101819052506110d2886002876145a8565b816002815181106110e5576110e56159b3565b602090810291909101015291506110fd604388614634565b5f8781526046602052604090819020600801805460ff19166002179055516810d3d354131155115160ba1b81526009016040518091039020877f64adf624f09c3abf7f8ff522d02f9297d5f69180632098d84933c1f2ec4e17474260405161116791815260200190565b60405180910390a3821561117e5761117e87612a84565b506111896001600855565b95945050505050565b61119a614468565b603e80546001600160a01b0319166001600160a01b0383169081179091556040519081527fc0a15db954f8aded5cda5092ae26da70558a30c4e12c48e77d87564c3197edf5906020015b60405180910390a150565b5f6111f8614468565b5f8281526046602052604081206004015490036112575760405162461bcd60e51b815260206004820152601f60248201527f5061796f7574507572737569743a20696e76616c6964206576656e74206964006044820152606401610bff565b823410156112cd5760405162461bcd60e51b815260206004820152602260248201527f5061796f7574507572737569743a20696e73756666696369656e7420616d6f7560448201527f6e740000000000000000000000000000000000000000000000000000000000006064820152608401610bff565b6112d783346159c7565b60445f8282546112e791906159a0565b925050819055508260455f8282546112ff91906159a0565b90915550505f82815260466020526040812060060180548592906113249084906159a0565b909155506001949350505050565b8061133c8161457b565b6113885760405162461bcd60e51b815260206004820152601b60248201527f5061796f75745075727375697454696d653a206e6f74206f70656e00000000006044820152606401610bff565b5f82815260046020526040902054829060ff161561140e5760405162461bcd60e51b815260206004820152602260248201527f5061796f75745075727375697454696d653a206576656e74206973207061757360448201527f65640000000000000000000000000000000000000000000000000000000000006064820152608401610bff565b5f8381526005602081815260408084203385529091529091200154839060ff16156114a15760405162461bcd60e51b815260206004820152603360248201527f5061796f7574507572737569743a20616c72656164792072656769737465726560448201527f6420666f722063757272656e74206576656e74000000000000000000000000006064820152608401610bff565b6114a96144dc565b5f806114b486614746565b5f888152604660205260408120600601805493955091935084926114d99084906159a0565b90915550505f86815260466020526040812060070180548392906114fe9084906159a0565b909155506115119050863342858561481a565b505061151d6001600855565b50505050565b5f6060805f805f805f6060805f60465f8d81526020019081526020015f20604051806101200160405290815f8201548152602001600182018054611566906159da565b80601f0160208091040260200160405190810160405280929190818152602001828054611592906159da565b80156115dd5780601f106115b4576101008083540402835291602001916115dd565b820191905f5260205f20905b8154815290600101906020018083116115c057829003601f168201915b505050505081526020016002820180546115f6906159da565b80601f0160208091040260200160405190810160405280929190818152602001828054611622906159da565b801561166d5780601f106116445761010080835404028352916020019161166d565b820191905f5260205f20905b81548152906001019060200180831161165057829003601f168201915b505050918352505060038201546020820152600482015460408201526005820154606082015260068201546080820152600782015460a0820152600882015460c09091019060ff1660028111156116c6576116c6615582565b60028111156116d7576116d7615582565b905250905060605f82610100015160028111156116f6576116f6615582565b0361182f575060408051808201909152600681526541435449564560d01b602082015260808201515f0361175e575060408051808201909152600881527f4e4f54455849535400000000000000000000000000000000000000000000000060208201526118b3565b5f8d81526004602052604090205460ff1615611797575060408051808201909152600681526514105554d15160d21b60208201526118b3565b5f8d8152600260205260409020544210156117e6575060408051808201909152600781527f50454e44494e470000000000000000000000000000000000000000000000000060208201526118b3565b6117ef8d61328f565b1561182a575060408051808201909152600781527f50524f434553530000000000000000000000000000000000000000000000000060208201525b6118b3565b6002826101000151600281111561184857611848615582565b03611873575060408051808201909152600981526810d3d354131155115160ba1b60208201526118b3565b6001826101000151600281111561188c5761188c615582565b036118b3575060408051808201909152600981526810d05390d15313115160ba1b60208201525b604080516003808252608082019092525f91816020015b60608152602001906001900390816118ca579050509050603e5f9054906101000a90046001600160a01b03166001600160a01b0316630222c7d78f6040518263ffffffff1660e01b815260040161192391815260200190565b5f60405180830381865afa15801561193d573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526119649190810190615a54565b835f81518110611976576119766159b3565b6020026020010184600181518110611990576119906159b3565b60200260200101856002815181106119aa576119aa6159b3565b60200260200101839052839052839052505050825f015183602001518460400151856060015186608001518760a001518860c001518960e0015189899c509c509c509c509c509c509c509c509c509c505050509193959799509193959799565b611a12614468565b611a1a6144dc565b8015611a2a57611a2a8183613258565b611a338261499a565b6040516541435449564560d01b81526006015b6040518091039020827f64adf624f09c3abf7f8ff522d02f9297d5f69180632098d84933c1f2ec4e174742604051611a8091815260200190565b60405180910390a3611a926001600855565b5050565b60435460609067ffffffffffffffff811115611ab457611ab46151e6565b604051908082528060200260200182016040528015611add578160200160208202803683370190505b5090505f805f5b60435460ff82161015611b8257611b1860438260ff1681548110611b0a57611b0a6159b3565b905f5260205f200154610ebd565b15611b6b5760438160ff1681548110611b3357611b336159b3565b905f5260205f200154848481518110611b4e57611b4e6159b3565b602090810291909101015282611b6381615ad6565b935050611b70565b600191505b80611b7a81615aee565b915050611ae4565b508015611c2f575f8267ffffffffffffffff811115611ba357611ba36151e6565b604051908082528060200260200182016040528015611bcc578160200160208202803683370190505b5090505f5b838160ff161015611c2b57848160ff1681518110611bf157611bf16159b3565b6020026020010151828260ff1681518110611c0e57611c0e6159b3565b602090810291909101015280611c2381615aee565b915050611bd1565b5092505b505090565b5f8181526046602052604081206003015481611c4f826139dc565b949350505050565b603b8054611c64906159da565b80601f0160208091040260200160405190810160405280929190818152602001828054611c90906159da565b8015611cdb5780601f10611cb257610100808354040283529160200191611cdb565b820191905f5260205f20905b815481529060010190602001808311611cbe57829003601f168201915b505050505081565b5f805f805f80611cf288612e8b565b805192955090935091505f9060049015611d84575f5b83518160ff161015611d8257896001600160a01b0316848260ff1681518110611d3357611d336159b3565b60200260200101516001600160a01b031603611d7057838160ff1681518110611d5e57611d5e6159b3565b602002602001015192505f9150611d82565b80611d7a81615aee565b915050611d08565b505b6004816004811115611d9857611d98615582565b03611e13575f5b8551811015611e1157896001600160a01b0316868281518110611dc457611dc46159b3565b60200260200101516001600160a01b031603611dff57858181518110611dec57611dec6159b3565b6020026020010151925060019150611e11565b80611e0981615ad6565b915050611d9f565b505b6004816004811115611e2757611e27615582565b03611ea2575f5b8451811015611ea057896001600160a01b0316858281518110611e5357611e536159b3565b60200260200101516001600160a01b031603611e8e57848181518110611e7b57611e7b6159b3565b6020026020010151925060029150611ea0565b80611e9881615ad6565b915050611e2e565b505b6004816004811115611eb657611eb6615582565b03611ecd575f97509550869450611f1f9350505050565b611eed611eda8b836149e1565b5f8c8152604c6020526040902054614a28565b5f8b81526049602090815260408083206001600160a01b038e16845290915290205490985090965060ff169450505050505b9250925092565b611f2e614468565b5f818152604c6020526040902060010154421015611fb45760405162461bcd60e51b815260206004820152603860248201527f5061796f7574507572737569743a206576656e742072657761726473206c6f6360448201527f6b656420666f722077696e6e65727320746f20636c61696d00000000000000006064820152608401610bff565b603c545f828152604c6020526040902054611fe2916001600160a01b031690611fdd9047614a28565b614a3d565b50565b611fed614468565b611ff65f614a98565b565b6120006144dc565b5f8181526048602052604090205460ff16801561202d57505f818152604c60205260409020600101544211155b61209f5760405162461bcd60e51b815260206004820152602360248201527f5061796f7574507572737569743a206e6f20726566756e647320617661696c6160448201527f626c6500000000000000000000000000000000000000000000000000000000006064820152608401610bff565b5f81815260496020908152604080832033845290915290205460ff16156121085760405162461bcd60e51b815260206004820152601e60248201527f5061796f7574507572737569743a20616c726561647920636c61696d656400006044820152606401610bff565b5f8181526005602090815260408083203384528252808320815160e0810190925280546001600160a01b03811683529192909190830190600160a01b900460ff16600481111561215a5761215a615582565b600481111561216b5761216b615582565b81526001820154602082015260028201546040820152600382015460608201526004820154608082015260059091015460ff16151560a09091015260c081015190915080156121c3575080516001600160a01b031633145b80156121d8575080516001600160a01b031615155b6122245760405162461bcd60e51b815260206004820152601e60248201527f5061796f7574507572737569743a20696e76616c6964206164647265737300006044820152606401610bff565b5f828152604960209081526040808320338452909152808220805460ff191660011790558201516122559047614a28565b5f848152604c60205260408120805492935083929091906122779084906159c7565b9091555050806122ef5760405162461bcd60e51b815260206004820152603960248201527f5061796f7574507572737569743a20696e73756666696369656e742066756e6460448201527f732c20706c6561736520636f6e7461637420737570706f7274000000000000006064820152608401610bff565b6122fa335b82614a3d565b5050611fe26001600855565b61230e614468565b603c80546001600160a01b0319166001600160a01b0383169081179091556040519081527f5748080475cb42a3ebe2b436c56efe7b4c51ee26f4bf66c2f6906fd3222edc84906020016111e4565b612364614468565b6001600160a01b03811615612500576040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201525f906001600160a01b038316906370a0823190602401602060405180830381865afa1580156123d0573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906123f49190615b0c565b90505f811161246b5760405162461bcd60e51b815260206004820152602c60248201527f5061796f7574507572737569743a20696e73756666696369656e7420636f6e7460448201527f726163742062616c616e636500000000000000000000000000000000000000006064820152608401610bff565b603c546040517fa9059cbb0000000000000000000000000000000000000000000000000000000081526001600160a01b039182166004820152602481018390529083169063a9059cbb906044016020604051808303815f875af11580156124d4573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906124f89190615b23565b611a92575f80fd5b5f47116125755760405162461bcd60e51b815260206004820152603760248201527f5061796f7574507572737569743a20696e73756666696369656e74206164646960448201527f74696f6e616c20636f6e74726163742062616c616e63650000000000000000006064820152608401610bff565b603c54604454612593916001600160a01b031690611fdd9047614a28565b5f60445550565b6125a2614468565b6125af8162015180615b3e565b6041556040518181527fc4ba5e42712b0d178f421c5e23f5376bece3c36990d44241ec7a934f37542e7d906020016111e4565b5f8181526006602090815260409182902080548351818402810184019094528084526060939283018282801561263f57602002820191905f5260205f20905b81546001600160a01b03168152600190910190602001808311612621575b50505050509050919050565b612653614468565b603d80546001600160a01b0319166001600160a01b0383169081179091556040519081527fe5b20b8497e4f3e2435ef9c20e2e26b47497ee13745ce1c681ad6640653119e6906020016111e4565b335f9081526020819052604081205460ff161515600114806126fb5750336126f07f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031690565b6001600160a01b0316145b6127475760405162461bcd60e51b815260206004820152601460248201527f596f7520617265206e6f7420616c6c6f7765642e0000000000000000000000006044820152606401610bff565b61274f6144dc565b5f8a6127625761275d614b08565b612764565b8a5b5f81815260466020526040902054909150156127e85760405162461bcd60e51b815260206004820152602660248201527f5061796f7574507572737569743a206576656e7420696420616c72656164792060448201527f65786973747300000000000000000000000000000000000000000000000000006064820152608401610bff565b6127f3878783614b5c565b6040518061012001604052808281526020018b81526020018a81526020018981526020018881526020018781526020015f81526020015f81526020015f600281111561284157612841615582565b90525f8281526046602090815260409091208251815590820151600182019061286a9082615b9a565b506040820151600282019061287f9082615b9a565b50606082015160038201556080820151600482015560a0820151600582015560c0820151600682015560e0820151600782015561010082015160088201805460ff191660018360028111156128d6576128d6615582565b0217905550506043805460018181019092557f9690ad99d6ce244efa8a0f6c2d04036d3b33a9474db32a71b71135c695102793018390556042805491820181555f527f38dfe4635b27babeca8be38d3b448cb5161a639b899a14825ba9c8d7892eb8c301829055508415158061294b57508315155b8061295557508215155b156129e257603e546040517f259481c7000000000000000000000000000000000000000000000000000000008152600481018390526024810187905260448101869052606481018590526001600160a01b039091169063259481c7906084015f604051808303815f87803b1580156129cb575f80fd5b505af11580156129dd573d5f803e3d5ffd5b505050505b60019150506129f16001600855565b9998505050505050505050565b612a06614468565b80612a108161457b565b612a5c5760405162461bcd60e51b815260206004820152601b60248201527f5061796f75745075727375697454696d653a206e6f74206f70656e00000000006044820152606401610bff565b612a646144dc565b612a6d82614c9f565b6040516514105554d15160d21b8152600601611a46565b612a8c614468565b5f805f612a9884612e8b565b9250925092505f83511180612aad57505f8251115b8015612ab957505f8151115b612b2a5760405162461bcd60e51b8152602060048201526024808201527f5061796f7574507572737569743a206c6561646572626f617264206e6f74206660448201527f6f756e64000000000000000000000000000000000000000000000000000000006064820152608401610bff565b5f848152604760209081526040808320805460ff191660011790556046825282206006015460038352604b9091527f18568898f741436c6378e97ae0a64b9a55f252371515c69c6b47e8a95ef4209454909190620186a090612b8c9084615b3e565b612b969190615c56565b5f8052604b6020527f08bf084be5767d8bb834edf3692454b23339ffcb9637cb06a941344461c3719854909150620186a090612bd29084615b3e565b612bdc9190615c56565b5f878152604a602090815260408083208380529091529020558451612c01575f612c51565b845160015f52604b6020527fa616258785d57c6565e8210a7a01441f8018ea52e0ce6d2ea56b8099c64a4d7554620186a090612c3d9085615b3e565b612c479190615c56565b612c519190615c56565b5f878152604a60209081526040808320600184529091529020558351612c77575f612cc7565b835160025f52604b6020527fed8fe69440ed7378c748b48bdf0a382a8b2b7193fd6134dd2b323f6392cefa4d54620186a090612cb39085615b3e565b612cbd9190615c56565b612cc79190615c56565b5f878152604a60209081526040808320600284529091529081902091909155805180820190915280612cf983856159c7565b815260200160415442612d0c91906159a0565b90525f878152604c6020908152604090912082518155910151600190910155603c54612d41906001600160a01b031682614a3d565b505050505050565b335f9081526020819052604090205460ff16151560011480612da3575033612d987f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031690565b6001600160a01b0316145b612def5760405162461bcd60e51b815260206004820152601460248201527f596f7520617265206e6f7420616c6c6f7765642e0000000000000000000000006044820152606401610bff565b612df76144dc565b8315612e11575f8181526046602052604090206003018490555b612e298360405180602001604052805f815250614d4b565b612e49575f818152604660205260409020600101612e478482615b9a565b505b612e618260405180602001604052805f815250614d4b565b612e81575f818152604660205260409020600201612e7f8382615b9a565b505b61151d6001600855565b5f81815260076020908152604080832083805282528083208054825181850281018501909352808352606094859485949193919290849084015b82821015612f6d578382905f5260205f20018054612ee2906159da565b80601f0160208091040260200160405190810160405280929190818152602001828054612f0e906159da565b8015612f595780601f10612f3057610100808354040283529160200191612f59565b820191905f5260205f20905b815481529060010190602001808311612f3c57829003601f168201915b505050505081526020019060010190612ec5565b5050505f8781526007602090815260408083206001845282528083208054825181850281018501909352808352959650929490935090849084015b82821015613050578382905f5260205f20018054612fc5906159da565b80601f0160208091040260200160405190810160405280929190818152602001828054612ff1906159da565b801561303c5780601f106130135761010080835404028352916020019161303c565b820191905f5260205f20905b81548152906001019060200180831161301f57829003601f168201915b505050505081526020019060010190612fa8565b5050505f8881526007602090815260408083206002845282528083208054825181850281018501909352808352959650929490935090849084015b82821015613133578382905f5260205f200180546130a8906159da565b80601f01602080910402602001604051908101604052809291908181526020018280546130d4906159da565b801561311f5780601f106130f65761010080835404028352916020019161311f565b820191905f5260205f20905b81548152906001019060200180831161310257829003601f168201915b50505050508152602001906001019061308b565b5050505090505f8351111561317657613173875f856001875161315691906159c7565b81518110613166576131666159b3565b6020026020010151614da3565b93505b81511561319557613192876001846001865161315691906159c7565b95505b8051156131b4576131b1876002836001855161315691906159c7565b94505b5050509193909250565b6131c6614468565b6001600160a01b0381165f9081526020819052604090205460ff161515600114610c085760405162461bcd60e51b815260206004820152602360248201527f546865206164647265737320697320616c7265616479206e6f7420616c6c6f7760448201527f65642e00000000000000000000000000000000000000000000000000000000006064820152608401610bff565b613260614468565b6132686144dc565b6132728282614f3e565b5f818152604660205260409020600501829055611a926001600855565b5f8181526003602052604081205442118015610ee15750505f90815260036020526040902054151590565b60608060608060605f60428054905067ffffffffffffffff8111156132e1576132e16151e6565b60405190808252806020026020018201604052801561330a578160200160208202803683370190505b506042549091505f9067ffffffffffffffff81111561332b5761332b6151e6565b604051908082528060200260200182016040528015613354578160200160208202803683370190505b506042549091505f9067ffffffffffffffff811115613375576133756151e6565b60405190808252806020026020018201604052801561339e578160200160208202803683370190505b506042549091505f9067ffffffffffffffff8111156133bf576133bf6151e6565b6040519080825280602002602001820160405280156133e8578160200160208202803683370190505b506042549091505f9067ffffffffffffffff811115613409576134096151e6565b604051908082528060200260200182016040528015613432578160200160208202803683370190505b5090505f80808080805b60425460ff82161015613672575f60428260ff1681548110613460576134606159b3565b5f91825260209091200154905060025f8281526046602052604090206008015460ff16600281111561349457613494615582565b036134c457808c886134a581615ad6565b9950815181106134b7576134b76159b3565b6020026020010181815250505b60015f8281526046602052604090206008015460ff1660028111156134eb576134eb615582565b0361351b57808b876134fc81615ad6565b98508151811061350e5761350e6159b3565b6020026020010181815250505b5f8181526004602052604090205460ff16801561355a57505f8181526046602052604081206008015460ff16600281111561355857613558615582565b145b1561358a57808a8661356b81615ad6565b97508151811061357d5761357d6159b3565b6020026020010181815250505b5f81815260026020526040902054421080156135c857505f8181526046602052604081206008015460ff1660028111156135c6576135c6615582565b145b156135f8578089856135d981615ad6565b9650815181106135eb576135eb6159b3565b6020026020010181815250505b6136018161328f565b801561362f57505f8181526046602052604081206008015460ff16600281111561362d5761362d615582565b145b1561365f5780888461364081615ad6565b955081518110613652576136526159b3565b6020026020010181815250505b508061366a81615aee565b91505061343c565b508467ffffffffffffffff81111561368c5761368c6151e6565b6040519080825280602002602001820160405280156136b5578160200160208202803683370190505b509e508367ffffffffffffffff8111156136d1576136d16151e6565b6040519080825280602002602001820160405280156136fa578160200160208202803683370190505b509d508267ffffffffffffffff811115613716576137166151e6565b60405190808252806020026020018201604052801561373f578160200160208202803683370190505b509c508167ffffffffffffffff81111561375b5761375b6151e6565b604051908082528060200260200182016040528015613784578160200160208202803683370190505b509b508067ffffffffffffffff8111156137a0576137a06151e6565b6040519080825280602002602001820160405280156137c9578160200160208202803683370190505b509a5050505050505f5b8a51811015613825578581815181106137ee576137ee6159b3565b60200260200101518b8281518110613808576138086159b3565b60209081029190910101528061381d81615ad6565b9150506137d3565b505f5b895181101561387a57848181518110613843576138436159b3565b60200260200101518a828151811061385d5761385d6159b3565b60209081029190910101528061387281615ad6565b915050613828565b505f5b88518110156138cf57838181518110613898576138986159b3565b60200260200101518982815181106138b2576138b26159b3565b6020908102919091010152806138c781615ad6565b91505061387d565b505f5b8751811015613924578281815181106138ed576138ed6159b3565b6020026020010151888281518110613907576139076159b3565b60209081029190910101528061391c81615ad6565b9150506138d2565b505f5b865181101561397957818181518110613942576139426159b3565b602002602001015187828151811061395c5761395c6159b3565b60209081029190910101528061397181615ad6565b915050613927565b5050505050509091929394565b606060428054806020026020016040519081016040528092919081815260200182805480156139d257602002820191905f5260205f20905b8154815260200190600101908083116139be575b5050505050905090565b5f80603d5f9054906101000a90046001600160a01b03166001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015613a2e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613a529190615c93565b5050509150505f816402540be400613a6a9190615b3e565b9050835f82613a8183670de0b6b3a7640000615b3e565b613a8b9190615c56565b9695505050505050565b613a9d614468565b604b60209081527f08bf084be5767d8bb834edf3692454b23339ffcb9637cb06a941344461c371988590557fa616258785d57c6565e8210a7a01441f8018ea52e0ce6d2ea56b8099c64a4d758490557fed8fe69440ed7378c748b48bdf0a382a8b2b7193fd6134dd2b323f6392cefa4d83905560035f527f18568898f741436c6378e97ae0a64b9a55f252371515c69c6b47e8a95ef420948290556040805186815291820185905281810184905260608201839052517f0d3de384c23ffe70860aed6b0034da97c6be2e6b03a6448171c1d4acfb9e854e9181900360800190a150505050565b613b8b614468565b6001600160a01b038116613bcd576040517f1e4fbdf70000000000000000000000000000000000000000000000000000000081525f6004820152602401610bff565b611fe281614a98565b613bde6144dc565b80613be88161328f565b613c405760405162461bcd60e51b8152602060048201526024808201527f5061796f75745075727375697454696d653a206576656e7420696e2070726f676044820152637265737360e01b6064820152608401610bff565b5f82815260496020908152604080832033845290915290205460ff1615613ca95760405162461bcd60e51b815260206004820152601e60248201527f5061796f7574507572737569743a20616c726561647920636c61696d656400006044820152606401610bff565b5f8281526005602090815260408083203384528252808320858452604c9092528220600101549091906004904211613cf0575f80613ce78733611ce3565b50909450925050505b5f8211613d655760405162461bcd60e51b815260206004820152603460248201527f5061796f7574507572737569743a206e6f20636c61696d20617661696c61626c60448201527f65206f7220616c726561647920636c61696d65640000000000000000000000006064820152608401610bff565b5f8581526049602090815260408083203384529091529020805460ff19166001179055426004848101919091558354829185917fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1690600160a01b908490811115613dd257613dd2615582565b021790555082546001600160a01b031916331783555f613df28347614a28565b5f878152604c6020526040812080549293508392909190613e149084906159c7565b9091555060049050826004811115613e2e57613e2e615582565b1461401257603e545f906001600160a01b03166330759ce988856004811115613e5957613e59615582565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b168152600481019290925260ff166024820152604401602060405180830381865afa158015613eb3573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613ed79190615b0c565b603e549091506001600160a01b031662fdd58e336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b03909116600482015260248101849052604401602060405180830381865afa158015613f4c573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613f709190615b0c565b5f0361401057603e546001600160a01b031663731133e9336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b0390911660048201526024810184905260016044820152608060648201525f608482015260a4015f604051808303815f87803b158015613ff9575f80fd5b505af115801561400b573d5f803e3d5ffd5b505050505b505b5f81116140875760405162461bcd60e51b815260206004820152603960248201527f5061796f7574507572737569743a20696e73756666696369656e742066756e6460448201527f732c20706c6561736520636f6e7461637420737570706f7274000000000000006064820152608401610bff565b614090336122f4565b5050505050611fe26001600855565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000810460ff16159067ffffffffffffffff165f811580156140e95750825b90505f8267ffffffffffffffff1660011480156141055750303b155b905081158015614113575080155b1561414a576040517ff92ee8a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b845467ffffffffffffffff19166001178555831561417e57845468ff00000000000000001916680100000000000000001785555b614187896150b6565b603c80546001600160a01b038a81166001600160a01b031992831617909255603d80548a8416908316179055603e805492891692909116919091179055604b6020908152616d607f08bf084be5767d8bb834edf3692454b23339ffcb9637cb06a941344461c3719855615a3c7fa616258785d57c6565e8210a7a01441f8018ea52e0ce6d2ea56b8099c64a4d75556149d47fed8fe69440ed7378c748b48bdf0a382a8b2b7193fd6134dd2b323f6392cefa4d5560035f9081526175307f18568898f741436c6378e97ae0a64b9a55f252371515c69c6b47e8a95ef4209455603f556005604090815562278d006041558051808201909152600181527f310000000000000000000000000000000000000000000000000000000000000091810191909152603b906142b79082615b9a565b50603a805460ff19166001179055831561431057845468ff000000000000000019168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b505050505050505050565b335f9081526020819052604090205460ff1615156001148061437557503361436a7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031690565b6001600160a01b0316145b6143c15760405162461bcd60e51b815260206004820152601460248201527f596f7520617265206e6f7420616c6c6f7765642e0000000000000000000000006044820152606401610bff565b5f5b8281101561442d578160015f8686858181106143e1576143e16159b3565b90506020020160208101906143f6919061514a565b6001600160a01b0316815260208101919091526040015f20805460ff191691151591909117905561442681615ad6565b90506143c3565b5060405181151581527f7dc357bd865f9219c544a8b0b14cb1583b26e3ffe765b3396ef2051d81a8de569060200160405180910390a1505050565b3361449a7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031690565b6001600160a01b031614611ff6576040517f118cdaa7000000000000000000000000000000000000000000000000000000008152336004820152602401610bff565b60026008540361452e5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610bff565b6002600855565b60405142808252907fe933406ce445ea24d84ca4529e514adc8926e62cdc8b5a67c568c9fd578f1a8a9060200160405180910390a15f9182526003602052604090912055565b5f818152600260205260408120544210801590610ee15750505f9081526003602052604090205442111590565b60605f826040516020016145bc9190615659565b60408051601f198184030181529181525f87815260076020529081209192508560048111156145ed576145ed615582565b60048111156145fe576145fe615582565b81526020808201929092526040015f9081208054600181018255908252919020016146298282615b9a565b5090505b9392505050565b815415611a925781545f19905f908190614650906001906159c7565b90505b8082116146cc578385838154811061466d5761466d6159b3565b905f5260205f20015403614683578192506146cc565b83858281548110614696576146966159b3565b905f5260205f200154036146ac578092506146cc565b816146b681615ad6565b92505080806146c490615cdf565b915050614653565b825f191461473f57845485906146e4906001906159c7565b815481106146f4576146f46159b3565b905f5260205f20015485848154811061470f5761470f6159b3565b905f5260205f2001819055508480548061472b5761472b615cf4565b600190038181905f5260205f20015f905590555b5050505050565b5f805f61475284611c34565b9050803410156147ca5760405162461bcd60e51b815260206004820152602160248201527f5061796f7574507572737569743a20696e76616c696420656e7472792066656560448201527f73000000000000000000000000000000000000000000000000000000000000006064820152608401610bff565b6147d481346159c7565b60445f8282546147e491906159a0565b925050819055508060455f8282546147fc91906159a0565b90915550505f93845260466020526040909320600301549293915050565b6040805160e081019091526001600160a01b0385168152602081016004815260208082018590526040808301859052606083018790525f60808401819052600160a090940193909352888352600582528083206001600160a01b03808a16855290835292208351815493166001600160a01b0319841681178255918401519092909183917fffffffffffffffffffffff0000000000000000000000000000000000000000001617600160a01b8360048111156148d8576148d8615582565b0217905550604082810151600183810191909155606084015160028401556080840151600384015560a0840151600484015560c0909301516005909201805460ff1916921515929092179091555f878152600660209081528282208054948501815582529081902090920180546001600160a01b0319166001600160a01b0388169081179091559051858152909187917f5d4e74d7fe247481ab545efef1bef98ba70cb6bedd0d08e2605409b0539e0661910160405180910390a35050505050565b5f8181526004602052604090819020805460ff19169055517f34cf8e99b6f44f9c706d7ef35b7b3af069a5797c286c9a2f28f0484de8f6bb99906111e49083815260200190565b5f828152604a6020526040812081836004811115614a0157614a01615582565b6004811115614a1257614a12615582565b81526020019081526020015f2054905092915050565b5f818310614a36578161462d565b5090919050565b5f826001600160a01b0316826040515f6040518083038185875af1925050503d805f8114614a86576040519150601f19603f3d011682016040523d82523d5f602084013e614a8b565b606091505b5050905080610eb8575f80fd5b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930080546001600160a01b031981166001600160a01b03848116918217845560405192169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a3505050565b5f8042603f54604051602001614b28929190918252602082015260400190565b60408051601f198184030181529190528051602090910120603f80549192505f614b5183615ad6565b909155509092915050565b42831015614bd25760405162461bcd60e51b815260206004820152603660248201527f5061796f75745075727375697454696d653a206f70656e696e672074696d652060448201527f6973206265666f72652063757272656e742074696d65000000000000000000006064820152608401610bff565b828211614c475760405162461bcd60e51b815260206004820152603660248201527f5061796f75745075727375697454696d653a20636c6f73696e672074696d652060448201527f6973206265666f7265206f70656e696e672074696d65000000000000000000006064820152608401610bff565b60408051848152602081018490527f36f8189c7d2c93ba984df4213bcb461ef59ac588902491237134e9f79ef10f1b910160405180910390a15f90815260026020908152604080832094909455600390529190912055565b80614ca98161457b565b614cf55760405162461bcd60e51b815260206004820152601b60248201527f5061796f75745075727375697454696d653a206e6f74206f70656e00000000006044820152606401610bff565b5f8281526004602052604090819020805460ff19166001179055517f820455334cc218aac711728d638cbbdf0f5f2b3a74787f5fe55ce8abd3142eab90614d3f9084815260200190565b60405180910390a15050565b5f81604051602001614d5d9190615d08565b6040516020818303038152906040528051906020012083604051602001614d849190615d08565b6040516020818303038152906040528051906020012014905092915050565b5f8381526007602052604081206060919081856004811115614dc757614dc7615582565b6004811115614dd857614dd8615582565b815260208101919091526040015f2054111561462d575f84815260076020526040812081856004811115614e0e57614e0e615582565b6004811115614e1f57614e1f615582565b81526020019081526020015f20600160075f8881526020019081526020015f205f876004811115614e5257614e52615582565b6004811115614e6357614e63615582565b815260208101919091526040015f2054614e7d91906159c7565b81548110614e8d57614e8d6159b3565b905f5260205f20018054614ea0906159da565b80601f0160208091040260200160405190810160405280929190818152602001828054614ecc906159da565b8015614f175780601f10614eee57610100808354040283529160200191614f17565b820191905f5260205f20905b815481529060010190602001808311614efa57829003601f168201915b505050505090505f83511115614f2a5750815b808060200190518101906111899190615d23565b614f478161328f565b1580614f6057505f8181526004602052604090205460ff165b614fb65760405162461bcd60e51b815260206004820152602160248201527f5061796f75745075727375697454696d653a20616c726561647920636c6f73656044820152601960fa1b6064820152608401610bff565b5f81815260036020526040902054821161505e5760405162461bcd60e51b815260206004820152604260248201527f5061796f75745075727375697454696d653a206e657720636c6f73696e67207460448201527f696d65206973206265666f72652063757272656e7420636c6f73696e6720746960648201527f6d65000000000000000000000000000000000000000000000000000000000000608482015260a401610bff565b5f818152600360209081526040918290205482519081529081018490527fb818c883d8b349292af8ecb2b89962bedcc279f3fb987752df3f2b05f40ec05c910160405180910390a15f90815260036020526040902055565b6150be6150c7565b611fe28161512e565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005468010000000000000000900460ff16611ff6576040517fd7e6bcf800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b613b8b6150c7565b6001600160a01b0381168114611fe2575f80fd5b5f6020828403121561515a575f80fd5b813561462d81615136565b5f60208284031215615175575f80fd5b5035919050565b8015158114611fe2575f80fd5b5f805f6060848603121561519b575f80fd5b83356151a68161517c565b92506020840135915060408401356151bd8161517c565b809150509250925092565b5f602082840312156151d8575f80fd5b81356005811061462d575f80fd5b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f1916810167ffffffffffffffff81118282101715615223576152236151e6565b604052919050565b5f67ffffffffffffffff821115615244576152446151e6565b5060051b60200190565b5f82601f83011261525d575f80fd5b8135602061527261526d8361522b565b6151fa565b82815260059290921b84018101918181019086841115615290575f80fd5b8286015b848110156152b45780356152a781615136565b8352918301918301615294565b509695505050505050565b5f805f805f60a086880312156152d3575f80fd5b85359450602086013567ffffffffffffffff808211156152f1575f80fd5b6152fd89838a0161524e565b95506040880135915080821115615312575f80fd5b61531e89838a0161524e565b94506060880135915080821115615333575f80fd5b506153408882890161524e565b92505060808601356153518161517c565b809150509295509295909350565b5f5b83811015615379578181015183820152602001615361565b50505f910152565b5f815180845261539881602086016020860161535f565b601f01601f19169290920160200192915050565b5f602080830181845280855180835260408601915060408160051b87010192508387015f5b828110156153ff57603f198886030184526153ed858351615381565b945092850192908501906001016153d1565b5092979650505050505050565b5f806040838503121561541d575f80fd5b50508035926020909101359150565b5f6101408c8352602081818501526154468285018e615381565b9150838203604085015261545a828d615381565b91508a60608501528960808501528860a08501528760c08501528660e085015283820361010085015261548d8287615381565b91508382036101208501528185518084528284019150828160051b8501018388015f5b838110156154de57601f198784030185526154cc838351615381565b948601949250908501906001016154b0565b505080955050505050509b9a5050505050505050505050565b5f8151808452602080850194508084015f5b8381101561552557815187529582019590820190600101615509565b509495945050505050565b602081525f61462d60208301846154f7565b602081525f61462d6020830184615381565b5f8060408385031215615565575f80fd5b82359150602083013561557781615136565b809150509250929050565b634e487b7160e01b5f52602160045260245ffd5b600581106155b257634e487b7160e01b5f52602160045260245ffd5b9052565b6001600160a01b038816815260e081016155d36020830189615596565b60408201969096526060810194909452608084019290925260a0830152151560c09091015292915050565b838152606081016156126020830185615596565b8215156040830152949350505050565b5f8151808452602080850194508084015f5b838110156155255781516001600160a01b031687529582019590820190600101615634565b602081525f61462d6020830184615622565b5f67ffffffffffffffff821115615684576156846151e6565b50601f01601f191660200190565b5f82601f8301126156a1575f80fd5b81356156af61526d8261566b565b8181528460208386010111156156c3575f80fd5b816020850160208301375f918101602001919091529392505050565b5f805f805f805f805f6101208a8c0312156156f8575f80fd5b8935985060208a013567ffffffffffffffff80821115615716575f80fd5b6157228d838e01615692565b995060408c0135915080821115615737575f80fd5b506157448c828d01615692565b999c989b5098996060810135995060808101359860a0820135985060c0820135975060e0820135965061010090910135945092505050565b5f805f806080858703121561578f575f80fd5b84359350602085013567ffffffffffffffff808211156157ad575f80fd5b6157b988838901615692565b945060408701359150808211156157ce575f80fd5b506157db87828801615692565b949793965093946060013593505050565b606081525f6157fe6060830186615622565b82810360208401526158108186615622565b90508281036040840152613a8b8185615622565b60a081525f61583660a08301886154f7565b828103602084015261584881886154f7565b9050828103604084015261585c81876154f7565b9050828103606084015261587081866154f7565b9050828103608084015261588481856154f7565b98975050505050505050565b5f805f80608085870312156158a3575f80fd5b5050823594602084013594506040840135936060013592509050565b5f805f80608085870312156158d2575f80fd5b84356158dd81615136565b935060208501356158ed81615136565b925060408501356158fd81615136565b9150606085013561590d81615136565b939692955090935050565b5f805f6040848603121561592a575f80fd5b833567ffffffffffffffff80821115615941575f80fd5b818601915086601f830112615954575f80fd5b813581811115615962575f80fd5b8760208260051b8501011115615976575f80fd5b602092830195509350508401356151bd8161517c565b634e487b7160e01b5f52601160045260245ffd5b80820180821115610ee157610ee161598c565b634e487b7160e01b5f52603260045260245ffd5b81810381811115610ee157610ee161598c565b600181811c908216806159ee57607f821691505b602082108103615a0c57634e487b7160e01b5f52602260045260245ffd5b50919050565b5f82601f830112615a21575f80fd5b8151615a2f61526d8261566b565b818152846020838601011115615a43575f80fd5b611c4f82602083016020870161535f565b5f805f60608486031215615a66575f80fd5b835167ffffffffffffffff80821115615a7d575f80fd5b615a8987838801615a12565b94506020860151915080821115615a9e575f80fd5b615aaa87838801615a12565b93506040860151915080821115615abf575f80fd5b50615acc86828701615a12565b9150509250925092565b5f60018201615ae757615ae761598c565b5060010190565b5f60ff821660ff8103615b0357615b0361598c565b60010192915050565b5f60208284031215615b1c575f80fd5b5051919050565b5f60208284031215615b33575f80fd5b815161462d8161517c565b8082028115828204841417610ee157610ee161598c565b601f821115610eb8575f81815260208120601f850160051c81016020861015615b7b5750805b601f850160051c820191505b81811015612d4157828155600101615b87565b815167ffffffffffffffff811115615bb457615bb46151e6565b615bc881615bc284546159da565b84615b55565b602080601f831160018114615bfb575f8415615be45750858301515b5f19600386901b1c1916600185901b178555612d41565b5f85815260208120601f198616915b82811015615c2957888601518255948401946001909101908401615c0a565b5085821015615c4657878501515f19600388901b60f8161c191681555b5050505050600190811b01905550565b5f82615c7057634e487b7160e01b5f52601260045260245ffd5b500490565b805169ffffffffffffffffffff81168114615c8e575f80fd5b919050565b5f805f805f60a08688031215615ca7575f80fd5b615cb086615c75565b9450602086015193506040860151925060608601519150615cd360808701615c75565b90509295509295909350565b5f81615ced57615ced61598c565b505f190190565b634e487b7160e01b5f52603160045260245ffd5b5f8251615d1981846020870161535f565b9190910192915050565b5f6020808385031215615d34575f80fd5b825167ffffffffffffffff811115615d4a575f80fd5b8301601f81018513615d5a575f80fd5b8051615d6861526d8261522b565b81815260059190911b82018301908381019087831115615d86575f80fd5b928401925b82841015615dad578351615d9e81615136565b82529284019290840190615d8b565b97965050505050505056fea264697066735822122023a01689af86bccb30548863bf243f36a7fd96861fb531ff2e999b74283a825164736f6c63430008140033

Deployed Bytecode

0x60806040526004361061033e575f3560e01c80637cb414eb116101ad578063b7c58d7a116100ea578063e1d69fe61161008e578063f54140231161006b578063f541402314610aff578063f8c8765e14610b1e578063fb2f349214610b3d578063fe575a8714610b5c57005b8063e1d69fe614610a96578063ebb32ec014610ac1578063f2fde38b14610ae057005b8063bea87817116100c7578063bea8781714610a10578063c27a500d14610a35578063c3610f0c14610a49578063dffb6b6714610a6857005b8063b7c58d7a146109b3578063b89596fa146109d2578063bddc99b4146109f157005b8063966722d211610151578063b0a750171161012e578063b0a7501714610900578063b38a397b14610947578063b43c789514610966578063b7086cc51461098557005b8063966722d2146108ad5780639e4146e1146108cc578063a54cd4f7146108eb57005b80638a0cf9e91161018a5780638a0cf9e9146107ef5780638da5cb5b1461081b5780638fa2a9031461085757806395877f781461088e57005b80637cb414eb146107835780637e44d2cc146107b15780638486758e146107d057005b80633ba86c441161027b578063715018a61161021f5780637491a0b3116101fc5780637491a0b3146106ed5780637706130c1461070c578063790692961461072b5780637917be031461074a57005b8063715018a61461068357806371de2ffc14610697578063741bef1a146106b657005b80635d31f873116102585780635d31f873146105865780635f629466146105b4578063651b8226146106365780636e2b54ee1461066457005b80633ba86c44146105315780634ea486a01461054657806354fd4d501461056557005b8063199a28cf116102e257806323bb7211116102bf57806323bb7211146104a95780632ca10898146104bc5780632e3740e7146104f15780633612280f1461051057005b8063199a28cf146104625780631c3e6ee6146104815780631e216c431461049657005b8063158ef93e1161031b578063158ef93e146103c357806316161e6e146103ec578063168e8ec91461040b57806317ea277f1461043657005b806308af4d88146103475780630ebc5f2a14610366578063124bcf6d146103a457005b3661034557005b005b348015610352575f80fd5b5061034561036136600461514a565b610b93565b348015610371575f80fd5b50610391610380366004615165565b5f9081526002602052604090205490565b6040519081526020015b60405180910390f35b3480156103af575f80fd5b506103456103be366004615189565b610c2b565b3480156103ce575f80fd5b50603a546103dc9060ff1681565b604051901515815260200161039b565b3480156103f7575f80fd5b506103dc610406366004615165565b610ebd565b348015610416575f80fd5b506103916104253660046151c8565b604b6020525f908152604090205481565b348015610441575f80fd5b506104556104503660046152bf565b610ee7565b60405161039b91906153ac565b34801561046d575f80fd5b5061034561047c36600461514a565b611192565b34801561048c575f80fd5b50610391603f5481565b6103dc6104a436600461540c565b6111ef565b6103456104b7366004615165565b611332565b3480156104c7575f80fd5b506104db6104d6366004615165565b611523565b60405161039b9a9998979695949392919061542c565b3480156104fc575f80fd5b5061034561050b36600461540c565b611a0a565b34801561051b575f80fd5b50610524611a96565b60405161039b9190615530565b34801561053c575f80fd5b5061039160415481565b348015610551575f80fd5b50610391610560366004615165565b611c34565b348015610570575f80fd5b50610579611c57565b60405161039b9190615542565b348015610591575f80fd5b506103dc6105a0366004615165565b60476020525f908152604090205460ff1681565b3480156105bf575f80fd5b506106236105ce366004615554565b600560208181525f938452604080852090915291835291208054600182015460028301546003840154600485015494909501546001600160a01b03841695600160a01b90940460ff9081169593949293911687565b60405161039b97969594939291906155b6565b348015610641575f80fd5b50610655610650366004615554565b611ce3565b60405161039b939291906155fe565b34801561066f575f80fd5b5061034561067e366004615165565b611f26565b34801561068e575f80fd5b50610345611fe5565b3480156106a2575f80fd5b506103456106b1366004615165565b611ff8565b3480156106c1575f80fd5b50603d546106d5906001600160a01b031681565b6040516001600160a01b03909116815260200161039b565b3480156106f8575f80fd5b5061034561070736600461514a565b612306565b348015610717575f80fd5b5061034561072636600461514a565b61235c565b348015610736575f80fd5b50610345610745366004615165565b61259a565b348015610755575f80fd5b506103dc610764366004615554565b604960209081525f928352604080842090915290825290205460ff1681565b34801561078e575f80fd5b506103dc61079d366004615165565b60486020525f908152604090205460ff1681565b3480156107bc575f80fd5b50603c546106d5906001600160a01b031681565b3480156107db575f80fd5b50603e546106d5906001600160a01b031681565b3480156107fa575f80fd5b5061080e610809366004615165565b6125e2565b60405161039b9190615659565b348015610826575f80fd5b507f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b03166106d5565b348015610862575f80fd5b506103dc61087136600461514a565b6001600160a01b03165f9081526020819052604090205460ff1690565b348015610899575f80fd5b506103456108a836600461514a565b61264b565b3480156108b8575f80fd5b506103dc6108c73660046156df565b6126a1565b3480156108d7575f80fd5b506103456108e6366004615165565b6129fe565b3480156108f6575f80fd5b5061039160405481565b34801561090b575f80fd5b5061093261091a366004615165565b604c6020525f90815260409020805460019091015482565b6040805192835260208301919091520161039b565b348015610952575f80fd5b50610345610961366004615165565b612a84565b348015610971575f80fd5b5061034561098036600461577c565b612d49565b348015610990575f80fd5b506109a461099f366004615165565b612e8b565b60405161039b939291906157ec565b3480156109be575f80fd5b506103456109cd36600461514a565b6131be565b3480156109dd575f80fd5b506103456109ec36600461540c565b613258565b3480156109fc575f80fd5b506103dc610a0b366004615165565b61328f565b348015610a1b575f80fd5b50610a246132ba565b60405161039b959493929190615824565b348015610a40575f80fd5b50610524613986565b348015610a54575f80fd5b50610391610a63366004615165565b6139dc565b348015610a73575f80fd5b506103dc610a82366004615165565b60046020525f908152604090205460ff1681565b348015610aa1575f80fd5b50610391610ab0366004615165565b5f9081526003602052604090205490565b348015610acc575f80fd5b50610345610adb366004615890565b613a95565b348015610aeb575f80fd5b50610345610afa36600461514a565b613b83565b348015610b0a575f80fd5b50610345610b19366004615165565b613bd6565b348015610b29575f80fd5b50610345610b383660046158bf565b61409f565b348015610b48575f80fd5b50610345610b57366004615918565b61431b565b348015610b67575f80fd5b506103dc610b7636600461514a565b6001600160a01b03165f9081526001602052604090205460ff1690565b610b9b614468565b6001600160a01b0381165f9081526020819052604090205460ff1615610c085760405162461bcd60e51b815260206004820152601f60248201527f546865206164647265737320697320616c726561647920616c6c6f7765642e0060448201526064015b60405180910390fd5b6001600160a01b03165f908152602081905260409020805460ff19166001179055565b610c33614468565b610c3b6144dc565b5f8281526046602052604090206001600882015460ff166002811115610c6357610c63615582565b03610cd65760405162461bcd60e51b815260206004820152602660248201527f5061796f7574507572737569743a206576656e7420616c72656164792063616e60448201527f63656c6c656400000000000000000000000000000000000000000000000000006064820152608401610bff565b604054610ce2846125e2565b5110158015610cef575081155b15610d5457610cfd8361328f565b15610d545760405162461bcd60e51b815260206004820152602160248201527f5061796f75745075727375697454696d653a20616c726561647920636c6f73656044820152601960fa1b6064820152608401610bff565b610d5d83614535565b5f83815260036020526040902054600582015560088101805460ff191660011790558315610ddd5760405180604001604052808260060154815260200160415442610da891906159a0565b90525f848152604c6020908152604080832084518155938201516001909401939093556048905220805460ff19168515151790555b603e546040517f3fc3b182000000000000000000000000000000000000000000000000000000008152600481018590526001600160a01b0390911690633fc3b182906024015f604051808303815f87803b158015610e39575f80fd5b505af1158015610e4b573d5f803e3d5ffd5b50505050604051610e6b906810d05390d15313115160ba1b815260090190565b6040518091039020837f64adf624f09c3abf7f8ff522d02f9297d5f69180632098d84933c1f2ec4e174742604051610ea591815260200190565b60405180910390a350610eb86001600855565b505050565b5f610ec78261457b565b8015610ee157505f8281526004602052604090205460ff16155b92915050565b6060610ef1614468565b610ef96144dc565b85610f038161328f565b610f5b5760405162461bcd60e51b8152602060048201526024808201527f5061796f75745075727375697454696d653a206576656e7420696e2070726f676044820152637265737360e01b6064820152608401610bff565b5f8781526047602052604090205460ff1615610fdf5760405162461bcd60e51b815260206004820152602760248201527f5061796f7574507572737569743a206576656e74206c6561646572626f61726460448201527f206c6f636b6564000000000000000000000000000000000000000000000000006064820152608401610bff565b8615801590610ffa57505f8781526046602052604090205415155b6110465760405162461bcd60e51b815260206004820152601f60248201527f5061796f7574507572737569743a206576656e7420696420696e76616c6964006044820152606401610bff565b604080516003808252608082019092525f91816020015b606081526020019060019003908161105d57905050905061107f885f896145a8565b815f81518110611091576110916159b3565b60200260200101819052506110a8886001886145a8565b816001815181106110bb576110bb6159b3565b60200260200101819052506110d2886002876145a8565b816002815181106110e5576110e56159b3565b602090810291909101015291506110fd604388614634565b5f8781526046602052604090819020600801805460ff19166002179055516810d3d354131155115160ba1b81526009016040518091039020877f64adf624f09c3abf7f8ff522d02f9297d5f69180632098d84933c1f2ec4e17474260405161116791815260200190565b60405180910390a3821561117e5761117e87612a84565b506111896001600855565b95945050505050565b61119a614468565b603e80546001600160a01b0319166001600160a01b0383169081179091556040519081527fc0a15db954f8aded5cda5092ae26da70558a30c4e12c48e77d87564c3197edf5906020015b60405180910390a150565b5f6111f8614468565b5f8281526046602052604081206004015490036112575760405162461bcd60e51b815260206004820152601f60248201527f5061796f7574507572737569743a20696e76616c6964206576656e74206964006044820152606401610bff565b823410156112cd5760405162461bcd60e51b815260206004820152602260248201527f5061796f7574507572737569743a20696e73756666696369656e7420616d6f7560448201527f6e740000000000000000000000000000000000000000000000000000000000006064820152608401610bff565b6112d783346159c7565b60445f8282546112e791906159a0565b925050819055508260455f8282546112ff91906159a0565b90915550505f82815260466020526040812060060180548592906113249084906159a0565b909155506001949350505050565b8061133c8161457b565b6113885760405162461bcd60e51b815260206004820152601b60248201527f5061796f75745075727375697454696d653a206e6f74206f70656e00000000006044820152606401610bff565b5f82815260046020526040902054829060ff161561140e5760405162461bcd60e51b815260206004820152602260248201527f5061796f75745075727375697454696d653a206576656e74206973207061757360448201527f65640000000000000000000000000000000000000000000000000000000000006064820152608401610bff565b5f8381526005602081815260408084203385529091529091200154839060ff16156114a15760405162461bcd60e51b815260206004820152603360248201527f5061796f7574507572737569743a20616c72656164792072656769737465726560448201527f6420666f722063757272656e74206576656e74000000000000000000000000006064820152608401610bff565b6114a96144dc565b5f806114b486614746565b5f888152604660205260408120600601805493955091935084926114d99084906159a0565b90915550505f86815260466020526040812060070180548392906114fe9084906159a0565b909155506115119050863342858561481a565b505061151d6001600855565b50505050565b5f6060805f805f805f6060805f60465f8d81526020019081526020015f20604051806101200160405290815f8201548152602001600182018054611566906159da565b80601f0160208091040260200160405190810160405280929190818152602001828054611592906159da565b80156115dd5780601f106115b4576101008083540402835291602001916115dd565b820191905f5260205f20905b8154815290600101906020018083116115c057829003601f168201915b505050505081526020016002820180546115f6906159da565b80601f0160208091040260200160405190810160405280929190818152602001828054611622906159da565b801561166d5780601f106116445761010080835404028352916020019161166d565b820191905f5260205f20905b81548152906001019060200180831161165057829003601f168201915b505050918352505060038201546020820152600482015460408201526005820154606082015260068201546080820152600782015460a0820152600882015460c09091019060ff1660028111156116c6576116c6615582565b60028111156116d7576116d7615582565b905250905060605f82610100015160028111156116f6576116f6615582565b0361182f575060408051808201909152600681526541435449564560d01b602082015260808201515f0361175e575060408051808201909152600881527f4e4f54455849535400000000000000000000000000000000000000000000000060208201526118b3565b5f8d81526004602052604090205460ff1615611797575060408051808201909152600681526514105554d15160d21b60208201526118b3565b5f8d8152600260205260409020544210156117e6575060408051808201909152600781527f50454e44494e470000000000000000000000000000000000000000000000000060208201526118b3565b6117ef8d61328f565b1561182a575060408051808201909152600781527f50524f434553530000000000000000000000000000000000000000000000000060208201525b6118b3565b6002826101000151600281111561184857611848615582565b03611873575060408051808201909152600981526810d3d354131155115160ba1b60208201526118b3565b6001826101000151600281111561188c5761188c615582565b036118b3575060408051808201909152600981526810d05390d15313115160ba1b60208201525b604080516003808252608082019092525f91816020015b60608152602001906001900390816118ca579050509050603e5f9054906101000a90046001600160a01b03166001600160a01b0316630222c7d78f6040518263ffffffff1660e01b815260040161192391815260200190565b5f60405180830381865afa15801561193d573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526119649190810190615a54565b835f81518110611976576119766159b3565b6020026020010184600181518110611990576119906159b3565b60200260200101856002815181106119aa576119aa6159b3565b60200260200101839052839052839052505050825f015183602001518460400151856060015186608001518760a001518860c001518960e0015189899c509c509c509c509c509c509c509c509c509c505050509193959799509193959799565b611a12614468565b611a1a6144dc565b8015611a2a57611a2a8183613258565b611a338261499a565b6040516541435449564560d01b81526006015b6040518091039020827f64adf624f09c3abf7f8ff522d02f9297d5f69180632098d84933c1f2ec4e174742604051611a8091815260200190565b60405180910390a3611a926001600855565b5050565b60435460609067ffffffffffffffff811115611ab457611ab46151e6565b604051908082528060200260200182016040528015611add578160200160208202803683370190505b5090505f805f5b60435460ff82161015611b8257611b1860438260ff1681548110611b0a57611b0a6159b3565b905f5260205f200154610ebd565b15611b6b5760438160ff1681548110611b3357611b336159b3565b905f5260205f200154848481518110611b4e57611b4e6159b3565b602090810291909101015282611b6381615ad6565b935050611b70565b600191505b80611b7a81615aee565b915050611ae4565b508015611c2f575f8267ffffffffffffffff811115611ba357611ba36151e6565b604051908082528060200260200182016040528015611bcc578160200160208202803683370190505b5090505f5b838160ff161015611c2b57848160ff1681518110611bf157611bf16159b3565b6020026020010151828260ff1681518110611c0e57611c0e6159b3565b602090810291909101015280611c2381615aee565b915050611bd1565b5092505b505090565b5f8181526046602052604081206003015481611c4f826139dc565b949350505050565b603b8054611c64906159da565b80601f0160208091040260200160405190810160405280929190818152602001828054611c90906159da565b8015611cdb5780601f10611cb257610100808354040283529160200191611cdb565b820191905f5260205f20905b815481529060010190602001808311611cbe57829003601f168201915b505050505081565b5f805f805f80611cf288612e8b565b805192955090935091505f9060049015611d84575f5b83518160ff161015611d8257896001600160a01b0316848260ff1681518110611d3357611d336159b3565b60200260200101516001600160a01b031603611d7057838160ff1681518110611d5e57611d5e6159b3565b602002602001015192505f9150611d82565b80611d7a81615aee565b915050611d08565b505b6004816004811115611d9857611d98615582565b03611e13575f5b8551811015611e1157896001600160a01b0316868281518110611dc457611dc46159b3565b60200260200101516001600160a01b031603611dff57858181518110611dec57611dec6159b3565b6020026020010151925060019150611e11565b80611e0981615ad6565b915050611d9f565b505b6004816004811115611e2757611e27615582565b03611ea2575f5b8451811015611ea057896001600160a01b0316858281518110611e5357611e536159b3565b60200260200101516001600160a01b031603611e8e57848181518110611e7b57611e7b6159b3565b6020026020010151925060029150611ea0565b80611e9881615ad6565b915050611e2e565b505b6004816004811115611eb657611eb6615582565b03611ecd575f97509550869450611f1f9350505050565b611eed611eda8b836149e1565b5f8c8152604c6020526040902054614a28565b5f8b81526049602090815260408083206001600160a01b038e16845290915290205490985090965060ff169450505050505b9250925092565b611f2e614468565b5f818152604c6020526040902060010154421015611fb45760405162461bcd60e51b815260206004820152603860248201527f5061796f7574507572737569743a206576656e742072657761726473206c6f6360448201527f6b656420666f722077696e6e65727320746f20636c61696d00000000000000006064820152608401610bff565b603c545f828152604c6020526040902054611fe2916001600160a01b031690611fdd9047614a28565b614a3d565b50565b611fed614468565b611ff65f614a98565b565b6120006144dc565b5f8181526048602052604090205460ff16801561202d57505f818152604c60205260409020600101544211155b61209f5760405162461bcd60e51b815260206004820152602360248201527f5061796f7574507572737569743a206e6f20726566756e647320617661696c6160448201527f626c6500000000000000000000000000000000000000000000000000000000006064820152608401610bff565b5f81815260496020908152604080832033845290915290205460ff16156121085760405162461bcd60e51b815260206004820152601e60248201527f5061796f7574507572737569743a20616c726561647920636c61696d656400006044820152606401610bff565b5f8181526005602090815260408083203384528252808320815160e0810190925280546001600160a01b03811683529192909190830190600160a01b900460ff16600481111561215a5761215a615582565b600481111561216b5761216b615582565b81526001820154602082015260028201546040820152600382015460608201526004820154608082015260059091015460ff16151560a09091015260c081015190915080156121c3575080516001600160a01b031633145b80156121d8575080516001600160a01b031615155b6122245760405162461bcd60e51b815260206004820152601e60248201527f5061796f7574507572737569743a20696e76616c6964206164647265737300006044820152606401610bff565b5f828152604960209081526040808320338452909152808220805460ff191660011790558201516122559047614a28565b5f848152604c60205260408120805492935083929091906122779084906159c7565b9091555050806122ef5760405162461bcd60e51b815260206004820152603960248201527f5061796f7574507572737569743a20696e73756666696369656e742066756e6460448201527f732c20706c6561736520636f6e7461637420737570706f7274000000000000006064820152608401610bff565b6122fa335b82614a3d565b5050611fe26001600855565b61230e614468565b603c80546001600160a01b0319166001600160a01b0383169081179091556040519081527f5748080475cb42a3ebe2b436c56efe7b4c51ee26f4bf66c2f6906fd3222edc84906020016111e4565b612364614468565b6001600160a01b03811615612500576040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201525f906001600160a01b038316906370a0823190602401602060405180830381865afa1580156123d0573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906123f49190615b0c565b90505f811161246b5760405162461bcd60e51b815260206004820152602c60248201527f5061796f7574507572737569743a20696e73756666696369656e7420636f6e7460448201527f726163742062616c616e636500000000000000000000000000000000000000006064820152608401610bff565b603c546040517fa9059cbb0000000000000000000000000000000000000000000000000000000081526001600160a01b039182166004820152602481018390529083169063a9059cbb906044016020604051808303815f875af11580156124d4573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906124f89190615b23565b611a92575f80fd5b5f47116125755760405162461bcd60e51b815260206004820152603760248201527f5061796f7574507572737569743a20696e73756666696369656e74206164646960448201527f74696f6e616c20636f6e74726163742062616c616e63650000000000000000006064820152608401610bff565b603c54604454612593916001600160a01b031690611fdd9047614a28565b5f60445550565b6125a2614468565b6125af8162015180615b3e565b6041556040518181527fc4ba5e42712b0d178f421c5e23f5376bece3c36990d44241ec7a934f37542e7d906020016111e4565b5f8181526006602090815260409182902080548351818402810184019094528084526060939283018282801561263f57602002820191905f5260205f20905b81546001600160a01b03168152600190910190602001808311612621575b50505050509050919050565b612653614468565b603d80546001600160a01b0319166001600160a01b0383169081179091556040519081527fe5b20b8497e4f3e2435ef9c20e2e26b47497ee13745ce1c681ad6640653119e6906020016111e4565b335f9081526020819052604081205460ff161515600114806126fb5750336126f07f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031690565b6001600160a01b0316145b6127475760405162461bcd60e51b815260206004820152601460248201527f596f7520617265206e6f7420616c6c6f7765642e0000000000000000000000006044820152606401610bff565b61274f6144dc565b5f8a6127625761275d614b08565b612764565b8a5b5f81815260466020526040902054909150156127e85760405162461bcd60e51b815260206004820152602660248201527f5061796f7574507572737569743a206576656e7420696420616c72656164792060448201527f65786973747300000000000000000000000000000000000000000000000000006064820152608401610bff565b6127f3878783614b5c565b6040518061012001604052808281526020018b81526020018a81526020018981526020018881526020018781526020015f81526020015f81526020015f600281111561284157612841615582565b90525f8281526046602090815260409091208251815590820151600182019061286a9082615b9a565b506040820151600282019061287f9082615b9a565b50606082015160038201556080820151600482015560a0820151600582015560c0820151600682015560e0820151600782015561010082015160088201805460ff191660018360028111156128d6576128d6615582565b0217905550506043805460018181019092557f9690ad99d6ce244efa8a0f6c2d04036d3b33a9474db32a71b71135c695102793018390556042805491820181555f527f38dfe4635b27babeca8be38d3b448cb5161a639b899a14825ba9c8d7892eb8c301829055508415158061294b57508315155b8061295557508215155b156129e257603e546040517f259481c7000000000000000000000000000000000000000000000000000000008152600481018390526024810187905260448101869052606481018590526001600160a01b039091169063259481c7906084015f604051808303815f87803b1580156129cb575f80fd5b505af11580156129dd573d5f803e3d5ffd5b505050505b60019150506129f16001600855565b9998505050505050505050565b612a06614468565b80612a108161457b565b612a5c5760405162461bcd60e51b815260206004820152601b60248201527f5061796f75745075727375697454696d653a206e6f74206f70656e00000000006044820152606401610bff565b612a646144dc565b612a6d82614c9f565b6040516514105554d15160d21b8152600601611a46565b612a8c614468565b5f805f612a9884612e8b565b9250925092505f83511180612aad57505f8251115b8015612ab957505f8151115b612b2a5760405162461bcd60e51b8152602060048201526024808201527f5061796f7574507572737569743a206c6561646572626f617264206e6f74206660448201527f6f756e64000000000000000000000000000000000000000000000000000000006064820152608401610bff565b5f848152604760209081526040808320805460ff191660011790556046825282206006015460038352604b9091527f18568898f741436c6378e97ae0a64b9a55f252371515c69c6b47e8a95ef4209454909190620186a090612b8c9084615b3e565b612b969190615c56565b5f8052604b6020527f08bf084be5767d8bb834edf3692454b23339ffcb9637cb06a941344461c3719854909150620186a090612bd29084615b3e565b612bdc9190615c56565b5f878152604a602090815260408083208380529091529020558451612c01575f612c51565b845160015f52604b6020527fa616258785d57c6565e8210a7a01441f8018ea52e0ce6d2ea56b8099c64a4d7554620186a090612c3d9085615b3e565b612c479190615c56565b612c519190615c56565b5f878152604a60209081526040808320600184529091529020558351612c77575f612cc7565b835160025f52604b6020527fed8fe69440ed7378c748b48bdf0a382a8b2b7193fd6134dd2b323f6392cefa4d54620186a090612cb39085615b3e565b612cbd9190615c56565b612cc79190615c56565b5f878152604a60209081526040808320600284529091529081902091909155805180820190915280612cf983856159c7565b815260200160415442612d0c91906159a0565b90525f878152604c6020908152604090912082518155910151600190910155603c54612d41906001600160a01b031682614a3d565b505050505050565b335f9081526020819052604090205460ff16151560011480612da3575033612d987f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031690565b6001600160a01b0316145b612def5760405162461bcd60e51b815260206004820152601460248201527f596f7520617265206e6f7420616c6c6f7765642e0000000000000000000000006044820152606401610bff565b612df76144dc565b8315612e11575f8181526046602052604090206003018490555b612e298360405180602001604052805f815250614d4b565b612e49575f818152604660205260409020600101612e478482615b9a565b505b612e618260405180602001604052805f815250614d4b565b612e81575f818152604660205260409020600201612e7f8382615b9a565b505b61151d6001600855565b5f81815260076020908152604080832083805282528083208054825181850281018501909352808352606094859485949193919290849084015b82821015612f6d578382905f5260205f20018054612ee2906159da565b80601f0160208091040260200160405190810160405280929190818152602001828054612f0e906159da565b8015612f595780601f10612f3057610100808354040283529160200191612f59565b820191905f5260205f20905b815481529060010190602001808311612f3c57829003601f168201915b505050505081526020019060010190612ec5565b5050505f8781526007602090815260408083206001845282528083208054825181850281018501909352808352959650929490935090849084015b82821015613050578382905f5260205f20018054612fc5906159da565b80601f0160208091040260200160405190810160405280929190818152602001828054612ff1906159da565b801561303c5780601f106130135761010080835404028352916020019161303c565b820191905f5260205f20905b81548152906001019060200180831161301f57829003601f168201915b505050505081526020019060010190612fa8565b5050505f8881526007602090815260408083206002845282528083208054825181850281018501909352808352959650929490935090849084015b82821015613133578382905f5260205f200180546130a8906159da565b80601f01602080910402602001604051908101604052809291908181526020018280546130d4906159da565b801561311f5780601f106130f65761010080835404028352916020019161311f565b820191905f5260205f20905b81548152906001019060200180831161310257829003601f168201915b50505050508152602001906001019061308b565b5050505090505f8351111561317657613173875f856001875161315691906159c7565b81518110613166576131666159b3565b6020026020010151614da3565b93505b81511561319557613192876001846001865161315691906159c7565b95505b8051156131b4576131b1876002836001855161315691906159c7565b94505b5050509193909250565b6131c6614468565b6001600160a01b0381165f9081526020819052604090205460ff161515600114610c085760405162461bcd60e51b815260206004820152602360248201527f546865206164647265737320697320616c7265616479206e6f7420616c6c6f7760448201527f65642e00000000000000000000000000000000000000000000000000000000006064820152608401610bff565b613260614468565b6132686144dc565b6132728282614f3e565b5f818152604660205260409020600501829055611a926001600855565b5f8181526003602052604081205442118015610ee15750505f90815260036020526040902054151590565b60608060608060605f60428054905067ffffffffffffffff8111156132e1576132e16151e6565b60405190808252806020026020018201604052801561330a578160200160208202803683370190505b506042549091505f9067ffffffffffffffff81111561332b5761332b6151e6565b604051908082528060200260200182016040528015613354578160200160208202803683370190505b506042549091505f9067ffffffffffffffff811115613375576133756151e6565b60405190808252806020026020018201604052801561339e578160200160208202803683370190505b506042549091505f9067ffffffffffffffff8111156133bf576133bf6151e6565b6040519080825280602002602001820160405280156133e8578160200160208202803683370190505b506042549091505f9067ffffffffffffffff811115613409576134096151e6565b604051908082528060200260200182016040528015613432578160200160208202803683370190505b5090505f80808080805b60425460ff82161015613672575f60428260ff1681548110613460576134606159b3565b5f91825260209091200154905060025f8281526046602052604090206008015460ff16600281111561349457613494615582565b036134c457808c886134a581615ad6565b9950815181106134b7576134b76159b3565b6020026020010181815250505b60015f8281526046602052604090206008015460ff1660028111156134eb576134eb615582565b0361351b57808b876134fc81615ad6565b98508151811061350e5761350e6159b3565b6020026020010181815250505b5f8181526004602052604090205460ff16801561355a57505f8181526046602052604081206008015460ff16600281111561355857613558615582565b145b1561358a57808a8661356b81615ad6565b97508151811061357d5761357d6159b3565b6020026020010181815250505b5f81815260026020526040902054421080156135c857505f8181526046602052604081206008015460ff1660028111156135c6576135c6615582565b145b156135f8578089856135d981615ad6565b9650815181106135eb576135eb6159b3565b6020026020010181815250505b6136018161328f565b801561362f57505f8181526046602052604081206008015460ff16600281111561362d5761362d615582565b145b1561365f5780888461364081615ad6565b955081518110613652576136526159b3565b6020026020010181815250505b508061366a81615aee565b91505061343c565b508467ffffffffffffffff81111561368c5761368c6151e6565b6040519080825280602002602001820160405280156136b5578160200160208202803683370190505b509e508367ffffffffffffffff8111156136d1576136d16151e6565b6040519080825280602002602001820160405280156136fa578160200160208202803683370190505b509d508267ffffffffffffffff811115613716576137166151e6565b60405190808252806020026020018201604052801561373f578160200160208202803683370190505b509c508167ffffffffffffffff81111561375b5761375b6151e6565b604051908082528060200260200182016040528015613784578160200160208202803683370190505b509b508067ffffffffffffffff8111156137a0576137a06151e6565b6040519080825280602002602001820160405280156137c9578160200160208202803683370190505b509a5050505050505f5b8a51811015613825578581815181106137ee576137ee6159b3565b60200260200101518b8281518110613808576138086159b3565b60209081029190910101528061381d81615ad6565b9150506137d3565b505f5b895181101561387a57848181518110613843576138436159b3565b60200260200101518a828151811061385d5761385d6159b3565b60209081029190910101528061387281615ad6565b915050613828565b505f5b88518110156138cf57838181518110613898576138986159b3565b60200260200101518982815181106138b2576138b26159b3565b6020908102919091010152806138c781615ad6565b91505061387d565b505f5b8751811015613924578281815181106138ed576138ed6159b3565b6020026020010151888281518110613907576139076159b3565b60209081029190910101528061391c81615ad6565b9150506138d2565b505f5b865181101561397957818181518110613942576139426159b3565b602002602001015187828151811061395c5761395c6159b3565b60209081029190910101528061397181615ad6565b915050613927565b5050505050509091929394565b606060428054806020026020016040519081016040528092919081815260200182805480156139d257602002820191905f5260205f20905b8154815260200190600101908083116139be575b5050505050905090565b5f80603d5f9054906101000a90046001600160a01b03166001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015613a2e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613a529190615c93565b5050509150505f816402540be400613a6a9190615b3e565b9050835f82613a8183670de0b6b3a7640000615b3e565b613a8b9190615c56565b9695505050505050565b613a9d614468565b604b60209081527f08bf084be5767d8bb834edf3692454b23339ffcb9637cb06a941344461c371988590557fa616258785d57c6565e8210a7a01441f8018ea52e0ce6d2ea56b8099c64a4d758490557fed8fe69440ed7378c748b48bdf0a382a8b2b7193fd6134dd2b323f6392cefa4d83905560035f527f18568898f741436c6378e97ae0a64b9a55f252371515c69c6b47e8a95ef420948290556040805186815291820185905281810184905260608201839052517f0d3de384c23ffe70860aed6b0034da97c6be2e6b03a6448171c1d4acfb9e854e9181900360800190a150505050565b613b8b614468565b6001600160a01b038116613bcd576040517f1e4fbdf70000000000000000000000000000000000000000000000000000000081525f6004820152602401610bff565b611fe281614a98565b613bde6144dc565b80613be88161328f565b613c405760405162461bcd60e51b8152602060048201526024808201527f5061796f75745075727375697454696d653a206576656e7420696e2070726f676044820152637265737360e01b6064820152608401610bff565b5f82815260496020908152604080832033845290915290205460ff1615613ca95760405162461bcd60e51b815260206004820152601e60248201527f5061796f7574507572737569743a20616c726561647920636c61696d656400006044820152606401610bff565b5f8281526005602090815260408083203384528252808320858452604c9092528220600101549091906004904211613cf0575f80613ce78733611ce3565b50909450925050505b5f8211613d655760405162461bcd60e51b815260206004820152603460248201527f5061796f7574507572737569743a206e6f20636c61696d20617661696c61626c60448201527f65206f7220616c726561647920636c61696d65640000000000000000000000006064820152608401610bff565b5f8581526049602090815260408083203384529091529020805460ff19166001179055426004848101919091558354829185917fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1690600160a01b908490811115613dd257613dd2615582565b021790555082546001600160a01b031916331783555f613df28347614a28565b5f878152604c6020526040812080549293508392909190613e149084906159c7565b9091555060049050826004811115613e2e57613e2e615582565b1461401257603e545f906001600160a01b03166330759ce988856004811115613e5957613e59615582565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b168152600481019290925260ff166024820152604401602060405180830381865afa158015613eb3573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613ed79190615b0c565b603e549091506001600160a01b031662fdd58e336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b03909116600482015260248101849052604401602060405180830381865afa158015613f4c573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613f709190615b0c565b5f0361401057603e546001600160a01b031663731133e9336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b0390911660048201526024810184905260016044820152608060648201525f608482015260a4015f604051808303815f87803b158015613ff9575f80fd5b505af115801561400b573d5f803e3d5ffd5b505050505b505b5f81116140875760405162461bcd60e51b815260206004820152603960248201527f5061796f7574507572737569743a20696e73756666696369656e742066756e6460448201527f732c20706c6561736520636f6e7461637420737570706f7274000000000000006064820152608401610bff565b614090336122f4565b5050505050611fe26001600855565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000810460ff16159067ffffffffffffffff165f811580156140e95750825b90505f8267ffffffffffffffff1660011480156141055750303b155b905081158015614113575080155b1561414a576040517ff92ee8a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b845467ffffffffffffffff19166001178555831561417e57845468ff00000000000000001916680100000000000000001785555b614187896150b6565b603c80546001600160a01b038a81166001600160a01b031992831617909255603d80548a8416908316179055603e805492891692909116919091179055604b6020908152616d607f08bf084be5767d8bb834edf3692454b23339ffcb9637cb06a941344461c3719855615a3c7fa616258785d57c6565e8210a7a01441f8018ea52e0ce6d2ea56b8099c64a4d75556149d47fed8fe69440ed7378c748b48bdf0a382a8b2b7193fd6134dd2b323f6392cefa4d5560035f9081526175307f18568898f741436c6378e97ae0a64b9a55f252371515c69c6b47e8a95ef4209455603f556005604090815562278d006041558051808201909152600181527f310000000000000000000000000000000000000000000000000000000000000091810191909152603b906142b79082615b9a565b50603a805460ff19166001179055831561431057845468ff000000000000000019168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b505050505050505050565b335f9081526020819052604090205460ff1615156001148061437557503361436a7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031690565b6001600160a01b0316145b6143c15760405162461bcd60e51b815260206004820152601460248201527f596f7520617265206e6f7420616c6c6f7765642e0000000000000000000000006044820152606401610bff565b5f5b8281101561442d578160015f8686858181106143e1576143e16159b3565b90506020020160208101906143f6919061514a565b6001600160a01b0316815260208101919091526040015f20805460ff191691151591909117905561442681615ad6565b90506143c3565b5060405181151581527f7dc357bd865f9219c544a8b0b14cb1583b26e3ffe765b3396ef2051d81a8de569060200160405180910390a1505050565b3361449a7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031690565b6001600160a01b031614611ff6576040517f118cdaa7000000000000000000000000000000000000000000000000000000008152336004820152602401610bff565b60026008540361452e5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610bff565b6002600855565b60405142808252907fe933406ce445ea24d84ca4529e514adc8926e62cdc8b5a67c568c9fd578f1a8a9060200160405180910390a15f9182526003602052604090912055565b5f818152600260205260408120544210801590610ee15750505f9081526003602052604090205442111590565b60605f826040516020016145bc9190615659565b60408051601f198184030181529181525f87815260076020529081209192508560048111156145ed576145ed615582565b60048111156145fe576145fe615582565b81526020808201929092526040015f9081208054600181018255908252919020016146298282615b9a565b5090505b9392505050565b815415611a925781545f19905f908190614650906001906159c7565b90505b8082116146cc578385838154811061466d5761466d6159b3565b905f5260205f20015403614683578192506146cc565b83858281548110614696576146966159b3565b905f5260205f200154036146ac578092506146cc565b816146b681615ad6565b92505080806146c490615cdf565b915050614653565b825f191461473f57845485906146e4906001906159c7565b815481106146f4576146f46159b3565b905f5260205f20015485848154811061470f5761470f6159b3565b905f5260205f2001819055508480548061472b5761472b615cf4565b600190038181905f5260205f20015f905590555b5050505050565b5f805f61475284611c34565b9050803410156147ca5760405162461bcd60e51b815260206004820152602160248201527f5061796f7574507572737569743a20696e76616c696420656e7472792066656560448201527f73000000000000000000000000000000000000000000000000000000000000006064820152608401610bff565b6147d481346159c7565b60445f8282546147e491906159a0565b925050819055508060455f8282546147fc91906159a0565b90915550505f93845260466020526040909320600301549293915050565b6040805160e081019091526001600160a01b0385168152602081016004815260208082018590526040808301859052606083018790525f60808401819052600160a090940193909352888352600582528083206001600160a01b03808a16855290835292208351815493166001600160a01b0319841681178255918401519092909183917fffffffffffffffffffffff0000000000000000000000000000000000000000001617600160a01b8360048111156148d8576148d8615582565b0217905550604082810151600183810191909155606084015160028401556080840151600384015560a0840151600484015560c0909301516005909201805460ff1916921515929092179091555f878152600660209081528282208054948501815582529081902090920180546001600160a01b0319166001600160a01b0388169081179091559051858152909187917f5d4e74d7fe247481ab545efef1bef98ba70cb6bedd0d08e2605409b0539e0661910160405180910390a35050505050565b5f8181526004602052604090819020805460ff19169055517f34cf8e99b6f44f9c706d7ef35b7b3af069a5797c286c9a2f28f0484de8f6bb99906111e49083815260200190565b5f828152604a6020526040812081836004811115614a0157614a01615582565b6004811115614a1257614a12615582565b81526020019081526020015f2054905092915050565b5f818310614a36578161462d565b5090919050565b5f826001600160a01b0316826040515f6040518083038185875af1925050503d805f8114614a86576040519150601f19603f3d011682016040523d82523d5f602084013e614a8b565b606091505b5050905080610eb8575f80fd5b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930080546001600160a01b031981166001600160a01b03848116918217845560405192169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a3505050565b5f8042603f54604051602001614b28929190918252602082015260400190565b60408051601f198184030181529190528051602090910120603f80549192505f614b5183615ad6565b909155509092915050565b42831015614bd25760405162461bcd60e51b815260206004820152603660248201527f5061796f75745075727375697454696d653a206f70656e696e672074696d652060448201527f6973206265666f72652063757272656e742074696d65000000000000000000006064820152608401610bff565b828211614c475760405162461bcd60e51b815260206004820152603660248201527f5061796f75745075727375697454696d653a20636c6f73696e672074696d652060448201527f6973206265666f7265206f70656e696e672074696d65000000000000000000006064820152608401610bff565b60408051848152602081018490527f36f8189c7d2c93ba984df4213bcb461ef59ac588902491237134e9f79ef10f1b910160405180910390a15f90815260026020908152604080832094909455600390529190912055565b80614ca98161457b565b614cf55760405162461bcd60e51b815260206004820152601b60248201527f5061796f75745075727375697454696d653a206e6f74206f70656e00000000006044820152606401610bff565b5f8281526004602052604090819020805460ff19166001179055517f820455334cc218aac711728d638cbbdf0f5f2b3a74787f5fe55ce8abd3142eab90614d3f9084815260200190565b60405180910390a15050565b5f81604051602001614d5d9190615d08565b6040516020818303038152906040528051906020012083604051602001614d849190615d08565b6040516020818303038152906040528051906020012014905092915050565b5f8381526007602052604081206060919081856004811115614dc757614dc7615582565b6004811115614dd857614dd8615582565b815260208101919091526040015f2054111561462d575f84815260076020526040812081856004811115614e0e57614e0e615582565b6004811115614e1f57614e1f615582565b81526020019081526020015f20600160075f8881526020019081526020015f205f876004811115614e5257614e52615582565b6004811115614e6357614e63615582565b815260208101919091526040015f2054614e7d91906159c7565b81548110614e8d57614e8d6159b3565b905f5260205f20018054614ea0906159da565b80601f0160208091040260200160405190810160405280929190818152602001828054614ecc906159da565b8015614f175780601f10614eee57610100808354040283529160200191614f17565b820191905f5260205f20905b815481529060010190602001808311614efa57829003601f168201915b505050505090505f83511115614f2a5750815b808060200190518101906111899190615d23565b614f478161328f565b1580614f6057505f8181526004602052604090205460ff165b614fb65760405162461bcd60e51b815260206004820152602160248201527f5061796f75745075727375697454696d653a20616c726561647920636c6f73656044820152601960fa1b6064820152608401610bff565b5f81815260036020526040902054821161505e5760405162461bcd60e51b815260206004820152604260248201527f5061796f75745075727375697454696d653a206e657720636c6f73696e67207460448201527f696d65206973206265666f72652063757272656e7420636c6f73696e6720746960648201527f6d65000000000000000000000000000000000000000000000000000000000000608482015260a401610bff565b5f818152600360209081526040918290205482519081529081018490527fb818c883d8b349292af8ecb2b89962bedcc279f3fb987752df3f2b05f40ec05c910160405180910390a15f90815260036020526040902055565b6150be6150c7565b611fe28161512e565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005468010000000000000000900460ff16611ff6576040517fd7e6bcf800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b613b8b6150c7565b6001600160a01b0381168114611fe2575f80fd5b5f6020828403121561515a575f80fd5b813561462d81615136565b5f60208284031215615175575f80fd5b5035919050565b8015158114611fe2575f80fd5b5f805f6060848603121561519b575f80fd5b83356151a68161517c565b92506020840135915060408401356151bd8161517c565b809150509250925092565b5f602082840312156151d8575f80fd5b81356005811061462d575f80fd5b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f1916810167ffffffffffffffff81118282101715615223576152236151e6565b604052919050565b5f67ffffffffffffffff821115615244576152446151e6565b5060051b60200190565b5f82601f83011261525d575f80fd5b8135602061527261526d8361522b565b6151fa565b82815260059290921b84018101918181019086841115615290575f80fd5b8286015b848110156152b45780356152a781615136565b8352918301918301615294565b509695505050505050565b5f805f805f60a086880312156152d3575f80fd5b85359450602086013567ffffffffffffffff808211156152f1575f80fd5b6152fd89838a0161524e565b95506040880135915080821115615312575f80fd5b61531e89838a0161524e565b94506060880135915080821115615333575f80fd5b506153408882890161524e565b92505060808601356153518161517c565b809150509295509295909350565b5f5b83811015615379578181015183820152602001615361565b50505f910152565b5f815180845261539881602086016020860161535f565b601f01601f19169290920160200192915050565b5f602080830181845280855180835260408601915060408160051b87010192508387015f5b828110156153ff57603f198886030184526153ed858351615381565b945092850192908501906001016153d1565b5092979650505050505050565b5f806040838503121561541d575f80fd5b50508035926020909101359150565b5f6101408c8352602081818501526154468285018e615381565b9150838203604085015261545a828d615381565b91508a60608501528960808501528860a08501528760c08501528660e085015283820361010085015261548d8287615381565b91508382036101208501528185518084528284019150828160051b8501018388015f5b838110156154de57601f198784030185526154cc838351615381565b948601949250908501906001016154b0565b505080955050505050509b9a5050505050505050505050565b5f8151808452602080850194508084015f5b8381101561552557815187529582019590820190600101615509565b509495945050505050565b602081525f61462d60208301846154f7565b602081525f61462d6020830184615381565b5f8060408385031215615565575f80fd5b82359150602083013561557781615136565b809150509250929050565b634e487b7160e01b5f52602160045260245ffd5b600581106155b257634e487b7160e01b5f52602160045260245ffd5b9052565b6001600160a01b038816815260e081016155d36020830189615596565b60408201969096526060810194909452608084019290925260a0830152151560c09091015292915050565b838152606081016156126020830185615596565b8215156040830152949350505050565b5f8151808452602080850194508084015f5b838110156155255781516001600160a01b031687529582019590820190600101615634565b602081525f61462d6020830184615622565b5f67ffffffffffffffff821115615684576156846151e6565b50601f01601f191660200190565b5f82601f8301126156a1575f80fd5b81356156af61526d8261566b565b8181528460208386010111156156c3575f80fd5b816020850160208301375f918101602001919091529392505050565b5f805f805f805f805f6101208a8c0312156156f8575f80fd5b8935985060208a013567ffffffffffffffff80821115615716575f80fd5b6157228d838e01615692565b995060408c0135915080821115615737575f80fd5b506157448c828d01615692565b999c989b5098996060810135995060808101359860a0820135985060c0820135975060e0820135965061010090910135945092505050565b5f805f806080858703121561578f575f80fd5b84359350602085013567ffffffffffffffff808211156157ad575f80fd5b6157b988838901615692565b945060408701359150808211156157ce575f80fd5b506157db87828801615692565b949793965093946060013593505050565b606081525f6157fe6060830186615622565b82810360208401526158108186615622565b90508281036040840152613a8b8185615622565b60a081525f61583660a08301886154f7565b828103602084015261584881886154f7565b9050828103604084015261585c81876154f7565b9050828103606084015261587081866154f7565b9050828103608084015261588481856154f7565b98975050505050505050565b5f805f80608085870312156158a3575f80fd5b5050823594602084013594506040840135936060013592509050565b5f805f80608085870312156158d2575f80fd5b84356158dd81615136565b935060208501356158ed81615136565b925060408501356158fd81615136565b9150606085013561590d81615136565b939692955090935050565b5f805f6040848603121561592a575f80fd5b833567ffffffffffffffff80821115615941575f80fd5b818601915086601f830112615954575f80fd5b813581811115615962575f80fd5b8760208260051b8501011115615976575f80fd5b602092830195509350508401356151bd8161517c565b634e487b7160e01b5f52601160045260245ffd5b80820180821115610ee157610ee161598c565b634e487b7160e01b5f52603260045260245ffd5b81810381811115610ee157610ee161598c565b600181811c908216806159ee57607f821691505b602082108103615a0c57634e487b7160e01b5f52602260045260245ffd5b50919050565b5f82601f830112615a21575f80fd5b8151615a2f61526d8261566b565b818152846020838601011115615a43575f80fd5b611c4f82602083016020870161535f565b5f805f60608486031215615a66575f80fd5b835167ffffffffffffffff80821115615a7d575f80fd5b615a8987838801615a12565b94506020860151915080821115615a9e575f80fd5b615aaa87838801615a12565b93506040860151915080821115615abf575f80fd5b50615acc86828701615a12565b9150509250925092565b5f60018201615ae757615ae761598c565b5060010190565b5f60ff821660ff8103615b0357615b0361598c565b60010192915050565b5f60208284031215615b1c575f80fd5b5051919050565b5f60208284031215615b33575f80fd5b815161462d8161517c565b8082028115828204841417610ee157610ee161598c565b601f821115610eb8575f81815260208120601f850160051c81016020861015615b7b5750805b601f850160051c820191505b81811015612d4157828155600101615b87565b815167ffffffffffffffff811115615bb457615bb46151e6565b615bc881615bc284546159da565b84615b55565b602080601f831160018114615bfb575f8415615be45750858301515b5f19600386901b1c1916600185901b178555612d41565b5f85815260208120601f198616915b82811015615c2957888601518255948401946001909101908401615c0a565b5085821015615c4657878501515f19600388901b60f8161c191681555b5050505050600190811b01905550565b5f82615c7057634e487b7160e01b5f52601260045260245ffd5b500490565b805169ffffffffffffffffffff81168114615c8e575f80fd5b919050565b5f805f805f60a08688031215615ca7575f80fd5b615cb086615c75565b9450602086015193506040860151925060608601519150615cd360808701615c75565b90509295509295909350565b5f81615ced57615ced61598c565b505f190190565b634e487b7160e01b5f52603160045260245ffd5b5f8251615d1981846020870161535f565b9190910192915050565b5f6020808385031215615d34575f80fd5b825167ffffffffffffffff811115615d4a575f80fd5b8301601f81018513615d5a575f80fd5b8051615d6861526d8261522b565b81815260059190911b82018301908381019087831115615d86575f80fd5b928401925b82841015615dad578351615d9e81615136565b82529284019290840190615d8b565b97965050505050505056fea264697066735822122023a01689af86bccb30548863bf243f36a7fd96861fb531ff2e999b74283a825164736f6c63430008140033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
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  ]

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.